diff --git a/AMD/Source/amd_order.c b/AMD/Source/amd_order.c index 1dcc15a009..9e4e17366d 100644 --- a/AMD/Source/amd_order.c +++ b/AMD/Source/amd_order.c @@ -71,9 +71,9 @@ int AMD_order return (AMD_INVALID) ; } - /* check if n or nz will cause size_t overflow */ - if (((size_t) n) >= SIZE_T_MAX / sizeof (Int) - || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int)) + /* check if n or nz will cause integer overflow */ + if (((size_t) n) >= Int_MAX / sizeof (Int) + || ((size_t) nz) >= Int_MAX / sizeof (Int)) { if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; /* problem too large */ diff --git a/CAMD/Source/camd_order.c b/CAMD/Source/camd_order.c index eb08cd3ea9..5873527e7d 100644 --- a/CAMD/Source/camd_order.c +++ b/CAMD/Source/camd_order.c @@ -72,9 +72,9 @@ int CAMD_order return (CAMD_INVALID) ; } - /* check if n or nz will cause size_t overflow */ - if ((size_t) n >= SIZE_T_MAX / sizeof (Int) - || (size_t) nz >= SIZE_T_MAX / sizeof (Int)) + /* check if n or nz will cause integer overflow */ + if (((size_t) n) >= Int_MAX / sizeof (Int) + || ((size_t) nz) >= Int_MAX / sizeof (Int)) { if (info) Info [CAMD_STATUS] = CAMD_OUT_OF_MEMORY ; return (CAMD_OUT_OF_MEMORY) ; /* problem too large */ diff --git a/CHOLMOD/CMakeLists.txt b/CHOLMOD/CMakeLists.txt index c2ff92f020..2a875a2de6 100644 --- a/CHOLMOD/CMakeLists.txt +++ b/CHOLMOD/CMakeLists.txt @@ -2,7 +2,7 @@ # SuiteSparse/CHOLMOD/CMakeLists.txt: cmake for CHOLMOD #------------------------------------------------------------------------------- -# CHOLMOD: Copyright (c) 2005-2022, Timothy A. Davis. +# CHOLMOD: Copyright (c) 2005-2023, Timothy A. Davis. # Copyright and license varies by module. #------------------------------------------------------------------------------- @@ -12,10 +12,10 @@ # cmake 3.22 is required to find the BLAS/LAPACK cmake_minimum_required ( VERSION 3.22 ) -set ( CHOLMOD_DATE "Oct 31, 2023" ) +set ( CHOLMOD_DATE "Nov 30, 2023" ) set ( CHOLMOD_VERSION_MAJOR 5 ) -set ( CHOLMOD_VERSION_MINOR 0 ) -set ( CHOLMOD_VERSION_SUB 1 ) +set ( CHOLMOD_VERSION_MINOR 1 ) +set ( CHOLMOD_VERSION_SUB 0 ) message ( STATUS "Building CHOLMOD version: v" ${CHOLMOD_VERSION_MAJOR}. @@ -616,9 +616,11 @@ endif ( ) # Demo library and programs #------------------------------------------------------------------------------- -option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." off ) +option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." on ) if ( DEMO ) + enable_testing ( ) + #--------------------------------------------------------------------------- # demo library #--------------------------------------------------------------------------- @@ -629,9 +631,15 @@ if ( DEMO ) # Demo programs #--------------------------------------------------------------------------- - add_executable ( cholmod_demo "Demo/cholmod_demo.c" ) - add_executable ( cholmod_l_demo "Demo/cholmod_l_demo.c" ) - add_executable ( cholmod_simple "Demo/cholmod_simple.c" ) + add_executable ( cholmod_di_demo "Demo/cholmod_di_demo.c" ) + add_executable ( cholmod_dl_demo "Demo/cholmod_dl_demo.c" ) + add_executable ( cholmod_si_demo "Demo/cholmod_si_demo.c" ) + add_executable ( cholmod_sl_demo "Demo/cholmod_sl_demo.c" ) + + add_executable ( cholmod_di_simple "Demo/cholmod_di_simple.c" ) + add_executable ( cholmod_dl_simple "Demo/cholmod_dl_simple.c" ) + add_executable ( cholmod_si_simple "Demo/cholmod_si_simple.c" ) + add_executable ( cholmod_sl_simple "Demo/cholmod_sl_simple.c" ) if ( NOT NFORTRAN ) add_executable ( readhb "Demo/readhb.f" ) @@ -640,18 +648,84 @@ if ( DEMO ) endif ( ) # Libraries required for Demo programs - target_link_libraries ( cholmod_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + target_link_libraries ( cholmod_di_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + if ( SUITESPARSE_CUDA ) + target_link_libraries ( cholmod_di_demo PUBLIC CHOLMOD_CUDA ) + endif ( ) + target_link_libraries ( cholmod_si_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + if ( SUITESPARSE_CUDA ) + target_link_libraries ( cholmod_si_demo PUBLIC CHOLMOD_CUDA ) + endif ( ) + target_link_libraries ( cholmod_dl_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) if ( SUITESPARSE_CUDA ) - target_link_libraries ( cholmod_demo PUBLIC CHOLMOD_CUDA ) + target_link_libraries ( cholmod_dl_demo PUBLIC CHOLMOD_CUDA ) endif ( ) - target_link_libraries ( cholmod_l_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + target_link_libraries ( cholmod_sl_demo PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) if ( SUITESPARSE_CUDA ) - target_link_libraries ( cholmod_l_demo PUBLIC CHOLMOD_CUDA ) + target_link_libraries ( cholmod_sl_demo PUBLIC CHOLMOD_CUDA ) endif ( ) - target_link_libraries ( cholmod_simple PUBLIC CHOLMOD ) + + target_link_libraries ( cholmod_di_simple PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + if ( SUITESPARSE_CUDA ) + target_link_libraries ( cholmod_di_simple PUBLIC CHOLMOD_CUDA ) + endif ( ) + target_link_libraries ( cholmod_si_simple PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) if ( SUITESPARSE_CUDA ) - target_link_libraries ( cholmod_simple PUBLIC CHOLMOD_CUDA ) + target_link_libraries ( cholmod_si_simple PUBLIC CHOLMOD_CUDA ) endif ( ) + target_link_libraries ( cholmod_dl_simple PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + if ( SUITESPARSE_CUDA ) + target_link_libraries ( cholmod_dl_simple PUBLIC CHOLMOD_CUDA ) + endif ( ) + target_link_libraries ( cholmod_sl_simple PUBLIC CHOLMOD SuiteSparse::SuiteSparseConfig ) + if ( SUITESPARSE_CUDA ) + target_link_libraries ( cholmod_sl_simple PUBLIC CHOLMOD_CUDA ) + endif ( ) + + add_test ( NAME int32_double_bcsstk01 + COMMAND cholmod_di_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk01.tri ) + add_test ( NAME int64_double_bcsstk01 + COMMAND cholmod_dl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk01.tri ) + add_test ( NAME int32_single_bcsstk01 + COMMAND cholmod_si_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk01.tri ) + add_test ( NAME int64_single_bcsstk01 + COMMAND cholmod_sl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk01.tri ) + + add_test ( NAME int32_double_lp_afiro + COMMAND cholmod_di_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/lp_afiro.tri ) + add_test ( NAME int64_double_lp_afiro + COMMAND cholmod_dl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/lp_afiro.tri ) + add_test ( NAME int32_single_lp_afiro + COMMAND cholmod_si_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/lp_afiro.tri ) + add_test ( NAME int64_single_lp_afiro + COMMAND cholmod_sl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/lp_afiro.tri ) + + add_test ( NAME int32_double_can24 + COMMAND cholmod_di_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/can___24.mtx ) + add_test ( NAME int64_double_can24 + COMMAND cholmod_dl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/can___24.mtx ) + add_test ( NAME int32_single_can24 + COMMAND cholmod_si_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/can___24.mtx ) + add_test ( NAME int64_single_can24 + COMMAND cholmod_sl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/can___24.mtx ) + + add_test ( NAME int32_double_complex + COMMAND cholmod_di_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/c.tri ) + add_test ( NAME int64_double_complex + COMMAND cholmod_dl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/c.tri ) + add_test ( NAME int32_single_complex + COMMAND cholmod_si_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/c.tri ) + add_test ( NAME int64_single_complex + COMMAND cholmod_sl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/c.tri ) + + add_test ( NAME int32_double_supernodal + COMMAND cholmod_di_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk02.tri ) + add_test ( NAME int64_double_supernodal + COMMAND cholmod_dl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk02.tri ) + add_test ( NAME int32_single_supernodal + COMMAND cholmod_si_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk02.tri ) + add_test ( NAME int64_single_supernodal + COMMAND cholmod_sl_demo ${CMAKE_SOURCE_DIR}/Demo/Matrix/bcsstk02.tri ) else ( ) diff --git a/CHOLMOD/Check/cholmod_check.c b/CHOLMOD/Check/cholmod_check.c index 56bc8e9a7f..93b1e8ce10 100644 --- a/CHOLMOD/Check/cholmod_check.c +++ b/CHOLMOD/Check/cholmod_check.c @@ -2,72 +2,71 @@ // CHOLMOD/Check/cholmod_check: check and print each CHOLMOD object //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Routines to check and print the contents of the 5 CHOLMOD objects: - * - * No CHOLMOD routine calls the check or print routines. If a user wants to - * check CHOLMOD's input parameters, a separate call to the appropriate check - * routine should be used before calling other CHOLMOD routines. - * - * cholmod_check_common check statistics and workspace in Common - * cholmod_check_sparse check sparse matrix in compressed column form - * cholmod_check_dense check dense matrix - * cholmod_check_factor check factorization - * cholmod_check_triplet check sparse matrix in triplet form - * - * cholmod_print_common print statistics in Common - * cholmod_print_sparse print sparse matrix in compressed column form - * cholmod_print_dense print dense matrix - * cholmod_print_factor print factorization - * cholmod_print_triplet print sparse matrix in triplet form - * - * In addition, this file contains routines to check and print three types of - * integer vectors: - * - * cholmod_check_perm check a permutation of 0:n-1 (no duplicates) - * cholmod_check_subset check a subset of 0:n-1 (duplicates OK) - * cholmod_check_parent check an elimination tree - * - * cholmod_print_perm print a permutation - * cholmod_print_subset print a subset - * cholmod_print_parent print an elimination tree - * - * Each Common->print level prints the items at or below the given level: - * - * 0: print nothing; just check the data structures and return TRUE/FALSE - * 1: error messages - * 2: warning messages - * 3: one-line summary of each object printed - * 4: short summary of each object (first and last few entries) - * 5: entire contents of the object - * - * No CHOLMOD routine calls these routines, so no printing occurs unless - * the user specifically calls a cholmod_print_* routine. Thus, the default - * print level is 3. - * - * Common->precise controls the # of digits printed for numerical entries - * (5 if FALSE, 15 if TRUE). - * - * If the SuiteSparse_config printf_func is NULL, then no printing occurs. The - * cholmod_check_* and cholmod_print_* routines still check their inputs and - * return TRUE/FALSE if the object is valid or not. - * - * This file also includes debugging routines that are enabled only when - * NDEBUG is defined in cholmod_internal.h (cholmod_dump_*). - */ +// Routines to check and print the contents of the 5 CHOLMOD objects: +// +// No CHOLMOD routine calls the check or print routines. If a user wants to +// check CHOLMOD's input parameters, a separate call to the appropriate check +// routine should be used before calling other CHOLMOD routines. +// +// cholmod_check_common check statistics and workspace in Common +// cholmod_check_sparse check sparse matrix in compressed column form +// cholmod_check_dense check dense matrix +// cholmod_check_factor check factorization +// cholmod_check_triplet check sparse matrix in triplet form +// +// cholmod_print_common print statistics in Common +// cholmod_print_sparse print sparse matrix in compressed column form +// cholmod_print_dense print dense matrix +// cholmod_print_factor print factorization +// cholmod_print_triplet print sparse matrix in triplet form +// +// In addition, this file contains routines to check and print three types of +// integer vectors: +// +// cholmod_check_perm check a permutation of 0:n-1 (no duplicates) +// cholmod_check_subset check a subset of 0:n-1 (duplicates OK) +// cholmod_check_parent check an elimination tree +// +// cholmod_print_perm print a permutation +// cholmod_print_subset print a subset +// cholmod_print_parent print an elimination tree +// +// Each Common->print level prints the items at or below the given level: +// +// 0: print nothing; just check the data structures and return TRUE/FALSE +// 1: error messages +// 2: warning messages +// 3: one-line summary of each object printed +// 4: short summary of each object (first and last few entries) +// 5: entire contents of the object +// +// No CHOLMOD routine calls these routines, so no printing occurs unless +// the user specifically calls a cholmod_print_* routine. Thus, the default +// print level is 3. +// +// Common->precise controls the # of digits printed for numerical entries +// (5 if FALSE, 15 if TRUE). +// +// If the SuiteSparse_config printf_func is NULL, then no printing occurs. The +// cholmod_check_* and cholmod_print_* routines still check their inputs and +// return TRUE/FALSE if the object is valid or not. +// +// This file also includes debugging routines that are enabled only when +// NDEBUG is defined in cholmod_internal.h (cholmod_dump_*). #ifndef NCHECK #include "cholmod_internal.h" -/* ========================================================================== */ -/* === printing definitions ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// printing definitions +//------------------------------------------------------------------------------ #if defined ( CHOLMOD_INT64 ) #define I8 "%8ld" @@ -95,58 +94,45 @@ #define P3(format,arg) PR(3,format,arg) #define P4(format,arg) PR(4,format,arg) -#define ERR(msg) \ -{ \ - P1 ("\nCHOLMOD ERROR: %s: ", type) ; \ - if (name != NULL) \ - { \ - P1 ("%s", name) ; \ - } \ - P1 (": %s\n", msg) ; \ - ERROR (CHOLMOD_INVALID, "invalid") ; \ - return (FALSE) ; \ +#define ERR(msg) \ +{ \ + P1 ("\nCHOLMOD ERROR: %s: ", type) ; \ + if (name != NULL) \ + { \ + P1 ("%s", name) ; \ + } \ + P1 (": %s\n", msg) ; \ + ERROR (CHOLMOD_INVALID, "invalid") ; \ + return (FALSE) ; \ } -/* print a numerical value */ -#define PRINTVALUE(value) \ -{ \ - if (Common->precise) \ - { \ - P4 (" %23.15e", value) ; \ - } \ - else \ - { \ - P4 (" %.5g", value) ; \ - } \ +// start printing +#define ETC_START(count,limit) \ +{ \ + count = (init_print == 4) ? (limit) : (-1) ; \ } -/* start printing */ -#define ETC_START(count,limit) \ -{ \ - count = (init_print == 4) ? (limit) : (-1) ; \ +// re-enable printing if condition is met +#define ETC_ENABLE(condition,count,limit) \ +{ \ + if ((condition) && init_print == 4) \ + { \ + count = limit ; \ + print = 4 ; \ + } \ } -/* re-enable printing if condition is met */ -#define ETC_ENABLE(condition,count,limit) \ -{ \ - if ((condition) && init_print == 4) \ - { \ - count = limit ; \ - print = 4 ; \ - } \ +// turn off printing if limit is reached +#define ETC_DISABLE(count) \ +{ \ + if ((count >= 0) && (count-- == 0) && print == 4) \ + { \ + P4 ("%s", " ...\n") ; \ + print = 3 ; \ + } \ } -/* turn off printing if limit is reached */ -#define ETC_DISABLE(count) \ -{ \ - if ((count >= 0) && (count-- == 0) && print == 4) \ - { \ - P4 ("%s", " ...\n") ; \ - print = 3 ; \ - } \ -} - -/* re-enable printing, or turn if off after limit is reached */ +// re-enable printing, or turn if off after limit is reached #define ETC(condition,count,limit) \ { \ ETC_ENABLE (condition, count, limit) ; \ @@ -155,67 +141,82 @@ #define BOOLSTR(x) ((x) ? "true " : "false") -/* ========================================================================== */ -/* === print_value ========================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// print_value +//------------------------------------------------------------------------------ + +// get a double or float value from an array at X [p] +#define GETVAL(X,p,dtype) \ + ((dtype == CHOLMOD_DOUBLE) ? (((double *) X) [p]) : (((float *) X) [p])) + +// print a numerical value in X [p], as float or double +#define PRINTVALUE(X,p,dtype) \ +{ \ + double value = GETVAL (X, p, dtype) ; \ + char *fmt = (Common->precise) ? \ + ((dtype == CHOLMOD_DOUBLE) ? (" %23.15e") : (" %15.7e")) : \ + (" %.5g ") ; \ + P4 (fmt, value) ; \ +} static void print_value ( - Int print, - Int xtype, - double *Xx, - double *Xz, + int print, + int xtype, // CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX + int dtype, // CHOLMOD_SINGLE or _DOUBLE + void *Xx, // pointer to float or double (real part) + void *Xz, // pointer to float or double (zomplex only) Int p, cholmod_common *Common) { + if (xtype == CHOLMOD_REAL) { - PRINTVALUE (Xx [p]) ; + PRINTVALUE (Xx, p, dtype) ; } else if (xtype == CHOLMOD_COMPLEX) { - P4 ("%s", "(") ; - PRINTVALUE (Xx [2*p ]) ; - P4 ("%s", " , ") ; - PRINTVALUE (Xx [2*p+1]) ; - P4 ("%s", ")") ; + P4 ("%s", "(") ; + PRINTVALUE (Xx, 2*p , dtype) ; + P4 ("%s", " , ") ; + PRINTVALUE (Xx, 2*p+1, dtype) ; + P4 ("%s", ")") ; } else if (xtype == CHOLMOD_ZOMPLEX) { - P4 ("%s", "(") ; - PRINTVALUE (Xx [p]) ; - P4 ("%s", " , ") ; - PRINTVALUE (Xz [p]) ; - P4 ("%s", ")") ; + P4 ("%s", "(") ; + PRINTVALUE (Xx, p, dtype) ; + P4 ("%s", " , ") ; + PRINTVALUE (Xz, p, dtype) ; + P4 ("%s", ")") ; } } -/* ========================================================================== */ -/* === cholmod_check_common ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_check_common +//------------------------------------------------------------------------------ -/* Print and verify the contents of Common */ +// Print and verify the contents of Common static int check_common ( - Int print, + int print, const char *name, cholmod_common *Common ) { double fl, lnz ; - uint8_t *Xwork ; Int *Flag, *Head ; int64_t mark ; - Int i, nrow, nmethods, ordering, xworksize, amd_backup, init_print ; + Int i, nrow, nmethods, ordering, amd_backup ; const char *type = "common" ; - /* ---------------------------------------------------------------------- */ - /* print control parameters and statistics */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print control parameters and statistics + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; - init_print = print ; + int init_print = print ; P2 ("%s", "\n") ; @@ -226,92 +227,93 @@ static int check_common if (name != NULL) { - P1 ("%s: ", name) ; + P1 ("%s: ", name) ; } switch (Common->status) { - case CHOLMOD_OK: - P1 ("%s", "status: OK\n") ; - break ; + case CHOLMOD_OK: + P1 ("%s", "status: OK\n") ; + break ; - case CHOLMOD_OUT_OF_MEMORY: - P1 ("%s", "status: ERROR, out of memory\n") ; - break ; + case CHOLMOD_OUT_OF_MEMORY: + P1 ("%s", "status: ERROR, out of memory\n") ; + break ; - case CHOLMOD_INVALID: - P1 ("%s", "status: ERROR, invalid parameter\n") ; - break ; + case CHOLMOD_INVALID: + P1 ("%s", "status: ERROR, invalid parameter\n") ; + break ; - case CHOLMOD_TOO_LARGE: - P1 ("%s", "status: ERROR, problem too large\n") ; - break ; + case CHOLMOD_TOO_LARGE: + P1 ("%s", "status: ERROR, problem too large\n") ; + break ; - case CHOLMOD_NOT_INSTALLED: - P1 ("%s", "status: ERROR, method not installed\n") ; - break ; + case CHOLMOD_NOT_INSTALLED: + P1 ("%s", "status: ERROR, method not installed\n") ; + break ; - case CHOLMOD_GPU_PROBLEM: - P1 ("%s", "status: ERROR, GPU had a fatal error\n") ; - break ; + case CHOLMOD_GPU_PROBLEM: + P1 ("%s", "status: ERROR, GPU had a fatal error\n") ; + break ; - case CHOLMOD_NOT_POSDEF: - P1 ("%s", "status: warning, matrix not positive definite\n") ; - break ; + case CHOLMOD_NOT_POSDEF: + P1 ("%s", "status: warning, matrix not positive definite\n") ; + break ; - case CHOLMOD_DSMALL: - P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ; - break ; + case CHOLMOD_DSMALL: + P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ; + break ; - default: - ERR ("unknown status") ; + default: + ERR ("unknown status") ; } - P2 (" Architecture: %s\n", CHOLMOD_ARCHITECTURE) ; + P3 ("%s", " Architecture:\n") ; P3 (" sizeof(int): %d\n", (int) sizeof (int)) ; P3 (" sizeof(int64_t): %d\n", (int) sizeof (int64_t)); P3 (" sizeof(void *): %d\n", (int) sizeof (void *)) ; P3 (" sizeof(double): %d\n", (int) sizeof (double)) ; - P3 (" sizeof(Int): %d (CHOLMOD's basic integer)\n", (int) sizeof (Int)) ; + P3 (" sizeof(Int): %d (CHOLMOD's basic integer)\n", + (int) sizeof (Int)) ; P3 (" sizeof(SUITESPARSE_BLAS_INT): %d (integer used in the BLAS)\n", - (int) sizeof (SUITESPARSE_BLAS_INT)) ; + (int) sizeof (SUITESPARSE_BLAS_INT)) ; if (Common->fl != EMPTY) { - P2 ("%s", " Results from most recent analysis:\n") ; - P2 (" Cholesky flop count: %.5g\n", Common->fl) ; - P2 (" Nonzeros in L: %.5g\n", Common->lnz) ; + P2 ("%s", " Results from most recent analysis:\n") ; + P2 (" Cholesky flop count: %.5g\n", Common->fl) ; + P2 (" Nonzeros in L: %.5g\n", Common->lnz) ; } if (Common->modfl != EMPTY) { - P2 (" Update/downdate flop count: %.5g\n", Common->modfl) ; + P2 (" Update/downdate flop count: %.5g\n", Common->modfl) ; } P2 (" memory blocks in use: %8.0f\n", (double) (Common->malloc_count)) ; - P2 (" memory in use (MB): %8.1f\n", - (double) (Common->memory_inuse) / 1048576.) ; - P2 (" peak memory usage (MB): %8.1f\n", - (double) (Common->memory_usage) / 1048576.) ; + P2 (" memory in use (MB): %8.1f\n", + (double) (Common->memory_inuse) / 1048576.) ; + P2 (" peak memory usage (MB): %8.1f\n", + (double) (Common->memory_usage) / 1048576.) ; - /* ---------------------------------------------------------------------- */ - /* primary control parameters and related ordering statistics */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // primary control parameters and related ordering statistics + //-------------------------------------------------------------------------- P3 (" maxrank: update/downdate rank: "ID"\n", - (Int) CHOLMOD(maxrank) (0, Common)) ; + (Int) CHOLMOD(maxrank) (0, Common)) ; P3 (" supernodal control: %d", Common->supernodal) ; P3 (" %g ", Common->supernodal_switch) ; if (Common->supernodal <= CHOLMOD_SIMPLICIAL) { - P3 ("%s", "(always do simplicial)\n") ; + P3 ("%s", "(always do simplicial)\n") ; } else if (Common->supernodal == CHOLMOD_AUTO) { - P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ; + P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ; } else { - P3 ("%s", "(always do supernodal)\n") ; + P3 ("%s", "(always do supernodal)\n") ; } nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ; @@ -319,197 +321,197 @@ static int check_common if (nmethods > 0) { - P3 ("%s", " nmethods: number of ordering methods to try: ") ; - P3 (""ID"\n", nmethods) ; + P3 ("%s", " nmethods: number of ordering methods to try: ") ; + P3 (""ID"\n", nmethods) ; amd_backup = (nmethods > 1) || (nmethods == 1 && (Common->method [0].ordering == CHOLMOD_METIS || Common->method [0].ordering == CHOLMOD_NESDIS)) ; } else { - P3 ("%s", " nmethods=0: default strategy: Try user permutation if " - "given. Try AMD.\n") ; -#ifndef NPARTITION - if (Common->default_nesdis) - { - P3 ("%s", " Try NESDIS if AMD reports flops/nnz(L) >= 500 and " - "nnz(L)/nnz(A) >= 5.\n") ; - } - else - { - P3 ("%s", " Try METIS if AMD reports flops/nnz(L) >= 500 and " - "nnz(L)/nnz(A) >= 5.\n") ; - } -#endif - P3 ("%s", " Select best ordering tried.\n") ; - Common->method [0].ordering = CHOLMOD_GIVEN ; - Common->method [1].ordering = CHOLMOD_AMD ; - Common->method [2].ordering = + P3 ("%s", " nmethods=0: default strategy: Try user permutation if " + "given. Try AMD.\n") ; + #ifndef NPARTITION + if (Common->default_nesdis) + { + P3 ("%s", " Try NESDIS if AMD reports flops/nnz(L) >= 500 and " + "nnz(L)/nnz(A) >= 5.\n") ; + } + else + { + P3 ("%s", " Try METIS if AMD reports flops/nnz(L) >= 500 and " + "nnz(L)/nnz(A) >= 5.\n") ; + } + #endif + P3 ("%s", " Select best ordering tried.\n") ; + Common->method [0].ordering = CHOLMOD_GIVEN ; + Common->method [1].ordering = CHOLMOD_AMD ; + Common->method [2].ordering = (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; amd_backup = FALSE ; -#ifndef NPARTITION - nmethods = 3 ; -#else - nmethods = 2 ; -#endif + #ifndef NPARTITION + nmethods = 3 ; + #else + nmethods = 2 ; + #endif } for (i = 0 ; i < nmethods ; i++) { - P3 (" method "ID": ", i) ; - ordering = Common->method [i].ordering ; - fl = Common->method [i].fl ; - lnz = Common->method [i].lnz ; - switch (ordering) - { - - case CHOLMOD_NATURAL: - P3 ("%s", "natural\n") ; - break ; - - case CHOLMOD_GIVEN: - P3 ("%s", "user permutation (if given)\n") ; - break ; - - case CHOLMOD_AMD: - P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; - amd_backup = FALSE ; - break ; - - case CHOLMOD_COLAMD: - P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n"); - amd_backup = FALSE ; - break ; - - case CHOLMOD_METIS: - P3 ("%s", "METIS_NodeND nested dissection\n") ; - break ; - - case CHOLMOD_NESDIS: - P3 ("%s", "CHOLMOD nested dissection\n") ; - - P3 (" nd_small: # nodes in uncut subgraph: "ID"\n", - (Int) (Common->method [i].nd_small)) ; - P3 (" nd_compress: compress the graph: %s\n", - BOOLSTR (Common->method [i].nd_compress)) ; - P3 (" nd_camd: use constrained min degree: %s\n", - BOOLSTR (Common->method [i].nd_camd)) ; - break ; - - default: - P3 (ID, ordering) ; - ERR ("unknown ordering method") ; - break ; - - } - - if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN)) - { - if (Common->method [i].prune_dense < 0) - { - P3 (" prune_dense: for pruning dense nodes: %s\n", - " none pruned") ; - } - else - { - P3 (" prune_dense: for pruning dense nodes: " - "%.5g\n", - Common->method [i].prune_dense) ; - P3 (" a dense node has degree " - ">= max(16,(%.5g)*sqrt(n))\n", - Common->method [i].prune_dense) ; - } - } - - if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS) - { - if (Common->method [i].prune_dense2 < 0) - { - P3 (" prune_dense2: for pruning dense rows for AA':" - " %s\n", " none pruned") ; - } - else - { - P3 (" prune_dense2: for pruning dense rows for AA':" - " %.5g\n", Common->method [i].prune_dense2) ; - P3 (" a dense row has degree " - ">= max(16,(%.5g)*sqrt(ncol))\n", - Common->method [i].prune_dense2) ; - } - } - - if (fl != EMPTY) P3 (" flop count: %.5g\n", fl) ; - if (lnz != EMPTY) P3 (" nnz(L): %.5g\n", lnz) ; - } - - /* backup AMD results, if any */ + P3 (" method "ID": ", i) ; + ordering = Common->method [i].ordering ; + fl = Common->method [i].fl ; + lnz = Common->method [i].lnz ; + switch (ordering) + { + + case CHOLMOD_NATURAL: + P3 ("%s", "natural\n") ; + break ; + + case CHOLMOD_GIVEN: + P3 ("%s", "user permutation (if given)\n") ; + break ; + + case CHOLMOD_AMD: + P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; + amd_backup = FALSE ; + break ; + + case CHOLMOD_COLAMD: + P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n"); + amd_backup = FALSE ; + break ; + + case CHOLMOD_METIS: + P3 ("%s", "METIS_NodeND nested dissection\n") ; + break ; + + case CHOLMOD_NESDIS: + P3 ("%s", "CHOLMOD nested dissection\n") ; + + P3 (" nd_small: # nodes in uncut subgraph: "ID"\n", + (Int) (Common->method [i].nd_small)) ; + P3 (" nd_compress: compress the graph: %s\n", + BOOLSTR (Common->method [i].nd_compress)) ; + P3 (" nd_camd: use constrained min degree: %s\n", + BOOLSTR (Common->method [i].nd_camd)) ; + break ; + + default: + P3 (ID, ordering) ; + ERR ("unknown ordering method") ; + break ; + + } + + if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN)) + { + if (Common->method [i].prune_dense < 0) + { + P3 (" prune_dense: for pruning dense nodes: %s\n", + " none pruned") ; + } + else + { + P3 (" prune_dense: for pruning dense nodes: " + "%.5g\n", + Common->method [i].prune_dense) ; + P3 (" a dense node has degree " + ">= max(16,(%.5g)*sqrt(n))\n", + Common->method [i].prune_dense) ; + } + } + + if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS) + { + if (Common->method [i].prune_dense2 < 0) + { + P3 (" prune_dense2: for pruning dense rows for AA':" + " %s\n", " none pruned") ; + } + else + { + P3 (" prune_dense2: for pruning dense rows for AA':" + " %.5g\n", Common->method [i].prune_dense2) ; + P3 (" a dense row has degree " + ">= max(16,(%.5g)*sqrt(ncol))\n", + Common->method [i].prune_dense2) ; + } + } + + if (fl != EMPTY) P3 (" flop count: %.5g\n", fl) ; + if (lnz != EMPTY) P3 (" nnz(L): %.5g\n", lnz) ; + } + + // backup AMD results, if any if (amd_backup) { - P3 ("%s", " backup method: ") ; - P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; - fl = Common->method [nmethods].fl ; - lnz = Common->method [nmethods].lnz ; - if (fl != EMPTY) P3 (" AMD flop count: %.5g\n", fl) ; - if (lnz != EMPTY) P3 (" AMD nnz(L): %.5g\n", lnz) ; + P3 ("%s", " backup method: ") ; + P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; + fl = Common->method [nmethods].fl ; + lnz = Common->method [nmethods].lnz ; + if (fl != EMPTY) P3 (" AMD flop count: %.5g\n", fl) ; + if (lnz != EMPTY) P3 (" AMD nnz(L): %.5g\n", lnz) ; } - /* ---------------------------------------------------------------------- */ - /* arcane control parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // arcane control parameters + //-------------------------------------------------------------------------- if (Common->final_asis) { - P4 ("%s", " final_asis: TRUE, leave as is\n") ; + P4 ("%s", " final_asis: TRUE, leave as is\n") ; } else { - P4 ("%s", " final_asis: FALSE, convert when done\n") ; - if (Common->final_super) - { - P4 ("%s", " final_super: TRUE, leave in supernodal form\n") ; - } - else - { - P4 ("%s", " final_super: FALSE, convert to simplicial form\n") ; - } - if (Common->final_ll) - { - P4 ("%s", " final_ll: TRUE, convert to LL' form\n") ; - } - else - { - P4 ("%s", " final_ll: FALSE, convert to LDL' form\n") ; - } - if (Common->final_pack) - { - P4 ("%s", " final_pack: TRUE, pack when done\n") ; - } - else - { - P4 ("%s", " final_pack: FALSE, do not pack when done\n") ; - } - if (Common->final_monotonic) - { - P4 ("%s", " final_monotonic: TRUE, ensure L is monotonic\n") ; - } - else - { - P4 ("%s", - " final_monotonic: FALSE, do not ensure L is monotonic\n") ; - } - P4 (" final_resymbol: remove zeros from amalgamation: %s\n", - BOOLSTR (Common->final_resymbol)) ; + P4 ("%s", " final_asis: FALSE, convert when done\n") ; + if (Common->final_super) + { + P4 ("%s", " final_super: TRUE, leave in supernodal form\n") ; + } + else + { + P4 ("%s", " final_super: FALSE, convert to simplicial form\n") ; + } + if (Common->final_ll) + { + P4 ("%s", " final_ll: TRUE, convert to LL' form\n") ; + } + else + { + P4 ("%s", " final_ll: FALSE, convert to LDL' form\n") ; + } + if (Common->final_pack) + { + P4 ("%s", " final_pack: TRUE, pack when done\n") ; + } + else + { + P4 ("%s", " final_pack: FALSE, do not pack when done\n") ; + } + if (Common->final_monotonic) + { + P4 ("%s", " final_monotonic: TRUE, ensure L is monotonic\n") ; + } + else + { + P4 ("%s", + " final_monotonic: FALSE, do not ensure L is monotonic\n") ; + } + P4 (" final_resymbol: remove zeros from amalgamation: %s\n", + BOOLSTR (Common->final_resymbol)) ; } P4 (" dbound: LDL' diagonal threshold: % .5g\n Entries with abs. value" - " less than dbound are replaced with +/- dbound.\n" + " less than dbound are replaced with +/- dbound.\n" " (for double precision case)\n", - Common->dbound) ; + Common->dbound) ; P4 (" sbound: LDL' diagonal threshold: % .5g\n Entries with abs. value" - " less than sbound are replaced with +/- sbound.\n" + " less than sbound are replaced with +/- sbound.\n" " (for single precision case)\n", - Common->sbound) ; + Common->sbound) ; P4 (" grow0: memory reallocation: % .5g\n", Common->grow0) ; P4 (" grow1: memory reallocation: % .5g\n", Common->grow1) ; @@ -520,16 +522,16 @@ static int check_common P4 ("%s", " z = % of zeros in new supernode if they are merged.\n") ; P4 ("%s", " Two supernodes are merged if") ; P4 (" (s <= %g) or (no new zero entries) or\n", - (double) (Common->nrelax [0])) ; + (double) (Common->nrelax [0])) ; P4 (" (s <= %g and ", (double) (Common->nrelax [1])) ; P4 ("z < %.5g%%) or", Common->zrelax [0] * 100) ; P4 (" (s <= %g and ", (double) (Common->nrelax [2])) ; P4 ("z < %.5g%%) or", Common->zrelax [1] * 100) ; P4 (" (z < %.5g%%)\n", Common->zrelax [2] * 100) ; - /* ---------------------------------------------------------------------- */ - /* check workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check workspace + //-------------------------------------------------------------------------- mark = Common->mark ; nrow = Common->nrow ; @@ -537,53 +539,52 @@ static int check_common Head = Common->Head ; if (nrow > 0) { - if (mark < 0 || Flag == NULL || Head == NULL) - { - ERR ("workspace corrupted (Flag and/or Head missing)") ; - } - for (i = 0 ; i < nrow ; i++) - { - if (Flag [i] >= mark) - { - PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ; - ERR ("workspace corrupted (Flag)") ; - } - } - for (i = 0 ; i <= nrow ; i++) - { - if (Head [i] != EMPTY) - { - PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ; - ERR ("workspace corrupted (Head)") ; - } - } - } - - xworksize = Common->xworkbytes ; - Xwork = Common->Xwork ; - if (xworksize > 0) - { - if (Xwork == NULL) - { - ERR ("workspace corrupted (Xwork missing)") ; - } - for (i = 0 ; i < xworksize ; i++) - { - if (Xwork [i] != 0.) - { - PRINT0 (("Xwork ["ID"] = %d\n", i, Xwork [i])) ; - ERR ("workspace corrupted (Xwork)") ; - } - } - } - - /* workspace and parameters are valid */ + if (mark < 0 || Flag == NULL || Head == NULL) + { + ERR ("workspace corrupted (Flag and/or Head missing)") ; + } + for (i = 0 ; i < nrow ; i++) + { + if (Flag [i] >= mark) + { + PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ; + ERR ("workspace corrupted (Flag)") ; + } + } + for (i = 0 ; i <= nrow ; i++) + { + if (Head [i] != EMPTY) + { + PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ; + ERR ("workspace corrupted (Head)") ; + } + } + } + + size_t xworkbytes = Common->xworkbytes ; + uint8_t *Xwork = Common->Xwork ; + if (xworkbytes > 0) + { + if (Xwork == NULL) + { + ERR ("workspace corrupted (Xwork missing)") ; + } + for (i = 0 ; i < xworkbytes ; i++) + { + if (Xwork [i] != 0.) + { + PRINT0 (("Xwork ["ID"] = %d\n", i, Xwork [i])) ; + ERR ("workspace corrupted (Xwork)") ; + } + } + } + + // workspace and parameters are valid P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - int CHOLMOD(check_common) ( cholmod_common *Common @@ -592,56 +593,65 @@ int CHOLMOD(check_common) return (check_common (0, NULL, Common)) ; } - int CHOLMOD(print_common) ( - /* ---- input ---- */ - const char *name, /* printed name of Common object */ - /* --------------- */ + // input: + const char *name, // printed name of Common object cholmod_common *Common ) { - Int print = (Common == NULL) ? 3 : (Common->print) ; + int print = (Common == NULL) ? 3 : (Common->print) ; return (check_common (print, name, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_gpu_stats +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_gpu_stats ==================================================== */ -/* ========================================================================== */ - -/* Print CPU / GPU statistics. If the timer is not installed, the times are - reported as zero, but this function still works. Likewise, the function - still works if the GPU BLAS is not installed. */ +// Print CPU / GPU statistics. If the timer is not installed, the times are +// reported as zero, but this function still works. Likewise, the function +// still works if the GPU BLAS is not installed. int CHOLMOD(gpu_stats) ( - cholmod_common *Common /* input */ + cholmod_common *Common // input ) { - double cpu_time, gpu_time ; - int print ; - RETURN_IF_NULL_COMMON (FALSE) ; - print = Common->print ; +#ifdef BLAS_TIMER + int print = Common->print ; + double cpu_time, gpu_time ; + + #ifdef SUITESPARSE_CUDA P2 ("%s", "\nCHOLMOD GPU/CPU statistics:\n") ; + #else + P2 ("%s", "\nCHOLMOD BLAS statistics:\n") ; + #endif P2 ("SYRK CPU calls %12.0f", (double) Common->CHOLMOD_CPU_SYRK_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_CPU_SYRK_TIME) ; + #ifdef SUITESPARSE_CUDA P2 (" GPU calls %12.0f", (double) Common->CHOLMOD_GPU_SYRK_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_GPU_SYRK_TIME) ; + #endif P2 ("GEMM CPU calls %12.0f", (double) Common->CHOLMOD_CPU_GEMM_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_CPU_GEMM_TIME) ; + #ifdef SUITESPARSE_CUDA P2 (" GPU calls %12.0f", (double) Common->CHOLMOD_GPU_GEMM_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_GPU_GEMM_TIME) ; + #endif P2 ("POTRF CPU calls %12.0f", (double) Common->CHOLMOD_CPU_POTRF_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_CPU_POTRF_TIME) ; + #ifdef SUITESPARSE_CUDA P2 (" GPU calls %12.0f", (double) Common->CHOLMOD_GPU_POTRF_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_GPU_POTRF_TIME) ; + #endif P2 ("TRSM CPU calls %12.0f", (double) Common->CHOLMOD_CPU_TRSM_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_CPU_TRSM_TIME) ; + #ifdef SUITESPARSE_CUDA P2 (" GPU calls %12.0f", (double) Common->CHOLMOD_GPU_TRSM_CALLS) ; P2 (" time %12.4e\n", Common->CHOLMOD_GPU_TRSM_TIME) ; + #endif cpu_time = Common->CHOLMOD_CPU_SYRK_TIME + Common->CHOLMOD_CPU_TRSM_TIME + Common->CHOLMOD_CPU_GEMM_TIME + Common->CHOLMOD_CPU_POTRF_TIME ; @@ -649,56 +659,59 @@ int CHOLMOD(gpu_stats) gpu_time = Common->CHOLMOD_GPU_SYRK_TIME + Common->CHOLMOD_GPU_TRSM_TIME + Common->CHOLMOD_GPU_GEMM_TIME + Common->CHOLMOD_GPU_POTRF_TIME ; + #ifdef SUITESPARSE_CUDA P2 ("time in the BLAS: CPU %12.4e", cpu_time) ; P2 (" GPU %12.4e", gpu_time) ; P2 (" total: %12.4e\n", cpu_time + gpu_time) ; + #else + P2 ("total time in the BLAS: %12.4e\n", cpu_time) ; + #endif - P2 ("assembly time %12.4e", Common->CHOLMOD_ASSEMBLE_TIME) ; - P2 (" %12.4e\n", Common->CHOLMOD_ASSEMBLE_TIME2) ; +// P2 ("assembly time %12.4e", Common->CHOLMOD_ASSEMBLE_TIME) ; +// P2 (" %12.4e\n", Common->CHOLMOD_ASSEMBLE_TIME2) ; +#endif return (TRUE) ; } +//------------------------------------------------------------------------------ +// cholmod_check_sparse +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_sparse ================================================= */ -/* ========================================================================== */ - -/* Ensure that a sparse matrix in column-oriented form is valid, and optionally - * print it. Returns the number of entries on the diagonal or -1 if error. - * - * workspace: Iwork (nrow) - */ +// Ensure that a sparse matrix in column-oriented form is valid, and optionally +// print it. Returns the number of entries on the diagonal or -1 if error. +// +// workspace: Iwork (nrow) static int64_t check_sparse ( Int *Wi, - Int print, + int print, const char *name, cholmod_sparse *A, int64_t *nnzdiag, cholmod_common *Common ) { - double *Ax, *Az ; + void *Ax, *Az ; Int *Ap, *Ai, *Anz ; Int nrow, ncol, nzmax, sorted, packed, j, p, pend, i, nz, ilast, - init_print, dnz, count, xtype ; + init_print, dnz, count ; const char *type = "sparse" ; - /* ---------------------------------------------------------------------- */ - /* print header information */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print header information + //-------------------------------------------------------------------------- P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD sparse: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } if (A == NULL) { - ERR ("null") ; + ERR ("null") ; } nrow = A->nrow ; @@ -706,7 +719,8 @@ static int64_t check_sparse nzmax = A->nzmax ; sorted = A->sorted ; packed = A->packed ; - xtype = A->xtype ; + int xtype = A->xtype ; + int dtype = A->dtype ; Ap = A->p ; Ai = A->i ; Ax = A->x ; @@ -719,123 +733,122 @@ static int64_t check_sparse P3 ("nz "ID",", nz) ; if (A->stype > 0) { - P3 ("%s", " upper.") ; + P3 ("%s", " upper.") ; } else if (A->stype < 0) { - P3 ("%s", " lower.") ; + P3 ("%s", " lower.") ; } else { - P3 ("%s", " up/lo.") ; + P3 ("%s", " up/lo.") ; } P4 ("\n nzmax "ID", ", nzmax) ; if (nz > nzmax) { - ERR ("nzmax too small") ; + ERR ("nzmax too small") ; } if (!sorted) { - P4 ("%s", "un") ; + P4 ("%s", "un") ; } P4 ("%s", "sorted, ") ; if (!packed) { - P4 ("%s", "un") ; + P4 ("%s", "un") ; } P4 ("%s", "packed, ") ; switch (A->itype) { - case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; - case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, "); - break ; - default: ERR ("unknown itype") ; + case CHOLMOD_INT: P4 ("%s", "\n scalar types: int32_t, ") ; break ; + case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, ") ; break ; + default: ERR ("unknown itype") ; } switch (A->xtype) { - case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; - case CHOLMOD_REAL: P4 ("%s", "real") ; break ; - case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; - case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; - default: ERR ("unknown xtype") ; + case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; + case CHOLMOD_REAL: P4 ("%s", "real") ; break ; + case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; + case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; + default: ERR ("unknown xtype") ; } switch (A->dtype) { - case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; - case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; - default: ERR ("unknown dtype") ; + case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; + case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; + default: ERR ("unknown dtype") ; } if (A->itype != ITYPE) { - ERR ("integer type must match routine") ; + ERR ("integer type must match routine") ; } if (A->stype && nrow != ncol) { - ERR ("symmetric but not square") ; + ERR ("symmetric but not square") ; } - /* check for existence of Ap, Ai, Anz, Ax, and Az arrays */ + // check for existence of Ap, Ai, Anz, Ax, and Az arrays if (Ap == NULL) { - ERR ("p array not present") ; + ERR ("p array not present") ; } if (Ai == NULL) { - ERR ("i array not present") ; + ERR ("i array not present") ; } if (!packed && Anz == NULL) { - ERR ("nz array not present") ; + ERR ("nz array not present") ; } if (xtype != CHOLMOD_PATTERN && Ax == NULL) { - ERR ("x array not present") ; + ERR ("x array not present") ; } if (xtype == CHOLMOD_ZOMPLEX && Az == NULL) { - ERR ("z array not present") ; + ERR ("z array not present") ; } - /* packed matrices must start at Ap [0] = 0 */ + // packed matrices must start at Ap [0] = 0 if (packed && Ap [0] != 0) { - ERR ("p [0] must be zero") ; + ERR ("p [0] must be zero") ; } if (packed && (Ap [ncol] < Ap [0] || Ap [ncol] > nzmax)) { - ERR ("p [ncol] invalid") ; + ERR ("p [ncol] invalid") ; } - /* ---------------------------------------------------------------------- */ - /* allocate workspace if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace if needed + //-------------------------------------------------------------------------- if (!sorted) { - if (Wi == NULL) - { - CHOLMOD(allocate_work) (0, nrow, 0, Common) ; - Wi = Common->Iwork ; /* size nrow, (i/i/l) */ - } - if (Common->status < CHOLMOD_OK) - { - return (FALSE) ; /* out of memory */ - } - for (i = 0 ; i < nrow ; i++) - { - Wi [i] = EMPTY ; - } - } - - /* ---------------------------------------------------------------------- */ - /* check and print each column */ - /* ---------------------------------------------------------------------- */ + if (Wi == NULL) + { + CHOLMOD(allocate_work) (0, nrow, 0, Common) ; + Wi = Common->Iwork ; // size nrow + } + if (Common->status < CHOLMOD_OK) + { + return (FALSE) ; // out of memory + } + for (i = 0 ; i < nrow ; i++) + { + Wi [i] = EMPTY ; + } + } + + //-------------------------------------------------------------------------- + // check and print each column + //-------------------------------------------------------------------------- init_print = print ; dnz = 0 ; @@ -843,68 +856,66 @@ static int64_t check_sparse for (j = 0 ; j < ncol ; j++) { - ETC (j == ncol-1, count, 4) ; - p = Ap [j] ; - if (packed) - { - pend = Ap [j+1] ; - nz = pend - p ; - } - else - { - /* Note that Anz [j] < 0 is treated as zero */ - nz = MAX (0, Anz [j]) ; - pend = p + nz ; - } - P4 (" col "ID":", j) ; - P4 (" nz "ID"", nz) ; - P4 (" start "ID"", p) ; - P4 (" end "ID"", pend) ; - P4 ("%s", ":\n") ; - if (p < 0 || pend > nzmax) - { - ERR ("pointer invalid") ; - } - if (nz < 0 || nz > nrow) - { - ERR ("nz invalid") ; - } - ilast = EMPTY ; - - for ( ; p < pend ; p++) - { - ETC (j == ncol-1 && p >= pend-4, count, -1) ; - i = Ai [p] ; - P4 (" "I8":", i) ; - - print_value (print, xtype, Ax, Az, p, Common) ; - - if (i == j) - { - dnz++ ; - } - if (i < 0 || i >= nrow) - { - ERR ("row index out of range") ; - } - if (sorted && i <= ilast) - { - ERR ("row indices out of order") ; - } - if (!sorted && Wi [i] == j) - { - ERR ("duplicate row index") ; - } - P4 ("%s", "\n") ; - ilast = i ; - if (!sorted) - { - Wi [i] = j ; - } - } - } - - /* matrix is valid */ + ETC (j == ncol-1, count, 4) ; + p = Ap [j] ; + if (packed) + { + pend = Ap [j+1] ; + nz = pend - p ; + } + else + { + // Note that Anz [j] < 0 is treated as zero + nz = MAX (0, Anz [j]) ; + pend = p + nz ; + } + P4 (" col "ID":", j) ; + P4 (" nz "ID"", nz) ; + P4 (" start "ID"", p) ; + P4 (" end "ID"", pend) ; + P4 ("%s", ":\n") ; + if (p < 0 || pend > nzmax) + { + ERR ("pointer invalid") ; + } + if (nz < 0 || nz > nrow) + { + ERR ("nz invalid") ; + } + ilast = EMPTY ; + + for ( ; p < pend ; p++) + { + ETC (j == ncol-1 && p >= pend-4, count, -1) ; + i = Ai [p] ; + P4 (" "I8":", i) ; + print_value (print, xtype, dtype, Ax, Az, p, Common) ; + if (i == j) + { + dnz++ ; + } + if (i < 0 || i >= nrow) + { + ERR ("row index out of range") ; + } + if (sorted && i <= ilast) + { + ERR ("row indices out of order") ; + } + if (!sorted && Wi [i] == j) + { + ERR ("duplicate row index") ; + } + P4 ("%s", "\n") ; + ilast = i ; + if (!sorted) + { + Wi [i] = j ; + } + } + } + + // matrix is valid P4 (" nnz on diagonal: "ID"\n", dnz) ; P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; @@ -912,12 +923,10 @@ static int64_t check_sparse return (TRUE) ; } - int CHOLMOD(check_sparse) ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to check */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to check cholmod_common *Common ) { @@ -927,13 +936,11 @@ int CHOLMOD(check_sparse) return (check_sparse (NULL, 0, NULL, A, &nnzdiag, Common)) ; } - int CHOLMOD(print_sparse) ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to print */ - const char *name, /* printed name of sparse matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to print + const char *name, // printed name of sparse matrix cholmod_common *Common ) { @@ -943,39 +950,38 @@ int CHOLMOD(print_sparse) return (check_sparse (NULL, Common->print, name, A, &nnzdiag, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_check_dense +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_dense ================================================== */ -/* ========================================================================== */ - -/* Ensure a dense matrix is valid, and optionally print it. */ +// Ensure a dense matrix is valid, and optionally print it. static int check_dense ( - Int print, + int print, const char *name, cholmod_dense *X, cholmod_common *Common ) { - double *Xx, *Xz ; - Int i, j, d, nrow, ncol, nzmax, nz, init_print, count, xtype ; + void *Xx, *Xz ; + Int i, j, d, nrow, ncol, nzmax, nz, init_print, count ; const char *type = "dense" ; - /* ---------------------------------------------------------------------- */ - /* print header information */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print header information + //-------------------------------------------------------------------------- P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD dense: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } if (X == NULL) { - ERR ("null") ; + ERR ("null") ; } nrow = X->nrow ; @@ -984,7 +990,8 @@ static int check_dense d = X->d ; Xx = X->x ; Xz = X->z ; - xtype = X->xtype ; + int xtype = X->xtype ; + int dtype = X->dtype ; P3 (" "ID"", nrow) ; P3 ("-by-"ID", ", ncol) ; @@ -992,70 +999,66 @@ static int check_dense P4 ("nzmax "ID", ", nzmax) ; if (d * ncol > nzmax) { - ERR ("nzmax too small") ; + ERR ("nzmax too small") ; } if (d < nrow) { - ERR ("leading dimension must be >= # of rows") ; + ERR ("leading dimension must be >= # of rows") ; } if (Xx == NULL) { - ERR ("null") ; + ERR ("null") ; } switch (X->xtype) { - case CHOLMOD_PATTERN: ERR ("pattern unsupported") ; break ; - case CHOLMOD_REAL: P4 ("%s", "real") ; break ; - case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; - case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; - default: ERR ("unknown xtype") ; + case CHOLMOD_PATTERN: ERR ("pattern unsupported") ; break ; + case CHOLMOD_REAL: P4 ("%s", "real") ; break ; + case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; + case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; + default: ERR ("unknown xtype") ; } switch (X->dtype) { - case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; - case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; - default: ERR ("unknown dtype") ; + case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; + case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; + default: ERR ("unknown dtype") ; } - /* ---------------------------------------------------------------------- */ - /* check and print each entry */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check and print each entry + //-------------------------------------------------------------------------- if (print >= 4) { - init_print = print ; - ETC_START (count, 9) ; - nz = nrow * ncol ; - for (j = 0 ; j < ncol ; j++) - { - ETC (j == ncol-1, count, 5) ; - P4 (" col "ID":\n", j) ; - for (i = 0 ; i < nrow ; i++) - { - ETC (j == ncol-1 && i >= nrow-4, count, -1) ; - P4 (" "I8":", i) ; - - print_value (print, xtype, Xx, Xz, i+j*d, Common) ; - - P4 ("%s", "\n") ; - } - } - } - - /* dense is valid */ + init_print = print ; + ETC_START (count, 9) ; + nz = nrow * ncol ; + for (j = 0 ; j < ncol ; j++) + { + ETC (j == ncol-1, count, 5) ; + P4 (" col "ID":\n", j) ; + for (i = 0 ; i < nrow ; i++) + { + ETC (j == ncol-1 && i >= nrow-4, count, -1) ; + P4 (" "I8":", i) ; + print_value (print, xtype, dtype, Xx, Xz, i+j*d, Common) ; + P4 ("%s", "\n") ; + } + } + } + + // dense is valid P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - int CHOLMOD(check_dense) ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to check */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to check cholmod_common *Common ) { @@ -1064,13 +1067,11 @@ int CHOLMOD(check_dense) return (check_dense (0, NULL, X, Common)) ; } - int CHOLMOD(print_dense) ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to print */ - const char *name, /* printed name of dense matrix */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to print + const char *name, // printed name of dense matrix cholmod_common *Common ) { @@ -1079,29 +1080,27 @@ int CHOLMOD(print_dense) return (check_dense (Common->print, name, X, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_check_subset +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_subset ================================================= */ -/* ========================================================================== */ - -/* Ensure S (0:len-1) is a subset of 0:n-1. Duplicates are allowed. S may be - * NULL. A negative len denotes the set 0:n-1. - * - * To check the rset and cset for A(rset,cset), where nc and nr are the length - * of cset and rset respectively: - * - * cholmod_check_subset (cset, nc, A->ncol, Common) ; - * cholmod_check_subset (rset, nr, A->nrow, Common) ; - * - * workspace: none - */ +// Ensure S (0:len-1) is a subset of 0:n-1. Duplicates are allowed. S may be +// NULL. A negative len denotes the set 0:n-1. +// +// To check the rset and cset for A(rset,cset), where nc and nr are the length +// of cset and rset respectively: +// +// cholmod_check_subset (cset, nc, A->ncol, Common) ; +// cholmod_check_subset (rset, nr, A->nrow, Common) ; +// +// workspace: none static int check_subset ( Int *S, int64_t len, size_t n, - Int print, + int print, const char *name, cholmod_common *Common ) @@ -1113,71 +1112,69 @@ static int check_subset if (S == NULL) { - /* zero len denotes S = [ ], negative len denotes S = 0:n-1 */ - len = (len < 0) ? (-1) : 0 ; + // zero len denotes S = [ ], negative len denotes S = 0:n-1 + len = (len < 0) ? (-1) : 0 ; } P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD subset: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } P3 (" len: %ld ", len) ; if (len < 0) { - P3 ("%s", "(denotes 0:n-1) ") ; + P3 ("%s", "(denotes 0:n-1) ") ; } P3 ("n: "ID"", (Int) n) ; P4 ("%s", "\n") ; if (len <= 0 || S == NULL) { - P3 ("%s", " OK\n") ; - P4 ("%s", "\n") ; - return (TRUE) ; + P3 ("%s", " OK\n") ; + P4 ("%s", "\n") ; + return (TRUE) ; } if (print >= 4) { - ETC_START (count, 8) ; - for (k = 0 ; k < ((Int) len) ; k++) - { - ETC (k == ((Int) len) - 4, count, -1) ; - i = S [k] ; - P4 (" "I8":", k) ; - P4 (" "ID"\n", i) ; - if (i < 0 || i >= ((Int) n)) - { - ERR ("entry out range") ; - } - } + ETC_START (count, 8) ; + for (k = 0 ; k < ((Int) len) ; k++) + { + ETC (k == ((Int) len) - 4, count, -1) ; + i = S [k] ; + P4 (" "I8":", k) ; + P4 (" "ID"\n", i) ; + if (i < 0 || i >= ((Int) n)) + { + ERR ("entry out range") ; + } + } } else { - for (k = 0 ; k < ((Int) len) ; k++) - { - i = S [k] ; - if (i < 0 || i >= ((Int) n)) - { - ERR ("entry out range") ; - } - } + for (k = 0 ; k < ((Int) len) ; k++) + { + i = S [k] ; + if (i < 0 || i >= ((Int) n)) + { + ERR ("entry out range") ; + } + } } P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - int CHOLMOD(check_subset) ( - /* ---- input ---- */ - Int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array), or < 0 if 0:n-1 */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + Int *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array), or < 0 if 0:n-1 + size_t n, // 0:n-1 is valid range cholmod_common *Common ) { @@ -1186,15 +1183,13 @@ int CHOLMOD(check_subset) return (check_subset (Set, len, n, 0, NULL, Common)) ; } - int CHOLMOD(print_subset) ( - /* ---- input ---- */ - Int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array), or < 0 if 0:n-1 */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Set */ - /* --------------- */ + // input: + Int *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array), or < 0 if 0:n-1 + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Set cholmod_common *Common ) { @@ -1203,29 +1198,27 @@ int CHOLMOD(print_subset) return (check_subset (Set, len, n, Common->print, name, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_check_perm +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_perm =================================================== */ -/* ========================================================================== */ - -/* Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1. Perm - * may be NULL, which is interpreted as the identity permutation. There can - * be no duplicate entries (len must be <= n). - * - * If n <= Common->nrow, then this routine takes O(len) time and does not - * allocate any memory, by using Common->Flag. Otherwise, it takes O(n) time - * and ensures that Common->Iwork is at least n*sizeof(Int) in size. - * - * To check the fset: cholmod_check_perm (fset, fsize, ncol, Common) ; - * To check a permutation: cholmod_check_perm (Perm, n, n, Common) ; - * - * workspace: Flag (n) if n <= Common->nrow, Iwork (n) otherwise. - */ +// Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1. Perm +// may be NULL, which is interpreted as the identity permutation. There can +// be no duplicate entries (len must be <= n). +// +// If n <= Common->nrow, then this routine takes O(len) time and does not +// allocate any memory, by using Common->Flag. Otherwise, it takes O(n) time +// and ensures that Common->Iwork is at least n*sizeof(Int) in size. +// +// To check the fset: cholmod_check_perm (fset, fsize, ncol, Common) ; +// To check a permutation: cholmod_check_perm (Perm, n, n, Common) ; +// +// workspace: Flag (n) if n <= Common->nrow, Iwork (n) otherwise. static int check_perm ( Int *Wi, - Int print, + int print, const char *name, Int *Perm, size_t len, @@ -1237,118 +1230,117 @@ static int check_perm Int i, k, mark, init_print, count ; const char *type = "perm" ; - /* ---------------------------------------------------------------------- */ - /* checks that take O(1) time */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // checks that take O(1) time + //-------------------------------------------------------------------------- if (Perm == NULL || n == 0) { - /* Perm is valid implicit identity, or empty */ - return (TRUE) ; + // Perm is valid implicit identity, or empty + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* checks that take O(n) time or require memory allocation */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // checks that take O(n) time or require memory allocation + //-------------------------------------------------------------------------- init_print = print ; ETC_START (count, 8) ; if (Wi == NULL && n <= Common->nrow) { - /* use the Common->Flag array if it's big enough */ - mark = CHOLMOD(clear_flag) (Common) ; - Flag = Common->Flag ; - ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ; - if (print >= 4) - { - for (k = 0 ; k < ((Int) len) ; k++) - { - ETC (k >= ((Int) len) - 4, count, -1) ; - i = Perm [k] ; - P4 (" "I8":", k) ; - P4 (""ID"\n", i) ; - if (i < 0 || i >= ((Int) n) || Flag [i] == mark) - { - CHOLMOD(clear_flag) (Common) ; - ERR ("invalid permutation") ; - } - Flag [i] = mark ; - } - } - else - { - for (k = 0 ; k < ((Int) len) ; k++) - { - i = Perm [k] ; - if (i < 0 || i >= ((Int) n) || Flag [i] == mark) - { - CHOLMOD(clear_flag) (Common) ; - ERR ("invalid permutation") ; - } - Flag [i] = mark ; - } - } - CHOLMOD(clear_flag) (Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ; + // use the Common->Flag array if it's big enough + mark = CHOLMOD(clear_flag) (Common) ; + Flag = Common->Flag ; + ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, 0, Common)) ; + if (print >= 4) + { + for (k = 0 ; k < ((Int) len) ; k++) + { + ETC (k >= ((Int) len) - 4, count, -1) ; + i = Perm [k] ; + P4 (" "I8":", k) ; + P4 (""ID"\n", i) ; + if (i < 0 || i >= ((Int) n) || Flag [i] == mark) + { + CHOLMOD(clear_flag) (Common) ; + ERR ("invalid permutation") ; + } + Flag [i] = mark ; + } + } + else + { + for (k = 0 ; k < ((Int) len) ; k++) + { + i = Perm [k] ; + if (i < 0 || i >= ((Int) n) || Flag [i] == mark) + { + CHOLMOD(clear_flag) (Common) ; + ERR ("invalid permutation") ; + } + Flag [i] = mark ; + } + } + CHOLMOD(clear_flag) (Common) ; + ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, 0, Common)) ; } else { - if (Wi == NULL) - { - /* use Common->Iwork instead, but initialize it first */ - CHOLMOD(allocate_work) (0, n, 0, Common) ; - Wi = Common->Iwork ; /* size n, (i/i/i) is OK */ - } - if (Common->status < CHOLMOD_OK) - { - return (FALSE) ; /* out of memory */ - } - for (i = 0 ; i < ((Int) n) ; i++) - { - Wi [i] = FALSE ; - } - if (print >= 4) - { - for (k = 0 ; k < ((Int) len) ; k++) - { - ETC (k >= ((Int) len) - 4, count, -1) ; - i = Perm [k] ; - P4 (" "I8":", k) ; - P4 (""ID"\n", i) ; - if (i < 0 || i >= ((Int) n) || Wi [i]) - { - ERR ("invalid permutation") ; - } - Wi [i] = TRUE ; - } - } - else - { - for (k = 0 ; k < ((Int) len) ; k++) - { - i = Perm [k] ; - if (i < 0 || i >= ((Int) n) || Wi [i]) - { - ERR ("invalid permutation") ; - } - Wi [i] = TRUE ; - } - } - } - - /* perm is valid */ + if (Wi == NULL) + { + // use Common->Iwork instead, but initialize it first + CHOLMOD(allocate_work) (0, n, 0, Common) ; + Wi = Common->Iwork ; // size n + } + if (Common->status < CHOLMOD_OK) + { + return (FALSE) ; // out of memory + } + for (i = 0 ; i < ((Int) n) ; i++) + { + Wi [i] = FALSE ; + } + if (print >= 4) + { + for (k = 0 ; k < ((Int) len) ; k++) + { + ETC (k >= ((Int) len) - 4, count, -1) ; + i = Perm [k] ; + P4 (" "I8":", k) ; + P4 (""ID"\n", i) ; + if (i < 0 || i >= ((Int) n) || Wi [i]) + { + ERR ("invalid permutation") ; + } + Wi [i] = TRUE ; + } + } + else + { + for (k = 0 ; k < ((Int) len) ; k++) + { + i = Perm [k] ; + if (i < 0 || i >= ((Int) n) || Wi [i]) + { + ERR ("invalid permutation") ; + } + Wi [i] = TRUE ; + } + } + } + + // perm is valid return (TRUE) ; } int CHOLMOD(check_perm) ( - /* ---- input ---- */ - Int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + Int *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range cholmod_common *Common ) { @@ -1360,12 +1352,11 @@ int CHOLMOD(check_perm) int CHOLMOD(print_perm) ( - /* ---- input ---- */ - Int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Perm */ - /* --------------- */ + // input: + Int *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Perm cholmod_common *Common ) { @@ -1377,7 +1368,7 @@ int CHOLMOD(print_perm) P3 ("%s", "CHOLMOD perm: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } P3 (" len: "ID"", (Int) len) ; P3 (" n: "ID"", (Int) n) ; @@ -1385,31 +1376,29 @@ int CHOLMOD(print_perm) ok = check_perm (NULL, print, name, Perm, len, n, Common) ; if (ok) { - P3 ("%s", " OK\n") ; - P4 ("%s", "\n") ; + P3 ("%s", " OK\n") ; + P4 ("%s", "\n") ; } return (ok) ; } +//------------------------------------------------------------------------------ +// cholmod_check_parent +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_parent ================================================= */ -/* ========================================================================== */ - -/* Ensure that Parent is a valid elimination tree of nodes 0 to n-1. - * If j is a root of the tree then Parent [j] is EMPTY (-1). - * - * NOTE: this check will fail if applied to the component tree (CParent) in - * cholmod_nested_dissection, unless it has been postordered and renumbered. - * - * workspace: none - */ +// Ensure that Parent is a valid elimination tree of nodes 0 to n-1. +// If j is a root of the tree then Parent [j] is EMPTY (-1). +// +// NOTE: this check will fail if applied to the component tree (CParent) in +// cholmod_nested_dissection, unless it has been postordered and renumbered. +// +// workspace: none static int check_parent ( Int *Parent, size_t n, - Int print, + int print, const char *name, cholmod_common *Common ) @@ -1423,7 +1412,7 @@ static int check_parent P3 ("%s", "CHOLMOD parent: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } P3 (" n: "ID"", (Int) n) ; @@ -1431,37 +1420,35 @@ static int check_parent if (Parent == NULL) { - ERR ("null") ; + ERR ("null") ; } - /* ---------------------------------------------------------------------- */ - /* checks that take O(n) time */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // checks that take O(n) time + //-------------------------------------------------------------------------- ETC_START (count, 8) ; for (j = 0 ; j < ((Int) n) ; j++) { - ETC (j == ((Int) n) - 4, count, -1) ; - p = Parent [j] ; - P4 (" "I8":", j) ; - P4 (" "ID"\n", p) ; - if (!(p == EMPTY || p > j)) - { - ERR ("invalid") ; - } + ETC (j == ((Int) n) - 4, count, -1) ; + p = Parent [j] ; + P4 (" "I8":", j) ; + P4 (" "ID"\n", p) ; + if (!(p == EMPTY || p > j)) + { + ERR ("invalid") ; + } } P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - int CHOLMOD(check_parent) ( - /* ---- input ---- */ - Int *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - /* --------------- */ + // input: + Int *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent cholmod_common *Common ) { @@ -1470,14 +1457,12 @@ int CHOLMOD(check_parent) return (check_parent (Parent, n, 0, NULL, Common)) ; } - int CHOLMOD(print_parent) ( - /* ---- input ---- */ - Int *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - const char *name, /* printed name of Parent */ - /* --------------- */ + // input: + Int *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent + const char *name, // printed name of Parent cholmod_common *Common ) { @@ -1486,50 +1471,50 @@ int CHOLMOD(print_parent) return (check_parent (Parent, n, Common->print, name, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_check_factor ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_check_factor +//------------------------------------------------------------------------------ static int check_factor ( Int *Wi, - Int print, + int print, const char *name, cholmod_factor *L, cholmod_common *Common ) { - double *Lx, *Lz ; + void *Lx, *Lz ; Int *Lp, *Li, *Lnz, *Lnext, *Lprev, *Perm, *ColCount, *Lpi, *Lpx, *Super, - *Ls ; + *Ls ; Int n, nzmax, j, p, pend, i, nz, ordering, space, is_monotonic, minor, - count, precise, init_print, ilast, lnz, head, tail, jprev, plast, - jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, - ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii, xtype ; + count, precise, init_print, ilast, lnz, head, tail, jprev, plast, + jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, + ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii ; Int check_Lpx ; const char *type = "factor" ; - /* ---------------------------------------------------------------------- */ - /* print header information */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print header information + //-------------------------------------------------------------------------- P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD factor: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } if (L == NULL) { - ERR ("null") ; + ERR ("null") ; } n = L->n ; minor = L->minor ; ordering = L->ordering ; - xtype = L->xtype ; + int xtype = L->xtype ; + int dtype = L->dtype ; Perm = L->Perm ; ColCount = L->ColCount ; @@ -1542,69 +1527,68 @@ static int check_factor if (minor < n) { - P3 (" not positive definite (column "ID")", minor) ; + P3 (" not positive definite (column "ID")", minor) ; } switch (L->itype) { - case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; - case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, "); - break ; - default: ERR ("unknown itype") ; + case CHOLMOD_INT: P4 ("%s", "\n scalar types: int32_t, ") ; break ; + case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, ") ; break ; + default: ERR ("unknown itype") ; } switch (L->xtype) { - case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; - case CHOLMOD_REAL: P4 ("%s", "real") ; break ; - case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; - case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; - default: ERR ("unknown xtype") ; + case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; + case CHOLMOD_REAL: P4 ("%s", "real") ; break ; + case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; + case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; + default: ERR ("unknown xtype") ; } switch (L->dtype) { - case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; - case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; - default: ERR ("unknown dtype") ; + case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; + case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; + default: ERR ("unknown dtype") ; } if (L->itype != ITYPE) { - ERR ("integer type must match routine") ; + ERR ("integer type must match routine") ; } if (L->is_super) { - P3 ("%s", " supernodal") ; + P3 ("%s", " supernodal") ; } else { - P3 ("%s", " simplicial") ; + P3 ("%s", " simplicial") ; } if (L->is_ll) { - P3 ("%s", ", LL'.") ; + P3 ("%s", ", LL'.") ; } else { - P3 ("%s", ", LDL'.") ; + P3 ("%s", ", LDL'.") ; } P4 ("%s", "\n ordering method used: ") ; switch (L->ordering) { - case CHOLMOD_POSTORDERED:P4 ("%s", "natural (postordered)") ; break ; - case CHOLMOD_NATURAL: P4 ("%s", "natural") ; break ; - case CHOLMOD_GIVEN: P4 ("%s", "user-provided") ; break ; - case CHOLMOD_AMD: P4 ("%s", "AMD") ; break ; - case CHOLMOD_COLAMD: P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ; -#ifndef NPARTITION - case CHOLMOD_METIS: P4 ("%s", "METIS NodeND") ; break ; - case CHOLMOD_NESDIS: P4 ("%s", "CHOLMOD nested dissection") ; break ; -#endif - default: ERR ("unknown ordering") ; + case CHOLMOD_POSTORDERED:P4("%s", "natural (postordered)") ; break ; + case CHOLMOD_NATURAL: P4 ("%s", "natural") ; break ; + case CHOLMOD_GIVEN: P4 ("%s", "user-provided") ; break ; + case CHOLMOD_AMD: P4 ("%s", "AMD") ; break ; + case CHOLMOD_COLAMD: P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ; + #ifndef NPARTITION + case CHOLMOD_METIS: P4 ("%s", "METIS NodeND") ; break ; + case CHOLMOD_NESDIS: P4 ("%s", "CHOLMOD nested dissection") ; break ; + #endif + default: ERR ("unknown ordering") ; } P4 ("%s", "\n") ; @@ -1613,306 +1597,306 @@ static int check_factor if (L->is_super && L->xtype == CHOLMOD_ZOMPLEX) { - ERR ("Supernodal zomplex L not supported") ; + ERR ("Supernodal zomplex L not supported") ; } - /* ---------------------------------------------------------------------- */ - /* check L->Perm */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check L->Perm + //-------------------------------------------------------------------------- if (!check_perm (Wi, print, name, Perm, n, n, Common)) { - return (FALSE) ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* check L->ColCount */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check L->ColCount + //-------------------------------------------------------------------------- if (ColCount == NULL) { - ERR ("ColCount vector invalid") ; + ERR ("ColCount vector invalid") ; } ETC_START (count, 8) ; for (j = 0 ; j < n ; j++) { - ETC (j >= n-4, count, -1) ; - P4 (" col: "ID" ", j) ; - nz = ColCount [j] ; - P4 ("colcount: "ID"\n", nz) ; - if (nz < 0 || nz > n-j) - { - ERR ("ColCount out of range") ; - } + ETC (j >= n-4, count, -1) ; + P4 (" col: "ID" ", j) ; + nz = ColCount [j] ; + P4 ("colcount: "ID"\n", nz) ; + if (nz < 0 || nz > n-j) + { + ERR ("ColCount out of range") ; + } } - /* ---------------------------------------------------------------------- */ - /* check factor */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check factor + //-------------------------------------------------------------------------- if (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) { - /* ------------------------------------------------------------------ */ - /* check simplicial symbolic factor */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // check simplicial symbolic factor + //---------------------------------------------------------------------- - /* nothing else to do */ ; + // nothing else to do + ; } else if (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) { - /* ------------------------------------------------------------------ */ - /* check simplicial numerical factor */ - /* ------------------------------------------------------------------ */ - - P4 ("monotonic: %d\n", L->is_monotonic) ; - nzmax = L->nzmax ; - P3 (" nzmax "ID".", nzmax) ; - P4 ("%s", "\n") ; - Lp = L->p ; - Li = L->i ; - Lx = L->x ; - Lz = L->z ; - Lnz = L->nz ; - Lnext = L->next ; - Lprev = L->prev ; - - /* check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays */ - if (Lp == NULL) - { - ERR ("p array not present") ; - } - if (Li == NULL) - { - ERR ("i array not present") ; - } - if (Lnz == NULL) - { - ERR ("nz array not present") ; - } - if (Lx == NULL) - { - ERR ("x array not present") ; - } - if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL) - { - ERR ("z array not present") ; - } - if (Lnext == NULL) - { - ERR ("next array not present") ; - } - if (Lprev == NULL) - { - ERR ("prev array not present") ; - } - - ETC_START (count, 8) ; - - /* check each column of L */ - plast = 0 ; - is_monotonic = TRUE ; - for (j = 0 ; j < n ; j++) - { - ETC (j >= n-3, count, -1) ; - p = Lp [j] ; - nz = Lnz [j] ; - pend = p + nz ; - lnz += nz ; - - P4 (" col "ID":", j) ; - P4 (" nz "ID"", nz) ; - P4 (" start "ID"", p) ; - P4 (" end "ID"", pend) ; - - if (Lnext [j] < 0 || Lnext [j] > n) - { - ERR ("invalid link list") ; - } - space = Lp [Lnext [j]] - p ; - - P4 (" space "ID"", space) ; - P4 (" free "ID":\n", space - nz) ; - - if (p < 0 || pend > nzmax || space < 1) - { - ERR ("pointer invalid") ; - } - if (nz < 1 || nz > (n-j) || nz > space) - { - ERR ("nz invalid") ; - } - ilast = j-1 ; - - if (p < plast) - { - is_monotonic = FALSE ; - } - plast = p ; - - i = Li [p] ; - P4 (" "I8":", i) ; - if (i != j) - { - ERR ("diagonal missing") ; - } - - print_value (print, xtype, Lx, Lz, p, Common) ; - - P4 ("%s", "\n") ; - ilast = j ; - for (p++ ; p < pend ; p++) - { - ETC_DISABLE (count) ; - i = Li [p] ; - P4 (" "I8":", i) ; - if (i < j || i >= n) - { - ERR ("row index out of range") ; - } - if (i <= ilast) - { - ERR ("row indices out of order") ; - } - - print_value (print, xtype, Lx, Lz, p, Common) ; - - P4 ("%s", "\n") ; - ilast = i ; - } - } - - if (L->is_monotonic && !is_monotonic) - { - ERR ("columns not monotonic") ; - } - - /* check the link list */ - head = n+1 ; - tail = n ; - j = head ; - jprev = EMPTY ; - count = 0 ; - for ( ; ; ) - { - if (j < 0 || j > n+1 || count > n+2) - { - ERR ("invalid link list") ; - } - jnext = Lnext [j] ; - if (j >= 0 && j < n) - { - if (jprev != Lprev [j]) - { - ERR ("invalid link list") ; - } - } - count++ ; - if (j == tail) - { - break ; - } - jprev = j ; - j = jnext ; - } - if (Lnext [tail] != EMPTY || count != n+2) - { - ERR ("invalid link list") ; - } + //---------------------------------------------------------------------- + // check simplicial numerical factor + //---------------------------------------------------------------------- + + P4 ("monotonic: %d\n", L->is_monotonic) ; + nzmax = L->nzmax ; + P3 (" nzmax "ID".", nzmax) ; + P4 ("%s", "\n") ; + Lp = L->p ; + Li = L->i ; + Lx = L->x ; + Lz = L->z ; + Lnz = L->nz ; + Lnext = L->next ; + Lprev = L->prev ; + + // check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays + if (Lp == NULL) + { + ERR ("p array not present") ; + } + if (Li == NULL) + { + ERR ("i array not present") ; + } + if (Lnz == NULL) + { + ERR ("nz array not present") ; + } + if (Lx == NULL) + { + ERR ("x array not present") ; + } + if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL) + { + ERR ("z array not present") ; + } + if (Lnext == NULL) + { + ERR ("next array not present") ; + } + if (Lprev == NULL) + { + ERR ("prev array not present") ; + } + + ETC_START (count, 8) ; + + // check each column of L + plast = 0 ; + is_monotonic = TRUE ; + for (j = 0 ; j < n ; j++) + { + ETC (j >= n-3, count, -1) ; + p = Lp [j] ; + nz = Lnz [j] ; + pend = p + nz ; + lnz += nz ; + + P4 (" col "ID":", j) ; + P4 (" nz "ID"", nz) ; + P4 (" start "ID"", p) ; + P4 (" end "ID"", pend) ; + + if (Lnext [j] < 0 || Lnext [j] > n) + { + ERR ("invalid link list") ; + } + space = Lp [Lnext [j]] - p ; + + P4 (" space "ID"", space) ; + P4 (" free "ID":\n", space - nz) ; + + if (p < 0 || pend > nzmax || space < 1) + { + ERR ("pointer invalid") ; + } + if (nz < 1 || nz > (n-j) || nz > space) + { + ERR ("nz invalid") ; + } + ilast = j-1 ; + + if (p < plast) + { + is_monotonic = FALSE ; + } + plast = p ; + + // print the diagonal entry + i = Li [p] ; + P4 (" "I8":", i) ; + if (i != j) + { + ERR ("diagonal missing") ; + } + print_value (print, xtype, dtype, Lx, Lz, p, Common) ; + + // print the off-diagonal entries + P4 ("%s", "\n") ; + ilast = j ; + for (p++ ; p < pend ; p++) + { + ETC_DISABLE (count) ; + i = Li [p] ; + P4 (" "I8":", i) ; + if (i < j || i >= n) + { + ERR ("row index out of range") ; + } + if (i <= ilast) + { + ERR ("row indices out of order") ; + } + print_value (print, xtype, dtype, Lx, Lz, p, Common) ; + P4 ("%s", "\n") ; + ilast = i ; + } + } + + if (L->is_monotonic && !is_monotonic) + { + ERR ("columns not monotonic") ; + } + + // check the link list + head = n+1 ; + tail = n ; + j = head ; + jprev = EMPTY ; + count = 0 ; + for ( ; ; ) + { + if (j < 0 || j > n+1 || count > n+2) + { + ERR ("invalid link list") ; + } + jnext = Lnext [j] ; + if (j >= 0 && j < n) + { + if (jprev != Lprev [j]) + { + ERR ("invalid link list") ; + } + } + count++ ; + if (j == tail) + { + break ; + } + jprev = j ; + j = jnext ; + } + if (Lnext [tail] != EMPTY || count != n+2) + { + ERR ("invalid link list") ; + } } else { - /* ------------------------------------------------------------------ */ - /* check supernodal numeric or symbolic factor */ - /* ------------------------------------------------------------------ */ - - nsuper = L->nsuper ; - ssize = L->ssize ; - xsize = L->xsize ; - maxcsize = L->maxcsize ; - maxesize = L->maxesize ; - Ls = L->s ; - Lpi = L->pi ; - Lpx = L->px ; - Super = L->super ; - Lx = L->x ; - ETC_START (count, 8) ; - - P4 (" ssize "ID" ", ssize) ; - P4 ("xsize "ID" ", xsize) ; - P4 ("maxcsize "ID" ", maxcsize) ; - P4 ("maxesize "ID"\n", maxesize) ; - - if (Ls == NULL) - { - ERR ("invalid: L->s missing") ; - } - if (Lpi == NULL) - { - ERR ("invalid: L->pi missing") ; - } - if (Lpx == NULL) - { - ERR ("invalid: L->px missing") ; - } - if (Super == NULL) - { - ERR ("invalid: L->super missing") ; - } - - if (L->xtype != CHOLMOD_PATTERN) - { - /* numerical supernodal factor */ - if (Lx == NULL) - { - ERR ("invalid: L->x missing") ; - } - if (Ls [0] == EMPTY) - { - ERR ("invalid: L->s not defined") ; - } - examine_super = TRUE ; - } - else - { - /* symbolic supernodal factor, but only if it has been computed */ - examine_super = (Ls [0] != EMPTY) ; - } - - if (examine_super) - { - if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize) - { - PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n", - Lpi [0], nsuper, Lpi [nsuper])) ; - ERR ("invalid: L->pi invalid") ; - } - - /* If Lpx [0] is 123456, then supernodes are present but - Lpx [0...nsuper] is not defined, so don't check it. This is - used in the non-GPU accelerated SPQR */ + //---------------------------------------------------------------------- + // check supernodal numeric or symbolic factor + //---------------------------------------------------------------------- + + nsuper = L->nsuper ; + ssize = L->ssize ; + xsize = L->xsize ; + maxcsize = L->maxcsize ; + maxesize = L->maxesize ; + Ls = L->s ; + Lpi = L->pi ; + Lpx = L->px ; + Super = L->super ; + Lx = L->x ; + ETC_START (count, 8) ; + + P4 (" ssize "ID" ", ssize) ; + P4 ("xsize "ID" ", xsize) ; + P4 ("maxcsize "ID" ", maxcsize) ; + P4 ("maxesize "ID"\n", maxesize) ; + + if (Ls == NULL) + { + ERR ("invalid: L->s missing") ; + } + if (Lpi == NULL) + { + ERR ("invalid: L->pi missing") ; + } + if (Lpx == NULL) + { + ERR ("invalid: L->px missing") ; + } + if (Super == NULL) + { + ERR ("invalid: L->super missing") ; + } + + if (L->xtype != CHOLMOD_PATTERN) + { + // numerical supernodal factor + if (Lx == NULL) + { + ERR ("invalid: L->x missing") ; + } + if (Ls [0] == EMPTY) + { + ERR ("invalid: L->s not defined") ; + } + examine_super = TRUE ; + } + else + { + // symbolic supernodal factor, but only if it has been computed + examine_super = (Ls [0] != EMPTY) ; + } + + if (examine_super) + { + if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize) + { + PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n", + Lpi [0], nsuper, Lpi [nsuper])) ; + ERR ("invalid: L->pi invalid") ; + } + + // If Lpx [0] is 123456, then supernodes are present but + // Lpx [0...nsuper] is not defined, so don't check it. This is + // used in the non-GPU accelerated SPQR check_Lpx = (Lpx [0] != 123456) ; - if (check_Lpx && (Lpx [0] != 0 || MAX (1, Lpx[nsuper]) != xsize)) - { - ERR ("invalid: L->px invalid") ; - } - - /* check and print each supernode */ - for (s = 0 ; s < nsuper ; s++) - { - k1 = Super [s] ; - k2 = Super [s+1] ; - psi = Lpi [s] ; - psend = Lpi [s+1] ; - nsrow = psend - psi ; - nscol = k2 - k1 ; - nsrow2 = nsrow - nscol ; - ps2 = psi + nscol ; + if (check_Lpx && (Lpx [0] != 0 || MAX (1, Lpx[nsuper]) != xsize)) + { + ERR ("invalid: L->px invalid") ; + } + + // check and print each supernode + for (s = 0 ; s < nsuper ; s++) + { + k1 = Super [s] ; + k2 = Super [s+1] ; + psi = Lpi [s] ; + psend = Lpi [s+1] ; + nsrow = psend - psi ; + nscol = k2 - k1 ; + nsrow2 = nsrow - nscol ; + ps2 = psi + nscol ; if (check_Lpx) { @@ -1920,12 +1904,12 @@ static int check_factor psxend = Lpx [s+1] ; } - ETC (s == nsuper-1, count, 4) ; + ETC (s == nsuper-1, count, 4) ; - P4 (" supernode "ID", ", s) ; - P4 ("col "ID" ", k1) ; - P4 ("to "ID". ", k2-1) ; - P4 ("nz in first col: "ID".\n", nsrow) ; + P4 (" supernode "ID", ", s) ; + P4 ("col "ID" ", k1) ; + P4 ("to "ID". ", k2-1) ; + P4 ("nz in first col: "ID".\n", nsrow) ; if (check_Lpx) { @@ -1933,101 +1917,99 @@ static int check_factor P4 ("end "ID"\n", psxend) ; } - if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0 + if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0 || (check_Lpx && psxend - psx != nsrow * nscol)) - { - ERR ("invalid supernode") ; - } - - lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ; - - if (L->xtype != CHOLMOD_PATTERN) - { - /* print each column of the supernode */ - for (jj = 0 ; jj < nscol ; jj++) - { - ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ; - j = k1 + jj ; - P4 (" col "ID"\n", j) ; - ilast = j ; - i = Ls [psi + jj] ; - P4 (" "I8":", i) ; - if (i != j) - { - ERR ("row index invalid") ; - } - - /* PRINTVALUE (Lx [psx + jj + jj*nsrow]) ; */ - print_value (print, xtype, Lx, NULL, - psx + jj + jj*nsrow, Common) ; - - P4 ("%s", "\n") ; - for (ii = jj + 1 ; ii < nsrow ; ii++) - { - ETC_DISABLE (count) ; - i = Ls [psi + ii] ; - P4 (" "I8":", i) ; - if (i <= ilast || i > n) - { - ERR ("row index out of range") ; - } - - /* PRINTVALUE (Lx [psx + ii + jj*nsrow]) ; */ - print_value (print, xtype, Lx, NULL, - psx + ii + jj*nsrow, Common) ; - - P4 ("%s", "\n") ; - ilast = i ; - } - } - } - else - { - /* just print the leading column of the supernode */ - P4 (" col "ID"\n", k1) ; - for (jj = 0 ; jj < nscol ; jj++) - { - ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ; - j = k1 + jj ; - i = Ls [psi + jj] ; - P4 (" "I8"", i) ; - if (i != j) - { - ERR ("row index invalid") ; - } - P4 ("%s", "\n") ; - } - ilast = j ; - for (ii = nscol ; ii < nsrow ; ii++) - { - ETC_DISABLE (count) ; - i = Ls [psi + ii] ; - P4 (" "I8"", i) ; - if (i <= ilast || i > n) - { - ERR ("row index out of range") ; - } - P4 ("%s", "\n") ; - ilast = i ; - } - } - } - } - } - - /* factor is valid */ + { + ERR ("invalid supernode") ; + } + + lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ; + + if (L->xtype != CHOLMOD_PATTERN) + { + // print each column of the supernode + for (jj = 0 ; jj < nscol ; jj++) + { + ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ; + j = k1 + jj ; + P4 (" col "ID"\n", j) ; + ilast = j ; + i = Ls [psi + jj] ; + P4 (" "I8":", i) ; + if (i != j) + { + ERR ("row index invalid") ; + } + + // print (Lx [psx + jj + jj*nsrow]) + print_value (print, xtype, dtype, Lx, NULL, + psx + jj + jj*nsrow, Common) ; + + P4 ("%s", "\n") ; + for (ii = jj + 1 ; ii < nsrow ; ii++) + { + ETC_DISABLE (count) ; + i = Ls [psi + ii] ; + P4 (" "I8":", i) ; + if (i <= ilast || i > n) + { + ERR ("row index out of range") ; + } + + // print (Lx [psx + ii + jj*nsrow]) + print_value (print, xtype, dtype, Lx, NULL, + psx + ii + jj*nsrow, Common) ; + + P4 ("%s", "\n") ; + ilast = i ; + } + } + } + else + { + // just print the leading column of the supernode + P4 (" col "ID"\n", k1) ; + for (jj = 0 ; jj < nscol ; jj++) + { + ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ; + j = k1 + jj ; + i = Ls [psi + jj] ; + P4 (" "I8"", i) ; + if (i != j) + { + ERR ("row index invalid") ; + } + P4 ("%s", "\n") ; + } + ilast = j ; + for (ii = nscol ; ii < nsrow ; ii++) + { + ETC_DISABLE (count) ; + i = Ls [psi + ii] ; + P4 (" "I8"", i) ; + if (i <= ilast || i > n) + { + ERR ("row index out of range") ; + } + P4 ("%s", "\n") ; + ilast = i ; + } + } + } + } + } + + // factor is valid P3 (" nz "ID"", lnz) ; P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - int CHOLMOD(check_factor) ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to check */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to check cholmod_common *Common ) { @@ -2036,13 +2018,11 @@ int CHOLMOD(check_factor) return (check_factor (NULL, 0, NULL, L, Common)) ; } - int CHOLMOD(print_factor) ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to print */ - const char *name, /* printed name of factor */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to print + const char *name, // printed name of factor cholmod_common *Common ) { @@ -2051,40 +2031,39 @@ int CHOLMOD(print_factor) return (check_factor (NULL, Common->print, name, L, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_check_triplet +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_check_triplet ================================================ */ -/* ========================================================================== */ - -/* Ensure a triplet matrix is valid, and optionally print it. */ +// Ensure a triplet matrix is valid, and optionally print it. static int check_triplet ( - Int print, + int print, const char *name, cholmod_triplet *T, cholmod_common *Common ) { - double *Tx, *Tz ; + void *Tx, *Tz ; Int *Ti, *Tj ; - Int i, j, p, nrow, ncol, nzmax, nz, xtype, init_print, count ; + Int i, j, p, nrow, ncol, nzmax, nz, init_print, count ; const char *type = "triplet" ; - /* ---------------------------------------------------------------------- */ - /* print header information */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print header information + //-------------------------------------------------------------------------- P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD triplet: ") ; if (name != NULL) { - P3 ("%s: ", name) ; + P3 ("%s: ", name) ; } if (T == NULL) { - ERR ("null") ; + ERR ("null") ; } nrow = T->nrow ; @@ -2095,126 +2074,120 @@ static int check_triplet Tj = T->j ; Tx = T->x ; Tz = T->z ; - xtype = T->xtype ; - + int xtype = T->xtype ; + int dtype = T->dtype ; P3 (" "ID"", nrow) ; P3 ("-by-"ID", ", ncol) ; P3 ("nz "ID",", nz) ; if (T->stype > 0) { - P3 ("%s", " upper.") ; + P3 ("%s", " upper.") ; } else if (T->stype < 0) { - P3 ("%s", " lower.") ; + P3 ("%s", " lower.") ; } else { - P3 ("%s", " up/lo.") ; + P3 ("%s", " up/lo.") ; } P4 ("\n nzmax "ID", ", nzmax) ; if (nz > nzmax) { - ERR ("nzmax too small") ; + ERR ("nzmax too small") ; } switch (T->itype) { - case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; - case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, "); - break ; - default: ERR ("unknown itype") ; + case CHOLMOD_INT: P4 ("%s", "\n scalar types: int32_t, ") ; break ; + case CHOLMOD_LONG: P4 ("%s", "\n scalar types: int64_t, ") ; break ; + default: ERR ("unknown itype") ; } switch (T->xtype) { - case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; - case CHOLMOD_REAL: P4 ("%s", "real") ; break ; - case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; - case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; - default: ERR ("unknown xtype") ; + case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; + case CHOLMOD_REAL: P4 ("%s", "real") ; break ; + case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; + case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; + default: ERR ("unknown xtype") ; } switch (T->dtype) { - case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; - case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; - default: ERR ("unknown dtype") ; + case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; + case CHOLMOD_SINGLE: P4 ("%s", ", single\n") ; break ; + default: ERR ("unknown dtype") ; } if (T->itype != ITYPE) { - ERR ("integer type must match routine") ; + ERR ("integer type must match routine") ; } if (T->stype && nrow != ncol) { - ERR ("symmetric but not square") ; + ERR ("symmetric but not square") ; } - /* check for existence of Ti, Tj, Tx arrays */ + // check for existence of Ti, Tj, Tx arrays if (Tj == NULL) { - ERR ("j array not present") ; + ERR ("j array not present") ; } if (Ti == NULL) { - ERR ("i array not present") ; + ERR ("i array not present") ; } if (xtype != CHOLMOD_PATTERN && Tx == NULL) { - ERR ("x array not present") ; + ERR ("x array not present") ; } if (xtype == CHOLMOD_ZOMPLEX && Tz == NULL) { - ERR ("z array not present") ; + ERR ("z array not present") ; } - /* ---------------------------------------------------------------------- */ - /* check and print each entry */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check and print each entry + //-------------------------------------------------------------------------- init_print = print ; ETC_START (count, 8) ; for (p = 0 ; p < nz ; p++) { - ETC (p >= nz-4, count, -1) ; - i = Ti [p] ; - P4 (" "I8":", p) ; - P4 (" "I_8"", i) ; - if (i < 0 || i >= nrow) - { - ERR ("row index out of range") ; - } - j = Tj [p] ; - P4 (" "I_8"", j) ; - if (j < 0 || j >= ncol) - { - ERR ("column index out of range") ; - } - - print_value (print, xtype, Tx, Tz, p, Common) ; - - P4 ("%s", "\n") ; - } - - /* triplet matrix is valid */ + ETC (p >= nz-4, count, -1) ; + i = Ti [p] ; + P4 (" "I8":", p) ; + P4 (" "I_8"", i) ; + if (i < 0 || i >= nrow) + { + ERR ("row index out of range") ; + } + j = Tj [p] ; + P4 (" "I_8"", j) ; + if (j < 0 || j >= ncol) + { + ERR ("column index out of range") ; + } + print_value (print, xtype, dtype, Tx, Tz, p, Common) ; + P4 ("%s", "\n") ; + } + + // triplet matrix is valid P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } - - int CHOLMOD(check_triplet) ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to check */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to check cholmod_common *Common ) { @@ -2223,13 +2196,11 @@ int CHOLMOD(check_triplet) return (check_triplet (0, NULL, T, Common)) ; } - int CHOLMOD(print_triplet) ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to print */ - const char *name, /* printed name of triplet matrix */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to print + const char *name, // printed name of triplet matrix cholmod_common *Common ) { @@ -2238,23 +2209,21 @@ int CHOLMOD(print_triplet) return (check_triplet (Common->print, name, T, Common)) ; } - - -/* ========================================================================== */ -/* === CHOLMOD debugging routines =========================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// CHOLMOD debugging routines +//------------------------------------------------------------------------------ #ifndef NDEBUG -/* The global variables present only when debugging enabled. */ +// The global variables present only when debugging enabled. int CHOLMOD(dump) = 0 ; int CHOLMOD(dump_malloc) = -1 ; -/* workspace: no debug routines use workspace in Common */ +// workspace: no debug routines use workspace in Common -/* ========================================================================== */ -/* === cholmod_dump_init ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_init +//------------------------------------------------------------------------------ void CHOLMOD(dump_init) (const char *s, cholmod_common *Common) { @@ -2264,18 +2233,17 @@ void CHOLMOD(dump_init) (const char *s, cholmod_common *Common) CHOLMOD(dump) = 0 ; if (f != NULL) { - i = fscanf (f, "%d", &CHOLMOD(dump)) ; - fclose (f) ; + i = fscanf (f, "%d", &CHOLMOD(dump)) ; + fclose (f) ; } PRINT1 (("%s: cholmod_dump_init, D = %d\n", s, CHOLMOD(dump))) ; } +//------------------------------------------------------------------------------ +// cholmod_dump_sparse +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_dump_sparse ================================================== */ -/* ========================================================================== */ - -/* returns nnz (diag (A)) or EMPTY if error */ +// returns nnz (diag (A)) or EMPTY if error int64_t CHOLMOD(dump_sparse) ( @@ -2290,8 +2258,8 @@ int64_t CHOLMOD(dump_sparse) if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (0) ; + // no checks if debug level is -2 or less + return (0) ; } RETURN_IF_NULL_COMMON (FALSE) ; @@ -2302,10 +2270,9 @@ int64_t CHOLMOD(dump_sparse) return (ok ? nnzdiag : EMPTY) ; } - -/* ========================================================================== */ -/* === cholmod_dump_factor ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_factor +//------------------------------------------------------------------------------ int CHOLMOD(dump_factor) ( @@ -2319,8 +2286,8 @@ int CHOLMOD(dump_factor) if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; @@ -2330,10 +2297,9 @@ int CHOLMOD(dump_factor) return (ok) ; } - -/* ========================================================================== */ -/* === cholmod_dump_perm ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_perm +//------------------------------------------------------------------------------ int CHOLMOD(dump_perm) ( @@ -2349,8 +2315,8 @@ int CHOLMOD(dump_perm) if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; Wi = malloc (MAX (1, n) * sizeof (Int)) ; @@ -2359,10 +2325,9 @@ int CHOLMOD(dump_perm) return (ok) ; } - -/* ========================================================================== */ -/* === cholmod_dump_dense =================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_dense +//------------------------------------------------------------------------------ int CHOLMOD(dump_dense) ( @@ -2373,17 +2338,16 @@ int CHOLMOD(dump_dense) { if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_dense (CHOLMOD(dump), name, X, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_dump_triplet ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_triplet +//------------------------------------------------------------------------------ int CHOLMOD(dump_triplet) ( @@ -2394,17 +2358,16 @@ int CHOLMOD(dump_triplet) { if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_triplet (CHOLMOD(dump), name, T, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_dump_subset ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_subset +//------------------------------------------------------------------------------ int CHOLMOD(dump_subset) ( @@ -2417,17 +2380,16 @@ int CHOLMOD(dump_subset) { if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_subset (S, len, n, CHOLMOD(dump), name, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_dump_parent ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_parent +//------------------------------------------------------------------------------ int CHOLMOD(dump_parent) ( @@ -2439,70 +2401,77 @@ int CHOLMOD(dump_parent) { if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_parent (Parent, n, CHOLMOD(dump), name, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_dump_real ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_real +//------------------------------------------------------------------------------ void CHOLMOD(dump_real) ( const char *name, - double *X, int64_t nrow, int64_t ncol, int lower, - int xentry, cholmod_common *Common + void *X, // float or double, in column-major form + int dtype, // CHOLMOD_SINGLE or CHOLMOD_DOUBLE + int64_t nrow, // # of rows + int64_t ncol, // # of cols + int lower, // if true, only print lower triangular part + int xentry, // 1 if real, 2 if complex (never zomplex) + cholmod_common *Common ) { - /* dump an nrow-by-ncol real dense matrix */ - int64_t i, j ; - double x, z ; + + // dump an nrow-by-ncol real or complex dense matrix if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return ; + // no checks if debug level is -2 or less + return ; } PRINT1 (("%s: dump_real, nrow: %ld ncol: %ld lower: %d\n", - name, nrow, ncol, lower)) ; - for (j = 0 ; j < ncol ; j++) - { - PRINT2 ((" col %ld\n", j)) ; - for (i = 0 ; i < nrow ; i++) - { - /* X is stored in column-major form */ - if (lower && i < j) - { - PRINT2 ((" %5ld: -", i)) ; - } - else - { - x = *X ; - PRINT2 ((" %5ld: %e", i, x)) ; - if (xentry == 2) - { - z = *(X+1) ; - PRINT2 ((", %e", z)) ; - } - } - PRINT2 (("\n")) ; - X += xentry ; - } + name, nrow, ncol, lower)) ; + int64_t p = 0 ; + for (int64_t j = 0 ; j < ncol ; j++) + { + PRINT2 ((" col %ld\n", j)) ; + for (int64_t i = 0 ; i < nrow ; i++) + { + // X is stored in column-major form + if (lower && i < j) + { + PRINT2 ((" %5ld: -", i)) ; + } + else + { + // x = X [p] + double x = GETVAL (X, p, dtype) ; + PRINT2 ((" %5ld: %e", i, x)) ; + if (xentry == 2) + { + // x = X [p+1] + double z = GETVAL (X, p+1, dtype) ; + PRINT2 ((", %e", z)) ; + } + } + PRINT2 (("\n")) ; + p += xentry ; + } } } - -/* ========================================================================== */ -/* === cholmod_dump_super =================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_super +//------------------------------------------------------------------------------ void CHOLMOD(dump_super) ( int64_t s, - Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx, + Int *Super, Int *Lpi, Int *Ls, Int *Lpx, + void *Lx, // float or double + int dtype, // CHOLMOD_SINGLE or CHOLMOD_DOUBLE int xentry, cholmod_common *Common ) @@ -2510,8 +2479,8 @@ void CHOLMOD(dump_super) Int k1, k2, do_values, psi, psx, nsrow, nscol, psend, ilast, p, i ; if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return ; + // no checks if debug level is -2 or less + return ; } k1 = Super [s] ; k2 = Super [s+1] ; @@ -2521,29 +2490,38 @@ void CHOLMOD(dump_super) psend = Lpi [s+1] ; nsrow = psend - psi ; PRINT1 (("\nSuper %ld, columns "ID" to "ID", "ID" rows "ID" cols\n", - s, k1, k2-1, nsrow, nscol)) ; + s, k1, k2-1, nsrow, nscol)) ; ilast = -1 ; for (p = psi ; p < psend ; p++) { - i = Ls [p] ; - PRINT2 ((" "ID" : p-psi "ID"\n", i, p-psi)) ; - ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ; - if (p-psi == nscol-1) PRINT2 (("------\n")) ; - ASSERT (i > ilast) ; - ilast = i ; + i = Ls [p] ; + PRINT2 ((" "ID" : p-psi "ID"\n", i, p-psi)) ; + ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ; + if (p-psi == nscol-1) PRINT2 (("------\n")) ; + ASSERT (i > ilast) ; + ilast = i ; } if (do_values) { - psx = Lpx [s] ; - CHOLMOD(dump_real) ("Supernode", Lx + xentry*psx, nsrow, nscol, TRUE, - xentry, Common) ; + psx = Lpx [s] ; + if (dtype == CHOLMOD_DOUBLE) + { + double *X = (double *) Lx ; + CHOLMOD(dump_real) ("Supernode", X + xentry*psx, dtype, + nsrow, nscol, TRUE, xentry, Common) ; + } + else + { + float *X = (float *) Lx ; + CHOLMOD(dump_real) ("Supernode", X + xentry*psx, dtype, + nsrow, nscol, TRUE, xentry, Common) ; + } } } - -/* ========================================================================== */ -/* === cholmod_dump_mem ===================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_dump_mem +//------------------------------------------------------------------------------ int CHOLMOD(dump_mem) ( @@ -2555,30 +2533,28 @@ int CHOLMOD(dump_mem) int64_t diff = should - Common->memory_inuse ; if (diff != 0) { - PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n", - where, (double) Common->memory_usage, (double) Common->memory_inuse, - (double) should)) ; - PRINT0 (("mem: %s diff %ld !\n", where, diff)) ; + PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n", + where, (double) Common->memory_usage, (double) Common->memory_inuse, + (double) should)) ; + PRINT0 (("mem: %s diff %ld !\n", where, diff)) ; } return (diff == 0) ; } +//------------------------------------------------------------------------------ +// cholmod_dump_partition +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_dump_partition =============================================== */ -/* ========================================================================== */ - -/* make sure we have a proper separator (for debugging only) - * - * workspace: none - */ +// make sure we have a proper separator (for debugging only) +// +// workspace: none int CHOLMOD(dump_partition) ( int64_t n, Int *Cp, Int *Ci, - Int *Cnw, /* can be NULL */ + Int *Cnw, // can be NULL Int *Part, int64_t sepsize, cholmod_common *Common @@ -2592,122 +2568,126 @@ int CHOLMOD(dump_partition) chek [2] = 0 ; for (j = 0 ; j < n ; j++) { - PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], + PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], Cnw ? (Cnw[j]):1)); - which = Part [j] ; - for (p = Cp [j] ; p < Cp [j+1] ; p++) - { - i = Ci [p] ; - PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ; - if (which == 0) - { - if (Part [i] == 1) - { - PRINT0 (("Error! "ID" "ID"\n", i, j)) ; - ok = FALSE ; - } - } - else if (which == 1) - { - if (Part [i] == 0) - { - PRINT0 (("Error! "ID" "ID"\n", i, j)) ; - ok = FALSE ; - } - } - } - if (which < 0 || which > 2) - { - PRINT0 (("Part out of range\n")) ; - ok = FALSE ; - } - chek [which] += (Cnw ? (Cnw [j]) : 1) ; + which = Part [j] ; + for (p = Cp [j] ; p < Cp [j+1] ; p++) + { + i = Ci [p] ; + PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ; + if (which == 0) + { + if (Part [i] == 1) + { + PRINT0 (("Error! "ID" "ID"\n", i, j)) ; + ok = FALSE ; + } + } + else if (which == 1) + { + if (Part [i] == 0) + { + PRINT0 (("Error! "ID" "ID"\n", i, j)) ; + ok = FALSE ; + } + } + } + if (which < 0 || which > 2) + { + PRINT0 (("Part out of range\n")) ; + ok = FALSE ; + } + chek [which] += (Cnw ? (Cnw [j]) : 1) ; } PRINT1 (("sepsize %ld check "ID" "ID" "ID"\n", - sepsize, chek[0], chek[1],chek[2])); + sepsize, chek[0], chek[1],chek[2])); if (sepsize != chek[2]) { - PRINT0 (("mismatch!\n")) ; - ok = FALSE ; + PRINT0 (("mismatch!\n")) ; + ok = FALSE ; } return (ok) ; } +//------------------------------------------------------------------------------ +// cholmod_dump_work +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_dump_work ==================================================== */ -/* ========================================================================== */ - -int CHOLMOD(dump_work) (int flag, int head, int64_t wsize, +int CHOLMOD(dump_work) (int flag, int head, int64_t wsize, int dtype, cholmod_common *Common) { - double *W ; Int *Flag, *Head ; Int k, nrow, mark ; if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return (TRUE) ; + // no checks if debug level is -2 or less + return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; nrow = Common->nrow ; Flag = Common->Flag ; Head = Common->Head ; - W = Common->Xwork ; mark = Common->mark ; -#if 0 - // FIXME: need float and double - if (wsize < 0) - { - /* check all of Xwork */ - wsize = Common->xworkbytes ; - } - else - { - /* check on the first wsize doubles in Xwork */ - wsize = MIN (wsize, (Int) (Common->xworkbytes)) ; - } -#endif - if (flag) { - for (k = 0 ; k < nrow ; k++) - { - if (Flag [k] >= mark) - { - PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n", - k, Flag [k], mark)) ; - return (FALSE) ; - } - } + for (k = 0 ; k < nrow ; k++) + { + if (Flag [k] >= mark) + { + PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n", + k, Flag [k], mark)) ; + return (FALSE) ; + } + } } if (head) { - for (k = 0 ; k < nrow ; k++) - { - if (Head [k] != EMPTY) - { - PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ; - return (FALSE) ; - } - } + for (k = 0 ; k < nrow ; k++) + { + if (Head [k] != EMPTY) + { + PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ; + return (FALSE) ; + } + } + } + + // if wsize is negative, all of Common->Xwork is checked. + + #define CHECK_XWORK(fltype) \ + { \ + fltype *W = Common->Xwork ; \ + int64_t s = (int64_t) (Common->xworkbytes / sizeof (fltype)) ; \ + if (wsize < 0) \ + { \ + wsize = s ; \ + } \ + else \ + { \ + wsize = MIN (wsize, s) ; \ + } \ + for (k = 0 ; k < wsize ; k++) \ + { \ + if (W [k] != 0.) \ + { \ + PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ; \ + return (FALSE) ; \ + } \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + CHECK_XWORK (double) ; } - -#if 0 - // FIXME: need float and double - for (k = 0 ; k < wsize ; k++) + else { - if (W [k] != 0.) - { - PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ; - return (FALSE) ; - } + CHECK_XWORK (float) ; } -#endif return (TRUE) ; } diff --git a/CHOLMOD/Check/cholmod_l_check.c b/CHOLMOD/Check/cholmod_l_check.c index 881ee34799..72c1e8584b 100644 --- a/CHOLMOD/Check/cholmod_l_check.c +++ b/CHOLMOD/Check/cholmod_l_check.c @@ -2,7 +2,7 @@ // CHOLMOD/Check/cholmod_l_check.c: int64_t version of cholmod_check //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Check/cholmod_l_read.c b/CHOLMOD/Check/cholmod_l_read.c index d0decedbc2..5e727d6904 100644 --- a/CHOLMOD/Check/cholmod_l_read.c +++ b/CHOLMOD/Check/cholmod_l_read.c @@ -2,7 +2,7 @@ // CHOLMOD/Check/cholmod_l_read.c: int64_t version of cholmod_read //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Check/cholmod_l_write.c b/CHOLMOD/Check/cholmod_l_write.c index 6ea5fa0880..01ef6314eb 100644 --- a/CHOLMOD/Check/cholmod_l_write.c +++ b/CHOLMOD/Check/cholmod_l_write.c @@ -2,7 +2,7 @@ // CHOLMOD/Check/cholmod_l_write.c: int64_t version of cholmod_write //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Check/cholmod_read.c b/CHOLMOD/Check/cholmod_read.c index f1153dd616..b5df255704 100644 --- a/CHOLMOD/Check/cholmod_read.c +++ b/CHOLMOD/Check/cholmod_read.c @@ -2,160 +2,159 @@ // CHOLMOD/Check/cholmod_read: read a sparse matrix from a file //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Read a sparse matrix in triplet or dense form. A triplet matrix can be - * returned as compressed-column sparse matrix. The file format is compatible - * with all variations of the Matrix Market "coordinate" and "array" format - * (http://www.nist.gov/MatrixMarket). The format supported by these routines - * also allow other formats, where the Matrix Market header is optional. - * - * Although the Matrix Market header is optional, I recommend that users stick - * with the strict Matrix Market format. The optional format appears here to - * support the reading of symmetric matrices stored with just their upper - * triangular parts present, for testing and development of the A->stype > 0 - * format in CHOLMOD. That format is not included in the Matrix Market format. - * - * If the first line of the file starts with %%MatrixMarket, then it is - * interpretted as a file in Matrix Market format. This line must have - * the following format: - * - * %%MatrixMarket matrix - * - * is one of: coordinate or array. The former is a sparse matrix in - * triplet form. The latter is a dense matrix in column-major form. - * - * is one of: real, complex, pattern, or integer. - * The functions here convert the "integer" and "pattern" types to real. - * - * is one of: general, hermitian, symmetric, or skew-symmetric - * - * The strings are case-insensitive. Only the first character is - * significant (or the first two for skew-symmetric). - * - * is ignored for all matrices; the actual type (real, complex, - * or pattern) is inferred from the number of tokens in each line of the - * file. For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for - * a dense "array" matrix: 1: real, 2: complex. This is compatible with - * the Matrix Market format, since pattern matrices must have two tokens - * per line, real matrices must have 3, and complex matrices must have 4. - * A storage of "general" implies an stype of zero (see below). - * "symmetric" and "hermitian" imply an stype of -1. Skew-symmetric and - * complex symmetric matrices are always returned with both upper and lower - * triangular parts present, with an stype of zero, since CHOLMOD does not - * have a method for representing skew-symmetric and complex symmetric - * matrices. real symmetric and complex Hermitian matrices may optionally - * be returned with both parts present. - * - * Any other lines starting with "%" are treated as comments, and are ignored. - * Blank lines are ignored. The Matrix Market header is optional in this - * routine (it is not optional in the Matrix Market format). - * - * Note that complex matrices are always returned in CHOLMOD_COMPLEX format, - * not CHOLMOD_ZOMPLEX. - * - * ----------------------------------------------------------------------------- - * Triplet matrices: - * ----------------------------------------------------------------------------- - * - * The first data line of a triplet matrix contains 3 or 4 integers: - * - * nrow ncol nnz stype - * - * where stype is optional (stype does not appear in the Matrix Market format). - * The matrix is nrow-by-ncol. The following nnz lines (excluding comments - * and blank lines) each contain a single entry. Duplicates are permitted, - * and are summed in the output matrix. - * - * The stype is first derived from the Matrix Market header. If the stype - * appears as the fourth integer in the first data line, it is determined from - * that line. - * - * If stype is present, it denotes the storage format for the matrix. - * stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general"). - * stype = -1 denotes a real symmetric or complex Hermitian matrix whose lower - * triangular entries are stored. Entries may be present in the upper - * triangular part, but these are ignored (same as Matrix Market - * "real symmetric" and "complex Hermitian"). - * stype = 1 denotes a real symmetric or complex Hermitian matrix whose upper - * triangular entries are stored. Entries may be present in the lower - * triangular part, but these are ignored. This option is not present - * in the Matrix Market format. - * - * If stype is not present (no Matrix Market header and not in the first data - * line) it is inferred from the rest of the data. If the matrix is - * rectangular, or has entries in both the upper and lower triangular parts, - * then it is assumed to be unsymmetric (stype=0). If only entries in the - * lower triangular part are present, the matrix is assumed to have stype = -1. - * If only entries in the upper triangular part are present, the matrix is - * assumed to have stype = 1. - * - * After the first data line (with nrow, ncol, nnz, and optionally stype), - * each nonzero consists of one line with 2, 3, or 4 entries. All lines must - * have the same number of entries. The first two entries are the row and - * column indices of the nonzero. If 3 entries are present, the 3rd entry is - * the numerical value, and the matrix is real. If 4 entries are present, - * the 3rd and 4th entries in the line are the real and imaginary parts of - * a complex value. - * - * The matrix can be either 0-based or 1-based. It is first assumed to be - * one-based (all matrices in the Matrix Market are one-based), with row indices - * in the range 1 to ncol and column indices in the range 1 to nrow. If a row - * or column index of zero is found, the matrix is assumed to be zero-based - * (with row indices in the range 0 to ncol-1 and column indices in the range 0 - * to nrow-1). - * - * If Common->prefer_binary is set to its default value of FALSE, then - * for symmetric pattern-only matrices, the kth diagonal (if present) is set to - * one plus the degree of the row/column k, and the off-diagonal entries are set - * to -1. A symmetric pattern-only matrix with a zero-free diagonal is thus - * converted into a symmetric positive definite matrix. All entries are set to - * one for an unsymmetric pattern-only matrix. This differs from the - * Matrix Market format (A = mmread ('file') returns a binary pattern for A for - * symmetric pattern-only matrices). If Common->prefer_binary is TRUE, then - * this function returns a binary matrix (just like mmread('file')). - * - * ----------------------------------------------------------------------------- - * Dense matrices: - * ----------------------------------------------------------------------------- - * - * A dense matrix is specified by the Matrix Market "array" format. The - * Matrix Market header is optional; if not present, the matrix is assumed to - * be in the Matrix Market "general" format. The first data line contains just - * two integers: - * - * nrow ncol - * - * The can be real, integer, or complex (not pattern). These functions - * convert an integer type to real. The entries in the matrix are stored in - * column-major format, with one line per entry. Two entries are present in - * each line for complex matrices, one for real and integer matrices. In - * rectangular and unsymmetric matrices, all entries are present. For real - * symmetric or complex Hermitian matrices, only entries in the lower triangular - * part appear. For skew-symmetric matrices, only entries in the strictly - * lower triangular part appear. - * - * Since CHOLMOD does not have a data structure for presenting dense symmetric/ - * Hermitian matrices, these functions always return a dense matrix in its - * general form, with both upper and lower parts present. - */ +// Read a sparse matrix in triplet or dense form. A triplet matrix can be +// returned as compressed-column sparse matrix. The file format is compatible +// with all variations of the Matrix Market "coordinate" and "array" format +// (http://www.nist.gov/MatrixMarket). The format supported by these routines +// also allow other formats, where the Matrix Market header is optional. +// +// Although the Matrix Market header is optional, I recommend that users stick +// with the strict Matrix Market format. The optional format appears here to +// support the reading of symmetric matrices stored with just their upper +// triangular parts present, for testing and development of the A->stype > 0 +// format in CHOLMOD. That format is not included in the Matrix Market format. +// +// If the first line of the file starts with %%MatrixMarket, then it is +// interpretted as a file in Matrix Market format. This line must have +// the following format: +// +// %%MatrixMarket matrix +// +// is one of: coordinate or array. The former is a sparse matrix in +// triplet form. The latter is a dense matrix in column-major form. +// +// is one of: real, complex, pattern, or integer. +// The functions here convert the "integer" and "pattern" types to real. +// +// is one of: general, hermitian, symmetric, or skew-symmetric +// +// The strings are case-insensitive. Only the first character is +// significant (or the first two for skew-symmetric). +// +// is ignored for all matrices; the actual type (real, complex, +// or pattern) is inferred from the number of tokens in each line of the +// file. For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for +// a dense "array" matrix: 1: real, 2: complex. This is compatible with +// the Matrix Market format, since pattern matrices must have two tokens +// per line, real matrices must have 3, and complex matrices must have 4. +// A storage of "general" implies an stype of zero (see below). +// "symmetric" and "hermitian" imply an stype of -1. Skew-symmetric and +// complex symmetric matrices are always returned with both upper and lower +// triangular parts present, with an stype of zero, since CHOLMOD does not +// have a method for representing skew-symmetric and complex symmetric +// matrices. real symmetric and complex Hermitian matrices may optionally +// be returned with both parts present. +// +// Any other lines starting with "%" are treated as comments, and are ignored. +// Blank lines are ignored. The Matrix Market header is optional in this +// routine (it is not optional in the Matrix Market format). +// +// Note that complex matrices are always returned in CHOLMOD_COMPLEX format, +// not CHOLMOD_ZOMPLEX. +// +// ----------------------------------------------------------------------------- +// Triplet matrices: +// ----------------------------------------------------------------------------- +// +// The first data line of a triplet matrix contains 3 or 4 integers: +// +// nrow ncol nnz stype +// +// where stype is optional (stype does not appear in the Matrix Market format). +// The matrix is nrow-by-ncol. The following nnz lines (excluding comments +// and blank lines) each contain a single entry. Duplicates are permitted, +// and are summed in the output matrix. +// +// The stype is first derived from the Matrix Market header. If the stype +// appears as the fourth integer in the first data line, it is determined from +// that line. +// +// If stype is present, it denotes the storage format for the matrix. +// stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general"). +// stype = -1 denotes a real symmetric or complex Hermitian matrix whose lower +// triangular entries are stored. Entries may be present in the upper +// triangular part, but these are ignored (same as Matrix Market +// "real symmetric" and "complex Hermitian"). +// stype = 1 denotes a real symmetric or complex Hermitian matrix whose upper +// triangular entries are stored. Entries may be present in the lower +// triangular part, but these are ignored. This option is not present +// in the Matrix Market format. +// +// If stype is not present (no Matrix Market header and not in the first data +// line) it is inferred from the rest of the data. If the matrix is +// rectangular, or has entries in both the upper and lower triangular parts, +// then it is assumed to be unsymmetric (stype=0). If only entries in the +// lower triangular part are present, the matrix is assumed to have stype = -1. +// If only entries in the upper triangular part are present, the matrix is +// assumed to have stype = 1. +// +// After the first data line (with nrow, ncol, nnz, and optionally stype), +// each nonzero consists of one line with 2, 3, or 4 entries. All lines must +// have the same number of entries. The first two entries are the row and +// column indices of the nonzero. If 3 entries are present, the 3rd entry is +// the numerical value, and the matrix is real. If 4 entries are present, +// the 3rd and 4th entries in the line are the real and imaginary parts of +// a complex value. +// +// The matrix can be either 0-based or 1-based. It is first assumed to be +// one-based (all matrices in the Matrix Market are one-based), with row indices +// in the range 1 to ncol and column indices in the range 1 to nrow. If a row +// or column index of zero is found, the matrix is assumed to be zero-based +// (with row indices in the range 0 to ncol-1 and column indices in the range 0 +// to nrow-1). +// +// If Common->prefer_binary is set to its default value of FALSE, then +// for symmetric pattern-only matrices, the kth diagonal (if present) is set to +// one plus the degree of the row/column k, and the off-diagonal entries are set +// to -1. A symmetric pattern-only matrix with a zero-free diagonal is thus +// converted into a symmetric positive definite matrix. All entries are set to +// one for an unsymmetric pattern-only matrix. This differs from the +// Matrix Market format (A = mmread ('file') returns a binary pattern for A for +// symmetric pattern-only matrices). If Common->prefer_binary is TRUE, then +// this function returns a binary matrix (just like mmread('file')). +// +// ----------------------------------------------------------------------------- +// Dense matrices: +// ----------------------------------------------------------------------------- +// +// A dense matrix is specified by the Matrix Market "array" format. The +// Matrix Market header is optional; if not present, the matrix is assumed to +// be in the Matrix Market "general" format. The first data line contains just +// two integers: +// +// nrow ncol +// +// The can be real, integer, or complex (not pattern). These functions +// convert an integer type to real. The entries in the matrix are stored in +// column-major format, with one line per entry. Two entries are present in +// each line for complex matrices, one for real and integer matrices. In +// rectangular and unsymmetric matrices, all entries are present. For real +// symmetric or complex Hermitian matrices, only entries in the lower triangular +// part appear. For skew-symmetric matrices, only entries in the strictly +// lower triangular part appear. +// +// Since CHOLMOD does not have a data structure for presenting dense symmetric/ +// Hermitian matrices, these functions always return a dense matrix in its +// general form, with both upper and lower parts present. #ifndef NCHECK #include "cholmod_internal.h" -/* The MatrixMarket format specificies a maximum line length of 1024 */ +// The MatrixMarket format specificies a maximum line length of 1024 #define MAXLINE 1030 -/* ========================================================================== */ -/* === get_line ============================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// get_line +//------------------------------------------------------------------------------ -/* Read one line of the file, return TRUE if successful, FALSE if EOF. */ +// Read one line of the file, return TRUE if successful, FALSE if EOF. static int get_line (FILE *f, char *buf) { @@ -165,29 +164,31 @@ static int get_line (FILE *f, char *buf) return (fgets (buf, MAXLINE, f) != NULL) ; } -/* ========================================================================== */ -/* === fix_inf ============================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// fix_inf +//------------------------------------------------------------------------------ -/* Replace huge values with +/- Inf's, since scanf and printf don't deal - * with Inf's properly. - */ +// Replace huge values with +/- Inf's, since scanf and printf don't deal +// with Inf's properly. static double fix_inf (double x) { - if ((x >= HUGE_DOUBLE) || (x <= -HUGE_DOUBLE)) + if (x >= HUGE_DOUBLE) { - /* treat this as +/- Inf (assume 2*x leads to overflow) */ - x = 2*x ; + x = INFINITY ; + } + else if (x <= -HUGE_DOUBLE) + { + x = -INFINITY ; } return (x) ; } -/* ========================================================================== */ -/* === is_blank_line ======================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// is_blank_line +//------------------------------------------------------------------------------ -/* TRUE if s is a blank line or comment, FALSE otherwise */ +// TRUE if s is a blank line or comment, FALSE otherwise static int is_blank_line ( @@ -197,71 +198,69 @@ static int is_blank_line int c, k ; if (s [0] == '%') { - /* a comment line */ - return (TRUE) ; + // a comment line + return (TRUE) ; } for (k = 0 ; k <= MAXLINE ; k++) { - c = s [k] ; - if (c == '\0') - { - /* end of line */ - break ; - } - if (!isspace (c)) - { - /* non-space character */ - return (FALSE) ; - } + c = s [k] ; + if (c == '\0') + { + // end of line + break ; + } + if (!isspace (c)) + { + // non-space character + return (FALSE) ; + } } return (TRUE) ; } +//------------------------------------------------------------------------------ +// read_header +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === read_header ========================================================== */ -/* ========================================================================== */ - -/* Read the header. This consists of zero or more comment lines (blank, or - * starting with a "%" in the first column), followed by a single data line - * containing up to four numerical values. - * - * The first line may optionally be a Matrix Market header line, of the form - * - * %%MatrixMarket matrix - * - * The first data line of a sparse matrix in triplet form consists of 3 or 4 - * numerical values: - * - * nrow ncol nnz stype - * - * where stype is optional (it does not appear in the Matrix Market file - * format). The first line of a dense matrix in column-major form consists of - * two numerical values: - * - * nrow ncol - * - * The stype of the matrix is determine either from the Matrix Market header, - * or (optionally) from the first data line. stypes of 0 to -3 directly - * correlate with the Matrix Market format; stype = 1 is an extension to that - * format. - * - * 999: unknown (will be inferred from the data) - * 1: real symmetric or complex Hermitian with upper part stored - * (not in the Matrix Market format) - * 0: unsymmetric (same as Matrix Market "general") - * -1: real symmetric or complex Hermitian, with lower part stored - * (Matrix Market "real symmetric" or "complex hermitian") - * -2: real or complex skew symmetric (lower part stored, can only be - * specified by Matrix Market header) - * -3: complex symmetric (lower part stored) - * specified by Matrix Market header) - * - * The Matrix Market header is optional. If stype appears in the first data - * line, it is determine by that data line. Otherwise, if the Matrix Market - * header appears, stype is determined from that header. If stype does not - * appear, it is set to "unknown" (999). - */ +// Read the header. This consists of zero or more comment lines (blank, or +// starting with a "%" in the first column), followed by a single data line +// containing up to four numerical values. +// +// The first line may optionally be a Matrix Market header line, of the form +// +// %%MatrixMarket matrix +// +// The first data line of a sparse matrix in triplet form consists of 3 or 4 +// numerical values: +// +// nrow ncol nnz stype +// +// where stype is optional (it does not appear in the Matrix Market file +// format). The first line of a dense matrix in column-major form consists of +// two numerical values: +// +// nrow ncol +// +// The stype of the matrix is determine either from the Matrix Market header, +// or (optionally) from the first data line. stypes of 0 to -3 directly +// correlate with the Matrix Market format; stype = 1 is an extension to that +// format. +// +// 999: unknown (will be inferred from the data) +// 1: real symmetric or complex Hermitian with upper part stored +// (not in the Matrix Market format) +// 0: unsymmetric (same as Matrix Market "general") +// -1: real symmetric or complex Hermitian, with lower part stored +// (Matrix Market "real symmetric" or "complex hermitian") +// -2: real or complex skew symmetric (lower part stored, can only be +// specified by Matrix Market header) +// -3: complex symmetric (lower part stored) +// specified by Matrix Market header) +// +// The Matrix Market header is optional. If stype appears in the first data +// line, it is determine by that data line. Otherwise, if the Matrix Market +// header appears, stype is determined from that header. If stype does not +// appear, it is set to "unknown" (999). #define STYPE_UNKNOWN 999 #define STYPE_SYMMETRIC_UPPER 1 @@ -270,17 +269,17 @@ static int is_blank_line #define STYPE_SKEW_SYMMETRIC -2 #define STYPE_COMPLEX_SYMMETRIC_LOWER -3 -static int read_header /* returns TRUE if successful, FALSE on error */ +static int read_header // returns TRUE if successful, FALSE on error ( - /* ---- input ---- */ - FILE *f, /* file to read from */ - /* ---- output --- */ - char *buf, /* a character array of size MAXLINE+1 */ - int *mtype, /* CHOLMOD_TRIPLET or CHOLMOD_DENSE */ - size_t *nrow, /* number of rows in the matrix */ - size_t *ncol, /* number of columns in the matrix */ - size_t *nnz, /* number of entries in a triplet matrix (0 for dense)*/ - int *stype /* stype (see above) */ + // input: + FILE *f, // file to read from + // output: + char *buf, // a character array of size MAXLINE+1 + int *mtype, // CHOLMOD_TRIPLET or CHOLMOD_DENSE + size_t *nrow, // number of rows in the matrix + size_t *ncol, // number of columns in the matrix + size_t *nnz, // number of entries in a triplet matrix (0 for dense) + int *stype // stype (see above) ) { char *p ; @@ -296,282 +295,277 @@ static int read_header /* returns TRUE if successful, FALSE on error */ for ( ; ; ) { - /* ------------------------------------------------------------------ */ - /* get the next line */ - /* ------------------------------------------------------------------ */ - - if (!get_line (f, buf)) - { - /* premature end of file */ - return (FALSE) ; - } - - if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0)) - { - - /* -------------------------------------------------------------- */ - /* read a Matrix Market header */ - /* -------------------------------------------------------------- */ - - got_mm_header = TRUE ; - p = buf ; - - /* -------------------------------------------------------------- */ - /* get "matrix" token */ - /* -------------------------------------------------------------- */ - - while (*p && !isspace (*p)) p++ ; - while (*p && isspace (*p)) p++ ; - c = tolower (*p) ; - if (c != 'm') - { - /* bad format */ - return (FALSE) ; - } - - /* -------------------------------------------------------------- */ - /* get the fmt token ("coord" or "array") */ - /* -------------------------------------------------------------- */ - - while (*p && !isspace (*p)) p++ ; - while (*p && isspace (*p)) p++ ; - c = tolower (*p) ; - if (c == 'c') - { - *mtype = CHOLMOD_TRIPLET ; - } - else if (c == 'a') - { - *mtype = CHOLMOD_DENSE ; - } - else - { - /* bad format, neither "coordinate" nor "array" */ - return (FALSE) ; - } - - /* -------------------------------------------------------------- */ - /* get type token (real, pattern, complex, integer) */ - /* -------------------------------------------------------------- */ - - while (*p && !isspace (*p)) p++ ; - while (*p && isspace (*p)) p++ ; - c = tolower (*p) ; - if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i')) - { - /* bad format */ - return (FALSE) ; - } - is_complex = (c == 'c') ; - - /* -------------------------------------------------------------- */ - /* get storage token (general, hermitian, symmetric, skew) */ - /* -------------------------------------------------------------- */ - - while (*p && !isspace (*p)) p++ ; - while (*p && isspace (*p)) p++ ; - c = tolower (*p) ; - c2 = tolower (*(p+1)) ; - if (c == 'g') - { - /* "general" storage (unsymmetric matrix), both parts present */ - *stype = STYPE_UNSYMMETRIC ; - } - else if (c == 's' && c2 == 'y') - { - /* "symmetric" */ - if (is_complex) - { - /* complex symmetric, lower triangular part present */ - *stype = STYPE_COMPLEX_SYMMETRIC_LOWER ; - } - else - { - /* real symmetric, lower triangular part present */ - *stype = STYPE_SYMMETRIC_LOWER ; - } - } - else if (c == 'h') - { - /* "hermitian" matrix, lower triangular part present */ - *stype = STYPE_SYMMETRIC_LOWER ; - } - else if (c == 's' && c2 == 'k') - { - /* "skew-symmetric" (real or complex), lower part present */ - *stype = STYPE_SKEW_SYMMETRIC ; - } - else - { - /* bad format */ - return (FALSE) ; - } - - } - else if (is_blank_line (buf)) - { - - /* -------------------------------------------------------------- */ - /* blank line or comment line */ - /* -------------------------------------------------------------- */ - - continue ; - - } - else - { - - /* -------------------------------------------------------------- */ - /* read the first data line and return */ - /* -------------------------------------------------------------- */ - - /* format: nrow ncol nnz stype */ - l1 = EMPTY ; - l2 = EMPTY ; - l3 = 0 ; - l4 = 0 ; - nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ; - if (nitems < 2 || nitems > 4 || + //---------------------------------------------------------------------- + // get the next line + //---------------------------------------------------------------------- + + if (!get_line (f, buf)) + { + // premature end of file + return (FALSE) ; + } + + if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0)) + { + + //------------------------------------------------------------------ + // read a Matrix Market header + //------------------------------------------------------------------ + + got_mm_header = TRUE ; + p = buf ; + + //------------------------------------------------------------------ + // get "matrix" token + //------------------------------------------------------------------ + + while (*p && !isspace (*p)) p++ ; + while (*p && isspace (*p)) p++ ; + c = tolower (*p) ; + if (c != 'm') + { + // bad format + return (FALSE) ; + } + + //------------------------------------------------------------------ + // get the fmt token ("coord" or "array") + //------------------------------------------------------------------ + + while (*p && !isspace (*p)) p++ ; + while (*p && isspace (*p)) p++ ; + c = tolower (*p) ; + if (c == 'c') + { + *mtype = CHOLMOD_TRIPLET ; + } + else if (c == 'a') + { + *mtype = CHOLMOD_DENSE ; + } + else + { + // bad format, neither "coordinate" nor "array" + return (FALSE) ; + } + + //------------------------------------------------------------------ + // get type token (real, pattern, complex, integer) + //------------------------------------------------------------------ + + while (*p && !isspace (*p)) p++ ; + while (*p && isspace (*p)) p++ ; + c = tolower (*p) ; + if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i')) + { + // bad format + return (FALSE) ; + } + is_complex = (c == 'c') ; + + //------------------------------------------------------------------ + // get storage token (general, hermitian, symmetric, skew) + //------------------------------------------------------------------ + + while (*p && !isspace (*p)) p++ ; + while (*p && isspace (*p)) p++ ; + c = tolower (*p) ; + c2 = tolower (*(p+1)) ; + if (c == 'g') + { + // "general" storage (unsymmetric matrix), both parts present + *stype = STYPE_UNSYMMETRIC ; + } + else if (c == 's' && c2 == 'y') + { + // "symmetric" + if (is_complex) + { + // complex symmetric, lower triangular part present + *stype = STYPE_COMPLEX_SYMMETRIC_LOWER ; + } + else + { + // real symmetric, lower triangular part present + *stype = STYPE_SYMMETRIC_LOWER ; + } + } + else if (c == 'h') + { + // "hermitian" matrix, lower triangular part present + *stype = STYPE_SYMMETRIC_LOWER ; + } + else if (c == 's' && c2 == 'k') + { + // "skew-symmetric" (real or complex), lower part present + *stype = STYPE_SKEW_SYMMETRIC ; + } + else + { + // bad format + return (FALSE) ; + } + + } + else if (is_blank_line (buf)) + { + + //------------------------------------------------------------------ + // blank line or comment line + //------------------------------------------------------------------ + + continue ; + + } + else + { + + //------------------------------------------------------------------ + // read the first data line and return + //------------------------------------------------------------------ + + // format: nrow ncol nnz stype + l1 = EMPTY ; + l2 = EMPTY ; + l3 = 0 ; + l4 = 0 ; + nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ; + if (nitems < 2 || nitems > 4 || l1 > (double) Int_max || l2 > (double) Int_max) - { - /* invalid matrix */ - return (FALSE) ; - } - *nrow = l1 ; - *ncol = l2 ; - if (nitems == 2) - { - /* a dense matrix */ - if (!got_mm_header) - { - *mtype = CHOLMOD_DENSE ; - *stype = STYPE_UNSYMMETRIC ; - } - } - if (nitems == 3 || nitems == 4) - { - /* a sparse triplet matrix */ - *nnz = l3 ; - if (!got_mm_header) - { - *mtype = CHOLMOD_TRIPLET ; - } - } - if (nitems == 4) - { - /* an stype specified here can only be 1, 0, or -1 */ - if (l4 < 0) - { - *stype = STYPE_SYMMETRIC_LOWER ; - } - else if (l4 > 0) - { - *stype = STYPE_SYMMETRIC_UPPER ; - } - else - { - *stype = STYPE_UNSYMMETRIC ; - } - } - if (*nrow != *ncol) - { - /* a rectangular matrix must be unsymmetric */ - *stype = STYPE_UNSYMMETRIC ; - } - return (TRUE) ; - } - - first = FALSE ; + { + // invalid matrix + return (FALSE) ; + } + *nrow = l1 ; + *ncol = l2 ; + if (nitems == 2) + { + // a dense matrix + if (!got_mm_header) + { + *mtype = CHOLMOD_DENSE ; + *stype = STYPE_UNSYMMETRIC ; + } + } + if (nitems == 3 || nitems == 4) + { + // a sparse triplet matrix + *nnz = l3 ; + if (!got_mm_header) + { + *mtype = CHOLMOD_TRIPLET ; + } + } + if (nitems == 4) + { + // an stype specified here can only be 1, 0, or -1 + if (l4 < 0) + { + *stype = STYPE_SYMMETRIC_LOWER ; + } + else if (l4 > 0) + { + *stype = STYPE_SYMMETRIC_UPPER ; + } + else + { + *stype = STYPE_UNSYMMETRIC ; + } + } + if (*nrow != *ncol) + { + // a rectangular matrix must be unsymmetric + *stype = STYPE_UNSYMMETRIC ; + } + return (TRUE) ; + } + + first = FALSE ; } } +//------------------------------------------------------------------------------ +// read_triplet +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === read_triplet ========================================================= */ -/* ========================================================================== */ - -/* Header has already been read in, including first line (nrow ncol nnz stype). - * Read the triplets. */ +// Header has already been read in, including first line (nrow ncol nnz stype). +// Read the triplets. static cholmod_triplet *read_triplet ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - size_t nrow, /* number of rows */ - size_t ncol, /* number of columns */ - size_t nnz, /* number of triplets in file to read */ - int stype, /* stype from header, or "unknown" */ - int prefer_unsym, /* if TRUE, always return T->stype of zero */ - /* ---- workspace */ - char *buf, /* of size MAXLINE+1 */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + size_t nrow, // number of rows + size_t ncol, // number of columns + size_t nnz, // number of triplets in file to read + int stype, // stype from header, or "unknown" + int prefer_unsym, // if TRUE, always return T->stype of zero + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE + // workspace: + char *buf, // of size MAXLINE+1 cholmod_common *Common ) { double x, z ; - double *Tx ; Int *Ti, *Tj, *Rdeg, *Cdeg ; cholmod_triplet *T ; double l1, l2 ; Int nitems, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j, - imax, jmax, skew_symmetric, p, complex_symmetric ; - size_t s, nnz2, extra ; - int ok = TRUE ; + imax, jmax, skew_symmetric, p, complex_symmetric ; - /* ---------------------------------------------------------------------- */ - /* quick return for empty matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return for empty matrix + //-------------------------------------------------------------------------- if (nrow == 0 || ncol == 0 || nnz == 0) { - /* return an empty matrix */ - return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL, - Common)) ; + // return an empty matrix + return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, + CHOLMOD_REAL + dtype, Common)) ; } - /* ---------------------------------------------------------------------- */ - /* special stype cases: unknown, skew symmetric, and complex symmetric */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // special stype cases: unknown, skew symmetric, and complex symmetric + //-------------------------------------------------------------------------- unknown = (stype == STYPE_UNKNOWN) ; skew_symmetric = (stype == STYPE_SKEW_SYMMETRIC) ; complex_symmetric = (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) ; - extra = 0 ; + size_t extra = 0 ; if (stype < STYPE_SYMMETRIC_LOWER - || (prefer_unsym && stype != STYPE_UNSYMMETRIC)) + || (prefer_unsym && stype != STYPE_UNSYMMETRIC)) { - /* 999: unknown might be converted to unsymmetric */ - /* 1: symmetric upper converted to unsym. if prefer_unsym is TRUE */ - /* -1: symmetric lower converted to unsym. if prefer_unsym is TRUE */ - /* -2: real or complex skew symmetric converted to unsymmetric */ - /* -3: complex symmetric converted to unsymmetric */ - stype = STYPE_UNSYMMETRIC ; - extra = nnz ; + // 999: unknown might be converted to unsymmetric + // 1: symmetric upper converted to unsym. if prefer_unsym is TRUE + // -1: symmetric lower converted to unsym. if prefer_unsym is TRUE + // -2: real or complex skew symmetric converted to unsymmetric + // -3: complex symmetric converted to unsymmetric + stype = STYPE_UNSYMMETRIC ; + extra = nnz ; } - nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ; + int ok = TRUE ; + size_t nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = nrow + ncol */ - s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ; - if (!ok || (Int) nrow > Int_max - || (Int) ncol > Int_max - || (Int) nnz > Int_max) + // s = nrow + ncol + size_t s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ; + if (!ok || nrow > Int_max || ncol > Int_max || nnz > Int_max) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (NULL) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (NULL) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; - Rdeg = Common->Iwork ; /* size nrow */ - Cdeg = Rdeg + nrow ; /* size ncol */ + Rdeg = Common->Iwork ; // size nrow + Cdeg = Rdeg + nrow ; // size ncol - /* ---------------------------------------------------------------------- */ - /* read the triplets */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the triplets + //-------------------------------------------------------------------------- is_lower = TRUE ; is_upper = TRUE ; @@ -579,7 +573,6 @@ static cholmod_triplet *read_triplet imax = 0 ; jmax = 0 ; - Tx = NULL ; Ti = NULL ; Tj = NULL ; xtype = 999 ; @@ -588,601 +581,708 @@ static cholmod_triplet *read_triplet for (k = 0 ; k < (Int) nnz ; k++) { - /* ------------------------------------------------------------------ */ - /* get the next triplet, skipping blank lines and comment lines */ - /* ------------------------------------------------------------------ */ - - l1 = EMPTY ; - l2 = EMPTY ; - x = 0 ; - z = 0 ; - - for ( ; ; ) - { - if (!get_line (f, buf)) - { - /* premature end of file - not enough triplets read in */ - ERROR (CHOLMOD_INVALID, "premature EOF") ; - return (NULL) ; - } - if (is_blank_line (buf)) - { - /* blank line or comment */ - continue ; - } - nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ; - x = fix_inf (x) ; - z = fix_inf (z) ; - break ; - } - - nitems = (nitems == EOF) ? 0 : nitems ; - i = l1 ; - j = l2 ; - - /* ------------------------------------------------------------------ */ - /* for first triplet: determine type and allocate triplet matrix */ - /* ------------------------------------------------------------------ */ - - if (k == 0) - { - if (nitems < 2 || nitems > 4) - { - /* invalid matrix */ - ERROR (CHOLMOD_INVALID, "invalid format") ; - return (NULL) ; - } - else if (nitems == 2) - { - /* this will be converted into a real matrix later */ - xtype = CHOLMOD_PATTERN ; - } - else if (nitems == 3) - { - xtype = CHOLMOD_REAL ; - } - else if (nitems == 4) - { - xtype = CHOLMOD_COMPLEX ; - } - - /* the rest of the lines should have the same number of entries */ - nshould = nitems ; - - /* allocate triplet matrix */ - T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, stype, - (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (NULL) ; - } - Ti = T->i ; - Tj = T->j ; - Tx = T->x ; - T->nnz = nnz ; - } - - /* ------------------------------------------------------------------ */ - /* save the entry in the triplet matrix */ - /* ------------------------------------------------------------------ */ - - if (nitems != nshould || i < 0 || j < 0) - { - /* wrong format, premature end-of-file, or negative indices */ - CHOLMOD(free_triplet) (&T, Common) ; - ERROR (CHOLMOD_INVALID, "invalid matrix file") ; - return (NULL) ; - } - - Ti [k] = i ; - Tj [k] = j ; - - if (i < j) - { - /* this entry is in the upper triangular part */ - is_lower = FALSE ; - } - if (i > j) - { - /* this entry is in the lower triangular part */ - is_upper = FALSE ; - } - - if (xtype == CHOLMOD_REAL) - { - Tx [k] = x ; - } - else if (xtype == CHOLMOD_COMPLEX) - { - Tx [2*k ] = x ; /* real part */ - Tx [2*k+1] = z ; /* imaginary part */ - } - - if (i == 0 || j == 0) - { - one_based = FALSE ; - } - - imax = MAX (i, imax) ; - jmax = MAX (j, jmax) ; + //---------------------------------------------------------------------- + // get the next triplet, skipping blank lines and comment lines + //---------------------------------------------------------------------- + + l1 = EMPTY ; + l2 = EMPTY ; + x = 0 ; + z = 0 ; + + for ( ; ; ) + { + if (!get_line (f, buf)) + { + // premature end of file - not enough triplets read in + ERROR (CHOLMOD_INVALID, "premature EOF") ; + return (NULL) ; + } + if (is_blank_line (buf)) + { + // blank line or comment + continue ; + } + nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ; + x = fix_inf (x) ; + z = fix_inf (z) ; + break ; + } + + nitems = (nitems == EOF) ? 0 : nitems ; + i = l1 ; + j = l2 ; + + //---------------------------------------------------------------------- + // for first triplet: determine type and allocate triplet matrix + //---------------------------------------------------------------------- + + if (k == 0) + { + if (nitems < 2 || nitems > 4) + { + // invalid matrix + ERROR (CHOLMOD_INVALID, "invalid format") ; + return (NULL) ; + } + else if (nitems == 2) + { + // this will be converted into a real matrix later + xtype = CHOLMOD_PATTERN ; + } + else if (nitems == 3) + { + xtype = CHOLMOD_REAL ; + } + else if (nitems == 4) + { + xtype = CHOLMOD_COMPLEX ; + } + + // the rest of the lines should have the same number of entries + nshould = nitems ; + + // allocate triplet matrix + T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, stype, + (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype) + dtype, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + Ti = T->i ; + Tj = T->j ; + T->nnz = nnz ; + } + + //---------------------------------------------------------------------- + // save the entry in the triplet matrix + //---------------------------------------------------------------------- + + if (nitems != nshould || i < 0 || j < 0) + { + // wrong format, premature end-of-file, or negative indices + CHOLMOD(free_triplet) (&T, Common) ; + ERROR (CHOLMOD_INVALID, "invalid matrix file") ; + return (NULL) ; + } + + Ti [k] = i ; + Tj [k] = j ; + + if (i < j) + { + // this entry is in the upper triangular part + is_lower = FALSE ; + } + if (i > j) + { + // this entry is in the lower triangular part + is_upper = FALSE ; + } + + #define ASSIGN_TRIPLET_VALUE(fltype) \ + { \ + fltype *Tx = (fltype *) T->x ; \ + if (xtype == CHOLMOD_REAL) \ + { \ + Tx [k] = x ; \ + } \ + else if (xtype == CHOLMOD_COMPLEX) \ + { \ + Tx [2*k ] = x ; \ + Tx [2*k+1] = z ; \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + ASSIGN_TRIPLET_VALUE (double) ; + } + else + { + ASSIGN_TRIPLET_VALUE (float) ; + } + + if (i == 0 || j == 0) + { + one_based = FALSE ; + } + + imax = MAX (i, imax) ; + jmax = MAX (j, jmax) ; } - /* ---------------------------------------------------------------------- */ - /* convert to zero-based */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert to zero-based + //-------------------------------------------------------------------------- if (one_based) { - /* input matrix is one-based; convert matrix to zero-based */ - for (k = 0 ; k < (Int) nnz ; k++) - { - Ti [k]-- ; - Tj [k]-- ; - } + // input matrix is one-based; convert matrix to zero-based + for (k = 0 ; k < (Int) nnz ; k++) + { + Ti [k]-- ; + Tj [k]-- ; + } } if (one_based ? - (imax > (Int) nrow || jmax > (Int) ncol) : - (imax >= (Int) nrow || jmax >= (Int) ncol)) + (imax > (Int) nrow || jmax > (Int) ncol) : + (imax >= (Int) nrow || jmax >= (Int) ncol)) { - /* indices out of range */ - CHOLMOD(free_triplet) (&T, Common) ; - ERROR (CHOLMOD_INVALID, "indices out of range") ; - return (NULL) ; + // indices out of range + CHOLMOD(free_triplet) (&T, Common) ; + ERROR (CHOLMOD_INVALID, "indices out of range") ; + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* determine the stype, if not yet known */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine the stype, if not yet known + //-------------------------------------------------------------------------- if (unknown) { - if (is_lower && is_upper) - { - /* diagonal matrix, symmetric with upper part present */ - stype = STYPE_SYMMETRIC_UPPER ; - } - else if (is_lower && !is_upper) - { - /* symmetric, lower triangular part present */ - stype = STYPE_SYMMETRIC_LOWER ; - } - else if (!is_lower && is_upper) - { - /* symmetric, upper triangular part present */ - stype = STYPE_SYMMETRIC_UPPER ; - } - else - { - /* unsymmetric */ - stype = STYPE_UNSYMMETRIC ; - extra = 0 ; - } + if (is_lower && is_upper) + { + // diagonal matrix, symmetric with upper part present + stype = STYPE_SYMMETRIC_UPPER ; + } + else if (is_lower && !is_upper) + { + // symmetric, lower triangular part present + stype = STYPE_SYMMETRIC_LOWER ; + } + else if (!is_lower && is_upper) + { + // symmetric, upper triangular part present + stype = STYPE_SYMMETRIC_UPPER ; + } + else + { + // unsymmetric + stype = STYPE_UNSYMMETRIC ; + extra = 0 ; + } } - /* ---------------------------------------------------------------------- */ - /* add the remainder of symmetric, skew-symmetric or Hermitian matrices */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // add the remainder of symmetric, skew-symmetric or Hermitian matrices + //-------------------------------------------------------------------------- - /* note that this step is not done for real symmetric or complex Hermitian - * matrices, unless prefer_unsym is TRUE */ + // note that this step is not done for real symmetric or complex Hermitian + // matrices, unless prefer_unsym is TRUE if (extra > 0) { - p = nnz ; - for (k = 0 ; k < (Int) nnz ; k++) - { - i = Ti [k] ; - j = Tj [k] ; - if (i != j) - { - Ti [p] = j ; - Tj [p] = i ; - if (xtype == CHOLMOD_REAL) - { - if (skew_symmetric) - { - Tx [p] = -Tx [k] ; - } - else - { - Tx [p] = Tx [k] ; - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - if (skew_symmetric) - { - Tx [2*p ] = -Tx [2*k ] ; - Tx [2*p+1] = -Tx [2*k+1] ; - } - else if (complex_symmetric) - { - Tx [2*p ] = Tx [2*k ] ; - Tx [2*p+1] = Tx [2*k+1] ; - } - else /* Hermitian */ - { - Tx [2*p ] = Tx [2*k ] ; - Tx [2*p+1] = -Tx [2*k+1] ; - } - } - p++ ; - } - } - T->nnz = p ; - nnz = p ; + p = nnz ; + for (k = 0 ; k < (Int) nnz ; k++) + { + i = Ti [k] ; + j = Tj [k] ; + if (i != j) + { + Ti [p] = j ; + Tj [p] = i ; + + #define ASSIGN_SYMMETRIC_TRIPLET(fltype) \ + { \ + fltype *Tx = (fltype *) T->x ; \ + if (xtype == CHOLMOD_REAL) \ + { \ + if (skew_symmetric) \ + { \ + Tx [p] = -Tx [k] ; \ + } \ + else \ + { \ + Tx [p] = Tx [k] ; \ + } \ + } \ + else if (xtype == CHOLMOD_COMPLEX) \ + { \ + if (skew_symmetric) \ + { \ + Tx [2*p ] = -Tx [2*k ] ; \ + Tx [2*p+1] = -Tx [2*k+1] ; \ + } \ + else if (complex_symmetric) \ + { \ + Tx [2*p ] = Tx [2*k ] ; \ + Tx [2*p+1] = Tx [2*k+1] ; \ + } \ + else /* Hermitian */ \ + { \ + Tx [2*p ] = Tx [2*k ] ; \ + Tx [2*p+1] = -Tx [2*k+1] ; \ + } \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + ASSIGN_SYMMETRIC_TRIPLET (double) ; + } + else + { + ASSIGN_SYMMETRIC_TRIPLET (float) ; + } + p++ ; + } + } + T->nnz = p ; + nnz = p ; } T->stype = stype ; - /* ---------------------------------------------------------------------- */ - /* create values for a pattern-only matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // create values for a pattern-only matrix + //-------------------------------------------------------------------------- if (xtype == CHOLMOD_PATTERN) { - if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary) - { - /* unsymmetric case, or binary case */ - for (k = 0 ; k < (Int) nnz ; k++) - { - Tx [k] = 1 ; - } - } - else - { - /* compute the row and columm degrees (excluding the diagonal) */ - for (i = 0 ; i < (Int) nrow ; i++) - { - Rdeg [i] = 0 ; - } - for (j = 0 ; j < (Int) ncol ; j++) - { - Cdeg [j] = 0 ; - } - for (k = 0 ; k < (Int) nnz ; k++) - { - i = Ti [k] ; - j = Tj [k] ; - if ((stype < 0 && i > j) || (stype > 0 && i < j)) - { - /* both a(i,j) and a(j,i) appear in the matrix */ - Rdeg [i]++ ; - Cdeg [j]++ ; - Rdeg [j]++ ; - Cdeg [i]++ ; - } - } - /* assign the numerical values */ - for (k = 0 ; k < (Int) nnz ; k++) - { - i = Ti [k] ; - j = Tj [k] ; - Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ; - } - } + if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary) + { + // unsymmetric case, or binary case + #define TRIPLETS_ALL_ONE(fltype) \ + { \ + fltype *Tx = (fltype *) T->x ; \ + for (k = 0 ; k < (Int) nnz ; k++) \ + { \ + Tx [k] = 1 ; \ + } \ + } + if (dtype == CHOLMOD_DOUBLE) + { + TRIPLETS_ALL_ONE (double) ; + } + else + { + TRIPLETS_ALL_ONE (float) ; + } + } + else + { + // compute the row and columm degrees (excluding the diagonal) + for (i = 0 ; i < (Int) nrow ; i++) + { + Rdeg [i] = 0 ; + } + for (j = 0 ; j < (Int) ncol ; j++) + { + Cdeg [j] = 0 ; + } + for (k = 0 ; k < (Int) nnz ; k++) + { + i = Ti [k] ; + j = Tj [k] ; + if ((stype < 0 && i > j) || (stype > 0 && i < j)) + { + // both a(i,j) and a(j,i) appear in the matrix + Rdeg [i]++ ; + Cdeg [j]++ ; + Rdeg [j]++ ; + Cdeg [i]++ ; + } + } + + // assign the numerical values + #define TRIPLET_LAPLACIAN(fltype) \ + { \ + fltype *Tx = (fltype *) T->x ; \ + for (k = 0 ; k < (Int) nnz ; k++) \ + { \ + i = Ti [k] ; \ + j = Tj [k] ; \ + Tx [k] = (i == j) ? (1 + MAX (Rdeg[i], Cdeg[j])) : (-1) ; \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + TRIPLET_LAPLACIAN (double) ; + } + else + { + TRIPLET_LAPLACIAN (float) ; + } + } } - /* ---------------------------------------------------------------------- */ - /* return the new triplet matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return the new triplet matrix + //-------------------------------------------------------------------------- return (T) ; } +//------------------------------------------------------------------------------ +// read_dense +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === read_dense =========================================================== */ -/* ========================================================================== */ - -/* Header has already been read in, including first line (nrow ncol). - * Read a dense matrix. */ +// Header has already been read in, including first line (nrow ncol). +// Read a dense matrix. static cholmod_dense *read_dense ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - size_t nrow, /* number of rows */ - size_t ncol, /* number of columns */ - int stype, /* stype from header */ - /* ---- workspace */ - char *buf, /* of size MAXLINE+1 */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + size_t nrow, // number of rows + size_t ncol, // number of columns + int stype, // stype from header + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE + // workspace: + char *buf, // of size MAXLINE+1 cholmod_common *Common ) { double x, z ; - double *Xx = NULL ; cholmod_dense *X ; Int nitems, xtype = -1, nshould = 0, i, j, k, kup, first ; - /* ---------------------------------------------------------------------- */ - /* quick return for empty matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return for empty matrix + //-------------------------------------------------------------------------- if (nrow == 0 || ncol == 0) { - /* return an empty dense matrix */ - return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL, Common)) ; + // return an empty dense matrix + return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL + dtype, Common)) ; } - /* ---------------------------------------------------------------------- */ - /* read the entries */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the entries + //-------------------------------------------------------------------------- first = TRUE ; for (j = 0 ; j < (Int) ncol ; j++) { - /* ------------------------------------------------------------------ */ - /* get the row index of the first entry in the file for column j */ - /* ------------------------------------------------------------------ */ - - if (stype == STYPE_UNSYMMETRIC) - { - i = 0 ; - } - else if (stype == STYPE_SKEW_SYMMETRIC) - { - i = j+1 ; - } - else /* real symmetric or complex Hermitian lower */ - { - i = j ; - } - - /* ------------------------------------------------------------------ */ - /* get column j */ - /* ------------------------------------------------------------------ */ - - for ( ; i < (Int) nrow ; i++) - { - - /* -------------------------------------------------------------- */ - /* get the next entry, skipping blank lines and comment lines */ - /* -------------------------------------------------------------- */ - - x = 0 ; - z = 0 ; - for ( ; ; ) - { - - if (!get_line (f, buf)) - { - /* premature end of file - not enough entries read in */ - ERROR (CHOLMOD_INVALID, "premature EOF") ; - return (NULL) ; - } - - if (is_blank_line (buf)) - { - /* blank line or comment */ - continue ; - } - nitems = sscanf (buf, "%lg %lg\n", &x, &z) ; - x = fix_inf (x) ; - z = fix_inf (z) ; - break ; - } - - nitems = (nitems == EOF) ? 0 : nitems ; - - /* -------------------------------------------------------------- */ - /* for first entry: determine type and allocate dense matrix */ - /* -------------------------------------------------------------- */ - - if (first) - { - first = FALSE ; - - if (nitems < 1 || nitems > 2) - { - /* invalid matrix */ - ERROR (CHOLMOD_INVALID, "invalid format") ; - return (NULL) ; - } - else if (nitems == 1) - { - /* a real matrix */ - xtype = CHOLMOD_REAL ; - } - else if (nitems == 2) - { - /* a complex matrix */ - xtype = CHOLMOD_COMPLEX ; - } - - /* the rest of the lines should have same number of entries */ - nshould = nitems ; - - /* allocate the result */ - X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (NULL) ; - } - Xx = X->x ; - } - - /* -------------------------------------------------------------- */ - /* save the entry in the dense matrix */ - /* -------------------------------------------------------------- */ - - if (nitems != nshould) - { - /* wrong format or premature end-of-file */ - CHOLMOD(free_dense) (&X, Common) ; - ERROR (CHOLMOD_INVALID, "invalid matrix file") ; - return (NULL) ; - } - - k = i + j*nrow ; - kup = j + i*nrow ; - - if (xtype == CHOLMOD_REAL) - { - /* real matrix */ - Xx [k] = x ; - if (k != kup) - { - if (stype == STYPE_SYMMETRIC_LOWER) - { - /* real symmetric matrix */ - Xx [kup] = x ; - } - else if (stype == STYPE_SKEW_SYMMETRIC) - { - /* real skew symmetric matrix */ - Xx [kup] = -x ; - } - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - Xx [2*k ] = x ; /* real part */ - Xx [2*k+1] = z ; /* imaginary part */ - if (k != kup) - { - if (stype == STYPE_SYMMETRIC_LOWER) - { - /* complex Hermitian */ - Xx [2*kup ] = x ; /* real part */ - Xx [2*kup+1] = -z ; /* imaginary part */ - } - else if (stype == STYPE_SKEW_SYMMETRIC) - { - /* complex skew symmetric */ - Xx [2*kup ] = -x ; /* real part */ - Xx [2*kup+1] = -z ; /* imaginary part */ - } - if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) - { - /* complex symmetric */ - Xx [2*kup ] = x ; /* real part */ - Xx [2*kup+1] = z ; /* imaginary part */ - } - } - } - } + //---------------------------------------------------------------------- + // get the row index of the first entry in the file for column j + //---------------------------------------------------------------------- + + if (stype == STYPE_UNSYMMETRIC) + { + i = 0 ; + } + else if (stype == STYPE_SKEW_SYMMETRIC) + { + i = j+1 ; + } + else // real symmetric or complex Hermitian lower + { + i = j ; + } + + //---------------------------------------------------------------------- + // get column j + //---------------------------------------------------------------------- + + for ( ; i < (Int) nrow ; i++) + { + + //------------------------------------------------------------------ + // get the next entry, skipping blank lines and comment lines + //------------------------------------------------------------------ + + x = 0 ; + z = 0 ; + for ( ; ; ) + { + + if (!get_line (f, buf)) + { + // premature end of file - not enough entries read in + ERROR (CHOLMOD_INVALID, "premature EOF") ; + return (NULL) ; + } + + if (is_blank_line (buf)) + { + // blank line or comment + continue ; + } + nitems = sscanf (buf, "%lg %lg\n", &x, &z) ; + x = fix_inf (x) ; + z = fix_inf (z) ; + break ; + } + + nitems = (nitems == EOF) ? 0 : nitems ; + + //------------------------------------------------------------------ + // for first entry: determine type and allocate dense matrix + //------------------------------------------------------------------ + + if (first) + { + first = FALSE ; + + if (nitems < 1 || nitems > 2) + { + // invalid matrix + ERROR (CHOLMOD_INVALID, "invalid format") ; + return (NULL) ; + } + else if (nitems == 1) + { + // a real matrix + xtype = CHOLMOD_REAL ; + } + else if (nitems == 2) + { + // a complex matrix + xtype = CHOLMOD_COMPLEX ; + } + + // the rest of the lines should have same number of entries + nshould = nitems ; + + // allocate the result + X = CHOLMOD(zeros) (nrow, ncol, xtype + dtype, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + } + + //------------------------------------------------------------------ + // save the entry in the dense matrix + //------------------------------------------------------------------ + + if (nitems != nshould) + { + // wrong format or premature end-of-file + CHOLMOD(free_dense) (&X, Common) ; + ERROR (CHOLMOD_INVALID, "invalid matrix file") ; + return (NULL) ; + } + + k = i + j*nrow ; + kup = j + i*nrow ; + + #define ASSIGN_DENSE_VALUE(fltype) \ + { \ + fltype *Xx = (fltype *) X->x ; \ + if (xtype == CHOLMOD_REAL) \ + { \ + /* real matrix */ \ + Xx [k] = x ; \ + if (k != kup) \ + { \ + if (stype == STYPE_SYMMETRIC_LOWER) \ + { \ + /* real symmetric matrix */ \ + Xx [kup] = x ; \ + } \ + else if (stype == STYPE_SKEW_SYMMETRIC) \ + { \ + /* real skew symmetric matrix */ \ + Xx [kup] = -x ; \ + } \ + } \ + } \ + else if (xtype == CHOLMOD_COMPLEX) \ + { \ + Xx [2*k ] = x ; /* real part */ \ + Xx [2*k+1] = z ; /* imaginary part */ \ + if (k != kup) \ + { \ + if (stype == STYPE_SYMMETRIC_LOWER) \ + { \ + /* complex Hermitian */ \ + Xx [2*kup ] = x ; /* real part */ \ + Xx [2*kup+1] = -z ; /* imaginary part */ \ + } \ + else if (stype == STYPE_SKEW_SYMMETRIC) \ + { \ + /* complex skew symmetric */ \ + Xx [2*kup ] = -x ; /* real part */ \ + Xx [2*kup+1] = -z ; /* imaginary part */ \ + } \ + if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) \ + { \ + /* complex symmetric */ \ + Xx [2*kup ] = x ; /* real part */ \ + Xx [2*kup+1] = z ; /* imaginary part */ \ + } \ + } \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + ASSIGN_DENSE_VALUE (double) ; + } + else + { + ASSIGN_DENSE_VALUE (float) ; + } + } } - /* ---------------------------------------------------------------------- */ - /* return the new dense matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return the new dense matrix + //-------------------------------------------------------------------------- return (X) ; } +//------------------------------------------------------------------------------ +// cholmod_read_triplet +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_read_triplet ================================================= */ -/* ========================================================================== */ - -/* Read in a triplet matrix from a file. */ +// Read in a triplet matrix from a file (as double, not float) cholmod_triplet *CHOLMOD(read_triplet) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) +{ + return (CHOLMOD(read_triplet2) (f, CHOLMOD_DOUBLE, Common)) ; +} + +//------------------------------------------------------------------------------ +// cholmod_read_triplet2 +//------------------------------------------------------------------------------ + +// Read in a triplet matrix from a file (as float or double) + +cholmod_triplet *CHOLMOD(read_triplet2) +( + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) { + char buf [MAXLINE+1] ; size_t nrow, ncol, nnz ; int stype, mtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* read the header and first data line */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the header and first data line + //-------------------------------------------------------------------------- if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) || - mtype != CHOLMOD_TRIPLET) + mtype != CHOLMOD_TRIPLET) { - /* invalid matrix - this function can only read in a triplet matrix */ - ERROR (CHOLMOD_INVALID, "invalid format") ; - return (NULL) ; + // invalid matrix - this function can only read in a triplet matrix + ERROR (CHOLMOD_INVALID, "invalid format") ; + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* read the triplet matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the triplet matrix + //-------------------------------------------------------------------------- - return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, buf, Common)) ; + return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, + dtype, buf, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_read_sparse +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_read_sparse ================================================== */ -/* ========================================================================== */ - -/* Read a sparse matrix from a file. See cholmod_read_triplet for a discussion - * of the file format. - * - * If Common->prefer_upper is TRUE (the default case), a symmetric matrix is - * returned stored in upper-triangular form (A->stype == 1). - */ +// Read a sparse matrix from a file (as double). See cholmod_read_triplet for +// a discussion of the file format. +// +// If Common->prefer_upper is TRUE (the default case), a symmetric matrix is +// returned stored in upper-triangular form (A->stype == 1). cholmod_sparse *CHOLMOD(read_sparse) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) +{ + return (CHOLMOD(read_sparse2) (f, CHOLMOD_DOUBLE, Common)) ; +} + +//------------------------------------------------------------------------------ +// cholmod_read_sparse2: read sparse matrix from a file (double or single) +//------------------------------------------------------------------------------ + +cholmod_sparse *CHOLMOD(read_sparse2) +( + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) { cholmod_sparse *A, *A2 ; cholmod_triplet *T ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* convert to a sparse matrix in compressed-column form */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert to a sparse matrix in compressed-column form + //-------------------------------------------------------------------------- - T = CHOLMOD(read_triplet) (f, Common) ; + T = CHOLMOD(read_triplet2) (f, dtype, Common) ; A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ; CHOLMOD(free_triplet) (&T, Common) ; if (Common->prefer_upper && A != NULL && A->stype == -1) { - /* A=A' */ - A2 = CHOLMOD(transpose) (A, 2, Common) ; - CHOLMOD(free_sparse) (&A, Common) ; - A = A2 ; + // A=A' + A2 = CHOLMOD(transpose) (A, 2, Common) ; + CHOLMOD(free_sparse) (&A, Common) ; + A = A2 ; } return (A) ; } +//------------------------------------------------------------------------------ +// cholmod_read_dense +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_read_dense =================================================== */ -/* ========================================================================== */ - -/* Read a dense matrix from a file. */ +// Read a dense matrix from a file (double only). cholmod_dense *CHOLMOD(read_dense) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) +{ + return (CHOLMOD(read_dense2) (f, CHOLMOD_DOUBLE, Common)) ; +} + +//------------------------------------------------------------------------------ +// cholmod_read_dense2 +//------------------------------------------------------------------------------ + +// Read a dense matrix from a file (float or double). + +cholmod_dense *CHOLMOD(read_dense2) +( + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) { @@ -1190,64 +1290,77 @@ cholmod_dense *CHOLMOD(read_dense) size_t nrow, ncol, nnz ; int stype, mtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* read the header and first data line */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the header and first data line + //-------------------------------------------------------------------------- if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) || - mtype != CHOLMOD_DENSE) + mtype != CHOLMOD_DENSE) { - /* invalid matrix - this function can only read in a dense matrix */ - ERROR (CHOLMOD_INVALID, "invalid format") ; - return (NULL) ; + // invalid matrix - this function can only read in a dense matrix + ERROR (CHOLMOD_INVALID, "invalid format") ; + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* read the dense matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the dense matrix + //-------------------------------------------------------------------------- - return (read_dense (f, nrow, ncol, stype, buf, Common)) ; + return (read_dense (f, nrow, ncol, stype, dtype, buf, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_read_matrix +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_read_matrix ================================================== */ -/* ========================================================================== */ - -/* Read a triplet matrix, sparse matrix or a dense matrix from a file. Returns - * a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense - * object. The type of object is passed back to the caller as the mtype - * argument. */ +// Read a triplet matrix, sparse matrix or a dense matrix from a file. Returns +// a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense +// object. The type of object is passed back to the caller as the mtype +// argument. The matrix is read in double precision only. void *CHOLMOD(read_matrix) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - int prefer, /* If 0, a sparse matrix is always return as a - * cholmod_triplet form. It can have any stype - * (symmetric-lower, unsymmetric, or - * symmetric-upper). - * If 1, a sparse matrix is returned as an unsymmetric - * cholmod_sparse form (A->stype == 0), with both - * upper and lower triangular parts present. - * This is what the MATLAB mread mexFunction does, - * since MATLAB does not have an stype. - * If 2, a sparse matrix is returned with an stype of 0 - * or 1 (unsymmetric, or symmetric with upper part - * stored). - * This argument has no effect for dense matrices. - */ - /* ---- output---- */ - int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int prefer, // If 0, a sparse matrix is always return as a + // cholmod_triplet form. It can have any stype + // (symmetric-lower, unsymmetric, or symmetric-upper). + // If 1, a sparse matrix is returned as an unsymmetric + // cholmod_sparse form (A->stype == 0), with both upper and + // lower triangular parts present. This is what the MATLAB + // mread mexFunction does, since MATLAB does not have an + // stype. + // If 2, a sparse matrix is returned with an stype of 0 or + // 1 (unsymmetric, or symmetric with upper part stored). + // This argument has no effect for dense matrices. + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE + cholmod_common *Common +) +{ + return (CHOLMOD(read_matrix2) (f, prefer, CHOLMOD_DOUBLE, mtype, Common)) ; +} + +//------------------------------------------------------------------------------ +// cholmod_read_matrix2: same as cholmod_read_matrix, but float or double +//------------------------------------------------------------------------------ + +void *CHOLMOD(read_matrix2) +( + // input: + FILE *f, // file to read from, must already be open + int prefer, // see cholmod_read_matrix + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE cholmod_common *Common ) { @@ -1258,61 +1371,64 @@ void *CHOLMOD(read_matrix) size_t nrow, ncol, nnz ; int stype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; RETURN_IF_NULL (mtype, NULL) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* read the header to determine the mtype */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the header to determine the mtype + //-------------------------------------------------------------------------- if (!read_header (f, buf, mtype, &nrow, &ncol, &nnz, &stype)) { - /* invalid matrix */ - ERROR (CHOLMOD_INVALID, "invalid format") ; - return (NULL) ; + // invalid matrix + ERROR (CHOLMOD_INVALID, "invalid format") ; + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* read a matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read a matrix + //-------------------------------------------------------------------------- if (*mtype == CHOLMOD_TRIPLET) { - /* read in the triplet matrix, converting to unsymmetric format if - * prefer == 1 */ - T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, buf, Common) ; - if (prefer == 0) - { - /* return matrix in its original triplet form */ - G = T ; - } - else - { - /* return matrix in a compressed-column form */ - A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ; - CHOLMOD(free_triplet) (&T, Common) ; - if (A != NULL && prefer == 2 && A->stype == -1) - { - /* convert A from symmetric-lower to symmetric-upper */ - A2 = CHOLMOD(transpose) (A, 2, Common) ; - CHOLMOD(free_sparse) (&A, Common) ; - A = A2 ; - } - *mtype = CHOLMOD_SPARSE ; - G = A ; - } + // read in the triplet matrix, converting to unsymmetric format if + // prefer == 1 + T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, + dtype, buf, Common) ; + if (prefer == 0) + { + // return matrix in its original triplet form + G = T ; + } + else + { + // return matrix in a compressed-column form + A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ; + CHOLMOD(free_triplet) (&T, Common) ; + if (A != NULL && prefer == 2 && A->stype == -1) + { + // convert A from symmetric-lower to symmetric-upper + A2 = CHOLMOD(transpose) (A, 2, Common) ; + CHOLMOD(free_sparse) (&A, Common) ; + A = A2 ; + } + *mtype = CHOLMOD_SPARSE ; + G = A ; + } } else if (*mtype == CHOLMOD_DENSE) { - /* return a dense matrix */ - G = read_dense (f, nrow, ncol, stype, buf, Common) ; + // return a dense matrix + G = read_dense (f, nrow, ncol, stype, dtype, buf, Common) ; } return (G) ; } + #endif + diff --git a/CHOLMOD/Check/cholmod_write.c b/CHOLMOD/Check/cholmod_write.c index b19f2d0304..da8a997245 100644 --- a/CHOLMOD/Check/cholmod_write.c +++ b/CHOLMOD/Check/cholmod_write.c @@ -2,29 +2,28 @@ // CHOLMOD/Check/cholmod_write: write a matrix to a file in Matrix Market format //------------------------------------------------------------------------------ -// CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Write a matrix to a file in Matrix Market form. - * - * A can be sparse or full. - * - * If present and non-empty, A and Z must have the same dimension. Z contains - * the explicit zero entries in the matrix (which MATLAB drops). The entries - * of Z appear as explicit zeros in the output file. Z is optional. If it is - * an empty matrix it is ignored. Z must be sparse or empty, if present. - * It is ignored if A is full. - * - * filename is the name of the output file. comments is file whose - * contents are include after the Matrix Market header and before the first - * data line. Ignored if an empty string or not present. - * - * Except for the workspace used by cholmod_symmetry (ncol integers) for - * the sparse case, these routines use no workspace at all. - */ +// Write a matrix to a file in Matrix Market form. +// +// A can be sparse or full. +// +// If present and non-empty, A and Z must have the same dimension. Z contains +// the explicit zero entries in the matrix (which MATLAB drops). The entries +// of Z appear as explicit zeros in the output file. Z is optional. If it is +// an empty matrix it is ignored. Z must be sparse or empty, if present. +// It is ignored if A is full. +// +// filename is the name of the output file. comments is file whose +// contents are include after the Matrix Market header and before the first +// data line. Ignored if an empty string or not present. +// +// Except for the workspace used by cholmod_symmetry (ncol integers) for +// the sparse case, these routines use no workspace at all. #ifndef NCHECK @@ -33,14 +32,13 @@ #define MMLEN 1024 #define MAXLINE MMLEN+6 -/* ========================================================================== */ -/* === include_comments ===================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// include_comments +//------------------------------------------------------------------------------ -/* Read in the comments file, if it exists, and copy it to the Matrix Market - * file. A "%" is prepended to each line. Returns TRUE if successful, FALSE - * otherwise. - */ +// Read in the comments file, if it exists, and copy it to the Matrix Market +// file. A "%" is prepended to each line. Returns TRUE if successful, FALSE +// otherwise. static int include_comments (FILE *f, const char *comments) { @@ -49,78 +47,88 @@ static int include_comments (FILE *f, const char *comments) int ok = TRUE ; if (comments != NULL && comments [0] != '\0') { - cf = fopen (comments, "r") ; - if (cf == NULL) - { - return (FALSE) ; - } - while (ok && fgets (buffer, MAXLINE, cf) != NULL) - { - /* ensure the line is not too long */ - buffer [MMLEN-1] = '\0' ; - buffer [MMLEN-2] = '\n' ; - ok = ok && (fprintf (f, "%%%s", buffer) > 0) ; - } - fclose (cf) ; + cf = fopen (comments, "r") ; + if (cf == NULL) + { + return (FALSE) ; + } + while (ok && fgets (buffer, MAXLINE, cf) != NULL) + { + // ensure the line is not too long + buffer [MMLEN-1] = '\0' ; + buffer [MMLEN-2] = '\n' ; + ok = ok && (fprintf (f, "%%%s", buffer) > 0) ; + } + fclose (cf) ; } return (ok) ; } +//------------------------------------------------------------------------------ +// get_value +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === get_value ============================================================ */ -/* ========================================================================== */ - -/* Get the pth value in the matrix. */ +// Get the pth value in a double or float matrix. Resulting scalar is returned +// as double (x and z). static void get_value ( - double *Ax, /* real values, or real/imag. for CHOLMOD_COMPLEX type */ - double *Az, /* imaginary values for CHOLMOD_ZOMPLEX type */ - Int p, /* get the pth entry */ - Int xtype, /* A->xtype: pattern, real, complex, or zomplex */ - double *x, /* the real part */ - double *z /* the imaginary part */ + void *Ax_in, // real values, or real/imag. for CHOLMOD_COMPLEX type + void *Az_in, // imaginary values for CHOLMOD_ZOMPLEX type + Int p, // get the pth entry + int xtype, // A->xtype: pattern, real, complex, or zomplex + int dtype, // A->dtype: double or single + double *x, // the real part + double *z // the imaginary part ) { - switch (xtype) + #define GET_VALUE(fltype) \ + { \ + fltype *Ax = (fltype *) Ax_in ; \ + fltype *Az = (fltype *) Az_in ; \ + switch (xtype) \ + { \ + case CHOLMOD_PATTERN: \ + *x = 1 ; \ + *z = 0 ; \ + break ; \ + case CHOLMOD_REAL: \ + *x = (double) Ax [p] ; \ + *z = 0 ; \ + break ; \ + case CHOLMOD_COMPLEX: \ + *x = (double) Ax [2*p] ; \ + *z = (double) Ax [2*p+1] ; \ + break ; \ + case CHOLMOD_ZOMPLEX: \ + *x = (double) Ax [p] ; \ + *z = (double) Az [p] ; \ + break ; \ + } \ + } + + if (dtype == CHOLMOD_DOUBLE) + { + GET_VALUE (double) ; + } + else { - case CHOLMOD_PATTERN: - *x = 1 ; - *z = 0 ; - break ; - - case CHOLMOD_REAL: - *x = Ax [p] ; - *z = 0 ; - break ; - - case CHOLMOD_COMPLEX: - *x = Ax [2*p] ; - *z = Ax [2*p+1] ; - break ; - - case CHOLMOD_ZOMPLEX: - *x = Ax [p] ; - *z = Az [p] ; - break ; + GET_VALUE (float) ; } } +//------------------------------------------------------------------------------ +// print_value +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === print_value ========================================================== */ -/* ========================================================================== */ - -/* Print a numeric value to the file, using the shortest format that ensures - * the value is written precisely. Returns TRUE if successful, FALSE otherwise. - */ +// Print a numeric value to the file, using the shortest format that ensures +// the value is written precisely. Returns TRUE if successful, FALSE otherwise. static int print_value ( - FILE *f, /* file to print to */ - double x, /* value to print */ - Int is_integer /* TRUE if printing as an integer */ + FILE *f, // file to print to + double x, // value to print + Int is_integer // TRUE if printing as an integer ) { double y ; @@ -130,174 +138,159 @@ static int print_value if (is_integer) { - i = (Int) x ; - ok = (fprintf (f, ID, i) > 0) ; - return (ok) ; + i = (Int) x ; + ok = (fprintf (f, ID, i) > 0) ; + return (ok) ; } - /* ---------------------------------------------------------------------- */ - /* handle Inf and NaN */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // handle Inf and NaN + //-------------------------------------------------------------------------- - /* change -inf to -HUGE_DOUBLE, and change +inf and nan to +HUGE_DOUBLE */ + // change -inf to -HUGE_DOUBLE, and change +inf and nan to +HUGE_DOUBLE if (isnan (x) || x >= HUGE_DOUBLE) { - x = HUGE_DOUBLE ; + x = HUGE_DOUBLE ; } else if (x <= -HUGE_DOUBLE) { - x = -HUGE_DOUBLE ; + x = -HUGE_DOUBLE ; } - /* ---------------------------------------------------------------------- */ - /* find the smallest acceptable precision */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the smallest acceptable precision + //-------------------------------------------------------------------------- for (width = 6 ; width < 20 ; width++) { - sprintf (s, "%.*g", width, x) ; - sscanf (s, "%lg", &y) ; - if (x == y) break ; + sprintf (s, "%.*g", width, x) ; + sscanf (s, "%lg", &y) ; + if (x == y) break ; } - /* ---------------------------------------------------------------------- */ - /* shorten the string */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // shorten the string + //-------------------------------------------------------------------------- - /* change "e+0" to "e", change "e+" to "e", and change "e-0" to "e-" */ + // change "e+0" to "e", change "e+" to "e", and change "e-0" to "e-" for (i = 0 ; i < MAXLINE && s [i] != '\0' ; i++) { - if (s [i] == 'e') - { - if (s [i+1] == '+') - { - dest = i+1 ; - if (s [i+2] == '0') - { - /* delete characters s[i+1] and s[i+2] */ - src = i+3 ; - } - else - { - /* delete characters s[i+1] */ - src = i+2 ; - } - } - else if (s [i+1] == '-') - { - dest = i+2 ; - if (s [i+2] == '0') - { - /* delete character s[i+2] */ - src = i+3 ; - } - else - { - /* no change */ - break ; - } - } - while (s [src] != '\0') - { - s [dest++] = s [src++] ; - } - s [dest] = '\0' ; - break ; - } - } - - /* delete the leading "0" if present and not necessary */ + if (s [i] == 'e') + { + if (s [i+1] == '+') + { + dest = i+1 ; + if (s [i+2] == '0') + { + // delete characters s[i+1] and s[i+2] + src = i+3 ; + } + else + { + // delete characters s[i+1] + src = i+2 ; + } + } + else if (s [i+1] == '-') + { + dest = i+2 ; + if (s [i+2] == '0') + { + // delete character s[i+2] + src = i+3 ; + } + else + { + // no change + break ; + } + } + while (s [src] != '\0') + { + s [dest++] = s [src++] ; + } + s [dest] = '\0' ; + break ; + } + } + + // delete the leading "0" if present and not necessary p = s ; s [MAXLINE-1] = '\0' ; i = strlen (s) ; if (i > 2 && s [0] == '0' && s [1] == '.') { - /* change "0.x" to ".x" */ - p = s + 1 ; + // change "0.x" to ".x" + p = s + 1 ; } else if (i > 3 && s [0] == '-' && s [1] == '0' && s [2] == '.') { - /* change "-0.x" to "-.x" */ - s [1] = '-' ; - p = s + 1 ; + // change "-0.x" to "-.x" + s [1] = '-' ; + p = s + 1 ; } -#if 0 - /* double-check */ - i = sscanf (p, "%lg", &z) ; - if (i != 1 || y != z) - { - /* oops! something went wrong in the "e+0" edit, above. */ - /* this "cannot" happen */ - sprintf (s, "%.*g", width, x) ; - p = s ; - } -#endif - - /* ---------------------------------------------------------------------- */ - /* print the value to the file */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // print the value to the file + //-------------------------------------------------------------------------- ok = (fprintf (f, "%s", p) > 0) ; return (ok) ; } +//------------------------------------------------------------------------------ +// print_triplet +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === print_triplet ======================================================== */ -/* ========================================================================== */ - -/* Print a triplet, converting it to one-based. Returns TRUE if successful, - * FALSE otherwise. - */ +// Print a triplet, converting it to one-based. Returns TRUE if successful, +// FALSE otherwise. static int print_triplet ( - FILE *f, /* file to print to */ - Int is_binary, /* TRUE if file is "pattern" */ - Int is_complex, /* TRUE if file is "complex" */ - Int is_integer, /* TRUE if file is "integer" */ - Int i, /* row index (zero-based) */ - Int j, /* column index (zero-based) */ - double x, /* real part */ - double z /* imaginary part */ + FILE *f, // file to print to + Int is_binary, // TRUE if file is "pattern" + Int is_complex, // TRUE if file is "complex" + Int is_integer, // TRUE if file is "integer" + Int i, // row index (zero-based) + Int j, // column index (zero-based) + double x, // real part + double z // imaginary part ) { - int ok ; + int ok ; ok = (fprintf (f, ID " " ID, 1+i, 1+j) > 0) ; if (!is_binary) { - fprintf (f, " ") ; - ok = ok && print_value (f, x, is_integer) ; - if (is_complex) - { - fprintf (f, " ") ; - ok = ok && print_value (f, z, is_integer) ; - } + fprintf (f, " ") ; + ok = ok && print_value (f, x, is_integer) ; + if (is_complex) + { + fprintf (f, " ") ; + ok = ok && print_value (f, z, is_integer) ; + } } ok = ok && (fprintf (f, "\n") > 0) ; return (ok) ; } +//------------------------------------------------------------------------------ +// ntriplets +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === ntriplets ============================================================ */ -/* ========================================================================== */ - -/* Compute the number of triplets that will be printed to the file - * from the matrix A. */ +// Compute the number of triplets that will be printed to the file +// from the matrix A. static Int ntriplets ( - cholmod_sparse *A, /* matrix that will be printed */ - Int is_sym /* TRUE if the file is symmetric (lower part only)*/ + cholmod_sparse *A, // matrix that will be printed + Int is_sym // TRUE if the file is symmetric (lower part only) ) { Int *Ap, *Ai, *Anz, packed, i, j, p, pend, ncol, stype, nz = 0 ; if (A == NULL) { - /* the Z matrix is NULL */ - return (0) ; + // the Z matrix is NULL + return (0) ; } stype = A->stype ; Ap = A->p ; @@ -307,70 +300,67 @@ static Int ntriplets ncol = A->ncol ; for (j = 0 ; j < ncol ; j++) { - p = Ap [j] ; - pend = (packed) ? Ap [j+1] : p + Anz [j] ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) - { - /* CHOLMOD matrix is symmetric-lower (and so is the file); - * or CHOLMOD matrix is unsymmetric and either A(i,j) is in - * the lower part or the file is unsymmetric. */ - nz++ ; - } - else if (stype > 0 && i <= j) - { - /* CHOLMOD matrix is symmetric-upper, but the file is - * symmetric-lower. Need to transpose the entry. */ - nz++ ; - } - } + p = Ap [j] ; + pend = (packed) ? Ap [j+1] : p + Anz [j] ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) + { + // CHOLMOD matrix is symmetric-lower (and so is the file); + // or CHOLMOD matrix is unsymmetric and either A(i,j) is in + // the lower part or the file is unsymmetric. + nz++ ; + } + else if (stype > 0 && i <= j) + { + // CHOLMOD matrix is symmetric-upper, but the file is + // symmetric-lower. Need to transpose the entry. + nz++ ; + } + } } return (nz) ; } +//------------------------------------------------------------------------------ +// cholmod_write_sparse +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_write_sparse ================================================= */ -/* ========================================================================== */ - -/* Write a sparse matrix to a file in Matrix Market format. Optionally include - * comments, and print explicit zero entries given by the pattern of the Z - * matrix. If not NULL, the Z matrix must have the same dimensions and stype - * as A. - * - * Returns the symmetry in which the matrix was printed (1 to 7, see the - * CHOLMOD_MM_* codes in CHOLMOD/Include/cholmod.h), or -1 on failure. - * - * If A and Z are sorted on input, and either unsymmetric (stype = 0) or - * symmetric-lower (stype < 0), and if A and Z do not overlap, then the triplets - * are sorted, first by column and then by row index within each column, with - * no duplicate entries. If all the above holds except stype > 0, then the - * triplets are sorted by row first and then column. - */ +// Write a sparse matrix to a file in Matrix Market format. Optionally include +// comments, and print explicit zero entries given by the pattern of the Z +// matrix. If not NULL, the Z matrix must have the same dimensions and stype +// as A. +// +// Returns the symmetry in which the matrix was printed (1 to 7, see the +// CHOLMOD_MM_* codes in CHOLMOD/Include/cholmod.h), or -1 on failure. +// +// If A and Z are sorted on input, and either unsymmetric (stype = 0) or +// symmetric-lower (stype < 0), and if A and Z do not overlap, then the triplets +// are sorted, first by column and then by row index within each column, with +// no duplicate entries. If all the above holds except stype > 0, then the +// triplets are sorted by row first and then column. int CHOLMOD(write_sparse) ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_sparse *A, /* matrix to print */ - cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to write to, must already be open + cholmod_sparse *A, // matrix to print + cholmod_sparse *Z, // optional matrix with pattern of explicit zeros + const char *comments, // optional filename of comments to include cholmod_common *Common ) { double x = 0, z = 0 ; - double *Ax, *Az ; + void *Ax, *Az ; Int *Ap, *Ai, *Anz, *Zp, *Zi, *Znz ; Int nrow, ncol, is_complex, symmetry, i, j, q, iz, p, nz, is_binary, stype, - is_integer, asym, is_sym, xtype, apacked, zpacked, pend, qend, zsym ; - int ok ; + is_integer, asym, is_sym, apacked, zpacked, pend, qend, zsym ; + int ok, xtype, dtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (f, EMPTY) ; @@ -378,23 +368,23 @@ int CHOLMOD(write_sparse) RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (Z != NULL && (Z->nrow == 0 || Z->ncol == 0)) { - /* Z is non-NULL but empty, so treat it as a NULL matrix */ - Z = NULL ; + // Z is non-NULL but empty, so treat it as a NULL matrix + Z = NULL ; } if (Z != NULL) { - RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; - if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype) - { - ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ; - return (EMPTY) ; - } + RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; + if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype) + { + ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ; + return (EMPTY) ; + } } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get the A matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the A matrix + //-------------------------------------------------------------------------- Ap = A->p ; Ai = A->i ; @@ -404,53 +394,54 @@ int CHOLMOD(write_sparse) nrow = A->nrow ; ncol = A->ncol ; xtype = A->xtype ; + dtype = A->dtype ; apacked = A->packed ; if (xtype == CHOLMOD_PATTERN) { - /* a CHOLMOD pattern matrix is printed as "pattern" in the file */ - is_binary = TRUE ; - is_integer = FALSE ; - is_complex = FALSE ; + // a CHOLMOD pattern matrix is printed as "pattern" in the file + is_binary = TRUE ; + is_integer = FALSE ; + is_complex = FALSE ; } else if (xtype == CHOLMOD_REAL) { - /* determine if a real matrix is in fact binary or integer */ - is_binary = TRUE ; - is_integer = TRUE ; - is_complex = FALSE ; - for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++) - { - p = Ap [j] ; - pend = (apacked) ? Ap [j+1] : p + Anz [j] ; - for ( ; (is_binary || is_integer) && p < pend ; p++) - { - x = Ax [p] ; - if (x != 1) - { - is_binary = FALSE ; - } - /* convert to Int and then back to double */ - i = (Int) x ; - z = (double) i ; - if (z != x) - { - is_integer = FALSE ; - } - } - } + // determine if a real matrix is in fact binary or integer + is_binary = TRUE ; + is_integer = TRUE ; + is_complex = FALSE ; + for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++) + { + p = Ap [j] ; + pend = (apacked) ? Ap [j+1] : p + Anz [j] ; + for ( ; (is_binary || is_integer) && p < pend ; p++) + { + get_value (Ax, Az, p, xtype, dtype, &x, &z) ; + if (x != 1) + { + is_binary = FALSE ; + } + // convert to Int and then back to double + i = (Int) x ; + z = (double) i ; + if (z != x) + { + is_integer = FALSE ; + } + } + } } else { - /* a CHOLMOD complex matrix is printed as "complex" in the file */ - is_binary = FALSE ; - is_integer = FALSE ; - is_complex = TRUE ; + // a CHOLMOD complex matrix is printed as "complex" in the file + is_binary = FALSE ; + is_integer = FALSE ; + is_complex = TRUE ; } - /* ---------------------------------------------------------------------- */ - /* get the Z matrix (only consider the pattern) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the Z matrix (only consider the pattern) + //-------------------------------------------------------------------------- Zp = NULL ; Zi = NULL ; @@ -458,220 +449,216 @@ int CHOLMOD(write_sparse) zpacked = TRUE ; if (Z != NULL) { - Zp = Z->p ; - Zi = Z->i ; - Znz = Z->nz ; - zpacked = Z->packed ; + Zp = Z->p ; + Zi = Z->i ; + Znz = Z->nz ; + zpacked = Z->packed ; } - /* ---------------------------------------------------------------------- */ - /* determine the symmetry of A and Z */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine the symmetry of A and Z + //-------------------------------------------------------------------------- stype = A->stype ; if (A->nrow != A->ncol) { - asym = CHOLMOD_MM_RECTANGULAR ; + asym = CHOLMOD_MM_RECTANGULAR ; } else if (stype != 0) { - /* CHOLMOD's A and Z matrices have a symmetric (and matching) stype. - * Note that the diagonal is not checked. */ - asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ; + // CHOLMOD's A and Z matrices have a symmetric (and matching) stype. + // Note that the diagonal is not checked. + asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ; } else if (!A->sorted) { - /* A is in unsymmetric storage, but unsorted */ - asym = CHOLMOD_MM_UNSYMMETRIC ; + // A is in unsymmetric storage, but unsorted + asym = CHOLMOD_MM_UNSYMMETRIC ; } else { - /* CHOLMOD's stype is zero (stored in unsymmetric form) */ - asym = EMPTY ; - zsym = EMPTY ; + // CHOLMOD's stype is zero (stored in unsymmetric form) + asym = EMPTY ; + zsym = EMPTY ; #ifndef NMATRIXOPS - /* determine if the matrices are in fact symmetric or Hermitian */ - asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ; - zsym = (Z == NULL) ? 999 : - CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ; + // determine if the matrices are in fact symmetric or Hermitian + asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ; + zsym = (Z == NULL) ? 999 : + CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ; #endif - if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC) - { - /* not computed, out of memory, or Z is unsymmetric */ - asym = CHOLMOD_MM_UNSYMMETRIC ; - } + if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC) + { + // not computed, out of memory, or Z is unsymmetric + asym = CHOLMOD_MM_UNSYMMETRIC ; + } } - /* ---------------------------------------------------------------------- */ - /* write the Matrix Market header */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // write the Matrix Market header + //-------------------------------------------------------------------------- ok = fprintf (f, "%%%%MatrixMarket matrix coordinate") > 0 ; if (is_complex) { - ok = ok && (fprintf (f, " complex") > 0) ; + ok = ok && (fprintf (f, " complex") > 0) ; } else if (is_binary) { - ok = ok && (fprintf (f, " pattern") > 0) ; + ok = ok && (fprintf (f, " pattern") > 0) ; } else if (is_integer) { - ok = ok && (fprintf (f, " integer") > 0) ; + ok = ok && (fprintf (f, " integer") > 0) ; } else { - ok = ok && (fprintf (f, " real") > 0) ; + ok = ok && (fprintf (f, " real") > 0) ; } is_sym = FALSE ; switch (asym) { - case CHOLMOD_MM_RECTANGULAR: - case CHOLMOD_MM_UNSYMMETRIC: - /* A is rectangular or unsymmetric */ - ok = ok && (fprintf (f, " general\n") > 0) ; - is_sym = FALSE ; - symmetry = CHOLMOD_MM_UNSYMMETRIC ; - break ; - - case CHOLMOD_MM_SYMMETRIC: - case CHOLMOD_MM_SYMMETRIC_POSDIAG: - /* A is symmetric */ - ok = ok && (fprintf (f, " symmetric\n") > 0) ; - is_sym = TRUE ; - symmetry = CHOLMOD_MM_SYMMETRIC ; - break ; - - case CHOLMOD_MM_HERMITIAN: - case CHOLMOD_MM_HERMITIAN_POSDIAG: - /* A is Hermitian */ - ok = ok && (fprintf (f, " Hermitian\n") > 0) ; - is_sym = TRUE ; - symmetry = CHOLMOD_MM_HERMITIAN ; - break ; - - case CHOLMOD_MM_SKEW_SYMMETRIC: - /* A is skew symmetric */ - ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ; - is_sym = TRUE ; - symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ; - break ; - } - - /* ---------------------------------------------------------------------- */ - /* include the comments if present */ - /* ---------------------------------------------------------------------- */ + case CHOLMOD_MM_RECTANGULAR: + case CHOLMOD_MM_UNSYMMETRIC: + // A is rectangular or unsymmetric + ok = ok && (fprintf (f, " general\n") > 0) ; + is_sym = FALSE ; + symmetry = CHOLMOD_MM_UNSYMMETRIC ; + break ; + + case CHOLMOD_MM_SYMMETRIC: + case CHOLMOD_MM_SYMMETRIC_POSDIAG: + // A is symmetric + ok = ok && (fprintf (f, " symmetric\n") > 0) ; + is_sym = TRUE ; + symmetry = CHOLMOD_MM_SYMMETRIC ; + break ; + + case CHOLMOD_MM_HERMITIAN: + case CHOLMOD_MM_HERMITIAN_POSDIAG: + // A is Hermitian + ok = ok && (fprintf (f, " Hermitian\n") > 0) ; + is_sym = TRUE ; + symmetry = CHOLMOD_MM_HERMITIAN ; + break ; + + case CHOLMOD_MM_SKEW_SYMMETRIC: + // A is skew symmetric + ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ; + is_sym = TRUE ; + symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ; + break ; + } + + //-------------------------------------------------------------------------- + // include the comments if present + //-------------------------------------------------------------------------- ok = ok && include_comments (f, comments) ; - /* ---------------------------------------------------------------------- */ - /* write a sparse matrix (A and Z) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // write a sparse matrix (A and Z) + //-------------------------------------------------------------------------- nz = ntriplets (A, is_sym) + ntriplets (Z, is_sym) ; - /* write the first data line, with nrow, ncol, and # of triplets */ + // write the first data line, with nrow, ncol, and # of triplets ok = ok && (fprintf (f, ID " " ID " " ID "\n", nrow, ncol, nz) > 0) ; for (j = 0 ; ok && j < ncol ; j++) { - /* merge column of A and Z */ - p = Ap [j] ; - pend = (apacked) ? Ap [j+1] : p + Anz [j] ; - q = (Z == NULL) ? 0 : Zp [j] ; - qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ; - while (ok) - { - /* get the next row index from A and Z */ - i = (p < pend) ? Ai [p] : (nrow+1) ; - iz = (q < qend) ? Zi [q] : (nrow+2) ; - if (i <= iz) - { - /* get A(i,j), or quit if both A and Z are exhausted */ - if (i == nrow+1) break ; - get_value (Ax, Az, p, xtype, &x, &z) ; - p++ ; - } - else - { - /* get Z(i,j) */ - i = iz ; - x = 0 ; - z = 0 ; - q++ ; - } - if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) - { - /* CHOLMOD matrix is symmetric-lower (and so is the file); - * or CHOLMOD matrix is unsymmetric and either A(i,j) is in - * the lower part or the file is unsymmetric. */ - ok = ok && print_triplet (f, is_binary, is_complex, is_integer, - i,j, x,z) ; - } - else if (stype > 0 && i <= j) - { - /* CHOLMOD matrix is symmetric-upper, but the file is - * symmetric-lower. Need to transpose the entry. If the - * matrix is real, the complex part is ignored. If the matrix - * is complex, it Hermitian. - */ - ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ; - if (z != 0) - { - z = -z ; - } - ok = ok && print_triplet (f, is_binary, is_complex, is_integer, - j,i, x,z) ; - } - } + // merge column of A and Z + p = Ap [j] ; + pend = (apacked) ? Ap [j+1] : p + Anz [j] ; + q = (Z == NULL) ? 0 : Zp [j] ; + qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ; + while (ok) + { + // get the next row index from A and Z + i = (p < pend) ? Ai [p] : (nrow+1) ; + iz = (q < qend) ? Zi [q] : (nrow+2) ; + if (i <= iz) + { + // get A(i,j), or quit if both A and Z are exhausted + if (i == nrow+1) break ; + get_value (Ax, Az, p, xtype, dtype, &x, &z) ; + p++ ; + } + else + { + // get Z(i,j) + i = iz ; + x = 0 ; + z = 0 ; + q++ ; + } + if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) + { + // CHOLMOD matrix is symmetric-lower (and so is the file); + // or CHOLMOD matrix is unsymmetric and either A(i,j) is in + // the lower part or the file is unsymmetric. + ok = ok && print_triplet (f, is_binary, is_complex, is_integer, + i,j, x,z) ; + } + else if (stype > 0 && i <= j) + { + // CHOLMOD matrix is symmetric-upper, but the file is + // symmetric-lower. Need to transpose the entry. If the + // matrix is real, the complex part is ignored. If the matrix + // is complex, it Hermitian. + ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ; + if (z != 0) + { + z = -z ; + } + ok = ok && print_triplet (f, is_binary, is_complex, is_integer, + j,i, x,z) ; + } + } } if (!ok) { - ERROR (CHOLMOD_INVALID, "error reading/writing file") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "error reading/writing file") ; + return (EMPTY) ; } return (asym) ; } +//------------------------------------------------------------------------------ +// cholmod_write_dense +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_write_dense ================================================== */ -/* ========================================================================== */ - -/* Write a dense matrix to a file in Matrix Market format. Optionally include - * comments. Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if - * square). Future versions may return 1 to 7 on success (a CHOLMOD_MM_* code, - * just as cholmod_write_sparse does). - * - * A dense matrix is written in "general" format; symmetric formats in the - * Matrix Market standard are not exploited. - */ +// Write a dense matrix to a file in Matrix Market format. Optionally include +// comments. Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if +// square). Future versions may return 1 to 7 on success (a CHOLMOD_MM_* code, +// just as cholmod_write_sparse does). +// +// A dense matrix is written in "general" format; symmetric formats in the +// Matrix Market standard are not exploited. int CHOLMOD(write_dense) ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_dense *X, /* matrix to print */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to write to, must already be open + cholmod_dense *X, // matrix to print + const char *comments, // optional filename of comments to include cholmod_common *Common ) { double x = 0, z = 0 ; - double *Xx, *Xz ; - Int nrow, ncol, is_complex, i, j, xtype, p ; - int ok ; + void *Xx, *Xz ; + Int nrow, ncol, is_complex, i, j, p ; + int ok, xtype, dtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (f, EMPTY) ; @@ -679,66 +666,65 @@ int CHOLMOD(write_dense) RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get the X matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the X matrix + //-------------------------------------------------------------------------- - Xx = X->x ; - Xz = X->z ; nrow = X->nrow ; ncol = X->ncol ; xtype = X->xtype ; + dtype = X->dtype ; is_complex = (xtype == CHOLMOD_COMPLEX) || (xtype == CHOLMOD_ZOMPLEX) ; - /* ---------------------------------------------------------------------- */ - /* write the Matrix Market header */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // write the Matrix Market header + //-------------------------------------------------------------------------- ok = (fprintf (f, "%%%%MatrixMarket matrix array") > 0) ; if (is_complex) { - ok = ok && (fprintf (f, " complex general\n") > 0) ; + ok = ok && (fprintf (f, " complex general\n") > 0) ; } else { - ok = ok && (fprintf (f, " real general\n") > 0) ; + ok = ok && (fprintf (f, " real general\n") > 0) ; } - /* ---------------------------------------------------------------------- */ - /* include the comments if present */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // include the comments if present + //-------------------------------------------------------------------------- ok = ok && include_comments (f, comments) ; - /* ---------------------------------------------------------------------- */ - /* write a dense matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // write a dense matrix + //-------------------------------------------------------------------------- - /* write the first data line, with nrow and ncol */ + // write the first data line, with nrow and ncol ok = ok && (fprintf (f, ID " " ID "\n", nrow, ncol) > 0) ; Xx = X->x ; Xz = X->z ; for (j = 0 ; ok && j < ncol ; j++) { - for (i = 0 ; ok && i < nrow ; i++) - { - p = i + j*nrow ; - get_value (Xx, Xz, p, xtype, &x, &z) ; - ok = ok && print_value (f, x, FALSE) ; - if (is_complex) - { - ok = ok && (fprintf (f, " ") > 0) ; - ok = ok && print_value (f, z, FALSE) ; - } - ok = ok && (fprintf (f, "\n") > 0) ; - } + for (i = 0 ; ok && i < nrow ; i++) + { + p = i + j*nrow ; + get_value (Xx, Xz, p, xtype, dtype, &x, &z) ; + ok = ok && print_value (f, x, FALSE) ; + if (is_complex) + { + ok = ok && (fprintf (f, " ") > 0) ; + ok = ok && print_value (f, z, FALSE) ; + } + ok = ok && (fprintf (f, "\n") > 0) ; + } } if (!ok) { - ERROR (CHOLMOD_INVALID, "error reading/writing file") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "error reading/writing file") ; + return (EMPTY) ; } return ((nrow == ncol) ? CHOLMOD_MM_UNSYMMETRIC : CHOLMOD_MM_RECTANGULAR) ; diff --git a/CHOLMOD/Cholesky/cholmod_amd.c b/CHOLMOD/Cholesky/cholmod_amd.c index 6925e0ec3e..9ccb7f6aea 100644 --- a/CHOLMOD/Cholesky/cholmod_amd.c +++ b/CHOLMOD/Cholesky/cholmod_amd.c @@ -2,68 +2,67 @@ // CHOLMOD/Cholesky/cholmod_amd: AMD interface for CHOLMOD //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the AMD ordering routine. Orders A if the matrix is - * symmetric. On output, Perm [k] = i if row/column i of A is the kth - * row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation. - * - * If A is unsymmetric, cholmod_amd orders A*A'. On output, Perm [k] = i if - * row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to - * A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is - * ordered. - * - * Computes the flop count for a subsequent LL' factorization, the number - * of nonzeros in L, and the number of nonzeros in the matrix ordered (A, - * A*A' or A(:,f)*A(:,f)'). - * - * workspace: Iwork (6*nrow). Head (nrow). - * - * Allocates a temporary copy of A+A' or A*A' (with - * both upper and lower triangular parts) as input to AMD. - * - * Supports any xtype (pattern, real, complex, or zomplex) - */ +// CHOLMOD interface to the AMD ordering routine. Orders A if the matrix is +// symmetric. On output, Perm [k] = i if row/column i of A is the kth +// row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation. +// +// If A is unsymmetric, cholmod_amd orders A*A'. On output, Perm [k] = i if +// row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to +// A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is +// ordered. +// +// Computes the flop count for a subsequent LL' factorization, the number +// of nonzeros in L, and the number of nonzeros in the matrix ordered (A, +// A*A' or A(:,f)*A(:,f)'). +// +// workspace: Iwork (6*nrow). Head (nrow). +// +// Allocates a temporary copy of A+A' or A*A' (with +// both upper and lower triangular parts) as input to AMD. +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCHOLESKY #include "amd.h" -#if (!defined (AMD_VERSION) || (AMD_VERSION < AMD_VERSION_CODE (2,0))) -#error "AMD v2.0 or later is required" +#if (!defined (AMD_VERSION) || (AMD_VERSION < AMD_VERSION_CODE (3,0))) +// AMD 3.0 or later required (SuiteSparse 6.0.0 or later) +#error "AMD v3.0 or later is required" #endif -/* ========================================================================== */ -/* === cholmod_amd ========================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_amd +//------------------------------------------------------------------------------ int CHOLMOD(amd) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + double Info [AMD_INFO], Control2 [AMD_CONTROL], *Control ; Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Iwork, *Next ; cholmod_sparse *C ; Int j, n, cnz ; - size_t s ; int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -74,125 +73,125 @@ int CHOLMOD(amd) Common->status = CHOLMOD_OK ; if (n == 0) { - /* nothing to do */ - Common->fl = 0 ; - Common->lnz = 0 ; - Common->anz = 0 ; - return (TRUE) ; + // nothing to do + Common->fl = 0 ; + Common->lnz = 0 ; + Common->anz = 0 ; + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - /* Note: this is less than the space used in cholmod_analyze, so if - * cholmod_amd is being called by that routine, no space will be - * allocated. - */ + // Note: this is less than the space used in cholmod_analyze, so if + // cholmod_amd is being called by that routine, no space will be + // allocated. - /* s = MAX (6*n, A->ncol) */ - s = CHOLMOD(mult_size_t) (n, 6, &ok) ; + // s = MAX (6*nrow, ncol) + size_t s = CHOLMOD(mult_size_t) (A->nrow, 6, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } s = MAX (s, A->ncol) ; - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } Iwork = Common->Iwork ; - Degree = Iwork ; /* size n */ - Wi = Iwork + n ; /* size n */ - Len = Iwork + 2*((size_t) n) ; /* size n */ - Nv = Iwork + 3*((size_t) n) ; /* size n */ - Next = Iwork + 4*((size_t) n) ; /* size n */ - Elen = Iwork + 5*((size_t) n) ; /* size n */ + Degree = Iwork ; // size n + Wi = Iwork + n ; // size n + Len = Iwork + 2*((size_t) n) ; // size n + Nv = Iwork + 3*((size_t) n) ; // size n + Next = Iwork + 4*((size_t) n) ; // size n + Elen = Iwork + 5*((size_t) n) ; // size n - Head = Common->Head ; /* size n+1, but only n is used */ + Head = Common->Head ; // size n+1, but only n is used - /* ---------------------------------------------------------------------- */ - /* construct the input matrix for AMD */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct the input matrix for AMD + //-------------------------------------------------------------------------- if (A->stype == 0) { - /* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */ - C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ; + // C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C + C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ; } else { - /* C = A+A', but use only the upper triangular part of A if A->stype = 1 - * and only the lower part of A if A->stype = -1. Add extra space of - * nnz(C)/2+n to C. */ - C = CHOLMOD(copy) (A, 0, -2, Common) ; + // C = A+A', but use only the upper triangular part of A if A->stype = 1 + // and only the lower part of A if A->stype = -1. Add extra space of + // nnz(C)/2+n to C. + C = CHOLMOD(copy) (A, 0, -2, Common) ; } if (Common->status < CHOLMOD_OK) { - /* out of memory, fset invalid, or other error */ - return (FALSE) ; + // out of memory, fset invalid, or other error + return (FALSE) ; } Cp = C->p ; for (j = 0 ; j < n ; j++) { - Len [j] = Cp [j+1] - Cp [j] ; + Len [j] = Cp [j+1] - Cp [j] ; } - /* C does not include the diagonal, and both upper and lower parts. - * Common->anz includes the diagonal, and just the lower part of C */ + // C does not include the diagonal, and both upper and lower parts. + // Common->anz includes the diagonal, and just the lower part of C cnz = Cp [n] ; Common->anz = cnz / 2 + n ; - /* ---------------------------------------------------------------------- */ - /* order C using AMD */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order C using AMD + //-------------------------------------------------------------------------- - /* get parameters */ + // get parameters if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { - /* use AMD defaults */ - Control = NULL ; + // use AMD defaults + Control = NULL ; } else { - Control = Control2 ; - Control [AMD_DENSE] = Common->method [Common->current].prune_dense ; - Control [AMD_AGGRESSIVE] = Common->method [Common->current].aggressive ; + Control = Control2 ; + Control [AMD_DENSE] = Common->method [Common->current].prune_dense ; + Control [AMD_AGGRESSIVE] = Common->method [Common->current].aggressive ; } -#if defined ( CHOLMOD_INT64 ) + #if defined ( CHOLMOD_INT64 ) amd_l2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, - Degree, Wi, Control, Info) ; -#else + Degree, Wi, Control, Info) ; + #else amd_2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, - Degree, Wi, Control, Info) ; -#endif + Degree, Wi, Control, Info) ; + #endif - /* LL' flop count. Need to subtract n for LL' flop count. Note that this - * is a slight upper bound which is often exact (see AMD/Source/amd_2.c for - * details). cholmod_analyze computes an exact flop count and fill-in. */ + // LL' flop count. Need to subtract n for LL' flop count. Note that this + // is a slight upper bound which is often exact (see AMD/Source/amd_2.c for + // details). cholmod_analyze computes an exact flop count and fill-in. Common->fl = Info [AMD_NDIV] + 2 * Info [AMD_NMULTSUBS_LDL] + n ; - /* Info [AMD_LNZ] excludes the diagonal */ + // Info [AMD_LNZ] excludes the diagonal Common->lnz = n + Info [AMD_LNZ] ; - /* ---------------------------------------------------------------------- */ - /* free the AMD workspace and clear the persistent workspace in Common */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the AMD workspace and clear the persistent workspace in Common + //-------------------------------------------------------------------------- ASSERT (IMPLIES (Common->status == CHOLMOD_OK, - CHOLMOD(dump_perm) (Perm, n, n, "AMD2 perm", Common))) ; + CHOLMOD(dump_perm) (Perm, n, n, "AMD2 perm", Common))) ; CHOLMOD(free_sparse) (&C, Common) ; for (j = 0 ; j <= n ; j++) { - Head [j] = EMPTY ; + Head [j] = EMPTY ; } return (TRUE) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_analyze.c b/CHOLMOD/Cholesky/cholmod_analyze.c index f61d8616d2..9a0161bb26 100644 --- a/CHOLMOD/Cholesky/cholmod_analyze.c +++ b/CHOLMOD/Cholesky/cholmod_analyze.c @@ -2,128 +2,126 @@ // CHOLMOD/Cholesky/cholmod_analyze: order and analyze a matrix //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Order and analyze a matrix (either simplicial or supernodal), in prepartion - * for numerical factorization via cholmod_factorize or via the "expert" - * routines cholmod_rowfac and cholmod_super_numeric. - * - * symmetric case: A or A(p,p) - * unsymmetric case: AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)' - * - * For the symmetric case, only the upper or lower triangular part of A is - * accessed (depending on the type of A). LL'=A (or permuted A) is analzed. - * For the unsymmetric case (LL'=AA' or permuted A). - * - * There can be no duplicate entries in p or f. p is of length m if A is - * m-by-n. f can be length 0 to n. - * - * In both cases, the columns of A need not be sorted. A can be in packed - * or unpacked form. - * - * Ordering options include: - * - * natural: A is not permuted to reduce fill-in - * given: a permutation can be provided to this routine (UserPerm) - * AMD: approximate minumum degree (AMD for the symmetric case, - * COLAMD for the AA' case). - * METIS: nested dissection with METIS_NodeND - * NESDIS: nested dissection using METIS_ComputeVertexSeparator, - * typically followed by a constrained minimum degree - * (CAMD for the symmetric case, CCOLAMD for the AA' case). - * - * Multiple ordering options can be tried (up to 9 of them), and the best one - * is selected (the one that gives the smallest number of nonzeros in the - * simplicial factor L). If one method fails, cholmod_analyze keeps going, and - * picks the best among the methods that succeeded. This routine fails (and - * returns NULL) if either initial memory allocation fails, all ordering methods - * fail, or the supernodal analysis (if requested) fails. By default, the 9 - * methods available are: - * - * 1) given permutation (skipped if UserPerm is NULL) - * 2) AMD (symmetric case) or COLAMD (unsymmetric case) - * 3) METIS with default parameters - * 4) NESDIS with default parameters (stopping the partitioning when - * the graph is of size nd_small = 200 or less, remove nodes with - * more than max (16, prune_dense * sqrt (n)) nodes where - * prune_dense = 10, and follow partitioning with CCOLAMD, a - * constrained minimum degree ordering). - * 5) natural - * 6) NESDIS, nd_small = 20000, prune_dense = 10 - * 7) NESDIS, nd_small = 4, prune_dense = 10, no min degree - * 8) NESDIS, nd_small = 200, prune_dense = 0 - * 9) COLAMD for A*A' or AMD for A - * - * By default, the first two are tried, and METIS is tried if AMD reports a high - * flop count and fill-in. Let fl denote the flop count for the AMD, ordering, - * nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A'). If - * fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted. The - * best ordering is used (UserPerm if given, AMD, and METIS if attempted). If - * you do not have METIS, only the first two will be tried (user permutation, - * if provided, and AMD/COLAMD). This default behavior is obtained when - * Common->nmethods is zero. In this case, methods 0, 1, and 2 in - * Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS - * if Common->default_nesdis is set to the non-default value of TRUE), - * respectively. - * - * You can modify these 9 methods and the number of methods tried by changing - * parameters in the Common argument. If you know the best ordering for your - * matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the - * requested ordering method. Parameters for each method can also be modified - * (refer to cholmod.h for details). - * - * Note that it is possible for METIS to terminate your program if it runs out - * of memory. This is not the case for any CHOLMOD or minimum degree ordering - * routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since NESDIS relies on - * METIS, it too can terminate your program. - * - * The factor L is returned as simplicial symbolic (L->is_super FALSE) if - * Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if - * Common->supernodal >= CHOLMOD_SUPERNODAL (2). If Common->supernodal is - * equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per - * nonzero in L is less than Common->supernodal_switch (default: 40), and - * is returned as a supernodal factor otherwise. - * - * In both cases, L->xtype is CHOLMOD_PATTERN. - * A subsequent call to cholmod_factorize will perform a - * simplicial or supernodal factorization, depending on the type of L. - * - * For the simplicial case, L contains the fill-reducing permutation (L->Perm) - * and the counts of nonzeros in each column of L (L->ColCount). For the - * supernodal case, L also contains the nonzero pattern of each supernode. - * - * workspace: Flag (nrow), Head (nrow+1) - * if symmetric: Iwork (6*nrow) - * if unsymmetric: Iwork (6*nrow+ncol). - * calls various ordering routines, which typically allocate O(nnz(A)) - * temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it - * can be much higher if A*A' must be explicitly formed for METIS). Also - * allocates up to 2 temporary (permuted/transpose) copies of the nonzero - * pattern of A, and up to 3*n*sizeof(Int) additional workspace. - * - * Supports any xtype (pattern, real, complex, or zomplex) - */ +// Order and analyze a matrix (either simplicial or supernodal), in prepartion +// for numerical factorization via cholmod_factorize or via the "expert" +// routines cholmod_rowfac and cholmod_super_numeric. +// +// symmetric case: A or A(p,p) +// unsymmetric case: AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)' +// +// For the symmetric case, only the upper or lower triangular part of A is +// accessed (depending on the type of A). LL'=A (or permuted A) is analzed. +// For the unsymmetric case (LL'=AA' or permuted A). +// +// There can be no duplicate entries in p or f. p is of length m if A is +// m-by-n. f can be length 0 to n. +// +// In both cases, the columns of A need not be sorted. A can be in packed +// or unpacked form. +// +// Ordering options include: +// +// natural: A is not permuted to reduce fill-in +// given: a permutation can be provided to this routine (UserPerm) +// AMD: approximate minumum degree (AMD for the symmetric case, +// COLAMD for the AA' case). +// METIS: nested dissection with METIS_NodeND +// NESDIS: nested dissection using METIS_ComputeVertexSeparator, +// typically followed by a constrained minimum degree +// (CAMD for the symmetric case, CCOLAMD for the AA' case). +// +// Multiple ordering options can be tried (up to 9 of them), and the best one +// is selected (the one that gives the smallest number of nonzeros in the +// simplicial factor L). If one method fails, cholmod_analyze keeps going, and +// picks the best among the methods that succeeded. This routine fails (and +// returns NULL) if either initial memory allocation fails, all ordering methods +// fail, or the supernodal analysis (if requested) fails. By default, the 9 +// methods available are: +// +// 1) given permutation (skipped if UserPerm is NULL) +// 2) AMD (symmetric case) or COLAMD (unsymmetric case) +// 3) METIS with default parameters +// 4) NESDIS with default parameters (stopping the partitioning when +// the graph is of size nd_small = 200 or less, remove nodes with +// more than max (16, prune_dense * sqrt (n)) nodes where +// prune_dense = 10, and follow partitioning with CCOLAMD, a +// constrained minimum degree ordering). +// 5) natural +// 6) NESDIS, nd_small = 20000, prune_dense = 10 +// 7) NESDIS, nd_small = 4, prune_dense = 10, no min degree +// 8) NESDIS, nd_small = 200, prune_dense = 0 +// 9) COLAMD for A*A' or AMD for A +// +// By default, the first two are tried, and METIS is tried if AMD reports a high +// flop count and fill-in. Let fl denote the flop count for the AMD, ordering, +// nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A'). If +// fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted. The +// best ordering is used (UserPerm if given, AMD, and METIS if attempted). If +// you do not have METIS, only the first two will be tried (user permutation, +// if provided, and AMD/COLAMD). This default behavior is obtained when +// Common->nmethods is zero. In this case, methods 0, 1, and 2 in +// Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS +// if Common->default_nesdis is set to the non-default value of TRUE), +// respectively. +// +// You can modify these 9 methods and the number of methods tried by changing +// parameters in the Common argument. If you know the best ordering for your +// matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the +// requested ordering method. Parameters for each method can also be modified +// (refer to cholmod.h for details). +// +// Note that it is possible for METIS to terminate your program if it runs out +// of memory. This is not the case for any CHOLMOD or minimum degree ordering +// routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since NESDIS relies on +// METIS, it too can terminate your program. +// +// The factor L is returned as simplicial symbolic (L->is_super FALSE) if +// Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if +// Common->supernodal >= CHOLMOD_SUPERNODAL (2). If Common->supernodal is +// equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per +// nonzero in L is less than Common->supernodal_switch (default: 40), and +// is returned as a supernodal factor otherwise. +// +// In both cases, L->xtype is CHOLMOD_PATTERN. +// A subsequent call to cholmod_factorize will perform a +// simplicial or supernodal factorization, depending on the type of L. +// +// For the simplicial case, L contains the fill-reducing permutation (L->Perm) +// and the counts of nonzeros in each column of L (L->ColCount). For the +// supernodal case, L also contains the nonzero pattern of each supernode. +// +// workspace: Flag (nrow), Head (nrow+1) +// if symmetric: Iwork (6*nrow) +// if unsymmetric: Iwork (6*nrow+ncol). +// calls various ordering routines, which typically allocate O(nnz(A)) +// temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it +// can be much higher if A*A' must be explicitly formed for METIS). Also +// allocates up to 2 temporary (permuted/transpose) copies of the nonzero +// pattern of A, and up to 3*n*sizeof(Int) additional workspace. +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === cholmod_analyze ====================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_analyze +//------------------------------------------------------------------------------ -/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor - * that can later be passed to cholmod_factorize. */ +// Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor +// that can later be passed to cholmod_factorize. -cholmod_factor *CHOLMOD(analyze) +cholmod_factor *CHOLMOD(analyze) // returns symbolic factor L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order and analyze cholmod_common *Common ) { @@ -131,58 +129,55 @@ cholmod_factor *CHOLMOD(analyze) } -/* ========================================================================== */ -/* === cholmod_analyze_p ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_analyze_p +//------------------------------------------------------------------------------ -/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a - * symbolic factor that can later be passed to cholmod_factorize, where - * F = A(:,fset) if fset is not NULL and A->stype is zero. - * UserPerm is tried if non-NULL. */ +// Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a +// symbolic factor that can later be passed to cholmod_factorize, where +// F = A(:,fset) if fset is not NULL and A->stype is zero. +// UserPerm is tried if non-NULL. -cholmod_factor *CHOLMOD(analyze_p) +cholmod_factor *CHOLMOD(analyze_p) // returns symbolic factor L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - Int *UserPerm, /* user-provided permutation, size A->nrow */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order and analyze + Int *UserPerm, // user-provided permutation, size A->nrow + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) { return (CHOLMOD(analyze_p2) (TRUE, A, UserPerm, fset, fsize, Common)) ; } +//------------------------------------------------------------------------------ +// permute_matrices +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === permute_matrices ===================================================== */ -/* ========================================================================== */ - -/* Permute and transpose a matrix. Allocates the A1 and A2 matrices, if needed, - * or returns them as NULL if not needed. - */ +// Permute and transpose a matrix. Allocates the A1 and A2 matrices, if needed, +// or returns them as NULL if not needed. static int permute_matrices ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to permute */ - Int ordering, /* ordering method used */ - Int *Perm, /* fill-reducing permutation */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - Int do_rowcolcounts,/* if TRUE, compute both S and F. If FALSE, only - * S is needed for the symmetric case, and only F for - * the unsymmetric case */ - /* ---- output --- */ - cholmod_sparse **A1_handle, /* see comments below for A1, A2, S, F */ + // input: + cholmod_sparse *A, // matrix to permute + Int ordering, // ordering method used + Int *Perm, // fill-reducing permutation + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + Int do_rowcolcounts,// if TRUE, compute both S and F. If FALSE, only + // S is needed for the symmetric case, and only F for + // the unsymmetric case + // output: + cholmod_sparse **A1_handle, // see comments below for A1, A2, S, F cholmod_sparse **A2_handle, cholmod_sparse **S_handle, cholmod_sparse **F_handle, - /* --------------- */ cholmod_common *Common ) { + cholmod_sparse *A1, *A2, *S, *F ; *A1_handle = NULL ; @@ -195,88 +190,88 @@ static int permute_matrices if (ordering == CHOLMOD_NATURAL) { - /* ------------------------------------------------------------------ */ - /* natural ordering of A */ - /* ------------------------------------------------------------------ */ - - if (A->stype < 0) - { - /* symmetric lower case: A already in lower form, so S=A' */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; - F = A ; - S = A2 ; - } - else if (A->stype > 0) - { - /* symmetric upper case: F = pattern of triu (A)', S = A */ - /* workspace: Iwork (nrow) */ - if (do_rowcolcounts) - { - /* F not needed for symmetric case if do_rowcolcounts FALSE */ - A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; - } - F = A1 ; - S = A ; - } - else - { - /* unsymmetric case: F = pattern of A (:,f)', S = A */ - /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ - A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; - F = A1 ; - S = A ; - } + //---------------------------------------------------------------------- + // natural ordering of A + //---------------------------------------------------------------------- + + if (A->stype < 0) + { + // symmetric lower case: A already in lower form, so S=A' + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; + F = A ; + S = A2 ; + } + else if (A->stype > 0) + { + // symmetric upper case: F = pattern of triu (A)', S = A + // workspace: Iwork (nrow) + if (do_rowcolcounts) + { + // F not needed for symmetric case if do_rowcolcounts FALSE + A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; + } + F = A1 ; + S = A ; + } + else + { + // unsymmetric case: F = pattern of A (:,f)', S = A + // workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; + F = A1 ; + S = A ; + } } else { - /* ------------------------------------------------------------------ */ - /* A is permuted */ - /* ------------------------------------------------------------------ */ - - if (A->stype < 0) - { - /* symmetric lower case: S = tril (A (p,p))' and F = S' */ - /* workspace: Iwork (2*nrow) */ - A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; - S = A2 ; - /* workspace: Iwork (nrow) */ - if (do_rowcolcounts) - { - /* F not needed for symmetric case if do_rowcolcounts FALSE */ - A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ; - } - F = A1 ; - } - else if (A->stype > 0) - { - /* symmetric upper case: F = triu (A (p,p))' and S = F' */ - /* workspace: Iwork (2*nrow) */ - A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; - F = A1 ; - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; - S = A2 ; - } - else - { - /* unsymmetric case: F = A (p,f)' and S = F' */ - /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ - A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ; - F = A1 ; - if (do_rowcolcounts) - { - /* S not needed for unsymmetric case if do_rowcolcounts FALSE */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; - } - S = A2 ; - } + //---------------------------------------------------------------------- + // A is permuted + //---------------------------------------------------------------------- + + if (A->stype < 0) + { + // symmetric lower case: S = tril (A (p,p))' and F = S' + // workspace: Iwork (2*nrow) + A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; + S = A2 ; + // workspace: Iwork (nrow) + if (do_rowcolcounts) + { + // F not needed for symmetric case if do_rowcolcounts FALSE + A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ; + } + F = A1 ; + } + else if (A->stype > 0) + { + // symmetric upper case: F = triu (A (p,p))' and S = F' + // workspace: Iwork (2*nrow) + A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; + F = A1 ; + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; + S = A2 ; + } + else + { + // unsymmetric case: F = A (p,f)' and S = F' + // workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ; + F = A1 ; + if (do_rowcolcounts) + { + // S not needed for unsymmetric case if do_rowcolcounts FALSE + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; + } + S = A2 ; + } } - /* If any cholmod_*transpose fails, one or more matrices will be NULL */ + // If any cholmod_*transpose fails, one or more matrices will be NULL *A1_handle = A1 ; *A2_handle = A2 ; *S_handle = S ; @@ -284,46 +279,44 @@ static int permute_matrices return (Common->status == CHOLMOD_OK) ; } +//------------------------------------------------------------------------------ +// cholmod_analyze_ordering +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_analyze_ordering ============================================= */ -/* ========================================================================== */ - -/* Given a matrix A and its fill-reducing permutation, compute the elimination - * tree, its (non-weighted) postordering, and the number of nonzeros in each - * column of L. Also computes the flop count, the total nonzeros in L, and - * the nonzeros in A (Common->fl, Common->lnz, and Common->anz). - * - * The column counts of L, flop count, and other statistics from - * cholmod_rowcolcounts are not computed if ColCount is NULL. - * - * workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric), - * Flag (nrow), Head (nrow+1) - */ +// Given a matrix A and its fill-reducing permutation, compute the elimination +// tree, its (non-weighted) postordering, and the number of nonzeros in each +// column of L. Also computes the flop count, the total nonzeros in L, and +// the nonzeros in A (Common->fl, Common->lnz, and Common->anz). +// +// The column counts of L, flop count, and other statistics from +// cholmod_rowcolcounts are not computed if ColCount is NULL. +// +// workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric), +// Flag (nrow), Head (nrow+1) int CHOLMOD(analyze_ordering) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int ordering, /* ordering method used */ - Int *Perm, /* size n, fill-reducing permutation to analyze */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - Int *Parent, /* size n, elimination tree */ - Int *Post, /* size n, postordering of elimination tree */ - Int *ColCount, /* size n, nnz in each column of L */ - /* ---- workspace */ - Int *First, /* size n workspace for cholmod_postorder */ - Int *Level, /* size n workspace for cholmod_postorder */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int ordering, // ordering method used + Int *Perm, // size n, fill-reducing permutation to analyze + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + Int *Parent, // size n, elimination tree + Int *Post, // size n, postordering of elimination tree + Int *ColCount, // size n, nnz in each column of L + // workspace: + Int *First, // size n workspace for cholmod_postorder + Int *Level, // size n workspace for cholmod_postorder cholmod_common *Common ) { + cholmod_sparse *A1, *A2, *S, *F ; Int n, ok, do_rowcolcounts ; - /* check inputs */ + // check inputs RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -331,92 +324,89 @@ int CHOLMOD(analyze_ordering) do_rowcolcounts = (ColCount != NULL) ; - /* permute A according to Perm and fset */ + // permute A according to Perm and fset ok = permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts, - &A1, &A2, &S, &F, Common) ; + &A1, &A2, &S, &F, Common) ; - /* find etree of S (symmetric upper/lower case) or F (unsym case) */ - /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */ + // find etree of S (symmetric upper/lower case) or F (unsym case) + // workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ; - /* postorder the etree (required by cholmod_rowcolcounts) */ - /* workspace: Iwork (2*nrow) */ + // postorder the etree (required by cholmod_rowcolcounts) + // workspace: Iwork (2*nrow) ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ; - /* cholmod_postorder doesn't set Common->status if it returns < n */ + // cholmod_postorder doesn't set Common->status if it returns < n Common->status = (!ok && Common->status == CHOLMOD_OK) ? - CHOLMOD_INVALID : Common->status ; + CHOLMOD_INVALID : Common->status ; - /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */ - /* workspace: - * if symmetric: Flag (nrow), Iwork (2*nrow) - * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) - */ + // analyze LL'=S or SS' or S(:,f)*S(:,f)' + // workspace: + // if symmetric: Flag (nrow), Iwork (2*nrow) + // if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) if (do_rowcolcounts) { - ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent, - Post, NULL, ColCount, First, Level, Common) ; + ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent, + Post, NULL, ColCount, First, Level, Common) ; } - /* free temporary matrices and return result */ + // free temporary matrices and return result CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; return (ok) ; } -/* ========================================================================== */ -/* === Free workspace and return L ========================================== */ -/* ========================================================================== */ - -#define FREE_WORKSPACE_AND_RETURN \ -{ \ - Common->no_workspace_reallocate = FALSE ; \ - CHOLMOD(free) (n, sizeof (Int), Lparent, Common) ; \ - CHOLMOD(free) (n, sizeof (Int), Perm, Common) ; \ - CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \ - if (Common->status < CHOLMOD_OK) \ - { \ - CHOLMOD(free_factor) (&L, Common) ; \ - } \ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \ - return (L) ; \ -} +//------------------------------------------------------------------------------ +// Free workspace and return L +//------------------------------------------------------------------------------ +#define FREE_WORKSPACE_AND_RETURN \ +{ \ + Common->no_workspace_reallocate = FALSE ; \ + CHOLMOD(free) (n, sizeof (Int), Lparent, Common) ; \ + CHOLMOD(free) (n, sizeof (Int), Perm, Common) ; \ + CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \ + if (Common->status < CHOLMOD_OK) \ + { \ + CHOLMOD(free_factor) (&L, Common) ; \ + } \ + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; \ + return (L) ; \ +} -/* ========================================================================== */ -/* === cholmod_analyze_p2 =================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_analyze_p2 +//------------------------------------------------------------------------------ -/* Ordering and analysis for sparse Cholesky or sparse QR. */ +// Ordering and analysis for sparse Cholesky or sparse QR. cholmod_factor *CHOLMOD(analyze_p2) ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to order and analyze */ - Int *UserPerm, /* user-provided permutation, size A->nrow */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to order and analyze + Int *UserPerm, // user-provided permutation, size A->nrow + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) { + double lnz_best ; Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent, - *Post, *Perm, *Lparent, *Lcolcount ; + *Post, *Perm, *Lparent, *Lcolcount ; cholmod_factor *L ; - Int k, n, method, nmethods, status, default_strategy, ncol, uncol, - skip_analysis, skip_best ; + Int k, n, method, nmethods, status, default_strategy, ncol, + skip_analysis, skip_best ; Int amd_backup ; - size_t s ; int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; @@ -426,55 +416,54 @@ cholmod_factor *CHOLMOD(analyze_p2) Common->selected = EMPTY ; Common->called_nd = FALSE ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- n = A->nrow ; ncol = A->ncol ; - uncol = (A->stype == 0) ? (A->ncol) : 0 ; - /* ---------------------------------------------------------------------- */ - /* set the default strategy */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // set the default strategy + //-------------------------------------------------------------------------- lnz_best = (double) EMPTY ; skip_best = FALSE ; nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ; nmethods = MAX (0, nmethods) ; -#ifndef NDEBUG + #ifndef NDEBUG PRINT1 (("cholmod_analyze_p2 :: nmethods "ID"\n", nmethods)) ; for (method = 0 ; method < nmethods ; method++) { - PRINT1 ((" "ID": ordering "ID"\n", + PRINT1 ((" "ID": ordering "ID"\n", method, Common->method [method].ordering)) ; } -#endif + #endif default_strategy = (nmethods == 0) ; if (default_strategy) { - /* default strategy: try UserPerm, if given. Try AMD for A, or AMD - * to order A*A'. Try METIS for the symmetric case only if AMD reports - * a high degree of fill-in and flop count. METIS is not tried if the - * Partition Module isn't installed. If Common->default_nesdis is - * TRUE, then NESDIS is used as the 3rd ordering instead. */ - Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */ - Common->method [1].ordering = CHOLMOD_AMD ; - Common->method [2].ordering = - (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; + // default strategy: try UserPerm, if given. Try AMD for A, or AMD + // to order A*A'. Try METIS for the symmetric case only if AMD reports + // a high degree of fill-in and flop count. METIS is not tried if the + // Partition Module isn't installed. If Common->default_nesdis is + // TRUE, then NESDIS is used as the 3rd ordering instead. + Common->method [0].ordering = CHOLMOD_GIVEN ; // skip if UserPerm NULL + Common->method [1].ordering = CHOLMOD_AMD ; + Common->method [2].ordering = + (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; amd_backup = FALSE ; -#ifndef NPARTITION - nmethods = 3 ; -#else - nmethods = 2 ; -#endif + #ifndef NPARTITION + nmethods = 3 ; + #else + nmethods = 2 ; + #endif } else { - /* If only METIS and NESDIS are selected, or if 2 or more methods are - * being tried, then enable AMD backup */ + // If only METIS and NESDIS are selected, or if 2 or more methods are + // being tried, then enable AMD backup amd_backup = (nmethods > 1) || (nmethods == 1 && (Common->method [0].ordering == CHOLMOD_METIS || Common->method [0].ordering == CHOLMOD_NESDIS || @@ -482,47 +471,47 @@ cholmod_factor *CHOLMOD(analyze_p2) UserPerm == NULL))) ; } -#ifdef NSUPERNODAL - /* CHOLMOD Supernodal module not installed, just do simplicial analysis */ + #ifdef NSUPERNODAL + // CHOLMOD Supernodal module not installed, just do simplicial analysis Common->supernodal = CHOLMOD_SIMPLICIAL ; -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* Note: enough space needs to be allocated here so that routines called by - * cholmod_analyze do not reallocate the space. - */ + // Note: enough space needs to be allocated here so that routines called by + // cholmod_analyze do not reallocate the space. - /* s = 6*n + uncol */ - s = CHOLMOD(mult_size_t) (n, 6, &ok) ; + // s = 6*nrow + uncol + size_t uncol = (A->stype == 0) ? (A->ncol) : 0 ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 6, &ok) ; s = CHOLMOD(add_size_t) (s, uncol, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (NULL) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (NULL) ; } - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (NULL) ; /* out of memory */ + return (NULL) ; // out of memory } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ensure that subsequent routines, called by cholmod_analyze, do not - * reallocate any workspace. This is set back to FALSE in the - * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function - * returns to its caller. */ + // ensure that subsequent routines, called by cholmod_analyze, do not + // reallocate any workspace. This is set back to FALSE in the + // FREE_WORKSPACE_AND_RETURN macro, which is the only way this function + // returns to its caller. Common->no_workspace_reallocate = TRUE ; - /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since - * other CHOLMOD routines will use the first 2n+uncol space. The ordering - * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis) - * are an exception. They can use all 6n + ncol space, since the contents - * of Parent, First, Level, and Post are not needed across calls to those - * routines. */ + // Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since + // other CHOLMOD routines will use the first 2n+uncol space. The ordering + // routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis) + // are an exception. They can use all 6n + ncol space, since the contents + // of Parent, First, Level, and Post are not needed across calls to those + // routines. Work4n = Common->Iwork ; Work4n += 2*((size_t) n) + uncol ; Parent = Work4n ; @@ -530,296 +519,293 @@ cholmod_factor *CHOLMOD(analyze_p2) Level = Work4n + 2*((size_t) n) ; Post = Work4n + 3*((size_t) n) ; - /* note that this assignment means that cholmod_nested_dissection, - * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol - * space in Common->Iwork */ + // note that this assignment means that cholmod_nested_dissection, + // cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol + // space in Common->Iwork Cmember = Post ; CParent = Level ; - /* ---------------------------------------------------------------------- */ - /* allocate more workspace, and an empty simplicial symbolic factor */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate more workspace, and an empty simplicial symbolic factor + //-------------------------------------------------------------------------- - L = CHOLMOD(allocate_factor) (n, Common) ; + // Numerical values are not yet in L for the symbolic analysis here, but + // set its dtype the same as A, for the numerical factorization: + L = CHOLMOD(alloc_factor) (n, A->dtype, Common) ; Lparent = CHOLMOD(malloc) (n, sizeof (Int), Common) ; Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - FREE_WORKSPACE_AND_RETURN ; + // out of memory + FREE_WORKSPACE_AND_RETURN ; } Lperm = L->Perm ; Lcolcount = L->ColCount ; Common->anz = EMPTY ; - /* ---------------------------------------------------------------------- */ - /* try all the requested ordering options and backup to AMD if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // try all the requested ordering options and backup to AMD if needed + //-------------------------------------------------------------------------- - /* turn off error handling [ */ + // turn off error handling [ Common->try_catch = TRUE ; for (method = 0 ; method <= nmethods ; method++) { - /* ------------------------------------------------------------------ */ - /* determine the method to try */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // determine the method to try + //---------------------------------------------------------------------- Int ordering ; - Common->fl = EMPTY ; - Common->lnz = EMPTY ; - skip_analysis = FALSE ; - - if (method == nmethods) - { - /* All methods failed: backup to AMD */ - if (Common->selected == EMPTY && amd_backup) - { - ordering = CHOLMOD_AMD ; - } - else - { - break ; - } - } - else - { - ordering = Common->method [method].ordering ; - } - Common->current = method ; - - /* ------------------------------------------------------------------ */ - /* find the fill-reducing permutation */ - /* ------------------------------------------------------------------ */ - - if (ordering == CHOLMOD_NATURAL) - { - - /* -------------------------------------------------------------- */ - /* natural ordering */ - /* -------------------------------------------------------------- */ - - for (k = 0 ; k < n ; k++) - { - Perm [k] = k ; - } - - } - else if (ordering == CHOLMOD_GIVEN) - { - - /* -------------------------------------------------------------- */ - /* use given ordering of A, if provided */ - /* -------------------------------------------------------------- */ - - if (UserPerm == NULL) - { - /* this is not an error condition */ - continue ; - } - for (k = 0 ; k < n ; k++) - { - /* UserPerm is checked in cholmod_ptranspose */ - Perm [k] = UserPerm [k] ; - } - - } - else if (ordering == CHOLMOD_AMD) - { - - /* -------------------------------------------------------------- */ - /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */ - /* -------------------------------------------------------------- */ - - amd_backup = FALSE ; /* no need to try AMD twice ... */ - CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; - skip_analysis = TRUE ; - - } - else if (ordering == CHOLMOD_COLAMD) - { - - /* -------------------------------------------------------------- */ - /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */ - /* -------------------------------------------------------------- */ - - if (A->stype) - { - CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; - skip_analysis = TRUE ; - } - else - { - /* do not postorder, it is done later, below */ - /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/ - CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ; - } - - } - else if (ordering == CHOLMOD_METIS) - { - - /* -------------------------------------------------------------- */ - /* use METIS_NodeND directly (via a CHOLMOD wrapper) */ - /* -------------------------------------------------------------- */ - -#ifndef NPARTITION - /* postorder parameter is false, because it will be later, below */ - /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */ - Common->called_nd = TRUE ; - CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ; -#else - Common->status = CHOLMOD_NOT_INSTALLED ; -#endif + Common->fl = EMPTY ; + Common->lnz = EMPTY ; + skip_analysis = FALSE ; - } - else if (ordering == CHOLMOD_NESDIS) - { - - /* -------------------------------------------------------------- */ - /* use CHOLMOD's nested dissection */ - /* -------------------------------------------------------------- */ - - /* this method is based on METIS' node bissection routine - * (METIS_ComputeVertexSeparator). In contrast to METIS_NodeND, - * it calls CAMD or CCOLAMD on the whole graph, instead of MMD - * on just the leaves. */ -#ifndef NPARTITION - /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */ - Common->called_nd = TRUE ; - CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember, - Common) ; -#else - Common->status = CHOLMOD_NOT_INSTALLED ; -#endif + if (method == nmethods) + { + // All methods failed: backup to AMD + if (Common->selected == EMPTY && amd_backup) + { + ordering = CHOLMOD_AMD ; + } + else + { + break ; + } + } + else + { + ordering = Common->method [method].ordering ; + } + Common->current = method ; + + //---------------------------------------------------------------------- + // find the fill-reducing permutation + //---------------------------------------------------------------------- + + if (ordering == CHOLMOD_NATURAL) + { + + //------------------------------------------------------------------ + // natural ordering + //------------------------------------------------------------------ + + for (k = 0 ; k < n ; k++) + { + Perm [k] = k ; + } + + } + else if (ordering == CHOLMOD_GIVEN) + { - } - else - { - - /* -------------------------------------------------------------- */ - /* invalid ordering method */ - /* -------------------------------------------------------------- */ - - Common->status = CHOLMOD_INVALID ; - } - - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; - - if (Common->status < CHOLMOD_OK) - { - /* out of memory, or method failed */ - status = MIN (status, Common->status) ; - Common->status = CHOLMOD_OK ; - continue ; - } - - /* ------------------------------------------------------------------ */ - /* analyze the ordering */ - /* ------------------------------------------------------------------ */ - - if (!skip_analysis) - { - if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize, - Parent, Post, ColCount, First, Level, Common)) - { - /* ordering method failed; clear status and try next method */ - status = MIN (status, Common->status) ; - Common->status = CHOLMOD_OK ; - continue ; - } - } - - ASSERT (Common->fl >= 0 && Common->lnz >= 0) ; - Common->method [method].fl = Common->fl ; - Common->method [method].lnz = Common->lnz ; - - /* ------------------------------------------------------------------ */ - /* pick the best method */ - /* ------------------------------------------------------------------ */ - - /* fl.pt. compare, but lnz can never be NaN */ - if (Common->selected == EMPTY || Common->lnz < lnz_best) - { - Common->selected = method ; - L->ordering = ordering ; - lnz_best = Common->lnz ; - for (k = 0 ; k < n ; k++) - { - Lperm [k] = Perm [k] ; - } - /* save the results of cholmod_analyze_ordering, if it was called */ - skip_best = skip_analysis ; - if (!skip_analysis) - { - /* save the column count; becomes permanent part of L */ - for (k = 0 ; k < n ; k++) - { - Lcolcount [k] = ColCount [k] ; - } - /* Parent is needed for weighted postordering and for supernodal - * analysis. Does not become a permanent part of L */ - for (k = 0 ; k < n ; k++) - { - Lparent [k] = Parent [k] ; - } - } - } - - /* ------------------------------------------------------------------ */ - /* determine if METIS is to be skipped */ - /* ------------------------------------------------------------------ */ - - if (default_strategy && ordering == CHOLMOD_AMD) - { - if ((Common->fl < 500 * Common->lnz) || - (Common->lnz < 5 * Common->anz)) - { - /* AMD found an ordering with less than 500 flops per nonzero in - * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than - * 5. This is pretty good, and it's unlikely that METIS will do - * better (this heuristic is based on tests on all symmetric - * positive definite matrices in the SuiteSparse Matrix - * Collection, and it works well across a wide range of - * problems). METIS can take much more time than AMD. */ - break ; - } - } + //------------------------------------------------------------------ + // use given ordering of A, if provided + //------------------------------------------------------------------ + + if (UserPerm == NULL) + { + // this is not an error condition + continue ; + } + for (k = 0 ; k < n ; k++) + { + // UserPerm is checked in cholmod_ptranspose + Perm [k] = UserPerm [k] ; + } + + } + else if (ordering == CHOLMOD_AMD) + { + + //------------------------------------------------------------------ + // AMD ordering of A, A*A', or A(:,f)*A(:,f)' + //------------------------------------------------------------------ + + amd_backup = FALSE ; // no need to try AMD twice ... + CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; + skip_analysis = TRUE ; + + } + else if (ordering == CHOLMOD_COLAMD) + { + + //------------------------------------------------------------------ + // AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' + //------------------------------------------------------------------ + + if (A->stype) + { + CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; + skip_analysis = TRUE ; + } + else + { + // do not postorder, it is done later, below + // workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) + CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ; + } + + } + else if (ordering == CHOLMOD_METIS) + { + + //------------------------------------------------------------------ + // use METIS_NodeND directly (via a CHOLMOD wrapper) + //------------------------------------------------------------------ + + #ifndef NPARTITION + // postorder parameter is false, because it will be later, below + // workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) + Common->called_nd = TRUE ; + CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ; + #else + Common->status = CHOLMOD_NOT_INSTALLED ; + #endif + + } + else if (ordering == CHOLMOD_NESDIS) + { + + //------------------------------------------------------------------ + // use CHOLMOD's nested dissection + //------------------------------------------------------------------ + + // this method is based on METIS' node bissection routine + // (METIS_ComputeVertexSeparator). In contrast to METIS_NodeND, + // it calls CAMD or CCOLAMD on the whole graph, instead of MMD + // on just the leaves. + #ifndef NPARTITION + // workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) + Common->called_nd = TRUE ; + CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember, + Common) ; + #else + Common->status = CHOLMOD_NOT_INSTALLED ; + #endif + + } + else + { + + //------------------------------------------------------------------ + // invalid ordering method + //------------------------------------------------------------------ + + Common->status = CHOLMOD_INVALID ; + } + + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; + + if (Common->status < CHOLMOD_OK) + { + // out of memory, or method failed + status = MIN (status, Common->status) ; + Common->status = CHOLMOD_OK ; + continue ; + } + + //---------------------------------------------------------------------- + // analyze the ordering + //---------------------------------------------------------------------- + + if (!skip_analysis) + { + if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize, + Parent, Post, ColCount, First, Level, Common)) + { + // ordering method failed; clear status and try next method + status = MIN (status, Common->status) ; + Common->status = CHOLMOD_OK ; + continue ; + } + } + + ASSERT (Common->fl >= 0 && Common->lnz >= 0) ; + Common->method [method].fl = Common->fl ; + Common->method [method].lnz = Common->lnz ; + + //---------------------------------------------------------------------- + // pick the best method + //---------------------------------------------------------------------- + + // fl.pt. compare, but lnz can never be NaN + if (Common->selected == EMPTY || Common->lnz < lnz_best) + { + Common->selected = method ; + L->ordering = ordering ; + lnz_best = Common->lnz ; + for (k = 0 ; k < n ; k++) + { + Lperm [k] = Perm [k] ; + } + // save the results of cholmod_analyze_ordering, if it was called + skip_best = skip_analysis ; + if (!skip_analysis) + { + // save the column count; becomes permanent part of L + for (k = 0 ; k < n ; k++) + { + Lcolcount [k] = ColCount [k] ; + } + // Parent is needed for weighted postordering and for supernodal + // analysis. Does not become a permanent part of L + for (k = 0 ; k < n ; k++) + { + Lparent [k] = Parent [k] ; + } + } + } + + //---------------------------------------------------------------------- + // determine if METIS is to be skipped + //---------------------------------------------------------------------- + + if (default_strategy && ordering == CHOLMOD_AMD) + { + if ((Common->fl < 500 * Common->lnz) || + (Common->lnz < 5 * Common->anz)) + { + // AMD found an ordering with less than 500 flops per nonzero in + // L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than + // 5. This is pretty good, and it's unlikely that METIS will do + // better (this heuristic is based on tests on all symmetric + // positive definite matrices in the SuiteSparse Matrix + // Collection, and it works well across a wide range of + // problems). METIS can take much more time than AMD. + break ; + } + } } - /* turn error printing back on ] */ + // turn error printing back on ] Common->try_catch = FALSE ; - /* ---------------------------------------------------------------------- */ - /* return if no ordering method succeeded */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return if no ordering method succeeded + //-------------------------------------------------------------------------- if (Common->selected == EMPTY) { - /* All methods failed. - * If two or more methods failed, they may have failed for different - * reasons. Both would clear Common->status and skip to the next - * method. Common->status needs to be restored here to the worst error - * obtained in any of the methods. CHOLMOD_INVALID is worse - * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may - * be wrong with the user's input. CHOLMOD_OUT_OF_MEMORY is simply an - * indication of lack of resources. */ - if (status >= CHOLMOD_OK) - { - /* this can occur if nmethods = 1, ordering = CHOLMOD_GIVEN, - but UserPerm is NULL */ - status = CHOLMOD_INVALID ; - } - ERROR (status, "all methods failed") ; - FREE_WORKSPACE_AND_RETURN ; + // All methods failed. + // If two or more methods failed, they may have failed for different + // reasons. Both would clear Common->status and skip to the next + // method. Common->status needs to be restored here to the worst error + // obtained in any of the methods. CHOLMOD_INVALID is worse + // than CHOLMOD_OUT_OF_MEMORY, since the former implies something may + // be wrong with the user's input. CHOLMOD_OUT_OF_MEMORY is simply an + // indication of lack of resources. + status = (status >= CHOLMOD_OK) ? CHOLMOD_INVALID : status ; + ERROR (status, "all methods failed") ; + FREE_WORKSPACE_AND_RETURN ; } - /* ---------------------------------------------------------------------- */ - /* do the analysis for AMD, if skipped */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // do the analysis for AMD, if skipped + //-------------------------------------------------------------------------- Common->fl = Common->method [Common->selected].fl ; Common->lnz = Common->method [Common->selected].lnz ; @@ -827,98 +813,99 @@ cholmod_factor *CHOLMOD(analyze_p2) if (skip_best) { - if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize, - Lparent, Post, Lcolcount, First, Level, Common)) - { - /* out of memory, or method failed */ - FREE_WORKSPACE_AND_RETURN ; - } + if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize, + Lparent, Post, Lcolcount, First, Level, Common)) + { + // out of memory, or method failed + FREE_WORKSPACE_AND_RETURN ; + } } - /* ---------------------------------------------------------------------- */ - /* postorder the etree, weighted by the column counts */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // postorder the etree, weighted by the column counts + //-------------------------------------------------------------------------- if (Common->postorder) { - /* combine the fill-reducing ordering with the weighted postorder */ - /* workspace: Iwork (2*nrow) */ - if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n) - { - /* use First and Level as workspace [ */ - Int *Wi = First, *InvPost = Level ; - Int newchild, oldchild, newparent, oldparent ; - - for (k = 0 ; k < n ; k++) - { - Wi [k] = Lperm [Post [k]] ; - } - for (k = 0 ; k < n ; k++) - { - Lperm [k] = Wi [k] ; - } - - for (k = 0 ; k < n ; k++) - { - Wi [k] = Lcolcount [Post [k]] ; - } - for (k = 0 ; k < n ; k++) - { - Lcolcount [k] = Wi [k] ; - } - for (k = 0 ; k < n ; k++) - { - InvPost [Post [k]] = k ; - } - - /* updated Lparent needed only for supernodal case */ - for (newchild = 0 ; newchild < n ; newchild++) - { - oldchild = Post [newchild] ; - oldparent = Lparent [oldchild] ; - newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ; - Wi [newchild] = newparent ; - } - for (k = 0 ; k < n ; k++) - { - Lparent [k] = Wi [k] ; - } - /* done using Iwork as workspace ] */ - - /* L is now postordered, no longer in natural ordering */ - if (L->ordering == CHOLMOD_NATURAL) - { - L->ordering = CHOLMOD_POSTORDERED ; - } - } + // combine the fill-reducing ordering with the weighted postorder + // workspace: Iwork (2*nrow) + if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n) + { + // use First and Level as workspace [ + Int *Wi = First, *InvPost = Level ; + Int newchild, oldchild, newparent, oldparent ; + + for (k = 0 ; k < n ; k++) + { + Wi [k] = Lperm [Post [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Lperm [k] = Wi [k] ; + } + + for (k = 0 ; k < n ; k++) + { + Wi [k] = Lcolcount [Post [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Lcolcount [k] = Wi [k] ; + } + for (k = 0 ; k < n ; k++) + { + InvPost [Post [k]] = k ; + } + + // updated Lparent needed only for supernodal case + for (newchild = 0 ; newchild < n ; newchild++) + { + oldchild = Post [newchild] ; + oldparent = Lparent [oldchild] ; + newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ; + Wi [newchild] = newparent ; + } + for (k = 0 ; k < n ; k++) + { + Lparent [k] = Wi [k] ; + } + // done using Iwork as workspace ] + + // L is now postordered, no longer in natural ordering + if (L->ordering == CHOLMOD_NATURAL) + { + L->ordering = CHOLMOD_POSTORDERED ; + } + } } - /* ---------------------------------------------------------------------- */ - /* supernodal analysis, if requested or if selected automatically */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // supernodal analysis, if requested or if selected automatically + //-------------------------------------------------------------------------- -#ifndef NSUPERNODAL + #ifndef NSUPERNODAL if (Common->supernodal > CHOLMOD_AUTO || (Common->supernodal == CHOLMOD_AUTO && - Common->lnz > 0 && - (Common->fl / Common->lnz) >= Common->supernodal_switch)) + Common->lnz > 0 && + (Common->fl / Common->lnz) >= Common->supernodal_switch)) { - cholmod_sparse *S, *F, *A2, *A1 ; + cholmod_sparse *S, *F, *A2, *A1 ; - permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE, - &A1, &A2, &S, &F, Common) ; + permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE, + &A1, &A2, &S, &F, Common) ; - /* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */ - CHOLMOD(super_symbolic2) (for_whom, S, F, Lparent, L, Common) ; - CHOLMOD(free_sparse) (&A1, Common) ; - CHOLMOD(free_sparse) (&A2, Common) ; + // workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) + CHOLMOD(super_symbolic2) (for_whom, S, F, Lparent, L, Common) ; + CHOLMOD(free_sparse) (&A1, Common) ; + CHOLMOD(free_sparse) (&A2, Common) ; } -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* free temporary matrices and workspace, and return result L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free temporary matrices and workspace, and return result L + //-------------------------------------------------------------------------- FREE_WORKSPACE_AND_RETURN ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_colamd.c b/CHOLMOD/Cholesky/cholmod_colamd.c index 3653d7d3bc..307ac58048 100644 --- a/CHOLMOD/Cholesky/cholmod_colamd.c +++ b/CHOLMOD/Cholesky/cholmod_colamd.c @@ -2,64 +2,62 @@ // CHOLMOD/Cholesky/cholmod_colamd: COLAMD interface for CHOLMOD //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the COLAMD ordering routine (version 2.4 or later). - * Finds a permutation p such that the Cholesky factorization of PAA'P' is - * sparser than AA' using colamd. If the postorder input parameter is TRUE, - * the column etree is found and postordered, and the colamd ordering is then - * combined with its postordering. A must be unsymmetric. - * - * There can be no duplicate entries in f. - * f can be length 0 to n if A is m-by-n. - * - * workspace: Iwork (4*nrow+ncol), Head (nrow+1), Flag (nrow) - * Allocates a copy of its input matrix, which - * is then used as CCOLAMD's workspace. - * - * Supports any xtype (pattern, real, complex, or zomplex) - */ +// CHOLMOD interface to the COLAMD ordering routine (version 2.4 or later). +// Finds a permutation p such that the Cholesky factorization of PAA'P' is +// sparser than AA' using colamd. If the postorder input parameter is TRUE, +// the column etree is found and postordered, and the colamd ordering is then +// combined with its postordering. A must be unsymmetric. +// +// There can be no duplicate entries in f. +// f can be length 0 to n if A is m-by-n. +// +// workspace: Iwork (4*nrow+ncol), Head (nrow+1), Flag (nrow) +// Allocates a copy of its input matrix, which +// is then used as CCOLAMD's workspace. +// +// Supports any xtype (pattern, real, complex, or zomplex) #include "cholmod_internal.h" #ifndef NCHOLESKY #include "colamd.h" -#if (!defined (COLAMD_VERSION) || (COLAMD_VERSION < COLAMD_VERSION_CODE (2,5))) -#error "COLAMD v2.5 or later is required" +#if (!defined (COLAMD_VERSION) || (COLAMD_VERSION < COLAMD_VERSION_CODE (3,0))) +// COLAMD 3.0 or later required (SuiteSparse 6.0.0 or later) +#error "COLAMD v3.0 or later is required" #endif -/* ========================================================================== */ -/* === cholmod_colamd ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_colamd +//------------------------------------------------------------------------------ int CHOLMOD(colamd) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with a coletree postorder */ - /* ---- output --- */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with a coletree postorder + // output: + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + double knobs [COLAMD_KNOBS] ; cholmod_sparse *C ; Int *NewPerm, *Parent, *Post, *Work2n ; Int k, nrow, ncol ; - size_t s, alen ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -67,138 +65,141 @@ int CHOLMOD(colamd) RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->stype != 0) { - ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- nrow = A->nrow ; ncol = A->ncol ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* Note: this is less than the space used in cholmod_analyze, so if - * cholmod_colamd is being called by that routine, no space will be - * allocated. - */ + // Note: this is less than the space used in cholmod_analyze, so if + // cholmod_colamd is being called by that routine, no space will be + // allocated. - /* s = 4*nrow + ncol */ - s = CHOLMOD(mult_size_t) (nrow, 4, &ok) ; - s = CHOLMOD(add_size_t) (s, ncol, &ok) ; + // s = 4*nrow + ncol + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 4, &ok) ; + s = CHOLMOD(add_size_t) (s, A->ncol, &ok) ; -#if defined ( CHOLMOD_INT64 ) - alen = colamd_l_recommended (A->nzmax, ncol, nrow) ; + #if defined ( CHOLMOD_INT64 ) + size_t alen = colamd_l_recommended (A->nzmax, ncol, nrow) ; colamd_l_set_defaults (knobs) ; -#else - alen = colamd_recommended (A->nzmax, ncol, nrow) ; + #else + size_t alen = colamd_recommended (A->nzmax, ncol, nrow) ; colamd_set_defaults (knobs) ; -#endif + #endif if (!ok || alen == 0) { - ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; + return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* allocate COLAMD workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate COLAMD workspace + //-------------------------------------------------------------------------- + // C is purely symbolic, so C->dtype doesn't actually matter, but it must + // match A->dtype for the call to cholmod_transpose_unsym below. C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, - CHOLMOD_PATTERN, Common) ; + CHOLMOD_PATTERN + A->dtype, Common) ; - /* ---------------------------------------------------------------------- */ - /* copy (and transpose) the input matrix A into the colamd workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy (and transpose) the input matrix A into the colamd workspace + //-------------------------------------------------------------------------- - /* C = A (:,f)', which also packs A if needed. */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) */ + // C = A (:,f)', which also packs A if needed. + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ; - /* ---------------------------------------------------------------------- */ - /* order the matrix (destroys the contents of C->i and C->p) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order the matrix (destroys the contents of C->i and C->p) + //-------------------------------------------------------------------------- - /* get parameters */ + // get parameters if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { - /* this is the CHOLMOD default, not the COLAMD default */ - knobs [COLAMD_DENSE_ROW] = -1 ; + // this is the CHOLMOD default, not the COLAMD default + knobs [COLAMD_DENSE_ROW] = -1 ; } else { - /* get the knobs from the Common parameters */ - knobs [COLAMD_DENSE_COL] = Common->method[Common->current].prune_dense ; - knobs [COLAMD_DENSE_ROW] = Common->method[Common->current].prune_dense2; - knobs [COLAMD_AGGRESSIVE] = Common->method[Common->current].aggressive ; + // get the knobs from the Common parameters + knobs [COLAMD_DENSE_COL] = Common->method[Common->current].prune_dense ; + knobs [COLAMD_DENSE_ROW] = Common->method[Common->current].prune_dense2; + knobs [COLAMD_AGGRESSIVE] = Common->method[Common->current].aggressive ; } if (ok) { - Int *Cp ; - Int stats [COLAMD_STATS] ; - Cp = C->p ; - -#if defined ( CHOLMOD_INT64 ) - colamd_l (ncol, nrow, alen, C->i, Cp, knobs, stats) ; -#else - colamd (ncol, nrow, alen, C->i, Cp, knobs, stats) ; -#endif - - ok = stats [COLAMD_STATUS] ; - ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ; - /* permutation returned in C->p, if the ordering succeeded */ - for (k = 0 ; k < nrow ; k++) - { - Perm [k] = Cp [k] ; - } + Int *Cp ; + Int stats [COLAMD_STATS] ; + Cp = C->p ; + + #if defined ( CHOLMOD_INT64 ) + colamd_l (ncol, nrow, alen, C->i, Cp, knobs, stats) ; + #else + colamd (ncol, nrow, alen, C->i, Cp, knobs, stats) ; + #endif + + ok = stats [COLAMD_STATUS] ; + ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ; + // permutation returned in C->p, if the ordering succeeded + for (k = 0 ; k < nrow ; k++) + { + Perm [k] = Cp [k] ; + } } CHOLMOD(free_sparse) (&C, Common) ; - /* ---------------------------------------------------------------------- */ - /* column etree postordering */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // column etree postordering + //-------------------------------------------------------------------------- if (postorder) { - /* use the last 2*n space in Iwork for Parent and Post */ - Work2n = Common->Iwork ; - Work2n += 2*((size_t) nrow) + ncol ; - Parent = Work2n ; /* size nrow (i/i/l) */ - Post = Work2n + nrow ; /* size nrow (i/i/l) */ - - /* workspace: Iwork (2*nrow+ncol), Flag (nrow), Head (nrow+1) */ - ok = ok && CHOLMOD(analyze_ordering) (A, CHOLMOD_COLAMD, Perm, fset, - fsize, Parent, Post, NULL, NULL, NULL, Common) ; - - /* combine the colamd permutation with its postordering */ - if (ok) - { - NewPerm = Common->Iwork ; /* size nrow (i/i/l) */ - for (k = 0 ; k < nrow ; k++) - { - NewPerm [k] = Perm [Post [k]] ; - } - for (k = 0 ; k < nrow ; k++) - { - Perm [k] = NewPerm [k] ; - } - } + // use the last 2*n space in Iwork for Parent and Post + Work2n = Common->Iwork ; + Work2n += 2*((size_t) nrow) + ncol ; + Parent = Work2n ; // size nrow + Post = Work2n + nrow ; // size nrow + + // workspace: Iwork (2*nrow+ncol), Flag (nrow), Head (nrow+1) + ok = ok && CHOLMOD(analyze_ordering) (A, CHOLMOD_COLAMD, Perm, fset, + fsize, Parent, Post, NULL, NULL, NULL, Common) ; + + // combine the colamd permutation with its postordering + if (ok) + { + NewPerm = Common->Iwork ; // size nrow + for (k = 0 ; k < nrow ; k++) + { + NewPerm [k] = Perm [Post [k]] ; + } + for (k = 0 ; k < nrow ; k++) + { + Perm [k] = NewPerm [k] ; + } + } } return (ok) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_etree.c b/CHOLMOD/Cholesky/cholmod_etree.c index 9ba5f62f14..3dbeef649a 100644 --- a/CHOLMOD/Cholesky/cholmod_etree.c +++ b/CHOLMOD/Cholesky/cholmod_etree.c @@ -2,101 +2,98 @@ // CHOLMOD/Cholesky/cholmod_etree: elimination tree of A or A'*A //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Compute the elimination tree of A or A'*A - * - * In the symmetric case, the upper triangular part of A is used. Entries not - * in this part of the matrix are ignored. Computing the etree of a symmetric - * matrix from just its lower triangular entries is not supported. - * - * In the unsymmetric case, all of A is used, and the etree of A'*A is computed. - * - * References: - * - * J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans. - * Math. Software, vol 12, 1986, pp. 127-148. - * - * J. Liu, "The role of elimination trees in sparse factorization", SIAM J. - * Matrix Analysis & Applic., vol 11, 1990, pp. 134-172. - * - * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for - * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. - * - * workspace: symmetric: Iwork (nrow), unsymmetric: Iwork (nrow+ncol) - * - * Supports any xtype (pattern, real, complex, or zomplex) - */ +// Compute the elimination tree of A or A'*A +// +// In the symmetric case, the upper triangular part of A is used. Entries not +// in this part of the matrix are ignored. Computing the etree of a symmetric +// matrix from just its lower triangular entries is not supported. +// +// In the unsymmetric case, all of A is used, and the etree of A'*A is computed. +// +// References: +// +// J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans. +// Math. Software, vol 12, 1986, pp. 127-148. +// +// J. Liu, "The role of elimination trees in sparse factorization", SIAM J. +// Matrix Analysis & Applic., vol 11, 1990, pp. 134-172. +// +// J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for +// sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. +// +// workspace: symmetric: Iwork (nrow), unsymmetric: Iwork (nrow+ncol) +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === update_etree ========================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// update_etree +//------------------------------------------------------------------------------ static void update_etree ( - /* inputs, not modified */ - Int k, /* process the edge (k,i) in the input graph */ + // input: + Int k, // process the edge (k,i) in the input graph Int i, - /* inputs, modified on output */ - Int Parent [ ], /* Parent [t] = p if p is the parent of t */ - Int Ancestor [ ] /* Ancestor [t] is the ancestor of node t in the - partially-constructed etree */ + // input/output: + Int Parent [ ], // Parent [t] = p if p is the parent of t + Int Ancestor [ ] // Ancestor [t] is the ancestor of node t in the + // partially-constructed etree ) { Int a ; - for ( ; ; ) /* traverse the path from k to the root of the tree */ + for ( ; ; ) // traverse the path from k to the root of the tree { - a = Ancestor [k] ; - if (a == i) - { - /* final ancestor reached; no change to tree */ - return ; - } - /* perform path compression */ - Ancestor [k] = i ; - if (a == EMPTY) - { - /* final ancestor undefined; this is a new edge in the tree */ - Parent [k] = i ; - return ; - } - /* traverse up to the ancestor of k */ - k = a ; + a = Ancestor [k] ; + if (a == i) + { + // final ancestor reached; no change to tree + return ; + } + // perform path compression + Ancestor [k] = i ; + if (a == EMPTY) + { + // final ancestor undefined; this is a new edge in the tree + Parent [k] = i ; + return ; + } + // traverse up to the ancestor of k + k = a ; } } -/* ========================================================================== */ -/* === cholmod_etree ======================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_etree +//------------------------------------------------------------------------------ -/* Find the elimination tree of A or A'*A */ +// Find the elimination tree of A or A'*A int CHOLMOD(etree) ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - /* ---- output --- */ - Int *Parent, /* size ncol. Parent [j] = p if p is the parent of j */ - /* --------------- */ + // output: + Int *Parent, // size ncol. Parent [j] = p if p is the parent of j cholmod_common *Common ) { + Int *Ap, *Ai, *Anz, *Ancestor, *Prev, *Iwork ; Int i, j, jprev, p, pend, nrow, ncol, packed, stype ; - size_t s ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -104,118 +101,119 @@ int CHOLMOD(etree) RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- stype = A->stype ; - /* s = A->nrow + (stype ? 0 : A->ncol) */ - s = CHOLMOD(add_size_t) (A->nrow, (stype ? 0 : A->ncol), &ok) ; + // s = A->nrow + (stype ? 0 : A->ncol) + int ok = TRUE ; + size_t s = CHOLMOD(add_size_t) (A->nrow, (stype ? 0 : A->ncol), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; /* out of memory */ + return (FALSE) ; // out of memory } ASSERT (CHOLMOD(dump_sparse) (A, "etree", Common) >= 0) ; Iwork = Common->Iwork ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - ncol = A->ncol ; /* the number of columns of A */ - nrow = A->nrow ; /* the number of rows of A */ - Ap = A->p ; /* size ncol+1, column pointers for A */ - Ai = A->i ; /* the row indices of A */ - Anz = A->nz ; /* number of nonzeros in each column of A */ + ncol = A->ncol ; // the number of columns of A + nrow = A->nrow ; // the number of rows of A + Ap = A->p ; // size ncol+1, column pointers for A + Ai = A->i ; // the row indices of A + Anz = A->nz ; // number of nonzeros in each column of A packed = A->packed ; - Ancestor = Iwork ; /* size ncol (i/i/l) */ + Ancestor = Iwork ; // size ncol for (j = 0 ; j < ncol ; j++) { - Parent [j] = EMPTY ; - Ancestor [j] = EMPTY ; + Parent [j] = EMPTY ; + Ancestor [j] = EMPTY ; } - /* ---------------------------------------------------------------------- */ - /* compute the etree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the etree + //-------------------------------------------------------------------------- if (stype > 0) { - /* ------------------------------------------------------------------ */ - /* symmetric (upper) case: compute etree (A) */ - /* ------------------------------------------------------------------ */ - - for (j = 0 ; j < ncol ; j++) - { - /* for each row i in column j of triu(A), excluding the diagonal */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i < j) - { - update_etree (i, j, Parent, Ancestor) ; - } - } - } + //---------------------------------------------------------------------- + // symmetric (upper) case: compute etree (A) + //---------------------------------------------------------------------- + + for (j = 0 ; j < ncol ; j++) + { + // for each row i in column j of triu(A), excluding the diagonal + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + if (i < j) + { + update_etree (i, j, Parent, Ancestor) ; + } + } + } } else if (stype == 0) { - /* ------------------------------------------------------------------ */ - /* unsymmetric case: compute etree (A'*A) */ - /* ------------------------------------------------------------------ */ - - Prev = Iwork + ncol ; /* size nrow (i/i/l) */ - for (i = 0 ; i < nrow ; i++) - { - Prev [i] = EMPTY ; - } - for (j = 0 ; j < ncol ; j++) - { - /* for each row i in column j of A */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - /* a graph is constructed dynamically with one path per row - * of A. If the ith row of A contains column indices - * (j1,j2,j3,j4) then the new graph has edges (j1,j2), (j2,j3), - * and (j3,j4). When at node i of this path-graph, all edges - * (jprev,j) are considered, where jprevPerm). If A is unsymmetric, either - * A(p,:)*A(p,:)'+beta*I or A(p,f)*A(p,f)'+beta*I is factorized. The set f and - * the nonzero pattern of the matrix A must be the same as the matrix passed to - * cholmod_analyze for the supernodal case. For the simplicial case, it can - * be different, but it should be the same for best performance. beta is real. - * - * A simplicial factorization or supernodal factorization is chosen, based on - * the type of the factor L. If L->is_super is TRUE, a supernodal LL' - * factorization is computed. Otherwise, a simplicial numeric factorization - * is computed, either LL' or LDL', depending on Common->final_ll. - * - * Once the factorization is complete, it can be left as is or optionally - * converted into any simplicial numeric type, depending on the - * Common->final_* parameters. If converted from a supernodal to simplicial - * type, and the Common->final_resymbol parameter is true, then numerically - * zero entries in L due to relaxed supernodal amalgamation are removed from - * the simplicial factor (they are always left in the supernodal form of L). - * Entries that are numerically zero but present in the simplicial symbolic - * pattern of L are left in place (that is, the graph of L remains chordal). - * This is required for the update/downdate/rowadd/rowdel routines to work - * properly. - * - * workspace: Flag (nrow), Head (nrow+1), - * if symmetric: Iwork (2*nrow+2*nsuper) - * if unsymmetric: Iwork (2*nrow+MAX(2*nsuper,ncol)) - * where nsuper is 0 if simplicial, or the # of relaxed supernodes in - * L otherwise (nsuper <= nrow). - * if simplicial: W (nrow). - * Allocates up to two temporary copies of its input matrix (including - * both pattern and numerical values). - * - * If the matrix is not positive definite the routine returns TRUE, but - * sets Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the - * column at which the failure occurred. Columns L->minor to L->n-1 are - * set to zero. - * - * Supports any xtype (pattern, real, complex, or zomplex), except that the - * input matrix A cannot be pattern-only. If L is simplicial, its numeric - * xtype matches A on output. If L is supernodal, its xtype is real if A is - * real, or complex if A is complex or zomplex. - */ +// Computes the numerical factorization of a symmetric matrix. The primary +// inputs to this routine are a sparse matrix A and the symbolic factor L from +// cholmod_analyze or a prior numerical factor L. If A is symmetric, this +// routine factorizes A(p,p)+beta*I (beta can be zero), where p is the +// fill-reducing permutation (L->Perm). If A is unsymmetric, either +// A(p,:)*A(p,:)'+beta*I or A(p,f)*A(p,f)'+beta*I is factorized. The set f and +// the nonzero pattern of the matrix A must be the same as the matrix passed to +// cholmod_analyze for the supernodal case. For the simplicial case, it can +// be different, but it should be the same for best performance. beta is real. +// +// A simplicial factorization or supernodal factorization is chosen, based on +// the type of the factor L. If L->is_super is TRUE, a supernodal LL' +// factorization is computed. Otherwise, a simplicial numeric factorization +// is computed, either LL' or LDL', depending on Common->final_ll. +// +// Once the factorization is complete, it can be left as is or optionally +// converted into any simplicial numeric type, depending on the +// Common->final_* parameters. If converted from a supernodal to simplicial +// type, and the Common->final_resymbol parameter is true, then numerically +// zero entries in L due to relaxed supernodal amalgamation are removed from +// the simplicial factor (they are always left in the supernodal form of L). +// Entries that are numerically zero but present in the simplicial symbolic +// pattern of L are left in place (that is, the graph of L remains chordal). +// This is required for the update/downdate/rowadd/rowdel routines to work +// properly. +// +// workspace: Flag (nrow), Head (nrow+1), +// if symmetric: Iwork (2*nrow+2*nsuper) +// if unsymmetric: Iwork (2*nrow+MAX(2*nsuper,ncol)) +// where nsuper is 0 if simplicial, or the # of relaxed supernodes in +// L otherwise (nsuper <= nrow). +// if simplicial: W (nrow). +// Allocates up to two temporary copies of its input matrix (including +// both pattern and numerical values). +// +// If the matrix is not positive definite the routine returns TRUE, but +// sets Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the +// column at which the failure occurred. Columns L->minor to L->n-1 are +// set to zero. +// +// Supports any xtype (pattern, real, complex, or zomplex), except that the +// input matrix A cannot be pattern-only. If L is simplicial, its numeric +// xtype matches A on output. If L is supernodal, its xtype is real if A is +// real, or complex if A is complex or zomplex. +// +// The factorization L is computed with the same dtype as A (L->dtype will +// be the same as A->dtype). #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === cholmod_factorize ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_factorize +//------------------------------------------------------------------------------ -/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained - * from cholmod_analyze. The analysis can be re-used simply by calling this - * routine a second time with another matrix. A must have the same nonzero - * pattern as that passed to cholmod_analyze. */ +// Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained +// from cholmod_analyze. The analysis can be re-used simply by calling this +// routine a second time with another matrix. A must have the same nonzero +// pattern as that passed to cholmod_analyze. int CHOLMOD(factorize) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) { @@ -83,34 +84,32 @@ int CHOLMOD(factorize) return (CHOLMOD(factorize_p) (A, zero, NULL, 0, L, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_factorize_p +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_factorize_p ================================================== */ -/* ========================================================================== */ - -/* Same as cholmod_factorize, but with more options. */ +// Same as cholmod_factorize, but with more options. int CHOLMOD(factorize_p) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + double beta [2], // factorize beta*I+A or beta*I+A'*A + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) { + cholmod_sparse *S, *F, *A1, *A2 ; - Int nrow, ncol, stype, convert, n, nsuper, grow2, status ; - size_t s, t, uncol ; + Int nrow, ncol, stype, convert, n, grow2, status ; int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -123,39 +122,39 @@ int CHOLMOD(factorize_p) stype = A->stype ; if (L->n != A->nrow) { - ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; + return (FALSE) ; } if (stype != 0 && nrow != ncol) { - ERROR (CHOLMOD_INVALID, "matrix invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "matrix invalid") ; + return (FALSE) ; } DEBUG (CHOLMOD(dump_sparse) (A, "A for cholmod_factorize", Common)) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - nsuper = (L->is_super ? L->nsuper : 0) ; - uncol = ((stype != 0) ? 0 : ncol) ; + size_t nsuper = (L->is_super ? L->nsuper : 0) ; + size_t uncol = ((stype != 0) ? 0 : A->ncol) ; - /* s = 2*nrow + MAX (uncol, 2*nsuper) */ - s = CHOLMOD(mult_size_t) (nsuper, 2, &ok) ; + // s = 2*nrow + MAX (uncol, 2*nsuper) + size_t s = CHOLMOD(mult_size_t) (nsuper, 2, &ok) ; s = MAX (uncol, s) ; - t = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; + size_t t = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ; s = CHOLMOD(add_size_t) (s, t, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } CHOLMOD(allocate_work) (nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } S = NULL ; @@ -163,255 +162,254 @@ int CHOLMOD(factorize_p) A1 = NULL ; A2 = NULL ; - /* convert to another form when done, if requested */ + // convert to another form when done, if requested convert = !(Common->final_asis) ; - /* ---------------------------------------------------------------------- */ - /* perform supernodal LL' or simplicial LDL' factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // perform supernodal LL' or simplicial LDL' factorization + //-------------------------------------------------------------------------- if (L->is_super) { -#ifndef NSUPERNODAL - - /* ------------------------------------------------------------------ */ - /* supernodal factorization */ - /* ------------------------------------------------------------------ */ - - if (L->ordering == CHOLMOD_NATURAL) - { - - /* -------------------------------------------------------------- */ - /* natural ordering */ - /* -------------------------------------------------------------- */ - - if (stype > 0) - { - /* S = tril (A'), F not needed */ - /* workspace: Iwork (nrow) */ - A1 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; - S = A1 ; - } - else if (stype < 0) - { - /* This is the fastest option for the natural ordering */ - /* S = A; F not needed */ - S = A ; - } - else - { - /* F = A(:,f)' */ - /* workspace: Iwork (nrow) */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ - A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; - F = A1 ; - /* S = A */ - S = A ; - } - - } - else - { - - /* -------------------------------------------------------------- */ - /* permute the input matrix before factorization */ - /* -------------------------------------------------------------- */ - - if (stype > 0) - { - /* This is the fastest option for factoring a permuted matrix */ - /* S = tril (PAP'); F not needed */ - /* workspace: Iwork (2*nrow) */ - A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; - S = A1 ; - } - else if (stype < 0) - { - /* A2 = triu (PAP') */ - /* workspace: Iwork (2*nrow) */ - A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; - /* S = tril (A2'); F not needed */ - /* workspace: Iwork (nrow) */ - A1 = CHOLMOD(ptranspose) (A2, 2, NULL, NULL, 0, Common) ; - S = A1 ; - CHOLMOD(free_sparse) (&A2, Common) ; - ASSERT (A2 == NULL) ; - } - else - { - /* F = A(p,f)' */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ - A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; - F = A1 ; - /* S = F' */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; - S = A2 ; - } - } - - /* ------------------------------------------------------------------ */ - /* supernodal factorization */ - /* ------------------------------------------------------------------ */ - - /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow+2*nsuper) */ - if (Common->status == CHOLMOD_OK) - { - CHOLMOD(super_numeric) (S, F, beta, L, Common) ; - } - status = Common->status ; - ASSERT (IMPLIES (status >= CHOLMOD_OK, L->xtype != CHOLMOD_PATTERN)) ; - - /* ------------------------------------------------------------------ */ - /* convert to final form, if requested */ - /* ------------------------------------------------------------------ */ - - if (Common->status >= CHOLMOD_OK && convert) - { - /* workspace: none */ - ok = CHOLMOD(change_factor) (L->xtype, Common->final_ll, - Common->final_super, Common->final_pack, - Common->final_monotonic, L, Common) ; - if (ok && Common->final_resymbol && !(L->is_super)) - { - /* workspace: Flag (nrow), Head (nrow+1), - * if symmetric: Iwork (2*nrow) - * if unsymmetric: Iwork (2*nrow+ncol) */ - CHOLMOD(resymbol_noperm) (S, fset, fsize, Common->final_pack, - L, Common) ; - } - } - -#else - - /* ------------------------------------------------------------------ */ - /* CHOLMOD Supernodal module not installed */ - /* ------------------------------------------------------------------ */ - - status = CHOLMOD_NOT_INSTALLED ; - ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; - -#endif + #ifndef NSUPERNODAL + + //---------------------------------------------------------------------- + // supernodal factorization + //---------------------------------------------------------------------- + + if (L->ordering == CHOLMOD_NATURAL) + { + + //------------------------------------------------------------------ + // natural ordering + //------------------------------------------------------------------ + + if (stype > 0) + { + // S = tril (A'), F not needed + // workspace: Iwork (nrow) + A1 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; + S = A1 ; + } + else if (stype < 0) + { + // This is the fastest option for the natural ordering + // S = A; F not needed + S = A ; + } + else + { + // F = A(:,f)' + // workspace: Iwork (nrow) + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; + F = A1 ; + // S = A + S = A ; + } + + } + else + { + + //------------------------------------------------------------------ + // permute the input matrix before factorization + //------------------------------------------------------------------ + + if (stype > 0) + { + // This is the fastest option for factoring a permuted matrix + // S = tril (PAP'); F not needed + // workspace: Iwork (2*nrow) + A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; + S = A1 ; + } + else if (stype < 0) + { + // A2 = triu (PAP') + // workspace: Iwork (2*nrow) + A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; + // S = tril (A2'); F not needed + // workspace: Iwork (nrow) + A1 = CHOLMOD(ptranspose) (A2, 2, NULL, NULL, 0, Common) ; + S = A1 ; + CHOLMOD(free_sparse) (&A2, Common) ; + ASSERT (A2 == NULL) ; + } + else + { + // F = A(p,f)' + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; + F = A1 ; + // S = F' + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; + S = A2 ; + } + } + + //---------------------------------------------------------------------- + // supernodal factorization + //---------------------------------------------------------------------- + + // workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow+2*nsuper) + if (Common->status == CHOLMOD_OK) + { + CHOLMOD(super_numeric) (S, F, beta, L, Common) ; + } + status = Common->status ; + ASSERT (IMPLIES (status >= CHOLMOD_OK, L->xtype != CHOLMOD_PATTERN)) ; + + //---------------------------------------------------------------------- + // convert to final form, if requested + //---------------------------------------------------------------------- + + if (Common->status >= CHOLMOD_OK && convert) + { + // workspace: none + ok = CHOLMOD(change_factor) (L->xtype, Common->final_ll, + Common->final_super, Common->final_pack, + Common->final_monotonic, L, Common) ; + if (ok && Common->final_resymbol && !(L->is_super)) + { + // workspace: Flag (nrow), Head (nrow+1), + // if symmetric: Iwork (2*nrow) + // if unsymmetric: Iwork (2*nrow+ncol) + CHOLMOD(resymbol_noperm) (S, fset, fsize, Common->final_pack, + L, Common) ; + } + } + + #else + + //---------------------------------------------------------------------- + // CHOLMOD Supernodal module not installed + //---------------------------------------------------------------------- + + status = CHOLMOD_NOT_INSTALLED ; + ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; + + #endif } else { - /* ------------------------------------------------------------------ */ - /* simplicial LDL' factorization */ - /* ------------------------------------------------------------------ */ - - /* Permute the input matrix A if necessary. cholmod_rowfac requires - * triu(A) in column form for the symmetric case, and A in column form - * for the unsymmetric case (the matrix S). The unsymmetric case - * requires A in row form, or equivalently A' in column form (the - * matrix F). - */ - - if (L->ordering == CHOLMOD_NATURAL) - { - - /* -------------------------------------------------------------- */ - /* natural ordering */ - /* -------------------------------------------------------------- */ - - if (stype > 0) - { - /* F is not needed, S = A */ - S = A ; - } - else if (stype < 0) - { - /* F is not needed, S = A' */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; - S = A2 ; - } - else - { - /* F = A (:,f)' */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ - A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; - F = A1 ; - S = A ; - } - - } - else - { - - /* -------------------------------------------------------------- */ - /* permute the input matrix before factorization */ - /* -------------------------------------------------------------- */ - - if (stype > 0) - { - /* F = tril (A (p,p)') */ - /* workspace: Iwork (2*nrow) */ - A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; - /* A2 = triu (F') */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (A1, 2, NULL, NULL, 0, Common) ; - /* the symmetric case does not need F, free it and set to NULL*/ - CHOLMOD(free_sparse) (&A1, Common) ; - } - else if (stype < 0) - { - /* A2 = triu (A (p,p)'), F not needed. This is the fastest - * way to factorize a matrix using the simplicial routine - * (cholmod_rowfac). */ - /* workspace: Iwork (2*nrow) */ - A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; - } - else - { - /* F = A (p,f)' */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ - A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; - F = A1 ; - /* A2 = F' */ - /* workspace: Iwork (nrow) */ - A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; - } - S = A2 ; - } - - /* ------------------------------------------------------------------ */ - /* simplicial LDL' or LL' factorization */ - /* ------------------------------------------------------------------ */ - - /* factorize beta*I+S (symmetric) or beta*I+F*F' (unsymmetric) */ - /* workspace: Flag (nrow), W (nrow), Iwork (2*nrow) */ - if (Common->status == CHOLMOD_OK) - { - grow2 = Common->grow2 ; - L->is_ll = (Common->final_ll) ? 1 : 0 ; - if (L->xtype == CHOLMOD_PATTERN && Common->final_pack) - { - /* allocate a factor with exactly the space required */ - Common->grow2 = 0 ; - } - CHOLMOD(rowfac) (S, F, beta, 0, nrow, L, Common) ; - Common->grow2 = grow2 ; - } - status = Common->status ; - - /* ------------------------------------------------------------------ */ - /* convert to final form, if requested */ - /* ------------------------------------------------------------------ */ - - if (Common->status >= CHOLMOD_OK && convert) - { - /* workspace: none */ - CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, - Common->final_pack, Common->final_monotonic, L, Common) ; - } + //---------------------------------------------------------------------- + // simplicial LDL' factorization + //---------------------------------------------------------------------- + + // Permute the input matrix A if necessary. cholmod_rowfac requires + // triu(A) in column form for the symmetric case, and A in column form + // for the unsymmetric case (the matrix S). The unsymmetric case + // requires A in row form, or equivalently A' in column form (the + // matrix F). + + if (L->ordering == CHOLMOD_NATURAL) + { + + //------------------------------------------------------------------ + // natural ordering + //------------------------------------------------------------------ + + if (stype > 0) + { + // F is not needed, S = A + S = A ; + } + else if (stype < 0) + { + // F is not needed, S = A' + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; + S = A2 ; + } + else + { + // F = A (:,f)' + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; + F = A1 ; + S = A ; + } + + } + else + { + + //------------------------------------------------------------------ + // permute the input matrix before factorization + //------------------------------------------------------------------ + + if (stype > 0) + { + // F = tril (A (p,p)') + // workspace: Iwork (2*nrow) + A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; + // A2 = triu (F') + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (A1, 2, NULL, NULL, 0, Common) ; + // the symmetric case does not need F, free it and set to NULL + CHOLMOD(free_sparse) (&A1, Common) ; + } + else if (stype < 0) + { + // A2 = triu (A (p,p)'), F not needed. This is the fastest + // way to factorize a matrix using the simplicial routine + // (cholmod_rowfac). + // workspace: Iwork (2*nrow) + A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; + } + else + { + // F = A (p,f)' + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) + A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; + F = A1 ; + // A2 = F' + // workspace: Iwork (nrow) + A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; + } + S = A2 ; + } + + //---------------------------------------------------------------------- + // simplicial LDL' or LL' factorization + //---------------------------------------------------------------------- + + // factorize beta*I+S (symmetric) or beta*I+F*F' (unsymmetric) + // workspace: Flag (nrow), W (nrow), Iwork (2*nrow) + if (Common->status == CHOLMOD_OK) + { + grow2 = Common->grow2 ; + L->is_ll = (Common->final_ll) ? 1 : 0 ; + if (L->xtype == CHOLMOD_PATTERN && Common->final_pack) + { + // allocate a factor with exactly the space required + Common->grow2 = 0 ; + } + CHOLMOD(rowfac) (S, F, beta, 0, nrow, L, Common) ; + Common->grow2 = grow2 ; + } + status = Common->status ; + + //---------------------------------------------------------------------- + // convert to final form, if requested + //---------------------------------------------------------------------- + + if (Common->status >= CHOLMOD_OK && convert) + { + // workspace: none + CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, + Common->final_pack, Common->final_monotonic, L, Common) ; + } } - /* ---------------------------------------------------------------------- */ - /* free A1 and A2 if they exist */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free A1 and A2 if they exist + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; @@ -419,3 +417,4 @@ int CHOLMOD(factorize_p) return (Common->status >= CHOLMOD_OK) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_l_amd.c b/CHOLMOD/Cholesky/cholmod_l_amd.c index 8cdd7ca0ee..b1b9db045a 100644 --- a/CHOLMOD/Cholesky/cholmod_l_amd.c +++ b/CHOLMOD/Cholesky/cholmod_l_amd.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_amd.c: int64_t version of cholmod_amd //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_analyze.c b/CHOLMOD/Cholesky/cholmod_l_analyze.c index 0a7d87d0ff..ab8399e859 100644 --- a/CHOLMOD/Cholesky/cholmod_l_analyze.c +++ b/CHOLMOD/Cholesky/cholmod_l_analyze.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_analyze.c: int64_t version of cholmod_analyze //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_colamd.c b/CHOLMOD/Cholesky/cholmod_l_colamd.c index 990fab3d5f..1416a6d3b7 100644 --- a/CHOLMOD/Cholesky/cholmod_l_colamd.c +++ b/CHOLMOD/Cholesky/cholmod_l_colamd.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_colamd.c: int64_t version of cholmod_colamd //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_etree.c b/CHOLMOD/Cholesky/cholmod_l_etree.c index 9c30c27cb8..510d1b3559 100644 --- a/CHOLMOD/Cholesky/cholmod_l_etree.c +++ b/CHOLMOD/Cholesky/cholmod_l_etree.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_etree.c: int64_t version of cholmod_etree //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_factorize.c b/CHOLMOD/Cholesky/cholmod_l_factorize.c index b7572779b3..c9f0a7628a 100644 --- a/CHOLMOD/Cholesky/cholmod_l_factorize.c +++ b/CHOLMOD/Cholesky/cholmod_l_factorize.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_factorize.c: int64_t version of cholmod_factorize //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_postorder.c b/CHOLMOD/Cholesky/cholmod_l_postorder.c index ebf4b2cbb2..cee8fe9713 100644 --- a/CHOLMOD/Cholesky/cholmod_l_postorder.c +++ b/CHOLMOD/Cholesky/cholmod_l_postorder.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_postorder.c: int64_t version of cholmod_postorder //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_rcond.c b/CHOLMOD/Cholesky/cholmod_l_rcond.c index 63bb7b2d08..cd277e6303 100644 --- a/CHOLMOD/Cholesky/cholmod_l_rcond.c +++ b/CHOLMOD/Cholesky/cholmod_l_rcond.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_rcond.c: int64_t version of cholmod_rcond //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_resymbol.c b/CHOLMOD/Cholesky/cholmod_l_resymbol.c index 8b5f15c755..d6dca22200 100644 --- a/CHOLMOD/Cholesky/cholmod_l_resymbol.c +++ b/CHOLMOD/Cholesky/cholmod_l_resymbol.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_resymbol.c: int64_t version of cholmod_resymbol //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_rowcolcounts.c b/CHOLMOD/Cholesky/cholmod_l_rowcolcounts.c index 884ab3fb02..a894aaff68 100644 --- a/CHOLMOD/Cholesky/cholmod_l_rowcolcounts.c +++ b/CHOLMOD/Cholesky/cholmod_l_rowcolcounts.c @@ -1,9 +1,8 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky/cholmod_l_rowcolcounts.c: -// int64_t version of cholmod_rowcolcounts +// CHOLMOD/Cholesky/cholmod_l_rowcolcounts: compute row/col counts of L //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_rowfac.c b/CHOLMOD/Cholesky/cholmod_l_rowfac.c index 5aa9253e0b..e7f1bdb4a5 100644 --- a/CHOLMOD/Cholesky/cholmod_l_rowfac.c +++ b/CHOLMOD/Cholesky/cholmod_l_rowfac.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_rowfac.c: int64_t version of cholmod_rowfac //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_solve.c b/CHOLMOD/Cholesky/cholmod_l_solve.c index 01de1758ef..59e534c4f0 100644 --- a/CHOLMOD/Cholesky/cholmod_l_solve.c +++ b/CHOLMOD/Cholesky/cholmod_l_solve.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_solve.c: int64_t version of cholmod_solve //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_l_spsolve.c b/CHOLMOD/Cholesky/cholmod_l_spsolve.c index 7c510d836d..a8bd097e06 100644 --- a/CHOLMOD/Cholesky/cholmod_l_spsolve.c +++ b/CHOLMOD/Cholesky/cholmod_l_spsolve.c @@ -2,7 +2,7 @@ // CHOLMOD/Cholesky/cholmod_l_spsolve.c: int64_t version of cholmod_spsolve //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Cholesky/cholmod_postorder.c b/CHOLMOD/Cholesky/cholmod_postorder.c index a6e67d4b2b..2ca7fab3bd 100644 --- a/CHOLMOD/Cholesky/cholmod_postorder.c +++ b/CHOLMOD/Cholesky/cholmod_postorder.c @@ -2,288 +2,287 @@ // CHOLMOD/Cholesky/cholmod_postorder: postordering of a tree //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Compute the postorder of a tree. */ +// Compute the postorder of a tree. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === dfs ================================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// dfs +//------------------------------------------------------------------------------ -/* The code below includes both a recursive and non-recursive depth-first-search - * of a tree. The recursive code is simpler, but can lead to stack overflow. - * It is left here for reference, to understand what the non-recursive code - * is computing. To try the recursive version, uncomment the following - * #define, or compile the code with -DRECURSIVE. Be aware that stack - * overflow may occur. -#define RECURSIVE - */ +// The code below includes both a recursive and non-recursive depth-first-search +// of a tree. The recursive code is simpler, but can lead to stack overflow. +// It is left here for reference, to understand what the non-recursive code +// is computing. To try the recursive version, uncomment the following +// #define, or compile the code with -DRECURSIVE. Be aware that stack +// overflow may occur. +// #define RECURSIVE +// #ifdef RECURSIVE -/* recursive version: a working code for reference only, not actual use */ +// recursive version: a working code for reference only, not actual use -static Int dfs /* return the new value of k */ +static Int dfs // return the new value of k ( - Int p, /* start a DFS at node p */ - Int k, /* start the node numbering at k */ - Int Post [ ], /* Post ordering, modified on output */ - Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */ - Int Next [ ], /* Next [j] = sibling of j; unmodified */ - Int Pstack [ ] /* unused */ + Int p, // start a DFS at node p + Int k, // start the node numbering at k + Int Post [ ], // Post ordering, modified on output + Int Head [ ], // Head [p] = youngest child of p; EMPTY on output + Int Next [ ], // Next [j] = sibling of j; unmodified + Int Pstack [ ] // unused ) { Int j ; - /* start a DFS at each child of node p */ + // start a DFS at each child of node p for (j = Head [p] ; j != EMPTY ; j = Next [j]) { - /* start a DFS at child node j */ - k = dfs (j, k, Post, Head, Next, Pstack) ; + // start a DFS at child node j + k = dfs (j, k, Post, Head, Next, Pstack) ; } - Post [k++] = p ; /* order node p as the kth node */ - Head [p] = EMPTY ; /* link list p no longer needed */ - return (k) ; /* the next node will be numbered k */ + Post [k++] = p ; // order node p as the kth node + Head [p] = EMPTY ; // link list p no longer needed + return (k) ; // the next node will be numbered k } #else -/* non-recursive version for actual use */ +// non-recursive version for actual use -static Int dfs /* return the new value of k */ +static Int dfs // return the new value of k ( - Int p, /* start the DFS at a root node p */ - Int k, /* start the node numbering at k */ - Int Post [ ], /* Post ordering, modified on output */ - Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */ - Int Next [ ], /* Next [j] = sibling of j; unmodified */ - Int Pstack [ ] /* workspace of size n, undefined on input or output */ + Int p, // start the DFS at a root node p + Int k, // start the node numbering at k + Int Post [ ], // Post ordering, modified on output + Int Head [ ], // Head [p] = youngest child of p; EMPTY on output + Int Next [ ], // Next [j] = sibling of j; unmodified + Int Pstack [ ] // workspace of size n, undefined on input or output ) { Int j, phead ; - /* put the root node on the stack */ + // put the root node on the stack Pstack [0] = p ; phead = 0 ; - /* while the stack is not empty, do: */ + // while the stack is not empty, do: while (phead >= 0) { - /* grab the node p from top of the stack and get its youngest child j */ - p = Pstack [phead] ; - j = Head [p] ; - if (j == EMPTY) - { - /* all children of p ordered. remove p from stack and order it */ - phead-- ; - Post [k++] = p ; /* order node p as the kth node */ - } - else - { - /* leave p on the stack. Start a DFS at child node j by putting - * j on the stack and removing j from the list of children of p. */ - Head [p] = Next [j] ; - Pstack [++phead] = j ; - } + // grab the node p from top of the stack and get its youngest child j + p = Pstack [phead] ; + j = Head [p] ; + if (j == EMPTY) + { + // all children of p ordered. remove p from stack and order it + phead-- ; + Post [k++] = p ; // order node p as the kth node + } + else + { + // leave p on the stack. Start a DFS at child node j by putting + // j on the stack and removing j from the list of children of p. + Head [p] = Next [j] ; + Pstack [++phead] = j ; + } } - return (k) ; /* the next node will be numbered k */ + return (k) ; // the next node will be numbered k } #endif -/* ========================================================================== */ -/* === cholmod_postorder ==================================================== */ -/* ========================================================================== */ - -/* Postorder a tree. The tree is either an elimination tree (the output from - * from cholmod_etree) or a component tree (from cholmod_nested_dissection). - * - * An elimination tree is a complete tree of n nodes with Parent [j] > j or - * Parent [j] = EMPTY if j is a root. On output Post [0..n-1] is a complete - * permutation vector. - * - * A component tree is a subset of 0..n-1. Parent [j] = -2 if node j is not - * in the component tree. Parent [j] = EMPTY if j is a root of the component - * tree, and Parent [j] is in the range 0 to n-1 if j is in the component - * tree but not a root. On output, Post [k] is defined only for nodes in - * the component tree. Post [k] = j if node j is the kth node in the - * postordered component tree, where k is in the range 0 to the number of - * components minus 1. - * - * Node j is ignored and not included in the postorder if Parent [j] < EMPTY. - * - * As a result, check_parent (Parent, n,...) may fail on input, since - * cholmod_check_parent assumes Parent is an elimination tree. Similarly, - * cholmod_check_perm (Post, ...) may fail on output, since Post is a partial - * permutation if Parent is a component tree. - * - * An optional node weight can be given. When starting a postorder at node j, - * the children of j are ordered in increasing order of their weight. - * If no weights are given (Weight is NULL) then children are ordered in - * increasing order of their node number. The weight of a node must be in the - * range 0 to n-1. Weights outside that range are silently converted to that - * range (weights < 0 are treated as zero, and weights >= n are treated as n-1). - * - * - * workspace: Head (n), Iwork (2*n) - */ - -Int CHOLMOD(postorder) /* return # of nodes postordered */ +//------------------------------------------------------------------------------ +// cholmod_postorder +//------------------------------------------------------------------------------ + +// Postorder a tree. The tree is either an elimination tree (the output from +// from cholmod_etree) or a component tree (from cholmod_nested_dissection). +// +// An elimination tree is a complete tree of n nodes with Parent [j] > j or +// Parent [j] = EMPTY if j is a root. On output Post [0..n-1] is a complete +// permutation vector. +// +// A component tree is a subset of 0..n-1. Parent [j] = -2 if node j is not +// in the component tree. Parent [j] = EMPTY if j is a root of the component +// tree, and Parent [j] is in the range 0 to n-1 if j is in the component +// tree but not a root. On output, Post [k] is defined only for nodes in +// the component tree. Post [k] = j if node j is the kth node in the +// postordered component tree, where k is in the range 0 to the number of +// components minus 1. +// +// Node j is ignored and not included in the postorder if Parent [j] < EMPTY. +// +// As a result, check_parent (Parent, n,...) may fail on input, since +// cholmod_check_parent assumes Parent is an elimination tree. Similarly, +// cholmod_check_perm (Post, ...) may fail on output, since Post is a partial +// permutation if Parent is a component tree. +// +// An optional node weight can be given. When starting a postorder at node j, +// the children of j are ordered in increasing order of their weight. +// If no weights are given (Weight is NULL) then children are ordered in +// increasing order of their node number. The weight of a node must be in the +// range 0 to n-1. Weights outside that range are silently converted to that +// range (weights < 0 are treated as zero, and weights >= n are treated as n-1). +// +// +// workspace: Head (n), Iwork (2*n) + +Int CHOLMOD(postorder) // return # of nodes postordered ( - /* ---- input ---- */ - Int *Parent, /* size n. Parent [j] = p if p is the parent of j */ + // input: + Int *Parent, // size n. Parent [j] = p if p is the parent of j size_t n_input, - Int *Weight, /* size n, optional. Weight [j] is weight of node j */ - /* ---- output --- */ - Int *Post, /* size n. Post [k] = j is kth in postordered tree */ - /* --------------- */ + Int *Weight, // size n, optional. Weight [j] is weight of node j + // output: + Int *Post, // size n. Post [k] = j is kth in postordered tree cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + Int *Head, *Next, *Pstack, *Iwork ; Int j, p, k, w, nextj ; size_t s ; int ok = TRUE ; Int n = (Int) n_input ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ - RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (Parent, EMPTY) ; RETURN_IF_NULL (Post, EMPTY) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 2*n */ + // s = 2*n s = CHOLMOD(mult_size_t) (n_input, (size_t) 2, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (EMPTY) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (EMPTY) ; } CHOLMOD(allocate_work) (n, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - Head = Common->Head ; /* size n+1, initially all EMPTY */ + Head = Common->Head ; // size n+1, initially all EMPTY Iwork = Common->Iwork ; - Next = Iwork ; /* size n (i/i/l) */ - Pstack = Iwork + n ; /* size n (i/i/l) */ + Next = Iwork ; // size n + Pstack = Iwork + n ; // size n - /* ---------------------------------------------------------------------- */ - /* construct a link list of children for each node */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a link list of children for each node + //-------------------------------------------------------------------------- if (Weight == NULL) { - /* in reverse order so children are in ascending order in each list */ - for (j = n-1 ; j >= 0 ; j--) - { - p = Parent [j] ; - if (p >= 0 && p < ((Int) n)) - { - /* add j to the list of children for node p */ - Next [j] = Head [p] ; - Head [p] = j ; - } - } - - /* Head [p] = j if j is the youngest (least-numbered) child of p */ - /* Next [j1] = j2 if j2 is the next-oldest sibling of j1 */ + // in reverse order so children are in ascending order in each list + for (j = n-1 ; j >= 0 ; j--) + { + p = Parent [j] ; + if (p >= 0 && p < ((Int) n)) + { + // add j to the list of children for node p + Next [j] = Head [p] ; + Head [p] = j ; + } + } + + // Head [p] = j if j is the youngest (least-numbered) child of p + // Next [j1] = j2 if j2 is the next-oldest sibling of j1 } else { - /* First, construct a set of link lists according to Weight. - * - * Whead [w] = j if node j is the first node in bucket w. - * Next [j1] = j2 if node j2 follows j1 in a link list. - */ - - Int *Whead = Pstack ; /* use Pstack as workspace for Whead [ */ - - for (w = 0 ; w < ((Int) n) ; w++) - { - Whead [w] = EMPTY ; - } - /* do in forward order, so nodes that ties are ordered by node index */ - for (j = 0 ; j < ((Int) n) ; j++) - { - p = Parent [j] ; - if (p >= 0 && p < ((Int) n)) - { - w = Weight [j] ; - w = MAX (0, w) ; - w = MIN (w, ((Int) n) - 1) ; - /* place node j at the head of link list for weight w */ - Next [j] = Whead [w] ; - Whead [w] = j ; - } - } - - /* traverse weight buckets, placing each node in its parent's list */ - for (w = n-1 ; w >= 0 ; w--) - { - for (j = Whead [w] ; j != EMPTY ; j = nextj) - { - nextj = Next [j] ; - /* put node j in the link list of its parent */ - p = Parent [j] ; - ASSERT (p >= 0 && p < ((Int) n)) ; - Next [j] = Head [p] ; - Head [p] = j ; - } - } - - /* Whead no longer needed ] */ - /* Head [p] = j if j is the lightest child of p */ - /* Next [j1] = j2 if j2 is the next-heaviest sibling of j1 */ + // First, construct a set of link lists according to Weight. + // + // Whead [w] = j if node j is the first node in bucket w. + // Next [j1] = j2 if node j2 follows j1 in a link list. + + Int *Whead = Pstack ; // use Pstack as workspace for Whead [ + + for (w = 0 ; w < ((Int) n) ; w++) + { + Whead [w] = EMPTY ; + } + // do in forward order, so nodes that ties are ordered by node index + for (j = 0 ; j < ((Int) n) ; j++) + { + p = Parent [j] ; + if (p >= 0 && p < ((Int) n)) + { + w = Weight [j] ; + w = MAX (0, w) ; + w = MIN (w, ((Int) n) - 1) ; + // place node j at the head of link list for weight w + Next [j] = Whead [w] ; + Whead [w] = j ; + } + } + + // traverse weight buckets, placing each node in its parent's list + for (w = n-1 ; w >= 0 ; w--) + { + for (j = Whead [w] ; j != EMPTY ; j = nextj) + { + nextj = Next [j] ; + // put node j in the link list of its parent + p = Parent [j] ; + ASSERT (p >= 0 && p < ((Int) n)) ; + Next [j] = Head [p] ; + Head [p] = j ; + } + } + + // Whead no longer needed ] + // Head [p] = j if j is the lightest child of p + // Next [j1] = j2 if j2 is the next-heaviest sibling of j1 } - /* ---------------------------------------------------------------------- */ - /* start a DFS at each root node of the etree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start a DFS at each root node of the etree + //-------------------------------------------------------------------------- k = 0 ; for (j = 0 ; j < ((Int) n) ; j++) { - if (Parent [j] == EMPTY) - { - /* j is the root of a tree; start a DFS here */ - k = dfs (j, k, Post, Head, Next, Pstack) ; - } + if (Parent [j] == EMPTY) + { + // j is the root of a tree; start a DFS here + k = dfs (j, k, Post, Head, Next, Pstack) ; + } } - /* this would normally be EMPTY already, unless Parent is invalid */ + // this would normally be EMPTY already, unless Parent is invalid for (j = 0 ; j < ((Int) n) ; j++) { - Head [j] = EMPTY ; + Head [j] = EMPTY ; } PRINT1 (("postordered "ID" nodes\n", k)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (k) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_rcond.c b/CHOLMOD/Cholesky/cholmod_rcond.c index ae69bfbda5..6cd58faf80 100644 --- a/CHOLMOD/Cholesky/cholmod_rcond.c +++ b/CHOLMOD/Cholesky/cholmod_rcond.c @@ -2,157 +2,111 @@ // CHOLMOD/Cholesky/cholmod_rcond: estimate the reciprocal of condition number //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Return a rough estimate of the reciprocal of the condition number: - * the minimum entry on the diagonal of L (or absolute entry of D for an LDL' - * factorization) divided by the maximum entry (squared for LL'). L can be - * real, complex, or zomplex. Returns -1 on error, 0 if the matrix is singular - * or has a zero entry on the diagonal of L, 1 if the matrix is 0-by-0, or - * min(diag(L))/max(diag(L)) otherwise. Never returns NaN; if L has a NaN on - * the diagonal it returns zero instead. - * - * For an LL' factorization, (min(diag(L))/max(diag(L)))^2 is returned. - * For an LDL' factorization, (min(diag(D))/max(diag(D))) is returned. - */ +// Return a rough estimate of the reciprocal of the condition number: +// the minimum entry on the diagonal of L (or absolute entry of D for an LDL' +// factorization) divided by the maximum entry (squared for LL'). L can be +// real, complex, or zomplex. Returns -1 on error, 0 if the matrix is singular +// or has a zero entry on the diagonal of L, 1 if the matrix is 0-by-0, or +// min(diag(L))/max(diag(L)) otherwise. Never returns NaN; if L has a NaN on +// the diagonal it returns zero instead. +// +// For an LL' factorization, (min(diag(L))/max(diag(L)))^2 is returned. +// For an LDL' factorization, (min(diag(D))/max(diag(D))) is returned. +// +// The real and zomplex cases are the same, since this method only accesses the +// the diagonal of L for an LL' factorization, or D for LDL' factorization, +// and these entries are always real. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === LMINMAX ============================================================== */ -/* ========================================================================== */ - -/* Update lmin and lmax for one entry L(j,j) */ - -#define FIRST_LMINMAX(Ljj,lmin,lmax) \ -{ \ - double ljj = Ljj ; \ - if (isnan (ljj)) \ - { \ - return (0) ; \ - } \ - lmin = ljj ; \ - lmax = ljj ; \ -} +//------------------------------------------------------------------------------ +// t_cholmod_rcond_worker template +//------------------------------------------------------------------------------ -#define LMINMAX(Ljj,lmin,lmax) \ -{ \ - double ljj = Ljj ; \ - if (isnan (ljj)) \ - { \ - return (0) ; \ - } \ - if (ljj < lmin) \ - { \ - lmin = ljj ; \ - } \ - else if (ljj > lmax) \ - { \ - lmax = ljj ; \ - } \ -} +#define DOUBLE +#define REAL +#include "t_cholmod_rcond_worker.c" +#define COMPLEX +#include "t_cholmod_rcond_worker.c" -/* ========================================================================== */ -/* === cholmod_rcond ======================================================== */ -/* ========================================================================== */ +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_rcond_worker.c" +#define COMPLEX +#include "t_cholmod_rcond_worker.c" -double CHOLMOD(rcond) /* return min(diag(L)) / max(diag(L)) */ +//------------------------------------------------------------------------------ +// cholmod_rcond +//------------------------------------------------------------------------------ + +double CHOLMOD(rcond) // return rcond estimate ( - /* ---- input ---- */ - cholmod_factor *L, - /* --------------- */ + // input: + cholmod_factor *L, // factorization to query; not modified cholmod_common *Common ) { - double lmin, lmax, rcond ; - double *Lx ; - Int *Lpi, *Lpx, *Super, *Lp ; - Int n, e, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, jj, j ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (L, EMPTY) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // handle special cases + //-------------------------------------------------------------------------- - n = L->n ; - if (n == 0) + if (L->n == 0) { - return (1) ; + return (1) ; } if (L->minor < L->n) { - return (0) ; + return (0) ; } - e = (L->xtype == CHOLMOD_COMPLEX) ? 2 : 1 ; + //-------------------------------------------------------------------------- + // compute rcond + //-------------------------------------------------------------------------- - if (L->is_super) - { - /* L is supernodal */ - nsuper = L->nsuper ; /* number of supernodes in L */ - Lpi = L->pi ; /* column pointers for integer pattern */ - Lpx = L->px ; /* column pointers for numeric values */ - Super = L->super ; /* supernode sizes */ - Lx = L->x ; /* numeric values */ - FIRST_LMINMAX (Lx [0], lmin, lmax) ; /* first diagonal entry of L */ - for (s = 0 ; s < nsuper ; s++) - { - k1 = Super [s] ; /* first column in supernode s */ - k2 = Super [s+1] ; /* last column in supernode is k2-1 */ - psi = Lpi [s] ; /* first row index is L->s [psi] */ - psend = Lpi [s+1] ; /* last row index is L->s [psend-1] */ - psx = Lpx [s] ; /* first numeric entry is Lx [psx] */ - nsrow = psend - psi ; /* supernode is nsrow-by-nscol */ - nscol = k2 - k1 ; - for (jj = 0 ; jj < nscol ; jj++) - { - LMINMAX (Lx [e * (psx + jj + jj*nsrow)], lmin, lmax) ; - } - } - } - else - { - /* L is simplicial */ - Lp = L->p ; - Lx = L->x ; - if (L->is_ll) - { - /* LL' factorization */ - FIRST_LMINMAX (Lx [Lp [0]], lmin, lmax) ; - for (j = 1 ; j < n ; j++) - { - LMINMAX (Lx [e * Lp [j]], lmin, lmax) ; - } - } - else - { - /* LDL' factorization, the diagonal might be negative */ - FIRST_LMINMAX (fabs (Lx [Lp [0]]), lmin, lmax) ; - for (j = 1 ; j < n ; j++) - { - LMINMAX (fabs (Lx [e * Lp [j]]), lmin, lmax) ; - } - } - } - rcond = lmin / lmax ; - if (L->is_ll) + double rcond = 0 ; + + switch ((L->xtype + L->dtype) % 8) { - rcond = rcond*rcond ; + + case CHOLMOD_REAL + CHOLMOD_SINGLE: + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + rcond = rs_cholmod_rcond_worker (L) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + rcond = cs_cholmod_rcond_worker (L) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + rcond = rd_cholmod_rcond_worker (L) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + rcond = cd_cholmod_rcond_worker (L) ; + break ; } + return (rcond) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_resymbol.c b/CHOLMOD/Cholesky/cholmod_resymbol.c index cc142a5b79..be63515ff9 100644 --- a/CHOLMOD/Cholesky/cholmod_resymbol.c +++ b/CHOLMOD/Cholesky/cholmod_resymbol.c @@ -2,64 +2,81 @@ // CHOLMOD/Cholesky/cholmod_resymbol: recompute symbolic pattern of L //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Recompute the symbolic pattern of L. Entries not in the symbolic pattern - * are dropped. L->Perm can be used (or not) to permute the input matrix A. - * - * These routines are used after a supernodal factorization is converted into - * a simplicial one, to remove zero entries that were added due to relaxed - * supernode amalgamation. They can also be used after a series of downdates - * to remove entries that would no longer be present if the matrix were - * factorized from scratch. A downdate (cholmod_updown) does not remove any - * entries from L. - * - * workspace: Flag (nrow), Head (nrow+1), - * if symmetric: Iwork (2*nrow) - * if unsymmetric: Iwork (2*nrow+ncol). - * Allocates up to 2 copies of its input matrix A (pattern only). - */ +// Recompute the symbolic pattern of L. Entries not in the symbolic pattern +// are dropped. L->Perm can be used (or not) to permute the input matrix A. +// +// These routines are used after a supernodal factorization is converted into +// a simplicial one, to remove zero entries that were added due to relaxed +// supernode amalgamation. They can also be used after a series of downdates +// to remove entries that would no longer be present if the matrix were +// factorized from scratch. A downdate (cholmod_updown) does not remove any +// entries from L. +// +// workspace: Flag (nrow), Head (nrow+1), +// if symmetric: Iwork (2*nrow) +// if unsymmetric: Iwork (2*nrow+ncol). +// Allocates up to 2 copies of its input matrix A (pattern only). #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === cholmod_resymbol ===================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_resymbol_worker +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_resymbol_worker.c" +#define COMPLEX +#include "t_cholmod_resymbol_worker.c" +#define ZOMPLEX +#include "t_cholmod_resymbol_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_resymbol_worker.c" +#define COMPLEX +#include "t_cholmod_resymbol_worker.c" +#define ZOMPLEX +#include "t_cholmod_resymbol_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_resymbol +//------------------------------------------------------------------------------ -/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', - * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). - * - * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it - * first permutes A according to L->Perm. A can be upper/lower/unsymmetric, - * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */ +// Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', +// or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). +// +// cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it +// first permutes A according to L->Perm. A can be upper/lower/unsymmetric, +// in contrast to cholmod_resymbol_noperm (which can be lower or unsym). -int CHOLMOD(resymbol) +int CHOLMOD(resymbol) // recompute symbolic pattern of L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) { - cholmod_sparse *H, *F, *G ; - Int stype, nrow, ncol ; - size_t s ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + cholmod_sparse *H = NULL, *F = NULL, *G = NULL ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -69,538 +86,390 @@ int CHOLMOD(resymbol) Common->status = CHOLMOD_OK ; if (L->is_super) { - /* cannot operate on a supernodal factorization */ - ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; - return (FALSE) ; + // cannot operate on a supernodal factorization + ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; + return (FALSE) ; } if (L->n != A->nrow) { - /* dimensions must agree */ - ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; - return (FALSE) ; + // dimensions must agree + ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - stype = A->stype ; - nrow = A->nrow ; - ncol = A->ncol ; + Int stype = A->stype ; + Int nrow = A->nrow ; + Int ncol = A->ncol ; - /* s = 2*nrow + (stype ? 0 : ncol) */ - s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; - s = CHOLMOD(add_size_t) (s, (stype ? 0 : ncol), &ok) ; + // s = 2*nrow + (stype ? 0 : ncol) + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ; + s = CHOLMOD(add_size_t) (s, (stype ? 0 : A->ncol), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (nrow, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* permute the input matrix if necessary */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // permute the input matrix if necessary + //-------------------------------------------------------------------------- H = NULL ; G = NULL ; if (stype > 0) { - if (L->ordering == CHOLMOD_NATURAL) - { - /* F = triu(A)' */ - /* workspace: Iwork (nrow) */ - G = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; - } - else - { - /* F = triu(A(p,p))' */ - /* workspace: Iwork (2*nrow) */ - G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; - } - F = G ; + if (L->ordering == CHOLMOD_NATURAL) + { + // F = triu(A)' + // workspace: Iwork (nrow) + G = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; + } + else + { + // F = triu(A(p,p))' + // workspace: Iwork (2*nrow) + G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; + } + F = G ; } else if (stype < 0) { - if (L->ordering == CHOLMOD_NATURAL) - { - F = A ; - } - else - { - /* G = triu(A(p,p))' */ - /* workspace: Iwork (2*nrow) */ - G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; - /* H = G' */ - /* workspace: Iwork (nrow) */ - H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; - F = H ; - } + if (L->ordering == CHOLMOD_NATURAL) + { + F = A ; + } + else + { + // G = triu(A(p,p))' + // workspace: Iwork (2*nrow) + G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; + // H = G' + // workspace: Iwork (nrow) + H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; + F = H ; + } } else { - if (L->ordering == CHOLMOD_NATURAL) - { - F = A ; - } - else - { - /* G = A(p,f)' */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ - G = CHOLMOD(ptranspose) (A, 0, L->Perm, fset, fsize, Common) ; - /* H = G' */ - /* workspace: Iwork (ncol) */ - H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; - F = H ; - } + if (L->ordering == CHOLMOD_NATURAL) + { + F = A ; + } + else + { + // G = A(p,f)' + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) + G = CHOLMOD(ptranspose) (A, 0, L->Perm, fset, fsize, Common) ; + // H = G' + // workspace: Iwork (ncol) + H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; + F = H ; + } } - /* No need to check for failure here. cholmod_resymbol_noperm will return - * FALSE if F is NULL. */ + // No need to check for failure here. cholmod_resymbol_noperm will return + // FALSE if F is NULL. - /* ---------------------------------------------------------------------- */ - /* resymbol */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // resymbol + //-------------------------------------------------------------------------- ok = CHOLMOD(resymbol_noperm) (F, fset, fsize, pack, L, Common) ; - /* ---------------------------------------------------------------------- */ - /* free the temporary matrices, if they exist */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the temporary matrices, if they exist + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&H, Common) ; CHOLMOD(free_sparse) (&G, Common) ; return (ok) ; } +//------------------------------------------------------------------------------ +// cholmod_resymbol_noperm +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_resymbol_noperm ============================================== */ -/* ========================================================================== */ - -/* Redo symbolic LDL' or LL' factorization of I + F*F' or I+A, where F=A(:,f). - * - * L already exists, but is a superset of the true dynamic pattern (simple - * column downdates and row deletions haven't pruned anything). Just redo the - * symbolic factorization and drop entries that are no longer there. The - * diagonal is not modified. The number of nonzeros in column j of L - * (L->nz[j]) can decrease. The column pointers (L->p[j]) remain unchanged if - * pack is FALSE or if L is not monotonic. Otherwise, the columns of L are - * packed in place. - * - * For the symmetric case, the columns of the lower triangular part of A - * are accessed by column. NOTE that this the transpose of the general case. - * - * For the unsymmetric case, F=A(:,f) is accessed by column. - * - * A need not be sorted, and can be packed or unpacked. If L->Perm is not - * identity, then A must already be permuted according to the permutation used - * to factorize L. The advantage of using this routine is that it does not - * need to create permuted copies of A first. - * - * This routine can be called if L is only partially factored via cholmod_rowfac - * since all it does is prune. If an entry is in F*F' or A, but not in L, it - * isn't added to L. - * - * L must be simplicial LDL' or LL'; it cannot be supernodal or symbolic. - * - * The set f is held in fset and fsize. - * fset = NULL means ":" in MATLAB. fset is ignored. - * fset != NULL means f = fset [0..fset-1]. - * fset != NULL and fsize = 0 means f is the empty set. - * There can be no duplicates in fset. - * Common->status is set to CHOLMOD_INVALID if fset is invalid. - * - * workspace: Flag (nrow), Head (nrow+1), - * if symmetric: Iwork (2*nrow) - * if unsymmetric: Iwork (2*nrow+ncol). - * Unlike cholmod_resymbol, this routine does not allocate any temporary - * copies of its input matrix. - */ - -int CHOLMOD(resymbol_noperm) +// Redo symbolic LDL' or LL' factorization of I + F*F' or I+A, where F=A(:,f). +// +// L already exists, but is a superset of the true dynamic pattern (simple +// column downdates and row deletions haven't pruned anything). Just redo the +// symbolic factorization and drop entries that are no longer there. The +// diagonal is not modified. The number of nonzeros in column j of L +// (L->nz[j]) can decrease. The column pointers (L->p[j]) remain unchanged if +// pack is FALSE or if L is not monotonic. Otherwise, the columns of L are +// packed in place. +// +// For the symmetric case, the columns of the lower triangular part of A +// are accessed by column. NOTE that this the transpose of the general case. +// +// For the unsymmetric case, F=A(:,f) is accessed by column. +// +// A need not be sorted, and can be packed or unpacked. If L->Perm is not +// identity, then A must already be permuted according to the permutation used +// to factorize L. The advantage of using this routine is that it does not +// need to create permuted copies of A first. +// +// This routine can be called if L is only partially factored via cholmod_rowfac +// since all it does is prune. If an entry is in F*F' or A, but not in L, it +// isn't added to L. +// +// L must be simplicial LDL' or LL'; it cannot be supernodal or symbolic. +// +// The set f is held in fset and fsize. +// fset = NULL means ":" in MATLAB. fset is ignored. +// fset != NULL means f = fset [0..fset-1]. +// fset != NULL and fsize = 0 means f is the empty set. +// There can be no duplicates in fset. +// Common->status is set to CHOLMOD_INVALID if fset is invalid. +// +// workspace: Flag (nrow), Head (nrow+1), +// if symmetric: Iwork (2*nrow) +// if unsymmetric: Iwork (2*nrow+ncol). +// Unlike cholmod_resymbol, this routine does not allocate any temporary +// copies of its input matrix. + +int CHOLMOD(resymbol_noperm) // recompute symbolic pattern of L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) { - double *Lx, *Lz ; - Int i, j, k, row, parent, p, pend, pdest, ncol, apacked, sorted, nrow, nf, - use_fset, mark, jj, stype, xtype ; - Int *Ap, *Ai, *Anz, *Li, *Lp, *Lnz, *Flag, *Head, *Link, *Anext, *Iwork ; - size_t s ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; - ncol = A->ncol ; - nrow = A->nrow ; - stype = A->stype ; + Int ncol = A->ncol ; + Int nrow = A->nrow ; + Int stype = A->stype ; ASSERT (IMPLIES (stype != 0, nrow == ncol)) ; if (stype > 0) { - /* symmetric, with upper triangular part, not supported */ - ERROR (CHOLMOD_INVALID, "symmetric upper not supported ") ; - return (FALSE) ; + // symmetric, with upper triangular part, not supported + ERROR (CHOLMOD_INVALID, "symmetric upper not supported ") ; + return (FALSE) ; } if (L->is_super) { - /* cannot operate on a supernodal or symbolic factorization */ - ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; - return (FALSE) ; + // cannot operate on a supernodal or symbolic factorization + ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; + return (FALSE) ; } if (L->n != A->nrow) { - /* dimensions must agree */ - ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; - return (FALSE) ; + // dimensions must agree + ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 2*nrow + (stype ? 0 : ncol) */ - s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; + // s = nrow + (stype ? 0 : ncol) + size_t s = A->nrow ; + int ok = TRUE ; if (stype != 0) { - s = CHOLMOD(add_size_t) (s, ncol, &ok) ; + s = CHOLMOD(add_size_t) (s, A->ncol, &ok) ; } if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (nrow, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; /* out of memory */ + return (FALSE) ; // out of memory } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - Ai = A->i ; - Ap = A->p ; - Anz = A->nz ; - apacked = A->packed ; - sorted = A->sorted ; + Int *Ai = A->i ; + Int *Ap = A->p ; + Int *Anz = A->nz ; + bool apacked = A->packed ; + bool sorted = A->sorted ; - Li = L->i ; - Lx = L->x ; - Lz = L->z ; - Lp = L->p ; - Lnz = L->nz ; - xtype = L->xtype ; + Int *Lp = L->p ; - /* If L is monotonic on input, then it can be packed or - * unpacked on output, depending on the pack input parameter. */ + // If L is monotonic on input, then it can be packed or + // unpacked on output, depending on the pack input parameter. - /* cannot pack a non-monotonic matrix */ + // cannot pack a non-monotonic matrix if (!(L->is_monotonic)) { - pack = FALSE ; + pack = FALSE ; } ASSERT (L->nzmax >= (size_t) (Lp [L->n])) ; - pdest = 0 ; - PRINT1 (("\n\n===================== Resymbol pack %d Apacked %d\n", - pack, A->packed)) ; + pack, A->packed)) ; ASSERT (CHOLMOD(dump_sparse) (A, "ReSymbol A:", Common) >= 0) ; DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol initial L (i, x):", Common)) ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Flag = Common->Flag ; /* size nrow */ - Head = Common->Head ; /* size nrow+1 */ - Iwork = Common->Iwork ; - Link = Iwork ; /* size nrow (i/i/l) [ */ - Lnz = Iwork + nrow ; /* size nrow (i/i/l), if L not packed */ - Anext = Iwork + 2*((size_t) nrow) ; /* size ncol (i/i/l), unsym. only */ - for (j = 0 ; j < nrow ; j++) + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Int *Head = Common->Head ; // size nrow+1 + Int *Iwork = Common->Iwork ; + Int *Link = Iwork ; // size nrow [ + Int *Anext = Iwork + nrow ; // size ncol, unsym. only + for (Int j = 0 ; j < nrow ; j++) { - Link [j] = EMPTY ; + Link [j] = EMPTY ; } - /* use Lnz in L itself */ - Lnz = L->nz ; - ASSERT (Lnz != NULL) ; - - /* ---------------------------------------------------------------------- */ - /* for the unsymmetric case, queue each column of A (:,f) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // for the unsymmetric case, queue each column of A (:,f) + //-------------------------------------------------------------------------- - /* place each column of the basis set on the link list corresponding to */ - /* the smallest row index in that column */ + // place each column of the basis set on the link list corresponding to + // the smallest row index in that column if (stype == 0) { - use_fset = (fset != NULL) ; - if (use_fset) - { - nf = fsize ; - /* This is the only O(ncol) loop in cholmod_resymbol. - * It is required only to check the fset. */ - for (j = 0 ; j < ncol ; j++) - { - Anext [j] = -2 ; - } - for (jj = 0 ; jj < nf ; jj++) - { - j = fset [jj] ; - if (j < 0 || j > ncol || Anext [j] != -2) - { - /* out-of-range or duplicate entry in fset */ - ERROR (CHOLMOD_INVALID, "fset invalid") ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; - return (FALSE) ; - } - /* flag column j as having been seen */ - Anext [j] = EMPTY ; - } - /* the fset is now valid */ - ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; - } - else - { - nf = ncol ; - } - for (jj = 0 ; jj < nf ; jj++) - { - j = (use_fset) ? (fset [jj]) : jj ; - /* column j is the fset; find the smallest row (if any) */ - p = Ap [j] ; - pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; - if (pend > p) - { - k = Ai [p] ; - if (!sorted) - { - for ( ; p < pend ; p++) - { - k = MIN (k, Ai [p]) ; - } - } - /* place column j on link list k */ - ASSERT (k >= 0 && k < nrow) ; - Anext [j] = Head [k] ; - Head [k] = j ; - } - } + Int nf ; + bool use_fset = (fset != NULL) ; + if (use_fset) + { + nf = fsize ; + // This is the only O(ncol) loop in cholmod_resymbol. + // It is required only to check the fset. + for (Int j = 0 ; j < ncol ; j++) + { + Anext [j] = -2 ; + } + for (Int jj = 0 ; jj < nf ; jj++) + { + Int j = fset [jj] ; + if (j < 0 || j > ncol || Anext [j] != -2) + { + // out-of-range or duplicate entry in fset + ERROR (CHOLMOD_INVALID, "fset invalid") ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; + return (FALSE) ; + } + // flag column j as having been seen + Anext [j] = EMPTY ; + } + // the fset is now valid + ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; + } + else + { + nf = ncol ; + } + for (Int jj = 0 ; jj < nf ; jj++) + { + Int j = (use_fset) ? (fset [jj]) : jj ; + // column j is the fset; find the smallest row (if any) + Int p = Ap [j] ; + Int pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; + if (pend > p) + { + Int k = Ai [p] ; + if (!sorted) + { + for ( ; p < pend ; p++) + { + k = MIN (k, Ai [p]) ; + } + } + // place column j on link list k + ASSERT (k >= 0 && k < nrow) ; + Anext [j] = Head [k] ; + Head [k] = j ; + } + } } - /* ---------------------------------------------------------------------- */ - /* recompute symbolic LDL' factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // recompute symbolic LDL' factorization + //-------------------------------------------------------------------------- - for (k = 0 ; k < nrow ; k++) + switch ((L->xtype + L->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; -#ifndef NDEBUG - PRINT1 (("\n\n================== Initial column k = "ID"\n", k)) ; - for (p = Lp [k] ; p < Lp [k] + Lnz [k] ; p++) - { - PRINT1 ((" row: "ID" value: ", Li [p])) ; - PRINT1 (("\n")) ; - } - PRINT1 (("Recomputing LDL, column k = "ID"\n", k)) ; -#endif + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; - /* ------------------------------------------------------------------ */ - /* compute column k of I+F*F' or I+A */ - /* ------------------------------------------------------------------ */ - - /* flag the diagonal entry */ - /* mark = CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - - Flag [k] = mark ; - PRINT1 ((" row: "ID" (diagonal)\n", k)) ; - - if (stype != 0) - { - /* merge column k of A into Flag (lower triangular part only) */ - p = Ap [k] ; - pend = (apacked) ? (Ap [k+1]) : (p + Anz [k]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i > k) - { - Flag [i] = mark ; - } - } - } - else - { - /* for each column j whos first row index is in row k */ - for (j = Head [k] ; j != EMPTY ; j = Anext [j]) - { - /* merge column j of A into Flag */ - PRINT1 ((" ---- A column "ID"\n", j)) ; - p = Ap [j] ; - pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; - PRINT1 ((" length "ID" adding\n", pend-p)) ; - for ( ; p < pend ; p++) - { -#ifndef NDEBUG - ASSERT (Ai [p] >= k && Ai [p] < nrow) ; - if (Flag [Ai [p]] < mark) PRINT1 ((" row "ID"\n", Ai [p])) ; -#endif - Flag [Ai [p]] = mark ; - } - } - /* clear the kth link list */ - Head [k] = EMPTY ; - } - - /* ------------------------------------------------------------------ */ - /* compute pruned pattern of kth column of L = union of children */ - /* ------------------------------------------------------------------ */ - - /* for each column j of L whose parent is k */ - for (j = Link [k] ; j != EMPTY ; j = Link [j]) - { - /* merge column j of L into Flag */ - PRINT1 ((" ---- L column "ID"\n", k)) ; - ASSERT (j < k) ; - ASSERT (Lnz [j] > 0) ; - p = Lp [j] ; - pend = p + Lnz [j] ; - ASSERT (Li [p] == j && Li [p+1] == k) ; - p++ ; /* skip past the diagonal entry */ - for ( ; p < pend ; p++) - { - /* add to pattern */ - ASSERT (Li [p] >= k && Li [p] < nrow) ; - Flag [Li [p]] = mark ; - } - } - - /* ------------------------------------------------------------------ */ - /* prune the kth column of L */ - /* ------------------------------------------------------------------ */ - - PRINT1 (("Final column of L:\n")) ; - p = Lp [k] ; - pend = p + Lnz [k] ; - - if (pack) - { - /* shift column k upwards */ - Lp [k] = pdest ; - } - else - { - /* leave column k in place, just reduce Lnz [k] */ - pdest = p ; - } - - for ( ; p < pend ; p++) - { - ASSERT (pdest < pend) ; - ASSERT (pdest <= p) ; - row = Li [p] ; - ASSERT (row >= k && row < nrow) ; - if (Flag [row] == mark) - { - /* keep this entry */ - Li [pdest] = row ; - if (xtype == CHOLMOD_REAL) - { - Lx [pdest] = Lx [p] ; - } - else if (xtype == CHOLMOD_COMPLEX) - { - Lx [2*pdest ] = Lx [2*p ] ; - Lx [2*pdest+1] = Lx [2*p+1] ; - } - else if (xtype == CHOLMOD_ZOMPLEX) - { - Lx [pdest] = Lx [p] ; - Lz [pdest] = Lz [p] ; - } - pdest++ ; - } - } - - /* ------------------------------------------------------------------ */ - /* prepare this column for its parent */ - /* ------------------------------------------------------------------ */ - - Lnz [k] = pdest - Lp [k] ; - - PRINT1 ((" L("ID") length "ID"\n", k, Lnz [k])) ; - ASSERT (Lnz [k] > 0) ; - - /* parent is the first entry in the column after the diagonal */ - parent = (Lnz [k] > 1) ? (Li [Lp [k] + 1]) : EMPTY ; - - PRINT1 (("parent ("ID") = "ID"\n", k, parent)) ; - ASSERT ((parent > k && parent < nrow) || (parent == EMPTY)) ; - - if (parent != EMPTY) - { - Link [k] = Link [parent] ; - Link [parent] = k ; - } + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_resymbol_worker (A, pack, L, Common) ; + break ; } - /* done using Iwork for Link, Lnz (if needed), and Anext ] */ + // done using Iwork for Link and Anext ] - /* ---------------------------------------------------------------------- */ - /* convert L to packed, if requested */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert L to packed, if requested + //-------------------------------------------------------------------------- if (pack) { - /* finalize Lp */ - Lp [nrow] = pdest ; - /* Shrink L to be just large enough. It cannot fail. */ - /* workspace: none */ - ASSERT ((size_t) (Lp [nrow]) <= L->nzmax) ; - CHOLMOD(reallocate_factor) (Lp [nrow], L, Common) ; - ASSERT (Common->status >= CHOLMOD_OK) ; + // Shrink L to be just large enough. It cannot fail. + // workspace: none + ASSERT ((size_t) (Lp [nrow]) <= L->nzmax) ; + CHOLMOD(reallocate_factor) (Lp [nrow], L, Common) ; + ASSERT (Common->status >= CHOLMOD_OK) ; } - /* ---------------------------------------------------------------------- */ - /* clear workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear workspace and return result + //-------------------------------------------------------------------------- - /* CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol final L (i, x):", Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (TRUE) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_rowcolcounts.c b/CHOLMOD/Cholesky/cholmod_rowcolcounts.c index f98002ae56..fb1805705f 100644 --- a/CHOLMOD/Cholesky/cholmod_rowcolcounts.c +++ b/CHOLMOD/Cholesky/cholmod_rowcolcounts.c @@ -2,219 +2,214 @@ // CHOLMOD/Cholesky/cholmod_rowcolcounts: compute row/col counts of L //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Compute the row and column counts of the Cholesky factor L of the matrix - * A or A*A'. The etree and its postordering must already be computed (see - * cholmod_etree and cholmod_postorder) and given as inputs to this routine. - * - * For the symmetric case (LL'=A), A is accessed by column. Only the lower - * triangular part of A is used. Entries not in this part of the matrix are - * ignored. This is the same as storing the upper triangular part of A by - * rows, with entries in the lower triangular part being ignored. NOTE: this - * representation is the TRANSPOSE of the input to cholmod_etree. - * - * For the unsymmetric case (LL'=AA'), A is accessed by column. Equivalently, - * if A is viewed as a matrix in compressed-row form, this routine computes - * the row and column counts for L where LL'=A'A. If the input vector f is - * present, then F*F' is analyzed instead, where F = A(:,f). - * - * The set f is held in fset and fsize. - * fset = NULL means ":" in MATLAB. fset is ignored. - * fset != NULL means f = fset [0..fset-1]. - * fset != NULL and fsize = 0 means f is the empty set. - * Common->status is set to CHOLMOD_INVALID if fset is invalid. - * - * In both cases, the columns of A need not be sorted. - * A can be packed or unpacked. - * - * References: - * J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and - * column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis & - * Applic., vol 15, 1994, pp. 1075-1091. - * - * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for - * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. - * - * workspace: - * if symmetric: Flag (nrow), Iwork (2*nrow) - * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// Compute the row and column counts of the Cholesky factor L of the matrix +// A or A*A'. The etree and its postordering must already be computed (see +// cholmod_etree and cholmod_postorder) and given as inputs to this routine. +// +// For the symmetric case (LL'=A), A is accessed by column. Only the lower +// triangular part of A is used. Entries not in this part of the matrix are +// ignored. This is the same as storing the upper triangular part of A by +// rows, with entries in the lower triangular part being ignored. NOTE: this +// representation is the TRANSPOSE of the input to cholmod_etree. +// +// For the unsymmetric case (LL'=AA'), A is accessed by column. Equivalently, +// if A is viewed as a matrix in compressed-row form, this routine computes +// the row and column counts for L where LL'=A'A. If the input vector f is +// present, then F*F' is analyzed instead, where F = A(:,f). +// +// The set f is held in fset and fsize. +// fset = NULL means ":" in MATLAB. fset is ignored. +// fset != NULL means f = fset [0..fset-1]. +// fset != NULL and fsize = 0 means f is the empty set. +// Common->status is set to CHOLMOD_INVALID if fset is invalid. +// +// In both cases, the columns of A need not be sorted. +// A can be packed or unpacked. +// +// References: +// J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and +// column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis & +// Applic., vol 15, 1994, pp. 1075-1091. +// +// J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for +// sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. +// +// workspace: +// if symmetric: Flag (nrow), Iwork (2*nrow) +// if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === initialize_node ====================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// initialize_node +//------------------------------------------------------------------------------ -static Int initialize_node /* initial work for kth node in postordered etree */ +static Int initialize_node // initial work for kth node in postordered etree ( - Int k, /* at the kth step of the algorithm (and kth node) */ - Int Post [ ], /* Post [k] = i, the kth node in postordered etree */ - Int Parent [ ], /* Parent [i] is the parent of i in the etree */ - Int ColCount [ ], /* ColCount [c] is the current weight of node c */ - Int PrevNbr [ ] /* PrevNbr [u] = k if u was last considered at step k */ + Int k, // at the kth step of the algorithm (and kth node) + Int Post [ ], // Post [k] = i, the kth node in postordered etree + Int Parent [ ], // Parent [i] is the parent of i in the etree + Int ColCount [ ], // ColCount [c] is the current weight of node c + Int PrevNbr [ ] // PrevNbr [u] = k if u was last considered at step k ) { Int p, parent ; - /* determine p, the kth node in the postordered etree */ + // determine p, the kth node in the postordered etree p = Post [k] ; - /* adjust the weight if p is not a root of the etree */ + // adjust the weight if p is not a root of the etree parent = Parent [p] ; if (parent != EMPTY) { - ColCount [parent]-- ; + ColCount [parent]-- ; } - /* flag node p to exclude self edges (p,p) */ + // flag node p to exclude self edges (p,p) PrevNbr [p] = k ; return (p) ; } +//------------------------------------------------------------------------------ +// process_edge +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === process_edge ========================================================= */ -/* ========================================================================== */ - -/* edge (p,u) is being processed. p < u is a descendant of its ancestor u in - * the etree. node p is the kth node in the postordered etree. */ +// edge (p,u) is being processed. p < u is a descendant of its ancestor u in +// the etree. node p is the kth node in the postordered etree. static void process_edge ( - Int p, /* process edge (p,u) of the matrix */ + Int p, // process edge (p,u) of the matrix Int u, - Int k, /* we are at the kth node in the postordered etree */ - Int First [ ], /* First [i] = k if the postordering of first - * descendent of node i is k */ - Int PrevNbr [ ], /* u was last considered at step k = PrevNbr [u] */ - Int ColCount [ ], /* ColCount [c] is the current weight of node c */ - Int PrevLeaf [ ], /* s = PrevLeaf [u] means that s was the last leaf - * seen in the subtree rooted at u. */ - Int RowCount [ ], /* RowCount [i] is # of nonzeros in row i of L, - * including the diagonal. Not computed if NULL. */ - Int SetParent [ ], /* the FIND/UNION data structure, which forms a set - * of trees. A root i has i = SetParent [i]. Following - * a path from i to the root q of the subtree containing - * i means that q is the SetParent representative of i. - * All nodes in the tree could have their SetParent - * equal to the root q; the tree representation is used - * to save time. When a path is traced from i to its - * root q, the path is re-traversed to set the SetParent - * of the whole path to be the root q. */ - Int Level [ ] /* Level [i] = length of path from node i to root */ + Int k, // we are at the kth node in the postordered etree + Int First [ ], // First [i] = k if the postordering of first + // descendent of node i is k + Int PrevNbr [ ], // u was last considered at step k = PrevNbr [u] + Int ColCount [ ], // ColCount [c] is the current weight of node c + Int PrevLeaf [ ], // s = PrevLeaf [u] means that s was the last leaf + // seen in the subtree rooted at u. + Int RowCount [ ], // RowCount [i] is # of nonzeros in row i of L, + // including the diagonal. Not computed if NULL. + Int SetParent [ ], // the FIND/UNION data structure, which forms a set + // of trees. A root i has i = SetParent [i]. Following + // a path from i to the root q of the subtree containing + // i means that q is the SetParent representative of i. + // All nodes in the tree could have their SetParent + // equal to the root q; the tree representation is used + // to save time. When a path is traced from i to its + // root q, the path is re-traversed to set the SetParent + // of the whole path to be the root q. + Int Level [ ] // Level [i] = length of path from node i to root ) { + Int prevleaf, q, s, sparent ; if (First [p] > PrevNbr [u]) { - /* p is a leaf of the subtree of u */ - ColCount [p]++ ; - prevleaf = PrevLeaf [u] ; - if (prevleaf == EMPTY) - { - /* p is the first leaf of subtree of u; RowCount will be incremented - * by the length of the path in the etree from p up to u. */ - q = u ; - } - else - { - /* q = FIND (prevleaf): find the root q of the - * SetParent tree containing prevleaf */ - for (q = prevleaf ; q != SetParent [q] ; q = SetParent [q]) - { - ; - } - /* the root q has been found; re-traverse the path and - * perform path compression */ - s = prevleaf ; - for (s = prevleaf ; s != q ; s = sparent) - { - sparent = SetParent [s] ; - SetParent [s] = q ; - } - /* adjust the RowCount and ColCount; RowCount will be incremented by - * the length of the path from p to the SetParent root q, and - * decrement the ColCount of q by one. */ - ColCount [q]-- ; - } - if (RowCount != NULL) - { - /* if RowCount is being computed, increment it by the length of - * the path from p to q */ - RowCount [u] += (Level [p] - Level [q]) ; - } - /* p is a leaf of the subtree of u, so mark PrevLeaf [u] to be p */ - PrevLeaf [u] = p ; + // p is a leaf of the subtree of u + ColCount [p]++ ; + prevleaf = PrevLeaf [u] ; + if (prevleaf == EMPTY) + { + // p is the first leaf of subtree of u; RowCount will be incremented + // by the length of the path in the etree from p up to u. + q = u ; + } + else + { + // q = FIND (prevleaf): find the root q of the + // SetParent tree containing prevleaf + for (q = prevleaf ; q != SetParent [q] ; q = SetParent [q]) + { + ; + } + // the root q has been found; re-traverse the path and + // perform path compression + s = prevleaf ; + for (s = prevleaf ; s != q ; s = sparent) + { + sparent = SetParent [s] ; + SetParent [s] = q ; + } + // adjust the RowCount and ColCount; RowCount will be incremented by + // the length of the path from p to the SetParent root q, and + // decrement the ColCount of q by one. + ColCount [q]-- ; + } + if (RowCount != NULL) + { + // if RowCount is being computed, increment it by the length of + // the path from p to q + RowCount [u] += (Level [p] - Level [q]) ; + } + // p is a leaf of the subtree of u, so mark PrevLeaf [u] to be p + PrevLeaf [u] = p ; } - /* flag u has having been processed at step k */ + // flag u has having been processed at step k PrevNbr [u] = k ; } +//------------------------------------------------------------------------------ +// finalize_node +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === finalize_node ======================================================== */ -/* ========================================================================== */ - -static void finalize_node /* compute UNION (p, Parent [p]) */ +static void finalize_node // compute UNION (p, Parent [p]) ( Int p, - Int Parent [ ], /* Parent [p] is the parent of p in the etree */ - Int SetParent [ ] /* see process_edge, above */ + Int Parent [ ], // Parent [p] is the parent of p in the etree + Int SetParent [ ] // see process_edge, above ) { - /* all nodes in the SetParent tree rooted at p now have as their final - * root the node Parent [p]. This computes UNION (p, Parent [p]) */ + // all nodes in the SetParent tree rooted at p now have as their final + // root the node Parent [p]. This computes UNION (p, Parent [p]) if (Parent [p] != EMPTY) { - SetParent [p] = Parent [p] ; + SetParent [p] = Parent [p] ; } } - -/* ========================================================================== */ -/* === cholmod_rowcolcounts ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_rowcolcounts +//------------------------------------------------------------------------------ int CHOLMOD(rowcolcounts) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - Int *Parent, /* size nrow. Parent [i] = p if p is the parent of i */ - Int *Post, /* size nrow. Post [k] = i if i is the kth node in - * the postordered etree. */ - /* ---- output --- */ - Int *RowCount, /* size nrow. RowCount [i] = # entries in the ith row of - * L, including the diagonal. */ - Int *ColCount, /* size nrow. ColCount [i] = # entries in the ith - * column of L, including the diagonal. */ - Int *First, /* size nrow. First [i] = k is the least postordering - * of any descendant of i. */ - Int *Level, /* size nrow. Level [i] is the length of the path from - * i to the root, with Level [root] = 0. */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + Int *Parent, // size nrow. Parent [i] = p if p is the parent of i + Int *Post, // size nrow. Post [k] = i if i is the kth node in + // the postordered etree. + // output: + Int *RowCount, // size nrow. RowCount [i] = # entries in the ith + // row of L, including the diagonal. + Int *ColCount, // size nrow. ColCount [i] = # entries in the ith + // column of L, including the diagonal. + Int *First, // size nrow. First [i] = k is the least + // postordering of any descendant of i. + Int *Level, // size nrow. Level [i] is the length of the path + // from i to the root, with Level [root] = 0. cholmod_common *Common ) { + double fl, ff ; Int *Ap, *Ai, *Anz, *PrevNbr, *SetParent, *Head, *PrevLeaf, *Anext, *Ipost, - *Iwork ; + *Iwork ; Int i, j, r, k, len, s, p, pend, inew, stype, nf, anz, inode, parent, - nrow, ncol, packed, use_fset, jj ; - size_t w ; - int ok = TRUE ; + nrow, ncol, packed, use_fset, jj ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -227,303 +222,303 @@ int CHOLMOD(rowcolcounts) stype = A->stype ; if (stype > 0) { - /* symmetric with upper triangular part not supported */ - ERROR (CHOLMOD_INVALID, "symmetric upper not supported") ; - return (FALSE) ; + // symmetric with upper triangular part not supported + ERROR (CHOLMOD_INVALID, "symmetric upper not supported") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - nrow = A->nrow ; /* the number of rows of A */ - ncol = A->ncol ; /* the number of columns of A */ + nrow = A->nrow ; // the number of rows of A + ncol = A->ncol ; // the number of columns of A - /* w = 2*nrow + (stype ? 0 : ncol) */ - w = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; - w = CHOLMOD(add_size_t) (w, (stype ? 0 : ncol), &ok) ; + // w = 2*nrow + (stype ? 0 : ncol) + int ok = TRUE ; + size_t w = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ; + w = CHOLMOD(add_size_t) (w, (stype ? 0 : A->ncol), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } CHOLMOD(allocate_work) (nrow, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } ASSERT (CHOLMOD(dump_perm) (Post, nrow, nrow, "Post", Common)) ; ASSERT (CHOLMOD(dump_parent) (Parent, nrow, "Parent", Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - Ap = A->p ; /* size ncol+1, column pointers for A */ - Ai = A->i ; /* the row indices of A, of size nz=Ap[ncol+1] */ + Ap = A->p ; // size ncol+1, column pointers for A + Ai = A->i ; // the row indices of A, of size nz=Ap[ncol+1] Anz = A->nz ; packed = A->packed ; ASSERT (IMPLIES (!packed, Anz != NULL)) ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- Iwork = Common->Iwork ; - SetParent = Iwork ; /* size nrow (i/i/l) */ - PrevNbr = Iwork + nrow ; /* size nrow (i/i/l) */ - Anext = Iwork + 2*((size_t) nrow) ; /* size ncol (i/i/l) (unsym only) */ - PrevLeaf = Common->Flag ; /* size nrow */ - Head = Common->Head ; /* size nrow+1 (unsym only)*/ + SetParent = Iwork ; // size nrow + PrevNbr = Iwork + nrow ; // size nrow + Anext = Iwork + 2*((size_t) nrow) ; // size ncol (unsym only) + PrevLeaf = Common->Flag ; // size nrow + Head = Common->Head ; // size nrow+1 (unsym only) - /* ---------------------------------------------------------------------- */ - /* find the first descendant and level of each node in the tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the first descendant and level of each node in the tree + //-------------------------------------------------------------------------- - /* First [i] = k if the postordering of first descendent of node i is k */ - /* Level [i] = length of path from node i to the root (Level [root] = 0) */ + // First [i] = k if the postordering of first descendent of node i is k + // Level [i] = length of path from node i to the root (Level [root] = 0) for (i = 0 ; i < nrow ; i++) { - First [i] = EMPTY ; + First [i] = EMPTY ; } - /* postorder traversal of the etree */ + // postorder traversal of the etree for (k = 0 ; k < nrow ; k++) { - /* node i of the etree is the kth node in the postordered etree */ - i = Post [k] ; - - /* i is a leaf if First [i] is still EMPTY */ - /* ColCount [i] starts at 1 if i is a leaf, zero otherwise */ - ColCount [i] = (First [i] == EMPTY) ? 1 : 0 ; - - /* traverse the path from node i to the root, stopping if we find a - * node r whose First [r] is already defined. */ - len = 0 ; - for (r = i ; (r != EMPTY) && (First [r] == EMPTY) ; r = Parent [r]) - { - First [r] = k ; - len++ ; - } - if (r == EMPTY) - { - /* we hit a root node, the level of which is zero */ - len-- ; - } - else - { - /* we stopped at node r, where Level [r] is already defined */ - len += Level [r] ; - } - /* re-traverse the path from node i to r; set the level of each node */ - for (s = i ; s != r ; s = Parent [s]) - { - Level [s] = len-- ; - } + // node i of the etree is the kth node in the postordered etree + i = Post [k] ; + + // i is a leaf if First [i] is still EMPTY + // ColCount [i] starts at 1 if i is a leaf, zero otherwise + ColCount [i] = (First [i] == EMPTY) ? 1 : 0 ; + + // traverse the path from node i to the root, stopping if we find a + // node r whose First [r] is already defined. + len = 0 ; + for (r = i ; (r != EMPTY) && (First [r] == EMPTY) ; r = Parent [r]) + { + First [r] = k ; + len++ ; + } + if (r == EMPTY) + { + // we hit a root node, the level of which is zero + len-- ; + } + else + { + // we stopped at node r, where Level [r] is already defined + len += Level [r] ; + } + // re-traverse the path from node i to r; set the level of each node + for (s = i ; s != r ; s = Parent [s]) + { + Level [s] = len-- ; + } } - /* ---------------------------------------------------------------------- */ - /* AA' case: sort columns of A according to first postordered row index */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // AA' case: sort columns of A according to first postordered row index + //-------------------------------------------------------------------------- fl = 0.0 ; if (stype == 0) { - /* [ use PrevNbr [0..nrow-1] as workspace for Ipost */ - Ipost = PrevNbr ; - /* Ipost [i] = k if i is the kth node in the postordered etree. */ - for (k = 0 ; k < nrow ; k++) - { - Ipost [Post [k]] = k ; - } - use_fset = (fset != NULL) ; - if (use_fset) - { - nf = fsize ; - /* clear Anext to check fset */ - for (j = 0 ; j < ncol ; j++) - { - Anext [j] = -2 ; - } - /* find the first postordered row in each column of A (post,f) - * and place the column in the corresponding link list */ - for (jj = 0 ; jj < nf ; jj++) - { - j = fset [jj] ; - if (j < 0 || j > ncol || Anext [j] != -2) - { - /* out-of-range or duplicate entry in fset */ - ERROR (CHOLMOD_INVALID, "fset invalid") ; - return (FALSE) ; - } - /* flag column j as having been seen */ - Anext [j] = EMPTY ; - } - /* fset is now valid */ - ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; - } - else - { - nf = ncol ; - } - for (jj = 0 ; jj < nf ; jj++) - { - j = (use_fset) ? (fset [jj]) : jj ; - /* column j is in the fset; find the smallest row (if any) */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - ff = (double) MAX (0, pend - p) ; - fl += ff*ff + ff ; - if (pend > p) - { - k = Ipost [Ai [p]] ; - for ( ; p < pend ; p++) - { - inew = Ipost [Ai [p]] ; - k = MIN (k, inew) ; - } - /* place column j in link list k */ - ASSERT (k >= 0 && k < nrow) ; - Anext [j] = Head [k] ; - Head [k] = j ; - } - } - /* Ipost no longer needed for inverse postordering ] - * Head [k] contains a link list of all columns whose first - * postordered row index is equal to k, for k = 0 to nrow-1. */ + // [ use PrevNbr [0..nrow-1] as workspace for Ipost + Ipost = PrevNbr ; + // Ipost [i] = k if i is the kth node in the postordered etree. + for (k = 0 ; k < nrow ; k++) + { + Ipost [Post [k]] = k ; + } + use_fset = (fset != NULL) ; + if (use_fset) + { + nf = fsize ; + // clear Anext to check fset + for (j = 0 ; j < ncol ; j++) + { + Anext [j] = -2 ; + } + // find the first postordered row in each column of A (post,f) + // and place the column in the corresponding link list + for (jj = 0 ; jj < nf ; jj++) + { + j = fset [jj] ; + if (j < 0 || j > ncol || Anext [j] != -2) + { + // out-of-range or duplicate entry in fset + ERROR (CHOLMOD_INVALID, "fset invalid") ; + return (FALSE) ; + } + // flag column j as having been seen + Anext [j] = EMPTY ; + } + // fset is now valid + ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; + } + else + { + nf = ncol ; + } + for (jj = 0 ; jj < nf ; jj++) + { + j = (use_fset) ? (fset [jj]) : jj ; + // column j is in the fset; find the smallest row (if any) + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + ff = (double) MAX (0, pend - p) ; + fl += ff*ff + ff ; + if (pend > p) + { + k = Ipost [Ai [p]] ; + for ( ; p < pend ; p++) + { + inew = Ipost [Ai [p]] ; + k = MIN (k, inew) ; + } + // place column j in link list k + ASSERT (k >= 0 && k < nrow) ; + Anext [j] = Head [k] ; + Head [k] = j ; + } + } + // Ipost no longer needed for inverse postordering ] + // Head [k] contains a link list of all columns whose first + // postordered row index is equal to k, for k = 0 to nrow-1. } - /* ---------------------------------------------------------------------- */ - /* compute the row counts and node weights */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the row counts and node weights + //-------------------------------------------------------------------------- if (RowCount != NULL) { - for (i = 0 ; i < nrow ; i++) - { - RowCount [i] = 1 ; - } + for (i = 0 ; i < nrow ; i++) + { + RowCount [i] = 1 ; + } } for (i = 0 ; i < nrow ; i++) { - PrevLeaf [i] = EMPTY ; - PrevNbr [i] = EMPTY ; - SetParent [i] = i ; /* every node is in its own set, by itself */ + PrevLeaf [i] = EMPTY ; + PrevNbr [i] = EMPTY ; + SetParent [i] = i ; // every node is in its own set, by itself } if (stype != 0) { - /* ------------------------------------------------------------------ */ - /* symmetric case: LL' = A */ - /* ------------------------------------------------------------------ */ - - /* also determine the number of entries in triu(A) */ - anz = nrow ; - for (k = 0 ; k < nrow ; k++) - { - /* j is the kth node in the postordered etree */ - j = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; - - /* for all nonzeros A(i,j) below the diagonal, in column j of A */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i > j) - { - /* j is a descendant of i in etree(A) */ - anz++ ; - process_edge (j, i, k, First, PrevNbr, ColCount, - PrevLeaf, RowCount, SetParent, Level) ; - } - } - /* update SetParent: UNION (j, Parent [j]) */ - finalize_node (j, Parent, SetParent) ; - } - Common->anz = anz ; + //---------------------------------------------------------------------- + // symmetric case: LL' = A + //---------------------------------------------------------------------- + + // also determine the number of entries in triu(A) + anz = nrow ; + for (k = 0 ; k < nrow ; k++) + { + // j is the kth node in the postordered etree + j = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; + + // for all nonzeros A(i,j) below the diagonal, in column j of A + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + if (i > j) + { + // j is a descendant of i in etree(A) + anz++ ; + process_edge (j, i, k, First, PrevNbr, ColCount, + PrevLeaf, RowCount, SetParent, Level) ; + } + } + // update SetParent: UNION (j, Parent [j]) + finalize_node (j, Parent, SetParent) ; + } + Common->anz = anz ; } else { - /* ------------------------------------------------------------------ */ - /* unsymmetric case: LL' = AA' */ - /* ------------------------------------------------------------------ */ - - for (k = 0 ; k < nrow ; k++) - { - /* inode is the kth node in the postordered etree */ - inode = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; - - /* for all cols j whose first postordered row is k: */ - for (j = Head [k] ; j != EMPTY ; j = Anext [j]) - { - /* k is the first postordered row in column j of A */ - /* for all rows i in column j: */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* has i already been considered at this step k */ - if (PrevNbr [i] < k) - { - /* inode is a descendant of i in etree(AA') */ - /* process edge (inode,i) and set PrevNbr[i] to k */ - process_edge (inode, i, k, First, PrevNbr, ColCount, - PrevLeaf, RowCount, SetParent, Level) ; - } - } - } - /* clear link list k */ - Head [k] = EMPTY ; - /* update SetParent: UNION (inode, Parent [inode]) */ - finalize_node (inode, Parent, SetParent) ; - } + //---------------------------------------------------------------------- + // unsymmetric case: LL' = AA' + //---------------------------------------------------------------------- + + for (k = 0 ; k < nrow ; k++) + { + // inode is the kth node in the postordered etree + inode = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; + + // for all cols j whose first postordered row is k: + for (j = Head [k] ; j != EMPTY ; j = Anext [j]) + { + // k is the first postordered row in column j of A + // for all rows i in column j: + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + // has i already been considered at this step k + if (PrevNbr [i] < k) + { + // inode is a descendant of i in etree(AA') + // process edge (inode,i) and set PrevNbr[i] to k + process_edge (inode, i, k, First, PrevNbr, ColCount, + PrevLeaf, RowCount, SetParent, Level) ; + } + } + } + // clear link list k + Head [k] = EMPTY ; + // update SetParent: UNION (inode, Parent [inode]) + finalize_node (inode, Parent, SetParent) ; + } } - /* ---------------------------------------------------------------------- */ - /* finish computing the column counts */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // finish computing the column counts + //-------------------------------------------------------------------------- for (j = 0 ; j < nrow ; j++) { - parent = Parent [j] ; - if (parent != EMPTY) - { - /* add the ColCount of j to its parent */ - ColCount [parent] += ColCount [j] ; - } + parent = Parent [j] ; + if (parent != EMPTY) + { + // add the ColCount of j to its parent + ColCount [parent] += ColCount [j] ; + } } - /* ---------------------------------------------------------------------- */ - /* clear workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear workspace + //-------------------------------------------------------------------------- Common->mark = EMPTY ; - /* CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* flop count and nnz(L) for subsequent LL' numerical factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // flop count and nnz(L) for subsequent LL' numerical factorization + //-------------------------------------------------------------------------- - /* use double to avoid integer overflow. lnz cannot be NaN. */ + // use double to avoid integer overflow. lnz cannot be NaN. Common->aatfl = fl ; Common->lnz = 0. ; fl = 0 ; for (j = 0 ; j < nrow ; j++) { - ff = (double) (ColCount [j]) ; - Common->lnz += ff ; - fl += ff*ff ; + ff = (double) (ColCount [j]) ; + Common->lnz += ff ; + fl += ff*ff ; } Common->fl = fl ; diff --git a/CHOLMOD/Cholesky/cholmod_rowfac.c b/CHOLMOD/Cholesky/cholmod_rowfac.c index 079d2c6860..86ad015c3d 100644 --- a/CHOLMOD/Cholesky/cholmod_rowfac.c +++ b/CHOLMOD/Cholesky/cholmod_rowfac.c @@ -2,222 +2,239 @@ // CHOLMOD/Cholesky/cholmod_rowfac: row-wise numerical LDL' or LL' factorization //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Full or incremental numerical LDL' or LL' factorization (simplicial, not - * supernodal) cholmod_factorize is the "easy" wrapper for this code, but it - * does not provide access to incremental factorization. - * - * cholmod_rowfac computes the full or incremental LDL' or LL' factorization of - * A+beta*I (where A is symmetric) or A*F+beta*I (where A and F are unsymmetric - * and only the upper triangular part of A*F+beta*I is used). It computes - * L (and D, for LDL') one row at a time. beta is real. - * - * A is nrow-by-ncol or nrow-by-nrow. In "packed" form it is a conventional - * column-oriented sparse matrix. Row indices of column j are in - * Ai [Ap [j] ... Ap [j+1]-1] and values in the same locations of Ax. - * will be faster if A has sorted columns. In "unpacked" form the column - * of A ends at Ap [j] + Anz [j] - 1 instead of Ap [j+1] - 1. - * - * Row indices in each column of A can be sorted or unsorted, but the routine - * routine works fastest if A is sorted, or if only triu(A) is provided - * for the symmetric case. - * - * The unit-diagonal nrow-by-nrow output matrix L is returned in "unpacked" - * column form, with row indices of column j in Li [Lp [j] ... - * Lp [j] + Lnz [j] - 1] and values in the same location in Lx. The row - * indices in each column of L are in sorted order. The unit diagonal of L - * is not stored. - * - * L can be a simplicial symbolic or numeric (L->is_super must be FALSE). - * A symbolic factor is converted immediately into a numeric factor containing - * the identity matrix. - * - * For a full factorization, kstart = 0 and kend = nrow. The existing nonzero - * entries (numerical values in L->x and L->z for the zomplex case, and indices - * in L->i), if any, are overwritten. - * - * To compute an incremental factorization, select kstart and kend as the range - * of rows of L you wish to compute. A correct factorization will be computed - * only if all descendants of all nodes k = kstart to kend-1 in the etree have - * been factorized by a prior call to this routine, and if rows kstart to kend-1 - * have not been factorized. This condition is NOT checked on input. - * - * --------------- - * Symmetric case: - * --------------- - * - * The factorization (in MATLAB notation) is: - * - * S = beta*I + A - * S = triu (S) + triu (S,1)' - * L*D*L' = S, or L*L' = S - * - * A is a conventional sparse matrix in compressed column form. Only the - * diagonal and upper triangular part of A is accessed; the lower - * triangular part is ignored and assumed to be equal to the upper - * triangular part. For an incremental factorization, only columns kstart - * to kend-1 of A are accessed. F is not used. - * - * --------------- - * Unsymmetric case: - * --------------- - * - * The factorization (in MATLAB notation) is: - * - * S = beta*I + A*F - * S = triu (S) + triu (S,1)' - * L*D*L' = S, or L*L' = S - * - * The typical case is F=A'. Alternatively, if F=A(:,f)', then this - * routine factorizes S = beta*I + A(:,f)*A(:,f)'. - * - * All of A and F are accessed, but only the upper triangular part of A*F - * is used. F must be of size A->ncol by A->nrow. F is used for the - * unsymmetric case only. F can be packed or unpacked and it need not be - * sorted. - * - * For a complete factorization of beta*I + A*A', - * this routine performs a number of flops exactly equal to: - * - * sum (for each column j of A) of (Anz (j)^2 + Anz (j)), to form S - * + - * sum (for each column j of L) of (Lnz (j)^2 + 3*Lnz (j)), to factorize S - * - * where Anz (j) is the number of nonzeros in column j of A, and Lnz (j) - * is the number of nonzero in column j of L below the diagonal. - * - * - * workspace: Flag (nrow), W (nrow if real, 2*nrow if complex/zomplex), - * Iwork (nrow) - * - * Supports any xtype, except a pattern-only input matrix A cannot be - * factorized. - */ +// Full or incremental numerical LDL' or LL' factorization (simplicial, not +// supernodal) cholmod_factorize is the "easy" wrapper for this code, but it +// does not provide access to incremental factorization. +// +// cholmod_rowfac computes the full or incremental LDL' or LL' factorization of +// A+beta*I (where A is symmetric) or A*F+beta*I (where A and F are unsymmetric +// and only the upper triangular part of A*F+beta*I is used). It computes +// L (and D, for LDL') one row at a time. beta is real. +// +// A is nrow-by-ncol or nrow-by-nrow. In "packed" form it is a conventional +// column-oriented sparse matrix. Row indices of column j are in +// Ai [Ap [j] ... Ap [j+1]-1] and values in the same locations of Ax. +// will be faster if A has sorted columns. In "unpacked" form the column +// of A ends at Ap [j] + Anz [j] - 1 instead of Ap [j+1] - 1. +// +// Row indices in each column of A can be sorted or unsorted, but the routine +// routine works fastest if A is sorted, or if only triu(A) is provided +// for the symmetric case. +// +// The unit-diagonal nrow-by-nrow output matrix L is returned in "unpacked" +// column form, with row indices of column j in Li [Lp [j] ... +// Lp [j] + Lnz [j] - 1] and values in the same location in Lx. The row +// indices in each column of L are in sorted order. The unit diagonal of L +// is not stored. +// +// L can be a simplicial symbolic or numeric (L->is_super must be FALSE). +// A symbolic factor is converted immediately into a numeric factor containing +// the identity matrix. +// +// For a full factorization, kstart = 0 and kend = nrow. The existing nonzero +// entries (numerical values in L->x and L->z for the zomplex case, and indices +// in L->i), if any, are overwritten. +// +// To compute an incremental factorization, select kstart and kend as the range +// of rows of L you wish to compute. A correct factorization will be computed +// only if all descendants of all nodes k = kstart to kend-1 in the etree have +// been factorized by a prior call to this routine, and if rows kstart to kend-1 +// have not been factorized. This condition is NOT checked on input. +// +// --------------- +// Symmetric case: +// --------------- +// +// The factorization (in MATLAB notation) is: +// +// S = beta*I + A +// S = triu (S) + triu (S,1)' +// L*D*L' = S, or L*L' = S +// +// A is a conventional sparse matrix in compressed column form. Only the +// diagonal and upper triangular part of A is accessed; the lower +// triangular part is ignored and assumed to be equal to the upper +// triangular part. For an incremental factorization, only columns kstart +// to kend-1 of A are accessed. F is not used. +// +// --------------- +// Unsymmetric case: +// --------------- +// +// The factorization (in MATLAB notation) is: +// +// S = beta*I + A*F +// S = triu (S) + triu (S,1)' +// L*D*L' = S, or L*L' = S +// +// The typical case is F=A'. Alternatively, if F=A(:,f)', then this +// routine factorizes S = beta*I + A(:,f)*A(:,f)'. +// +// All of A and F are accessed, but only the upper triangular part of A*F +// is used. F must be of size A->ncol by A->nrow. F is used for the +// unsymmetric case only. F can be packed or unpacked and it need not be +// sorted. +// +// For a complete factorization of beta*I + A*A', +// this routine performs a number of flops exactly equal to: +// +// sum (for each column j of A) of (Anz (j)^2 + Anz (j)), to form S +// + +// sum (for each column j of L) of (Lnz (j)^2 + 3*Lnz (j)), to factorize S +// +// where Anz (j) is the number of nonzeros in column j of A, and Lnz (j) +// is the number of nonzero in column j of L below the diagonal. +// +// +// workspace: Flag (nrow), W (nrow if real, 2*nrow if complex/zomplex), +// Iwork (nrow) +// +// Supports any xtype and dtype, except a pattern-only input matrix A cannot be +// factorized. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === subtree ============================================================== */ -/* ========================================================================== */ - -/* Compute the nonzero pattern of the sparse triangular solve Lx=b, where L in - * this case is L(0:k-1,0:k-1), and b is a column of A. This is done by - * traversing the kth row-subtree of the elimination tree of L, starting from - * each nonzero entry in b. The pattern is returned postordered, and is valid - * for a subsequent numerical triangular solve of Lx=b. The elimination tree - * can be provided in a Parent array, or extracted from the pattern of L itself. - * - * The pattern of x = inv(L)*b is returned in Stack [top...]. - * Also scatters b, or a multiple of b, into the work vector W. - * - * The SCATTER macro is defines how the numerical values of A or A*A' are to be - * scattered. - * - * PARENT(i) is a macro the defines how the etree is accessed. It is either: - * #define PARENT(i) Parent [i] - * #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY - */ - -#define SUBTREE \ - for ( ; p < pend ; p++) \ - { \ - i = Ai [p] ; \ - if (i <= k) \ - { \ - /* scatter the column of A, or A*A' into Wx and Wz */ \ - SCATTER ; \ - /* start at node i and traverse up the subtree, stop at node k */ \ - for (len = 0 ; i < k && i != EMPTY && Flag [i] < mark ; i = parent) \ - { \ - /* L(k,i) is nonzero, and seen for the first time */ \ - Stack [len++] = i ; /* place i on the stack */ \ - Flag [i] = mark ; /* mark i as visited */ \ - parent = PARENT (i) ; /* traverse up the etree to the parent */ \ - } \ - /* move the path down to the bottom of the stack */ \ - while (len > 0) \ - { \ - Stack [--top] = Stack [--len] ; \ - } \ - } \ - else if (sorted) \ - { \ - break ; \ - } \ - } +//------------------------------------------------------------------------------ +// subtree +//------------------------------------------------------------------------------ + +// Compute the nonzero pattern of the sparse triangular solve Lx=b, where L in +// this case is L(0:k-1,0:k-1), and b is a column of A. This is done by +// traversing the kth row-subtree of the elimination tree of L, starting from +// each nonzero entry in b. The pattern is returned postordered, and is valid +// for a subsequent numerical triangular solve of Lx=b. The elimination tree +// can be provided in a Parent array, or extracted from the pattern of L itself. +// +// The pattern of x = inv(L)*b is returned in Stack [top...]. +// Also scatters b, or a multiple of b, into the work vector W. +// +// The SCATTER macro is defines how the numerical values of A or A*A' are to be +// scattered. +// +// PARENT(i) is a macro the defines how the etree is accessed. It is either: +// #define PARENT(i) Parent [i] +// #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY +// + +#define SUBTREE \ +for ( ; p < pend ; p++) \ +{ \ + i = Ai [p] ; \ + if (i <= k) \ + { \ + /* scatter the column of A, or A*A' into Wx and Wz */ \ + SCATTER ; \ + /* start at node i and traverse up the subtree, stop at node k */ \ + for (len = 0 ; i < k && i != EMPTY && Flag [i] < mark ; i = parent) \ + { \ + /* L(k,i) is nonzero, and seen for the first time */ \ + Stack [len++] = i ; /* place i on the stack */ \ + Flag [i] = mark ; /* mark i as visited */ \ + parent = PARENT (i) ; /* traverse up the etree to parent */ \ + } \ + /* move the path down to the bottom of the stack */ \ + while (len > 0) \ + { \ + Stack [--top] = Stack [--len] ; \ + } \ + } \ + else if (sorted) \ + { \ + break ; \ + } \ +} + +//------------------------------------------------------------------------------ +// t_cholmod_rowfac template +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_rowfac_worker.c" +#define COMPLEX +#include "t_cholmod_rowfac_worker.c" +#define ZOMPLEX +#include "t_cholmod_rowfac_worker.c" + +#define MASK +#define REAL +#include "t_cholmod_rowfac_worker.c" +#define COMPLEX +#include "t_cholmod_rowfac_worker.c" +#define ZOMPLEX +#include "t_cholmod_rowfac_worker.c" +#undef MASK -/* ========================================================================== */ -/* === TEMPLATE ============================================================= */ -/* ========================================================================== */ +#undef DOUBLE +#define SINGLE #define REAL -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #define COMPLEX -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #define ZOMPLEX -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #define MASK #define REAL -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #define COMPLEX -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #define ZOMPLEX -#include "t_cholmod_rowfac.c" +#include "t_cholmod_rowfac_worker.c" #undef MASK +//------------------------------------------------------------------------------ +// cholmod_row_subtree +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_row_subtree ================================================== */ -/* ========================================================================== */ - -/* Compute the nonzero pattern of the solution to the lower triangular system - * L(0:k-1,0:k-1) * x = A (0:k-1,k) if A is symmetric, or - * L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' if A is unsymmetric. - * This gives the nonzero pattern of row k of L (excluding the diagonal). - * The pattern is returned postordered. - * - * The symmetric case requires A to be in symmetric-upper form. - * - * The result is returned in R, a pre-allocated sparse matrix of size nrow-by-1, - * with R->nzmax >= nrow. R is assumed to be packed (Rnz [0] is not updated); - * the number of entries in R is given by Rp [0]. - * - * FUTURE WORK: a very minor change to this routine could allow it to compute - * the nonzero pattern of x for any system Lx=b. The SUBTREE macro would need - * to change, to eliminate its dependence on k. - * - * workspace: Flag (nrow) - */ +// Compute the nonzero pattern of the solution to the lower triangular system +// L(0:k-1,0:k-1) * x = A (0:k-1,k) if A is symmetric, or +// L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' if A is unsymmetric. +// This gives the nonzero pattern of row k of L (excluding the diagonal). +// The pattern is returned postordered. +// +// The symmetric case requires A to be in symmetric-upper form. +// +// The result is returned in R, a pre-allocated sparse matrix of size nrow-by-1, +// with R->nzmax >= nrow. R is assumed to be packed (Rnz [0] is not updated); +// the number of entries in R is given by Rp [0]. +// +// FUTURE WORK: a very minor change to this routine could allow it to compute +// the nonzero pattern of x for any system Lx=b. The SUBTREE macro would need +// to change, to eliminate its dependence on k. +// +// workspace: Flag (nrow) int CHOLMOD(row_subtree) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ - size_t krow, /* row k of L */ - Int *Parent, /* elimination tree */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + size_t krow, // row k of L + Int *Parent, // elimination tree + // output: + cholmod_sparse *R, // pattern of L(k,:), 1-by-n with R->nzmax >= n cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Fp, *Fi, *Fnz ; Int p, pend, parent, t, stype, nrow, k, pf, pfend, Fpacked, packed, - sorted, top, len, i, mark ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + sorted, top, len, i, mark ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -228,58 +245,58 @@ int CHOLMOD(row_subtree) stype = A->stype ; if (stype == 0) { - RETURN_IF_NULL (F, FALSE) ; - RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; + RETURN_IF_NULL (F, FALSE) ; + RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; } if (krow >= A->nrow) { - ERROR (CHOLMOD_INVALID, "subtree: k invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "subtree: k invalid") ; + return (FALSE) ; } if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax) { - ERROR (CHOLMOD_INVALID, "subtree: R invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "subtree: R invalid") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- nrow = A->nrow ; CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (stype > 0) { - /* symmetric upper case: F is not needed. It may be NULL */ - Fp = NULL ; - Fi = NULL ; - Fnz = NULL ; - Fpacked = TRUE ; + // symmetric upper case: F is not needed. It may be NULL + Fp = NULL ; + Fi = NULL ; + Fnz = NULL ; + Fpacked = TRUE ; } else if (stype == 0) { - /* unsymmetric case: F is required. */ - Fp = F->p ; - Fi = F->i ; - Fnz = F->nz ; - Fpacked = F->packed ; + // unsymmetric case: F is required. + Fp = F->p ; + Fi = F->i ; + Fnz = F->nz ; + Fpacked = F->packed ; } else { - /* symmetric lower triangular form not supported */ - ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; - return (FALSE) ; + // symmetric lower triangular form not supported + ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; + return (FALSE) ; } Ap = A->p ; @@ -291,56 +308,55 @@ int CHOLMOD(row_subtree) k = krow ; Stack = R->i ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ - /* mark = CHOLMOD(clear_flag) (Common) ; */ + Flag = Common->Flag ; // size nrow, Flag [i] < mark must hold CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; mark = Common->mark ; - /* ---------------------------------------------------------------------- */ - /* compute the pattern of L(k,:) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the pattern of L(k,:) + //-------------------------------------------------------------------------- - top = nrow ; /* Stack is empty */ - Flag [k] = mark ; /* do not include diagonal entry in Stack */ + top = nrow ; // Stack is empty + Flag [k] = mark ; // do not include diagonal entry in Stack -#define SCATTER /* do not scatter numerical values */ -#define PARENT(i) Parent [i] /* use Parent for etree */ + #define SCATTER /* do not scatter numerical values */ + #define PARENT(i) Parent [i] /* use Parent for etree */ if (stype != 0) { - /* scatter kth col of triu (A), get pattern L(k,:) */ - p = Ap [k] ; - pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; - SUBTREE ; + // scatter kth col of triu (A), get pattern L(k,:) + p = Ap [k] ; + pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; + SUBTREE ; } else { - /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ - pf = Fp [k] ; - pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; - for ( ; pf < pfend ; pf++) - { - /* get nonzero entry F (t,k) */ - t = Fi [pf] ; - p = Ap [t] ; - pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; - SUBTREE ; - } + // scatter kth col of triu (beta*I+AA'), get pattern L(k,:) + pf = Fp [k] ; + pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; + for ( ; pf < pfend ; pf++) + { + // get nonzero entry F (t,k) + t = Fi [pf] ; + p = Ap [t] ; + pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; + SUBTREE ; + } } -#undef SCATTER -#undef PARENT + #undef SCATTER + #undef PARENT - /* shift the stack upwards, to the first part of R */ + // shift the stack upwards, to the first part of R len = nrow - top ; for (i = 0 ; i < len ; i++) { - Stack [i] = Stack [top + i] ; + Stack [i] = Stack [top + i] ; } Rp = R->p ; @@ -349,30 +365,28 @@ int CHOLMOD(row_subtree) R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (TRUE) ; } -/* ========================================================================== */ -/* === cholmod_lsolve_pattern =============================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_lsolve_pattern +//------------------------------------------------------------------------------ -/* Compute the nonzero pattern of Y=L\B. L must be simplicial, and B - * must be a single sparse column vector with B->stype = 0. The values of - * B are not used; it just specifies a nonzero pattern. The pattern of - * Y is not sorted, but is in topological order instead (suitable for a - * sparse forward/backsolve). - */ +// Compute the nonzero pattern of Y=L\B. L must be simplicial, and B +// must be a single sparse column vector with B->stype = 0. The values of +// B are not used; it just specifies a nonzero pattern. The pattern of +// Y is not sorted, but is in topological order instead (suitable for a +// sparse forward/backsolve). int CHOLMOD(lsolve_pattern) ( - /* ---- input ---- */ - cholmod_sparse *B, /* sparse right-hand-side (a single sparse column) */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *Yset, /* pattern of Y=L\B, n-by-1 with Y->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *B, // sparse right-hand-side (a single sparse column) + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *Yset, // pattern of Y=L\B, n-by-1 with Y->nzmax >= n cholmod_common *Common ) { @@ -383,41 +397,41 @@ int CHOLMOD(lsolve_pattern) } -/* ========================================================================== */ -/* === cholmod_row_lsubtree ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_row_lsubtree +//------------------------------------------------------------------------------ -/* Identical to cholmod_row_subtree, except that the elimination tree is - * obtained from L itself, as the first off-diagonal entry in each column. - * L must be simplicial, not supernodal. - * - * If krow = A->nrow, then A must be a single sparse column vector, (A->stype - * must be zero), and the nonzero pattern of x=L\b is computed, where b=A(:,0) - * is the single sparse right-hand-side. The inputs Fi and fnz are ignored. - * See CHOLMOD(lsolve_pattern) above for a simpler interface for this case. - */ +// Identical to cholmod_row_subtree, except that the elimination tree is +// obtained from L itself, as the first off-diagonal entry in each column. +// L must be simplicial, not supernodal. +// +// If krow = A->nrow, then A must be a single sparse column vector, (A->stype +// must be zero), and the nonzero pattern of x=L\b is computed, where b=A(:,0) +// is the single sparse right-hand-side. The inputs Fi and fnz are ignored. +// See CHOLMOD(lsolve_pattern) above for a simpler interface for this case. int CHOLMOD(row_lsubtree) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - Int *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required - * for the symmetric case. Need not be sorted. */ - size_t krow, /* row k of L */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), n-by-1 with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + Int *Fi, // nonzero pattern of kth row of A', not required + // for the symmetric case. Need not be sorted. + size_t fnz, // size of Fi + size_t krow, // row k of L + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *R, // pattern of L(k,:), n-by-1 with R->nzmax >= n cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Lp, *Li, *Lnz ; Int p, pend, parent, t, stype, nrow, k, pf, packed, sorted, top, len, i, - mark, ka ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + mark, ka ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -431,9 +445,9 @@ int CHOLMOD(row_lsubtree) stype = A->stype ; if (stype < 0) { - /* symmetric lower triangular form not supported */ - ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; - return (FALSE) ; + // symmetric lower triangular form not supported + ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; + return (FALSE) ; } if (krow > nrow) @@ -443,21 +457,21 @@ int CHOLMOD(row_lsubtree) } else if (krow == nrow) { - /* find pattern of x=L\b where b=A(:,0) */ - k = nrow ; /* compute all of the result; don't stop in SUBTREE */ - ka = 0 ; /* use column A(:,0) */ + // find pattern of x=L\b where b=A(:,0) + k = nrow ; // compute all of the result; don't stop in SUBTREE + ka = 0 ; // use column A(:,0) if (stype != 0 || A->ncol != 1) { - /* A must be unsymmetric (it's a single sparse column vector) */ + // A must be unsymmetric (it's a single sparse column vector) ERROR (CHOLMOD_INVALID, "lsubtree: A invalid") ; return (FALSE) ; } } else { - /* find pattern of L(k,:) using A(:,k) and Fi if A unsymmetric */ - k = krow ; /* which row of L to compute */ - ka = k ; /* which column of A to use */ + // find pattern of L(k,:) using A(:,k) and Fi if A unsymmetric + k = krow ; // which row of L to compute + ka = k ; // which column of A to use if (stype == 0) { RETURN_IF_NULL (Fi, FALSE) ; @@ -467,30 +481,30 @@ int CHOLMOD(row_lsubtree) if (R->ncol != 1 || nrow != R->nrow || nrow > R->nzmax || ((krow == nrow || stype != 0) && ka >= A->ncol)) { - ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ; + return (FALSE) ; } if (L->is_super) { - ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- Ap = A->p ; Ai = A->i ; @@ -504,54 +518,54 @@ int CHOLMOD(row_lsubtree) Li = L->i ; Lnz = L->nz ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ + Flag = Common->Flag ; // size nrow, Flag [i] < mark must hold mark = CHOLMOD(clear_flag) (Common) ; - /* ---------------------------------------------------------------------- */ - /* compute the pattern of L(k,:) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the pattern of L(k,:) + //-------------------------------------------------------------------------- - top = nrow ; /* Stack is empty */ + top = nrow ; // Stack is empty if (k < nrow) { - Flag [k] = mark ; /* do not include diagonal entry in Stack */ + Flag [k] = mark ; // do not include diagonal entry in Stack } -#define SCATTER /* do not scatter numerical values */ -#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY + #define SCATTER /* do not scatter numerical values */ + #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY if (krow == nrow || stype != 0) { - /* scatter kth col of triu (A), get pattern L(k,:) */ - p = Ap [ka] ; - pend = (packed) ? (Ap [ka+1]) : (p + Anz [ka]) ; - SUBTREE ; + // scatter kth col of triu (A), get pattern L(k,:) + p = Ap [ka] ; + pend = (packed) ? (Ap [ka+1]) : (p + Anz [ka]) ; + SUBTREE ; } else { - /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ - for (pf = 0 ; pf < (Int) fnz ; pf++) - { - /* get nonzero entry F (t,k) */ - t = Fi [pf] ; - p = Ap [t] ; - pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; - SUBTREE ; - } + // scatter kth col of triu (beta*I+AA'), get pattern L(k,:) + for (pf = 0 ; pf < (Int) fnz ; pf++) + { + // get nonzero entry F (t,k) + t = Fi [pf] ; + p = Ap [t] ; + pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; + SUBTREE ; + } } -#undef SCATTER -#undef PARENT + #undef SCATTER + #undef PARENT - /* shift the stack upwards, to the first part of R */ + // shift the stack upwards, to the first part of R len = nrow - top ; for (i = 0 ; i < len ; i++) { - Stack [i] = Stack [top + i] ; + Stack [i] = Stack [top + i] ; } Rp = R->p ; @@ -560,55 +574,53 @@ int CHOLMOD(row_lsubtree) R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (TRUE) ; } -/* ========================================================================== */ -/* === cholmod_rowfac ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_rowfac +//------------------------------------------------------------------------------ -/* This is the incremental factorization for general purpose usage. */ +// This is the incremental factorization for general purpose usage. int CHOLMOD(rowfac) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ - double beta [2], /* factorize beta*I+A or beta*I+AA' */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(rowfac_mask2) (A, F, beta, kstart, kend, NULL, 0, NULL, L, - Common)) ; + Common)) ; } -/* ========================================================================== */ -/* === cholmod_rowfac_mask ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_rowfac_mask +//------------------------------------------------------------------------------ -/* This is meant for use in LPDASA only. */ +// This is meant for use in LPDASA only. int CHOLMOD(rowfac_mask) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ - double beta [2], /* factorize beta*I+A or beta*I+AA' */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - Int *mask, /* size A->nrow. if mask[i] >= 0 row i is set to zero */ - Int *RLinkUp, /* size A->nrow. link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + Int *mask, // size A->nrow. if mask[i] >= 0 row i is set to zero + Int *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) { @@ -617,148 +629,189 @@ int CHOLMOD(rowfac_mask) RLinkUp, L, Common)) ; } -/* ========================================================================== */ -/* === cholmod_rowfac_mask2 ================================================= */ -/* ========================================================================== */ -/* This is meant for use in LPDASA only. */ +//------------------------------------------------------------------------------ +// cholmod_rowfac_mask2 +//------------------------------------------------------------------------------ + +// This is meant for use in LPDASA only. For general usage, see +// cholmod_rowfac. int CHOLMOD(rowfac_mask2) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ - double beta [2], /* factorize beta*I+A or beta*I+AA' */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - Int *mask, /* size A->nrow. if mask[i] >= maskmark row i is set - to zero */ - Int maskmark, /* for mask [i] test */ - Int *RLinkUp, /* size A->nrow. link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + Int *mask, // size A->nrow. if mask[i] >= maskmark row i is set + // to zero + Int maskmark, // for mask [i] test + Int *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + Int n ; size_t s ; - int ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; - if (L->xtype != CHOLMOD_PATTERN && A->xtype != L->xtype) + if (L->xtype != CHOLMOD_PATTERN && + (A->xtype != L->xtype || A->dtype != L->dtype)) { - ERROR (CHOLMOD_INVALID, "xtype of A and L do not match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "xtype or dtype of A and L do not match") ; + return (FALSE) ; } if (L->is_super) { - ERROR (CHOLMOD_INVALID, "can only do simplicial factorization"); - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "can only do simplicial factorization"); + return (FALSE) ; } if (A->stype == 0) { - RETURN_IF_NULL (F, FALSE) ; - if (A->xtype != F->xtype) - { - ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ; - return (FALSE) ; - } + RETURN_IF_NULL (F, FALSE) ; + if (A->xtype != F->xtype) + { + ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ; + return (FALSE) ; + } } if (A->stype < 0) { - /* symmetric lower triangular form not supported */ - ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; - return (FALSE) ; + // symmetric lower triangular form not supported + ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; + return (FALSE) ; } if (kend > L->n) { - ERROR (CHOLMOD_INVALID, "kend invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "kend invalid") ; + return (FALSE) ; } if (A->nrow != L->n) { - ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; Common->rowfacfl = 0 ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* Xwork is of size n for the real case, 2*n for complex/zomplex */ + // Xwork is of size n for the real case, 2*n for complex/zomplex n = L->n ; - /* s = ((A->xtype != CHOLMOD_REAL) ? 2:1)*n */ - s = CHOLMOD(mult_size_t) (n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ; + // s = n * ((A->xtype != CHOLMOD_REAL) ? 2:1) + int ok = TRUE ; + s = CHOLMOD(mult_size_t) (L->n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, n, s, Common) ; + CHOLMOD(alloc_work) (n, n, s, A->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, A->dtype, Common)) ; + + //-------------------------------------------------------------------------- + // factorize the matrix, using template routine + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* factorize the matrix, using template routine */ - /* ---------------------------------------------------------------------- */ + float s_beta [2] ; + s_beta [0] = (float) beta [0] ; + s_beta [1] = (float) beta [1] ; if (RLinkUp == NULL) { - switch (A->xtype) - { - case CHOLMOD_REAL: - ok = r_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; - break ; - - case CHOLMOD_COMPLEX: - ok = c_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - ok = z_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; - break ; - } + switch ((A->xtype + A->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + ok = rs_cholmod_rowfac_worker (A, F, s_beta, kstart, kend, L, + Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + ok = cs_cholmod_rowfac_worker (A, F, s_beta, kstart, kend, L, + Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + ok = zs_cholmod_rowfac_worker (A, F, s_beta, kstart, kend, L, + Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + ok = rd_cholmod_rowfac_worker (A, F, beta, kstart, kend, L, + Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + ok = cd_cholmod_rowfac_worker (A, F, beta, kstart, kend, L, + Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + ok = zd_cholmod_rowfac_worker (A, F, beta, kstart, kend, L, + Common) ; + break ; + } } else { - switch (A->xtype) - { - case CHOLMOD_REAL: - ok = r_cholmod_rowfac_mask (A, F, beta, kstart, kend, - mask, maskmark, RLinkUp, L, Common) ; - break ; - - case CHOLMOD_COMPLEX: - ok = c_cholmod_rowfac_mask (A, F, beta, kstart, kend, - mask, maskmark, RLinkUp, L, Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - ok = z_cholmod_rowfac_mask (A, F, beta, kstart, kend, - mask, maskmark, RLinkUp, L, Common) ; - break ; - } + switch ((A->xtype + A->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + ok = rs_cholmod_rowfac_mask_worker (A, F, s_beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + ok = cs_cholmod_rowfac_mask_worker (A, F, s_beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + ok = zs_cholmod_rowfac_mask_worker (A, F, s_beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + ok = rd_cholmod_rowfac_mask_worker (A, F, beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + ok = cd_cholmod_rowfac_mask_worker (A, F, beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + ok = zd_cholmod_rowfac_mask_worker (A, F, beta, kstart, kend, + mask, maskmark, RLinkUp, L, Common) ; + break ; + } } return (ok) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_solve.c b/CHOLMOD/Cholesky/cholmod_solve.c index 905f85fe10..3d74649d8a 100644 --- a/CHOLMOD/Cholesky/cholmod_solve.c +++ b/CHOLMOD/Cholesky/cholmod_solve.c @@ -2,963 +2,116 @@ // CHOLMOD/Cholesky/cholmod_solve: solve a linear system //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Solve one of the following systems. D is identity for an LL' factorization, - * in which the D operation is skipped: - * - * Ax=b 0: CHOLMOD_A x = P' * (L' \ (D \ (L \ (P * b)))) - * LDL'x=b 1: CHOLMOD_LDLt x = (L' \ (D \ (L \ ( b)))) - * LDx=b 2: CHOLMOD_LD x = ( (D \ (L \ ( b)))) - * DL'x=b 3: CHOLMOD_DLt x = (L' \ (D \ ( ( b)))) - * Lx=b 4: CHOLMOD_L x = ( ( (L \ ( b)))) - * L'x=b 5: CHOLMOD_Lt x = (L' \ ( ( ( b)))) - * Dx=b 6: CHOLMOD_D x = ( (D \ ( ( b)))) - * x=Pb 7: CHOLMOD_P x = ( ( ( (P * b)))) - * x=P'b 8: CHOLMOD_Pt x = P' * ( ( ( ( b)))) - * - * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. - * For an LL' factorization, D is the identity matrix. Thus CHOLMOD_LD and - * CHOLMOD_L solve the same system if an LL' factorization was performed, - * for example. - * - * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm, - * or their complex counterparts ztrsv, zgemv, ztrsm, and zgemm. - * - * If both L and B are real, then X is returned real. If either is complex - * or zomplex, X is returned as either complex or zomplex, depending on the - * Common->prefer_zomplex parameter. - * - * Supports any numeric xtype (pattern-only matrices not supported). - * - * This routine does not check to see if the diagonal of L or D is zero, - * because sometimes a partial solve can be done with indefinite or singular - * matrix. If you wish to check in your own code, test L->minor. If - * L->minor == L->n, then the matrix has no zero diagonal entries. - * If k = L->minor < L->n, then L(k,k) is zero for an LL' factorization, or - * D(k,k) is zero for an LDL' factorization. - * - * This routine returns X as NULL only if it runs out of memory. If L is - * indefinite or singular, then X may contain Inf's or NaN's, but it will - * exist on output. - */ +// Solve one of the following systems. D is identity for an LL' factorization, +// in which the D operation is skipped: +// +// Ax=b 0: CHOLMOD_A x = P' * (L' \ (D \ (L \ (P * b)))) +// LDL'x=b 1: CHOLMOD_LDLt x = (L' \ (D \ (L \ ( b)))) +// LDx=b 2: CHOLMOD_LD x = ( (D \ (L \ ( b)))) +// DL'x=b 3: CHOLMOD_DLt x = (L' \ (D \ ( ( b)))) +// Lx=b 4: CHOLMOD_L x = ( ( (L \ ( b)))) +// L'x=b 5: CHOLMOD_Lt x = (L' \ ( ( ( b)))) +// Dx=b 6: CHOLMOD_D x = ( (D \ ( ( b)))) +// x=Pb 7: CHOLMOD_P x = ( ( ( (P * b)))) +// x=P'b 8: CHOLMOD_Pt x = P' * ( ( ( ( b)))) +// +// The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. +// For an LL' factorization, D is the identity matrix. Thus CHOLMOD_LD and +// CHOLMOD_L solve the same system if an LL' factorization was performed, +// for example. +// +// The supernodal solver uses BLAS routines: +// +// dtrsv, dgemv, dtrsm, dgemm: double real +// ztrsv, zgemv, ztrsm, zgemm: double complex +// strsv, sgemv, strsm, sgemm: float real +// ctrsv, cgemv, ctrsm, cgemm: float complex +// +// If both L and B are real, then X is returned real. If either is complex +// or zomplex, X is returned as either complex or zomplex, depending on the +// Common->prefer_zomplex parameter. +// +// Supports any numeric xtype (real, complex, or zomplex; pattern-only matrices +// not supported), and any dtype. +// +// This routine does not check to see if the diagonal of L or D is zero, +// because sometimes a partial solve can be done with indefinite or singular +// matrix. If you wish to check in your own code, test L->minor. If L->minor +// == L->n, then the matrix has no zero diagonal entries. If k = L->minor < +// L->n, then L(k,k) is zero for an LL' factorization, or D(k,k) is zero for an +// LDL' factorization. +// +// This routine returns X as NULL only if it runs out of memory. If L is +// indefinite or singular, then X may contain Inf's or NaN's, but it will exist +// on output. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === TEMPLATE ============================================================= */ -/* ========================================================================== */ - -#define REAL -#include "t_cholmod_solve.c" - -#define COMPLEX -#include "t_cholmod_solve.c" - -#define ZOMPLEX -#include "t_cholmod_solve.c" - -/* ========================================================================== */ -/* === Permutation macro ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// P(k): permutation macro for t_cholmod_*_worker methods +//------------------------------------------------------------------------------ -/* If Perm is NULL, it is interpretted as the identity permutation */ +// If Perm is NULL, it is interpretted as the identity permutation #define P(k) ((Perm == NULL) ? (k) : Perm [k]) +//------------------------------------------------------------------------------ +// t_cholmod_solve_worker +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === perm ================================================================= */ -/* ========================================================================== */ - -/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1) where B is nrow-by-ncol. - * - * Creates a permuted copy of a contiguous set of columns of B. - * Y is already allocated on input. Y must be of sufficient size. Let nk be - * the number of columns accessed in B. Y->xtype determines the complexity of - * the result. - * - * If B is real and Y is complex (or zomplex), only the real part of B is - * copied into Y. The imaginary part of Y is set to zero. - * - * If B is complex (or zomplex) and Y is real, both the real and imaginary and - * parts of B are returned in Y. Y is returned as nrow-by-2*nk. The even - * columns of Y contain the real part of B and the odd columns contain the - * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is - * returned as nrow-by-nk with leading dimension nrow. Y->nzmax must be >= - * nrow*nk. - * - * The case where the input (B) is real and the output (Y) is zomplex is - * not used. - */ - -static void perm -( - /* ---- input ---- */ - cholmod_dense *B, /* input matrix B */ - Int *Perm, /* optional input permutation (can be NULL) */ - Int k1, /* first column of B to copy */ - Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ - /* ---- in/out --- */ - cholmod_dense *Y /* output matrix Y, already allocated */ -) -{ - double *Yx, *Yz, *Bx, *Bz ; - Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; - size_t dual ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - ncol = B->ncol ; - nrow = B->nrow ; - k2 = MIN (k1+ncols, ncol) ; - nk = MAX (k2 - k1, 0) ; - dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; - d = B->d ; - Bx = B->x ; - Bz = B->z ; - Yx = Y->x ; - Yz = Y->z ; - Y->nrow = nrow ; - Y->ncol = dual*nk ; - Y->d = nrow ; - ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; - - /* ---------------------------------------------------------------------- */ - /* Y = B (P (1:nrow), k1:k2-1) */ - /* ---------------------------------------------------------------------- */ - - switch (Y->xtype) - { - - case CHOLMOD_REAL: - - switch (B->xtype) - { - - case CHOLMOD_REAL: - /* Y real, B real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [k + j2] = Bx [p] ; /* real */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y real, B complex. Y is nrow-by-2*nk */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [k + j2 ] = Bx [2*p ] ; /* real */ - Yx [k + j2 + nrow] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y real, B zomplex. Y is nrow-by-2*nk */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [k + j2 ] = Bx [p] ; /* real */ - Yx [k + j2 + nrow] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_COMPLEX: - - switch (B->xtype) - { - - case CHOLMOD_REAL: - /* Y complex, B real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [2*k + j2] = Bx [p] ; /* real */ - Yx [2*k+1 + j2] = 0 ; /* imag */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y complex, B complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [2*k + j2] = Bx [2*p ] ; /* real */ - Yx [2*k+1 + j2] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y complex, B zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [2*k + j2] = Bx [p] ; /* real */ - Yx [2*k+1 + j2] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_ZOMPLEX: - - switch (B->xtype) - { - -#if 0 - case CHOLMOD_REAL: - /* this case is not used */ - break ; -#endif - - case CHOLMOD_COMPLEX: - /* Y zomplex, B complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [k + j2] = Bx [2*p ] ; /* real */ - Yz [k + j2] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y zomplex, B zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [k + j2] = Bx [p] ; /* real */ - Yz [k + j2] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - } -} - - -/* ========================================================================== */ -/* === iperm ================================================================ */ -/* ========================================================================== */ - -/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y where X is nrow-by-ncol. - * - * Copies and permutes Y into a contiguous set of columns of X. X is already - * allocated on input. Y must be of sufficient size. Let nk be the number - * of columns accessed in X. X->xtype determines the complexity of the result. - * - * If X is real and Y is complex (or zomplex), only the real part of B is - * copied into X. The imaginary part of Y is ignored. - * - * If X is complex (or zomplex) and Y is real, both the real and imaginary and - * parts of Y are returned in X. Y is nrow-by-2*nk. The even - * columns of Y contain the real part of B and the odd columns contain the - * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is - * nrow-by-nk with leading dimension nrow. Y->nzmax must be >= nrow*nk. - * - * The case where the input (Y) is complex and the output (X) is real, - * and the case where the input (Y) is zomplex and the output (X) is real, - * are not used. - */ - -static void iperm -( - /* ---- input ---- */ - cholmod_dense *Y, /* input matrix Y */ - Int *Perm, /* optional input permutation (can be NULL) */ - Int k1, /* first column of B to copy */ - Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ - /* ---- in/out --- */ - cholmod_dense *X /* output matrix X, already allocated */ -) -{ - double *Yx, *Yz, *Xx, *Xz ; - Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - ncol = X->ncol ; - nrow = X->nrow ; - k2 = MIN (k1+ncols, ncol) ; - nk = MAX (k2 - k1, 0) ; - d = X->d ; - Xx = X->x ; - Xz = X->z ; - Yx = Y->x ; - Yz = Y->z ; - ASSERT (((Int) Y->nzmax) >= nrow*nk* - ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; - - /* ---------------------------------------------------------------------- */ - /* X (P (1:nrow), k1:k2-1) = Y */ - /* ---------------------------------------------------------------------- */ - - switch (Y->xtype) - { - - case CHOLMOD_REAL: - - switch (X->xtype) - { - - case CHOLMOD_REAL: - /* Y real, X real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [k + j2] ; /* real */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y real, X complex. Y is nrow-by-2*nk */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [k + j2 ] ; /* real */ - Xx [2*p+1] = Yx [k + j2 + nrow] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y real, X zomplex. Y is nrow-by-2*nk */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [k + j2 ] ; /* real */ - Xz [p] = Yx [k + j2 + nrow] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_COMPLEX: - - switch (X->xtype) - { - -#if 0 - case CHOLMOD_REAL: - /* this case is not used */ - break ; -#endif - - case CHOLMOD_COMPLEX: - /* Y complex, X complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [2*k + j2] ; /* real */ - Xx [2*p+1] = Yx [2*k+1 + j2] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y complex, X zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * 2 * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [2*k + j2] ; /* real */ - Xz [p] = Yx [2*k+1 + j2] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_ZOMPLEX: - - switch (X->xtype) - { - -#if 0 - case CHOLMOD_REAL: - /* this case is not used */ - break ; -#endif - - case CHOLMOD_COMPLEX: - /* Y zomplex, X complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [k + j2] ; /* real */ - Xx [2*p+1] = Yz [k + j2] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y zomplex, X zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = nrow * (j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [k + j2] ; /* real */ - Xz [p] = Yz [k + j2] ; /* imag */ - } - } - break ; - - } - break ; - - } -} - - -/* ========================================================================== */ -/* === ptrans =============================================================== */ -/* ========================================================================== */ - -/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1)' where B is nrow-by-ncol. - * - * Creates a permuted and transposed copy of a contiguous set of columns of B. - * Y is already allocated on input. Y must be of sufficient size. Let nk be - * the number of columns accessed in B. Y->xtype determines the complexity of - * the result. - * - * If B is real and Y is complex (or zomplex), only the real part of B is - * copied into Y. The imaginary part of Y is set to zero. - * - * If B is complex (or zomplex) and Y is real, both the real and imaginary and - * parts of B are returned in Y. Y is returned as 2*nk-by-nrow. The even - * rows of Y contain the real part of B and the odd rows contain the - * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is - * returned as nk-by-nrow with leading dimension nk. Y->nzmax must be >= - * nrow*nk. - * - * The array transpose is performed, not the complex conjugate transpose. - */ - -static void ptrans -( - /* ---- input ---- */ - cholmod_dense *B, /* input matrix B */ - Int *Perm, /* optional input permutation (can be NULL) */ - Int k1, /* first column of B to copy */ - Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ - /* ---- in/out --- */ - cholmod_dense *Y /* output matrix Y, already allocated */ -) -{ - double *Yx, *Yz, *Bx, *Bz ; - Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; - size_t dual ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - ncol = B->ncol ; - nrow = B->nrow ; - k2 = MIN (k1+ncols, ncol) ; - nk = MAX (k2 - k1, 0) ; - dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; - d = B->d ; - Bx = B->x ; - Bz = B->z ; - Yx = Y->x ; - Yz = Y->z ; - Y->nrow = dual*nk ; - Y->ncol = nrow ; - Y->d = dual*nk ; - ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; - - /* ---------------------------------------------------------------------- */ - /* Y = B (P (1:nrow), k1:k2-1)' */ - /* ---------------------------------------------------------------------- */ - - switch (Y->xtype) - { - - case CHOLMOD_REAL: - - switch (B->xtype) - { - - case CHOLMOD_REAL: - /* Y real, B real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*nk] = Bx [p] ; /* real */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y real, B complex. Y is 2*nk-by-nrow */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*2*nk] = Bx [2*p ] ; /* real */ - Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y real, B zomplex. Y is 2*nk-by-nrow */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*2*nk] = Bx [p] ; /* real */ - Yx [j2+1 + k*2*nk] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_COMPLEX: - - switch (B->xtype) - { - - case CHOLMOD_REAL: - /* Y complex, B real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*2*nk] = Bx [p] ; /* real */ - Yx [j2+1 + k*2*nk] = 0 ; /* imag */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y complex, B complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*2*nk] = Bx [2*p ] ; /* real */ - Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y complex, B zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*2*nk] = Bx [p] ; /* real */ - Yx [j2+1 + k*2*nk] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_ZOMPLEX: - - switch (B->xtype) - { - - case CHOLMOD_REAL: - /* Y zomplex, B real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*nk] = Bx [p] ; /* real */ - Yz [j2 + k*nk] = 0 ; /* imag */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y zomplex, B complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*nk] = Bx [2*p ] ; /* real */ - Yz [j2 + k*nk] = Bx [2*p+1] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y zomplex, B zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Yx [j2 + k*nk] = Bx [p] ; /* real */ - Yz [j2 + k*nk] = Bz [p] ; /* imag */ - } - } - break ; - - } - break ; - - } -} - - -/* ========================================================================== */ -/* === iptrans ============================================================== */ -/* ========================================================================== */ - -/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y' where X is nrow-by-ncol. - * - * Copies into a permuted and transposed contiguous set of columns of X. - * X is already allocated on input. Y must be of sufficient size. Let nk be - * the number of columns accessed in X. X->xtype determines the complexity of - * the result. - * - * If X is real and Y is complex (or zomplex), only the real part of Y is - * copied into X. The imaginary part of Y is ignored. - * - * If X is complex (or zomplex) and Y is real, both the real and imaginary and - * parts of X are returned in Y. Y is 2*nk-by-nrow. The even - * rows of Y contain the real part of X and the odd rows contain the - * imaginary part of X. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is - * nk-by-nrow with leading dimension nk. Y->nzmax must be >= nrow*nk. - * - * The case where Y is complex or zomplex, and X is real, is not used. - * - * The array transpose is performed, not the complex conjugate transpose. - */ - -static void iptrans -( - /* ---- input ---- */ - cholmod_dense *Y, /* input matrix Y */ - Int *Perm, /* optional input permutation (can be NULL) */ - Int k1, /* first column of X to copy into */ - Int ncols, /* last column to copy is min(k1+ncols,X->ncol)-1 */ - /* ---- in/out --- */ - cholmod_dense *X /* output matrix X, already allocated */ -) -{ - double *Yx, *Yz, *Xx, *Xz ; - Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - ncol = X->ncol ; - nrow = X->nrow ; - k2 = MIN (k1+ncols, ncol) ; - nk = MAX (k2 - k1, 0) ; - d = X->d ; - Xx = X->x ; - Xz = X->z ; - Yx = Y->x ; - Yz = Y->z ; - ASSERT (((Int) Y->nzmax) >= nrow*nk* - ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; - - /* ---------------------------------------------------------------------- */ - /* X (P (1:nrow), k1:k2-1) = Y' */ - /* ---------------------------------------------------------------------- */ - - switch (Y->xtype) - { - - case CHOLMOD_REAL: - - switch (X->xtype) - { - - case CHOLMOD_REAL: - /* Y real, X real */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [j2 + k*nk] ; /* real */ - } - } - break ; - - case CHOLMOD_COMPLEX: - /* Y real, X complex. Y is 2*nk-by-nrow */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [j2 + k*2*nk] ; /* real */ - Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y real, X zomplex. Y is 2*nk-by-nrow */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [j2 + k*2*nk] ; /* real */ - Xz [p] = Yx [j2+1 + k*2*nk] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_COMPLEX: - - switch (X->xtype) - { - -#if 0 - case CHOLMOD_REAL: - /* this case is not used */ - break ; -#endif - - case CHOLMOD_COMPLEX: - /* Y complex, X complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [j2 + k*2*nk] ; /* real */ - Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y complex, X zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = 2*(j-k1) ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [j2 + k*2*nk] ; /* real */ - Xz [p] = Yx [j2+1 + k*2*nk] ; /* imag */ - } - } - break ; - - } - break ; - - case CHOLMOD_ZOMPLEX: - - switch (X->xtype) - { - -#if 0 - case CHOLMOD_REAL: - /* this case is not used */ - break ; -#endif - - case CHOLMOD_COMPLEX: - /* Y zomplex, X complex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [2*p ] = Yx [j2 + k*nk] ; /* real */ - Xx [2*p+1] = Yz [j2 + k*nk] ; /* imag */ - } - } - break ; - - case CHOLMOD_ZOMPLEX: - /* Y zomplex, X zomplex */ - for (j = k1 ; j < k2 ; j++) - { - dj = d*j ; - j2 = j-k1 ; - for (k = 0 ; k < nrow ; k++) - { - p = P(k) + dj ; - Xx [p] = Yx [j2 + k*nk] ; /* real */ - Xz [p] = Yz [j2 + k*nk] ; /* imag */ - } - } - break ; - - } - break ; - - } -} +#define DOUBLE +#include "t_cholmod_psolve_worker.c" +#define REAL +#include "t_cholmod_solve_worker.c" +#define COMPLEX +#include "t_cholmod_solve_worker.c" +#define ZOMPLEX +#include "t_cholmod_solve_worker.c" +#undef DOUBLE +#define SINGLE +#include "t_cholmod_psolve_worker.c" +#define REAL +#include "t_cholmod_solve_worker.c" +#define COMPLEX +#include "t_cholmod_solve_worker.c" +#define ZOMPLEX +#include "t_cholmod_solve_worker.c" -/* ========================================================================== */ -/* === cholmod_solve ======================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_solve +//------------------------------------------------------------------------------ -/* Solve a linear system. - * - * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. - * The Dx=b solve returns silently for the LL' factorizations (it is implicitly - * identity). - */ +// Solve a linear system. +// +// The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. +// The Dx=b solve returns silently for the LL' factorizations (it is implicitly +// identity). -cholmod_dense *CHOLMOD(solve) +cholmod_dense *CHOLMOD(solve) // returns solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_common *Common ) { - cholmod_dense *Y = NULL, *X = NULL ; - cholmod_dense *E = NULL ; - int ok ; - /* do the solve, allocating workspaces as needed */ - ok = CHOLMOD (solve2) (sys, L, B, NULL, &X, NULL, &Y, &E, Common) ; + cholmod_dense *Y = NULL, *X = NULL, *E = NULL ; + + // do the solve, allocating workspaces as needed + int ok = CHOLMOD (solve2) (sys, L, B, NULL, &X, NULL, &Y, &E, Common) ; - /* free workspaces if allocated, and free result if an error occured */ + // free workspaces if allocated, and free result if an error occured CHOLMOD(free_dense) (&Y, Common) ; CHOLMOD(free_dense) (&E, Common) ; if (!ok) @@ -969,92 +122,89 @@ cholmod_dense *CHOLMOD(solve) } -/* ========================================================================== */ -/* === cholmod_solve2 ======================================================= */ -/* ========================================================================== */ - -/* This function acts just like cholmod_solve, except that the solution X and - * the internal workspace (Y and E) can be passed in preallocated. If the - * solution X or any required workspaces are not allocated on input, or if they - * are the wrong size or type, then this function frees them and reallocates - * them as the proper size and type. Thus, if you have a sequence of solves to - * do, you can let this function allocate X, Y, and E on the first call. - * Subsequent calls to cholmod_solve2 can then reuse this space. You must - * then free the workspaces Y and E (and X if desired) when you are finished. - * For example, the first call to cholmod_l_solve2, below, will solve the - * requested system. The next 2 calls (with different right-hand-sides but - * the same value of "sys") will resuse the workspace and solution X from the - * first call. Finally, when all solves are done, you must free the workspaces - * Y and E (otherwise you will have a memory leak), and you should also free X - * when you are done with it. Note that on input, X, Y, and E must be either - * valid cholmod_dense matrices, or initialized to NULL. You cannot pass in an - * uninitialized X, Y, or E. - * - * cholmod_dense *X = NULL, *Y = NULL, *E = NULL ; - * ... - * cholmod_l_solve2 (sys, L, B1, NULL, &X, NULL, &Y, &E, Common) ; - * cholmod_l_solve2 (sys, L, B2, NULL, &X, NULL, &Y, &E, Common) ; - * cholmod_l_solve2 (sys, L, B3, NULL, &X, NULL, &Y, &E, Common) ; - * cholmod_l_free_dense (&X, Common) ; - * cholmod_l_free_dense (&Y, Common) ; - * cholmod_l_free_dense (&E, Common) ; - * - * The equivalent when using cholmod_l_solve is: - * - * cholmod_dense *X = NULL, *Y = NULL, *E = NULL ; - * ... - * X = cholmod_l_solve (sys, L, B1, Common) ; - * cholmod_l_free_dense (&X, Common) ; - * X = cholmod_l_solve (sys, L, B2, Common) ; - * cholmod_l_free_dense (&X, Common) ; - * X = cholmod_l_solve (sys, L, B3, Common) ; - * cholmod_l_free_dense (&X, Common) ; - * - * Both methods work fine, but in the 2nd method with cholmod_solve, the - * internal workspaces (Y and E) are allocated and freed on each call. - * - * Bset is an optional sparse column (pattern only) that specifies a set - * of row indices. It is ignored if NULL, or if sys is CHOLMOD_P or - * CHOLMOD_Pt. If it is present and not ignored, B must be a dense column - * vector, and only entries B(i) where i is in the pattern of Bset are - * considered. All others are treated as if they were zero (they are not - * accessed). L must be a simplicial factorization, not supernodal. L is - * converted from supernodal to simplicial if necessary. The solution X is - * defined only for entries in the output sparse pattern of Xset. - * The xtype (real/complex/zomplex) of L and B must match. - * - * NOTE: If Bset is present and L is supernodal, it is converted to simplicial - * on output. - */ - -int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ +//------------------------------------------------------------------------------ +// cholmod_solve2 +//------------------------------------------------------------------------------ + +// This function acts just like cholmod_solve, except that the solution X and +// the internal workspace (Y and E) can be passed in preallocated. If the +// solution X or any required workspaces are not allocated on input, or if they +// are the wrong size or type, then this function frees them and reallocates +// them as the proper size and type. Thus, if you have a sequence of solves to +// do, you can let this function allocate X, Y, and E on the first call. +// Subsequent calls to cholmod_solve2 can then reuse this space. You must then +// free the workspaces Y and E (and X if desired) when you are finished. For +// example, the first call to cholmod_l_solve2, below, will solve the requested +// system. The next 2 calls (with different right-hand-sides but the same +// value of "sys") will resuse the workspace and solution X from the first +// call. Finally, when all solves are done, you must free the workspaces Y and +// E (otherwise you will have a memory leak), and you should also free X when +// you are done with it. Note that on input, X, Y, and E must be either valid +// cholmod_dense matrices, or initialized to NULL. You cannot pass in an +// uninitialized X, Y, or E. +// +// cholmod_dense *X = NULL, *Y = NULL, *E = NULL ; +// ... +// cholmod_l_solve2 (sys, L, B1, NULL, &X, NULL, &Y, &E, Common) ; +// cholmod_l_solve2 (sys, L, B2, NULL, &X, NULL, &Y, &E, Common) ; +// cholmod_l_solve2 (sys, L, B3, NULL, &X, NULL, &Y, &E, Common) ; +// cholmod_l_free_dense (&X, Common) ; +// cholmod_l_free_dense (&Y, Common) ; +// cholmod_l_free_dense (&E, Common) ; +// +// The equivalent when using cholmod_l_solve is: +// +// cholmod_dense *X = NULL, *Y = NULL, *E = NULL ; +// ... +// X = cholmod_l_solve (sys, L, B1, Common) ; +// cholmod_l_free_dense (&X, Common) ; +// X = cholmod_l_solve (sys, L, B2, Common) ; +// cholmod_l_free_dense (&X, Common) ; +// X = cholmod_l_solve (sys, L, B3, Common) ; +// cholmod_l_free_dense (&X, Common) ; +// +// Both methods work fine, but in the 2nd method with cholmod_solve, the +// internal workspaces (Y and E) are allocated and freed on each call. +// +// Bset is an optional sparse column (pattern only) that specifies a set of row +// indices. It is ignored if NULL, or if sys is CHOLMOD_P or CHOLMOD_Pt. If +// it is present and not ignored, B must be a dense column vector, and only +// entries B(i) where i is in the pattern of Bset are considered. All others +// are treated as if they were zero (they are not accessed). L must be a +// simplicial factorization, not supernodal. L is converted from supernodal to +// simplicial if necessary. The solution X is defined only for entries in the +// output sparse pattern of Xset. The xtype (real/complex/zomplex) of L and B +// must match. +// +// NOTE: If Bset is present and L is supernodal, it is converted to simplicial +// on output. + +int CHOLMOD(solve2) // returns TRUE on success, FALSE on failure ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_sparse *Bset, - /* ---- output --- */ - cholmod_dense **X_Handle, /* solution, allocated if need be */ + // output: + cholmod_dense **X_Handle, // solution, allocated if need be cholmod_sparse **Xset_Handle, - /* ---- workspace */ - cholmod_dense **Y_Handle, /* workspace, or NULL */ - cholmod_dense **E_Handle, /* workspace, or NULL */ - /* --------------- */ + // workspace: + cholmod_dense **Y_Handle, // workspace, or NULL + cholmod_dense **E_Handle, // workspace, or NULL cholmod_common *Common ) { - double *Yx, *Yz, *Bx, *Bz, *Xx, *Xz ; + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + cholmod_dense *Y = NULL, *X = NULL ; cholmod_sparse *C, *Yset, C_header, Yset_header, *Xset ; Int *Perm = NULL, *IPerm = NULL ; - Int n, nrhs, ncols, ctype, xtype, k1, nr, ytype, k, blen, p, i, d, nrow ; + Int n, nrhs, ncols, k1, nr, ytype, k, blen, p, i, d, nrow ; Int Cp [2], Ysetp [2], *Ci, *Yseti, ysetlen ; - Int *Bsetp, *Bseti, *Bsetnz, *Xseti, *Xsetp, *Iwork ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; @@ -1063,8 +213,13 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (sys < CHOLMOD_A || sys > CHOLMOD_Pt) { - ERROR (CHOLMOD_INVALID, "invalid system") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "invalid system") ; + return (FALSE) ; + } + if (L->dtype != B->dtype) + { + ERROR (CHOLMOD_INVALID, "dtype of L and B must match") ; + return (FALSE) ; } DEBUG (CHOLMOD(dump_factor) (L, "L", Common)) ; DEBUG (CHOLMOD(dump_dense) (B, "B", Common)) ; @@ -1074,9 +229,16 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ nrow = (Int) B->nrow ; if (d < n || nrow != n) { - ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; + return (FALSE) ; + } + + if (sys == CHOLMOD_P || sys == CHOLMOD_Pt) + { + // Bset is ignored when solving Px=b or P'x=b + Bset = NULL ; } + if (Bset) { if (nrhs != 1) @@ -1093,66 +255,66 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if ((sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_A) - && L->ordering != CHOLMOD_NATURAL) + && L->ordering != CHOLMOD_NATURAL) { - /* otherwise, Perm is NULL, and the identity permutation is used */ - Perm = L->Perm ; + // otherwise, Perm is NULL, and the identity permutation is used + Perm = L->Perm ; } - /* ---------------------------------------------------------------------- */ - /* allocate the result X (or resuse the space from a prior call) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate the result X (or resuse the space from a prior call) + //-------------------------------------------------------------------------- - ctype = (Common->prefer_zomplex) ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX ; + int ctype = (Common->prefer_zomplex) ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX ; + int X_xtype ; if (Bset) { - xtype = L->xtype ; + X_xtype = L->xtype ; } else if (sys == CHOLMOD_P || sys == CHOLMOD_Pt) { - /* x=Pb and x=P'b return X real if B is real; X is the preferred - * complex/zcomplex type if B is complex or zomplex */ - xtype = (B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : ctype ; + // x=Pb and x=P'b return X real if B is real; X is the preferred + // complex/zcomplex type if B is complex or zomplex + X_xtype = (B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : ctype ; } else if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) { - /* X is real if both L and B are real */ - xtype = CHOLMOD_REAL ; + // X is real if both L and B are real + X_xtype = CHOLMOD_REAL ; } else { - /* X is complex, use the preferred complex/zomplex type */ - xtype = ctype ; + // X is complex, use the preferred complex/zomplex type + X_xtype = ctype ; } - /* ensure X has the right size and type */ - X = CHOLMOD(ensure_dense) (X_Handle, n, nrhs, n, xtype, Common) ; + // ensure X has the right size and type + X = CHOLMOD(ensure_dense) (X_Handle, n, nrhs, n, X_xtype + L->dtype, + Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* solve using L, D, L', P, or some combination */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve using L, D, L', P, or some combination + //-------------------------------------------------------------------------- if (Bset) { - /* ------------------------------------------------------------------ */ - /* solve for a subset of x, with a sparse b */ - /* ------------------------------------------------------------------ */ - - Int save_realloc_state ; + //---------------------------------------------------------------------- + // solve for a subset of x, with a sparse b + //---------------------------------------------------------------------- -#ifndef NSUPERNODAL - /* convert a supernodal L to simplicial when using Bset */ + #ifndef NSUPERNODAL + // convert a supernodal L to simplicial when using Bset if (L->is_super) { // Can only use Bset on a simplicial factorization. The supernodal @@ -1162,48 +324,49 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ // the super_num_to_simplicial_num function in // cholmod_change_factor. CHOLMOD(change_factor) ( - CHOLMOD_REAL, /* ignored, since L is already numeric */ - TRUE, /* convert to LL' (no change to num. values) */ - FALSE, /* convert to simplicial */ - FALSE, /* do not pack the columns of L */ - FALSE, /* (ignored) */ + CHOLMOD_REAL, // ignored, since L is already numeric + TRUE, // convert to LL' (no change to num. values) + FALSE, // convert to simplicial + FALSE, // do not pack the columns of L + FALSE, // (ignored) L, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory, L is returned unchanged */ + // out of memory, L is returned unchanged return (FALSE) ; } } -#endif + #endif - /* L, X, and B are all the same xtype */ - /* ensure Y is the the right size */ - Y = CHOLMOD(ensure_dense) (Y_Handle, 1, n, 1, L->xtype, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (FALSE) ; - } + // L, X, and B are all the same xtype + // ensure Y is the the right size + Y = CHOLMOD(ensure_dense) (Y_Handle, 1, n, 1, L->xtype + L->dtype, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (FALSE) ; + } - /* ------------------------------------------------------------------ */ - /* get the inverse permutation, constructing it if needed */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // get the inverse permutation, constructing it if needed + //---------------------------------------------------------------------- DEBUG (CHOLMOD (dump_perm) (Perm, n,n, "Perm", Common)) ; if ((sys == CHOLMOD_A || sys == CHOLMOD_P) && Perm != NULL) { - /* The inverse permutation IPerm is used for the c=Pb step, - which is needed only for solving Ax=b or x=Pb. No other - steps should use IPerm */ + // The inverse permutation IPerm is used for the c=Pb step, + // which is needed only for solving Ax=b or x=Pb. No other + // steps should use IPerm if (L->IPerm == NULL) { - /* construct the inverse permutation. This is done only once - * and then stored in L permanently. */ + // construct the inverse permutation. This is done only once + // and then stored in L permanently. L->IPerm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ + // out of memory return (FALSE) ; } IPerm = L->IPerm ; @@ -1212,78 +375,72 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ IPerm [Perm [k]] = k ; } } - /* x=A\b and x=Pb both need IPerm */ + // x=A\b and x=Pb both need IPerm IPerm = L->IPerm ; } - if (sys == CHOLMOD_P) - { - /* x=Pb needs to turn off the subsequent x=P'b permutation */ - Perm = NULL ; - } - DEBUG (CHOLMOD (dump_perm) (Perm, n,n, "Perm", Common)) ; DEBUG (CHOLMOD (dump_perm) (IPerm, n,n, "IPerm", Common)) ; - /* ------------------------------------------------------------------ */ - /* ensure Xset is the right size and type */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // ensure Xset is the right size and type + //---------------------------------------------------------------------- - /* Xset is n-by-1, nzmax >= n, pattern-only, packed, unsorted */ + // Xset is n-by-1, nzmax >= n, pattern-only, packed, unsorted Xset = *Xset_Handle ; if (Xset == NULL || (Int) Xset->nrow != n || (Int) Xset->ncol != 1 || (Int) Xset->nzmax < n || Xset->itype != CHOLMOD_PATTERN) { - /* this is done only once, for the 1st call to cholmod_solve */ + // this is done only once, for the 1st call to cholmod_solve CHOLMOD(free_sparse) (Xset_Handle, Common) ; Xset = CHOLMOD(allocate_sparse) (n, 1, n, FALSE, TRUE, 0, - CHOLMOD_PATTERN, Common) ; - *Xset_Handle = Xset ; + CHOLMOD_PATTERN + L->dtype, Common) ; + (*Xset_Handle) = Xset ; } - Xset->sorted = FALSE ; - Xset->stype = 0 ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ + // out of memory return (FALSE) ; } + Xset->sorted = FALSE ; + Xset->stype = 0 ; - /* -------------------------------------------------------------- */ - /* ensure Flag of size n, and 3*n Int workspace is available */ - /* -------------------------------------------------------------- */ + //---------------------------------------------------------------------- + // ensure Flag of size n, and 3*n Int workspace is available + //---------------------------------------------------------------------- - /* does no work if prior calls already allocated enough space */ + // does no work if prior calls already allocated enough space CHOLMOD(allocate_work) (n, 3*n, 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ + // out of memory return (FALSE) ; } - /* [ use Iwork (n:3n-1) for Ci and Yseti */ - Iwork = Common->Iwork ; - /* Iwork (0:n-1) is not used because it is used by check_perm, - print_perm, check_sparse, and print_sparse */ + // [ use Iwork (n:3n-1) for Ci and Yseti + Int *Iwork = Common->Iwork ; + // Iwork (0:n-1) is not used because it is used by check_perm, + // print_perm, check_sparse, and print_sparse Ci = Iwork + n ; Yseti = Ci + n ; - /* reallocating workspace would break Ci and Yseti */ - save_realloc_state = Common->no_workspace_reallocate ; + // reallocating workspace would break Ci and Yseti + int save_realloc_state = Common->no_workspace_reallocate ; Common->no_workspace_reallocate = TRUE ; - /* -------------------------------------------------------------- */ - /* C = permuted Bset, to correspond to the permutation of L */ - /* -------------------------------------------------------------- */ + //---------------------------------------------------------------------- + // C = permuted Bset, to correspond to the permutation of L + //---------------------------------------------------------------------- - /* C = IPerm (Bset) */ + // C = IPerm (Bset) DEBUG (CHOLMOD(dump_sparse) (Bset, "Bset", Common)) ; - Bsetp = Bset->p ; - Bseti = Bset->i ; - Bsetnz = Bset->nz ; + Int *Bsetp = Bset->p ; + Int *Bseti = Bset->i ; + Int *Bsetnz = Bset->nz ; blen = (Bset->packed) ? Bsetp [1] : Bsetnz [0] ; - /* C = spones (P*B) or C = spones (B) if IPerm is NULL */ + // C = spones (P*B) or C = spones (B) if IPerm is NULL C = &C_header ; C->nrow = n ; C->ncol = 1 ; @@ -1292,7 +449,7 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ C->stype = 0 ; C->itype = ITYPE ; C->xtype = CHOLMOD_PATTERN ; - C->dtype = CHOLMOD_DOUBLE ; + C->dtype = L->dtype ; C->nz = NULL ; C->p = Cp ; C->i = Ci ; @@ -1308,7 +465,7 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ } DEBUG (CHOLMOD (dump_sparse) (C, "C", Common)) ; - /* create a sparse column Yset from Iwork (n:2n-1) */ + // create a sparse column Yset from Iwork (n:2n-1) Yset = &Yset_header ; Yset->nrow = n ; Yset->ncol = 1 ; @@ -1317,7 +474,7 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ Yset->stype = 0 ; Yset->itype = ITYPE ; Yset->xtype = CHOLMOD_PATTERN ; - Yset->dtype = CHOLMOD_DOUBLE ; + Yset->dtype = L->dtype ; Yset->nz = NULL ; Yset->p = Ysetp ; Yset->i = Yseti ; @@ -1328,11 +485,12 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ Ysetp [1] = 0 ; DEBUG (CHOLMOD (dump_sparse) (Yset, "Yset empty", Common)) ; - /* -------------------------------------------------------------- */ - /* Yset = nonzero pattern of L\C, or just C itself */ - /* -------------------------------------------------------------- */ + //---------------------------------------------------------------------- + // Yset = nonzero pattern of L\C, or just C itself + //---------------------------------------------------------------------- - /* this takes O(ysetlen) time */ + // this takes O(ysetlen) time + int ok = true ; if (sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_D) { Ysetp [1] = blen ; @@ -1343,338 +501,332 @@ int CHOLMOD(solve2) /* returns TRUE on success, FALSE on failure */ } else { - if (!CHOLMOD(lsolve_pattern) (C, L, Yset, Common)) - { - Common->no_workspace_reallocate = save_realloc_state ; - return (FALSE) ; - } + ok = CHOLMOD(lsolve_pattern) (C, L, Yset, Common) ; } - DEBUG (CHOLMOD (dump_sparse) (Yset, "Yset", Common)) ; - /* -------------------------------------------------------------- */ - /* clear the parts of Y that we will use in the solve */ - /* -------------------------------------------------------------- */ + if (ok) + { - Yx = Y->x ; - Yz = Y->z ; - ysetlen = Ysetp [1] ; + DEBUG (CHOLMOD (dump_sparse) (Yset, "Yset", Common)) ; - switch (L->xtype) - { + //------------------------------------------------------------------ + // Y (C) = B (Bset) + //------------------------------------------------------------------ - case CHOLMOD_REAL: - for (p = 0 ; p < ysetlen ; p++) - { - i = Yseti [p] ; - Yx [i] = 0 ; - } - break ; + switch ((L->xtype + L->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_bset_perm (B, Bset, Yset, C, Y) ; + break ; - case CHOLMOD_COMPLEX: - for (p = 0 ; p < ysetlen ; p++) - { - i = Yseti [p] ; - Yx [2*i ] = 0 ; - Yx [2*i+1] = 0 ; - } - break ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_bset_perm (B, Bset, Yset, C, Y) ; + break ; - case CHOLMOD_ZOMPLEX: - for (p = 0 ; p < ysetlen ; p++) - { - i = Yseti [p] ; - Yx [i] = 0 ; - Yz [i] = 0 ; - } - break ; - } + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_bset_perm (B, Bset, Yset, C, Y) ; + break ; - DEBUG (CHOLMOD (dump_dense) (Y, "Y (Yset) = 0", Common)) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_bset_perm (B, Bset, Yset, C, Y) ; + break ; - /* -------------------------------------------------------------- */ - /* scatter and permute B into Y */ - /* -------------------------------------------------------------- */ + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_bset_perm (B, Bset, Yset, C, Y) ; + break ; - /* Y (C) = B (Bset) */ - Bx = B->x ; - Bz = B->z ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_bset_perm (B, Bset, Yset, C, Y) ; + break ; + } - switch (L->xtype) - { + DEBUG (CHOLMOD (dump_dense) (Y, "Y (C) = B (Bset)", Common)) ; - case CHOLMOD_REAL: - for (p = 0 ; p < blen ; p++) - { - Int iold = Bseti [p] ; - Int inew = Ci [p] ; - Yx [inew] = Bx [iold] ; - } - break ; + //------------------------------------------------------------------ + // solve Y = (L' \ (L \ Y'))', or other system, with template + //------------------------------------------------------------------ - case CHOLMOD_COMPLEX: - for (p = 0 ; p < blen ; p++) - { - Int iold = Bseti [p] ; - Int inew = Ci [p] ; - Yx [2*inew ] = Bx [2*iold ] ; - Yx [2*inew+1] = Bx [2*iold+1] ; - } - break ; + // the solve only iterates over columns in Yseti [0...ysetlen-1] - case CHOLMOD_ZOMPLEX: - for (p = 0 ; p < blen ; p++) + if (! (sys == CHOLMOD_P || sys == CHOLMOD_Pt)) + { + switch ((L->xtype + L->dtype) % 8) { - Int iold = Bseti [p] ; - Int inew = Ci [p] ; - Yx [inew] = Bx [iold] ; - Yz [inew] = Bz [iold] ; - } - break ; - } + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_simplicial_solver (sys, L, Y, Yset) ; + break ; - DEBUG (CHOLMOD (dump_dense) (Y, "Y (C) = B (Bset)", Common)) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_simplicial_solver (sys, L, Y, Yset) ; + break ; - /* -------------------------------------------------------------- */ - /* solve Y = (L' \ (L \ Y'))', or other system, with template */ - /* -------------------------------------------------------------- */ + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_simplicial_solver (sys, L, Y, Yset) ; + break ; - /* the solve only iterates over columns in Yseti [0...ysetlen-1] */ + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_simplicial_solver (sys, L, Y, Yset) ; + break ; - if (! (sys == CHOLMOD_P || sys == CHOLMOD_Pt)) - { - switch (L->xtype) + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_simplicial_solver (sys, L, Y, Yset) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_simplicial_solver (sys, L, Y, Yset) ; + break ; + } + } + + DEBUG (CHOLMOD (dump_dense) (Y, "Y after solve", Common)) ; + + //------------------------------------------------------------------ + // X = P'*Y, but only for rows in Yset, and create Xset + //------------------------------------------------------------------ + + switch ((L->xtype + L->dtype) % 8) { - case CHOLMOD_REAL: - r_simplicial_solver (sys, L, Y, Yseti, ysetlen) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_bset_iperm (Y, Yset, Perm, X, Xset) ; break ; - case CHOLMOD_COMPLEX: - c_simplicial_solver (sys, L, Y, Yseti, ysetlen) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_bset_iperm (Y, Yset, Perm, X, Xset) ; break ; - case CHOLMOD_ZOMPLEX: - z_simplicial_solver (sys, L, Y, Yseti, ysetlen) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_bset_iperm (Y, Yset, Perm, X, Xset) ; break ; - } - } - - DEBUG (CHOLMOD (dump_dense) (Y, "Y after solve", Common)) ; - - /* -------------------------------------------------------------- */ - /* X = P'*Y, but only for rows in Yset, and create Xset */ - /* -------------------------------------------------------------- */ - /* X (Perm (Yset)) = Y (Yset) */ - Xx = X->x ; - Xz = X->z ; - Xseti = Xset->i ; - Xsetp = Xset->p ; - - switch (L->xtype) - { + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_bset_iperm (Y, Yset, Perm, X, Xset) ; + break ; - case CHOLMOD_REAL: - for (p = 0 ; p < ysetlen ; p++) - { - Int inew = Yseti [p] ; - Int iold = Perm ? Perm [inew] : inew ; - Xx [iold] = Yx [inew] ; - Xseti [p] = iold ; - } - break ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_bset_iperm (Y, Yset, Perm, X, Xset) ; + break ; - case CHOLMOD_COMPLEX: - for (p = 0 ; p < ysetlen ; p++) - { - Int inew = Yseti [p] ; - Int iold = Perm ? Perm [inew] : inew ; - Xx [2*iold ] = Yx [2*inew] ; - Xx [2*iold+1] = Yx [2*inew+1] ; - Xseti [p] = iold ; - } - break ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_bset_iperm (Y, Yset, Perm, X, Xset) ; + break ; + } - case CHOLMOD_ZOMPLEX: - for (p = 0 ; p < ysetlen ; p++) - { - Int inew = Yseti [p] ; - Int iold = Perm ? Perm [inew] : inew ; - Xx [iold] = Yx [inew] ; - Xz [iold] = Yz [inew] ; - Xseti [p] = iold ; - } - break ; + DEBUG (CHOLMOD(dump_sparse) (Xset, "Xset", Common)) ; + DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ; } - Xsetp [0] = 0 ; - Xsetp [1] = ysetlen ; - - DEBUG (CHOLMOD(dump_sparse) (Xset, "Xset", Common)) ; - DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ; Common->no_workspace_reallocate = save_realloc_state ; - /* done using Iwork (n:3n-1) for Ci and Yseti ] */ + // done using Iwork (n:3n-1) for Ci and Yseti ] } else if (sys == CHOLMOD_P) { - /* ------------------------------------------------------------------ */ - /* x = P*b */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // x = P*b + //---------------------------------------------------------------------- - perm (B, Perm, 0, nrhs, X) ; + if (L->dtype == CHOLMOD_DOUBLE) + { + d_perm (B, Perm, 0, nrhs, X) ; + } + else + { + s_perm (B, Perm, 0, nrhs, X) ; + } } else if (sys == CHOLMOD_Pt) { - /* ------------------------------------------------------------------ */ - /* x = P'*b */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // x = P'*b + //---------------------------------------------------------------------- - iperm (B, Perm, 0, nrhs, X) ; + if (L->dtype == CHOLMOD_DOUBLE) + { + d_iperm (B, Perm, 0, nrhs, X) ; + } + else + { + s_iperm (B, Perm, 0, nrhs, X) ; + } } else if (L->is_super) { - /* ------------------------------------------------------------------ */ - /* solve using a supernodal LL' factorization */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // solve using a supernodal LL' factorization + //---------------------------------------------------------------------- -#ifndef NSUPERNODAL - /* allocate workspace */ - cholmod_dense *E ; - size_t dual ; + #ifndef NSUPERNODAL + // allocate workspace + cholmod_dense *E ; + size_t dual ; Common->blas_ok = TRUE ; - dual = (L->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; - Y = CHOLMOD(ensure_dense) (Y_Handle, n, dual*nrhs, n, L->xtype, Common); + dual = (L->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; + Y = CHOLMOD(ensure_dense) (Y_Handle, n, dual*nrhs, n, + L->xtype + L->dtype, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ + if (Common->status < CHOLMOD_OK) + { + // out of memory return (FALSE) ; - } + } - E = CHOLMOD(ensure_dense) (E_Handle, dual*nrhs, L->maxesize, dual*nrhs, - L->xtype, Common) ; + E = CHOLMOD(ensure_dense) (E_Handle, dual*nrhs, L->maxesize, dual*nrhs, + L->xtype + L->dtype, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ + if (Common->status < CHOLMOD_OK) + { + // out of memory return (FALSE) ; - } - - perm (B, Perm, 0, nrhs, Y) ; /* Y = P*B */ - - if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) - { - CHOLMOD(super_lsolve) (L, Y, E, Common) ; /* Y = L\Y */ - CHOLMOD(super_ltsolve) (L, Y, E, Common) ; /* Y = L'\Y*/ - } - else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) - { - CHOLMOD(super_lsolve) (L, Y, E, Common) ; /* Y = L\Y */ - } - else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) - { - CHOLMOD(super_ltsolve) (L, Y, E, Common) ; /* Y = L'\Y*/ - } - - iperm (Y, Perm, 0, nrhs, X) ; /* X = P'*Y */ - - if (sizeof (SUITESPARSE_BLAS_INT) < sizeof (Int) && !Common->blas_ok) - { - /* Integer overflow in the BLAS. This is probably impossible, - * since the BLAS were used to create the supernodal factorization. - * It might be possible for the calls to the BLAS to differ between - * factorization and forward/backsolves, however. This statement - * cannot be tested. */ - return (FALSE) ; - } - -#else - /* CHOLMOD Supernodal module not installed */ - ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; -#endif + } + + if (L->dtype == CHOLMOD_DOUBLE) + { + d_perm (B, Perm, 0, nrhs, Y) ; // Y = P*B + } + else + { + s_perm (B, Perm, 0, nrhs, Y) ; // Y = P*B + } + + if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) + { + CHOLMOD(super_lsolve) (L, Y, E, Common) ; // Y = L\Y + CHOLMOD(super_ltsolve) (L, Y, E, Common) ; // Y = L'\Y + } + else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) + { + CHOLMOD(super_lsolve) (L, Y, E, Common) ; // Y = L\Y + } + else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) + { + CHOLMOD(super_ltsolve) (L, Y, E, Common) ; // Y = L'\Y + } + + if (L->dtype == CHOLMOD_DOUBLE) + { + d_iperm (Y, Perm, 0, nrhs, X) ; // X = P'*Y + } + else + { + s_iperm (Y, Perm, 0, nrhs, X) ; // X = P'*Y + } + + #else + // CHOLMOD Supernodal module not installed + ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; + #endif } else { - /* ------------------------------------------------------------------ */ - /* solve using a simplicial LL' or LDL' factorization */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // solve using a simplicial LL' or LDL' factorization + //---------------------------------------------------------------------- if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) - { - /* L, B, and Y are all real */ - /* solve with up to 4 columns of B at a time */ + { + // L, B, and Y are all real + // solve with up to 4 columns of B at a time ncols = 4 ; nr = MAX (4, nrhs) ; - ytype = CHOLMOD_REAL ; - } - else if (L->xtype == CHOLMOD_REAL) - { - /* L is real and B is complex or zomplex */ - /* solve with one column of B (real/imag), at a time */ - ncols = 1 ; - nr = 2 ; - ytype = CHOLMOD_REAL ; - } - else - { - /* L is complex or zomplex, B is real/complex/zomplex, Y has the - * same complexity as L. Solve with one column of B at a time. */ - ncols = 1 ; - nr = 1 ; - ytype = L->xtype ; - } - - Y = CHOLMOD(ensure_dense) (Y_Handle, nr, n, nr, ytype, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (FALSE) ; - } + ytype = CHOLMOD_REAL ; + } + else if (L->xtype == CHOLMOD_REAL) + { + // L is real and B is complex or zomplex + // solve with one column of B (real/imag), at a time + ncols = 1 ; + nr = 2 ; + ytype = CHOLMOD_REAL ; + } + else + { + // L is complex or zomplex, B is real/complex/zomplex, Y has the + // same complexity as L. Solve with one column of B at a time. + ncols = 1 ; + nr = 1 ; + ytype = L->xtype ; + } + + Y = CHOLMOD(ensure_dense) (Y_Handle, nr, n, nr, ytype + L->dtype, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (FALSE) ; + } for (k1 = 0 ; k1 < nrhs ; k1 += ncols) { - /* -------------------------------------------------------------- */ - /* Y = B (P, k1:k1+ncols-1)' = (P * B (:,...))' */ - /* -------------------------------------------------------------- */ + //------------------------------------------------------------------ + // Y = B (P, k1:k1+ncols-1)' = (P * B (:,...))' + //------------------------------------------------------------------ - ptrans (B, Perm, k1, ncols, Y) ; + if (L->dtype == CHOLMOD_DOUBLE) + { + d_ptrans (B, Perm, k1, ncols, Y) ; + } + else + { + s_ptrans (B, Perm, k1, ncols, Y) ; + } - /* -------------------------------------------------------------- */ - /* solve Y = (L' \ (L \ Y'))', or other system, with template */ - /* -------------------------------------------------------------- */ + //------------------------------------------------------------------ + // solve Y = (L' \ (L \ Y'))', or other system, with template + //------------------------------------------------------------------ - switch (L->xtype) + switch ((L->xtype + L->dtype) % 8) { - case CHOLMOD_REAL: - r_simplicial_solver (sys, L, Y, NULL, 0) ; + + case CHOLMOD_SINGLE + CHOLMOD_REAL: + rs_simplicial_solver (sys, L, Y, NULL) ; + break ; + + case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: + cs_simplicial_solver (sys, L, Y, NULL) ; break ; - case CHOLMOD_COMPLEX: - c_simplicial_solver (sys, L, Y, NULL, 0) ; + case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: + zs_simplicial_solver (sys, L, Y, NULL) ; break ; - case CHOLMOD_ZOMPLEX: - z_simplicial_solver (sys, L, Y, NULL, 0) ; + case CHOLMOD_DOUBLE + CHOLMOD_REAL: + rd_simplicial_solver (sys, L, Y, NULL) ; + break ; + + case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: + cd_simplicial_solver (sys, L, Y, NULL) ; + break ; + + case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: + zd_simplicial_solver (sys, L, Y, NULL) ; break ; } - /* -------------------------------------------------------------- */ - /* X (P, k1:k2+ncols-1) = Y' */ - /* -------------------------------------------------------------- */ + //------------------------------------------------------------------ + // X (P, k1:k2+ncols-1) = Y' + //------------------------------------------------------------------ - iptrans (Y, Perm, k1, ncols, X) ; + if (L->dtype == CHOLMOD_DOUBLE) + { + d_iptrans (Y, Perm, k1, ncols, X) ; + } + else + { + s_iptrans (Y, Perm, k1, ncols, X) ; + } } } DEBUG (CHOLMOD(dump_dense) (X, "X result", Common)) ; - return (TRUE) ; + return (Common->status == CHOLMOD_OK) ; } #endif + diff --git a/CHOLMOD/Cholesky/cholmod_spsolve.c b/CHOLMOD/Cholesky/cholmod_spsolve.c index 869aefc399..f3fe91f17a 100644 --- a/CHOLMOD/Cholesky/cholmod_spsolve.c +++ b/CHOLMOD/Cholesky/cholmod_spsolve.c @@ -2,82 +2,74 @@ // CHOLMOD/Cholesky/cholmod_spsolve: solve a linear system with sparse x and b //------------------------------------------------------------------------------ -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis // All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* Given an LL' or LDL' factorization of A, solve one of the following systems: - * - * Ax=b 0: CHOLMOD_A also applies the permutation L->Perm - * LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm - * LDx=b 2: CHOLMOD_LD - * DL'x=b 3: CHOLMOD_DLt - * Lx=b 4: CHOLMOD_L - * L'x=b 5: CHOLMOD_Lt - * Dx=b 6: CHOLMOD_D - * x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) - * x=P'b 8: CHOLMOD_Pt apply an inverse permutation - * - * where b and x are sparse. If L and b are real, then x is real. Otherwise, - * x is complex or zomplex, depending on the Common->prefer_zomplex parameter. - * All xtypes of x and b are supported (real, complex, and zomplex). - */ +// Given an LL' or LDL' factorization of A, solve one of the following systems: +// +// Ax=b 0: CHOLMOD_A also applies the permutation L->Perm +// LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm +// LDx=b 2: CHOLMOD_LD +// DL'x=b : CHOLMOD_DLt +// Lx=b 4: CHOLMOD_L +// L'x=b 5: CHOLMOD_Lt +// Dx=b 6: CHOLMOD_D +// x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) +// x=P'b 8: CHOLMOD_Pt apply an inverse permutation +// +// where b and x are sparse. If L and b are real, then x is real. Otherwise, +// x is complex or zomplex, depending on the Common->prefer_zomplex parameter. +// All xtypes of x and b are supported (real, complex, and zomplex), and +// all dtypes. #include "cholmod_internal.h" #ifndef NCHOLESKY -/* ========================================================================== */ -/* === EXPAND_AS_NEEDED ===================================================== */ -/* ========================================================================== */ - -/* Double the size of the sparse matrix X, if we have run out of space. */ - -#define EXPAND_AS_NEEDED \ -if (xnz >= nzmax) \ -{ \ - nzmax *= 2 ; \ - CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; \ - if (Common->status < CHOLMOD_OK) \ - { \ - CHOLMOD(free_sparse) (&X, Common) ; \ - CHOLMOD(free_dense) (&X4, Common) ; \ - CHOLMOD(free_dense) (&B4, Common) ; \ - return (NULL) ; \ - } \ - Xi = X->i ; \ - Xx = X->x ; \ - Xz = X->z ; \ -} +//------------------------------------------------------------------------------ +// t_cholmod_spsolve_worker +//------------------------------------------------------------------------------ +#define DOUBLE +#define REAL +#include "t_cholmod_spsolve_worker.c" +#define COMPLEX +#include "t_cholmod_spsolve_worker.c" +#define ZOMPLEX +#include "t_cholmod_spsolve_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_spsolve_worker.c" +#define COMPLEX +#include "t_cholmod_spsolve_worker.c" +#define ZOMPLEX +#include "t_cholmod_spsolve_worker.c" -/* ========================================================================== */ -/* === cholmod_spolve ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_spsolve +//------------------------------------------------------------------------------ -cholmod_sparse *CHOLMOD(spsolve) /* returns the sparse solution X */ +cholmod_sparse *CHOLMOD(spsolve) // returns the sparse solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_sparse *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_sparse *B, // right-hand-side cholmod_common *Common ) { - double x, z ; - cholmod_dense *X4, *B4 ; - cholmod_sparse *X ; - double *Bx, *Bz, *Xx, *Xz, *B4x, *B4z, *X4x, *X4z ; - Int *Bi, *Bp, *Xp, *Xi, *Bnz ; - Int n, nrhs, q, p, i, j, jfirst, jlast, packed, block, pend, j_n, xtype ; - size_t xnz, nzmax ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + cholmod_dense *X4 = NULL, *B4 = NULL ; + cholmod_sparse *X = NULL ; RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; @@ -86,305 +78,198 @@ cholmod_sparse *CHOLMOD(spsolve) /* returns the sparse solution X */ RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; if (L->n != B->nrow) { - ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; - return (NULL) ; + ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; + return (NULL) ; } if (B->stype) { - ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ; - return (NULL) ; + ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ; + return (NULL) ; + } + if (L->dtype != B->dtype) + { + ERROR (CHOLMOD_INVALID, "dtype of L and B must match") ; + return (NULL) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace B4 and initial result X */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace B4 and initial result X + //-------------------------------------------------------------------------- - n = L->n ; - nrhs = B->ncol ; + Int n = L->n ; + Int nrhs = B->ncol ; - /* X is real if both L and B are real, complex/zomplex otherwise */ - xtype = (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ? - CHOLMOD_REAL : - (Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ; + // X is real if both L and B are real, complex/zomplex otherwise + int X_xtype = + (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : + (Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ; - /* solve up to 4 columns at a time */ - block = MIN (nrhs, 4) ; + // solve up to 4 columns at a time + Int block = MIN (nrhs, 4) ; - /* initial size of X is at most 4*n */ - nzmax = ((size_t) n) * ((size_t) block) ; + // initial size of X is at most 4*n + size_t nzmax = ((size_t) n) * ((size_t) block) ; - X = CHOLMOD(spzeros) (n, nrhs, nzmax, xtype, Common) ; - B4 = CHOLMOD(zeros) (n, block, B->xtype, Common) ; + X = CHOLMOD(spzeros) (n, nrhs, nzmax, X_xtype + B->dtype, Common) ; + B4 = CHOLMOD(zeros) (n, block, B->xtype + B->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - CHOLMOD(free_sparse) (&X, Common) ; - CHOLMOD(free_dense) (&B4, Common) ; - return (NULL) ; + CHOLMOD(free_sparse) (&X, Common) ; + CHOLMOD(free_dense) (&B4, Common) ; + return (NULL) ; } - Bp = B->p ; - Bi = B->i ; - Bx = B->x ; - Bz = B->z ; - Bnz = B->nz ; - packed = B->packed ; - - Xp = X->p ; - Xi = X->i ; - Xx = X->x ; - Xz = X->z ; - - xnz = 0 ; - - B4x = B4->x ; - B4z = B4->z ; + size_t xnz = 0 ; - /* ---------------------------------------------------------------------- */ - /* solve in chunks of 4 columns at a time */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve in chunks of 4 columns at a time + //-------------------------------------------------------------------------- - for (jfirst = 0 ; jfirst < nrhs ; jfirst += block) + for (Int jfirst = 0 ; jfirst < nrhs ; jfirst += block) { - /* ------------------------------------------------------------------ */ - /* adjust the number of columns of B4 */ - /* ------------------------------------------------------------------ */ - - jlast = MIN (nrhs, jfirst + block) ; - B4->ncol = jlast - jfirst ; - - /* ------------------------------------------------------------------ */ - /* scatter B(jfirst:jlast-1) into B4 */ - /* ------------------------------------------------------------------ */ - - for (j = jfirst ; j < jlast ; j++) - { - p = Bp [j] ; - pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; - j_n = (j-jfirst)*n ; - - switch (B->xtype) - { - - case CHOLMOD_REAL: - for ( ; p < pend ; p++) - { - B4x [Bi [p] + j_n] = Bx [p] ; - } - break ; - - case CHOLMOD_COMPLEX: - for ( ; p < pend ; p++) - { - q = Bi [p] + j_n ; - B4x [2*q ] = Bx [2*p ] ; - B4x [2*q+1] = Bx [2*p+1] ; - } - break ; - - case CHOLMOD_ZOMPLEX: - for ( ; p < pend ; p++) - { - q = Bi [p] + j_n ; - B4x [q] = Bx [p] ; - B4z [q] = Bz [p] ; - } - break ; - } - } - - /* ------------------------------------------------------------------ */ - /* solve the system (X4 = A\B4 or other system) */ - /* ------------------------------------------------------------------ */ - - X4 = CHOLMOD(solve) (sys, L, B4, Common) ; - if (Common->status < CHOLMOD_OK) - { - CHOLMOD(free_sparse) (&X, Common) ; - CHOLMOD(free_dense) (&B4, Common) ; - CHOLMOD(free_dense) (&X4, Common) ; - return (NULL) ; - } - ASSERT (X4->xtype == xtype) ; - X4x = X4->x ; - X4z = X4->z ; - - /* ------------------------------------------------------------------ */ - /* append the solution onto X */ - /* ------------------------------------------------------------------ */ - - for (j = jfirst ; j < jlast ; j++) - { - Xp [j] = xnz ; - j_n = (j-jfirst)*n ; - if ( xnz + n <= nzmax) - { - - /* ---------------------------------------------------------- */ - /* X is guaranteed to be large enough */ - /* ---------------------------------------------------------- */ - - switch (xtype) - { - - case CHOLMOD_REAL: - for (i = 0 ; i < n ; i++) - { - x = X4x [i + j_n] ; - if (x != 0) - { - Xi [xnz] = i ; - Xx [xnz] = x ; - xnz++ ; - } - } - break ; - - case CHOLMOD_COMPLEX: - for (i = 0 ; i < n ; i++) - { - x = X4x [2*(i + j_n) ] ; - z = X4x [2*(i + j_n)+1] ; - if ((x != 0) || (z != 0)) - { - Xi [xnz] = i ; - Xx [2*xnz ] = x ; - Xx [2*xnz+1] = z ; - xnz++ ; - } - } - break ; - - case CHOLMOD_ZOMPLEX: - for (i = 0 ; i < n ; i++) - { - x = X4x [i + j_n] ; - z = X4z [i + j_n] ; - if ((x != 0) || (z != 0)) - { - Xi [xnz] = i ; - Xx [xnz] = x ; - Xz [xnz] = z ; - xnz++ ; - } - } - break ; - } - - } - else - { - - /* ---------------------------------------------------------- */ - /* X may need to increase in size */ - /* ---------------------------------------------------------- */ - - switch (xtype) - { - - case CHOLMOD_REAL: - for (i = 0 ; i < n ; i++) - { - x = X4x [i + j_n] ; - if (x != 0) - { - EXPAND_AS_NEEDED ; - Xi [xnz] = i ; - Xx [xnz] = x ; - xnz++ ; - } - } - break ; - - case CHOLMOD_COMPLEX: - for (i = 0 ; i < n ; i++) - { - x = X4x [2*(i + j_n) ] ; - z = X4x [2*(i + j_n)+1] ; - if ((x != 0) || (z != 0)) - { - EXPAND_AS_NEEDED ; - Xi [xnz] = i ; - Xx [2*xnz ] = x ; - Xx [2*xnz+1] = z ; - xnz++ ; - } - } - break ; - - case CHOLMOD_ZOMPLEX: - for (i = 0 ; i < n ; i++) - { - x = X4x [i + j_n] ; - z = X4z [i + j_n] ; - if ((x != 0) || (z != 0)) - { - EXPAND_AS_NEEDED ; - Xi [xnz] = i ; - Xx [xnz] = x ; - Xz [xnz] = z ; - xnz++ ; - } - } - break ; - } - - } - } - CHOLMOD(free_dense) (&X4, Common) ; - - /* ------------------------------------------------------------------ */ - /* clear B4 for next iteration */ - /* ------------------------------------------------------------------ */ - - if (jlast < nrhs) - { - - for (j = jfirst ; j < jlast ; j++) - { - p = Bp [j] ; - pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; - j_n = (j-jfirst)*n ; - - switch (B->xtype) - { - - case CHOLMOD_REAL: - for ( ; p < pend ; p++) - { - B4x [Bi [p] + j_n] = 0 ; - } - break ; - - case CHOLMOD_COMPLEX: - for ( ; p < pend ; p++) - { - q = Bi [p] + j_n ; - B4x [2*q ] = 0 ; - B4x [2*q+1] = 0 ; - } - break ; - - case CHOLMOD_ZOMPLEX: - for ( ; p < pend ; p++) - { - q = Bi [p] + j_n ; - B4x [q] = 0 ; - B4z [q] = 0 ; - } - break ; - } - } - } + //---------------------------------------------------------------------- + // adjust the number of columns of B4 + //---------------------------------------------------------------------- + + Int jlast = MIN (nrhs, jfirst + block) ; + B4->ncol = jlast - jfirst ; + + //---------------------------------------------------------------------- + // scatter B(jfirst:jlast-1) into B4 + //---------------------------------------------------------------------- + + switch ((B->xtype + B->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_spsolve_B_scatter_worker (B4, B, jfirst, jlast) ; + break ; + } + + //---------------------------------------------------------------------- + // solve the system (X4 = A\B4 or other system) + //---------------------------------------------------------------------- + + X4 = CHOLMOD(solve) (sys, L, B4, Common) ; + if (Common->status < CHOLMOD_OK) + { + CHOLMOD(free_sparse) (&X, Common) ; + CHOLMOD(free_dense) (&B4, Common) ; + CHOLMOD(free_dense) (&X4, Common) ; + return (NULL) ; + } + ASSERT (X4->xtype == X_xtype) ; + + //---------------------------------------------------------------------- + // append the solution onto X + //---------------------------------------------------------------------- + + bool ok = true ; + + switch ((X->xtype + X->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + ok = rs_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + ok = cs_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + ok = zs_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + ok = rd_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + ok = cd_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + ok = zd_cholmod_spsolve_X_worker (X, X4, jfirst, jlast, &xnz, + Common) ; + break ; + } + + CHOLMOD(free_dense) (&X4, Common) ; + if (!ok) + { + // out of memory + CHOLMOD(free_sparse) (&X, Common) ; + CHOLMOD(free_dense) (&B4, Common) ; + return (NULL) ; + } + + //---------------------------------------------------------------------- + // clear B4 for next iteration + //---------------------------------------------------------------------- + + if (jlast < nrhs) + { + switch ((B->xtype + B->dtype) % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_spsolve_B_clear_worker (B4, B, jfirst, jlast) ; + break ; + } + } } - Xp [nrhs] = xnz ; - - /* ---------------------------------------------------------------------- */ - /* reduce X in size, free workspace, and return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // finalize X, reduce it in size, free workspace, and return result + //-------------------------------------------------------------------------- + Int *Xp = X->p ; + Xp [nrhs] = xnz ; ASSERT (xnz <= X->nzmax) ; CHOLMOD(reallocate_sparse) (xnz, X, Common) ; ASSERT (Common->status == CHOLMOD_OK) ; @@ -392,3 +277,4 @@ cholmod_sparse *CHOLMOD(spsolve) /* returns the sparse solution X */ return (X) ; } #endif + diff --git a/CHOLMOD/Cholesky/t_cholmod_lsolve.c b/CHOLMOD/Cholesky/t_cholmod_lsolve.c deleted file mode 100644 index ed6023f383..0000000000 --- a/CHOLMOD/Cholesky/t_cholmod_lsolve.c +++ /dev/null @@ -1,849 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Cholesky/t_cholmod_lsolve: template for solving Lx=b or LDx=b -//------------------------------------------------------------------------------ - -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis -// All Rights Reserved. -// SPDX-License-Identifier: LGPL-2.1+ - -//------------------------------------------------------------------------------ - -/* Template routine to solve Lx=b with unit or non-unit diagonal, or - * solve LDx=b. - * - * The numeric xtype of L and Y must match. Y contains b on input and x on - * output, stored in row-form. Y is nrow-by-n, where nrow must equal 1 for the - * complex or zomplex cases, and nrow <= 4 for the real case. - * - * This file is not compiled separately. It is included in t_cholmod_solve.c - * instead. It contains no user-callable routines. - * - * workspace: none - * - * Supports real, complex, and zomplex factors. - */ - -/* undefine all prior definitions */ -#undef FORM_NAME -#undef LSOLVE - -/* -------------------------------------------------------------------------- */ -/* define the method */ -/* -------------------------------------------------------------------------- */ - -#ifdef LL -/* LL': solve Lx=b with non-unit diagonal */ -#define FORM_NAME(prefix,rank) prefix ## ll_lsolve_ ## rank - -#elif defined (LD) -/* LDL': solve LDx=b */ -#define FORM_NAME(prefix,rank) prefix ## ldl_ldsolve_ ## rank - -#else -/* LDL': solve Lx=b with unit diagonal */ -#define FORM_NAME(prefix,rank) prefix ## ldl_lsolve_ ## rank - -#endif - -/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */ - -#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank) - -#ifdef REAL - -/* ========================================================================== */ -/* === LSOLVE (1) =========================================================== */ -/* ========================================================================== */ - -/* Solve Lx=b, where b has 1 column */ - -static void LSOLVE (PREFIX,1) -( - cholmod_factor *L, - double X [ ] /* n-by-1 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = 0 ; j < n ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j+1, and j+2) */ - if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y = X [j] ; -#ifdef LL - y /= Lx [p] ; - X [j] = y ; -#elif defined (LD) - X [j] = y / Lx [p] ; -#endif - for (p++ ; p < pend ; p++) - { - X [Li [p]] -= Lx [p] * y ; - } - j++ ; /* advance to next column of L */ - - } - else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2] ; - Int q = Lp [j+1] ; -#ifdef LL - y [0] = X [j] / Lx [p] ; - y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; - X [j ] = y [0] ; - X [j+1] = y [1] ; -#elif defined (LD) - y [0] = X [j] ; - y [1] = X [j+1] - Lx [p+1] * y [0] ; - X [j ] = y [0] / Lx [p] ; - X [j+1] = y [1] / Lx [q] ; -#else - y [0] = X [j] ; - y [1] = X [j+1] - Lx [p+1] * y [0] ; - X [j+1] = y [1] ; -#endif - for (p += 2, q++ ; p < pend ; p++, q++) - { - X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] ; - } - j += 2 ; /* advance to next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3] ; - Int q = Lp [j+1] ; - Int r = Lp [j+2] ; -#ifdef LL - y [0] = X [j] / Lx [p] ; - y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; - y [2] = (X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1]) / Lx [r] ; - X [j ] = y [0] ; - X [j+1] = y [1] ; - X [j+2] = y [2] ; -#elif defined (LD) - y [0] = X [j] ; - y [1] = X [j+1] - Lx [p+1] * y [0] ; - y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; - X [j ] = y [0] / Lx [p] ; - X [j+1] = y [1] / Lx [q] ; - X [j+2] = y [2] / Lx [r] ; -#else - y [0] = X [j] ; - y [1] = X [j+1] - Lx [p+1] * y [0] ; - y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; - X [j+1] = y [1] ; - X [j+2] = y [2] ; -#endif - for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) - { - X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] + Lx [r] * y [2] ; - } - j += 3 ; /* advance to next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (2) =========================================================== */ -/* ========================================================================== */ - -/* Solve Lx=b, where b has 2 columns */ - -static void LSOLVE (PREFIX,2) -( - cholmod_factor *L, - double X [ ][2] /* n-by-2 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = 0 ; j < n ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j+1, and j+2) */ - if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [2] ; - y [0] = X [j][0] ; - y [1] = X [j][1] ; -#ifdef LL - y [0] /= Lx [p] ; - y [1] /= Lx [p] ; - X [j][0] = y [0] ; - X [j][1] = y [1] ; -#elif defined (LD) - X [j][0] = y [0] / Lx [p] ; - X [j][1] = y [1] / Lx [p] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - X [i][0] -= Lx [p] * y [0] ; - X [i][1] -= Lx [p] * y [1] ; - } - j++ ; /* advance to next column of L */ - - } - else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][2] ; - Int q = Lp [j+1] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; -#endif - for (p += 2, q++ ; p < pend ; p++, q++) - { - Int i = Li [p] ; - X [i][0] -= Lx [p] * y [0][0] + Lx [q] * y [1][0] ; - X [i][1] -= Lx [p] * y [0][1] + Lx [q] * y [1][1] ; - } - j += 2 ; /* advance to next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3][2] ; - Int q = Lp [j+1] ; - Int r = Lp [j+2] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; - y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; - y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; - X [j+2][0] = y [2][0] / Lx [r] ; - X [j+2][1] = y [2][1] / Lx [r] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; -#endif - for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - X[i][0] -= Lx[p] * y[0][0] + Lx[q] * y[1][0] + Lx[r] * y[2][0] ; - X[i][1] -= Lx[p] * y[0][1] + Lx[q] * y[1][1] + Lx[r] * y[2][1] ; - } - j += 3 ; /* advance to next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (3) =========================================================== */ -/* ========================================================================== */ - -/* Solve Lx=b, where b has 3 columns */ - -static void LSOLVE (PREFIX,3) -( - cholmod_factor *L, - double X [ ][3] /* n-by-3 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = 0 ; j < n ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j+1, and j+2) */ - if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [3] ; - y [0] = X [j][0] ; - y [1] = X [j][1] ; - y [2] = X [j][2] ; -#ifdef LL - y [0] /= Lx [p] ; - y [1] /= Lx [p] ; - y [2] /= Lx [p] ; - X [j][0] = y [0] ; - X [j][1] = y [1] ; - X [j][2] = y [2] ; -#elif defined (LD) - X [j][0] = y [0] / Lx [p] ; - X [j][1] = y [1] / Lx [p] ; - X [j][2] = y [2] / Lx [p] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - double lx = Lx [p] ; - X [i][0] -= lx * y [0] ; - X [i][1] -= lx * y [1] ; - X [i][2] -= lx * y [2] ; - } - j++ ; /* advance to next column of L */ - - } - else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][3] ; - Int q = Lp [j+1] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; - y [0][2] = X [j][2] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [0][2] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; - y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j ][2] = y [0][2] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; - X [j+1][2] = y [1][2] / Lx [q] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; -#endif - for (p += 2, q++ ; p < pend ; p++, q++) - { - Int i = Li [p] ; - double lx [2] ; - lx [0] = Lx [p] ; - lx [1] = Lx [q] ; - X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; - X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; - X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; - } - j += 2 ; /* advance to next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3][3] ; - Int q = Lp [j+1] ; - Int r = Lp [j+2] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; - y [0][2] = X [j][2] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [0][2] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; - y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; - y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; - y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; - y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; - X [j+2][2] = y [2][2] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j ][2] = y [0][2] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; - X [j+1][2] = y [1][2] / Lx [q] ; - X [j+2][0] = y [2][0] / Lx [r] ; - X [j+2][1] = y [2][1] / Lx [r] ; - X [j+2][2] = y [2][2] / Lx [r] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; - X [j+2][2] = y [2][2] ; -#endif - for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - double lx [3] ; - lx [0] = Lx [p] ; - lx [1] = Lx [q] ; - lx [2] = Lx [r] ; - X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; - X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; - X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; - } - j += 3 ; /* advance to next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (4) =========================================================== */ -/* ========================================================================== */ - -/* Solve Lx=b, where b has 4 columns */ - -static void LSOLVE (PREFIX,4) -( - cholmod_factor *L, - double X [ ][4] /* n-by-4 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = 0 ; j < n ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j+1, and j+2) */ - if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [4] ; - y [0] = X [j][0] ; - y [1] = X [j][1] ; - y [2] = X [j][2] ; - y [3] = X [j][3] ; -#ifdef LL - y [0] /= Lx [p] ; - y [1] /= Lx [p] ; - y [2] /= Lx [p] ; - y [3] /= Lx [p] ; - X [j][0] = y [0] ; - X [j][1] = y [1] ; - X [j][2] = y [2] ; - X [j][3] = y [3] ; -#elif defined (LD) - X [j][0] = y [0] / Lx [p] ; - X [j][1] = y [1] / Lx [p] ; - X [j][2] = y [2] / Lx [p] ; - X [j][3] = y [3] / Lx [p] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - double lx = Lx [p] ; - X [i][0] -= lx * y [0] ; - X [i][1] -= lx * y [1] ; - X [i][2] -= lx * y [2] ; - X [i][3] -= lx * y [3] ; - } - j++ ; /* advance to next column of L */ - - } - else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][4] ; - Int q = Lp [j+1] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; - y [0][2] = X [j][2] ; - y [0][3] = X [j][3] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [0][2] /= Lx [p] ; - y [0][3] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; - y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; - y [1][3] = (X [j+1][3] - Lx [p+1] * y [0][3]) / Lx [q] ; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j ][3] = y [0][3] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+1][3] = y [1][3] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j ][2] = y [0][2] / Lx [p] ; - X [j ][3] = y [0][3] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; - X [j+1][2] = y [1][2] / Lx [q] ; - X [j+1][3] = y [1][3] / Lx [q] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+1][3] = y [1][3] ; -#endif - for (p += 2, q++ ; p < pend ; p++, q++) - { - Int i = Li [p] ; - double lx [2] ; - lx [0] = Lx [p] ; - lx [1] = Lx [q] ; - X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; - X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; - X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; - X [i][3] -= lx [0] * y [0][3] + lx [1] * y [1][3] ; - } - j += 2 ; /* advance to next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3][4] ; - Int q = Lp [j+1] ; - Int r = Lp [j+2] ; - y [0][0] = X [j][0] ; - y [0][1] = X [j][1] ; - y [0][2] = X [j][2] ; - y [0][3] = X [j][3] ; -#ifdef LL - y [0][0] /= Lx [p] ; - y [0][1] /= Lx [p] ; - y [0][2] /= Lx [p] ; - y [0][3] /= Lx [p] ; - y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; - y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; - y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; - y [1][3] = (X [j+1][3] - Lx[p+1] * y[0][3]) / Lx [q] ; - y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; - y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; - y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; - y [2][3] = (X [j+2][3] - Lx[p+2] * y[0][3] - Lx[q+1]*y[1][3])/Lx[r]; - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j ][3] = y [0][3] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+1][3] = y [1][3] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; - X [j+2][2] = y [2][2] ; - X [j+2][3] = y [2][3] ; -#elif defined (LD) - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; - y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; - X [j ][0] = y [0][0] / Lx [p] ; - X [j ][1] = y [0][1] / Lx [p] ; - X [j ][2] = y [0][2] / Lx [p] ; - X [j ][3] = y [0][3] / Lx [p] ; - X [j+1][0] = y [1][0] / Lx [q] ; - X [j+1][1] = y [1][1] / Lx [q] ; - X [j+1][2] = y [1][2] / Lx [q] ; - X [j+1][3] = y [1][3] / Lx [q] ; - X [j+2][0] = y [2][0] / Lx [r] ; - X [j+2][1] = y [2][1] / Lx [r] ; - X [j+2][2] = y [2][2] / Lx [r] ; - X [j+2][3] = y [2][3] / Lx [r] ; -#else - y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; - y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; - y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; - y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; - y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; - y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; - y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; - y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; - X [j+1][0] = y [1][0] ; - X [j+1][1] = y [1][1] ; - X [j+1][2] = y [1][2] ; - X [j+1][3] = y [1][3] ; - X [j+2][0] = y [2][0] ; - X [j+2][1] = y [2][1] ; - X [j+2][2] = y [2][2] ; - X [j+2][3] = y [2][3] ; -#endif - for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - double lx [3] ; - lx [0] = Lx [p] ; - lx [1] = Lx [q] ; - lx [2] = Lx [r] ; - X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; - X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; - X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; - X [i][3] -= lx[0] * y[0][3] + lx[1] * y[1][3] + lx[2] * y[2][3]; - } - j += 3 ; /* advance to next column of L */ - } - } -} - -#endif - - -/* ========================================================================== */ -/* === LSOLVE (k) =========================================================== */ -/* ========================================================================== */ - -static void LSOLVE (PREFIX,k) -( - cholmod_factor *L, - cholmod_dense *Y, /* nr-by-n where nr is 1 to 4 */ - Int *Yseti, Int ysetlen -) -{ - - double yx [2] ; -#ifdef ZOMPLEX - double yz [1] ; - double *Lz = L->z ; - double *Xz = Y->z ; -#endif - double *Lx = L->x ; - double *Xx = Y->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int n = L->n, jj, jjiters ; - - ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ - ASSERT (L->n == Y->ncol) ; /* dimensions must match */ - ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ - ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ - ASSERT (!(L->is_super)) ; /* L is simplicial LL' or LDL' */ - -#ifdef REAL - - if (Yseti == NULL) - { - - /* ------------------------------------------------------------------ */ - /* real case, no Yseti, with 1 to 4 RHS's and dynamic supernodes */ - /* ------------------------------------------------------------------ */ - - ASSERT (Y->nrow <= 4) ; - - switch (Y->nrow) - { - case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; - case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; - case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; - case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; - } - - } - else -#endif - { - - /* ------------------------------------------------------------------ */ - /* solve a complex linear system or solve with Yseti */ - /* ------------------------------------------------------------------ */ - - ASSERT (Y->nrow == 1) ; - - jjiters = Yseti ? ysetlen : n ; - - for (jj = 0 ; jj < jjiters ; jj++) - { - Int j = Yseti ? Yseti [jj] : jj ; - - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* y = X [j] ; */ - ASSIGN (yx,yz,0, Xx,Xz,j) ; - -#ifdef LL - /* y /= Lx [p] ; */ - /* X [j] = y ; */ - DIV_REAL (yx,yz,0, yx,yz,0, Lx,p) ; - ASSIGN (Xx,Xz,j, yx,yz,0) ; -#elif defined (LD) - /* X [j] = y / Lx [p] ; */ - DIV_REAL (Xx,Xz,j, yx,yz,0, Lx,p) ; -#endif - - for (p++ ; p < pend ; p++) - { - /* X [Li [p]] -= Lx [p] * y ; */ - Int i = Li [p] ; - MULTSUB (Xx,Xz,i, Lx,Lz,p, yx,yz,0) ; - } - } - } -} - -/* prepare for the next inclusion of this file in cholmod_solve.c */ -#undef LL -#undef LD diff --git a/CHOLMOD/Cholesky/t_cholmod_lsolve_template.c b/CHOLMOD/Cholesky/t_cholmod_lsolve_template.c new file mode 100644 index 0000000000..ca0cc6098e --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_lsolve_template.c @@ -0,0 +1,847 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_lsolve_template: template for Lx=b or LDx=b +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// Template routine to solve Lx=b with unit or non-unit diagonal, or solve +// LDx=b. +// +// The numeric xtype of L and Y must match. Y contains b on input and x on +// output, stored in row-form. Y is nrow-by-n, where nrow must equal 1 for the +// complex or zomplex cases, and nrow <= 4 for the real case. +// +// This file is not compiled separately. It is included in +// t_cholmod_solve_worker.c instead. It contains no user-callable routines. +// +// workspace: none +// +// Supports real, complex, and zomplex factors, and any dtype. + +// undefine all prior definitions +#undef FORM_NAME +#undef LSOLVE + +//------------------------------------------------------------------------------ +// define the method +//------------------------------------------------------------------------------ + +#ifdef LL +// LL': solve Lx=b with non-unit diagonal +#define FORM_NAME(prefix,rank) prefix ## ll_lsolve_ ## rank + +#elif defined (LD) +// LDL': solve LDx=b +#define FORM_NAME(prefix,rank) prefix ## ldl_ldsolve_ ## rank + +#else +// LDL': solve Lx=b with unit diagonal +#define FORM_NAME(prefix,rank) prefix ## ldl_lsolve_ ## rank + +#endif + +// LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. + +#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank) + +#ifdef REAL + +//------------------------------------------------------------------------------ +// LSOLVE (1) +//------------------------------------------------------------------------------ + +// Solve Lx=b, where b has 1 column. + +static void LSOLVE (PREFIX,1) +( + cholmod_factor *L, + Real X [ ] // n-by-1 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = 0 ; j < n ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j+1, and j+2) + if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y = X [j] ; + #ifdef LL + y /= Lx [p] ; + X [j] = y ; + #elif defined (LD) + X [j] = y / Lx [p] ; + #endif + for (p++ ; p < pend ; p++) + { + X [Li [p]] -= Lx [p] * y ; + } + j++ ; // advance to next column of L + + } + else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2] ; + Int q = Lp [j+1] ; + #ifdef LL + y [0] = X [j] / Lx [p] ; + y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; + X [j ] = y [0] ; + X [j+1] = y [1] ; + #elif defined (LD) + y [0] = X [j] ; + y [1] = X [j+1] - Lx [p+1] * y [0] ; + X [j ] = y [0] / Lx [p] ; + X [j+1] = y [1] / Lx [q] ; + #else + y [0] = X [j] ; + y [1] = X [j+1] - Lx [p+1] * y [0] ; + X [j+1] = y [1] ; + #endif + for (p += 2, q++ ; p < pend ; p++, q++) + { + X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] ; + } + j += 2 ; // advance to next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3] ; + Int q = Lp [j+1] ; + Int r = Lp [j+2] ; + #ifdef LL + y [0] = X [j] / Lx [p] ; + y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; + y [2] = (X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1]) / Lx [r] ; + X [j ] = y [0] ; + X [j+1] = y [1] ; + X [j+2] = y [2] ; + #elif defined (LD) + y [0] = X [j] ; + y [1] = X [j+1] - Lx [p+1] * y [0] ; + y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; + X [j ] = y [0] / Lx [p] ; + X [j+1] = y [1] / Lx [q] ; + X [j+2] = y [2] / Lx [r] ; + #else + y [0] = X [j] ; + y [1] = X [j+1] - Lx [p+1] * y [0] ; + y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; + X [j+1] = y [1] ; + X [j+2] = y [2] ; + #endif + for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) + { + X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] + Lx [r] * y [2] ; + } + j += 3 ; // advance to next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (2) +//------------------------------------------------------------------------------ + +// Solve Lx=b, where b has 2 columns + +static void LSOLVE (PREFIX,2) +( + cholmod_factor *L, + Real X [ ][2] // n-by-2 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = 0 ; j < n ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j+1, and j+2) + if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [2] ; + y [0] = X [j][0] ; + y [1] = X [j][1] ; + #ifdef LL + y [0] /= Lx [p] ; + y [1] /= Lx [p] ; + X [j][0] = y [0] ; + X [j][1] = y [1] ; + #elif defined (LD) + X [j][0] = y [0] / Lx [p] ; + X [j][1] = y [1] / Lx [p] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + X [i][0] -= Lx [p] * y [0] ; + X [i][1] -= Lx [p] * y [1] ; + } + j++ ; // advance to next column of L + + } + else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][2] ; + Int q = Lp [j+1] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + #endif + for (p += 2, q++ ; p < pend ; p++, q++) + { + Int i = Li [p] ; + X [i][0] -= Lx [p] * y [0][0] + Lx [q] * y [1][0] ; + X [i][1] -= Lx [p] * y [0][1] + Lx [q] * y [1][1] ; + } + j += 2 ; // advance to next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3][2] ; + Int q = Lp [j+1] ; + Int r = Lp [j+2] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; + y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; + y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + X [j+2][0] = y [2][0] / Lx [r] ; + X [j+2][1] = y [2][1] / Lx [r] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + #endif + for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + X[i][0] -= Lx[p] * y[0][0] + Lx[q] * y[1][0] + Lx[r] * y[2][0] ; + X[i][1] -= Lx[p] * y[0][1] + Lx[q] * y[1][1] + Lx[r] * y[2][1] ; + } + j += 3 ; // advance to next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (3) +//------------------------------------------------------------------------------ + +// Solve Lx=b, where b has 3 columns + +static void LSOLVE (PREFIX,3) +( + cholmod_factor *L, + Real X [ ][3] // n-by-3 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = 0 ; j < n ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j+1, and j+2) + if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [3] ; + y [0] = X [j][0] ; + y [1] = X [j][1] ; + y [2] = X [j][2] ; + #ifdef LL + y [0] /= Lx [p] ; + y [1] /= Lx [p] ; + y [2] /= Lx [p] ; + X [j][0] = y [0] ; + X [j][1] = y [1] ; + X [j][2] = y [2] ; + #elif defined (LD) + X [j][0] = y [0] / Lx [p] ; + X [j][1] = y [1] / Lx [p] ; + X [j][2] = y [2] / Lx [p] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + Real lx = Lx [p] ; + X [i][0] -= lx * y [0] ; + X [i][1] -= lx * y [1] ; + X [i][2] -= lx * y [2] ; + } + j++ ; // advance to next column of L + + } + else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][3] ; + Int q = Lp [j+1] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + y [0][2] = X [j][2] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [0][2] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; + y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j ][2] = y [0][2] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + X [j+1][2] = y [1][2] / Lx [q] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + #endif + for (p += 2, q++ ; p < pend ; p++, q++) + { + Int i = Li [p] ; + Real lx [2] ; + lx [0] = Lx [p] ; + lx [1] = Lx [q] ; + X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; + X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; + X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; + } + j += 2 ; // advance to next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3][3] ; + Int q = Lp [j+1] ; + Int r = Lp [j+2] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + y [0][2] = X [j][2] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [0][2] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; + y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; + y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; + y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; + y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + X [j+2][2] = y [2][2] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j ][2] = y [0][2] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + X [j+1][2] = y [1][2] / Lx [q] ; + X [j+2][0] = y [2][0] / Lx [r] ; + X [j+2][1] = y [2][1] / Lx [r] ; + X [j+2][2] = y [2][2] / Lx [r] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + X [j+2][2] = y [2][2] ; + #endif + for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + Real lx [3] ; + lx [0] = Lx [p] ; + lx [1] = Lx [q] ; + lx [2] = Lx [r] ; + X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; + X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; + X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; + } + j += 3 ; // advance to next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (4) +//------------------------------------------------------------------------------ + +// Solve Lx=b, where b has 4 columns + +static void LSOLVE (PREFIX,4) +( + cholmod_factor *L, + Real X [ ][4] // n-by-4 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = 0 ; j < n ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j+1, and j+2) + if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [4] ; + y [0] = X [j][0] ; + y [1] = X [j][1] ; + y [2] = X [j][2] ; + y [3] = X [j][3] ; + #ifdef LL + y [0] /= Lx [p] ; + y [1] /= Lx [p] ; + y [2] /= Lx [p] ; + y [3] /= Lx [p] ; + X [j][0] = y [0] ; + X [j][1] = y [1] ; + X [j][2] = y [2] ; + X [j][3] = y [3] ; + #elif defined (LD) + X [j][0] = y [0] / Lx [p] ; + X [j][1] = y [1] / Lx [p] ; + X [j][2] = y [2] / Lx [p] ; + X [j][3] = y [3] / Lx [p] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + Real lx = Lx [p] ; + X [i][0] -= lx * y [0] ; + X [i][1] -= lx * y [1] ; + X [i][2] -= lx * y [2] ; + X [i][3] -= lx * y [3] ; + } + j++ ; // advance to next column of L + + } + else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][4] ; + Int q = Lp [j+1] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + y [0][2] = X [j][2] ; + y [0][3] = X [j][3] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [0][2] /= Lx [p] ; + y [0][3] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; + y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; + y [1][3] = (X [j+1][3] - Lx [p+1] * y [0][3]) / Lx [q] ; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j ][3] = y [0][3] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+1][3] = y [1][3] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j ][2] = y [0][2] / Lx [p] ; + X [j ][3] = y [0][3] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + X [j+1][2] = y [1][2] / Lx [q] ; + X [j+1][3] = y [1][3] / Lx [q] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+1][3] = y [1][3] ; + #endif + for (p += 2, q++ ; p < pend ; p++, q++) + { + Int i = Li [p] ; + Real lx [2] ; + lx [0] = Lx [p] ; + lx [1] = Lx [q] ; + X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; + X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; + X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; + X [i][3] -= lx [0] * y [0][3] + lx [1] * y [1][3] ; + } + j += 2 ; // advance to next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3][4] ; + Int q = Lp [j+1] ; + Int r = Lp [j+2] ; + y [0][0] = X [j][0] ; + y [0][1] = X [j][1] ; + y [0][2] = X [j][2] ; + y [0][3] = X [j][3] ; + #ifdef LL + y [0][0] /= Lx [p] ; + y [0][1] /= Lx [p] ; + y [0][2] /= Lx [p] ; + y [0][3] /= Lx [p] ; + y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; + y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; + y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; + y [1][3] = (X [j+1][3] - Lx[p+1] * y[0][3]) / Lx [q] ; + y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; + y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; + y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; + y [2][3] = (X [j+2][3] - Lx[p+2] * y[0][3] - Lx[q+1]*y[1][3])/Lx[r]; + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j ][3] = y [0][3] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+1][3] = y [1][3] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + X [j+2][2] = y [2][2] ; + X [j+2][3] = y [2][3] ; + #elif defined (LD) + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; + y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; + X [j ][0] = y [0][0] / Lx [p] ; + X [j ][1] = y [0][1] / Lx [p] ; + X [j ][2] = y [0][2] / Lx [p] ; + X [j ][3] = y [0][3] / Lx [p] ; + X [j+1][0] = y [1][0] / Lx [q] ; + X [j+1][1] = y [1][1] / Lx [q] ; + X [j+1][2] = y [1][2] / Lx [q] ; + X [j+1][3] = y [1][3] / Lx [q] ; + X [j+2][0] = y [2][0] / Lx [r] ; + X [j+2][1] = y [2][1] / Lx [r] ; + X [j+2][2] = y [2][2] / Lx [r] ; + X [j+2][3] = y [2][3] / Lx [r] ; + #else + y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; + y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; + y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; + y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; + y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; + y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; + y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; + y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; + X [j+1][0] = y [1][0] ; + X [j+1][1] = y [1][1] ; + X [j+1][2] = y [1][2] ; + X [j+1][3] = y [1][3] ; + X [j+2][0] = y [2][0] ; + X [j+2][1] = y [2][1] ; + X [j+2][2] = y [2][2] ; + X [j+2][3] = y [2][3] ; + #endif + for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + Real lx [3] ; + lx [0] = Lx [p] ; + lx [1] = Lx [q] ; + lx [2] = Lx [r] ; + X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; + X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; + X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; + X [i][3] -= lx[0] * y[0][3] + lx[1] * y[1][3] + lx[2] * y[2][3]; + } + j += 3 ; // advance to next column of L + } + } +} + +#endif + +//------------------------------------------------------------------------------ +// LSOLVE (k) +//------------------------------------------------------------------------------ + +static void LSOLVE (PREFIX,k) +( + cholmod_factor *L, + cholmod_dense *Y, // nr-by-n where nr is 1 to 4 + cholmod_sparse *Yset // input pattern Yset +) +{ + + Real yx [2] ; + #ifdef ZOMPLEX + Real yz [1] ; + Real *Lz = L->z ; + Real *Xz = Y->z ; + #endif + Real *Lx = L->x ; + Real *Xx = Y->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int n = L->n ; + + ASSERT (L->xtype == Y->xtype) ; // L and Y must have the same xtype + ASSERT (L->dtype == Y->dtype) ; // L and Y must have the same dtype + ASSERT (L->n == Y->ncol) ; // dimensions must match + ASSERT (Y->nrow == Y->d) ; // leading dimension of Y = # rows of Y + ASSERT (L->xtype != CHOLMOD_PATTERN) ; // L is not symbolic + ASSERT (!(L->is_super)) ; // L is simplicial LL' or LDL' + +#ifdef REAL + if (Yset == NULL) + { + + //---------------------------------------------------------------------- + // real case, no Yset, with 1 to 4 RHS's and dynamic supernodes + //---------------------------------------------------------------------- + + ASSERT (Y->nrow <= 4) ; + + switch (Y->nrow) + { + case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; + case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; + case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; + case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; + } + + } + else +#endif + { + + //---------------------------------------------------------------------- + // solve a complex linear system or solve with Yset + //---------------------------------------------------------------------- + + ASSERT (Y->nrow == 1) ; + + Int *Ysetp = (Yset == NULL) ? NULL : Yset->p ; + Int *Yseti = (Yset == NULL) ? NULL : Yset->i ; + Int ysetlen = (Yset == NULL) ? n : Ysetp [1] ; + + for (Int jj = 0 ; jj < ysetlen ; jj++) + { + Int j = Yseti ? Yseti [jj] : jj ; + + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // y = X [j] + ASSIGN (yx,yz,0, Xx,Xz,j) ; + + #ifdef LL + // y /= Lx [p] + // X [j] = y + DIV_REAL (yx,yz,0, yx,yz,0, Lx,p) ; + ASSIGN (Xx,Xz,j, yx,yz,0) ; + #elif defined (LD) + // X [j] = y / Lx [p] + DIV_REAL (Xx,Xz,j, yx,yz,0, Lx,p) ; + #endif + + for (p++ ; p < pend ; p++) + { + // X [Li [p]] -= Lx [p] * y + Int i = Li [p] ; + MULTSUB (Xx,Xz,i, Lx,Lz,p, yx,yz,0) ; + } + } + } +} + +// prepare for the next inclusion of this file in cholmod_solve.c +#undef LL +#undef LD + diff --git a/CHOLMOD/Cholesky/t_cholmod_ltsolve.c b/CHOLMOD/Cholesky/t_cholmod_ltsolve.c deleted file mode 100644 index 9cd1f00dfb..0000000000 --- a/CHOLMOD/Cholesky/t_cholmod_ltsolve.c +++ /dev/null @@ -1,848 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Cholesky/t_cholmod_ltsolve: template for solving L'x=b or DL'x=b -//------------------------------------------------------------------------------ - -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis -// All Rights Reserved. -// SPDX-License-Identifier: LGPL-2.1+ - -//------------------------------------------------------------------------------ - -/* Template routine to solve L'x=b with unit or non-unit diagonal, or - * solve DL'x=b. - * - * The numeric xtype of L and Y must match. Y contains b on input and x on - * output, stored in row-form. Y is nrow-by-n, where nrow must equal 1 for the - * complex or zomplex cases, and nrow <= 4 for the real case. - * - * This file is not compiled separately. It is included in t_cholmod_solve.c - * instead. It contains no user-callable routines. - * - * workspace: none - * - * Supports real, complex, and zomplex factors. - */ - -/* undefine all prior definitions */ -#undef FORM_NAME -#undef LSOLVE -#undef DIAG - -/* -------------------------------------------------------------------------- */ -/* define the method */ -/* -------------------------------------------------------------------------- */ - -#ifdef LL -/* LL': solve Lx=b with non-unit diagonal */ -#define FORM_NAME(prefix,rank) prefix ## ll_ltsolve_ ## rank -#define DIAG - -#elif defined (LD) -/* LDL': solve LDx=b */ -#define FORM_NAME(prefix,rank) prefix ## ldl_dltsolve_ ## rank -#define DIAG - -#else -/* LDL': solve Lx=b with unit diagonal */ -#define FORM_NAME(prefix,rank) prefix ## ldl_ltsolve_ ## rank - -#endif - -/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */ -#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank) - -#ifdef REAL - -/* ========================================================================== */ -/* === LSOLVE (1) =========================================================== */ -/* ========================================================================== */ - -/* Solve L'x=b, where b has 1 column */ - -static void LSOLVE (PREFIX,1) -( - cholmod_factor *L, - double X [ ] /* n-by-1 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = n-1 ; j >= 0 ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j-1, and j-2) */ - if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y = X [j] ; -#ifdef DIAG - double d = Lx [p] ; -#endif -#ifdef LD - y /= d ; -#endif - for (p++ ; p < pend ; p++) - { - y -= Lx [p] * X [Li [p]] ; - } -#ifdef LL - X [j] = y / d ; -#else - X [j] = y ; -#endif - j-- ; /* advance to the next column of L */ - - } - else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2], t ; - Int q = Lp [j-1] ; -#ifdef DIAG - double d [2] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; -#endif - t = Lx [q+1] ; -#ifdef LD - y [0] = X [j ] / d [0] ; - y [1] = X [j-1] / d [1] ; -#else - y [0] = X [j ] ; - y [1] = X [j-1] ; -#endif - for (p++, q += 2 ; p < pend ; p++, q++) - { - Int i = Li [p] ; - y [0] -= Lx [p] * X [i] ; - y [1] -= Lx [q] * X [i] ; - } -#ifdef LL - y [0] /= d [0] ; - y [1] = (y [1] - t * y [0]) / d [1] ; -#else - y [1] -= t * y [0] ; -#endif - X [j ] = y [0] ; - X [j-1] = y [1] ; - j -= 2 ; /* advance to the next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3], t [3] ; - Int q = Lp [j-1] ; - Int r = Lp [j-2] ; -#ifdef DIAG - double d [3] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; - d [2] = Lx [r] ; -#endif - t [0] = Lx [q+1] ; - t [1] = Lx [r+1] ; - t [2] = Lx [r+2] ; -#ifdef LD - y [0] = X [j] / d [0] ; - y [1] = X [j-1] / d [1] ; - y [2] = X [j-2] / d [2] ; -#else - y [0] = X [j] ; - y [1] = X [j-1] ; - y [2] = X [j-2] ; -#endif - for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - y [0] -= Lx [p] * X [i] ; - y [1] -= Lx [q] * X [i] ; - y [2] -= Lx [r] * X [i] ; - } -#ifdef LL - y [0] /= d [0] ; - y [1] = (y [1] - t [0] * y [0]) / d [1] ; - y [2] = (y [2] - t [2] * y [0] - t [1] * y [1]) / d [2] ; -#else - y [1] -= t [0] * y [0] ; - y [2] -= t [2] * y [0] + t [1] * y [1] ; -#endif - X [j-2] = y [2] ; - X [j-1] = y [1] ; - X [j ] = y [0] ; - j -= 3 ; /* advance to the next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (2) =========================================================== */ -/* ========================================================================== */ - -/* Solve L'x=b, where b has 2 columns */ - -static void LSOLVE (PREFIX,2) -( - cholmod_factor *L, - double X [ ][2] /* n-by-2 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = n-1 ; j >= 0 ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j-1, and j-2) */ - if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [2] ; -#ifdef DIAG - double d = Lx [p] ; -#endif -#ifdef LD - y [0] = X [j][0] / d ; - y [1] = X [j][1] / d ; -#else - y [0] = X [j][0] ; - y [1] = X [j][1] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - y [0] -= Lx [p] * X [i][0] ; - y [1] -= Lx [p] * X [i][1] ; - } -#ifdef LL - X [j][0] = y [0] / d ; - X [j][1] = y [1] / d ; -#else - X [j][0] = y [0] ; - X [j][1] = y [1] ; -#endif - j-- ; /* advance to the next column of L */ - - } - else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][2], t ; - Int q = Lp [j-1] ; -#ifdef DIAG - double d [2] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; -#endif - t = Lx [q+1] ; -#ifdef LD - y [0][0] = X [j ][0] / d [0] ; - y [0][1] = X [j ][1] / d [0] ; - y [1][0] = X [j-1][0] / d [1] ; - y [1][1] = X [j-1][1] / d [1] ; -#else - y [0][0] = X [j ][0] ; - y [0][1] = X [j ][1] ; - y [1][0] = X [j-1][0] ; - y [1][1] = X [j-1][1] ; -#endif - for (p++, q += 2 ; p < pend ; p++, q++) - { - Int i = Li [p] ; - y [0][0] -= Lx [p] * X [i][0] ; - y [0][1] -= Lx [p] * X [i][1] ; - y [1][0] -= Lx [q] * X [i][0] ; - y [1][1] -= Lx [q] * X [i][1] ; - } -#ifdef LL - y [0][0] /= d [0] ; - y [0][1] /= d [0] ; - y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; - y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; -#else - y [1][0] -= t * y [0][0] ; - y [1][1] -= t * y [0][1] ; -#endif - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j-1][0] = y [1][0] ; - X [j-1][1] = y [1][1] ; - j -= 2 ; /* advance to the next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3][2], t [3] ; - Int q = Lp [j-1] ; - Int r = Lp [j-2] ; -#ifdef DIAG - double d [3] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; - d [2] = Lx [r] ; -#endif - t [0] = Lx [q+1] ; - t [1] = Lx [r+1] ; - t [2] = Lx [r+2] ; -#ifdef LD - y [0][0] = X [j ][0] / d [0] ; - y [0][1] = X [j ][1] / d [0] ; - y [1][0] = X [j-1][0] / d [1] ; - y [1][1] = X [j-1][1] / d [1] ; - y [2][0] = X [j-2][0] / d [2] ; - y [2][1] = X [j-2][1] / d [2] ; -#else - y [0][0] = X [j ][0] ; - y [0][1] = X [j ][1] ; - y [1][0] = X [j-1][0] ; - y [1][1] = X [j-1][1] ; - y [2][0] = X [j-2][0] ; - y [2][1] = X [j-2][1] ; -#endif - for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - y [0][0] -= Lx [p] * X [i][0] ; - y [0][1] -= Lx [p] * X [i][1] ; - y [1][0] -= Lx [q] * X [i][0] ; - y [1][1] -= Lx [q] * X [i][1] ; - y [2][0] -= Lx [r] * X [i][0] ; - y [2][1] -= Lx [r] * X [i][1] ; - } -#ifdef LL - y [0][0] /= d [0] ; - y [0][1] /= d [0] ; - y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; - y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; - y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; - y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; -#else - y [1][0] -= t [0] * y [0][0] ; - y [1][1] -= t [0] * y [0][1] ; - y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; - y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; -#endif - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j-1][0] = y [1][0] ; - X [j-1][1] = y [1][1] ; - X [j-2][0] = y [2][0] ; - X [j-2][1] = y [2][1] ; - j -= 3 ; /* advance to the next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (3) =========================================================== */ -/* ========================================================================== */ - -/* Solve L'x=b, where b has 3 columns */ - -static void LSOLVE (PREFIX,3) -( - cholmod_factor *L, - double X [ ][3] /* n-by-3 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = n-1 ; j >= 0 ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j-1, and j-2) */ - if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [3] ; -#ifdef DIAG - double d = Lx [p] ; -#endif -#ifdef LD - y [0] = X [j][0] / d ; - y [1] = X [j][1] / d ; - y [2] = X [j][2] / d ; -#else - y [0] = X [j][0] ; - y [1] = X [j][1] ; - y [2] = X [j][2] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - y [0] -= Lx [p] * X [i][0] ; - y [1] -= Lx [p] * X [i][1] ; - y [2] -= Lx [p] * X [i][2] ; - } -#ifdef LL - X [j][0] = y [0] / d ; - X [j][1] = y [1] / d ; - X [j][2] = y [2] / d ; -#else - X [j][0] = y [0] ; - X [j][1] = y [1] ; - X [j][2] = y [2] ; -#endif - j-- ; /* advance to the next column of L */ - - } - else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][3], t ; - Int q = Lp [j-1] ; -#ifdef DIAG - double d [2] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; -#endif - t = Lx [q+1] ; -#ifdef LD - y [0][0] = X [j ][0] / d [0] ; - y [0][1] = X [j ][1] / d [0] ; - y [0][2] = X [j ][2] / d [0] ; - y [1][0] = X [j-1][0] / d [1] ; - y [1][1] = X [j-1][1] / d [1] ; - y [1][2] = X [j-1][2] / d [1] ; -#else - y [0][0] = X [j ][0] ; - y [0][1] = X [j ][1] ; - y [0][2] = X [j ][2] ; - y [1][0] = X [j-1][0] ; - y [1][1] = X [j-1][1] ; - y [1][2] = X [j-1][2] ; -#endif - for (p++, q += 2 ; p < pend ; p++, q++) - { - Int i = Li [p] ; - y [0][0] -= Lx [p] * X [i][0] ; - y [0][1] -= Lx [p] * X [i][1] ; - y [0][2] -= Lx [p] * X [i][2] ; - y [1][0] -= Lx [q] * X [i][0] ; - y [1][1] -= Lx [q] * X [i][1] ; - y [1][2] -= Lx [q] * X [i][2] ; - } -#ifdef LL - y [0][0] /= d [0] ; - y [0][1] /= d [0] ; - y [0][2] /= d [0] ; - y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; - y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; - y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; -#else - y [1][0] -= t * y [0][0] ; - y [1][1] -= t * y [0][1] ; - y [1][2] -= t * y [0][2] ; -#endif - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j-1][0] = y [1][0] ; - X [j-1][1] = y [1][1] ; - X [j-1][2] = y [1][2] ; - j -= 2 ; /* advance to the next column of L */ - - } - else - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of three columns of L */ - /* -------------------------------------------------------------- */ - - double y [3][3], t [3] ; - Int q = Lp [j-1] ; - Int r = Lp [j-2] ; -#ifdef DIAG - double d [3] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; - d [2] = Lx [r] ; -#endif - t [0] = Lx [q+1] ; - t [1] = Lx [r+1] ; - t [2] = Lx [r+2] ; -#ifdef LD - y [0][0] = X [j ][0] / d [0] ; - y [0][1] = X [j ][1] / d [0] ; - y [0][2] = X [j ][2] / d [0] ; - y [1][0] = X [j-1][0] / d [1] ; - y [1][1] = X [j-1][1] / d [1] ; - y [1][2] = X [j-1][2] / d [1] ; - y [2][0] = X [j-2][0] / d [2] ; - y [2][1] = X [j-2][1] / d [2] ; - y [2][2] = X [j-2][2] / d [2] ; -#else - y [0][0] = X [j ][0] ; - y [0][1] = X [j ][1] ; - y [0][2] = X [j ][2] ; - y [1][0] = X [j-1][0] ; - y [1][1] = X [j-1][1] ; - y [1][2] = X [j-1][2] ; - y [2][0] = X [j-2][0] ; - y [2][1] = X [j-2][1] ; - y [2][2] = X [j-2][2] ; -#endif - for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) - { - Int i = Li [p] ; - y [0][0] -= Lx [p] * X [i][0] ; - y [0][1] -= Lx [p] * X [i][1] ; - y [0][2] -= Lx [p] * X [i][2] ; - y [1][0] -= Lx [q] * X [i][0] ; - y [1][1] -= Lx [q] * X [i][1] ; - y [1][2] -= Lx [q] * X [i][2] ; - y [2][0] -= Lx [r] * X [i][0] ; - y [2][1] -= Lx [r] * X [i][1] ; - y [2][2] -= Lx [r] * X [i][2] ; - } -#ifdef LL - y [0][0] /= d [0] ; - y [0][1] /= d [0] ; - y [0][2] /= d [0] ; - y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; - y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; - y [1][2] = (y [1][2] - t [0] * y [0][2]) / d [1] ; - y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; - y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; - y [2][2] = (y [2][2] - t [2] * y [0][2] - t [1] * y [1][2]) / d [2]; -#else - y [1][0] -= t [0] * y [0][0] ; - y [1][1] -= t [0] * y [0][1] ; - y [1][2] -= t [0] * y [0][2] ; - y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; - y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; - y [2][2] -= t [2] * y [0][2] + t [1] * y [1][2] ; -#endif - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j-1][0] = y [1][0] ; - X [j-1][1] = y [1][1] ; - X [j-1][2] = y [1][2] ; - X [j-2][0] = y [2][0] ; - X [j-2][1] = y [2][1] ; - X [j-2][2] = y [2][2] ; - j -= 3 ; /* advance to the next column of L */ - } - } -} - - -/* ========================================================================== */ -/* === LSOLVE (4) =========================================================== */ -/* ========================================================================== */ - -/* Solve L'x=b, where b has 4 columns */ - -static void LSOLVE (PREFIX,4) -( - cholmod_factor *L, - double X [ ][4] /* n-by-4 in row form */ -) -{ - double *Lx = L->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int j, n = L->n ; - - for (j = n-1 ; j >= 0 ; ) - { - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* find a chain of supernodes (up to j, j-1, and j-2) */ - if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) - { - - /* -------------------------------------------------------------- */ - /* solve with a single column of L */ - /* -------------------------------------------------------------- */ - - double y [4] ; -#ifdef DIAG - double d = Lx [p] ; -#endif -#ifdef LD - y [0] = X [j][0] / d ; - y [1] = X [j][1] / d ; - y [2] = X [j][2] / d ; - y [3] = X [j][3] / d ; -#else - y [0] = X [j][0] ; - y [1] = X [j][1] ; - y [2] = X [j][2] ; - y [3] = X [j][3] ; -#endif - for (p++ ; p < pend ; p++) - { - Int i = Li [p] ; - y [0] -= Lx [p] * X [i][0] ; - y [1] -= Lx [p] * X [i][1] ; - y [2] -= Lx [p] * X [i][2] ; - y [3] -= Lx [p] * X [i][3] ; - } -#ifdef LL - X [j][0] = y [0] / d ; - X [j][1] = y [1] / d ; - X [j][2] = y [2] / d ; - X [j][3] = y [3] / d ; -#else - X [j][0] = y [0] ; - X [j][1] = y [1] ; - X [j][2] = y [2] ; - X [j][3] = y [3] ; -#endif - j-- ; /* advance to the next column of L */ - - } - else /* if (j == 1 || lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) */ - { - - /* -------------------------------------------------------------- */ - /* solve with a supernode of two columns of L */ - /* -------------------------------------------------------------- */ - - double y [2][4], t ; - Int q = Lp [j-1] ; -#ifdef DIAG - double d [2] ; - d [0] = Lx [p] ; - d [1] = Lx [q] ; -#endif - t = Lx [q+1] ; -#ifdef LD - y [0][0] = X [j ][0] / d [0] ; - y [0][1] = X [j ][1] / d [0] ; - y [0][2] = X [j ][2] / d [0] ; - y [0][3] = X [j ][3] / d [0] ; - y [1][0] = X [j-1][0] / d [1] ; - y [1][1] = X [j-1][1] / d [1] ; - y [1][2] = X [j-1][2] / d [1] ; - y [1][3] = X [j-1][3] / d [1] ; -#else - y [0][0] = X [j ][0] ; - y [0][1] = X [j ][1] ; - y [0][2] = X [j ][2] ; - y [0][3] = X [j ][3] ; - y [1][0] = X [j-1][0] ; - y [1][1] = X [j-1][1] ; - y [1][2] = X [j-1][2] ; - y [1][3] = X [j-1][3] ; -#endif - for (p++, q += 2 ; p < pend ; p++, q++) - { - Int i = Li [p] ; - y [0][0] -= Lx [p] * X [i][0] ; - y [0][1] -= Lx [p] * X [i][1] ; - y [0][2] -= Lx [p] * X [i][2] ; - y [0][3] -= Lx [p] * X [i][3] ; - y [1][0] -= Lx [q] * X [i][0] ; - y [1][1] -= Lx [q] * X [i][1] ; - y [1][2] -= Lx [q] * X [i][2] ; - y [1][3] -= Lx [q] * X [i][3] ; - } -#ifdef LL - y [0][0] /= d [0] ; - y [0][1] /= d [0] ; - y [0][2] /= d [0] ; - y [0][3] /= d [0] ; - y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; - y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; - y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; - y [1][3] = (y [1][3] - t * y [0][3]) / d [1] ; -#else - y [1][0] -= t * y [0][0] ; - y [1][1] -= t * y [0][1] ; - y [1][2] -= t * y [0][2] ; - y [1][3] -= t * y [0][3] ; -#endif - X [j ][0] = y [0][0] ; - X [j ][1] = y [0][1] ; - X [j ][2] = y [0][2] ; - X [j ][3] = y [0][3] ; - X [j-1][0] = y [1][0] ; - X [j-1][1] = y [1][1] ; - X [j-1][2] = y [1][2] ; - X [j-1][3] = y [1][3] ; - j -= 2 ; /* advance to the next column of L */ - } - - /* NOTE: with 4 right-hand-sides, it suffices to exploit dynamic - * supernodes of just size 1 and 2. 3-column supernodes are not - * needed. */ - } -} - -#endif - -/* ========================================================================== */ -/* === LSOLVE (k) =========================================================== */ -/* ========================================================================== */ - -static void LSOLVE (PREFIX,k) -( - cholmod_factor *L, - cholmod_dense *Y, /* nr-by-n where nr is 1 to 4 */ - Int *Yseti, Int ysetlen -) -{ - -#ifdef DIAG - double d [1] ; -#endif - double yx [2] ; -#ifdef ZOMPLEX - double yz [1] ; - double *Lz = L->z ; - double *Xz = Y->z ; -#endif - double *Lx = L->x ; - double *Xx = Y->x ; - Int *Li = L->i ; - Int *Lp = L->p ; - Int *Lnz = L->nz ; - Int n = L->n, jj, jjiters ; - - ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ - ASSERT (L->n == Y->ncol) ; /* dimensions must match */ - ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ - ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ - ASSERT (!(L->is_super)) ; /* L is simplicial LL' or LDL' */ - -#ifdef REAL - - if (Yseti == NULL) - { - - /* ------------------------------------------------------------------ */ - /* real case, no Yseti, with 1 to 4 RHS's and dynamic supernodes */ - /* ------------------------------------------------------------------ */ - - ASSERT (Y->nrow <= 4) ; - switch (Y->nrow) - { - case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; - case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; - case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; - case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; - } - - } - else -#endif - { - - /* ------------------------------------------------------------------ */ - /* solve a complex linear system or solve with Yseti */ - /* ------------------------------------------------------------------ */ - - ASSERT (Y->nrow == 1) ; - - jjiters = Yseti ? ysetlen : n ; - - for (jj = jjiters-1 ; jj >= 0 ; jj--) - { - - Int j = Yseti ? Yseti [jj] : jj ; - - /* get the start, end, and length of column j */ - Int p = Lp [j] ; - Int lnz = Lnz [j] ; - Int pend = p + lnz ; - - /* y = X [j] ; */ - ASSIGN (yx,yz,0, Xx,Xz,j) ; - -#ifdef DIAG - /* d = Lx [p] ; */ - ASSIGN_REAL (d,0, Lx,p) ; -#endif -#ifdef LD - /* y /= d ; */ - DIV_REAL (yx,yz,0, yx,yz,0, d,0) ; -#endif - - for (p++ ; p < pend ; p++) - { - /* y -= conj (Lx [p]) * X [Li [p]] ; */ - Int i = Li [p] ; - MULTSUBCONJ (yx,yz,0, Lx,Lz,p, Xx,Xz,i) ; - } - -#ifdef LL - /* X [j] = y / d ; */ - DIV_REAL (Xx,Xz,j, yx,yz,0, d,0) ; -#else - /* X [j] = y ; */ - ASSIGN (Xx,Xz,j, yx,yz,0) ; -#endif - - } - } -} - -/* prepare for the next inclusion of this file in cholmod_solve.c */ -#undef LL -#undef LD diff --git a/CHOLMOD/Cholesky/t_cholmod_ltsolve_template.c b/CHOLMOD/Cholesky/t_cholmod_ltsolve_template.c new file mode 100644 index 0000000000..ab41630684 --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_ltsolve_template.c @@ -0,0 +1,846 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_ltsolve_template: template for L'x=b or DL'x=b +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// Template routine to solve L'x=b with unit or non-unit diagonal, or solve +// DL'x=b. +// +// The numeric xtype of L and Y must match. Y contains b on input and x on +// output, stored in row-form. Y is nrow-by-n, where nrow must equal 1 for the +// complex or zomplex cases, and nrow <= 4 for the real case. +// +// This file is not compiled separately. It is included in +// t_cholmod_solve_worker.c instead. It contains no user-callable routines. +// +// workspace: none +// +// Supports real, complex, and zomplex factors, and any dtype. + +// undefine all prior definitions +#undef FORM_NAME +#undef LSOLVE +#undef DIAG + +//------------------------------------------------------------------------------ +// define the method +//------------------------------------------------------------------------------ + +#ifdef LL +// LL': solve Lx=b with non-unit diagonal +#define FORM_NAME(prefix,rank) prefix ## ll_ltsolve_ ## rank +#define DIAG + +#elif defined (LD) +// LDL': solve LDx=b +#define FORM_NAME(prefix,rank) prefix ## ldl_dltsolve_ ## rank +#define DIAG + +#else +// LDL': solve Lx=b with unit diagonal +#define FORM_NAME(prefix,rank) prefix ## ldl_ltsolve_ ## rank + +#endif + +// LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. +#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank) + +#ifdef REAL + +//------------------------------------------------------------------------------ +// LSOLVE (1) +//------------------------------------------------------------------------------ + +// Solve L'x=b, where b has 1 column + +static void LSOLVE (PREFIX,1) +( + cholmod_factor *L, + Real X [ ] // n-by-1 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = n-1 ; j >= 0 ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j-1, and j-2) + if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y = X [j] ; + #ifdef DIAG + Real d = Lx [p] ; + #endif + #ifdef LD + y /= d ; + #endif + for (p++ ; p < pend ; p++) + { + y -= Lx [p] * X [Li [p]] ; + } + #ifdef LL + X [j] = y / d ; + #else + X [j] = y ; + #endif + j-- ; // advance to the next column of L + + } + else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2], t ; + Int q = Lp [j-1] ; + #ifdef DIAG + Real d [2] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + #endif + t = Lx [q+1] ; + #ifdef LD + y [0] = X [j ] / d [0] ; + y [1] = X [j-1] / d [1] ; + #else + y [0] = X [j ] ; + y [1] = X [j-1] ; + #endif + for (p++, q += 2 ; p < pend ; p++, q++) + { + Int i = Li [p] ; + y [0] -= Lx [p] * X [i] ; + y [1] -= Lx [q] * X [i] ; + } + #ifdef LL + y [0] /= d [0] ; + y [1] = (y [1] - t * y [0]) / d [1] ; + #else + y [1] -= t * y [0] ; + #endif + X [j ] = y [0] ; + X [j-1] = y [1] ; + j -= 2 ; // advance to the next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3], t [3] ; + Int q = Lp [j-1] ; + Int r = Lp [j-2] ; + #ifdef DIAG + Real d [3] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + d [2] = Lx [r] ; + #endif + t [0] = Lx [q+1] ; + t [1] = Lx [r+1] ; + t [2] = Lx [r+2] ; + #ifdef LD + y [0] = X [j] / d [0] ; + y [1] = X [j-1] / d [1] ; + y [2] = X [j-2] / d [2] ; + #else + y [0] = X [j] ; + y [1] = X [j-1] ; + y [2] = X [j-2] ; + #endif + for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + y [0] -= Lx [p] * X [i] ; + y [1] -= Lx [q] * X [i] ; + y [2] -= Lx [r] * X [i] ; + } + #ifdef LL + y [0] /= d [0] ; + y [1] = (y [1] - t [0] * y [0]) / d [1] ; + y [2] = (y [2] - t [2] * y [0] - t [1] * y [1]) / d [2] ; + #else + y [1] -= t [0] * y [0] ; + y [2] -= t [2] * y [0] + t [1] * y [1] ; + #endif + X [j-2] = y [2] ; + X [j-1] = y [1] ; + X [j ] = y [0] ; + j -= 3 ; // advance to the next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (2) +//------------------------------------------------------------------------------ + +// Solve L'x=b, where b has 2 columns + +static void LSOLVE (PREFIX,2) +( + cholmod_factor *L, + Real X [ ][2] // n-by-2 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = n-1 ; j >= 0 ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j-1, and j-2) + if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [2] ; + #ifdef DIAG + Real d = Lx [p] ; + #endif + #ifdef LD + y [0] = X [j][0] / d ; + y [1] = X [j][1] / d ; + #else + y [0] = X [j][0] ; + y [1] = X [j][1] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + y [0] -= Lx [p] * X [i][0] ; + y [1] -= Lx [p] * X [i][1] ; + } + #ifdef LL + X [j][0] = y [0] / d ; + X [j][1] = y [1] / d ; + #else + X [j][0] = y [0] ; + X [j][1] = y [1] ; + #endif + j-- ; // advance to the next column of L + + } + else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][2], t ; + Int q = Lp [j-1] ; + #ifdef DIAG + Real d [2] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + #endif + t = Lx [q+1] ; + #ifdef LD + y [0][0] = X [j ][0] / d [0] ; + y [0][1] = X [j ][1] / d [0] ; + y [1][0] = X [j-1][0] / d [1] ; + y [1][1] = X [j-1][1] / d [1] ; + #else + y [0][0] = X [j ][0] ; + y [0][1] = X [j ][1] ; + y [1][0] = X [j-1][0] ; + y [1][1] = X [j-1][1] ; + #endif + for (p++, q += 2 ; p < pend ; p++, q++) + { + Int i = Li [p] ; + y [0][0] -= Lx [p] * X [i][0] ; + y [0][1] -= Lx [p] * X [i][1] ; + y [1][0] -= Lx [q] * X [i][0] ; + y [1][1] -= Lx [q] * X [i][1] ; + } + #ifdef LL + y [0][0] /= d [0] ; + y [0][1] /= d [0] ; + y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; + y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; + #else + y [1][0] -= t * y [0][0] ; + y [1][1] -= t * y [0][1] ; + #endif + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j-1][0] = y [1][0] ; + X [j-1][1] = y [1][1] ; + j -= 2 ; // advance to the next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3][2], t [3] ; + Int q = Lp [j-1] ; + Int r = Lp [j-2] ; + #ifdef DIAG + Real d [3] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + d [2] = Lx [r] ; + #endif + t [0] = Lx [q+1] ; + t [1] = Lx [r+1] ; + t [2] = Lx [r+2] ; + #ifdef LD + y [0][0] = X [j ][0] / d [0] ; + y [0][1] = X [j ][1] / d [0] ; + y [1][0] = X [j-1][0] / d [1] ; + y [1][1] = X [j-1][1] / d [1] ; + y [2][0] = X [j-2][0] / d [2] ; + y [2][1] = X [j-2][1] / d [2] ; + #else + y [0][0] = X [j ][0] ; + y [0][1] = X [j ][1] ; + y [1][0] = X [j-1][0] ; + y [1][1] = X [j-1][1] ; + y [2][0] = X [j-2][0] ; + y [2][1] = X [j-2][1] ; + #endif + for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + y [0][0] -= Lx [p] * X [i][0] ; + y [0][1] -= Lx [p] * X [i][1] ; + y [1][0] -= Lx [q] * X [i][0] ; + y [1][1] -= Lx [q] * X [i][1] ; + y [2][0] -= Lx [r] * X [i][0] ; + y [2][1] -= Lx [r] * X [i][1] ; + } + #ifdef LL + y [0][0] /= d [0] ; + y [0][1] /= d [0] ; + y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; + y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; + y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; + y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; + #else + y [1][0] -= t [0] * y [0][0] ; + y [1][1] -= t [0] * y [0][1] ; + y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; + y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; + #endif + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j-1][0] = y [1][0] ; + X [j-1][1] = y [1][1] ; + X [j-2][0] = y [2][0] ; + X [j-2][1] = y [2][1] ; + j -= 3 ; // advance to the next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (3) +//------------------------------------------------------------------------------ + +// Solve L'x=b, where b has 3 columns + +static void LSOLVE (PREFIX,3) +( + cholmod_factor *L, + Real X [ ][3] // n-by-3 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = n-1 ; j >= 0 ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j-1, and j-2) + if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [3] ; + #ifdef DIAG + Real d = Lx [p] ; + #endif + #ifdef LD + y [0] = X [j][0] / d ; + y [1] = X [j][1] / d ; + y [2] = X [j][2] / d ; + #else + y [0] = X [j][0] ; + y [1] = X [j][1] ; + y [2] = X [j][2] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + y [0] -= Lx [p] * X [i][0] ; + y [1] -= Lx [p] * X [i][1] ; + y [2] -= Lx [p] * X [i][2] ; + } + #ifdef LL + X [j][0] = y [0] / d ; + X [j][1] = y [1] / d ; + X [j][2] = y [2] / d ; + #else + X [j][0] = y [0] ; + X [j][1] = y [1] ; + X [j][2] = y [2] ; + #endif + j-- ; // advance to the next column of L + + } + else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][3], t ; + Int q = Lp [j-1] ; + #ifdef DIAG + Real d [2] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + #endif + t = Lx [q+1] ; + #ifdef LD + y [0][0] = X [j ][0] / d [0] ; + y [0][1] = X [j ][1] / d [0] ; + y [0][2] = X [j ][2] / d [0] ; + y [1][0] = X [j-1][0] / d [1] ; + y [1][1] = X [j-1][1] / d [1] ; + y [1][2] = X [j-1][2] / d [1] ; + #else + y [0][0] = X [j ][0] ; + y [0][1] = X [j ][1] ; + y [0][2] = X [j ][2] ; + y [1][0] = X [j-1][0] ; + y [1][1] = X [j-1][1] ; + y [1][2] = X [j-1][2] ; + #endif + for (p++, q += 2 ; p < pend ; p++, q++) + { + Int i = Li [p] ; + y [0][0] -= Lx [p] * X [i][0] ; + y [0][1] -= Lx [p] * X [i][1] ; + y [0][2] -= Lx [p] * X [i][2] ; + y [1][0] -= Lx [q] * X [i][0] ; + y [1][1] -= Lx [q] * X [i][1] ; + y [1][2] -= Lx [q] * X [i][2] ; + } + #ifdef LL + y [0][0] /= d [0] ; + y [0][1] /= d [0] ; + y [0][2] /= d [0] ; + y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; + y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; + y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; + #else + y [1][0] -= t * y [0][0] ; + y [1][1] -= t * y [0][1] ; + y [1][2] -= t * y [0][2] ; + #endif + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j-1][0] = y [1][0] ; + X [j-1][1] = y [1][1] ; + X [j-1][2] = y [1][2] ; + j -= 2 ; // advance to the next column of L + + } + else + { + + //------------------------------------------------------------------ + // solve with a supernode of three columns of L + //------------------------------------------------------------------ + + Real y [3][3], t [3] ; + Int q = Lp [j-1] ; + Int r = Lp [j-2] ; + #ifdef DIAG + Real d [3] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + d [2] = Lx [r] ; + #endif + t [0] = Lx [q+1] ; + t [1] = Lx [r+1] ; + t [2] = Lx [r+2] ; + #ifdef LD + y [0][0] = X [j ][0] / d [0] ; + y [0][1] = X [j ][1] / d [0] ; + y [0][2] = X [j ][2] / d [0] ; + y [1][0] = X [j-1][0] / d [1] ; + y [1][1] = X [j-1][1] / d [1] ; + y [1][2] = X [j-1][2] / d [1] ; + y [2][0] = X [j-2][0] / d [2] ; + y [2][1] = X [j-2][1] / d [2] ; + y [2][2] = X [j-2][2] / d [2] ; + #else + y [0][0] = X [j ][0] ; + y [0][1] = X [j ][1] ; + y [0][2] = X [j ][2] ; + y [1][0] = X [j-1][0] ; + y [1][1] = X [j-1][1] ; + y [1][2] = X [j-1][2] ; + y [2][0] = X [j-2][0] ; + y [2][1] = X [j-2][1] ; + y [2][2] = X [j-2][2] ; + #endif + for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) + { + Int i = Li [p] ; + y [0][0] -= Lx [p] * X [i][0] ; + y [0][1] -= Lx [p] * X [i][1] ; + y [0][2] -= Lx [p] * X [i][2] ; + y [1][0] -= Lx [q] * X [i][0] ; + y [1][1] -= Lx [q] * X [i][1] ; + y [1][2] -= Lx [q] * X [i][2] ; + y [2][0] -= Lx [r] * X [i][0] ; + y [2][1] -= Lx [r] * X [i][1] ; + y [2][2] -= Lx [r] * X [i][2] ; + } + #ifdef LL + y [0][0] /= d [0] ; + y [0][1] /= d [0] ; + y [0][2] /= d [0] ; + y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; + y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; + y [1][2] = (y [1][2] - t [0] * y [0][2]) / d [1] ; + y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; + y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; + y [2][2] = (y [2][2] - t [2] * y [0][2] - t [1] * y [1][2]) / d [2]; + #else + y [1][0] -= t [0] * y [0][0] ; + y [1][1] -= t [0] * y [0][1] ; + y [1][2] -= t [0] * y [0][2] ; + y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; + y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; + y [2][2] -= t [2] * y [0][2] + t [1] * y [1][2] ; + #endif + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j-1][0] = y [1][0] ; + X [j-1][1] = y [1][1] ; + X [j-1][2] = y [1][2] ; + X [j-2][0] = y [2][0] ; + X [j-2][1] = y [2][1] ; + X [j-2][2] = y [2][2] ; + j -= 3 ; // advance to the next column of L + } + } +} + +//------------------------------------------------------------------------------ +// LSOLVE (4) +//------------------------------------------------------------------------------ + +// Solve L'x=b, where b has 4 columns + +static void LSOLVE (PREFIX,4) +( + cholmod_factor *L, + Real X [ ][4] // n-by-4 in row form +) +{ + Real *Lx = L->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int j, n = L->n ; + + for (j = n-1 ; j >= 0 ; ) + { + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // find a chain of supernodes (up to j, j-1, and j-2) + if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) + { + + //------------------------------------------------------------------ + // solve with a single column of L + //------------------------------------------------------------------ + + Real y [4] ; + #ifdef DIAG + Real d = Lx [p] ; + #endif + #ifdef LD + y [0] = X [j][0] / d ; + y [1] = X [j][1] / d ; + y [2] = X [j][2] / d ; + y [3] = X [j][3] / d ; + #else + y [0] = X [j][0] ; + y [1] = X [j][1] ; + y [2] = X [j][2] ; + y [3] = X [j][3] ; + #endif + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + y [0] -= Lx [p] * X [i][0] ; + y [1] -= Lx [p] * X [i][1] ; + y [2] -= Lx [p] * X [i][2] ; + y [3] -= Lx [p] * X [i][3] ; + } + #ifdef LL + X [j][0] = y [0] / d ; + X [j][1] = y [1] / d ; + X [j][2] = y [2] / d ; + X [j][3] = y [3] / d ; + #else + X [j][0] = y [0] ; + X [j][1] = y [1] ; + X [j][2] = y [2] ; + X [j][3] = y [3] ; + #endif + j-- ; // advance to the next column of L + + } + else // if (j == 1 || lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) + { + + //------------------------------------------------------------------ + // solve with a supernode of two columns of L + //------------------------------------------------------------------ + + Real y [2][4], t ; + Int q = Lp [j-1] ; + #ifdef DIAG + Real d [2] ; + d [0] = Lx [p] ; + d [1] = Lx [q] ; + #endif + t = Lx [q+1] ; + #ifdef LD + y [0][0] = X [j ][0] / d [0] ; + y [0][1] = X [j ][1] / d [0] ; + y [0][2] = X [j ][2] / d [0] ; + y [0][3] = X [j ][3] / d [0] ; + y [1][0] = X [j-1][0] / d [1] ; + y [1][1] = X [j-1][1] / d [1] ; + y [1][2] = X [j-1][2] / d [1] ; + y [1][3] = X [j-1][3] / d [1] ; + #else + y [0][0] = X [j ][0] ; + y [0][1] = X [j ][1] ; + y [0][2] = X [j ][2] ; + y [0][3] = X [j ][3] ; + y [1][0] = X [j-1][0] ; + y [1][1] = X [j-1][1] ; + y [1][2] = X [j-1][2] ; + y [1][3] = X [j-1][3] ; + #endif + for (p++, q += 2 ; p < pend ; p++, q++) + { + Int i = Li [p] ; + y [0][0] -= Lx [p] * X [i][0] ; + y [0][1] -= Lx [p] * X [i][1] ; + y [0][2] -= Lx [p] * X [i][2] ; + y [0][3] -= Lx [p] * X [i][3] ; + y [1][0] -= Lx [q] * X [i][0] ; + y [1][1] -= Lx [q] * X [i][1] ; + y [1][2] -= Lx [q] * X [i][2] ; + y [1][3] -= Lx [q] * X [i][3] ; + } + #ifdef LL + y [0][0] /= d [0] ; + y [0][1] /= d [0] ; + y [0][2] /= d [0] ; + y [0][3] /= d [0] ; + y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; + y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; + y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; + y [1][3] = (y [1][3] - t * y [0][3]) / d [1] ; + #else + y [1][0] -= t * y [0][0] ; + y [1][1] -= t * y [0][1] ; + y [1][2] -= t * y [0][2] ; + y [1][3] -= t * y [0][3] ; + #endif + X [j ][0] = y [0][0] ; + X [j ][1] = y [0][1] ; + X [j ][2] = y [0][2] ; + X [j ][3] = y [0][3] ; + X [j-1][0] = y [1][0] ; + X [j-1][1] = y [1][1] ; + X [j-1][2] = y [1][2] ; + X [j-1][3] = y [1][3] ; + j -= 2 ; // advance to the next column of L + } + + // NOTE: with 4 right-hand-sides, it suffices to exploit dynamic + // supernodes of just size 1 and 2. 3-column supernodes are not + // needed. + } +} + +#endif + +//------------------------------------------------------------------------------ +// LSOLVE (k) +//------------------------------------------------------------------------------ + +static void LSOLVE (PREFIX,k) +( + cholmod_factor *L, + cholmod_dense *Y, // nr-by-n where nr is 1 to 4 + cholmod_sparse *Yset // input pattern Yset +) +{ + + #ifdef DIAG + Real d [1] ; + #endif + Real yx [2] ; + #ifdef ZOMPLEX + Real yz [1] ; + Real *Lz = L->z ; + Real *Xz = Y->z ; + #endif + Real *Lx = L->x ; + Real *Xx = Y->x ; + Int *Li = L->i ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int n = L->n ; + + ASSERT (L->xtype == Y->xtype) ; // L and Y must have the same xtype + ASSERT (L->dtype == Y->dtype) ; // L and Y must have the same dtype + ASSERT (L->n == Y->ncol) ; // dimensions must match + ASSERT (Y->nrow == Y->d) ; // leading dimension of Y = # rows of Y + ASSERT (L->xtype != CHOLMOD_PATTERN) ; // L is not symbolic + ASSERT (!(L->is_super)) ; // L is simplicial LL' or LDL' + +#ifdef REAL + if (Yset == NULL) + { + + //---------------------------------------------------------------------- + // real case, no Yset, with 1 to 4 RHS's and dynamic supernodes + //---------------------------------------------------------------------- + + ASSERT (Y->nrow <= 4) ; + switch (Y->nrow) + { + case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; + case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; + case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; + case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; + } + + } + else +#endif + { + + //---------------------------------------------------------------------- + // solve a complex linear system or solve with Yset + //---------------------------------------------------------------------- + + ASSERT (Y->nrow == 1) ; + + Int *Ysetp = (Yset == NULL) ? NULL : Yset->p ; + Int *Yseti = (Yset == NULL) ? NULL : Yset->i ; + Int ysetlen = (Yset == NULL) ? n : Ysetp [1] ; + + for (Int jj = ysetlen-1 ; jj >= 0 ; jj--) + { + + Int j = Yseti ? Yseti [jj] : jj ; + + // get the start, end, and length of column j + Int p = Lp [j] ; + Int lnz = Lnz [j] ; + Int pend = p + lnz ; + + // y = X [j] + ASSIGN (yx,yz,0, Xx,Xz,j) ; + + #ifdef DIAG + // d = Lx [p] + ASSIGN_REAL (d,0, Lx,p) ; + #endif + #ifdef LD + // y /= d + DIV_REAL (yx,yz,0, yx,yz,0, d,0) ; + #endif + + for (p++ ; p < pend ; p++) + { + // y -= conj (Lx [p]) * X [Li [p]] + Int i = Li [p] ; + MULTSUBCONJ (yx,yz,0, Lx,Lz,p, Xx,Xz,i) ; + } + + #ifdef LL + // X [j] = y / d + DIV_REAL (Xx,Xz,j, yx,yz,0, d,0) ; + #else + // X [j] = y + ASSIGN (Xx,Xz,j, yx,yz,0) ; + #endif + } + } +} + +// prepare for the next inclusion of this file in cholmod_solve.c +#undef LL +#undef LD + diff --git a/CHOLMOD/Cholesky/t_cholmod_psolve_worker.c b/CHOLMOD/Cholesky/t_cholmod_psolve_worker.c new file mode 100644 index 0000000000..9b12234830 --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_psolve_worker.c @@ -0,0 +1,838 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_psolve_worker: permutations for cholmod_solve +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// This worker is included just twice into cholmod_solve.c, for both dtypes. +// Each method below handles all xtypes (real, complex, and zomplex) itself. + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// perm +//------------------------------------------------------------------------------ + +// Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1) where B is nrow-by-ncol. +// +// Creates a permuted copy of a contiguous set of columns of B. +// Y is already allocated on input. Y must be of sufficient size. Let nk be +// the number of columns accessed in B. Y->xtype determines the complexity of +// the result. +// +// If B is real and Y is complex (or zomplex), only the real part of B is +// copied into Y. The imaginary part of Y is set to zero. +// +// If B is complex (or zomplex) and Y is real, both the real and imaginary and +// parts of B are returned in Y. Y is returned as nrow-by-2*nk. The even +// columns of Y contain the real part of B and the odd columns contain the +// imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is +// returned as nrow-by-nk with leading dimension nrow. Y->nzmax must be >= +// nrow*nk. +// +// The case where the input (B) is real and the output (Y) is zomplex is +// not used. + +static void TEMPLATE_DTYPE (perm) +( + // input: + cholmod_dense *B, // input matrix B + Int *Perm, // optional input permutation (can be NULL) + Int k1, // first column of B to copy + Int ncols, // last column to copy is min(k1+ncols,B->ncol)-1 + // input/output: + cholmod_dense *Y // output matrix Y, already allocated +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Yx, *Yz, *Bx, *Bz ; + Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; + size_t dual ; + + ncol = B->ncol ; + nrow = B->nrow ; + k2 = MIN (k1+ncols, ncol) ; + nk = MAX (k2 - k1, 0) ; + dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; + d = B->d ; + Bx = B->x ; + Bz = B->z ; + Yx = Y->x ; + Yz = Y->z ; + Y->nrow = nrow ; + Y->ncol = dual*nk ; + Y->d = nrow ; + ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; + ASSERT (Y->dtype == B->dtype) ; + + //-------------------------------------------------------------------------- + // Y = B (P (1:nrow), k1:k2-1) + //-------------------------------------------------------------------------- + + switch (Y->xtype) + { + + case CHOLMOD_REAL: + + switch (B->xtype) + { + + case CHOLMOD_REAL: + // Y real, B real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [k + j2] = Bx [p] ; // real + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y real, B complex. Y is nrow-by-2*nk + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [k + j2 ] = Bx [2*p ] ; // real + Yx [k + j2 + nrow] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y real, B zomplex. Y is nrow-by-2*nk + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [k + j2 ] = Bx [p] ; // real + Yx [k + j2 + nrow] = Bz [p] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_COMPLEX: + + switch (B->xtype) + { + + case CHOLMOD_REAL: + // Y complex, B real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [2*k + j2] = Bx [p] ; // real + Yx [2*k+1 + j2] = 0 ; // imag + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y complex, B complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [2*k + j2] = Bx [2*p ] ; // real + Yx [2*k+1 + j2] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y complex, B zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [2*k + j2] = Bx [p] ; // real + Yx [2*k+1 + j2] = Bz [p] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_ZOMPLEX: + + switch (B->xtype) + { + + case CHOLMOD_COMPLEX: + // Y zomplex, B complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [k + j2] = Bx [2*p ] ; // real + Yz [k + j2] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y zomplex, B zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [k + j2] = Bx [p] ; // real + Yz [k + j2] = Bz [p] ; // imag + } + } + break ; + + } + break ; + } +} + +//------------------------------------------------------------------------------ +// iperm +//------------------------------------------------------------------------------ + +// X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y where X is nrow-by-ncol. +// +// Copies and permutes Y into a contiguous set of columns of X. X is already +// allocated on input. Y must be of sufficient size. Let nk be the number +// of columns accessed in X. X->xtype determines the complexity of the result. +// +// If X is real and Y is complex (or zomplex), only the real part of B is +// copied into X. The imaginary part of Y is ignored. +// +// If X is complex (or zomplex) and Y is real, both the real and imaginary and +// parts of Y are returned in X. Y is nrow-by-2*nk. The even +// columns of Y contain the real part of B and the odd columns contain the +// imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is +// nrow-by-nk with leading dimension nrow. Y->nzmax must be >= nrow*nk. +// +// The case where the input (Y) is complex and the output (X) is real, +// and the case where the input (Y) is zomplex and the output (X) is real, +// are not used. + +static void TEMPLATE_DTYPE (iperm) +( + // input: + cholmod_dense *Y, // input matrix Y + Int *Perm, // optional input permutation (can be NULL) + Int k1, // first column of B to copy + Int ncols, // last column to copy is min(k1+ncols,B->ncol)-1 + // input/output: + cholmod_dense *X // output matrix X, already allocated +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Yx, *Yz, *Xx, *Xz ; + Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; + + ncol = X->ncol ; + nrow = X->nrow ; + k2 = MIN (k1+ncols, ncol) ; + nk = MAX (k2 - k1, 0) ; + d = X->d ; + Xx = X->x ; + Xz = X->z ; + Yx = Y->x ; + Yz = Y->z ; + ASSERT (((Int) Y->nzmax) >= nrow*nk* + ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; + ASSERT (Y->dtype == X->dtype) ; + + //-------------------------------------------------------------------------- + // X (P (1:nrow), k1:k2-1) = Y + //-------------------------------------------------------------------------- + + switch (Y->xtype) + { + + case CHOLMOD_REAL: + + switch (X->xtype) + { + + case CHOLMOD_REAL: + // Y real, X real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [k + j2] ; // real + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y real, X complex. Y is nrow-by-2*nk + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [k + j2 ] ; // real + Xx [2*p+1] = Yx [k + j2 + nrow] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y real, X zomplex. Y is nrow-by-2*nk + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [k + j2 ] ; // real + Xz [p] = Yx [k + j2 + nrow] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_COMPLEX: + + switch (X->xtype) + { + + case CHOLMOD_COMPLEX: + // Y complex, X complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [2*k + j2] ; // real + Xx [2*p+1] = Yx [2*k+1 + j2] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y complex, X zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * 2 * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [2*k + j2] ; // real + Xz [p] = Yx [2*k+1 + j2] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_ZOMPLEX: + + switch (X->xtype) + { + + case CHOLMOD_COMPLEX: + // Y zomplex, X complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [k + j2] ; // real + Xx [2*p+1] = Yz [k + j2] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y zomplex, X zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = nrow * (j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [k + j2] ; // real + Xz [p] = Yz [k + j2] ; // imag + } + } + break ; + + } + break ; + } +} + +//------------------------------------------------------------------------------ +// ptrans +//------------------------------------------------------------------------------ + +// Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1)' where B is nrow-by-ncol. +// +// Creates a permuted and transposed copy of a contiguous set of columns of B. +// Y is already allocated on input. Y must be of sufficient size. Let nk be +// the number of columns accessed in B. Y->xtype determines the complexity of +// the result. +// +// If B is real and Y is complex (or zomplex), only the real part of B is +// copied into Y. The imaginary part of Y is set to zero. +// +// If B is complex (or zomplex) and Y is real, both the real and imaginary and +// parts of B are returned in Y. Y is returned as 2*nk-by-nrow. The even +// rows of Y contain the real part of B and the odd rows contain the +// imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is +// returned as nk-by-nrow with leading dimension nk. Y->nzmax must be >= +// nrow*nk. +// +// The array transpose is performed, not the complex conjugate transpose. + +static void TEMPLATE_DTYPE (ptrans) +( + // input: + cholmod_dense *B, // input matrix B + Int *Perm, // optional input permutation (can be NULL) + Int k1, // first column of B to copy + Int ncols, // last column to copy is min(k1+ncols,B->ncol)-1 + // input/output: + cholmod_dense *Y // output matrix Y, already allocated +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Yx, *Yz, *Bx, *Bz ; + Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; + size_t dual ; + + ncol = B->ncol ; + nrow = B->nrow ; + k2 = MIN (k1+ncols, ncol) ; + nk = MAX (k2 - k1, 0) ; + dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; + d = B->d ; + Bx = B->x ; + Bz = B->z ; + Yx = Y->x ; + Yz = Y->z ; + Y->nrow = dual*nk ; + Y->ncol = nrow ; + Y->d = dual*nk ; + ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; + ASSERT (Y->dtype == B->dtype) ; + + //-------------------------------------------------------------------------- + // Y = B (P (1:nrow), k1:k2-1)' + //-------------------------------------------------------------------------- + + switch (Y->xtype) + { + + case CHOLMOD_REAL: + + switch (B->xtype) + { + + case CHOLMOD_REAL: + // Y real, B real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*nk] = Bx [p] ; // real + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y real, B complex. Y is 2*nk-by-nrow + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*2*nk] = Bx [2*p ] ; // real + Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y real, B zomplex. Y is 2*nk-by-nrow + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*2*nk] = Bx [p] ; // real + Yx [j2+1 + k*2*nk] = Bz [p] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_COMPLEX: + + switch (B->xtype) + { + + case CHOLMOD_REAL: + // Y complex, B real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*2*nk] = Bx [p] ; // real + Yx [j2+1 + k*2*nk] = 0 ; // imag + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y complex, B complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*2*nk] = Bx [2*p ] ; // real + Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y complex, B zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*2*nk] = Bx [p] ; // real + Yx [j2+1 + k*2*nk] = Bz [p] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_ZOMPLEX: + + switch (B->xtype) + { + + case CHOLMOD_REAL: + // Y zomplex, B real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*nk] = Bx [p] ; // real + Yz [j2 + k*nk] = 0 ; // imag + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y zomplex, B complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*nk] = Bx [2*p ] ; // real + Yz [j2 + k*nk] = Bx [2*p+1] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y zomplex, B zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Yx [j2 + k*nk] = Bx [p] ; // real + Yz [j2 + k*nk] = Bz [p] ; // imag + } + } + break ; + + } + break ; + } +} + +//------------------------------------------------------------------------------ +// iptrans +//------------------------------------------------------------------------------ + +// X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y' where X is nrow-by-ncol. +// +// Copies into a permuted and transposed contiguous set of columns of X. +// X is already allocated on input. Y must be of sufficient size. Let nk be +// the number of columns accessed in X. X->xtype determines the complexity of +// the result. +// +// If X is real and Y is complex (or zomplex), only the real part of Y is +// copied into X. The imaginary part of Y is ignored. +// +// If X is complex (or zomplex) and Y is real, both the real and imaginary and +// parts of X are returned in Y. Y is 2*nk-by-nrow. The even +// rows of Y contain the real part of X and the odd rows contain the +// imaginary part of X. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is +// nk-by-nrow with leading dimension nk. Y->nzmax must be >= nrow*nk. +// +// The case where Y is complex or zomplex, and X is real, is not used. +// +// The array transpose is performed, not the complex conjugate transpose. + +static void TEMPLATE_DTYPE (iptrans) +( + // input: + cholmod_dense *Y, // input matrix Y + Int *Perm, // optional input permutation (can be NULL) + Int k1, // first column of X to copy into + Int ncols, // last column to copy is min(k1+ncols,X->ncol)-1 + // input/output: + cholmod_dense *X // output matrix X, already allocated +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Yx, *Yz, *Xx, *Xz ; + Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; + + ncol = X->ncol ; + nrow = X->nrow ; + k2 = MIN (k1+ncols, ncol) ; + nk = MAX (k2 - k1, 0) ; + d = X->d ; + Xx = X->x ; + Xz = X->z ; + Yx = Y->x ; + Yz = Y->z ; + ASSERT (((Int) Y->nzmax) >= nrow*nk* + ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; + ASSERT (Y->dtype == X->dtype) ; + + //-------------------------------------------------------------------------- + // X (P (1:nrow), k1:k2-1) = Y' + //-------------------------------------------------------------------------- + + switch (Y->xtype) + { + + case CHOLMOD_REAL: + + switch (X->xtype) + { + + case CHOLMOD_REAL: + // Y real, X real + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [j2 + k*nk] ; // real + } + } + break ; + + case CHOLMOD_COMPLEX: + // Y real, X complex. Y is 2*nk-by-nrow + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [j2 + k*2*nk] ; // real + Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y real, X zomplex. Y is 2*nk-by-nrow + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [j2 + k*2*nk] ; // real + Xz [p] = Yx [j2+1 + k*2*nk] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_COMPLEX: + + switch (X->xtype) + { + + case CHOLMOD_COMPLEX: + // Y complex, X complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [j2 + k*2*nk] ; // real + Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y complex, X zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = 2*(j-k1) ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [j2 + k*2*nk] ; // real + Xz [p] = Yx [j2+1 + k*2*nk] ; // imag + } + } + break ; + + } + break ; + + case CHOLMOD_ZOMPLEX: + + switch (X->xtype) + { + + case CHOLMOD_COMPLEX: + // Y zomplex, X complex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [2*p ] = Yx [j2 + k*nk] ; // real + Xx [2*p+1] = Yz [j2 + k*nk] ; // imag + } + } + break ; + + case CHOLMOD_ZOMPLEX: + // Y zomplex, X zomplex + for (j = k1 ; j < k2 ; j++) + { + dj = d*j ; + j2 = j-k1 ; + for (k = 0 ; k < nrow ; k++) + { + p = P(k) + dj ; + Xx [p] = Yx [j2 + k*nk] ; // real + Xz [p] = Yz [j2 + k*nk] ; // imag + } + } + break ; + + } + break ; + } +} + diff --git a/CHOLMOD/Cholesky/t_cholmod_rcond_worker.c b/CHOLMOD/Cholesky/t_cholmod_rcond_worker.c new file mode 100644 index 0000000000..d7fd2bfb58 --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_rcond_worker.c @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_rcond_worker: estimate rcond of a factorization +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// Return a rough estimate of the reciprocal of the condition number. + +//------------------------------------------------------------------------------ +// LMINMAX macros +//------------------------------------------------------------------------------ + +// Update lmin and lmax for one entry L(j,j) + +#define FIRST_LMINMAX(Ljj,lmin,lmax) \ +{ \ + Real ljj = Ljj ; \ + if (isnan (ljj)) \ + { \ + return (0) ; \ + } \ + lmin = ljj ; \ + lmax = ljj ; \ +} + +#define LMINMAX(Ljj,lmin,lmax) \ +{ \ + Real ljj = Ljj ; \ + if (isnan (ljj)) \ + { \ + return (0) ; \ + } \ + if (ljj < lmin) \ + { \ + lmin = ljj ; \ + } \ + else if (ljj > lmax) \ + { \ + lmax = ljj ; \ + } \ +} + +//------------------------------------------------------------------------------ +// t_cholmod_rcond_worker +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static double TEMPLATE (cholmod_rcond_worker) +( + cholmod_factor *L +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real lmin = 0 ; + Real lmax = 0 ; + Real *Lx = L->x ; + Int n = L->n ; + Int e = (L->xtype == CHOLMOD_COMPLEX) ? 2 : 1 ; + + //-------------------------------------------------------------------------- + // compute the approximate rcond of L + //-------------------------------------------------------------------------- + + if (L->is_super) + { + + //---------------------------------------------------------------------- + // L is supernodal + //---------------------------------------------------------------------- + + Int nsuper = L->nsuper ; // number of supernodes in L + Int *Lpi = L->pi ; // column pointers for integer pattern + Int *Lpx = L->px ; // column pointers for numeric values + Int *Super = L->super ; // supernode sizes + FIRST_LMINMAX (Lx [0], lmin, lmax) ; // first diagonal entry of L + for (Int s = 0 ; s < nsuper ; s++) + { + Int k1 = Super [s] ; // first column in supernode s + Int k2 = Super [s+1] ; // last column in supernode is k2-1 + Int psi = Lpi [s] ; // first row index is L->s [psi] + Int psend = Lpi [s+1] ; // last row index is L->s [psend-1] + Int psx = Lpx [s] ; // first numeric entry is Lx [psx] + Int nsrow = psend - psi ; // supernode is nsrow-by-nscol + Int nscol = k2 - k1 ; + for (Int jj = 0 ; jj < nscol ; jj++) + { + LMINMAX (Lx [e * (psx + jj + jj*nsrow)], lmin, lmax) ; + } + } + } + else + { + + //---------------------------------------------------------------------- + // L is simplicial + //---------------------------------------------------------------------- + + Int *Lp = L->p ; + if (L->is_ll) + { + // LL' factorization + FIRST_LMINMAX (Lx [Lp [0]], lmin, lmax) ; + for (Int j = 1 ; j < n ; j++) + { + LMINMAX (Lx [e * Lp [j]], lmin, lmax) ; + } + } + else + { + // LDL' factorization, the diagonal might be negative + FIRST_LMINMAX (fabs (Lx [Lp [0]]), lmin, lmax) ; + for (Int j = 1 ; j < n ; j++) + { + LMINMAX (fabs (Lx [e * Lp [j]]), lmin, lmax) ; + } + } + } + + double rcond = ((double) lmin) / ((double) lmax) ; + if (L->is_ll) + { + rcond = rcond*rcond ; + } + return (rcond) ; +} + +#undef LMINMAX +#undef FIRST_LMINMAX + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Cholesky/t_cholmod_resymbol_worker.c b/CHOLMOD/Cholesky/t_cholmod_resymbol_worker.c new file mode 100644 index 0000000000..3b3d07a6c4 --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_resymbol_worker.c @@ -0,0 +1,206 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_resymbol_worker: recompute symbolic pattern of L +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_resymbol_worker) +( + cholmod_sparse *A, + bool pack, + cholmod_factor *L, + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int nrow = A->nrow ; + + Int *Ai = A->i ; + Int *Ap = A->p ; + Int *Anz = A->nz ; + bool apacked = A->packed ; + bool sorted = A->sorted ; + int stype = A->stype ; + + Int *Li = L->i ; + Real *Lx = L->x ; + Real *Lz = L->z ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + + Int *Flag = Common->Flag ; // size nrow + Int *Head = Common->Head ; // size nrow+1 + Int *Iwork = Common->Iwork ; + Int *Link = Iwork ; // size nrow + Int *Anext = Iwork + nrow ; // size ncol, unsym. only + + Int pdest = 0 ; + + //-------------------------------------------------------------------------- + // resymbol + //-------------------------------------------------------------------------- + + for (Int k = 0 ; k < nrow ; k++) + { + + #ifndef NDEBUG + PRINT1 (("\n\n================== Initial column k = "ID"\n", k)) ; + for (Int p = Lp [k] ; p < Lp [k] + Lnz [k] ; p++) + { + PRINT1 ((" row: "ID" value: ", Li [p])) ; + PRINT1 (("\n")) ; + } + PRINT1 (("Recomputing LDL, column k = "ID"\n", k)) ; + #endif + + //---------------------------------------------------------------------- + // compute column k of I+F*F' or I+A + //---------------------------------------------------------------------- + + // flag the diagonal entry + CLEAR_FLAG (Common) ; + Int mark = Common->mark ; + + Flag [k] = mark ; + PRINT1 (("row: "ID" (diagonal)\n", k)) ; + + if (stype != 0) + { + // merge column k of A into Flag (lower triangular part only) + Int p = Ap [k] ; + Int pend = (apacked) ? (Ap [k+1]) : (p + Anz [k]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i > k) + { + Flag [i] = mark ; + } + } + } + else + { + // for each column j whos first row index is in row k + for (Int j = Head [k] ; j != EMPTY ; j = Anext [j]) + { + // merge column j of A into Flag + PRINT1 ((" ---- A column "ID"\n", j)) ; + Int p = Ap [j] ; + Int pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; + PRINT1 ((" length "ID" adding\n", pend-p)) ; + for ( ; p < pend ; p++) + { + #ifndef NDEBUG + ASSERT (Ai [p] >= k && Ai [p] < nrow) ; + if (Flag [Ai [p]] < mark) PRINT1 ((" row "ID"\n", Ai [p])) ; + #endif + Flag [Ai [p]] = mark ; + } + } + // clear the kth link list + Head [k] = EMPTY ; + } + + //---------------------------------------------------------------------- + // compute pruned pattern of kth column of L = union of children + //---------------------------------------------------------------------- + + // for each column j of L whose parent is k + for (Int j = Link [k] ; j != EMPTY ; j = Link [j]) + { + // merge column j of L into Flag + PRINT1 ((" ---- L column "ID"\n", k)) ; + ASSERT (j < k) ; + ASSERT (Lnz [j] > 0) ; + Int p = Lp [j] ; + Int pend = p + Lnz [j] ; + ASSERT (Li [p] == j && Li [p+1] == k) ; + p++ ; // skip past the diagonal entry + for ( ; p < pend ; p++) + { + // add to pattern + ASSERT (Li [p] >= k && Li [p] < nrow) ; + Flag [Li [p]] = mark ; + } + } + + //---------------------------------------------------------------------- + // prune the kth column of L + //---------------------------------------------------------------------- + + PRINT1 (("Final column of L:\n")) ; + + Int p = Lp [k] ; + Int pend = p + Lnz [k] ; + + if (pack) + { + // shift column k upwards + Lp [k] = pdest ; + } + else + { + // leave column k in place, just reduce Lnz [k] + pdest = p ; + } + + for ( ; p < pend ; p++) + { + ASSERT (pdest < pend) ; + ASSERT (pdest <= p) ; + Int row = Li [p] ; + ASSERT (row >= k && row < nrow) ; + if (Flag [row] == mark) + { + // keep this entry + Li [pdest] = row ; + // Lx,Lz [pdest] = Lx,Lz [p] + ASSIGN (Lx, Lz, pdest, Lx, Lz, p) ; + pdest++ ; + } + } + + //---------------------------------------------------------------------- + // prepare this column for its parent + //---------------------------------------------------------------------- + + Lnz [k] = pdest - Lp [k] ; + + PRINT1 ((" L("ID") length "ID"\n", k, Lnz [k])) ; + ASSERT (Lnz [k] > 0) ; + + // parent is the first entry in the column after the diagonal + Int parent = (Lnz [k] > 1) ? (Li [Lp [k] + 1]) : EMPTY ; + + PRINT1 (("parent ("ID") = "ID"\n", k, parent)) ; + ASSERT ((parent > k && parent < nrow) || (parent == EMPTY)) ; + + if (parent != EMPTY) + { + Link [k] = Link [parent] ; + Link [parent] = k ; + } + } + + if (pack) + { + // finalize Lp + Lp [nrow] = pdest ; + } +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Cholesky/t_cholmod_rowfac.c b/CHOLMOD/Cholesky/t_cholmod_rowfac.c deleted file mode 100644 index ffdce34f3e..0000000000 --- a/CHOLMOD/Cholesky/t_cholmod_rowfac.c +++ /dev/null @@ -1,459 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Cholesky/t_cholmod_rowfac: template for cholmod_rowfac -//------------------------------------------------------------------------------ - -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis -// All Rights Reserved. -// SPDX-License-Identifier: LGPL-2.1+ - -//------------------------------------------------------------------------------ - -/* Template routine for cholmod_rowfac. Supports any numeric xtype - * (real, complex, or zomplex). - * - * workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex) - */ - -#include "cholmod_template.h" - -#ifdef MASK -static int TEMPLATE (cholmod_rowfac_mask) -#else -static int TEMPLATE (cholmod_rowfac) -#endif -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ - double beta [2], /* factorize beta*I+A or beta*I+AA' (beta [0] only) */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ -#ifdef MASK - /* These inputs are used for cholmod_rowfac_mask only */ - Int *mask, /* size A->nrow. if mask[i] >= maskmark - then W(i) is set to zero */ - Int maskmark, - Int *RLinkUp, /* size A->nrow. link list of rows to compute */ -#endif - /* ---- in/out --- */ - cholmod_factor *L, - /* --------------- */ - cholmod_common *Common -) -{ - double yx [2], lx [2], fx [2], dk [1], di [1], fl = 0 ; -#ifdef ZOMPLEX - double yz [1], lz [1], fz [1] ; -#endif - double *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ; - Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz, - *Iwork ; - Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds, - use_dbound, packed, stype, Fpacked, sorted, nzmax, len, parent ; -#ifndef REAL - Int dk_imaginary ; -#endif - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n", - kstart, kend, A->stype)) ; - DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ; - - n = A->nrow ; - stype = A->stype ; - - if (stype > 0) - { - /* symmetric upper case: F is not needed. It may be NULL */ - Fp = NULL ; - Fi = NULL ; - Fx = NULL ; - Fz = NULL ; - Fnz = NULL ; - Fpacked = TRUE ; - } - else - { - /* unsymmetric case: F is required. */ - Fp = F->p ; - Fi = F->i ; - Fx = F->x ; - Fz = F->z ; - Fnz = F->nz ; - Fpacked = F->packed ; - } - - Ap = A->p ; /* size A->ncol+1, column pointers of A */ - Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ - Ax = A->x ; /* size nz, numeric values of A */ - Az = A->z ; - Anz = A->nz ; - packed = A->packed ; - sorted = A->sorted ; - - use_dbound = (Common->dbound > 0) ; - - /* get the current factors L (and D for LDL'); allocate space if needed */ - is_ll = L->is_ll ; - if (L->xtype == CHOLMOD_PATTERN) - { - /* ------------------------------------------------------------------ */ - /* L is symbolic only; allocate and initialize L (and D for LDL') */ - /* ------------------------------------------------------------------ */ - - /* workspace: none */ - CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common); - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (FALSE) ; - } - ASSERT (L->minor == (size_t) n) ; - } - else if (kstart == 0 && kend == (size_t) n) - { - /* ------------------------------------------------------------------ */ - /* refactorization; reset L->nz and L->minor to restart factorization */ - /* ------------------------------------------------------------------ */ - - L->minor = n ; - Lnz = L->nz ; - for (k = 0 ; k < n ; k++) - { - Lnz [k] = 1 ; - } - } - - ASSERT (is_ll == L->is_ll) ; - ASSERT (L->xtype != CHOLMOD_PATTERN) ; - DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ; - DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ; - DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ; - - /* inputs, can be modified on output: */ - Lp = L->p ; /* size n+1 */ - ASSERT (Lp != NULL) ; - - /* outputs, contents defined on input for incremental case only: */ - Lnz = L->nz ; /* size n */ - Lnext = L->next ; /* size n+2 */ - Li = L->i ; /* size L->nzmax, can change in size */ - Lx = L->x ; /* size L->nzmax or 2*L->nzmax, can change in size */ - Lz = L->z ; /* size L->nzmax for zomplex case, can change in size */ - nzmax = L->nzmax ; - ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Iwork = Common->Iwork ; - Stack = Iwork ; /* size n (i/i/l) */ - Flag = Common->Flag ; /* size n, Flag [i] < mark must hold */ - Wx = Common->Xwork ; /* size n if real, 2*n if complex or - * zomplex. Xwork [i] == 0 must hold. */ - Wz = Wx + n ; /* size n for zomplex case only */ - mark = Common->mark ; - size_t wsize = (L->xtype == CHOLMOD_REAL ? 1:2) * ((size_t) n) ; - ASSERT (Common->xworkbytes >= wsize * sizeof (Real)) ; - - /* ---------------------------------------------------------------------- */ - /* compute LDL' or LL' factorization by rows */ - /* ---------------------------------------------------------------------- */ - -#ifdef MASK -#define NEXT(k) k = RLinkUp [k] -#else -#define NEXT(k) k++ -#endif - - for (k = kstart ; k < ((Int) kend) ; NEXT(k)) - { - PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ; - - /* ------------------------------------------------------------------ */ - /* compute pattern of kth row of L and scatter kth input column */ - /* ------------------------------------------------------------------ */ - - /* column k of L is currently empty */ - ASSERT (Lnz [k] == 1) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, Common)) ; - - top = n ; /* Stack is empty */ - Flag [k] = mark ; /* do not include diagonal entry in Stack */ - - /* use Li [Lp [i]+1] for etree */ -#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY - - if (stype > 0) - { - /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ - p = Ap [k] ; - pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; - /* W [i] = Ax [i] ; scatter column of A */ -#define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p) - SUBTREE ; -#undef SCATTER - } - else - { - /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ - pf = Fp [k] ; - pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; - for ( ; pf < pfend ; pf++) - { - /* get nonzero entry F (t,k) */ - t = Fi [pf] ; - /* fk = Fx [pf] */ - ASSIGN (fx, fz, 0, Fx, Fz, pf) ; - p = Ap [t] ; - pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; - multadds = 0 ; - /* W [i] += Ax [p] * fx ; scatter column of A*A' */ -#define SCATTER MULTADD (Wx,Wz,i, Ax,Az,p, fx,fz,0) ; multadds++ ; - SUBTREE ; -#undef SCATTER -#ifdef REAL - fl += 2 * ((double) multadds) ; -#else - fl += 8 * ((double) multadds) ; -#endif - } - } - -#undef PARENT - - /* ------------------------------------------------------------------ */ - /* if mask is present, set the corresponding entries in W to zero */ - /* ------------------------------------------------------------------ */ - -#ifdef MASK - /* remove the dead element of Wx */ - if (mask != NULL) - { - -#if 0 - /* older version */ - for (p = n; p > top;) - { - i = Stack [--p] ; - if ( mask [i] >= 0 ) - { - CLEAR (Wx,Wz,i) ; /* set W(i) to zero */ - } - } -#endif - - for (s = top ; s < n ; s++) - { - i = Stack [s] ; - if (mask [i] >= maskmark) - { - CLEAR (Wx,Wz,i) ; /* set W(i) to zero */ - } - } - - } -#endif - - /* nonzero pattern of kth row of L is now in Stack [top..n-1]. - * Flag [Stack [top..n-1]] is equal to mark, but no longer needed */ - - /* mark = CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - - /* ------------------------------------------------------------------ */ - /* compute kth row of L and store in column form */ - /* ------------------------------------------------------------------ */ - - /* Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where - * b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack. - * - * For LDL' factorization: - * L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1) - * D (k) = b (k) - L (k, 0:k-1) * y (0:k-1) - * - * For LL' factorization: - * L (k, 0:k-1) = y (0:k-1) - * L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k)) - */ - - /* dk = W [k] + beta */ - ADD_REAL (dk,0, Wx,k, beta,0) ; - -#ifndef REAL - /* In the unsymmetric case, the imaginary part of W[k] must be real, - * since F is assumed to be the complex conjugate transpose of A. In - * the symmetric case, W[k] is the diagonal of A. If the imaginary part - * of W[k] is nonzero, then the Cholesky factorization cannot be - * computed; A is not positive definite */ - dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ; -#endif - - /* W [k] = 0.0 ; */ - CLEAR (Wx,Wz,k) ; - - for (s = top ; s < n ; s++) - { - /* get i for each nonzero entry L(k,i) */ - i = Stack [s] ; - - /* y = W [i] ; */ - ASSIGN (yx,yz,0, Wx,Wz,i) ; - - /* W [i] = 0.0 ; */ - CLEAR (Wx,Wz,i) ; - - lnz = Lnz [i] ; - p = Lp [i] ; - ASSERT (lnz > 0 && Li [p] == i) ; - pend = p + lnz ; - - /* di = Lx [p] ; the diagonal entry L or D(i,i), which is real */ - ASSIGN_REAL (di,0, Lx,p) ; - - if (i >= (Int) L->minor || (di [0] == 0)) - { - /* For the LL' factorization, L(i,i) is zero. For the LDL', - * D(i,i) is zero. Skip column i of L, and set L(k,i) = 0. */ - CLEAR (lx,lz,0) ; - p = pend ; - } - else if (is_ll) - { -#ifdef REAL - fl += 2 * ((double) (pend - p - 1)) + 3 ; -#else - fl += 8 * ((double) (pend - p - 1)) + 6 ; -#endif - /* forward solve using L (i:(k-1),i) */ - /* divide by L(i,i), which must be real and nonzero */ - /* y /= di [0] */ - DIV_REAL (yx,yz,0, yx,yz,0, di,0) ; - for (p++ ; p < pend ; p++) - { - /* W [Li [p]] -= Lx [p] * y ; */ - MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; - } - /* do not scale L; compute dot product for L(k,k) */ - /* L(k,i) = conj(y) ; */ - ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; - /* d -= conj(y) * y ; */ - LLDOT (dk,0, yx,yz,0) ; - } - else - { -#ifdef REAL - fl += 2 * ((double) (pend - p - 1)) + 3 ; -#else - fl += 8 * ((double) (pend - p - 1)) + 6 ; -#endif - /* forward solve using D (i,i) and L ((i+1):(k-1),i) */ - for (p++ ; p < pend ; p++) - { - /* W [Li [p]] -= Lx [p] * y ; */ - MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; - } - /* Scale L (k,0:k-1) for LDL' factorization, compute D (k,k)*/ -#ifdef REAL - /* L(k,i) = y/d */ - lx [0] = yx [0] / di [0] ; - /* d -= L(k,i) * y */ - dk [0] -= lx [0] * yx [0] ; -#else - /* L(k,i) = conj(y) ; */ - ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; - /* L(k,i) /= di ; */ - DIV_REAL (lx,lz,0, lx,lz,0, di,0) ; - /* d -= conj(y) * y / di */ - LDLDOT (dk,0, yx,yz,0, di,0) ; -#endif - } - - /* determine if column i of L can hold the new L(k,i) entry */ - if (p >= Lp [Lnext [i]]) - { - /* column i needs to grow */ - PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i])); - if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common)) - { - /* out of memory, L is now simplicial symbolic */ - for (i = 0 ; i < n ; i++) - { - /* W [i] = 0 ; */ - CLEAR (Wx,Wz,i) ; - } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, Common)) ; - return (FALSE) ; - } - Li = L->i ; /* L->i, L->x, L->z may have moved */ - Lx = L->x ; - Lz = L->z ; - p = Lp [i] + lnz ; /* contents of L->p changed */ - ASSERT (p < Lp [Lnext [i]]) ; - } - - /* store L (k,i) in the column form matrix of L */ - Li [p] = k ; - /* Lx [p] = L(k,i) ; */ - ASSIGN (Lx,Lz,p, lx,lz,0) ; - Lnz [i]++ ; - } - - /* ------------------------------------------------------------------ */ - /* ensure abs (d) >= dbound if dbound is given, and store it in L */ - /* ------------------------------------------------------------------ */ - - p = Lp [k] ; - Li [p] = k ; - - if (k >= (Int) L->minor) - { - /* the matrix is already not positive definite */ - dk [0] = 0 ; - } - else if (use_dbound) - { - /* modify the diagonal to force LL' or LDL' to exist */ - dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ; - } - else if ((is_ll ? (dk [0] <= 0) : (dk [0] == 0)) -#ifndef REAL - || dk_imaginary -#endif - ) - { - /* the matrix has just been found to be not positive definite */ - dk [0] = 0 ; - L->minor = k ; - ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ; - } - - if (is_ll) - { - /* this is counted as one flop, below */ - dk [0] = sqrt (dk [0]) ; - } - - /* Lx [p] = D(k,k) = d ; real part only */ - ASSIGN_REAL (Lx,p, dk,0) ; - CLEAR_IMAG (Lx,Lz,p) ; - } - -#undef NEXT - - if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ; /* count sqrt's */ - Common->rowfacfl = fl ; - - DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, Common)) ; - return (TRUE) ; -} -#undef PATTERN -#undef REAL -#undef COMPLEX -#undef ZOMPLEX diff --git a/CHOLMOD/Cholesky/t_cholmod_rowfac_worker.c b/CHOLMOD/Cholesky/t_cholmod_rowfac_worker.c new file mode 100644 index 0000000000..bb88d6fb9b --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_rowfac_worker.c @@ -0,0 +1,461 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_rowfac_worker: template for cholmod_rowfac +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// Template routine for cholmod_rowfac. Supports any numeric xtype +// (real, complex, or zomplex) but not pattern, and any dtype. +// +// workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex) + +#include "cholmod_template.h" + +#ifdef MASK +static int TEMPLATE (cholmod_rowfac_mask_worker) +#else +static int TEMPLATE (cholmod_rowfac_worker) +#endif +( + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + Real beta [2], // factorize beta*I+A or beta*I+AA' (beta [0] only) + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 +#ifdef MASK + // These inputs are used for cholmod_rowfac_mask only + Int *mask, // size A->nrow. if mask[i] >= maskmark + // then W(i) is set to zero + Int maskmark, + Int *RLinkUp, // size A->nrow. link list of rows to compute +#endif + // input/output: + cholmod_factor *L, + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + double fl = 0 ; + Real yx [2], lx [2], fx [2], dk [1], di [1] ; + #ifdef ZOMPLEX + Real yz [1], lz [1], fz [1] ; + #endif + Real *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ; + Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz, + *Iwork ; + Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds, + use_bound, packed, stype, Fpacked, sorted, nzmax, len, parent ; + #ifndef REAL + Int dk_imaginary ; + #endif + + PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n", + kstart, kend, A->stype)) ; + DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ; + + n = A->nrow ; + stype = A->stype ; + + if (stype > 0) + { + // symmetric upper case: F is not needed. It may be NULL + Fp = NULL ; + Fi = NULL ; + Fx = NULL ; + Fz = NULL ; + Fnz = NULL ; + Fpacked = TRUE ; + } + else + { + // unsymmetric case: F is required. + Fp = F->p ; + Fi = F->i ; + Fx = F->x ; + Fz = F->z ; + Fnz = F->nz ; + Fpacked = F->packed ; + } + + Ap = A->p ; // size A->ncol+1, column pointers of A + Ai = A->i ; // size nz = Ap [A->ncol], row indices of A + Ax = A->x ; // size nz, numeric values of A + Az = A->z ; + Anz = A->nz ; + packed = A->packed ; + sorted = A->sorted ; + + #ifdef DOUBLE + use_bound = (Common->dbound > 0) ; + #else + use_bound = (Common->sbound > 0) ; + #endif + + //-------------------------------------------------------------------------- + // get the current factors L (and D for LDL'); allocate space if needed + //-------------------------------------------------------------------------- + + is_ll = L->is_ll ; + if (L->xtype == CHOLMOD_PATTERN) + { + + //---------------------------------------------------------------------- + // L is symbolic only; allocate and initialize L (and D for LDL') + //---------------------------------------------------------------------- + + // workspace: none + L->dtype = A->dtype ; // ensure L has the same dtype as A + CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common); + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (FALSE) ; + } + ASSERT (L->minor == (size_t) n) ; + + } + else if (kstart == 0 && kend == (size_t) n) + { + + //---------------------------------------------------------------------- + // refactorization; reset L->nz and L->minor to restart factorization + //---------------------------------------------------------------------- + + L->minor = n ; + Lnz = L->nz ; + for (k = 0 ; k < n ; k++) + { + Lnz [k] = 1 ; + } + } + + ASSERT (is_ll == L->is_ll) ; + ASSERT (L->xtype != CHOLMOD_PATTERN) ; + DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ; + DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ; + DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ; + + // inputs, can be modified on output: + Lp = L->p ; // size n+1 + ASSERT (Lp != NULL) ; + + // outputs, contents defined on input for incremental case only: + Lnz = L->nz ; // size n + Lnext = L->next ; // size n+2 + Li = L->i ; // size L->nzmax, can change in size + Lx = L->x ; // size L->nzmax or 2*L->nzmax, can change in size + Lz = L->z ; // size L->nzmax for zomplex case, can change in size + nzmax = L->nzmax ; + ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ; + + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Iwork = Common->Iwork ; + Stack = Iwork ; // size n + Flag = Common->Flag ; // size n, Flag [i] < mark must hold + Wx = Common->Xwork ; // size n if real, 2*n if complex or + // zomplex. Xwork [i] == 0 must hold. + Wz = Wx + n ; // size n for zomplex case only + mark = Common->mark ; + size_t wsize = (L->xtype == CHOLMOD_REAL ? 1:2) * ((size_t) n) ; + ASSERT (Common->xworkbytes >= wsize * sizeof (Real)) ; + + //-------------------------------------------------------------------------- + // compute LDL' or LL' factorization by rows + //-------------------------------------------------------------------------- + + #ifdef MASK + #define NEXT(k) k = RLinkUp [k] + #else + #define NEXT(k) k++ + #endif + + for (k = kstart ; k < ((Int) kend) ; NEXT(k)) + { + + //---------------------------------------------------------------------- + // compute pattern of kth row of L and scatter kth input column + //---------------------------------------------------------------------- + + PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ; + // column k of L is currently empty + ASSERT (Lnz [k] == 1) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, A->dtype, Common)) ; + + top = n ; // Stack is empty + Flag [k] = mark ; // do not include diagonal entry in Stack + + // use Li [Lp [i]+1] for etree + #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY + + if (stype > 0) + { + // scatter kth col of triu (beta*I+AA'), get pattern L(k,:) + p = Ap [k] ; + pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; + // W [i] = Ax [i] ; scatter column of A + #define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p) + SUBTREE ; + #undef SCATTER + } + else + { + // scatter kth col of triu (beta*I+AA'), get pattern L(k,:) + pf = Fp [k] ; + pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; + for ( ; pf < pfend ; pf++) + { + // get nonzero entry F (t,k) + t = Fi [pf] ; + // fk = Fx [pf] + ASSIGN (fx, fz, 0, Fx, Fz, pf) ; + p = Ap [t] ; + pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; + multadds = 0 ; + // W [i] += Ax [p] * fx ; scatter column of A*A' + #define SCATTER MULTADD (Wx,Wz,i,Ax,Az,p,fx,fz,0) ; multadds++ ; + SUBTREE ; + #undef SCATTER + #ifdef REAL + fl += 2 * ((double) multadds) ; + #else + fl += 8 * ((double) multadds) ; + #endif + } + } + + #undef PARENT + + //---------------------------------------------------------------------- + // if mask is present, set the corresponding entries in W to zero + //---------------------------------------------------------------------- + + #ifdef MASK + // remove the dead element of Wx + if (mask != NULL) + { + for (s = top ; s < n ; s++) + { + i = Stack [s] ; + if (mask [i] >= maskmark) + { + CLEAR (Wx,Wz,i) ; // set W(i) to zero + } + } + } + #endif + + // nonzero pattern of kth row of L is now in Stack [top..n-1]. + // Flag [Stack [top..n-1]] is equal to mark, but no longer needed + + CLEAR_FLAG (Common) ; + mark = Common->mark ; + + //---------------------------------------------------------------------- + // compute kth row of L and store in column form + //---------------------------------------------------------------------- + + // Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where + // b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack. + // + // For LDL' factorization: + // L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1) + // D (k) = b (k) - L (k, 0:k-1) * y (0:k-1) + // + // For LL' factorization: + // L (k, 0:k-1) = y (0:k-1) + // L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k)) + + // dk = W [k] + beta + ADD_REAL (dk,0, Wx,k, beta,0) ; + + #ifndef REAL + // In the unsymmetric case, the imaginary part of W[k] must be real, + // since F is assumed to be the complex conjugate transpose of A. In + // the symmetric case, W[k] is the diagonal of A. If the imaginary part + // of W[k] is nonzero, then the Cholesky factorization cannot be + // computed; A is not positive definite + dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ; + #endif + + // W [k] = 0.0 ; + CLEAR (Wx,Wz,k) ; + + for (s = top ; s < n ; s++) + { + // get i for each nonzero entry L(k,i) + i = Stack [s] ; + + // y = W [i] ; + ASSIGN (yx,yz,0, Wx,Wz,i) ; + + // W [i] = 0.0 ; + CLEAR (Wx,Wz,i) ; + + lnz = Lnz [i] ; + p = Lp [i] ; + ASSERT (lnz > 0 && Li [p] == i) ; + pend = p + lnz ; + + // di = Lx [p] ; the diagonal entry L or D(i,i), which is real + ASSIGN_REAL (di,0, Lx,p) ; + + if (i >= (Int) L->minor || (di [0] == 0)) + { + // For the LL' factorization, L(i,i) is zero. For the LDL', + // D(i,i) is zero. Skip column i of L, and set L(k,i) = 0. + CLEAR (lx,lz,0) ; + p = pend ; + } + else if (is_ll) + { + #ifdef REAL + fl += 2 * ((double) (pend - p - 1)) + 3 ; + #else + fl += 8 * ((double) (pend - p - 1)) + 6 ; + #endif + // forward solve using L (i:(k-1),i) + // divide by L(i,i), which must be real and nonzero + // y /= di [0] + DIV_REAL (yx,yz,0, yx,yz,0, di,0) ; + for (p++ ; p < pend ; p++) + { + // W [Li [p]] -= Lx [p] * y ; + MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; + } + // do not scale L; compute dot product for L(k,k) + // L(k,i) = conj(y) ; + ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; + // d -= conj(y) * y ; + LLDOT (dk,0, yx,yz,0) ; + } + else + { + #ifdef REAL + fl += 2 * ((double) (pend - p - 1)) + 3 ; + #else + fl += 8 * ((double) (pend - p - 1)) + 6 ; + #endif + // forward solve using D (i,i) and L ((i+1):(k-1),i) + for (p++ ; p < pend ; p++) + { + // W [Li [p]] -= Lx [p] * y ; + MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; + } + // Scale L (k,0:k-1) for LDL' factorization, compute D (k,k) + #ifdef REAL + // L(k,i) = y/d + lx [0] = yx [0] / di [0] ; + // d -= L(k,i) * y + dk [0] -= lx [0] * yx [0] ; + #else + // L(k,i) = conj(y) ; + ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; + // L(k,i) /= di ; + DIV_REAL (lx,lz,0, lx,lz,0, di,0) ; + // d -= conj(y) * y / di + LDLDOT (dk,0, yx,yz,0, di,0) ; + #endif + } + + // determine if column i of L can hold the new L(k,i) entry + if (p >= Lp [Lnext [i]]) + { + // column i needs to grow + PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i])); + if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common)) + { + // out of memory, L is now simplicial symbolic + for (i = 0 ; i < n ; i++) + { + // W [i] = 0 ; + CLEAR (Wx,Wz,i) ; + } + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, A->dtype, + Common)) ; + return (FALSE) ; + } + Li = L->i ; // L->i, L->x, L->z may have moved + Lx = L->x ; + Lz = L->z ; + p = Lp [i] + lnz ; // contents of L->p changed + ASSERT (p < Lp [Lnext [i]]) ; + } + + // store L (k,i) in the column form matrix of L + Li [p] = k ; + // Lx [p] = L(k,i) ; + ASSIGN (Lx,Lz,p, lx,lz,0) ; + Lnz [i]++ ; + } + + //---------------------------------------------------------------------- + // ensure abs (d) >= bound if dbound/sbound is given, and store it in L + //---------------------------------------------------------------------- + + p = Lp [k] ; + Li [p] = k ; + + if (k >= (Int) L->minor) + { + // the matrix is already not positive definite + dk [0] = 0 ; + } + else if (use_bound) + { + // modify the diagonal to force LL' or LDL' to exist + #ifdef DOUBLE + dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ; + #else + dk [0] = CHOLMOD(sbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ; + #endif + } + else if ((is_ll ? (dk [0] <= 0) : (dk [0] == 0)) + #ifndef REAL + || dk_imaginary + #endif + ) + { + // the matrix has just been found to be not positive definite + dk [0] = 0 ; + L->minor = k ; + ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ; + } + + if (is_ll) + { + // this is counted as one flop, below + dk [0] = sqrt (dk [0]) ; + } + + // Lx [p] = D(k,k) = d ; real part only + ASSIGN_REAL (Lx,p, dk,0) ; + CLEAR_IMAG (Lx,Lz,p) ; + } + + #undef NEXT + + if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ; // count sqrt's + Common->rowfacfl = fl ; + + DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wsize, A->dtype, Common)) ; + return (TRUE) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Cholesky/t_cholmod_solve.c b/CHOLMOD/Cholesky/t_cholmod_solve.c deleted file mode 100644 index 315bef0a8a..0000000000 --- a/CHOLMOD/Cholesky/t_cholmod_solve.c +++ /dev/null @@ -1,176 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Cholesky/t_cholmod_solve: template for cholmod_solve -//------------------------------------------------------------------------------ - -// CHOLMOD/Cholesky Module. Copyright (C) 2005-2022, Timothy A. Davis -// All Rights Reserved. -// SPDX-License-Identifier: LGPL-2.1+ - -//------------------------------------------------------------------------------ - -/* Template routine for cholmod_solve. Supports any numeric xtype (real, - * complex, or zomplex). The xtypes of all matrices (L and Y) must match. - */ - -#include "cholmod_template.h" - -/* ========================================================================== */ -/* === simplicial template solvers ========================================== */ -/* ========================================================================== */ - -/* LL': solve Lx=b with non-unit diagonal */ -#define LL -#include "t_cholmod_lsolve.c" - -/* LDL': solve LDx=b */ -#define LD -#include "t_cholmod_lsolve.c" - -/* LDL': solve Lx=b with unit diagonal */ -#include "t_cholmod_lsolve.c" - -/* LL': solve L'x=b with non-unit diagonal */ -#define LL -#include "t_cholmod_ltsolve.c" - -/* LDL': solve DL'x=b */ -#define LD -#include "t_cholmod_ltsolve.c" - -/* LDL': solve L'x=b with unit diagonal */ -#include "t_cholmod_ltsolve.c" - - -/* ========================================================================== */ -/* === t_ldl_dsolve ========================================================= */ -/* ========================================================================== */ - -/* Solve Dx=b for an LDL' factorization, where Y holds b' on input and x' on - * output. - * - * The number of right-hand-sides (nrhs) is not restricted, even if Yseti - * is present. - */ - -static void TEMPLATE (ldl_dsolve) -( - cholmod_factor *L, - cholmod_dense *Y, /* nr-by-n with leading dimension nr */ - Int *Yseti, Int ysetlen -) -{ - double d [1] ; - double *Lx, *Yx, *Yz ; - Int *Lp ; - Int n, nrhs, k, p, k1, k2, kk, kkiters ; - - ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ - ASSERT (L->n == Y->ncol) ; /* dimensions must match */ - ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ - ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ - ASSERT (!(L->is_super) && !(L->is_ll)) ; /* L is simplicial LDL' */ - - nrhs = Y->nrow ; - n = L->n ; - Lp = L->p ; - Lx = L->x ; - Yx = Y->x ; - Yz = Y->z ; - kkiters = Yseti ? ysetlen : n ; - for (kk = 0 ; kk < kkiters ; kk++) - { - k = Yseti ? Yseti [kk] : kk ; - k1 = k*nrhs ; - k2 = (k+1)*nrhs ; - ASSIGN_REAL (d,0, Lx,Lp[k]) ; - for (p = k1 ; p < k2 ; p++) - { - DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ; - } - } -} - - -/* ========================================================================== */ -/* === t_simplicial_solver ================================================== */ -/* ========================================================================== */ - -/* Solve a linear system, where Y' contains the (array-transposed) right-hand - * side on input, and the solution on output. No permutations are applied; - * these must have already been applied to Y on input. - * - * Yseti [0..ysetlen-1] is an optional list of indices from - * cholmod_lsolve_pattern. The solve is performed only on the columns of L - * corresponding to entries in Yseti. Ignored if NULL. If present, most - * functions require that Y' consist of a single dense column. - */ - -static void TEMPLATE (simplicial_solver) -( - int sys, /* system to solve */ - cholmod_factor *L, /* factor to use, a simplicial LL' or LDL' */ - cholmod_dense *Y, /* right-hand-side on input, solution on output */ - Int *Yseti, Int ysetlen -) -{ - if (L->is_ll) - { - /* The factorization is LL' */ - if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) - { - /* Solve Ax=b or LL'x=b */ - TEMPLATE (ll_lsolve_k) (L, Y, Yseti, ysetlen) ; - TEMPLATE (ll_ltsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) - { - /* Solve Lx=b */ - TEMPLATE (ll_lsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) - { - /* Solve L'x=b */ - TEMPLATE (ll_ltsolve_k) (L, Y, Yseti, ysetlen) ; - } - } - else - { - /* The factorization is LDL' */ - if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) - { - /* Solve Ax=b or LDL'x=b */ - TEMPLATE (ldl_lsolve_k) (L, Y, Yseti, ysetlen) ; - TEMPLATE (ldl_dltsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_LD) - { - /* Solve LDx=b */ - TEMPLATE (ldl_ldsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_L) - { - /* Solve Lx=b */ - TEMPLATE (ldl_lsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_Lt) - { - /* Solve L'x=b */ - TEMPLATE (ldl_ltsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_DLt) - { - /* Solve DL'x=b */ - TEMPLATE (ldl_dltsolve_k) (L, Y, Yseti, ysetlen) ; - } - else if (sys == CHOLMOD_D) - { - /* Solve Dx=b */ - TEMPLATE (ldl_dsolve) (L, Y, Yseti, ysetlen) ; - } - } -} - -#undef PATTERN -#undef REAL -#undef COMPLEX -#undef ZOMPLEX diff --git a/CHOLMOD/Cholesky/t_cholmod_solve_worker.c b/CHOLMOD/Cholesky/t_cholmod_solve_worker.c new file mode 100644 index 0000000000..397ff2738b --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_solve_worker.c @@ -0,0 +1,293 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_solve: template for cholmod_solve +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +// Template routine for cholmod_solve. Supports any numeric xtype (real, +// complex, or zomplex). The xtypes of all matrices (L and Y) must match. + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// simplicial template solvers +//------------------------------------------------------------------------------ + +// LL': solve Lx=b with non-unit diagonal +#define LL +#include "t_cholmod_lsolve_template.c" + +// LDL': solve LDx=b +#define LD +#include "t_cholmod_lsolve_template.c" + +// LDL': solve Lx=b with unit diagonal +#include "t_cholmod_lsolve_template.c" + +// LL': solve L'x=b with non-unit diagonal +#define LL +#include "t_cholmod_ltsolve_template.c" + +// LDL': solve DL'x=b +#define LD +#include "t_cholmod_ltsolve_template.c" + +// LDL': solve L'x=b with unit diagonal +#include "t_cholmod_ltsolve_template.c" + +//------------------------------------------------------------------------------ +// t_ldl_dsolve +//------------------------------------------------------------------------------ + +// Solve Dx=b for an LDL' factorization, where Y holds b' on input and x' on +// output. +// +// The number of right-hand-sides (nrhs) is not restricted, even if Yset +// is present. + +static void TEMPLATE (ldl_dsolve) +( + cholmod_factor *L, + cholmod_dense *Y, // nr-by-n with leading dimension nr + cholmod_sparse *Yset // input pattern Yset +) +{ + + ASSERT (L->xtype == Y->xtype) ; // L and Y must have the same xtype + ASSERT (L->dtype == Y->dtype) ; // L and Y must have the same dtype + ASSERT (L->n == Y->ncol) ; // dimensions must match + ASSERT (Y->nrow == Y->d) ; // leading dimension of Y = # rows of Y + ASSERT (L->xtype != CHOLMOD_PATTERN) ; // L is not symbolic + ASSERT (!(L->is_super) && !(L->is_ll)) ; // L is simplicial LDL' + + Real d [1] ; + Int nrhs = Y->nrow ; + Int n = L->n ; + Int *Lp = L->p ; + Real *Lx = L->x ; + Real *Yx = Y->x ; + Real *Yz = Y->z ; + + if (Yset) + { + Int *Yseti = Yset->i ; + Int *Ysetp = Yset->p ; + Int ysetlen = Ysetp [1] ; + for (Int kk = 0 ; kk < ysetlen ; kk++) + { + Int k = Yseti [kk] ; + Int k1 = k*nrhs ; + Int k2 = (k+1)*nrhs ; + // d = L (k,k) + ASSIGN_REAL (d,0, Lx,Lp[k]) ; + for (Int p = k1 ; p < k2 ; p++) + { + // Y (p) = Y (p) / d + DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ; + } + } + } + else + { + for (Int k = 0 ; k < n ; k++) + { + Int k1 = k*nrhs ; + Int k2 = (k+1)*nrhs ; + // d = L (k,k) + ASSIGN_REAL (d,0, Lx,Lp[k]) ; + for (Int p = k1 ; p < k2 ; p++) + { + // Y (p) = Y (p) / d + DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ; + } + } + } +} + +//------------------------------------------------------------------------------ +// t_simplicial_solver +//------------------------------------------------------------------------------ + +// Solve a linear system, where Y' contains the (array-transposed) right-hand +// side on input, and the solution on output. No permutations are applied; +// these must have already been applied to Y on input. +// +// Yset is an optional list of indices from cholmod_lsolve_pattern. The solve +// is performed only on the columns of L corresponding to entries in Yset. +// Ignored if NULL. If present, most functions require that Y' consist of a +// single dense column. + +static void TEMPLATE (simplicial_solver) +( + int sys, // system to solve + cholmod_factor *L, // factor to use, a simplicial LL' or LDL' + cholmod_dense *Y, // right-hand-side on input, solution on output + cholmod_sparse *Yset // input pattern Yset +) +{ + if (L->is_ll) + { + // The factorization is LL' + if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) + { + // Solve Ax=b or LL'x=b + TEMPLATE (ll_lsolve_k) (L, Y, Yset) ; + TEMPLATE (ll_ltsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) + { + // Solve Lx=b + TEMPLATE (ll_lsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) + { + // Solve L'x=b + TEMPLATE (ll_ltsolve_k) (L, Y, Yset) ; + } + } + else + { + // The factorization is LDL' + if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) + { + // Solve Ax=b or LDL'x=b + TEMPLATE (ldl_lsolve_k) (L, Y, Yset) ; + TEMPLATE (ldl_dltsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_LD) + { + // Solve LDx=b + TEMPLATE (ldl_ldsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_L) + { + // Solve Lx=b + TEMPLATE (ldl_lsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_Lt) + { + // Solve L'x=b + TEMPLATE (ldl_ltsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_DLt) + { + // Solve DL'x=b + TEMPLATE (ldl_dltsolve_k) (L, Y, Yset) ; + } + else if (sys == CHOLMOD_D) + { + // Solve Dx=b + TEMPLATE (ldl_dsolve) (L, Y, Yset) ; + } + } +} + +//------------------------------------------------------------------------------ +// bset_perm +//------------------------------------------------------------------------------ + +// Y (C) = B (Bset) + +static void TEMPLATE (bset_perm) +( + // input: + cholmod_dense *B, // input matrix B + cholmod_sparse *Bset, // input pattern Bset + cholmod_sparse *Yset, // input pattern Yset + cholmod_sparse *C, // input pattern C + // input/output: + cholmod_dense *Y // output matrix Y, already allocated +) +{ + + //-------------------------------------------------------------------------- + // clear the parts of Y that we will use in the solve + //-------------------------------------------------------------------------- + + Real *Yx = Y->x ; + Real *Yz = Y->z ; + Int *Ysetp = Yset->p ; + Int *Yseti = Yset->i ; + Int ysetlen = Ysetp [1] ; + + for (Int p = 0 ; p < ysetlen ; p++) + { + Int i = Yseti [p] ; + // Y (i) = 0 + CLEAR (Yx, Yz, i) ; + } + + //-------------------------------------------------------------------------- + // scatter and permute B into Y + //-------------------------------------------------------------------------- + + // Y (C) = B (Bset) + Real *Bx = B->x ; + Real *Bz = B->z ; + Int *Bsetp = Bset->p ; + Int *Bseti = Bset->i ; + Int *Bsetnz = Bset->nz ; + Int blen = (Bset->packed) ? Bsetp [1] : Bsetnz [0] ; + Int *Ci = C->i ; + + for (Int p = 0 ; p < blen ; p++) + { + Int iold = Bseti [p] ; + Int inew = Ci [p] ; + // Y (inew) = B (iold) + ASSIGN (Yx, Yz, inew, Bx, Bz, iold) ; + } +} + +//------------------------------------------------------------------------------ +// bset_iperm +//------------------------------------------------------------------------------ + +// X (P (Yset)) = Y (Yset) + +static void TEMPLATE (bset_iperm) +( + // input: + cholmod_dense *Y, // input matrix Y + cholmod_sparse *Yset, // input pattern Yset + Int *Perm, // optional input permutation (can be NULL) + // input/output: + cholmod_dense *X, // output matrix X, already allocated + cholmod_sparse *Xset // output pattern Xset +) +{ + + Real *Xx = X->x ; + Real *Xz = X->z ; + Int *Xseti = Xset->i ; + Int *Xsetp = Xset->p ; + + Real *Yx = Y->x ; + Real *Yz = Y->z ; + + Int *Ysetp = Yset->p ; + Int *Yseti = Yset->i ; + Int ysetlen = Ysetp [1] ; + + for (Int p = 0 ; p < ysetlen ; p++) + { + Int inew = Yseti [p] ; + Int iold = P(inew) ; // was: (Perm ? Perm [inew] : inew) ; + // X (iold) = Y (inew) + ASSIGN (Xx, Xz, iold, Yx, Yz, inew) ; + Xseti [p] = iold ; + } + + Xsetp [0] = 0 ; + Xsetp [1] = ysetlen ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Cholesky/t_cholmod_spsolve_worker.c b/CHOLMOD/Cholesky/t_cholmod_spsolve_worker.c new file mode 100644 index 0000000000..3f20ca8488 --- /dev/null +++ b/CHOLMOD/Cholesky/t_cholmod_spsolve_worker.c @@ -0,0 +1,208 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Cholesky/t_cholmod_spsolve_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/Cholesky Module. Copyright (C) 2005-2023, Timothy A. Davis +// All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// t_cholmod_spsolve_B_scatter_worker: scatter the sparse B into the dense B4 +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_spsolve_B_scatter_worker) +( + cholmod_dense *B4, // output dense matrix + cholmod_sparse *B, // input sparse matrix + Int jfirst, + Int jlast +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Bp = B->p ; + Int *Bi = B->i ; + Real *Bx = B->x ; + Real *Bz = B->z ; + Int *Bnz = B->nz ; + bool packed = B->packed ; + + Real *B4x = B4->x ; + Real *B4z = B4->z ; + + Int n = B4->nrow ; + + //-------------------------------------------------------------------------- + // B4 = B (:, jfirst:jlast-1) + //-------------------------------------------------------------------------- + + for (Int j = jfirst ; j < jlast ; j++) + { + Int p = Bp [j] ; + Int pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; + Int j_n = (j-jfirst)*n ; + for ( ; p < pend ; p++) + { + Int q = Bi [p] + j_n ; + ASSIGN (B4x, B4z, q, Bx, Bz, p) ; + } + } +} + +//------------------------------------------------------------------------------ +// t_cholmod_spsolve_X_worker: append entries from X4 onto X +//------------------------------------------------------------------------------ + +static bool TEMPLATE (cholmod_spsolve_X_worker) +( + cholmod_sparse *X, // append X4 onto X + cholmod_dense *X4, + Int jfirst, + Int jlast, + size_t *xnz, // position to place entries into X + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Xp = X->p ; + Int *Xi = X->i ; + Real *Xx = X->x ; + Real *Xz = X->z ; + size_t px = (*xnz) ; + + size_t nzmax = X->nzmax ; + + Real *X4x = X4->x ; + Real *X4z = X4->z ; + Int n = X4->nrow ; + + //-------------------------------------------------------------------------- + // append nonzeros from X4 onto X + //-------------------------------------------------------------------------- + + for (Int j = jfirst ; j < jlast ; j++) + { + Xp [j] = px ; + Int j_n = (j-jfirst)*n ; + if (px + n <= nzmax) + { + + //------------------------------------------------------------------ + // X is guaranteed to be large enough + //------------------------------------------------------------------ + + for (Int i = 0 ; i < n ; i++) + { + // append X4 (i,j) to X if nonzero + Int p = i + j_n ; + if (ENTRY_IS_NONZERO (X4x, X4z, p)) + { + Xi [px] = i ; + ASSIGN (Xx, Xz, px, X4x, X4z, p) ; + px++ ; + } + } + + } + else + { + + //------------------------------------------------------------------ + // X may need to increase in size + //------------------------------------------------------------------ + + for (Int i = 0 ; i < n ; i++) + { + // append X4 (i,j) to X if nonzero + Int p = i + j_n ; + if (ENTRY_IS_NONZERO (X4x, X4z, p)) + { + if (px >= nzmax) + { + // increase the size of X + nzmax *= 2 ; + CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; + if (Common->status < CHOLMOD_OK) + { + return (false) ; + } + Xi = X->i ; + Xx = X->x ; + Xz = X->z ; + } + Xi [px] = i ; + ASSIGN (Xx, Xz, px, X4x, X4z, p) ; + px++ ; + } + } + } + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + (*xnz) = px ; + return (true) ; +} + +//------------------------------------------------------------------------------ +// t_cholmod_spsolve_B_clear_worker: clear B4 for the next iteration +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_spsolve_B_clear_worker) +( + cholmod_dense *B4, // output dense matrix + cholmod_sparse *B, // input sparse matrix + Int jfirst, + Int jlast +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Bp = B->p ; + Int *Bi = B->i ; + Int *Bnz = B->nz ; + bool packed = B->packed ; + + Real *B4x = B4->x ; + Real *B4z = B4->z ; + + Int n = B4->nrow ; + + //-------------------------------------------------------------------------- + // clear the entries B4 that were scattered from B (:, jfirst:jast-1) + //-------------------------------------------------------------------------- + + for (Int j = jfirst ; j < jlast ; j++) + { + Int p = Bp [j] ; + Int pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; + Int j_n = (j-jfirst)*n ; + for ( ; p < pend ; p++) + { + Int q = Bi [p] + j_n ; + CLEAR (B4x, B4z, q) ; + } + } +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Config/cholmod.h.in b/CHOLMOD/Config/cholmod.h.in index ba146c7b54..34f4425447 100644 --- a/CHOLMOD/Config/cholmod.h.in +++ b/CHOLMOD/Config/cholmod.h.in @@ -21,14 +21,16 @@ // CHOLMOD/Tcov: SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -// CHOLMOD consists of a set of Modules, each with their own license: either -// LGPL-2.1+ or GPL-2.0+. This cholmod.h file includes defintions of the -// CHOLMOD API for all Modules, and this cholmod.h file itself is provided to -// you with a permissive license (Apache-2.0). You are permitted to provide -// the hooks for an optional interface to CHOLMOD in a non-GPL/non-LGPL code, -// without requiring you to agree to the GPL/LGPL license of the Modules, as -// long as you don't use the *.c files in the relevant Modules. The Modules -// themselves can only be functional if their GPL or LGPL licenses are used. +// CHOLMOD consists of a set of Modules, each with their own Copyright and +// license: either LGPL-2.1+ or GPL-2.0+. This cholmod.h file includes +// defintions of the CHOLMOD API for all Modules, and this cholmod.h file +// itself is provided to you with a permissive license (Apache-2.0). You are +// permitted to provide the hooks for an optional interface to CHOLMOD in a +// non-GPL/non-LGPL code, without requiring you to agree to the GPL/LGPL +// license of the Modules, as long as you don't use the *.c files in the +// relevant Modules. The Modules themselves can only be functional if their +// GPL or LGPL licenses are used, or if you obtain a different license from the +// respective copyright holders. // // The Modify Module is co-authored by William W. Hager. // @@ -38,14 +40,20 @@ // CHOLMOD's Partition Module. // ----------------------------------------------------------------------------- -// Each routine in CHOLMOD has a consistent interface. +#ifndef CHOLMOD_H +#define CHOLMOD_H + +//------------------------------------------------------------------------------ +// CHOLMOD conventions +//------------------------------------------------------------------------------ + +// Each routine in CHOLMOD follows the following conventions: // // Naming convention: // ------------------ // -// All routine names, data types, and CHOLMOD library files use the -// cholmod_ prefix. All macros and other #define's use the CHOLMOD -// prefix. +// All routine names, data types, and CHOLMOD library files use the cholmod_ +// prefix. All macros and other #define's use the CHOLMOD prefix. // // Return value: // ------------- @@ -85,12 +93,152 @@ // The cholmod_common *Common parameter always appears as the last // parameter. It is always an input/output parameter. -#ifndef CHOLMOD_H -#define CHOLMOD_H +//------------------------------------------------------------------------------ +// CHOLMOD matrix formats +//------------------------------------------------------------------------------ -//============================================================================== +// A CHOLMOD sparse, dense, or triplet matrix A, or a sparse factorization L +// can hold numeric values of 8 different types, according to its A->xtype and +// A->dtype parameters (or L->xtype and L->dtype for a sparse factor object). +// These values are held in the A->x array, and also A->z for "zomplex" +// matrices. +// +// A->xtype: the matrix is real, complex, "zomplex", or pattern-only. +// +// (0): CHOLMOD_PATTERN: A->x and A->z are NULL. The matrix has no +// numerical values. Only the pattern is stored. +// +// (1): CHOLMOD_REAL: The matrix is real, and the values are held in +// A->x, whose size (in terms of double or float +// values) is given by A->nzmax. The kth value in +// the matrix is held in A->x [k]. +// +// (2): CHOLMOD_COMPLEX: The matrix is complex, with interleaved real and +// imaginary parts. The kth value in the matrix +// is held in A->x [2*k] and A->x [2*k+1], where +// A->x can hold up to 2*A->nzmax values. +// +// (3): CHOLMOD_ZOMPLEX: The matrix is complex, with separate array for +// the real and imaginary parts. The kth value in +// the matrix is held in A->x [k] and A->z [k], +// where A->x and A->z can hold up to A->nzmax +// values each. + + // A->xtype values: + #define CHOLMOD_PATTERN 0 + #define CHOLMOD_REAL 1 + #define CHOLMOD_COMPLEX 2 + #define CHOLMOD_ZOMPLEX 3 + +// A->dtype: this parameter determines the type of values in A->x (and A->z +// if zomplex). +// +// (0) CHOLMOD_DOUBLE: A->x (and A->z for zomplex matrices) is double. +// If A is real, A->x has a size of A->nzmax * +// sizeof (double). If A is complex, A->x has +// size A->nzmax * 2 * sizeof (double). If +// zomplex, both A->x and A->z have size A->nzmax +// * sizeof (double). +// +// (4) CHOLMOD_SINGLE: A->x (and A->z for zomplex matrices) is float. +// If A is real, A->x has a size of A->nzmax * +// sizeof (float). If A is complex, A->x has size +// A->nzmax * 2 * sizeof (float). If zomplex, +// both A->x and A->z have size A->nzmax * sizeof +// (float). This feature is new to CHOLMOD v5. +// + + // A->dtype values: + #define CHOLMOD_DOUBLE 0 + #define CHOLMOD_SINGLE 4 + +// Unless stated otherwise, the xtype and dtypes of all inputs to a method must +// be the same. +// +// Many methods accept an xdtype parameter, which is simply xtype + dtype, +// combining the two parameters into a single number handling all 8 cases: +// +// (0) CHOLMOD_DOUBLE + CHOLMOD_PATTERN a pattern-only matrix +// (1) CHOLMOD_DOUBLE + CHOLMOD_REAL a double real matrix +// (2) CHOLMOD_DOUBLE + CHOLMOD_COMPLEX a double complex matrix +// (3) CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX a double zomplex matrix +// (4) CHOLMOD_SINGLE + CHOLMOD_PATTERN a pattern-only matrix +// (5) CHOLMOD_SINGLE + CHOLMOD_REAL a float real matrix +// (6) CHOLMOD_SINGLE + CHOLMOD_COMPLEX a float complex matrix +// (7) CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX a float zomplex matrix +// +// This approach was selected for backward compatibility with CHOLMOD v4 and +// earlier, where only the first four values were supported, and where the +// parameter was called "xtype" instead of "xdtype". Several function names +// reflect the older parameter name (cholmod_*_xtype), but they have not been +// renamed "_xdtype", for backward compatibility. +// +// A CHOLMOD sparse or triplet matrix A can held in three symmetry formats +// according to its A->stype parameter. Dense matrices do not have this +// parameter and are always treated as unsymmetric. A sparse factor object L +// is always held in lower triangular form, with no entries ever held in the +// strictly upper triangular part. +// +// 0: the matrix is unsymmetric with both lower and upper parts stored. +// +// <0: the matrix is symmetric, with just the lower triangular part and +// diagonal stored. Any entries in the upper part are ignored. +// +// >0: the matrix is symmetric, with just the upper triangular part stored +// and diagonal. Any entries in the upper part are ignored. +// +// If a sparse or triplet matrix A is complex or zomplex, most methods treat +// the matrix as Hermitian, where A(i,j) is the complex conjugate of A(j,i), +// when i is not equal to j. Some methods can also interpret the matrix as +// complex symmetric, where A(i,j) == A(j,i) when i != j. This is not +// determined by the matrix itself, but by a "mode" parameter of the function. +// This mode parameter also determines if the values of any matrix are to be +// ignored entirely, in which case only the pattern is operated on. Any output +// matrix will have an xtype of CHOLMOD_PATTERN. +// +// The valid mode values are given below, except that many methods do not +// handle the negative cases. Values below the range accepted by the method +// are treated as its lowest accepted value, and values above the range +// accepted by the method are treated as its highest accepted value. +// +// mode = 2: the numerical values of a real, complex, or zomplex matrix are +// handled. If the matrix is complex or zomplex, an entry A(i,j) +// that not stored (or in the ignored part) is treated as the +// complex conjugate of A (j,i). Use this mode to treat a +// complex or zomplex matrix as Hermitian. +// +// mode = 1: the numerical values of a real, complex, or zomplex matrix are +// handled. If the matrix is complex or zomplex, an entry A(i,j) +// that not stored (or in the ignored part) is treated as equal A +// (j,i). Use this mode to treat a complex or zomplex matrix as +// complex symmetric. +// +// mode = 0: the numerical values are ignored. Any output matrix will have +// an xtype of CHOLMOD_PATTERN. This mode allows inputs to have +// different dtypes. +// +// mode = -1: the same as mode = 0, except that the diagonal entries are +// ignored, and do not appear in any output matrix. +// +// mode = -2: the same as mode = -1, except that the output matrix is given an +// additional slack space so that it can hold about 50% more +// entries. This mode is documented here but it is primarily +// meant for internal use, for CHOLMOD's interface to the AMD, +// CAMD, COLAMD, and CCOLAMD ordering methods. +// +// The integer arrays in all objects are either int32 or int64, as determined +// by A->type. This integer type must be identical for all inputs, and must +// also match both the function name (cholmod_method for int32, or +// cholmod_l_method for int64) and the Common->itype as defined when CHOLMOD +// was initialized (via cholmod_start for int32, or cholmod_l_start for int64). + + // itype values: + #define CHOLMOD_INT 0 /* int32, for cholmod_* methods (no _l_) */ + #define CHOLMOD_LONG 2 /* int64, for cholmod_l_* methods */ + +//------------------------------------------------------------------------------ // version control -//============================================================================== +//------------------------------------------------------------------------------ #define CHOLMOD_DATE "@CHOLMOD_DATE@" #define CHOLMOD_MAIN_VERSION @CHOLMOD_VERSION_MAJOR@ @@ -120,9 +268,9 @@ int cholmod_l_version (int version [3]) ; } #endif -//============================================================================== +//------------------------------------------------------------------------------ // Large file support -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD assumes large file support. If problems occur, compile with // -DNLARGEFILE @@ -148,15 +296,15 @@ int cholmod_l_version (int version [3]) ; #endif #endif -//============================================================================== -// SuiteSparse_config -//============================================================================== +//------------------------------------------------------------------------------ +// SuiteSparse_config: definitions for all SuiteSparse packages +//------------------------------------------------------------------------------ #include "SuiteSparse_config.h" -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD configuration -//============================================================================== +//------------------------------------------------------------------------------ // You do not have to edit any CHOLMOD files to compile and install CHOLMOD. // However, if you do not use all of CHOLMOD's modules, you need to compile @@ -231,83 +379,16 @@ int cholmod_l_version (int version [3]) ; //------------------------------------------------------------------------------ // CHOLMOD object enums -#define CHOLMOD_COMMON 0 -#define CHOLMOD_SPARSE 1 -#define CHOLMOD_FACTOR 2 -#define CHOLMOD_DENSE 3 -#define CHOLMOD_TRIPLET 4 - -// enums used by cholmod_symmetry and cholmod_write -#define CHOLMOD_MM_RECTANGULAR 1 -#define CHOLMOD_MM_UNSYMMETRIC 2 -#define CHOLMOD_MM_SYMMETRIC 3 -#define CHOLMOD_MM_HERMITIAN 4 -#define CHOLMOD_MM_SKEW_SYMMETRIC 5 -#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 -#define CHOLMOD_MM_HERMITIAN_POSDIAG 7 +#define CHOLMOD_COMMON 0 /* parameters, statistics, and workspace */ +#define CHOLMOD_SPARSE 1 /* a sparse matrix in CSC form (and variants) */ +#define CHOLMOD_FACTOR 2 /* a sparse factorization */ +#define CHOLMOD_DENSE 3 /* a dense matrix in column-oriented form */ +#define CHOLMOD_TRIPLET 4 /* a sparse matrix in triplet form */ //------------------------------------------------------------------------------ // CHOLMOD Common object //------------------------------------------------------------------------------ -// itype: integer sizes -// The itype is held in the Common object and must match the method used. -#define CHOLMOD_INT 0 /* int32, for cholmod_* methods (no _l_) */ -#define CHOLMOD_LONG 2 /* int64, for cholmod_l_* methods */ - -// dtype: floating point sizes (double or float) -// The dtype of all parameters for all CHOLMOD routines must match. -// NOTE: CHOLMOD_SINGLE is still under development. -#define CHOLMOD_DOUBLE 0 /* matrix or factorization is double precision */ -#define CHOLMOD_SINGLE 4 /* matrix or factorization is single precision */ - -// xtype: pattern, real, complex, or zomplex -#define CHOLMOD_PATTERN 0 /* no numerical values */ -#define CHOLMOD_REAL 1 /* real (double or single), not complex */ -#define CHOLMOD_COMPLEX 2 /* complex (double or single), interleaved */ -#define CHOLMOD_ZOMPLEX 3 /* complex (double or single), with real and imag */ - /* parts held in different arrays */ - -// xdtype is (xtype + dtype), which combines the two type parameters into -// a single number handling all 8 cases: -// -// (0) CHOLMOD_DOUBLE + CHOLMOD_PATTERN a pattern-only matrix -// (1) CHOLMOD_DOUBLE + CHOLMOD_REAL a double real matrix -// (2) CHOLMOD_DOUBLE + CHOLMOD_COMPLEX a double complex matrix -// (3) CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX a double zomplex matrix -// (4) CHOLMOD_SINGLE + CHOLMOD_PATTERN a pattern-only matrix -// (5) CHOLMOD_SINGLE + CHOLMOD_REAL a float real matrix -// (6) CHOLMOD_SINGLE + CHOLMOD_COMPLEX a float complex matrix -// (7) CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX a float zomplex matrix - -// max # of ordering methods in Common -#define CHOLMOD_MAXMETHODS 9 - -// Common->status for error handling: 0 is ok, negative is a fatal error, -// and positive is a warning -#define CHOLMOD_OK (0) -#define CHOLMOD_NOT_INSTALLED (-1) /* module not installed */ -#define CHOLMOD_OUT_OF_MEMORY (-2) /* malloc, calloc, or realloc failed */ -#define CHOLMOD_TOO_LARGE (-3) /* integer overflow */ -#define CHOLMOD_INVALID (-4) /* input invalid */ -#define CHOLMOD_GPU_PROBLEM (-5) /* CUDA error */ -#define CHOLMOD_NOT_POSDEF (1) /* matrix not positive definite */ -#define CHOLMOD_DSMALL (2) /* diagonal entry very small */ - -// ordering method -#define CHOLMOD_NATURAL 0 /* no preordering */ -#define CHOLMOD_GIVEN 1 /* user-provided permutation */ -#define CHOLMOD_AMD 2 /* AMD: approximate minimum degree */ -#define CHOLMOD_METIS 3 /* METIS: mested dissection */ -#define CHOLMOD_NESDIS 4 /* CHOLMOD's nested dissection */ -#define CHOLMOD_COLAMD 5 /* AMD for A, COLAMD for AA' or A'A */ -#define CHOLMOD_POSTORDERED 6 /* natural then postordered */ - -// supernodal strategy -#define CHOLMOD_SIMPLICIAL 0 /* always use simplicial method */ -#define CHOLMOD_AUTO 1 /* auto select simplicial vs supernodal */ -#define CHOLMOD_SUPERNODAL 2 /* always use supernoda method */ - #ifdef __cplusplus extern "C" { #endif @@ -321,22 +402,22 @@ typedef struct cholmod_common_struct double dbound ; // Bounds the diagonal entries of D for LDL' // factorization and update/downdate/rowadd. Entries outside this - // bound are replaced with dbound. Default: 0. - // dbound is used for double precision factorization only. - // See sbound for single precision factorization. + // bound are replaced with dbound. Default: 0. dbound is used for + // double precision factorization only. See sbound for single + // precision factorization. double grow0 ; // default: 1.2 double grow1 ; // default: 1.2 size_t grow2 ; // default: 5 // Initial space for simplicial factorization is max(grow0,1) times the - // required space. If space is exhausted, L is grown by - // max(grow0,1.2) times the required space. grow1 and grow2 control - // how each column of L can grow in an update/downdate; if space runs - // out, then grow1*(required space) + grow2 is allocated. + // required space. If space is exhausted, L is grown by max(grow0,1.2) + // times the required space. grow1 and grow2 control how each column + // of L can grow in an update/downdate; if space runs out, then + // grow1*(required space) + grow2 is allocated. size_t maxrank ; // maximum rank for update/downdate. Valid values are - // 2, 4, and 8. Default is 8. If a larger update/downdate is done, - // it is done in steps of maxrank. + // 2, 4, and 8. Default is 8. If a larger update/downdate is done, it + // is done in steps of maxrank. double supernodal_switch ; // default: 40 int supernodal ; // default: CHOLMOD_AUTO. @@ -346,6 +427,10 @@ typedef struct cholmod_common_struct // always done. If CHOLMOD_AUTO, then a simplicial factorization is // down if flops/nnz(L) < Common->supernodal_switch. + #define CHOLMOD_SIMPLICIAL 0 /* always use simplicial method */ + #define CHOLMOD_AUTO 1 /* auto select simplicial vs supernodal */ + #define CHOLMOD_SUPERNODAL 2 /* always use supernoda method */ + int final_asis ; // if true, other final_* parameters are ignored, // except for final_pack and the factors are left as-is when done. // Default: true. @@ -411,6 +496,10 @@ typedef struct cholmod_common_struct // entries in row/column k, and off-diagonals are set to -1. // Default: false. + //-------------------------------------------------------------------------- + // printing and error handling options + //-------------------------------------------------------------------------- + int print ; // print level. Default is 3. int precise ; // if true, print 16 digits, otherwise 5. Default: false. @@ -543,11 +632,20 @@ typedef struct cholmod_common_struct // components is partitioned separately. If false, the whole // subgraph is partitioned. Default: false. - int ordering ; // ordering method to use + int ordering ; // ordering method to use: + + #define CHOLMOD_NATURAL 0 /* no preordering */ + #define CHOLMOD_GIVEN 1 /* user-provided permutation */ + #define CHOLMOD_AMD 2 /* AMD: approximate minimum degree */ + #define CHOLMOD_METIS 3 /* METIS: mested dissection */ + #define CHOLMOD_NESDIS 4 /* CHOLMOD's nested dissection */ + #define CHOLMOD_COLAMD 5 /* AMD for A, COLAMD for AA' or A'A */ + #define CHOLMOD_POSTORDERED 6 /* natural then postordered */ size_t other_3 [4] ; // unused, for future expansion } + #define CHOLMOD_MAXMETHODS 9 /* max # of methods in Common->method */ method [CHOLMOD_MAXMETHODS + 1] ; int postorder ; // if true, CHOLMOD performs a weighted postordering @@ -586,9 +684,8 @@ typedef struct cholmod_common_struct int64_t mark ; // Flag is cleared if Flag [0..nrow-1] < mark. size_t iworksize ; // size of Iwork, in Ints (int32 or int64). // This is at most 6*nrow + ncol. - size_t xworkbytes ; // size of Xwork, in bytes. for update/downdate: - // maxrank*nrow*sizeof(double or float), 2*nrow*sizeof(double or float) - // otherwise. NOTE: in CHOLMOD v4 and earlier, xworkwise was in terms + size_t xworkbytes ; // size of Xwork, in bytes. + // NOTE: in CHOLMOD v4 and earlier, xworkwise was in terms // of # of doubles, not # of bytes. void *Flag ; // size nrow. If this is "cleared" then @@ -624,7 +721,19 @@ typedef struct cholmod_common_struct // statistics //-------------------------------------------------------------------------- - int status ; // status code (0: ok, negative: error, pos: warning + int status ; // status code (0: ok, negative: error, pos: warning) + + // Common->status for error handling: 0 is ok, negative is a fatal + // error, and positive is a warning + #define CHOLMOD_OK (0) + #define CHOLMOD_NOT_INSTALLED (-1) /* module not installed */ + #define CHOLMOD_OUT_OF_MEMORY (-2) /* malloc/calloc/realloc failed */ + #define CHOLMOD_TOO_LARGE (-3) /* integer overflow */ + #define CHOLMOD_INVALID (-4) /* input invalid */ + #define CHOLMOD_GPU_PROBLEM (-5) /* CUDA error */ + #define CHOLMOD_NOT_POSDEF (1) /* matrix not positive definite */ + #define CHOLMOD_DSMALL (2) /* diagonal entry very small */ + double fl ; // flop count from last analysis double lnz ; // nnz(L) from last analysis double anz ; // in last analysis: nnz(tril(A)) or nnz(triu(A)) if A @@ -692,11 +801,12 @@ typedef struct cholmod_common_struct // as well. This mitigates any changes between v4.0 and v5.0, and may make // it easier to upgrade from v4 to v5. - double nsbounds_hit ; // # of times diagonal modified by sbound. This - // ought to be int64_t, but ndbounds_hit was double in v4 - // (see above), so nsbounds_hit is made the same type for - // consistency. - float sbound ; // Same as dbound, but for single precision factorization. + double nsbounds_hit ; // # of times diagonal modified by sbound. + // This ought to be int64_t, but ndbounds_hit was double in + // v4 (see above), so nsbounds_hit is made the same type + // for consistency. + float sbound ; // Same as dbound, + // but for single precision factorization. float other_6 ; // for future expansion //-------------------------------------------------------------------------- @@ -777,6 +887,8 @@ typedef struct cholmod_common_struct int nthreads_max ; // max # of OpenMP threads to use in CHOLMOD. // Defaults to SUITESPARSE_OPENMP_MAX_THREADS. + FILE *blas_dump ; // only used if CHOLMOD is compiled with -DBLAS_DUMP + } cholmod_common ; // size_t BLAS statistcs in Common: @@ -801,11 +913,6 @@ typedef struct cholmod_common_struct #define CHOLMOD_ASSEMBLE_TIME cholmod_assemble_time #define CHOLMOD_ASSEMBLE_TIME2 cholmod_assemble_time2 -// for supernodal analysis: -#define CHOLMOD_ANALYZE_FOR_SPQR 0 -#define CHOLMOD_ANALYZE_FOR_CHOLESKY 1 -#define CHOLMOD_ANALYZE_FOR_SPQRGPU 2 - //------------------------------------------------------------------------------ // cholmod_start: first call to CHOLMOD //------------------------------------------------------------------------------ @@ -833,6 +940,7 @@ int cholmod_l_defaults (cholmod_common *) ; size_t cholmod_maxrank // return validated Common->maxrank ( + // input: size_t n, // # of rows of L and A cholmod_common *Common ) ; @@ -847,6 +955,7 @@ size_t cholmod_l_maxrank (size_t, cholmod_common *) ; int cholmod_allocate_work ( + // input: size_t nrow, // size of Common->Flag (nrow int32's) // and Common->Head (nrow+1 int32's) size_t iworksize, // size of Common->Iwork (# of int32's) @@ -863,6 +972,7 @@ int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ; int cholmod_alloc_work ( + // input: size_t nrow, // size of Common->Flag (nrow int32's) // and Common->Head (nrow+1 int32's) size_t iworksize, // size of Common->Iwork (# of int32's) @@ -903,6 +1013,7 @@ int64_t cholmod_l_clear_flag (cholmod_common *) ; int cholmod_error ( + // input: int status, // Common->status const char *file, // source file where error occurred int line, // line number where error occurred @@ -920,8 +1031,8 @@ int cholmod_l_error (int, const char *, int, const char *, cholmod_common *) ; double cholmod_dbound (double, cholmod_common *) ; double cholmod_l_dbound (double, cholmod_common *) ; -float cholmod_sbound (float, cholmod_common *) ; -float cholmod_l_sbound (float, cholmod_common *) ; +float cholmod_sbound (float, cholmod_common *) ; +float cholmod_l_sbound (float, cholmod_common *) ; //------------------------------------------------------------------------------ // cholmod_hypot: compute sqrt (x*x + y*y) accurately @@ -936,6 +1047,7 @@ double cholmod_l_hypot (double, double) ; int cholmod_divcomplex // return 1 if divide-by-zero, 0 if OK ( + // input: double ar, double ai, // a (real, imaginary) double br, double bi, // b (real, imaginary) double *cr, double *ci // c (real, imaginary) @@ -992,6 +1104,7 @@ typedef struct cholmod_sparse_struct cholmod_sparse *cholmod_allocate_sparse ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1012,6 +1125,7 @@ cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int, int cholmod_free_sparse ( + // input/output: cholmod_sparse **A, // handle of sparse matrix to free cholmod_common *Common ) ; @@ -1023,7 +1137,9 @@ int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ; int cholmod_reallocate_sparse ( + // input: size_t nznew, // new max # of nonzeros the sparse matrix can hold + // input/output: cholmod_sparse *A, // sparse matrix to reallocate cholmod_common *Common ) ; @@ -1035,6 +1151,7 @@ int cholmod_l_reallocate_sparse (size_t, cholmod_sparse *, cholmod_common *) ; int64_t cholmod_nnz // return # of entries in the sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to query cholmod_common *Common ) ; @@ -1046,6 +1163,7 @@ int64_t cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ; cholmod_sparse *cholmod_speye ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1064,6 +1182,7 @@ cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ; cholmod_sparse *cholmod_spzeros // return a sparse matrix with no entries ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1081,9 +1200,11 @@ cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int, cholmod_sparse *cholmod_transpose // return new sparse matrix C ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) cholmod_common *Common ) ; cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; @@ -1098,12 +1219,15 @@ cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; int cholmod_transpose_unsym ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,f)', or NULL int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) ; @@ -1120,10 +1244,13 @@ int cholmod_l_transpose_unsym (cholmod_sparse *, int, int64_t *, int64_t *, int cholmod_transpose_sym ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,p)', or NULL + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) ; @@ -1136,9 +1263,11 @@ int cholmod_l_transpose_sym (cholmod_sparse *, int, int64_t *, cholmod_sparse *, cholmod_sparse *cholmod_ptranspose // return new sparse matrix C ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,f)', or NULL int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset @@ -1148,11 +1277,12 @@ cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, int64_t *, int64_t *, size_t, cholmod_common *) ; //------------------------------------------------------------------------------ -// cholmod_sort: sort the indices of a sparse matrix +// cholmod_sort: sort the indices of a sparse matrix //------------------------------------------------------------------------------ int cholmod_sort ( + // input/output: cholmod_sparse *A, // input/output matrix to sort cholmod_common *Common ) ; @@ -1164,6 +1294,7 @@ int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ; int64_t cholmod_band_nnz // return # of entries in a band (-1 if error) ( + // input: cholmod_sparse *A, // matrix to examine int64_t k1, // count entries in k1:k2 diagonals int64_t k2, @@ -1179,6 +1310,7 @@ int64_t cholmod_l_band_nnz (cholmod_sparse *, int64_t, int64_t, bool, cholmod_sparse *cholmod_band // return a new matrix C ( + // input: cholmod_sparse *A, // input matrix int64_t k1, // count entries in k1:k2 diagonals int64_t k2, @@ -1189,14 +1321,16 @@ cholmod_sparse *cholmod_l_band (cholmod_sparse *, int64_t, int64_t, int, cholmod_common *) ; //------------------------------------------------------------------------------ -// cholmod_band_inplace: A = tril (triu (A,k1), k2) */ +// cholmod_band_inplace: A = tril (triu (A,k1), k2) //------------------------------------------------------------------------------ int cholmod_band_inplace ( + // input: int64_t k1, // count entries in k1:k2 diagonals int64_t k2, int mode, // >0: numerical, 0: pattern, <0: pattern (no diag) + // input/output: cholmod_sparse *A, // input/output matrix cholmod_common *Common ) ; @@ -1209,11 +1343,14 @@ int cholmod_l_band_inplace (int64_t, int64_t, int, cholmod_sparse *, cholmod_sparse *cholmod_aat // return sparse matrix C ( + // input: cholmod_sparse *A, // input matrix int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) + // -1: pattern (remove diag), // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) ; @@ -1230,6 +1367,7 @@ cholmod_sparse *cholmod_l_aat (cholmod_sparse *, int64_t *, size_t, int, cholmod_sparse *cholmod_copy_sparse // return new sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to copy cholmod_common *Common ) ; @@ -1241,10 +1379,13 @@ cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ; cholmod_sparse *cholmod_copy // return new sparse matrix ( + // input: cholmod_sparse *A, // input matrix, not modified int stype, // stype of C - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) + // -1: pattern (remove diag) // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) ; @@ -1256,11 +1397,14 @@ cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ; cholmod_sparse *cholmod_add // return C = alpha*A + beta*B ( + // input: cholmod_sparse *A, // input matrix cholmod_sparse *B, // input matrix double alpha [2], // scale factor for A (two entires used if complex) double beta [2], // scale factor for A (two entires used if complex) - int values, // if TRUE compute the numerical values of C + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern int sorted, // ignored; C is now always returned as sorted cholmod_common *Common ) ; @@ -1273,7 +1417,9 @@ cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *, int cholmod_sparse_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_sparse *A, // sparse matrix to change cholmod_common *Common ) ; @@ -1305,24 +1451,19 @@ typedef struct cholmod_factor_struct // simplicial factorization (not supernodal) //-------------------------------------------------------------------------- - size_t nzmax ; // # of entries that L->i, L->x, and L->z can hold + // The row indices of L(:,j) are held in L->i [L->p [j] ... L->p [j] + + // L->nz [j] - 1]. The numeical values of L(:,j) are held in the same + // positions in L->x (and L->z if L is zomplex). L->next and L->prev hold + // a link list of columns of L, that tracks the order they appear in the + // arrays L->i, L->x, and L->z. The head and tail of the list is n+1 and + // n, respectively. + size_t nzmax ; // # of entries that L->i, L->x, and L->z can hold void *p ; // int32/int64, size n+1, column pointers void *i ; // int32/int64, size nzmax, row indices void *x ; // float/double, size nzmax or 2*nzmax, numerical values void *z ; // float/double, size nzmax or empty, imaginary values void *nz ; // int32/int64, size ncol, # of entries in each column - - // The row indices of L(:,j) are held in - // L->i [L->p [j] ... L->p [j] + L->nz [j] - 1]. - - // The numeical values of L(:,j) are held in the same positions in L->x - // (and L->z if L is zomplex) - - // L->next and L->prev hold a link list of columns of L, that tracks the - // order they appear in the arrays L->i, L->x, and L->z. The head and tail - // of the list is n+1 and n, respectively. - void *next ; // int32/int64, size n+2 void *prev ; // int32/int64, size n+2 @@ -1338,13 +1479,12 @@ typedef struct cholmod_factor_struct size_t xsize ; // # of entries in L->x size_t maxcsize ; // size of largest update matrix size_t maxesize ; // max # of rows in supernodes, excl. triangular part - // the following are int32/int64 and are size nsuper+1: void *super ; // first column in each supernode void *pi ; // index into L->s for integer part of a supernode void *px ; // index into L->x for numeric part of a supernode - - void *s ; // int32/int64, ssize, integer part of supernodes + // int32/int64, of size ssize: + void *s ; // integer part of supernodes //-------------------------------------------------------------------------- // type of the factorization @@ -1378,7 +1518,6 @@ typedef struct cholmod_factor_struct // If L->xtype is CHOLMOD_REAL, CHOLMOD_COMPLEX, or CHOLMOD_ZOMPLEX, // then L is a numeric factor: // - // // simplicial LDL': (is_ll false, is_super false). Stored in compressed // column form, using the simplicial components above (nzmax, p, i, // x, z, nz, next, and prev). The unit diagonal of L is not stored, @@ -1414,6 +1553,7 @@ typedef struct cholmod_factor_struct cholmod_factor *cholmod_allocate_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix cholmod_common *Common ) ; @@ -1423,8 +1563,9 @@ cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ; // cholmod_alloc_factor: allocate a numerical factor (double or single) //------------------------------------------------------------------------------ -cholmod_factor *cholmod_alloc_factor // return the new factor L +cholmod_factor *cholmod_alloc_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix int dtype, // CHOLMOD_SINGLE or CHOLMOD_DOUBLE cholmod_common *Common @@ -1437,6 +1578,7 @@ cholmod_factor *cholmod_l_alloc_factor (size_t, int, cholmod_common *) ; int cholmod_free_factor ( + // input/output: cholmod_factor **L, // handle of sparse factorization to free cholmod_common *Common ) ; @@ -1448,7 +1590,9 @@ int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ; int cholmod_reallocate_factor ( + // input: size_t nznew, // new max # of nonzeros the factor matrix can hold + // input/output: cholmod_factor *L, // factor to reallocate cholmod_common *Common ) ; @@ -1460,11 +1604,14 @@ int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ; int cholmod_change_factor ( - int to_xtype, // CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX + // input: + int to_xtype, // CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX; + // L->dtype remains unchanged. int to_ll, // if true: convert to LL'; else to LDL' int to_super, // if true: convert to supernodal; else to simplicial int to_packed, // if true: pack simplicial columns' else: do not pack int to_monotonic, // if true, put simplicial columns in order + // input/output: cholmod_factor *L, // factor to change. cholmod_common *Common ) ; @@ -1479,6 +1626,7 @@ int cholmod_l_change_factor (int, int, int, int, int, cholmod_factor *, int cholmod_pack_factor ( + // input/output: cholmod_factor *L, // factor to pack cholmod_common *Common ) ; @@ -1490,8 +1638,10 @@ int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ; int cholmod_reallocate_column ( + // input: size_t j, // reallocate L(:,j) size_t need, // space in L(:,j) for this # of entries + // input/output: cholmod_factor *L, // L factor modified, L(:,j) resized cholmod_common *Common ) ; @@ -1504,6 +1654,7 @@ int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *, cholmod_sparse *cholmod_factor_to_sparse // return a new sparse matrix ( + // input/output: cholmod_factor *L, // input: factor to convert; output: L is converted // to a simplicial symbolic factor cholmod_common *Common @@ -1517,6 +1668,7 @@ cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *, cholmod_factor *cholmod_copy_factor // return a copy of the factor ( + // input: cholmod_factor *L, // factor to copy (not modified) cholmod_common *Common ) ; @@ -1528,7 +1680,9 @@ cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ; int cholmod_factor_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_factor *L, // factor to change cholmod_common *Common ) ; @@ -1557,6 +1711,7 @@ typedef struct cholmod_dense_struct cholmod_dense *cholmod_allocate_dense ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension @@ -1574,6 +1729,7 @@ cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int, cholmod_dense *cholmod_zeros ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1589,6 +1745,7 @@ cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ; cholmod_dense *cholmod_ones ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1604,6 +1761,7 @@ cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ; cholmod_dense *cholmod_eye // return a dense identity matrix ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1619,6 +1777,7 @@ cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ; int cholmod_free_dense ( + // input/output: cholmod_dense **X, // handle of dense matrix to free cholmod_common *Common ) ; @@ -1630,7 +1789,9 @@ int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ; cholmod_dense *cholmod_ensure_dense ( + // input/output: cholmod_dense **X, // matrix to resize as needed (*X may be NULL) + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension @@ -1648,6 +1809,7 @@ cholmod_dense *cholmod_l_ensure_dense (cholmod_dense **, size_t, size_t, cholmod_dense *cholmod_sparse_to_dense // return a dense matrix ( + // input: cholmod_sparse *A, // input matrix cholmod_common *Common ) ; @@ -1659,6 +1821,7 @@ cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *, cholmod_common *) ; int64_t cholmod_dense_nnz // return # of entries in the dense matrix ( + // input: cholmod_dense *X, // input matrix cholmod_common *Common ) ; @@ -1670,8 +1833,10 @@ int64_t cholmod_l_dense_nnz (cholmod_dense *, cholmod_common *) ; cholmod_sparse *cholmod_dense_to_sparse // return a sparse matrix C ( + // input: cholmod_dense *X, // input matrix - int values, // if true, copy the values; if false, C is pattern + int mode, // 1: copy the values + // 0: C is pattern cholmod_common *Common ) ; cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, @@ -1683,6 +1848,7 @@ cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, cholmod_dense *cholmod_copy_dense // returns new dense matrix ( + // input: cholmod_dense *X, // input dense matrix cholmod_common *Common ) ; @@ -1694,7 +1860,9 @@ cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ; int cholmod_copy_dense2 ( + // input: cholmod_dense *X, // input dense matrix + // input/output: cholmod_dense *Y, // output dense matrix (already allocated on input) cholmod_common *Common ) ; @@ -1706,7 +1874,9 @@ int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ; int cholmod_dense_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_dense *X, // dense matrix to change cholmod_common *Common ) ; @@ -1760,6 +1930,7 @@ typedef struct cholmod_triplet_struct cholmod_triplet *cholmod_allocate_triplet // return triplet matrix T ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1778,6 +1949,7 @@ cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int, int cholmod_free_triplet ( + // input/output: cholmod_triplet **T, // handle of triplet matrix to free cholmod_common *Common ) ; @@ -1789,7 +1961,9 @@ int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ; int cholmod_reallocate_triplet ( + // input: size_t nznew, // new max # of nonzeros the triplet matrix can hold + // input/output: cholmod_triplet *T, // triplet matrix to reallocate cholmod_common *Common ) ; @@ -1801,6 +1975,7 @@ int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ; cholmod_triplet *cholmod_sparse_to_triplet ( + // input: cholmod_sparse *A, // matrix to copy into triplet form T cholmod_common *Common ) ; @@ -1813,6 +1988,7 @@ cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *, cholmod_sparse *cholmod_triplet_to_sparse // return sparse matrix A ( + // input: cholmod_triplet *T, // input triplet matrix size_t nzmax, // allocate space for max(nzmax,nnz(A)) entries cholmod_common *Common @@ -1826,6 +2002,7 @@ cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t, cholmod_triplet *cholmod_copy_triplet // return new triplet matrix ( + // input: cholmod_triplet *T, // triplet matrix to copy cholmod_common *Common ) ; @@ -1837,15 +2014,17 @@ cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ; int cholmod_triplet_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_triplet *T, // triplet matrix to change cholmod_common *Common ) ; int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; -//============================================================================== -// memory allocation -//============================================================================== +//------------------------------------------------------------------------------ +// memory allocation: malloc/calloc/realloc/free +//------------------------------------------------------------------------------ // These methods act like malloc/calloc/realloc/free, with some differences. // They are simple wrappers around the memory management functions in @@ -1858,6 +2037,7 @@ int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; void *cholmod_malloc // return pointer to newly allocated memory ( + // input: size_t n, // number of items size_t size, // size of each item cholmod_common *Common @@ -1866,6 +2046,7 @@ void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ; void *cholmod_calloc // return pointer to newly allocated memory ( + // input: size_t n, // number of items size_t size, // size of each item cholmod_common *Common @@ -1874,8 +2055,10 @@ void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ; void *cholmod_free // returns NULL to simplify its usage ( + // input: size_t n, // number of items size_t size, // size of each item + // input/output: void *p, // memory to free cholmod_common *Common ) ; @@ -1883,8 +2066,10 @@ void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ; void *cholmod_realloc // return newly reallocated block of memory ( + // input: size_t nnew, // # of items in newly reallocate memory size_t size, // size of each item + // input/output: void *p, // pointer to memory to reallocate (may be NULL) size_t *n, // # of items in p on input; nnew on output if success cholmod_common *Common @@ -1893,6 +2078,7 @@ void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ; int cholmod_realloc_multiple // returns true if successful, false otherwise ( + // input: size_t nnew, // # of items in newly reallocate memory int nint, // 0: do not allocate I_block or J_block, 1: just I_block, // 2: both I_block and J_block @@ -1911,9 +2097,9 @@ int cholmod_realloc_multiple // returns true if successful, false otherwise int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, void **, size_t *, cholmod_common *) ; -//============================================================================== +//------------------------------------------------------------------------------ // numerical comparisons -//============================================================================== +//------------------------------------------------------------------------------ // These macros were different on Windows for older versions of CHOLMOD. // They are no longer needed but are kept for backward compatibility. @@ -1933,411 +2119,427 @@ int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, #ifndef NCHECK -/* Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds - * of integer vectors (subset, perm, and parent), and read in matrices from a - * file: - * - * cholmod_check_common check/print the Common object - * cholmod_print_common - * - * cholmod_check_sparse check/print a sparse matrix in column-oriented form - * cholmod_print_sparse - * - * cholmod_check_dense check/print a dense matrix - * cholmod_print_dense - * - * cholmod_check_factor check/print a Cholesky factorization - * cholmod_print_factor - * - * cholmod_check_triplet check/print a sparse matrix in triplet form - * cholmod_print_triplet - * - * cholmod_check_subset check/print a subset (integer vector in given range) - * cholmod_print_subset - * - * cholmod_check_perm check/print a permutation (an integer vector) - * cholmod_print_perm - * - * cholmod_check_parent check/print an elimination tree (an integer vector) - * cholmod_print_parent - * - * cholmod_read_triplet read a matrix in triplet form (any Matrix Market - * "coordinate" format, or a generic triplet format). - * - * cholmod_read_sparse read a matrix in sparse form (same file format as - * cholmod_read_triplet). - * - * cholmod_read_dense read a dense matrix (any Matrix Market "array" - * format, or a generic dense format). - * - * cholmod_write_sparse write a sparse matrix to a Matrix Market file. - * - * cholmod_write_dense write a dense matrix to a Matrix Market file. - * - * cholmod_print_common and cholmod_check_common are the only two routines that - * you may call after calling cholmod_finish. - * - * Requires the Utility module. Not required by any CHOLMOD module, except when - * debugging is enabled (in which case all modules require the Check module). - * - * See cholmod_read.c for a description of the file formats supported by the - * cholmod_read_* routines. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_check_common: check the Common object */ -/* -------------------------------------------------------------------------- */ +// Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds +// of integer vectors (subset, perm, and parent), and read in matrices from a +// file: +// +// cholmod_check_common check/print the Common object +// cholmod_print_common +// +// cholmod_check_sparse check/print a sparse matrix in column-oriented form +// cholmod_print_sparse +// +// cholmod_check_dense check/print a dense matrix +// cholmod_print_dense +// +// cholmod_check_factor check/print a Cholesky factorization +// cholmod_print_factor +// +// cholmod_check_triplet check/print a sparse matrix in triplet form +// cholmod_print_triplet +// +// cholmod_check_subset check/print a subset (integer vector in given range) +// cholmod_print_subset +// +// cholmod_check_perm check/print a permutation (an integer vector) +// cholmod_print_perm +// +// cholmod_check_parent check/print an elimination tree (an integer vector) +// cholmod_print_parent +// +// cholmod_read_triplet read a matrix in triplet form (any Matrix Market +// "coordinate" format, or a generic triplet format). +// +// cholmod_read_sparse read a matrix in sparse form (same file format as +// cholmod_read_triplet). +// +// cholmod_read_dense read a dense matrix (any Matrix Market "array" +// format, or a generic dense format). +// +// cholmod_write_sparse write a sparse matrix to a Matrix Market file. +// +// cholmod_write_dense write a dense matrix to a Matrix Market file. +// +// cholmod_print_common and cholmod_check_common are the only two routines that +// you may call after calling cholmod_finish. +// +// Requires the Utility module. Not required by any CHOLMOD module, except when +// debugging is enabled (in which case all modules require the Check module). +// +// See cholmod_read.c for a description of the file formats supported by the +// cholmod_read_* routines. + +//------------------------------------------------------------------------------ +// cholmod_check_common: check the Common object +//------------------------------------------------------------------------------ int cholmod_check_common ( cholmod_common *Common ) ; - int cholmod_l_check_common (cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_common: print the Common object */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_common: print the Common object +//------------------------------------------------------------------------------ int cholmod_print_common ( - /* ---- input ---- */ - const char *name, /* printed name of Common object */ - /* --------------- */ + // input: + const char *name, // printed name of Common object cholmod_common *Common ) ; int cholmod_l_print_common (const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_gpu_stats: print the GPU / CPU statistics */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_gpu_stats: print the GPU / CPU statistics +//------------------------------------------------------------------------------ int cholmod_gpu_stats (cholmod_common *) ; int cholmod_l_gpu_stats (cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_sparse: check a sparse matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_sparse: check a sparse matrix +//------------------------------------------------------------------------------ int cholmod_check_sparse ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to check */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to check cholmod_common *Common ) ; - int cholmod_l_check_sparse (cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_sparse */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_sparse +//------------------------------------------------------------------------------ int cholmod_print_sparse ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to print */ - const char *name, /* printed name of sparse matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to print + const char *name, // printed name of sparse matrix cholmod_common *Common ) ; - int cholmod_l_print_sparse (cholmod_sparse *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_dense: check a dense matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_dense: check a dense matrix +//------------------------------------------------------------------------------ int cholmod_check_dense ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to check */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to check cholmod_common *Common ) ; - int cholmod_l_check_dense (cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_dense: print a dense matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_dense: print a dense matrix +//------------------------------------------------------------------------------ int cholmod_print_dense ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to print */ - const char *name, /* printed name of dense matrix */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to print + const char *name, // printed name of dense matrix cholmod_common *Common ) ; - int cholmod_l_print_dense (cholmod_dense *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_factor: check a factor */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_factor: check a factor +//------------------------------------------------------------------------------ int cholmod_check_factor ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to check */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to check cholmod_common *Common ) ; - int cholmod_l_check_factor (cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_factor: print a factor */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_factor: print a factor +//------------------------------------------------------------------------------ int cholmod_print_factor ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to print */ - const char *name, /* printed name of factor */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to print + const char *name, // printed name of factor cholmod_common *Common ) ; - int cholmod_l_print_factor (cholmod_factor *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_triplet: check a sparse matrix in triplet form */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_triplet: check a sparse matrix in triplet form +//------------------------------------------------------------------------------ int cholmod_check_triplet ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to check */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to check cholmod_common *Common ) ; - int cholmod_l_check_triplet (cholmod_triplet *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_triplet: print a triplet matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_triplet: print a triplet matrix +//------------------------------------------------------------------------------ int cholmod_print_triplet ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to print */ - const char *name, /* printed name of triplet matrix */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to print + const char *name, // printed name of triplet matrix cholmod_common *Common ) ; - int cholmod_l_print_triplet (cholmod_triplet *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_subset: check a subset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_subset: check a subset +//------------------------------------------------------------------------------ int cholmod_check_subset ( - /* ---- input ---- */ - int32_t *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + int32_t *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array) + size_t n, // 0:n-1 is valid range cholmod_common *Common ) ; +int cholmod_l_check_subset (int64_t *, int64_t, size_t, cholmod_common *) ; -int cholmod_l_check_subset (int64_t *, int64_t, size_t, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_print_subset: print a subset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_subset: print a subset +//------------------------------------------------------------------------------ int cholmod_print_subset ( - /* ---- input ---- */ - int32_t *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Set */ - /* --------------- */ + // input: + int32_t *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array) + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Set cholmod_common *Common ) ; +int cholmod_l_print_subset (int64_t *, int64_t, size_t, const char *, + cholmod_common *) ; -int cholmod_l_print_subset (int64_t *, int64_t, size_t, - const char *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_check_perm: check a permutation */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_perm: check a permutation +//------------------------------------------------------------------------------ int cholmod_check_perm ( - /* ---- input ---- */ - int32_t *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + int32_t *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range cholmod_common *Common ) ; +int cholmod_l_check_perm (int64_t *, size_t, size_t, cholmod_common *) ; -int cholmod_l_check_perm (int64_t *, size_t, size_t, cholmod_common *); - -/* -------------------------------------------------------------------------- */ -/* cholmod_print_perm: print a permutation vector */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_perm: print a permutation vector +//------------------------------------------------------------------------------ int cholmod_print_perm ( - /* ---- input ---- */ - int32_t *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Perm */ - /* --------------- */ + // input: + int32_t *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Perm cholmod_common *Common ) ; - int cholmod_l_print_perm (int64_t *, size_t, size_t, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_parent: check an elimination tree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_parent: check an elimination tree +//------------------------------------------------------------------------------ int cholmod_check_parent ( - /* ---- input ---- */ - int32_t *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - /* --------------- */ + // input: + int32_t *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent cholmod_common *Common ) ; - int cholmod_l_check_parent (int64_t *, size_t, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_parent */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_parent +//------------------------------------------------------------------------------ int cholmod_print_parent ( - /* ---- input ---- */ - int32_t *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - const char *name, /* printed name of Parent */ - /* --------------- */ + // input: + int32_t *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent + const char *name, // printed name of Parent cholmod_common *Common ) ; +int cholmod_l_print_parent (int64_t *, size_t, const char *, cholmod_common *) ; -int cholmod_l_print_parent (int64_t *, size_t, const char *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_read_sparse: read a sparse matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_sparse: read a sparse matrix from a file (double only) +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_read_sparse +cholmod_sparse *cholmod_read_sparse // return sparse matrix (double) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_read_sparse (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_triplet: read a triplet matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_sparse2: read a sparse matrix from a file (float or double) +//------------------------------------------------------------------------------ -cholmod_triplet *cholmod_read_triplet +cholmod_sparse *cholmod_read_sparse2 // return sparse matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_sparse *cholmod_l_read_sparse2 (FILE *, int, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_read_triplet: read a triplet matrix from a file (double only) +//------------------------------------------------------------------------------ + +cholmod_triplet *cholmod_read_triplet // return triplet matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) ; cholmod_triplet *cholmod_l_read_triplet (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_dense: read a dense matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_triplet: read a triplet matrix from a file (float or double) +//------------------------------------------------------------------------------ -cholmod_dense *cholmod_read_dense +cholmod_triplet *cholmod_read_triplet2 // return triplet matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_triplet *cholmod_l_read_triplet2 (FILE *, int, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_read_dense: read a dense matrix from a file (double only) +//------------------------------------------------------------------------------ + +cholmod_dense *cholmod_read_dense // return dense matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) ; cholmod_dense *cholmod_l_read_dense (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_matrix: read a sparse or dense matrix from a file */ -/* -------------------------------------------------------------------------- */ - -void *cholmod_read_matrix -( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - int prefer, /* If 0, a sparse matrix is always return as a - * cholmod_triplet form. It can have any stype - * (symmetric-lower, unsymmetric, or - * symmetric-upper). - * If 1, a sparse matrix is returned as an unsymmetric - * cholmod_sparse form (A->stype == 0), with both - * upper and lower triangular parts present. - * This is what the MATLAB mread mexFunction does, - * since MATLAB does not have an stype. - * If 2, a sparse matrix is returned with an stype of 0 - * or 1 (unsymmetric, or symmetric with upper part - * stored). - * This argument has no effect for dense matrices. - */ - /* ---- output---- */ - int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */ - /* --------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_dense2: read a dense matrix from a file (float or double) +//------------------------------------------------------------------------------ + +cholmod_dense *cholmod_read_dense2 // return dense matrix (double/single) +( + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_dense *cholmod_l_read_dense2 (FILE *, int, cholmod_common *) ; + +//------------------------------------------------------------------------------ +// cholmod_read_matrix: read a sparse or dense matrix from a file (double only) +//------------------------------------------------------------------------------ +void *cholmod_read_matrix // return sparse/triplet/double matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + int prefer, // If 0, a sparse matrix is always return as a + // cholmod_triplet form. It can have any stype + // (symmetric-lower, unsymmetric, or symmetric-upper). + // If 1, a sparse matrix is returned as an unsymmetric + // cholmod_sparse form (A->stype == 0), with both upper and + // lower triangular parts present. This is what the MATLAB + // mread mexFunction does, since MATLAB does not have an + // stype. + // If 2, a sparse matrix is returned with an stype of 0 or + // 1 (unsymmetric, or symmetric with upper part stored). + // This argument has no effect for dense matrices. + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE + cholmod_common *Common +) ; void *cholmod_l_read_matrix (FILE *, int, int *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_write_sparse: write a sparse matrix to a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_matrix2: read a sparse or dense matrix (float or double) +//------------------------------------------------------------------------------ -int cholmod_write_sparse // returns the same result as cholmod_symmetry +void *cholmod_read_matrix2 // sparse/triplet/double matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_sparse *A, /* matrix to print */ - cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int prefer, // see cholmod_read_matrix + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE cholmod_common *Common ) ; +void *cholmod_l_read_matrix2 (FILE *, int, int, int *, cholmod_common *) ; -int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *, - const char *c, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_write_sparse: write a sparse matrix to a file +//------------------------------------------------------------------------------ -/* -------------------------------------------------------------------------- */ -/* cholmod_write_dense: write a dense matrix to a file */ -/* -------------------------------------------------------------------------- */ +// return values of cholmod_symmetry and cholmod_write: +#define CHOLMOD_MM_RECTANGULAR 1 +#define CHOLMOD_MM_UNSYMMETRIC 2 +#define CHOLMOD_MM_SYMMETRIC 3 +#define CHOLMOD_MM_HERMITIAN 4 +#define CHOLMOD_MM_SKEW_SYMMETRIC 5 +#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 +#define CHOLMOD_MM_HERMITIAN_POSDIAG 7 -int cholmod_write_dense +int cholmod_write_sparse // see above, or -1 on error ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_dense *X, /* matrix to print */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to write to, must already be open + cholmod_sparse *A, // matrix to print + cholmod_sparse *Z, // optional matrix with pattern of explicit zeros + const char *comments, // optional filename of comments to include cholmod_common *Common ) ; +int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *, + const char *c, cholmod_common *) ; + +//------------------------------------------------------------------------------ +// cholmod_write_dense: write a dense matrix to a file +//------------------------------------------------------------------------------ +int cholmod_write_dense // CHOLMOD_MM_UNSYMMETRIC or _RECTANGULAR, or +( // -1 on error + // input: + FILE *f, // file to write to, must already be open + cholmod_dense *X, // matrix to print + const char *comments, // optional filename of comments to include + cholmod_common *Common +) ; int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *, cholmod_common *) ; @@ -2349,562 +2551,517 @@ int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *, #ifndef NCHOLESKY -/* Sparse Cholesky routines: analysis, factorization, and solve. - * - * The primary routines are all that a user requires to order, analyze, and - * factorize a sparse symmetric positive definite matrix A (or A*A'), and - * to solve Ax=b (or A*A'x=b). The primary routines rely on the secondary - * routines, the CHOLMOD Utility module, and the AMD and COLAMD packages. They - * make optional use of the CHOLMOD Supernodal and Partition modules, the - * METIS package, and the CCOLAMD package. - * - * Primary routines: - * ----------------- - * - * cholmod_analyze order and analyze (simplicial or supernodal) - * cholmod_factorize simplicial or supernodal Cholesky factorization - * cholmod_solve solve a linear system (simplicial or supernodal) - * cholmod_solve2 like cholmod_solve, but reuse workspace - * cholmod_spsolve solve a linear system (sparse x and b) - * - * Secondary routines: - * ------------------ - * - * cholmod_analyze_p analyze, with user-provided permutation or f set - * cholmod_factorize_p factorize, with user-provided permutation or f - * cholmod_analyze_ordering analyze a fill-reducing ordering - * cholmod_etree find the elimination tree - * cholmod_rowcolcounts compute the row/column counts of L - * cholmod_amd order using AMD - * cholmod_colamd order using COLAMD - * cholmod_rowfac incremental simplicial factorization - * cholmod_rowfac_mask rowfac, specific to LPDASA - * cholmod_rowfac_mask2 rowfac, specific to LPDASA - * cholmod_row_subtree find the nonzero pattern of a row of L - * cholmod_resymbol recompute the symbolic pattern of L - * cholmod_resymbol_noperm recompute the symbolic pattern of L, no L->Perm - * cholmod_postorder postorder a tree - * - * Requires the Utility module, and two packages: AMD and COLAMD. - * Optionally uses the Supernodal and Partition modules. - * Required by the Partition module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze: order and analyze (simplicial or supernodal) */ -/* -------------------------------------------------------------------------- */ - -/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor - * that can later be passed to cholmod_factorize. */ - -cholmod_factor *cholmod_analyze // order and analyze -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - /* --------------- */ +// Sparse Cholesky routines: analysis, factorization, and solve. +// +// The primary routines are all that a user requires to order, analyze, and +// factorize a sparse symmetric positive definite matrix A (or A*A'), and +// to solve Ax=b (or A*A'x=b). The primary routines rely on the secondary +// routines, the CHOLMOD Utility module, and the AMD and COLAMD packages. They +// make optional use of the CHOLMOD Supernodal and Partition modules, the +// METIS package, and the CCOLAMD package. +// +// Primary routines: +// ----------------- +// +// cholmod_analyze order and analyze (simplicial or supernodal) +// cholmod_factorize simplicial or supernodal Cholesky factorization +// cholmod_solve solve a linear system (simplicial or supernodal) +// cholmod_solve2 like cholmod_solve, but reuse workspace +// cholmod_spsolve solve a linear system (sparse x and b) +// +// Secondary routines: +// ------------------ +// +// cholmod_analyze_p analyze, with user-provided permutation or f set +// cholmod_factorize_p factorize, with user-provided permutation or f +// cholmod_analyze_ordering analyze a fill-reducing ordering +// cholmod_etree find the elimination tree +// cholmod_rowcolcounts compute the row/column counts of L +// cholmod_amd order using AMD +// cholmod_colamd order using COLAMD +// cholmod_rowfac incremental simplicial factorization +// cholmod_rowfac_mask rowfac, specific to LPDASA +// cholmod_rowfac_mask2 rowfac, specific to LPDASA +// cholmod_row_subtree find the nonzero pattern of a row of L +// cholmod_resymbol recompute the symbolic pattern of L +// cholmod_resymbol_noperm recompute the symbolic pattern of L, no L->Perm +// cholmod_postorder postorder a tree +// +// Requires the Utility module, and two packages: AMD and COLAMD. +// Optionally uses the Supernodal and Partition modules. +// Required by the Partition module. + +//------------------------------------------------------------------------------ +// cholmod_analyze: order and analyze (simplicial or supernodal) +//------------------------------------------------------------------------------ + +// Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor +// that can later be passed to cholmod_factorize. + +cholmod_factor *cholmod_analyze // returns symbolic factor L +( + // input: + cholmod_sparse *A, // matrix to order and analyze cholmod_common *Common ) ; - cholmod_factor *cholmod_l_analyze (cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_p: analyze, with user-provided permutation or f set */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_analyze_p: analyze, with user-provided permutation or f set +//------------------------------------------------------------------------------ -/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a - * symbolic factor that can later be passed to cholmod_factorize, where - * F = A(:,fset) if fset is not NULL and A->stype is zero. - * UserPerm is tried if non-NULL. */ +// Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a +// symbolic factor that can later be passed to cholmod_factorize, where +// F = A(:,fset) if fset is not NULL and A->stype is zero. +// UserPerm is tried if non-NULL. -cholmod_factor *cholmod_analyze_p +cholmod_factor *cholmod_analyze_p // returns symbolic factor L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - int32_t *UserPerm, /* user-provided permutation, size A->nrow */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order and analyze + int32_t *UserPerm, // user-provided permutation, size A->nrow + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) ; +cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, int64_t *, int64_t *, + size_t, cholmod_common *) ; -cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, int64_t *, - int64_t *, size_t, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_analyze_p2: analyze for sparse Cholesky or sparse QR +//------------------------------------------------------------------------------ -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_p2: analyze for sparse Cholesky or sparse QR */ -/* -------------------------------------------------------------------------- */ +// This is normally not need by the user application. cholmod_factor *cholmod_analyze_p2 ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to order and analyze */ - int32_t *UserPerm, /* user-provided permutation, size A->nrow */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to order and analyze + int32_t *UserPerm, // user-provided permutation, size A->nrow + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) ; - cholmod_factor *cholmod_l_analyze_p2 (int, cholmod_sparse *, int64_t *, int64_t *, size_t, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_factorize: simplicial or supernodal Cholesky factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_factorize: simplicial or supernodal Cholesky factorization +//------------------------------------------------------------------------------ -/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained - * from cholmod_analyze. The analysis can be re-used simply by calling this - * routine a second time with another matrix. A must have the same nonzero - * pattern as that passed to cholmod_analyze. */ +// Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained +// from cholmod_analyze. The analysis can be re-used simply by calling this +// routine a second time with another matrix. A must have the same nonzero +// pattern as that passed to cholmod_analyze. int cholmod_factorize // simplicial or superodal Cholesky factorization ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) ; - int cholmod_l_factorize (cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_factorize_p: factorize, with user-provided permutation or fset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_factorize_p: factorize, with user-provided permutation or fset +//------------------------------------------------------------------------------ -/* Same as cholmod_factorize, but with more options. */ +// Same as cholmod_factorize, but with more options. int cholmod_factorize_p ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + double beta [2], // factorize beta*I+A or beta*I+A'*A + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) ; +int cholmod_l_factorize_p (cholmod_sparse *, double *, int64_t *, size_t, + cholmod_factor *, cholmod_common *) ; -int cholmod_l_factorize_p (cholmod_sparse *, double *, int64_t *, - size_t, cholmod_factor *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_solve: solve a linear system (simplicial or supernodal) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_solve: solve a linear system (simplicial or supernodal) +//------------------------------------------------------------------------------ -/* Solves one of many linear systems with a dense right-hand-side, using the - * factorization from cholmod_factorize (or as modified by any other CHOLMOD - * routine). D is identity for LL' factorizations. */ +// Solves one of many linear systems with a dense right-hand-side, using the +// factorization from cholmod_factorize (or as modified by any other CHOLMOD +// routine). D is identity for LL' factorizations. -#define CHOLMOD_A 0 /* solve Ax=b */ -#define CHOLMOD_LDLt 1 /* solve LDL'x=b */ -#define CHOLMOD_LD 2 /* solve LDx=b */ -#define CHOLMOD_DLt 3 /* solve DL'x=b */ -#define CHOLMOD_L 4 /* solve Lx=b */ -#define CHOLMOD_Lt 5 /* solve L'x=b */ -#define CHOLMOD_D 6 /* solve Dx=b */ -#define CHOLMOD_P 7 /* permute x=Px */ -#define CHOLMOD_Pt 8 /* permute x=P'x */ +#define CHOLMOD_A 0 /* solve Ax=b */ +#define CHOLMOD_LDLt 1 /* solve LDL'x=b */ +#define CHOLMOD_LD 2 /* solve LDx=b */ +#define CHOLMOD_DLt 3 /* solve DL'x=b */ +#define CHOLMOD_L 4 /* solve Lx=b */ +#define CHOLMOD_Lt 5 /* solve L'x=b */ +#define CHOLMOD_D 6 /* solve Dx=b */ +#define CHOLMOD_P 7 /* permute x=Px */ +#define CHOLMOD_Pt 8 /* permute x=P'x */ -cholmod_dense *cholmod_solve /* returns the solution X */ +cholmod_dense *cholmod_solve // returns the solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_common *Common ) ; - cholmod_dense *cholmod_l_solve (int, cholmod_factor *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_solve2: like cholmod_solve, but with reusable workspace */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_solve2: like cholmod_solve, but with reusable workspace +//------------------------------------------------------------------------------ -int cholmod_solve2 /* returns TRUE on success, FALSE on failure */ +int cholmod_solve2 // returns TRUE on success, FALSE on failure ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_sparse *Bset, - /* ---- output --- */ - cholmod_dense **X_Handle, /* solution, allocated if need be */ + // output: + cholmod_dense **X_Handle, // solution, allocated if need be cholmod_sparse **Xset_Handle, - /* ---- workspace */ - cholmod_dense **Y_Handle, /* workspace, or NULL */ - cholmod_dense **E_Handle, /* workspace, or NULL */ - /* --------------- */ + // workspace: + cholmod_dense **Y_Handle, // workspace, or NULL + cholmod_dense **E_Handle, // workspace, or NULL cholmod_common *Common ) ; - int cholmod_l_solve2 (int, cholmod_factor *, cholmod_dense *, cholmod_sparse *, cholmod_dense **, cholmod_sparse **, cholmod_dense **, cholmod_dense **, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_spsolve: solve a linear system with a sparse right-hand-side */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_spsolve: solve a linear system with a sparse right-hand-side +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_spsolve +cholmod_sparse *cholmod_spsolve // returns the sparse solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_sparse *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_sparse *B, // right-hand-side cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_spsolve (int, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_etree: find the elimination tree of A or A'*A */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_etree: find the elimination tree of A or A'*A +//------------------------------------------------------------------------------ int cholmod_etree ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - /* ---- output --- */ - int32_t *Parent, /* size ncol. Parent [j] = p if p is the parent of j */ - /* --------------- */ + // output: + int32_t *Parent, // size ncol. Parent [j] = p if p is the parent of j cholmod_common *Common ) ; - int cholmod_l_etree (cholmod_sparse *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowcolcounts: compute the row/column counts of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowcolcounts: compute the row/column counts of L +//------------------------------------------------------------------------------ int cholmod_rowcolcounts ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int32_t *Parent, /* size nrow. Parent [i] = p if p is the parent of i */ - int32_t *Post, /* size nrow. Post [k] = i if i is the kth node in - * the postordered etree. */ - /* ---- output --- */ - int32_t *RowCount, /* size nrow. RowCount [i] = # entries in the ith row of - * L, including the diagonal. */ - int32_t *ColCount, /* size nrow. ColCount [i] = # entries in the ith - * column of L, including the diagonal. */ - int32_t *First, /* size nrow. First [i] = k is the least postordering - * of any descendant of i. */ - int32_t *Level, /* size nrow. Level [i] is the length of the path from - * i to the root, with Level [root] = 0. */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_rowcolcounts (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, int64_t *, - int64_t *, int64_t *, int64_t *, - cholmod_common *) ; + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Parent, // size nrow. Parent [i] = p if p is the parent of i + int32_t *Post, // size nrow. Post [k] = i if i is the kth node in + // the postordered etree. + // output: + int32_t *RowCount, // size nrow. RowCount [i] = # entries in the ith + // row of L, including the diagonal. + int32_t *ColCount, // size nrow. ColCount [i] = # entries in the ith + // column of L, including the diagonal. + int32_t *First, // size nrow. First [i] = k is the least + // postordering of any descendant of i. + int32_t *Level, // size nrow. Level [i] is the length of the path + // from i to the root, with Level [root] = 0. + cholmod_common *Common +) ; +int cholmod_l_rowcolcounts (cholmod_sparse *, int64_t *, size_t, int64_t *, + int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_ordering: analyze a fill-reducing ordering */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_analyze_ordering: analyze a fill-reducing ordering +//------------------------------------------------------------------------------ int cholmod_analyze_ordering ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int ordering, /* ordering method used */ - int32_t *Perm, /* size n, fill-reducing permutation to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Parent, /* size n, elimination tree */ - int32_t *Post, /* size n, postordering of elimination tree */ - int32_t *ColCount, /* size n, nnz in each column of L */ - /* ---- workspace */ - int32_t *First, /* size nworkspace for cholmod_postorder */ - int32_t *Level, /* size n workspace for cholmod_postorder */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_analyze_ordering (cholmod_sparse *, int, int64_t *, - int64_t *, size_t, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, + // input: + cholmod_sparse *A, // matrix to analyze + int ordering, // ordering method used + int32_t *Perm, // size n, fill-reducing permutation to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Parent, // size n, elimination tree + int32_t *Post, // size n, postordering of elimination tree + int32_t *ColCount, // size n, nnz in each column of L + // workspace: + int32_t *First, // size n workspace for cholmod_postorder + int32_t *Level, // size n workspace for cholmod_postorder + cholmod_common *Common +) ; +int cholmod_l_analyze_ordering (cholmod_sparse *, int, int64_t *, int64_t *, + size_t, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_amd: order using AMD */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_amd: order using AMD +//------------------------------------------------------------------------------ -/* Finds a permutation P to reduce fill-in in the factorization of P*A*P' - * or P*A*A'P' */ +// Finds a permutation P to reduce fill-in in the factorization of P*A*P' +// or P*A*A'P' int cholmod_amd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_amd (cholmod_sparse *, int64_t *, size_t, int64_t *, + cholmod_common *) ; -int cholmod_l_amd (cholmod_sparse *, int64_t *, size_t, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_colamd: order using COLAMD */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_colamd: order using COLAMD +//------------------------------------------------------------------------------ -/* Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'. - * Orders F*F' where F = A (:,fset) if fset is not NULL */ +// Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'. +// Orders F*F' where F = A (:,fset) if fset is not NULL int cholmod_colamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with a coletree postorder */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with a coletree postorder + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_colamd (cholmod_sparse *, int64_t *, size_t, int, int64_t *, + cholmod_common *) ; -int cholmod_l_colamd (cholmod_sparse *, int64_t *, size_t, int, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowfac: incremental simplicial factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowfac: incremental simplicial factorization +//------------------------------------------------------------------------------ -/* Partial or complete simplicial factorization. Rows and columns kstart:kend-1 - * of L and D must be initially equal to rows/columns kstart:kend-1 of the - * identity matrix. Row k can only be factorized if all descendants of node - * k in the elimination tree have been factorized. */ +// Partial or complete simplicial factorization. Rows and columns kstart:kend-1 +// of L and D must be initially equal to rows/columns kstart:kend-1 of the +// identity matrix. Row k can only be factorized if all descendants of node +// k in the elimination tree have been factorized. -int cholmod_rowfac +int cholmod_rowfac ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - int cholmod_l_rowfac (cholmod_sparse *, cholmod_sparse *, double *, size_t, size_t, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowfac_mask: incremental simplicial factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowfac_mask: incremental simplicial factorization +//------------------------------------------------------------------------------ -/* cholmod_rowfac_mask is a version of cholmod_rowfac that is specific to - * LPDASA. It is unlikely to be needed by any other application. */ +// cholmod_rowfac_mask and cholmod_rowfac_mask2 are version of cholmod_rowfac +// that are specific to LPDASA. It is unlikely to be needed by any other +// application, and is not documented in the CHOLMOD User Guide. int cholmod_rowfac_mask ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - int32_t *mask, /* if mask[i] >= 0, then set row i to zero */ - int32_t *RLinkUp, /* link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + int32_t *mask, // size A->nrow. if mask[i] >= 0 row i is set to zero + int32_t *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - -int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, size_t, - size_t, int64_t *, int64_t *, cholmod_factor *, - cholmod_common *) ; +int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, + size_t, size_t, int64_t *, int64_t *, cholmod_factor *, cholmod_common *) ; int cholmod_rowfac_mask2 ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - int32_t *mask, /* if mask[i] >= maskmark, then set row i to zero */ - int32_t maskmark, - int32_t *RLinkUp, /* link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + int32_t *mask, // size A->nrow. if mask[i] >= maskmark row i is set + // to zero + int32_t maskmark, // for mask [i] test + int32_t *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - int cholmod_l_rowfac_mask2 (cholmod_sparse *, cholmod_sparse *, double *, - size_t, size_t, int64_t *, int64_t, int64_t *, - cholmod_factor *, cholmod_common *) ; + size_t, size_t, int64_t *, int64_t, int64_t *, cholmod_factor *, + cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_row_subtree: find the nonzero pattern of a row of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_row_subtree: find the nonzero pattern of a row of L +//------------------------------------------------------------------------------ -/* Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1) - * and b = kth column of A or A*A' (rows 0 to k-1 only) */ +// Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1) +// and b = kth column of A or A*A' (rows 0 to k-1 only) int cholmod_row_subtree ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - size_t k, /* row k of L */ - int32_t *Parent, /* elimination tree */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), n-by-1 with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + size_t krow, // row k of L + int32_t *Parent, // elimination tree + // output: + cholmod_sparse *R, // pattern of L(k,:), 1-by-n with R->nzmax >= n cholmod_common *Common ) ; - int cholmod_l_row_subtree (cholmod_sparse *, cholmod_sparse *, size_t, int64_t *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_lsolve_pattern: find the nonzero pattern of x=L\b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_lsolve_pattern: find the nonzero pattern of y=L\b +//------------------------------------------------------------------------------ int cholmod_lsolve_pattern ( - /* ---- input ---- */ - cholmod_sparse *B, /* sparse right-hand-side (a single sparse column) */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *X, /* pattern of X=L\B, n-by-1 with X->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *B, // sparse right-hand-side (a single sparse column) + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *Yset, // pattern of Y=L\B, n-by-1 with Y->nzmax >= n cholmod_common *Common ) ; - int cholmod_l_lsolve_pattern (cholmod_sparse *, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_row_lsubtree: find the nonzero pattern of a row of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_row_lsubtree: find the nonzero pattern of a row of L +//------------------------------------------------------------------------------ -/* Identical to cholmod_row_subtree, except that it finds the elimination tree - * from L itself. */ +// Identical to cholmod_row_subtree, except that it finds the elimination tree +// from L itself. int cholmod_row_lsubtree ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required - * for the symmetric case. Need not be sorted. */ - size_t k, /* row k of L */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), n-by-1 with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *Fi, // nonzero pattern of kth row of A', not required + // for the symmetric case. Need not be sorted. + size_t fnz, // size of Fi + size_t krow, // row k of L + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *R, // pattern of L(k,:), n-by-1 with R->nzmax >= n cholmod_common *Common ) ; +int cholmod_l_row_lsubtree (cholmod_sparse *, int64_t *, size_t, size_t, + cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -int cholmod_l_row_lsubtree (cholmod_sparse *, int64_t *, size_t, - size_t, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_resymbol: recompute the symbolic pattern of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_resymbol: recompute the symbolic pattern of L +//------------------------------------------------------------------------------ -/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', - * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). - * - * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it - * first permutes A according to L->Perm. A can be upper/lower/unsymmetric, - * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */ +// Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', +// or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). +// +// cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it +// first permutes A according to L->Perm. A can be upper/lower/unsymmetric, +// in contrast to cholmod_resymbol_noperm (which can be lower or unsym). int cholmod_resymbol // recompute symbolic pattern of L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) ; - int cholmod_l_resymbol (cholmod_sparse *, int64_t *, size_t, int, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_resymbol_noperm: recompute the symbolic pattern of L, no L->Perm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_resymbol_noperm: recompute the symbolic pattern of L, no L->Perm +//------------------------------------------------------------------------------ -/* Remove entries from L that are not in the factorization of A, A*A', - * or F*F' (depending on A->stype and whether fset is NULL or not). */ +// Remove entries from L that are not in the factorization of A, A*A', +// or F*F' (depending on A->stype and whether fset is NULL or not). int cholmod_resymbol_noperm ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) ; - int cholmod_l_resymbol_noperm (cholmod_sparse *, int64_t *, size_t, int, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rcond: compute rough estimate of reciprocal of condition number */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rcond: compute rough estimate of reciprocal of condition number +//------------------------------------------------------------------------------ -double cholmod_rcond /* return min(diag(L)) / max(diag(L)) */ +double cholmod_rcond // return rcond estimate ( - /* ---- input ---- */ - cholmod_factor *L, - /* --------------- */ + // input: + cholmod_factor *L, // factorization to query; not modified cholmod_common *Common ) ; - double cholmod_l_rcond (cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_postorder: Compute the postorder of a tree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_postorder: Compute the postorder of a tree +//------------------------------------------------------------------------------ -int32_t cholmod_postorder /* return # of nodes postordered */ +int32_t cholmod_postorder // return # of nodes postordered ( - /* ---- input ---- */ - int32_t *Parent, /* size n. Parent [j] = p if p is the parent of j */ + // input: + int32_t *Parent, // size n. Parent [j] = p if p is the parent of j size_t n, - int32_t *Weight_p, /* size n, optional. Weight [j] is weight of node j */ - /* ---- output --- */ - int32_t *Post, /* size n. Post [k] = j is kth in postordered tree */ - /* --------------- */ + int32_t *Weight, // size n, optional. Weight [j] is weight of node j + // output: + int32_t *Post, // size n. Post [k] = j is kth in postordered tree cholmod_common *Common ) ; - int64_t cholmod_l_postorder (int64_t *, size_t, int64_t *, int64_t *, cholmod_common *) ; @@ -2916,217 +3073,227 @@ int64_t cholmod_l_postorder (int64_t *, size_t, int64_t *, int64_t *, #ifndef NMATRIXOPS -/* Basic operations on sparse and dense matrices. - * - * cholmod_drop A = entries in A with abs. value >= tol - * cholmod_norm_dense s = norm (X), 1-norm, inf-norm, or 2-norm - * cholmod_norm_sparse s = norm (A), 1-norm or inf-norm - * cholmod_horzcat C = [A,B] - * cholmod_scale A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) - * cholmod_sdmult Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y - * cholmod_ssmult C = A*B - * cholmod_submatrix C = A (i,j), where i and j are arbitrary vectors - * cholmod_vertcat C = [A ; B] - * - * A, B, C: sparse matrices (cholmod_sparse) - * X, Y: dense matrices (cholmod_dense) - * s: scalar or vector - * - * Requires the Utility module. Not required by any other CHOLMOD module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_drop: drop entries with small absolute value */ -/* -------------------------------------------------------------------------- */ +// Basic operations on sparse and dense matrices. +// +// cholmod_drop A = entries in A with abs. value >= tol +// cholmod_norm_dense s = norm (X), 1-norm, inf-norm, or 2-norm +// cholmod_norm_sparse s = norm (A), 1-norm or inf-norm +// cholmod_horzcat C = [A,B] +// cholmod_scale A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) +// cholmod_sdmult Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y +// cholmod_ssmult C = A*B +// cholmod_submatrix C = A (i,j), where i and j are arbitrary vectors +// cholmod_vertcat C = [A ; B] +// +// A, B, C: sparse matrices (cholmod_sparse) +// X, Y: dense matrices (cholmod_dense) +// s: scalar or vector +// +// Requires the Utility module. Not required by any other CHOLMOD module. + +//------------------------------------------------------------------------------ +// cholmod_drop: drop entries with small absolute value +//------------------------------------------------------------------------------ int cholmod_drop ( - /* ---- input ---- */ - double tol, /* keep entries with absolute value > tol */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to drop entries from */ - /* --------------- */ + // input: + double tol, // keep entries with absolute value > tol + // input/output: + cholmod_sparse *A, // matrix to drop entries from cholmod_common *Common ) ; - int cholmod_l_drop (double, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_norm_dense: s = norm (X), 1-norm, inf-norm, or 2-norm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_norm_dense: s = norm (X), 1-norm, inf-norm, or 2-norm +//------------------------------------------------------------------------------ -double cholmod_norm_dense +double cholmod_norm_dense // returns norm (X) ( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */ - /* --------------- */ + // input: + cholmod_dense *X, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm cholmod_common *Common ) ; - double cholmod_l_norm_dense (cholmod_dense *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_norm_sparse: s = norm (A), 1-norm or inf-norm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_norm_sparse: s = norm (A), 1-norm or inf-norm +//------------------------------------------------------------------------------ -double cholmod_norm_sparse +double cholmod_norm_sparse // returns norm (A) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm cholmod_common *Common ) ; - double cholmod_l_norm_sparse (cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_horzcat: C = [A,B] */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_horzcat: C = [A,B] +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_horzcat +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_horzcat // returns C = [A B] ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to concatenate + cholmod_sparse *B, // right matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_horzcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_scale: A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_scale: A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) +//------------------------------------------------------------------------------ -/* scaling modes, selected by the scale input parameter: */ -#define CHOLMOD_SCALAR 0 /* A = s*A */ -#define CHOLMOD_ROW 1 /* A = diag(s)*A */ -#define CHOLMOD_COL 2 /* A = A*diag(s) */ -#define CHOLMOD_SYM 3 /* A = diag(s)*A*diag(s) */ +// scaling modes, selected by the scale input parameter: +#define CHOLMOD_SCALAR 0 /* A = s*A */ +#define CHOLMOD_ROW 1 /* A = diag(s)*A */ +#define CHOLMOD_COL 2 /* A = A*diag(s) */ +#define CHOLMOD_SYM 3 /* A = diag(s)*A*diag(s) */ int cholmod_scale ( - /* ---- input ---- */ - cholmod_dense *S, /* scale factors (scalar or vector) */ - int scale, /* type of scaling to compute */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to scale */ - /* --------------- */ + // input: + cholmod_dense *S, // scale factors (scalar or vector) + int scale, // type of scaling to compute + // input/output: + cholmod_sparse *A, // matrix to scale cholmod_common *Common ) ; - int cholmod_l_scale (cholmod_dense *, int, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_sdmult: Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_sdmult: Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y +//------------------------------------------------------------------------------ -/* Sparse matrix times dense matrix */ +// Sparse matrix times dense matrix int cholmod_sdmult ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to multiply */ - int transpose, /* use A if 0, or A' otherwise */ - double alpha [2], /* scale factor for A */ - double beta [2], /* scale factor for Y */ - cholmod_dense *X, /* dense matrix to multiply */ - /* ---- in/out --- */ - cholmod_dense *Y, /* resulting dense matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to multiply + int transpose, // use A if 0, otherwise use A' + double alpha [2], // scale factor for A + double beta [2], // scale factor for Y + cholmod_dense *X, // dense matrix to multiply + // input/output: + cholmod_dense *Y, // resulting dense matrix cholmod_common *Common ) ; - int cholmod_l_sdmult (cholmod_sparse *, int, double *, double *, cholmod_dense *, cholmod_dense *Y, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_ssmult: C = A*B */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_ssmult: C = A*B +//------------------------------------------------------------------------------ -/* Sparse matrix times sparse matrix */ +// Sparse matrix times sparse matrix. -cholmod_sparse *cholmod_ssmult +// If A and/or B are symmetric, they are converted first to unsymmetric, and +// the conversion is governed by the mode input parameter. + +cholmod_sparse *cholmod_ssmult // return C=A*B ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to multiply */ - cholmod_sparse *B, /* right matrix to multiply */ - int stype, /* requested stype of C */ - int values, /* TRUE: do numerical values, FALSE: pattern only */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to multiply + cholmod_sparse *B, // right matrix to multiply + int stype, // requested stype of C + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_ssmult (cholmod_sparse *, cholmod_sparse *, int, int, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_submatrix: C = A (r,c), where i and j are arbitrary vectors */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_submatrix: C = A (r,c), where i and j are arbitrary vectors +//------------------------------------------------------------------------------ -/* rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1. - * In this case, r can be NULL. An rsize of zero, or r = NULL and rsize >= 0, - * denotes "[ ]" in MATLAB notation (the empty set). - * Similar rules hold for csize. - */ +// rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1. +// In this case, r can be NULL. An rsize of zero, or r = NULL and rsize >= 0, +// denotes "[ ]" in MATLAB notation (the empty set). +// Similar rules hold for csize. -cholmod_sparse *cholmod_submatrix +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_submatrix // return C = A (rset,cset) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to subreference */ - int32_t *rset, /* set of row indices, duplicates OK */ - int64_t rsize, /* size of r; rsize < 0 denotes ":" */ - int32_t *cset, /* set of column indices, duplicates OK */ - int64_t csize, /* size of c; csize < 0 denotes ":" */ - int values, /* if TRUE compute the numerical values of C */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to subreference + int32_t *rset, // set of row indices, duplicates OK + int64_t rsize, // size of rset, or -1 for ":" + int32_t *cset, // set of column indices, duplicates OK + int64_t csize, // size of cset, or -1 for ":" + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_submatrix (cholmod_sparse *, int64_t *, int64_t, int64_t *, int64_t, int, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_vertcat: C = [A ; B] */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_vertcat: C = [A ; B] +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_vertcat +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_vertcat // returns C = [A ; B] ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // top matrix to concatenate + cholmod_sparse *B, // bottom matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric + // 0: pattern cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_vertcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_symmetry: determine if a sparse matrix is symmetric */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_symmetry: determine if a sparse matrix is symmetric +//------------------------------------------------------------------------------ -int cholmod_symmetry +// return values of cholmod_symmetry and cholmod_write: +// #define CHOLMOD_MM_RECTANGULAR 1 +// #define CHOLMOD_MM_UNSYMMETRIC 2 +// #define CHOLMOD_MM_SYMMETRIC 3 +// #define CHOLMOD_MM_HERMITIAN 4 +// #define CHOLMOD_MM_SKEW_SYMMETRIC 5 +// #define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 +// #define CHOLMOD_MM_HERMITIAN_POSDIAG 7 + +int cholmod_symmetry // returns the matrix symmetry (see above) ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - int option, - /* ---- output ---- */ - int32_t *xmatched, - int32_t *pmatched, - int32_t *nzoffdiag, - int32_t *nzdiag, - /* --------------- */ + int option, // option 0, 1, or 2 + // output: + int32_t *xmatched, // # of matched numerical entries + int32_t *pmatched, // # of matched entries in pattern + int32_t *nzoffdiag, // # of off diagonal entries + int32_t *nzdiag, // # of diagonal entries cholmod_common *Common ) ; - int cholmod_l_symmetry (cholmod_sparse *, int, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; @@ -3138,316 +3305,289 @@ int cholmod_l_symmetry (cholmod_sparse *, int, int64_t *, int64_t *, int64_t *, #ifndef NMODIFY -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_modify.h. - * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager - * http://www.suitesparse.com - * -------------------------------------------------------------------------- */ - -/* Sparse Cholesky modification routines: update / downdate / rowadd / rowdel. - * Can also modify a corresponding solution to Lx=b when L is modified. This - * module is most useful when applied on a Cholesky factorization computed by - * the Cholesky module, but it does not actually require the Cholesky module. - * The Utility module can create an identity Cholesky factorization (LDL' where - * L=D=I) that can then by modified by these routines. - * - * Primary routines: - * ----------------- - * - * cholmod_updown multiple rank update/downdate - * cholmod_rowadd add a row to an LDL' factorization - * cholmod_rowdel delete a row from an LDL' factorization - * - * Secondary routines: - * ------------------- - * - * cholmod_updown_solve update/downdate, and modify solution to Lx=b - * cholmod_updown_mark update/downdate, and modify solution to partial Lx=b - * cholmod_updown_mask update/downdate for LPDASA - * cholmod_updown_mask2 update/downdate for LPDASA - * cholmod_rowadd_solve add a row, and update solution to Lx=b - * cholmod_rowadd_mark add a row, and update solution to partial Lx=b - * cholmod_rowdel_solve delete a row, and downdate Lx=b - * cholmod_rowdel_mark delete a row, and downdate solution to partial Lx=b - * - * Requires the Utility module. Not required by any other CHOLMOD module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_updown: multiple rank update/downdate */ -/* -------------------------------------------------------------------------- */ - -/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' - * (a downdate). The factor object L need not be an LDL' factorization; it - * is converted to one if it isn't. */ +//------------------------------------------------------------------------------ +// CHOLMOD:Modify Module. Copyright (C) 2005-2023, Timothy A. Davis and William +// W. Hager. http://www.suitesparse.com +//------------------------------------------------------------------------------ + +// Sparse Cholesky modification routines: update / downdate / rowadd / rowdel. +// Can also modify a corresponding solution to Lx=b when L is modified. This +// module is most useful when applied on a Cholesky factorization computed by +// the Cholesky module, but it does not actually require the Cholesky module. +// The Utility module can create an identity Cholesky factorization (LDL' where +// L=D=I) that can then by modified by these routines. +// +// Primary routines: +// ----------------- +// +// cholmod_updown multiple rank update/downdate +// cholmod_rowadd add a row to an LDL' factorization +// cholmod_rowdel delete a row from an LDL' factorization +// +// Secondary routines: +// ------------------- +// +// cholmod_updown_solve update/downdate, and modify solution to Lx=b +// cholmod_updown_mark update/downdate, and modify solution to partial Lx=b +// cholmod_updown_mask update/downdate for LPDASA +// cholmod_updown_mask2 update/downdate for LPDASA +// cholmod_rowadd_solve add a row, and update solution to Lx=b +// cholmod_rowadd_mark add a row, and update solution to partial Lx=b +// cholmod_rowdel_solve delete a row, and downdate Lx=b +// cholmod_rowdel_mark delete a row, and downdate solution to partial Lx=b +// +// Requires the Utility module. Not required by any other CHOLMOD module. + +//------------------------------------------------------------------------------ +// cholmod_updown: multiple rank update/downdate +//------------------------------------------------------------------------------ + +// Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' +// (a downdate). The factor object L need not be an LDL' factorization; it +// is converted to one if it isn't. int cholmod_updown // update/downdate ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; -int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; - +int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *, + cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_solve: update/downdate, and modify solution to Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_solve: update/downdate, and modify solution to Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown, except that it also updates/downdates the - * solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not - * need as input to this routine, but a sparse change to b is (DeltaB). Only - * entries in DeltaB corresponding to columns modified in L are accessed; the - * rest must be zero. */ +// Does the same as cholmod_updown, except that it also updates/downdates the +// solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not +// need as input to this routine, but a sparse change to b is (DeltaB). Only +// entries in DeltaB corresponding to columns modified in L are accessed; the +// rest must be zero. int cholmod_updown_solve ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_updown_solve (int, cholmod_sparse *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_mark: update/downdate, and modify solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_mark: update/downdate, and modify solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. See cholmod_updown.c for - * a description of colmark. */ +// Does the same as cholmod_updown_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. See cholmod_updown.c for +// a description of colmark. int cholmod_updown_mark ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_updown_mark (int, cholmod_sparse *, int64_t *, cholmod_factor *, + cholmod_dense *, cholmod_dense *, cholmod_common *) ; -int cholmod_l_updown_mark (int, cholmod_sparse *, int64_t *, - cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_mask: update/downdate, for LPDASA */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_mask: update/downdate, for LPDASA +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown_mark, except has an additional "mask" - * argument. This routine is an "expert" routine. It is meant for use in - * LPDASA only. See cholmod_updown.c for a description of mask. */ +// Does the same as cholmod_updown_mark, except has an additional "mask" +// argument. This routine is an "expert" routine. It is meant for use in +// LPDASA only. See cholmod_updown.c for a description of mask. int cholmod_updown_mask ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - int32_t *mask, /* size n */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + int32_t *mask, // size n + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - -int cholmod_l_updown_mask (int, cholmod_sparse *, int64_t *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; +int cholmod_l_updown_mask (int, cholmod_sparse *, int64_t *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; int cholmod_updown_mask2 ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - int32_t *mask, /* size n */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + int32_t *mask, // size n int32_t maskmark, - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_updown_mask2 (int, cholmod_sparse *, int64_t *, int64_t *, + int64_t, cholmod_factor *, cholmod_dense *, cholmod_dense *, + cholmod_common *) ; -int cholmod_l_updown_mask2 (int, cholmod_sparse *, int64_t *, - int64_t *, int64_t, cholmod_factor *, cholmod_dense *, - cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd: add a row to an LDL' factorization (a rank-2 update) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd: add a row to an LDL' factorization (a rank-2 update) +//------------------------------------------------------------------------------ -/* cholmod_rowadd adds a row to the LDL' factorization. It computes the kth - * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) - * accordingly. The kth row and column of L must originally be equal to the - * kth row and column of the identity matrix. The kth row/column of L is - * computed as the factorization of the kth row/column of the matrix to - * factorize, which is provided as a single n-by-1 sparse matrix R. */ +// cholmod_rowadd adds a row to the LDL' factorization. It computes the kth +// row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) +// accordingly. The kth row and column of L must originally be equal to the +// kth row and column of the identity matrix. The kth row/column of L is +// computed as the factorization of the kth row/column of the matrix to +// factorize, which is provided as a single n-by-1 sparse matrix R. int cholmod_rowadd // add a row to an LDL' factorization ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; - int cholmod_l_rowadd (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd_solve: add a row, and update solution to Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd_solve: add a row, and update solution to Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b - * See cholmod_updown for a description of how Lx=b is updated. There is on - * additional parameter: bk specifies the new kth entry of b. */ +// Does the same as cholmod_rowadd, and also updates the solution to Lx=b +// See cholmod_updown for a description of how Lx=b is updated. There is on +// additional parameter: bk specifies the new kth entry of b. int cholmod_rowadd_solve ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right-hand-side b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right-hand-side b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_rowadd_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd_mark: add a row, and update solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd_mark: add a row, and update solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowadd_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. */ +// Does the same as cholmod_rowadd_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. int cholmod_rowadd_mark ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right hand side, b */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right hand side, b + int32_t *colmark, // int32_t array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel: delete a row from an LDL' factorization (a rank-2 update) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel: delete a row from an LDL' factorization (a rank-2 update) +//------------------------------------------------------------------------------ -/* Sets the kth row and column of L to be the kth row and column of the identity - * matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, - * the caller can optionally provide the nonzero pattern (or an upper bound) of - * kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want - * CHOLMOD to determine this itself, which is easier for the caller, but takes - * a little more time. - */ +// Sets the kth row and column of L to be the kth row and column of the identity +// matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, +// the caller can optionally provide the nonzero pattern (or an upper bound) of +// kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want +// CHOLMOD to determine this itself, which is easier for the caller, but takes +// a little more time. int cholmod_rowdel // delete a rw from an LDL' factorization ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; - int cholmod_l_rowdel (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel_solve: delete a row, and downdate Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel_solve: delete a row, and downdate Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. - * When row/column k of A is "deleted" from the system A*y=b, this can induce - * a change to x, in addition to changes arising when L and b are modified. - * If this is the case, the kth entry of y is required as input (yk) */ +// Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. +// When row/column k of A is "deleted" from the system A*y=b, this can induce +// a change to x, in addition to changes arising when L and b are modified. +// If this is the case, the kth entry of y is required as input (yk). int cholmod_rowdel_solve ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_rowdel_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel_mark: delete a row, and downdate solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel_mark: delete a row, and downdate solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowdel_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. */ +// Does the same as cholmod_rowdel_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. int cholmod_rowdel_mark ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + int32_t *colmark, // int32_t array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - -int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; +int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; #endif @@ -3455,254 +3595,217 @@ int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, // CHOLMOD:Partition Module (CAMD, CCOLAMD, and CSYMAMD) //============================================================================== +//------------------------------------------------------------------------------ +// CHOLMOD/Partition: +// Copyright (C) 2005-2023, Univ. of Florida. Author: Timothy A. Davis +//------------------------------------------------------------------------------ + +// CHOLMOD Partition module, interface to CAMD, CCOLAMD, CSYMAMD, and METIS, +// and graph partitioning and graph-partition-based orderings. Includes an +// interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering +// methods which order a matrix following constraints determined via nested +// dissection. +// +// These functions do not require METIS. They are installed unless NCAMD +// is defined: +// cholmod_ccolamd interface to CCOLAMD ordering +// cholmod_csymamd interface to CSYMAMD ordering +// cholmod_camd interface to CAMD ordering +// +// These functions require METIS: +// cholmod_nested_dissection CHOLMOD nested dissection ordering +// cholmod_metis METIS nested dissection ordering (METIS_NodeND) +// cholmod_bisect graph partitioner (currently based on METIS) +// cholmod_metis_bisector direct interface to METIS_ComputeVertexSeparator +// +// Requires the Utility and Cholesky modules, and three packages: METIS, CAMD, +// and CCOLAMD. Optionally used by the Cholesky module. + #ifndef NCAMD -/* CHOLMOD Partition module, interface to CAMD, CCOLAMD, and CSYMAMD - * - * An interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering - * methods which order a matrix following constraints determined via nested - * dissection. - * - * These functions do not require METIS. They are installed unless NCAMD - * is defined: - * cholmod_ccolamd interface to CCOLAMD ordering - * cholmod_csymamd interface to CSYMAMD ordering - * cholmod_camd interface to CAMD ordering - * - * Requires the Utility and Cholesky modules, and two packages: CAMD, - * and CCOLAMD. Used by functions in the Partition Module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_ccolamd */ -/* -------------------------------------------------------------------------- */ - -/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */ +//------------------------------------------------------------------------------ +// cholmod_ccolamd +//------------------------------------------------------------------------------ + +// Order AA' or A(:,f)*A(:,f)' using CCOLAMD. int cholmod_ccolamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int32_t *Cmember, /* size A->nrow. Cmember [i] = c if row i is in the - * constraint set c. c must be >= 0. The # of - * constraint sets is max (Cmember) + 1. If Cmember is - * NULL, then it is interpretted as Cmember [i] = 0 for - * all i */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Cmember, // size A->nrow. Cmember [i] = c if row i is in the + // constraint set c. c must be >= 0. The # of + // constraint sets is max (Cmember) + 1. If Cmember is + // NULL, then it is interpretted as Cmember [i] = 0 for + // all i. + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_ccolamd (cholmod_sparse *, int64_t *, size_t, int64_t *, + int64_t *, cholmod_common *) ; -int cholmod_l_ccolamd (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_csymamd */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_csymamd +//------------------------------------------------------------------------------ -/* Order A using CSYMAMD. */ +// Order A using CSYMAMD. int cholmod_csymamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - /* ---- output --- */ - int32_t *Cmember, /* size nrow. see cholmod_ccolamd above */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + // output: + int32_t *Cmember, // size nrow. see cholmod_ccolamd.c for description + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_csymamd (cholmod_sparse *, int64_t *, int64_t *, + cholmod_common *) ; -int cholmod_l_csymamd (cholmod_sparse *, int64_t *, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_camd */ -/* -------------------------------------------------------------------------- */ - -/* Order A using CAMD. */ +//------------------------------------------------------------------------------ +// cholmod_camd: order A using CAMD +//------------------------------------------------------------------------------ int cholmod_camd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Cmember, /* size nrow. see cholmod_ccolamd above */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Cmember, // size nrow. see cholmod_ccolamd.c for description. + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; - -int cholmod_l_camd (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, cholmod_common *) ; +int cholmod_l_camd (cholmod_sparse *, int64_t *, size_t, int64_t *, int64_t *, + cholmod_common *) ; #endif -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD:Partition Module (graph partition methods) -//============================================================================== +//------------------------------------------------------------------------------ // These routines still exist if CHOLMOD is compiled with -DNPARTITION, // but they return Common->status = CHOLMOD_NOT_INSTALLED in that case. + #if 1 -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_partition.h. - * Copyright (C) 2005-2013, Univ. of Florida. Author: Timothy A. Davis - * -------------------------------------------------------------------------- */ - -/* CHOLMOD Partition module. - * - * Graph partitioning and graph-partition-based orderings. Includes an - * interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering - * methods which order a matrix following constraints determined via nested - * dissection. - * - * These functions require METIS: - * cholmod_nested_dissection CHOLMOD nested dissection ordering - * cholmod_metis METIS nested dissection ordering (METIS_NodeND) - * cholmod_bisect graph partitioner (currently based on METIS) - * cholmod_metis_bisector direct interface to METIS_ComputeVertexSeparator - * - * Requires the Utility and Cholesky modules, and three packages: METIS, CAMD, - * and CCOLAMD. Optionally used by the Cholesky module. - * - * Note that METIS does not have a version that uses int64_t integers. If you - * try to use cholmod_nested_dissection, cholmod_metis, cholmod_bisect, or - * cholmod_metis_bisector on a matrix that is too large, an error code will be - * returned. METIS does have an "idxtype", which could be redefined as - * int64_t, if you wish to edit METIS or use compile-time flags to redefine - * idxtype. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_nested_dissection */ -/* -------------------------------------------------------------------------- */ - -/* Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method - * (METIS's node bisector applied recursively to compute the separator tree - * and constraint sets, followed by CCOLAMD using the constraints). Usually - * finds better orderings than METIS_NodeND, but takes longer. - */ - -int64_t cholmod_nested_dissection /* returns # of components */ -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - int32_t *CParent, /* size A->nrow. On output, CParent [c] is the parent - * of component c, or EMPTY if c is a root, and where - * c is in the range 0 to # of components minus 1 */ - int32_t *Cmember, /* size A->nrow. Cmember [j] = c if node j of A is - * in component c */ - /* --------------- */ +//------------------------------------------------------------------------------ +// cholmod_nested_dissection +//------------------------------------------------------------------------------ + +// Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method +// (METIS's node bisector applied recursively to compute the separator tree +// and constraint sets, followed by CCOLAMD using the constraints). Usually +// finds better orderings than METIS_NodeND, but takes longer. + +int64_t cholmod_nested_dissection // returns # of components, or -1 if error +( + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Perm, // size A->nrow, output permutation + int32_t *CParent, // size A->nrow. On output, CParent [c] is the parent + // of component c, or EMPTY if c is a root, and where + // c is in the range 0 to # of components minus 1 + int32_t *Cmember, // size A->nrow. Cmember [j] = c if node j of A is + // in component c cholmod_common *Common ) ; - int64_t cholmod_l_nested_dissection (cholmod_sparse *, int64_t *, size_t, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_metis */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_metis +//------------------------------------------------------------------------------ -/* Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. */ +// Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. int cholmod_metis ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with etree or coletree postorder */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with etree or coletree postorder + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; - int cholmod_l_metis (cholmod_sparse *, int64_t *, size_t, int, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_bisect */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_bisect +//------------------------------------------------------------------------------ -/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. */ +// Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. -int64_t cholmod_bisect /* returns # of nodes in separator */ +int64_t cholmod_bisect // returns # of nodes in separator ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int compress, /* if TRUE, compress the graph first */ - /* ---- output --- */ - int32_t *Partition, /* size A->nrow. Node i is in the left graph if - * Partition [i] = 0, the right graph if 1, and in the - * separator if 2. */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int compress, // if TRUE, compress the graph first + // output: + int32_t *Partition, // size A->nrow. Node i is in the left graph if + // Partition [i] = 0, the right graph if 1, and in the + // separator if 2. cholmod_common *Common ) ; - int64_t cholmod_l_bisect (cholmod_sparse *, int64_t *, size_t, int, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_metis_bisector */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_metis_bisector +//------------------------------------------------------------------------------ -/* Find a set of nodes that bisects the graph of A or AA' (direct interface - * to METIS_ComputeVertexSeperator). */ +// Find a set of nodes that bisects the graph of A or AA' (direct interface +// to METIS_ComputeVertexSeperator). -int64_t cholmod_metis_bisector /* returns separator size */ +int64_t cholmod_metis_bisector // returns separator size ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - int32_t *Anw, /* size A->nrow, node weights, can be NULL, */ - /* which means the graph is unweighted. */ - int32_t *Aew, /* size nz, edge weights (silently ignored). */ - /* This option was available with METIS 4, but not */ - /* in METIS 5. This argument is now unused, but */ - /* it remains for backward compatibilty, so as not */ - /* to change the API for cholmod_metis_bisector. */ - /* ---- output --- */ - int32_t *Partition, /* size A->nrow */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + int32_t *Anw, // size A->nrow, node weights, can be NULL, + // which means the graph is unweighted. + int32_t *Aew, // size nz, edge weights (silently ignored). + // This option was available with METIS 4, but not + // in METIS 5. This argument is now unused, but + // it remains for backward compatibilty, so as not + // to change the API for cholmod_metis_bisector. + // output: + int32_t *Partition, // size A->nrow cholmod_common *Common ) ; - int64_t cholmod_l_metis_bisector (cholmod_sparse *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_collapse_septree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_collapse_septree +//------------------------------------------------------------------------------ -/* Collapse nodes in a separator tree. */ +// Collapse nodes in a separator tree. int64_t cholmod_collapse_septree ( - /* ---- input ---- */ - size_t n, /* # of nodes in the graph */ - size_t ncomponents, /* # of nodes in the separator tree (must be <= n) */ - double nd_oksep, /* collapse if #sep >= nd_oksep * #nodes in subtree */ - size_t nd_small, /* collapse if #nodes in subtree < nd_small */ - /* ---- in/out --- */ - int32_t *CParent, /* size ncomponents; from cholmod_nested_dissection */ - int32_t *Cmember, /* size n; from cholmod_nested_dissection */ - /* --------------- */ + // input: + size_t n, // # of nodes in the graph + size_t ncomponents, // # of nodes in the separator tree (must be <= n) + double nd_oksep, // collapse if #sep >= nd_oksep * #nodes in subtree + size_t nd_small, // collapse if #nodes in subtree < nd_small + // output: + int32_t *CParent, // size ncomponents; from cholmod_nested_dissection + int32_t *Cmember, // size n; from cholmod_nested_dissection cholmod_common *Common ) ; - int64_t cholmod_l_collapse_septree (size_t, size_t, double, size_t, int64_t *, int64_t *, cholmod_common *) ; @@ -3714,154 +3817,147 @@ int64_t cholmod_l_collapse_septree (size_t, size_t, double, size_t, int64_t *, #ifndef NSUPERNODAL -/* Supernodal analysis, factorization, and solve. The simplest way to use - * these routines is via the Cholesky module. It does not provide any - * fill-reducing orderings, but does accept the orderings computed by the - * Cholesky module. It does not require the Cholesky module itself, however. - * - * Primary routines: - * ----------------- - * cholmod_super_symbolic supernodal symbolic analysis - * cholmod_super_numeric supernodal numeric factorization - * cholmod_super_lsolve supernodal Lx=b solve - * cholmod_super_ltsolve supernodal L'x=b solve - * - * Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed - * below, including how they are used in CHOLMOD. - * - * BLAS routines: - * -------------- - * dtrsv solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1 - * dtrsm solve LX=B or L'X=b, L non-unit diagonal - * dgemv y=y-A*x or y=y-A'*x (x and y stride-1) - * dgemm C=A*B', C=C-A*B, or C=C-A'*B - * dsyrk C=tril(A*A') - * - * LAPACK routines: - * ---------------- - * dpotrf LAPACK: A=chol(tril(A)) - * - * Requires the Utility module, and two external packages: LAPACK and the BLAS. - * Optionally used by the Cholesky module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_super_symbolic */ -/* -------------------------------------------------------------------------- */ - -/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric - * factorization. The user need not call this directly; cholmod_analyze is - * a "simple" wrapper for this routine. - */ - -int cholmod_super_symbolic -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - int32_t *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ +// Supernodal analysis, factorization, and solve. The simplest way to use +// these routines is via the Cholesky module. It does not provide any +// fill-reducing orderings, but does accept the orderings computed by the +// Cholesky module. It does not require the Cholesky module itself, however. +// +// Primary routines: +// ----------------- +// cholmod_super_symbolic supernodal symbolic analysis +// cholmod_super_numeric supernodal numeric factorization +// cholmod_super_lsolve supernodal Lx=b solve +// cholmod_super_ltsolve supernodal L'x=b solve +// +// Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed +// below, including how they are used in CHOLMOD. Only the double methods are +// listed, but CHOLMOD also uses the corresponding single, single complex, and +// double complex routines. +// +// BLAS routines: +// -------------- +// dtrsv solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1 +// dtrsm solve LX=B or L'X=b, L non-unit diagonal +// dgemv y=y-A*x or y=y-A'*x (x and y stride-1) +// dgemm C=A*B', C=C-A*B, or C=C-A'*B +// dsyrk C=tril(A*A'), zherk for the double complex case +// +// LAPACK routines: +// ---------------- +// dpotrf LAPACK: A=chol(tril(A)) +// +// Requires the Utility module, and two external packages: LAPACK and the BLAS. +// Optionally used by the Cholesky module. + +//------------------------------------------------------------------------------ +// cholmod_super_symbolic +//------------------------------------------------------------------------------ + +// Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric +// factorization. The user need not call this directly; cholmod_analyze is +// a "simple" wrapper for this routine. + +int cholmod_super_symbolic +( + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + int32_t *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) ; - int cholmod_l_super_symbolic (cholmod_sparse *, cholmod_sparse *, int64_t *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_symbolic2 */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_symbolic2 +//------------------------------------------------------------------------------ -/* Analyze for supernodal Cholesky or multifrontal QR */ +// Analyze for supernodal Cholesky or multifrontal QR + +#define CHOLMOD_ANALYZE_FOR_SPQR 0 +#define CHOLMOD_ANALYZE_FOR_CHOLESKY 1 +#define CHOLMOD_ANALYZE_FOR_SPQRGPU 2 int cholmod_super_symbolic2 ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - int32_t *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + int32_t *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) ; - int cholmod_l_super_symbolic2 (int, cholmod_sparse *, cholmod_sparse *, int64_t *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_numeric */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_numeric +//------------------------------------------------------------------------------ -/* Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using - * a BLAS-based supernodal method. The user need not call this directly; - * cholmod_factorize is a "simple" wrapper for this routine. - */ +// Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using +// a BLAS-based supernodal method. The user need not call this directly; +// cholmod_factorize is a "simple" wrapper for this routine. int cholmod_super_numeric ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - double beta [2], /* beta*I is added to diagonal of matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // F = A' or A(:,f)' + double beta [2], // beta*I is added to diagonal of matrix to factorize + // input/output: + cholmod_factor *L, // factorization cholmod_common *Common ) ; - int cholmod_l_super_numeric (cholmod_sparse *, cholmod_sparse *, double *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_lsolve */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_lsolve +//------------------------------------------------------------------------------ -/* Solve Lx=b where L is from a supernodal numeric factorization. The user - * need not call this routine directly. cholmod_solve is a "simple" wrapper - * for this routine. */ +// Solve Lx=b where L is from a supernodal numeric factorization. The user +// need not call this routine directly. cholmod_solve is a "simple" wrapper +// for this routine. int cholmod_super_lsolve ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the forward solve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to Lx=b on output */ - /* ---- workspace */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the forward solve + // input/output: + cholmod_dense *X, // b on input, solution to Lx=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) ; - int cholmod_l_super_lsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_ltsolve */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_ltsolve +//------------------------------------------------------------------------------ -/* Solve L'x=b where L is from a supernodal numeric factorization. The user - * need not call this routine directly. cholmod_solve is a "simple" wrapper - * for this routine. */ +// Solve L'x=b where L is from a supernodal numeric factorization. The user +// need not call this routine directly. cholmod_solve is a "simple" wrapper +// for this routine. int cholmod_super_ltsolve ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the backsolve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to L'x=b on output */ - /* ---- workspace */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the backsolve + // input/output: + cholmod_dense *X, // b on input, solution to L'x=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) ; - int cholmod_l_super_ltsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; @@ -3912,18 +4008,16 @@ int cholmod_l_score_comp (struct cholmod_descendant_score_t *i, #include #endif -/* CHOLMOD_GPU_PRINTF: for printing GPU debug error messages */ -/* -#define CHOLMOD_GPU_PRINTF(args) printf args -*/ +// CHOLMOD_GPU_PRINTF: for printing GPU debug error messages +// #define CHOLMOD_GPU_PRINTF(args) printf args #define CHOLMOD_GPU_PRINTF(args) -/* define supernode requirements for processing on GPU */ -#define CHOLMOD_ND_ROW_LIMIT 256 /* required descendant rows */ -#define CHOLMOD_ND_COL_LIMIT 32 /* required descendnat cols */ +// define supernode requirements for processing on GPU +#define CHOLMOD_ND_ROW_LIMIT 256 /* required descendant rows */ +#define CHOLMOD_ND_COL_LIMIT 32 /* required descendnat cols */ #define CHOLMOD_POTRF_LIMIT 512 /* required cols for POTRF & TRSM on GPU */ -/* # of host supernodes to perform before checking for free pinned buffers */ +// # of host supernodes to perform before checking for free pinned buffers #define CHOLMOD_GPU_SKIP 3 #define CHOLMOD_HANDLE_CUDA_ERROR(e,s) {if (e) {ERROR(CHOLMOD_GPU_PROBLEM,s);}} @@ -3944,14 +4038,14 @@ typedef struct cholmod_gpu_pointers } cholmod_gpu_pointers ; -int cholmod_gpu_memorysize /* GPU memory size available, 1 if no GPU */ +int cholmod_gpu_memorysize // GPU memory size available, 1 if no GPU ( size_t *total_mem, size_t *available_mem, cholmod_common *Common ) ; -int cholmod_l_gpu_memorysize /* GPU memory size available, 1 if no GPU */ +int cholmod_l_gpu_memorysize // GPU memory size available, 1 if no GPU ( size_t *total_mem, size_t *available_mem, diff --git a/CHOLMOD/Demo/Matrix/n5 b/CHOLMOD/Demo/Matrix/n5 deleted file mode 100644 index b3f24d5b98..0000000000 --- a/CHOLMOD/Demo/Matrix/n5 +++ /dev/null @@ -1,4061 +0,0 @@ -210 210 4060 1 -1 1 5 -2 1 1 -3 1 1 -4 1 1 -25 1 1 -45 1 1 -65 1 1 -85 1 1 -101 1 2 -102 1 2 -103 1 2 -104 1 2 -152 1 1 -158 1 1 -169 1 1 -185 1 1 -201 1 -1 -206 1 -1 -1 2 1 -2 2 5 -3 2 1 -4 2 1 -29 2 1 -49 2 1 -69 2 1 -89 2 1 -101 2 2 -102 2 2 -103 2 2 -104 2 2 -153 2 1 -160 2 1 -172 2 1 -189 2 1 -201 2 -1 -206 2 -1 -1 3 1 -2 3 1 -3 3 5 -4 3 1 -33 3 1 -53 3 1 -73 3 1 -93 3 1 -101 3 2 -102 3 2 -103 3 2 -104 3 2 -154 3 1 -162 3 1 -175 3 1 -193 3 1 -201 3 -1 -206 3 -1 -1 4 1 -2 4 1 -3 4 1 -4 4 5 -37 4 1 -57 4 1 -77 4 1 -97 4 1 -101 4 2 -102 4 2 -103 4 2 -104 4 2 -155 4 1 -164 4 1 -178 4 1 -197 4 1 -201 4 -1 -206 4 -1 -5 5 5 -6 5 1 -7 5 1 -8 5 1 -21 5 1 -41 5 1 -61 5 1 -81 5 1 -105 5 2 -106 5 2 -107 5 2 -108 5 2 -151 5 1 -156 5 1 -166 5 1 -181 5 1 -202 5 -1 -206 5 -1 -5 6 1 -6 6 5 -7 6 1 -8 6 1 -30 6 1 -50 6 1 -70 6 1 -90 6 1 -105 6 2 -106 6 2 -107 6 2 -108 6 2 -153 6 1 -160 6 1 -172 6 1 -189 6 1 -202 6 -1 -206 6 -1 -5 7 1 -6 7 1 -7 7 5 -8 7 1 -34 7 1 -54 7 1 -74 7 1 -94 7 1 -105 7 2 -106 7 2 -107 7 2 -108 7 2 -154 7 1 -162 7 1 -175 7 1 -193 7 1 -202 7 -1 -206 7 -1 -5 8 1 -6 8 1 -7 8 1 -8 8 5 -38 8 1 -58 8 1 -78 8 1 -98 8 1 -105 8 2 -106 8 2 -107 8 2 -108 8 2 -155 8 1 -164 8 1 -178 8 1 -197 8 1 -202 8 -1 -206 8 -1 -9 9 5 -10 9 1 -11 9 1 -12 9 1 -22 9 1 -42 9 1 -62 9 1 -82 9 1 -109 9 2 -110 9 2 -111 9 2 -112 9 2 -151 9 1 -156 9 1 -166 9 1 -181 9 1 -203 9 -1 -206 9 -1 -9 10 1 -10 10 5 -11 10 1 -12 10 1 -26 10 1 -46 10 1 -66 10 1 -86 10 1 -109 10 2 -110 10 2 -111 10 2 -112 10 2 -152 10 1 -158 10 1 -169 10 1 -185 10 1 -203 10 -1 -206 10 -1 -9 11 1 -10 11 1 -11 11 5 -12 11 1 -35 11 1 -55 11 1 -75 11 1 -95 11 1 -109 11 2 -110 11 2 -111 11 2 -112 11 2 -154 11 1 -162 11 1 -175 11 1 -193 11 1 -203 11 -1 -206 11 -1 -9 12 1 -10 12 1 -11 12 1 -12 12 5 -39 12 1 -59 12 1 -79 12 1 -99 12 1 -109 12 2 -110 12 2 -111 12 2 -112 12 2 -155 12 1 -164 12 1 -178 12 1 -197 12 1 -203 12 -1 -206 12 -1 -13 13 5 -14 13 1 -15 13 1 -16 13 1 -23 13 1 -43 13 1 -63 13 1 -83 13 1 -113 13 2 -114 13 2 -115 13 2 -116 13 2 -151 13 1 -156 13 1 -166 13 1 -181 13 1 -204 13 -1 -206 13 -1 -13 14 1 -14 14 5 -15 14 1 -16 14 1 -27 14 1 -47 14 1 -67 14 1 -87 14 1 -113 14 2 -114 14 2 -115 14 2 -116 14 2 -152 14 1 -158 14 1 -169 14 1 -185 14 1 -204 14 -1 -206 14 -1 -13 15 1 -14 15 1 -15 15 5 -16 15 1 -31 15 1 -51 15 1 -71 15 1 -91 15 1 -113 15 2 -114 15 2 -115 15 2 -116 15 2 -153 15 1 -160 15 1 -172 15 1 -189 15 1 -204 15 -1 -206 15 -1 -13 16 1 -14 16 1 -15 16 1 -16 16 5 -40 16 1 -60 16 1 -80 16 1 -100 16 1 -113 16 2 -114 16 2 -115 16 2 -116 16 2 -155 16 1 -164 16 1 -178 16 1 -197 16 1 -204 16 -1 -206 16 -1 -17 17 5 -18 17 1 -19 17 1 -20 17 1 -24 17 1 -44 17 1 -64 17 1 -84 17 1 -117 17 2 -118 17 2 -119 17 2 -120 17 2 -151 17 1 -156 17 1 -166 17 1 -181 17 1 -205 17 -1 -206 17 -1 -17 18 1 -18 18 5 -19 18 1 -20 18 1 -28 18 1 -48 18 1 -68 18 1 -88 18 1 -117 18 2 -118 18 2 -119 18 2 -120 18 2 -152 18 1 -158 18 1 -169 18 1 -185 18 1 -205 18 -1 -206 18 -1 -17 19 1 -18 19 1 -19 19 5 -20 19 1 -32 19 1 -52 19 1 -72 19 1 -92 19 1 -117 19 2 -118 19 2 -119 19 2 -120 19 2 -153 19 1 -160 19 1 -172 19 1 -189 19 1 -205 19 -1 -206 19 -1 -17 20 1 -18 20 1 -19 20 1 -20 20 5 -36 20 1 -56 20 1 -76 20 1 -96 20 1 -117 20 2 -118 20 2 -119 20 2 -120 20 2 -154 20 1 -162 20 1 -175 20 1 -193 20 1 -205 20 -1 -206 20 -1 -5 21 1 -21 21 5 -22 21 1 -23 21 1 -24 21 1 -45 21 1 -65 21 1 -85 21 1 -105 21 1 -121 21 2 -122 21 2 -123 21 2 -151 21 2 -159 21 1 -170 21 1 -186 21 1 -201 21 -1 -207 21 -1 -9 22 1 -21 22 1 -22 22 5 -23 22 1 -24 22 1 -49 22 1 -69 22 1 -89 22 1 -109 22 1 -121 22 2 -122 22 2 -123 22 2 -151 22 2 -161 22 1 -173 22 1 -190 22 1 -201 22 -1 -207 22 -1 -13 23 1 -21 23 1 -22 23 1 -23 23 5 -24 23 1 -53 23 1 -73 23 1 -93 23 1 -113 23 1 -121 23 2 -122 23 2 -123 23 2 -151 23 2 -163 23 1 -176 23 1 -194 23 1 -201 23 -1 -207 23 -1 -17 24 1 -21 24 1 -22 24 1 -23 24 1 -24 24 5 -57 24 1 -77 24 1 -97 24 1 -117 24 1 -121 24 2 -122 24 2 -123 24 2 -151 24 2 -165 24 1 -179 24 1 -198 24 1 -201 24 -1 -207 24 -1 -1 25 1 -25 25 5 -26 25 1 -27 25 1 -28 25 1 -41 25 1 -61 25 1 -81 25 1 -101 25 1 -124 25 2 -125 25 2 -126 25 2 -152 25 2 -157 25 1 -167 25 1 -182 25 1 -202 25 -1 -207 25 -1 -10 26 1 -25 26 1 -26 26 5 -27 26 1 -28 26 1 -50 26 1 -70 26 1 -90 26 1 -109 26 1 -124 26 2 -125 26 2 -126 26 2 -152 26 2 -161 26 1 -173 26 1 -190 26 1 -202 26 -1 -207 26 -1 -14 27 1 -25 27 1 -26 27 1 -27 27 5 -28 27 1 -54 27 1 -74 27 1 -94 27 1 -113 27 1 -124 27 2 -125 27 2 -126 27 2 -152 27 2 -163 27 1 -176 27 1 -194 27 1 -202 27 -1 -207 27 -1 -18 28 1 -25 28 1 -26 28 1 -27 28 1 -28 28 5 -58 28 1 -78 28 1 -98 28 1 -117 28 1 -124 28 2 -125 28 2 -126 28 2 -152 28 2 -165 28 1 -179 28 1 -198 28 1 -202 28 -1 -207 28 -1 -2 29 1 -29 29 5 -30 29 1 -31 29 1 -32 29 1 -42 29 1 -62 29 1 -82 29 1 -101 29 1 -127 29 2 -128 29 2 -129 29 2 -153 29 2 -157 29 1 -167 29 1 -182 29 1 -203 29 -1 -207 29 -1 -6 30 1 -29 30 1 -30 30 5 -31 30 1 -32 30 1 -46 30 1 -66 30 1 -86 30 1 -105 30 1 -127 30 2 -128 30 2 -129 30 2 -153 30 2 -159 30 1 -170 30 1 -186 30 1 -203 30 -1 -207 30 -1 -15 31 1 -29 31 1 -30 31 1 -31 31 5 -32 31 1 -55 31 1 -75 31 1 -95 31 1 -113 31 1 -127 31 2 -128 31 2 -129 31 2 -153 31 2 -163 31 1 -176 31 1 -194 31 1 -203 31 -1 -207 31 -1 -19 32 1 -29 32 1 -30 32 1 -31 32 1 -32 32 5 -59 32 1 -79 32 1 -99 32 1 -117 32 1 -127 32 2 -128 32 2 -129 32 2 -153 32 2 -165 32 1 -179 32 1 -198 32 1 -203 32 -1 -207 32 -1 -3 33 1 -33 33 5 -34 33 1 -35 33 1 -36 33 1 -43 33 1 -63 33 1 -83 33 1 -101 33 1 -130 33 2 -131 33 2 -132 33 2 -154 33 2 -157 33 1 -167 33 1 -182 33 1 -204 33 -1 -207 33 -1 -7 34 1 -33 34 1 -34 34 5 -35 34 1 -36 34 1 -47 34 1 -67 34 1 -87 34 1 -105 34 1 -130 34 2 -131 34 2 -132 34 2 -154 34 2 -159 34 1 -170 34 1 -186 34 1 -204 34 -1 -207 34 -1 -11 35 1 -33 35 1 -34 35 1 -35 35 5 -36 35 1 -51 35 1 -71 35 1 -91 35 1 -109 35 1 -130 35 2 -131 35 2 -132 35 2 -154 35 2 -161 35 1 -173 35 1 -190 35 1 -204 35 -1 -207 35 -1 -20 36 1 -33 36 1 -34 36 1 -35 36 1 -36 36 5 -60 36 1 -80 36 1 -100 36 1 -117 36 1 -130 36 2 -131 36 2 -132 36 2 -154 36 2 -165 36 1 -179 36 1 -198 36 1 -204 36 -1 -207 36 -1 -4 37 1 -37 37 5 -38 37 1 -39 37 1 -40 37 1 -44 37 1 -64 37 1 -84 37 1 -101 37 1 -133 37 2 -134 37 2 -135 37 2 -155 37 2 -157 37 1 -167 37 1 -182 37 1 -205 37 -1 -207 37 -1 -8 38 1 -37 38 1 -38 38 5 -39 38 1 -40 38 1 -48 38 1 -68 38 1 -88 38 1 -105 38 1 -133 38 2 -134 38 2 -135 38 2 -155 38 2 -159 38 1 -170 38 1 -186 38 1 -205 38 -1 -207 38 -1 -12 39 1 -37 39 1 -38 39 1 -39 39 5 -40 39 1 -52 39 1 -72 39 1 -92 39 1 -109 39 1 -133 39 2 -134 39 2 -135 39 2 -155 39 2 -161 39 1 -173 39 1 -190 39 1 -205 39 -1 -207 39 -1 -16 40 1 -37 40 1 -38 40 1 -39 40 1 -40 40 5 -56 40 1 -76 40 1 -96 40 1 -113 40 1 -133 40 2 -134 40 2 -135 40 2 -155 40 2 -163 40 1 -176 40 1 -194 40 1 -205 40 -1 -207 40 -1 -5 41 1 -25 41 1 -41 41 5 -42 41 1 -43 41 1 -44 41 1 -65 41 1 -85 41 1 -106 41 1 -124 41 1 -136 41 2 -137 41 2 -156 41 2 -157 41 2 -171 41 1 -187 41 1 -201 41 -1 -208 41 -1 -9 42 1 -29 42 1 -41 42 1 -42 42 5 -43 42 1 -44 42 1 -69 42 1 -89 42 1 -110 42 1 -127 42 1 -136 42 2 -137 42 2 -156 42 2 -157 42 2 -174 42 1 -191 42 1 -201 42 -1 -208 42 -1 -13 43 1 -33 43 1 -41 43 1 -42 43 1 -43 43 5 -44 43 1 -73 43 1 -93 43 1 -114 43 1 -130 43 1 -136 43 2 -137 43 2 -156 43 2 -157 43 2 -177 43 1 -195 43 1 -201 43 -1 -208 43 -1 -17 44 1 -37 44 1 -41 44 1 -42 44 1 -43 44 1 -44 44 5 -77 44 1 -97 44 1 -118 44 1 -133 44 1 -136 44 2 -137 44 2 -156 44 2 -157 44 2 -180 44 1 -199 44 1 -201 44 -1 -208 44 -1 -1 45 1 -21 45 1 -45 45 5 -46 45 1 -47 45 1 -48 45 1 -61 45 1 -81 45 1 -102 45 1 -121 45 1 -138 45 2 -139 45 2 -158 45 2 -159 45 2 -168 45 1 -183 45 1 -202 45 -1 -208 45 -1 -10 46 1 -30 46 1 -45 46 1 -46 46 5 -47 46 1 -48 46 1 -70 46 1 -90 46 1 -110 46 1 -127 46 1 -138 46 2 -139 46 2 -158 46 2 -159 46 2 -174 46 1 -191 46 1 -202 46 -1 -208 46 -1 -14 47 1 -34 47 1 -45 47 1 -46 47 1 -47 47 5 -48 47 1 -74 47 1 -94 47 1 -114 47 1 -130 47 1 -138 47 2 -139 47 2 -158 47 2 -159 47 2 -177 47 1 -195 47 1 -202 47 -1 -208 47 -1 -18 48 1 -38 48 1 -45 48 1 -46 48 1 -47 48 1 -48 48 5 -78 48 1 -98 48 1 -118 48 1 -133 48 1 -138 48 2 -139 48 2 -158 48 2 -159 48 2 -180 48 1 -199 48 1 -202 48 -1 -208 48 -1 -2 49 1 -22 49 1 -49 49 5 -50 49 1 -51 49 1 -52 49 1 -62 49 1 -82 49 1 -102 49 1 -121 49 1 -140 49 2 -141 49 2 -160 49 2 -161 49 2 -168 49 1 -183 49 1 -203 49 -1 -208 49 -1 -6 50 1 -26 50 1 -49 50 1 -50 50 5 -51 50 1 -52 50 1 -66 50 1 -86 50 1 -106 50 1 -124 50 1 -140 50 2 -141 50 2 -160 50 2 -161 50 2 -171 50 1 -187 50 1 -203 50 -1 -208 50 -1 -15 51 1 -35 51 1 -49 51 1 -50 51 1 -51 51 5 -52 51 1 -75 51 1 -95 51 1 -114 51 1 -130 51 1 -140 51 2 -141 51 2 -160 51 2 -161 51 2 -177 51 1 -195 51 1 -203 51 -1 -208 51 -1 -19 52 1 -39 52 1 -49 52 1 -50 52 1 -51 52 1 -52 52 5 -79 52 1 -99 52 1 -118 52 1 -133 52 1 -140 52 2 -141 52 2 -160 52 2 -161 52 2 -180 52 1 -199 52 1 -203 52 -1 -208 52 -1 -3 53 1 -23 53 1 -53 53 5 -54 53 1 -55 53 1 -56 53 1 -63 53 1 -83 53 1 -102 53 1 -121 53 1 -142 53 2 -143 53 2 -162 53 2 -163 53 2 -168 53 1 -183 53 1 -204 53 -1 -208 53 -1 -7 54 1 -27 54 1 -53 54 1 -54 54 5 -55 54 1 -56 54 1 -67 54 1 -87 54 1 -106 54 1 -124 54 1 -142 54 2 -143 54 2 -162 54 2 -163 54 2 -171 54 1 -187 54 1 -204 54 -1 -208 54 -1 -11 55 1 -31 55 1 -53 55 1 -54 55 1 -55 55 5 -56 55 1 -71 55 1 -91 55 1 -110 55 1 -127 55 1 -142 55 2 -143 55 2 -162 55 2 -163 55 2 -174 55 1 -191 55 1 -204 55 -1 -208 55 -1 -20 56 1 -40 56 1 -53 56 1 -54 56 1 -55 56 1 -56 56 5 -80 56 1 -100 56 1 -118 56 1 -133 56 1 -142 56 2 -143 56 2 -162 56 2 -163 56 2 -180 56 1 -199 56 1 -204 56 -1 -208 56 -1 -4 57 1 -24 57 1 -57 57 5 -58 57 1 -59 57 1 -60 57 1 -64 57 1 -84 57 1 -102 57 1 -121 57 1 -144 57 2 -145 57 2 -164 57 2 -165 57 2 -168 57 1 -183 57 1 -205 57 -1 -208 57 -1 -8 58 1 -28 58 1 -57 58 1 -58 58 5 -59 58 1 -60 58 1 -68 58 1 -88 58 1 -106 58 1 -124 58 1 -144 58 2 -145 58 2 -164 58 2 -165 58 2 -171 58 1 -187 58 1 -205 58 -1 -208 58 -1 -12 59 1 -32 59 1 -57 59 1 -58 59 1 -59 59 5 -60 59 1 -72 59 1 -92 59 1 -110 59 1 -127 59 1 -144 59 2 -145 59 2 -164 59 2 -165 59 2 -174 59 1 -191 59 1 -205 59 -1 -208 59 -1 -16 60 1 -36 60 1 -57 60 1 -58 60 1 -59 60 1 -60 60 5 -76 60 1 -96 60 1 -114 60 1 -130 60 1 -144 60 2 -145 60 2 -164 60 2 -165 60 2 -177 60 1 -195 60 1 -205 60 -1 -208 60 -1 -5 61 1 -25 61 1 -45 61 1 -61 61 5 -62 61 1 -63 61 1 -64 61 1 -85 61 1 -107 61 1 -125 61 1 -138 61 1 -146 61 2 -166 61 2 -167 61 2 -168 61 2 -188 61 1 -201 61 -1 -209 61 -1 -9 62 1 -29 62 1 -49 62 1 -61 62 1 -62 62 5 -63 62 1 -64 62 1 -89 62 1 -111 62 1 -128 62 1 -140 62 1 -146 62 2 -166 62 2 -167 62 2 -168 62 2 -192 62 1 -201 62 -1 -209 62 -1 -13 63 1 -33 63 1 -53 63 1 -61 63 1 -62 63 1 -63 63 5 -64 63 1 -93 63 1 -115 63 1 -131 63 1 -142 63 1 -146 63 2 -166 63 2 -167 63 2 -168 63 2 -196 63 1 -201 63 -1 -209 63 -1 -17 64 1 -37 64 1 -57 64 1 -61 64 1 -62 64 1 -63 64 1 -64 64 5 -97 64 1 -119 64 1 -134 64 1 -144 64 1 -146 64 2 -166 64 2 -167 64 2 -168 64 2 -200 64 1 -201 64 -1 -209 64 -1 -1 65 1 -21 65 1 -41 65 1 -65 65 5 -66 65 1 -67 65 1 -68 65 1 -81 65 1 -103 65 1 -122 65 1 -136 65 1 -147 65 2 -169 65 2 -170 65 2 -171 65 2 -184 65 1 -202 65 -1 -209 65 -1 -10 66 1 -30 66 1 -50 66 1 -65 66 1 -66 66 5 -67 66 1 -68 66 1 -90 66 1 -111 66 1 -128 66 1 -140 66 1 -147 66 2 -169 66 2 -170 66 2 -171 66 2 -192 66 1 -202 66 -1 -209 66 -1 -14 67 1 -34 67 1 -54 67 1 -65 67 1 -66 67 1 -67 67 5 -68 67 1 -94 67 1 -115 67 1 -131 67 1 -142 67 1 -147 67 2 -169 67 2 -170 67 2 -171 67 2 -196 67 1 -202 67 -1 -209 67 -1 -18 68 1 -38 68 1 -58 68 1 -65 68 1 -66 68 1 -67 68 1 -68 68 5 -98 68 1 -119 68 1 -134 68 1 -144 68 1 -147 68 2 -169 68 2 -170 68 2 -171 68 2 -200 68 1 -202 68 -1 -209 68 -1 -2 69 1 -22 69 1 -42 69 1 -69 69 5 -70 69 1 -71 69 1 -72 69 1 -82 69 1 -103 69 1 -122 69 1 -136 69 1 -148 69 2 -172 69 2 -173 69 2 -174 69 2 -184 69 1 -203 69 -1 -209 69 -1 -6 70 1 -26 70 1 -46 70 1 -69 70 1 -70 70 5 -71 70 1 -72 70 1 -86 70 1 -107 70 1 -125 70 1 -138 70 1 -148 70 2 -172 70 2 -173 70 2 -174 70 2 -188 70 1 -203 70 -1 -209 70 -1 -15 71 1 -35 71 1 -55 71 1 -69 71 1 -70 71 1 -71 71 5 -72 71 1 -95 71 1 -115 71 1 -131 71 1 -142 71 1 -148 71 2 -172 71 2 -173 71 2 -174 71 2 -196 71 1 -203 71 -1 -209 71 -1 -19 72 1 -39 72 1 -59 72 1 -69 72 1 -70 72 1 -71 72 1 -72 72 5 -99 72 1 -119 72 1 -134 72 1 -144 72 1 -148 72 2 -172 72 2 -173 72 2 -174 72 2 -200 72 1 -203 72 -1 -209 72 -1 -3 73 1 -23 73 1 -43 73 1 -73 73 5 -74 73 1 -75 73 1 -76 73 1 -83 73 1 -103 73 1 -122 73 1 -136 73 1 -149 73 2 -175 73 2 -176 73 2 -177 73 2 -184 73 1 -204 73 -1 -209 73 -1 -7 74 1 -27 74 1 -47 74 1 -73 74 1 -74 74 5 -75 74 1 -76 74 1 -87 74 1 -107 74 1 -125 74 1 -138 74 1 -149 74 2 -175 74 2 -176 74 2 -177 74 2 -188 74 1 -204 74 -1 -209 74 -1 -11 75 1 -31 75 1 -51 75 1 -73 75 1 -74 75 1 -75 75 5 -76 75 1 -91 75 1 -111 75 1 -128 75 1 -140 75 1 -149 75 2 -175 75 2 -176 75 2 -177 75 2 -192 75 1 -204 75 -1 -209 75 -1 -20 76 1 -40 76 1 -60 76 1 -73 76 1 -74 76 1 -75 76 1 -76 76 5 -100 76 1 -119 76 1 -134 76 1 -144 76 1 -149 76 2 -175 76 2 -176 76 2 -177 76 2 -200 76 1 -204 76 -1 -209 76 -1 -4 77 1 -24 77 1 -44 77 1 -77 77 5 -78 77 1 -79 77 1 -80 77 1 -84 77 1 -103 77 1 -122 77 1 -136 77 1 -150 77 2 -178 77 2 -179 77 2 -180 77 2 -184 77 1 -205 77 -1 -209 77 -1 -8 78 1 -28 78 1 -48 78 1 -77 78 1 -78 78 5 -79 78 1 -80 78 1 -88 78 1 -107 78 1 -125 78 1 -138 78 1 -150 78 2 -178 78 2 -179 78 2 -180 78 2 -188 78 1 -205 78 -1 -209 78 -1 -12 79 1 -32 79 1 -52 79 1 -77 79 1 -78 79 1 -79 79 5 -80 79 1 -92 79 1 -111 79 1 -128 79 1 -140 79 1 -150 79 2 -178 79 2 -179 79 2 -180 79 2 -192 79 1 -205 79 -1 -209 79 -1 -16 80 1 -36 80 1 -56 80 1 -77 80 1 -78 80 1 -79 80 1 -80 80 5 -96 80 1 -115 80 1 -131 80 1 -142 80 1 -150 80 2 -178 80 2 -179 80 2 -180 80 2 -196 80 1 -205 80 -1 -209 80 -1 -5 81 1 -25 81 1 -45 81 1 -65 81 1 -81 81 5 -82 81 1 -83 81 1 -84 81 1 -108 81 1 -126 81 1 -139 81 1 -147 81 1 -181 81 2 -182 81 2 -183 81 2 -184 81 2 -201 81 -1 -210 81 -1 -9 82 1 -29 82 1 -49 82 1 -69 82 1 -81 82 1 -82 82 5 -83 82 1 -84 82 1 -112 82 1 -129 82 1 -141 82 1 -148 82 1 -181 82 2 -182 82 2 -183 82 2 -184 82 2 -201 82 -1 -210 82 -1 -13 83 1 -33 83 1 -53 83 1 -73 83 1 -81 83 1 -82 83 1 -83 83 5 -84 83 1 -116 83 1 -132 83 1 -143 83 1 -149 83 1 -181 83 2 -182 83 2 -183 83 2 -184 83 2 -201 83 -1 -210 83 -1 -17 84 1 -37 84 1 -57 84 1 -77 84 1 -81 84 1 -82 84 1 -83 84 1 -84 84 5 -120 84 1 -135 84 1 -145 84 1 -150 84 1 -181 84 2 -182 84 2 -183 84 2 -184 84 2 -201 84 -1 -210 84 -1 -1 85 1 -21 85 1 -41 85 1 -61 85 1 -85 85 5 -86 85 1 -87 85 1 -88 85 1 -104 85 1 -123 85 1 -137 85 1 -146 85 1 -185 85 2 -186 85 2 -187 85 2 -188 85 2 -202 85 -1 -210 85 -1 -10 86 1 -30 86 1 -50 86 1 -70 86 1 -85 86 1 -86 86 5 -87 86 1 -88 86 1 -112 86 1 -129 86 1 -141 86 1 -148 86 1 -185 86 2 -186 86 2 -187 86 2 -188 86 2 -202 86 -1 -210 86 -1 -14 87 1 -34 87 1 -54 87 1 -74 87 1 -85 87 1 -86 87 1 -87 87 5 -88 87 1 -116 87 1 -132 87 1 -143 87 1 -149 87 1 -185 87 2 -186 87 2 -187 87 2 -188 87 2 -202 87 -1 -210 87 -1 -18 88 1 -38 88 1 -58 88 1 -78 88 1 -85 88 1 -86 88 1 -87 88 1 -88 88 5 -120 88 1 -135 88 1 -145 88 1 -150 88 1 -185 88 2 -186 88 2 -187 88 2 -188 88 2 -202 88 -1 -210 88 -1 -2 89 1 -22 89 1 -42 89 1 -62 89 1 -89 89 5 -90 89 1 -91 89 1 -92 89 1 -104 89 1 -123 89 1 -137 89 1 -146 89 1 -189 89 2 -190 89 2 -191 89 2 -192 89 2 -203 89 -1 -210 89 -1 -6 90 1 -26 90 1 -46 90 1 -66 90 1 -89 90 1 -90 90 5 -91 90 1 -92 90 1 -108 90 1 -126 90 1 -139 90 1 -147 90 1 -189 90 2 -190 90 2 -191 90 2 -192 90 2 -203 90 -1 -210 90 -1 -15 91 1 -35 91 1 -55 91 1 -75 91 1 -89 91 1 -90 91 1 -91 91 5 -92 91 1 -116 91 1 -132 91 1 -143 91 1 -149 91 1 -189 91 2 -190 91 2 -191 91 2 -192 91 2 -203 91 -1 -210 91 -1 -19 92 1 -39 92 1 -59 92 1 -79 92 1 -89 92 1 -90 92 1 -91 92 1 -92 92 5 -120 92 1 -135 92 1 -145 92 1 -150 92 1 -189 92 2 -190 92 2 -191 92 2 -192 92 2 -203 92 -1 -210 92 -1 -3 93 1 -23 93 1 -43 93 1 -63 93 1 -93 93 5 -94 93 1 -95 93 1 -96 93 1 -104 93 1 -123 93 1 -137 93 1 -146 93 1 -193 93 2 -194 93 2 -195 93 2 -196 93 2 -204 93 -1 -210 93 -1 -7 94 1 -27 94 1 -47 94 1 -67 94 1 -93 94 1 -94 94 5 -95 94 1 -96 94 1 -108 94 1 -126 94 1 -139 94 1 -147 94 1 -193 94 2 -194 94 2 -195 94 2 -196 94 2 -204 94 -1 -210 94 -1 -11 95 1 -31 95 1 -51 95 1 -71 95 1 -93 95 1 -94 95 1 -95 95 5 -96 95 1 -112 95 1 -129 95 1 -141 95 1 -148 95 1 -193 95 2 -194 95 2 -195 95 2 -196 95 2 -204 95 -1 -210 95 -1 -20 96 1 -40 96 1 -60 96 1 -80 96 1 -93 96 1 -94 96 1 -95 96 1 -96 96 5 -120 96 1 -135 96 1 -145 96 1 -150 96 1 -193 96 2 -194 96 2 -195 96 2 -196 96 2 -204 96 -1 -210 96 -1 -4 97 1 -24 97 1 -44 97 1 -64 97 1 -97 97 5 -98 97 1 -99 97 1 -100 97 1 -104 97 1 -123 97 1 -137 97 1 -146 97 1 -197 97 2 -198 97 2 -199 97 2 -200 97 2 -205 97 -1 -210 97 -1 -8 98 1 -28 98 1 -48 98 1 -68 98 1 -97 98 1 -98 98 5 -99 98 1 -100 98 1 -108 98 1 -126 98 1 -139 98 1 -147 98 1 -197 98 2 -198 98 2 -199 98 2 -200 98 2 -205 98 -1 -210 98 -1 -12 99 1 -32 99 1 -52 99 1 -72 99 1 -97 99 1 -98 99 1 -99 99 5 -100 99 1 -112 99 1 -129 99 1 -141 99 1 -148 99 1 -197 99 2 -198 99 2 -199 99 2 -200 99 2 -205 99 -1 -210 99 -1 -16 100 1 -36 100 1 -56 100 1 -76 100 1 -97 100 1 -98 100 1 -99 100 1 -100 100 5 -116 100 1 -132 100 1 -143 100 1 -149 100 1 -197 100 2 -198 100 2 -199 100 2 -200 100 2 -205 100 -1 -210 100 -1 -1 101 2 -2 101 2 -3 101 2 -4 101 2 -25 101 1 -29 101 1 -33 101 1 -37 101 1 -101 101 5 -102 101 1 -103 101 1 -104 101 1 -152 101 1 -153 101 1 -154 101 1 -155 101 1 -201 101 -1 -206 101 -1 -1 102 2 -2 102 2 -3 102 2 -4 102 2 -45 102 1 -49 102 1 -53 102 1 -57 102 1 -101 102 1 -102 102 5 -103 102 1 -104 102 1 -158 102 1 -160 102 1 -162 102 1 -164 102 1 -201 102 -1 -206 102 -1 -1 103 2 -2 103 2 -3 103 2 -4 103 2 -65 103 1 -69 103 1 -73 103 1 -77 103 1 -101 103 1 -102 103 1 -103 103 5 -104 103 1 -169 103 1 -172 103 1 -175 103 1 -178 103 1 -201 103 -1 -206 103 -1 -1 104 2 -2 104 2 -3 104 2 -4 104 2 -85 104 1 -89 104 1 -93 104 1 -97 104 1 -101 104 1 -102 104 1 -103 104 1 -104 104 5 -185 104 1 -189 104 1 -193 104 1 -197 104 1 -201 104 -1 -206 104 -1 -5 105 2 -6 105 2 -7 105 2 -8 105 2 -21 105 1 -30 105 1 -34 105 1 -38 105 1 -105 105 5 -106 105 1 -107 105 1 -108 105 1 -151 105 1 -153 105 1 -154 105 1 -155 105 1 -202 105 -1 -206 105 -1 -5 106 2 -6 106 2 -7 106 2 -8 106 2 -41 106 1 -50 106 1 -54 106 1 -58 106 1 -105 106 1 -106 106 5 -107 106 1 -108 106 1 -156 106 1 -160 106 1 -162 106 1 -164 106 1 -202 106 -1 -206 106 -1 -5 107 2 -6 107 2 -7 107 2 -8 107 2 -61 107 1 -70 107 1 -74 107 1 -78 107 1 -105 107 1 -106 107 1 -107 107 5 -108 107 1 -166 107 1 -172 107 1 -175 107 1 -178 107 1 -202 107 -1 -206 107 -1 -5 108 2 -6 108 2 -7 108 2 -8 108 2 -81 108 1 -90 108 1 -94 108 1 -98 108 1 -105 108 1 -106 108 1 -107 108 1 -108 108 5 -181 108 1 -189 108 1 -193 108 1 -197 108 1 -202 108 -1 -206 108 -1 -9 109 2 -10 109 2 -11 109 2 -12 109 2 -22 109 1 -26 109 1 -35 109 1 -39 109 1 -109 109 5 -110 109 1 -111 109 1 -112 109 1 -151 109 1 -152 109 1 -154 109 1 -155 109 1 -203 109 -1 -206 109 -1 -9 110 2 -10 110 2 -11 110 2 -12 110 2 -42 110 1 -46 110 1 -55 110 1 -59 110 1 -109 110 1 -110 110 5 -111 110 1 -112 110 1 -156 110 1 -158 110 1 -162 110 1 -164 110 1 -203 110 -1 -206 110 -1 -9 111 2 -10 111 2 -11 111 2 -12 111 2 -62 111 1 -66 111 1 -75 111 1 -79 111 1 -109 111 1 -110 111 1 -111 111 5 -112 111 1 -166 111 1 -169 111 1 -175 111 1 -178 111 1 -203 111 -1 -206 111 -1 -9 112 2 -10 112 2 -11 112 2 -12 112 2 -82 112 1 -86 112 1 -95 112 1 -99 112 1 -109 112 1 -110 112 1 -111 112 1 -112 112 5 -181 112 1 -185 112 1 -193 112 1 -197 112 1 -203 112 -1 -206 112 -1 -13 113 2 -14 113 2 -15 113 2 -16 113 2 -23 113 1 -27 113 1 -31 113 1 -40 113 1 -113 113 5 -114 113 1 -115 113 1 -116 113 1 -151 113 1 -152 113 1 -153 113 1 -155 113 1 -204 113 -1 -206 113 -1 -13 114 2 -14 114 2 -15 114 2 -16 114 2 -43 114 1 -47 114 1 -51 114 1 -60 114 1 -113 114 1 -114 114 5 -115 114 1 -116 114 1 -156 114 1 -158 114 1 -160 114 1 -164 114 1 -204 114 -1 -206 114 -1 -13 115 2 -14 115 2 -15 115 2 -16 115 2 -63 115 1 -67 115 1 -71 115 1 -80 115 1 -113 115 1 -114 115 1 -115 115 5 -116 115 1 -166 115 1 -169 115 1 -172 115 1 -178 115 1 -204 115 -1 -206 115 -1 -13 116 2 -14 116 2 -15 116 2 -16 116 2 -83 116 1 -87 116 1 -91 116 1 -100 116 1 -113 116 1 -114 116 1 -115 116 1 -116 116 5 -181 116 1 -185 116 1 -189 116 1 -197 116 1 -204 116 -1 -206 116 -1 -17 117 2 -18 117 2 -19 117 2 -20 117 2 -24 117 1 -28 117 1 -32 117 1 -36 117 1 -117 117 5 -118 117 1 -119 117 1 -120 117 1 -151 117 1 -152 117 1 -153 117 1 -154 117 1 -205 117 -1 -206 117 -1 -17 118 2 -18 118 2 -19 118 2 -20 118 2 -44 118 1 -48 118 1 -52 118 1 -56 118 1 -117 118 1 -118 118 5 -119 118 1 -120 118 1 -156 118 1 -158 118 1 -160 118 1 -162 118 1 -205 118 -1 -206 118 -1 -17 119 2 -18 119 2 -19 119 2 -20 119 2 -64 119 1 -68 119 1 -72 119 1 -76 119 1 -117 119 1 -118 119 1 -119 119 5 -120 119 1 -166 119 1 -169 119 1 -172 119 1 -175 119 1 -205 119 -1 -206 119 -1 -17 120 2 -18 120 2 -19 120 2 -20 120 2 -84 120 1 -88 120 1 -92 120 1 -96 120 1 -117 120 1 -118 120 1 -119 120 1 -120 120 5 -181 120 1 -185 120 1 -189 120 1 -193 120 1 -205 120 -1 -206 120 -1 -21 121 2 -22 121 2 -23 121 2 -24 121 2 -45 121 1 -49 121 1 -53 121 1 -57 121 1 -121 121 5 -122 121 1 -123 121 1 -151 121 1 -159 121 1 -161 121 1 -163 121 1 -165 121 1 -201 121 -1 -207 121 -1 -21 122 2 -22 122 2 -23 122 2 -24 122 2 -65 122 1 -69 122 1 -73 122 1 -77 122 1 -121 122 1 -122 122 5 -123 122 1 -151 122 1 -170 122 1 -173 122 1 -176 122 1 -179 122 1 -201 122 -1 -207 122 -1 -21 123 2 -22 123 2 -23 123 2 -24 123 2 -85 123 1 -89 123 1 -93 123 1 -97 123 1 -121 123 1 -122 123 1 -123 123 5 -151 123 1 -186 123 1 -190 123 1 -194 123 1 -198 123 1 -201 123 -1 -207 123 -1 -25 124 2 -26 124 2 -27 124 2 -28 124 2 -41 124 1 -50 124 1 -54 124 1 -58 124 1 -124 124 5 -125 124 1 -126 124 1 -152 124 1 -157 124 1 -161 124 1 -163 124 1 -165 124 1 -202 124 -1 -207 124 -1 -25 125 2 -26 125 2 -27 125 2 -28 125 2 -61 125 1 -70 125 1 -74 125 1 -78 125 1 -124 125 1 -125 125 5 -126 125 1 -152 125 1 -167 125 1 -173 125 1 -176 125 1 -179 125 1 -202 125 -1 -207 125 -1 -25 126 2 -26 126 2 -27 126 2 -28 126 2 -81 126 1 -90 126 1 -94 126 1 -98 126 1 -124 126 1 -125 126 1 -126 126 5 -152 126 1 -182 126 1 -190 126 1 -194 126 1 -198 126 1 -202 126 -1 -207 126 -1 -29 127 2 -30 127 2 -31 127 2 -32 127 2 -42 127 1 -46 127 1 -55 127 1 -59 127 1 -127 127 5 -128 127 1 -129 127 1 -153 127 1 -157 127 1 -159 127 1 -163 127 1 -165 127 1 -203 127 -1 -207 127 -1 -29 128 2 -30 128 2 -31 128 2 -32 128 2 -62 128 1 -66 128 1 -75 128 1 -79 128 1 -127 128 1 -128 128 5 -129 128 1 -153 128 1 -167 128 1 -170 128 1 -176 128 1 -179 128 1 -203 128 -1 -207 128 -1 -29 129 2 -30 129 2 -31 129 2 -32 129 2 -82 129 1 -86 129 1 -95 129 1 -99 129 1 -127 129 1 -128 129 1 -129 129 5 -153 129 1 -182 129 1 -186 129 1 -194 129 1 -198 129 1 -203 129 -1 -207 129 -1 -33 130 2 -34 130 2 -35 130 2 -36 130 2 -43 130 1 -47 130 1 -51 130 1 -60 130 1 -130 130 5 -131 130 1 -132 130 1 -154 130 1 -157 130 1 -159 130 1 -161 130 1 -165 130 1 -204 130 -1 -207 130 -1 -33 131 2 -34 131 2 -35 131 2 -36 131 2 -63 131 1 -67 131 1 -71 131 1 -80 131 1 -130 131 1 -131 131 5 -132 131 1 -154 131 1 -167 131 1 -170 131 1 -173 131 1 -179 131 1 -204 131 -1 -207 131 -1 -33 132 2 -34 132 2 -35 132 2 -36 132 2 -83 132 1 -87 132 1 -91 132 1 -100 132 1 -130 132 1 -131 132 1 -132 132 5 -154 132 1 -182 132 1 -186 132 1 -190 132 1 -198 132 1 -204 132 -1 -207 132 -1 -37 133 2 -38 133 2 -39 133 2 -40 133 2 -44 133 1 -48 133 1 -52 133 1 -56 133 1 -133 133 5 -134 133 1 -135 133 1 -155 133 1 -157 133 1 -159 133 1 -161 133 1 -163 133 1 -205 133 -1 -207 133 -1 -37 134 2 -38 134 2 -39 134 2 -40 134 2 -64 134 1 -68 134 1 -72 134 1 -76 134 1 -133 134 1 -134 134 5 -135 134 1 -155 134 1 -167 134 1 -170 134 1 -173 134 1 -176 134 1 -205 134 -1 -207 134 -1 -37 135 2 -38 135 2 -39 135 2 -40 135 2 -84 135 1 -88 135 1 -92 135 1 -96 135 1 -133 135 1 -134 135 1 -135 135 5 -155 135 1 -182 135 1 -186 135 1 -190 135 1 -194 135 1 -205 135 -1 -207 135 -1 -41 136 2 -42 136 2 -43 136 2 -44 136 2 -65 136 1 -69 136 1 -73 136 1 -77 136 1 -136 136 5 -137 136 1 -156 136 1 -157 136 1 -171 136 1 -174 136 1 -177 136 1 -180 136 1 -201 136 -1 -208 136 -1 -41 137 2 -42 137 2 -43 137 2 -44 137 2 -85 137 1 -89 137 1 -93 137 1 -97 137 1 -136 137 1 -137 137 5 -156 137 1 -157 137 1 -187 137 1 -191 137 1 -195 137 1 -199 137 1 -201 137 -1 -208 137 -1 -45 138 2 -46 138 2 -47 138 2 -48 138 2 -61 138 1 -70 138 1 -74 138 1 -78 138 1 -138 138 5 -139 138 1 -158 138 1 -159 138 1 -168 138 1 -174 138 1 -177 138 1 -180 138 1 -202 138 -1 -208 138 -1 -45 139 2 -46 139 2 -47 139 2 -48 139 2 -81 139 1 -90 139 1 -94 139 1 -98 139 1 -138 139 1 -139 139 5 -158 139 1 -159 139 1 -183 139 1 -191 139 1 -195 139 1 -199 139 1 -202 139 -1 -208 139 -1 -49 140 2 -50 140 2 -51 140 2 -52 140 2 -62 140 1 -66 140 1 -75 140 1 -79 140 1 -140 140 5 -141 140 1 -160 140 1 -161 140 1 -168 140 1 -171 140 1 -177 140 1 -180 140 1 -203 140 -1 -208 140 -1 -49 141 2 -50 141 2 -51 141 2 -52 141 2 -82 141 1 -86 141 1 -95 141 1 -99 141 1 -140 141 1 -141 141 5 -160 141 1 -161 141 1 -183 141 1 -187 141 1 -195 141 1 -199 141 1 -203 141 -1 -208 141 -1 -53 142 2 -54 142 2 -55 142 2 -56 142 2 -63 142 1 -67 142 1 -71 142 1 -80 142 1 -142 142 5 -143 142 1 -162 142 1 -163 142 1 -168 142 1 -171 142 1 -174 142 1 -180 142 1 -204 142 -1 -208 142 -1 -53 143 2 -54 143 2 -55 143 2 -56 143 2 -83 143 1 -87 143 1 -91 143 1 -100 143 1 -142 143 1 -143 143 5 -162 143 1 -163 143 1 -183 143 1 -187 143 1 -191 143 1 -199 143 1 -204 143 -1 -208 143 -1 -57 144 2 -58 144 2 -59 144 2 -60 144 2 -64 144 1 -68 144 1 -72 144 1 -76 144 1 -144 144 5 -145 144 1 -164 144 1 -165 144 1 -168 144 1 -171 144 1 -174 144 1 -177 144 1 -205 144 -1 -208 144 -1 -57 145 2 -58 145 2 -59 145 2 -60 145 2 -84 145 1 -88 145 1 -92 145 1 -96 145 1 -144 145 1 -145 145 5 -164 145 1 -165 145 1 -183 145 1 -187 145 1 -191 145 1 -195 145 1 -205 145 -1 -208 145 -1 -61 146 2 -62 146 2 -63 146 2 -64 146 2 -85 146 1 -89 146 1 -93 146 1 -97 146 1 -146 146 5 -166 146 1 -167 146 1 -168 146 1 -188 146 1 -192 146 1 -196 146 1 -200 146 1 -201 146 -1 -209 146 -1 -65 147 2 -66 147 2 -67 147 2 -68 147 2 -81 147 1 -90 147 1 -94 147 1 -98 147 1 -147 147 5 -169 147 1 -170 147 1 -171 147 1 -184 147 1 -192 147 1 -196 147 1 -200 147 1 -202 147 -1 -209 147 -1 -69 148 2 -70 148 2 -71 148 2 -72 148 2 -82 148 1 -86 148 1 -95 148 1 -99 148 1 -148 148 5 -172 148 1 -173 148 1 -174 148 1 -184 148 1 -188 148 1 -196 148 1 -200 148 1 -203 148 -1 -209 148 -1 -73 149 2 -74 149 2 -75 149 2 -76 149 2 -83 149 1 -87 149 1 -91 149 1 -100 149 1 -149 149 5 -175 149 1 -176 149 1 -177 149 1 -184 149 1 -188 149 1 -192 149 1 -200 149 1 -204 149 -1 -209 149 -1 -77 150 2 -78 150 2 -79 150 2 -80 150 2 -84 150 1 -88 150 1 -92 150 1 -96 150 1 -150 150 5 -178 150 1 -179 150 1 -180 150 1 -184 150 1 -188 150 1 -192 150 1 -196 150 1 -205 150 -1 -209 150 -1 -5 151 1 -9 151 1 -13 151 1 -17 151 1 -21 151 2 -22 151 2 -23 151 2 -24 151 2 -105 151 1 -109 151 1 -113 151 1 -117 151 1 -121 151 1 -122 151 1 -123 151 1 -151 151 5 -201 151 -1 -207 151 -1 -1 152 1 -10 152 1 -14 152 1 -18 152 1 -25 152 2 -26 152 2 -27 152 2 -28 152 2 -101 152 1 -109 152 1 -113 152 1 -117 152 1 -124 152 1 -125 152 1 -126 152 1 -152 152 5 -202 152 -1 -207 152 -1 -2 153 1 -6 153 1 -15 153 1 -19 153 1 -29 153 2 -30 153 2 -31 153 2 -32 153 2 -101 153 1 -105 153 1 -113 153 1 -117 153 1 -127 153 1 -128 153 1 -129 153 1 -153 153 5 -203 153 -1 -207 153 -1 -3 154 1 -7 154 1 -11 154 1 -20 154 1 -33 154 2 -34 154 2 -35 154 2 -36 154 2 -101 154 1 -105 154 1 -109 154 1 -117 154 1 -130 154 1 -131 154 1 -132 154 1 -154 154 5 -204 154 -1 -207 154 -1 -4 155 1 -8 155 1 -12 155 1 -16 155 1 -37 155 2 -38 155 2 -39 155 2 -40 155 2 -101 155 1 -105 155 1 -109 155 1 -113 155 1 -133 155 1 -134 155 1 -135 155 1 -155 155 5 -205 155 -1 -207 155 -1 -5 156 1 -9 156 1 -13 156 1 -17 156 1 -41 156 2 -42 156 2 -43 156 2 -44 156 2 -106 156 1 -110 156 1 -114 156 1 -118 156 1 -136 156 1 -137 156 1 -156 156 5 -157 156 1 -201 156 -1 -208 156 -1 -25 157 1 -29 157 1 -33 157 1 -37 157 1 -41 157 2 -42 157 2 -43 157 2 -44 157 2 -124 157 1 -127 157 1 -130 157 1 -133 157 1 -136 157 1 -137 157 1 -156 157 1 -157 157 5 -201 157 -1 -208 157 -1 -1 158 1 -10 158 1 -14 158 1 -18 158 1 -45 158 2 -46 158 2 -47 158 2 -48 158 2 -102 158 1 -110 158 1 -114 158 1 -118 158 1 -138 158 1 -139 158 1 -158 158 5 -159 158 1 -202 158 -1 -208 158 -1 -21 159 1 -30 159 1 -34 159 1 -38 159 1 -45 159 2 -46 159 2 -47 159 2 -48 159 2 -121 159 1 -127 159 1 -130 159 1 -133 159 1 -138 159 1 -139 159 1 -158 159 1 -159 159 5 -202 159 -1 -208 159 -1 -2 160 1 -6 160 1 -15 160 1 -19 160 1 -49 160 2 -50 160 2 -51 160 2 -52 160 2 -102 160 1 -106 160 1 -114 160 1 -118 160 1 -140 160 1 -141 160 1 -160 160 5 -161 160 1 -203 160 -1 -208 160 -1 -22 161 1 -26 161 1 -35 161 1 -39 161 1 -49 161 2 -50 161 2 -51 161 2 -52 161 2 -121 161 1 -124 161 1 -130 161 1 -133 161 1 -140 161 1 -141 161 1 -160 161 1 -161 161 5 -203 161 -1 -208 161 -1 -3 162 1 -7 162 1 -11 162 1 -20 162 1 -53 162 2 -54 162 2 -55 162 2 -56 162 2 -102 162 1 -106 162 1 -110 162 1 -118 162 1 -142 162 1 -143 162 1 -162 162 5 -163 162 1 -204 162 -1 -208 162 -1 -23 163 1 -27 163 1 -31 163 1 -40 163 1 -53 163 2 -54 163 2 -55 163 2 -56 163 2 -121 163 1 -124 163 1 -127 163 1 -133 163 1 -142 163 1 -143 163 1 -162 163 1 -163 163 5 -204 163 -1 -208 163 -1 -4 164 1 -8 164 1 -12 164 1 -16 164 1 -57 164 2 -58 164 2 -59 164 2 -60 164 2 -102 164 1 -106 164 1 -110 164 1 -114 164 1 -144 164 1 -145 164 1 -164 164 5 -165 164 1 -205 164 -1 -208 164 -1 -24 165 1 -28 165 1 -32 165 1 -36 165 1 -57 165 2 -58 165 2 -59 165 2 -60 165 2 -121 165 1 -124 165 1 -127 165 1 -130 165 1 -144 165 1 -145 165 1 -164 165 1 -165 165 5 -205 165 -1 -208 165 -1 -5 166 1 -9 166 1 -13 166 1 -17 166 1 -61 166 2 -62 166 2 -63 166 2 -64 166 2 -107 166 1 -111 166 1 -115 166 1 -119 166 1 -146 166 1 -166 166 5 -167 166 1 -168 166 1 -201 166 -1 -209 166 -1 -25 167 1 -29 167 1 -33 167 1 -37 167 1 -61 167 2 -62 167 2 -63 167 2 -64 167 2 -125 167 1 -128 167 1 -131 167 1 -134 167 1 -146 167 1 -166 167 1 -167 167 5 -168 167 1 -201 167 -1 -209 167 -1 -45 168 1 -49 168 1 -53 168 1 -57 168 1 -61 168 2 -62 168 2 -63 168 2 -64 168 2 -138 168 1 -140 168 1 -142 168 1 -144 168 1 -146 168 1 -166 168 1 -167 168 1 -168 168 5 -201 168 -1 -209 168 -1 -1 169 1 -10 169 1 -14 169 1 -18 169 1 -65 169 2 -66 169 2 -67 169 2 -68 169 2 -103 169 1 -111 169 1 -115 169 1 -119 169 1 -147 169 1 -169 169 5 -170 169 1 -171 169 1 -202 169 -1 -209 169 -1 -21 170 1 -30 170 1 -34 170 1 -38 170 1 -65 170 2 -66 170 2 -67 170 2 -68 170 2 -122 170 1 -128 170 1 -131 170 1 -134 170 1 -147 170 1 -169 170 1 -170 170 5 -171 170 1 -202 170 -1 -209 170 -1 -41 171 1 -50 171 1 -54 171 1 -58 171 1 -65 171 2 -66 171 2 -67 171 2 -68 171 2 -136 171 1 -140 171 1 -142 171 1 -144 171 1 -147 171 1 -169 171 1 -170 171 1 -171 171 5 -202 171 -1 -209 171 -1 -2 172 1 -6 172 1 -15 172 1 -19 172 1 -69 172 2 -70 172 2 -71 172 2 -72 172 2 -103 172 1 -107 172 1 -115 172 1 -119 172 1 -148 172 1 -172 172 5 -173 172 1 -174 172 1 -203 172 -1 -209 172 -1 -22 173 1 -26 173 1 -35 173 1 -39 173 1 -69 173 2 -70 173 2 -71 173 2 -72 173 2 -122 173 1 -125 173 1 -131 173 1 -134 173 1 -148 173 1 -172 173 1 -173 173 5 -174 173 1 -203 173 -1 -209 173 -1 -42 174 1 -46 174 1 -55 174 1 -59 174 1 -69 174 2 -70 174 2 -71 174 2 -72 174 2 -136 174 1 -138 174 1 -142 174 1 -144 174 1 -148 174 1 -172 174 1 -173 174 1 -174 174 5 -203 174 -1 -209 174 -1 -3 175 1 -7 175 1 -11 175 1 -20 175 1 -73 175 2 -74 175 2 -75 175 2 -76 175 2 -103 175 1 -107 175 1 -111 175 1 -119 175 1 -149 175 1 -175 175 5 -176 175 1 -177 175 1 -204 175 -1 -209 175 -1 -23 176 1 -27 176 1 -31 176 1 -40 176 1 -73 176 2 -74 176 2 -75 176 2 -76 176 2 -122 176 1 -125 176 1 -128 176 1 -134 176 1 -149 176 1 -175 176 1 -176 176 5 -177 176 1 -204 176 -1 -209 176 -1 -43 177 1 -47 177 1 -51 177 1 -60 177 1 -73 177 2 -74 177 2 -75 177 2 -76 177 2 -136 177 1 -138 177 1 -140 177 1 -144 177 1 -149 177 1 -175 177 1 -176 177 1 -177 177 5 -204 177 -1 -209 177 -1 -4 178 1 -8 178 1 -12 178 1 -16 178 1 -77 178 2 -78 178 2 -79 178 2 -80 178 2 -103 178 1 -107 178 1 -111 178 1 -115 178 1 -150 178 1 -178 178 5 -179 178 1 -180 178 1 -205 178 -1 -209 178 -1 -24 179 1 -28 179 1 -32 179 1 -36 179 1 -77 179 2 -78 179 2 -79 179 2 -80 179 2 -122 179 1 -125 179 1 -128 179 1 -131 179 1 -150 179 1 -178 179 1 -179 179 5 -180 179 1 -205 179 -1 -209 179 -1 -44 180 1 -48 180 1 -52 180 1 -56 180 1 -77 180 2 -78 180 2 -79 180 2 -80 180 2 -136 180 1 -138 180 1 -140 180 1 -142 180 1 -150 180 1 -178 180 1 -179 180 1 -180 180 5 -205 180 -1 -209 180 -1 -5 181 1 -9 181 1 -13 181 1 -17 181 1 -81 181 2 -82 181 2 -83 181 2 -84 181 2 -108 181 1 -112 181 1 -116 181 1 -120 181 1 -181 181 5 -182 181 1 -183 181 1 -184 181 1 -201 181 -1 -210 181 -1 -25 182 1 -29 182 1 -33 182 1 -37 182 1 -81 182 2 -82 182 2 -83 182 2 -84 182 2 -126 182 1 -129 182 1 -132 182 1 -135 182 1 -181 182 1 -182 182 5 -183 182 1 -184 182 1 -201 182 -1 -210 182 -1 -45 183 1 -49 183 1 -53 183 1 -57 183 1 -81 183 2 -82 183 2 -83 183 2 -84 183 2 -139 183 1 -141 183 1 -143 183 1 -145 183 1 -181 183 1 -182 183 1 -183 183 5 -184 183 1 -201 183 -1 -210 183 -1 -65 184 1 -69 184 1 -73 184 1 -77 184 1 -81 184 2 -82 184 2 -83 184 2 -84 184 2 -147 184 1 -148 184 1 -149 184 1 -150 184 1 -181 184 1 -182 184 1 -183 184 1 -184 184 5 -201 184 -1 -210 184 -1 -1 185 1 -10 185 1 -14 185 1 -18 185 1 -85 185 2 -86 185 2 -87 185 2 -88 185 2 -104 185 1 -112 185 1 -116 185 1 -120 185 1 -185 185 5 -186 185 1 -187 185 1 -188 185 1 -202 185 -1 -210 185 -1 -21 186 1 -30 186 1 -34 186 1 -38 186 1 -85 186 2 -86 186 2 -87 186 2 -88 186 2 -123 186 1 -129 186 1 -132 186 1 -135 186 1 -185 186 1 -186 186 5 -187 186 1 -188 186 1 -202 186 -1 -210 186 -1 -41 187 1 -50 187 1 -54 187 1 -58 187 1 -85 187 2 -86 187 2 -87 187 2 -88 187 2 -137 187 1 -141 187 1 -143 187 1 -145 187 1 -185 187 1 -186 187 1 -187 187 5 -188 187 1 -202 187 -1 -210 187 -1 -61 188 1 -70 188 1 -74 188 1 -78 188 1 -85 188 2 -86 188 2 -87 188 2 -88 188 2 -146 188 1 -148 188 1 -149 188 1 -150 188 1 -185 188 1 -186 188 1 -187 188 1 -188 188 5 -202 188 -1 -210 188 -1 -2 189 1 -6 189 1 -15 189 1 -19 189 1 -89 189 2 -90 189 2 -91 189 2 -92 189 2 -104 189 1 -108 189 1 -116 189 1 -120 189 1 -189 189 5 -190 189 1 -191 189 1 -192 189 1 -203 189 -1 -210 189 -1 -22 190 1 -26 190 1 -35 190 1 -39 190 1 -89 190 2 -90 190 2 -91 190 2 -92 190 2 -123 190 1 -126 190 1 -132 190 1 -135 190 1 -189 190 1 -190 190 5 -191 190 1 -192 190 1 -203 190 -1 -210 190 -1 -42 191 1 -46 191 1 -55 191 1 -59 191 1 -89 191 2 -90 191 2 -91 191 2 -92 191 2 -137 191 1 -139 191 1 -143 191 1 -145 191 1 -189 191 1 -190 191 1 -191 191 5 -192 191 1 -203 191 -1 -210 191 -1 -62 192 1 -66 192 1 -75 192 1 -79 192 1 -89 192 2 -90 192 2 -91 192 2 -92 192 2 -146 192 1 -147 192 1 -149 192 1 -150 192 1 -189 192 1 -190 192 1 -191 192 1 -192 192 5 -203 192 -1 -210 192 -1 -3 193 1 -7 193 1 -11 193 1 -20 193 1 -93 193 2 -94 193 2 -95 193 2 -96 193 2 -104 193 1 -108 193 1 -112 193 1 -120 193 1 -193 193 5 -194 193 1 -195 193 1 -196 193 1 -204 193 -1 -210 193 -1 -23 194 1 -27 194 1 -31 194 1 -40 194 1 -93 194 2 -94 194 2 -95 194 2 -96 194 2 -123 194 1 -126 194 1 -129 194 1 -135 194 1 -193 194 1 -194 194 5 -195 194 1 -196 194 1 -204 194 -1 -210 194 -1 -43 195 1 -47 195 1 -51 195 1 -60 195 1 -93 195 2 -94 195 2 -95 195 2 -96 195 2 -137 195 1 -139 195 1 -141 195 1 -145 195 1 -193 195 1 -194 195 1 -195 195 5 -196 195 1 -204 195 -1 -210 195 -1 -63 196 1 -67 196 1 -71 196 1 -80 196 1 -93 196 2 -94 196 2 -95 196 2 -96 196 2 -146 196 1 -147 196 1 -148 196 1 -150 196 1 -193 196 1 -194 196 1 -195 196 1 -196 196 5 -204 196 -1 -210 196 -1 -4 197 1 -8 197 1 -12 197 1 -16 197 1 -97 197 2 -98 197 2 -99 197 2 -100 197 2 -104 197 1 -108 197 1 -112 197 1 -116 197 1 -197 197 5 -198 197 1 -199 197 1 -200 197 1 -205 197 -1 -210 197 -1 -24 198 1 -28 198 1 -32 198 1 -36 198 1 -97 198 2 -98 198 2 -99 198 2 -100 198 2 -123 198 1 -126 198 1 -129 198 1 -132 198 1 -197 198 1 -198 198 5 -199 198 1 -200 198 1 -205 198 -1 -210 198 -1 -44 199 1 -48 199 1 -52 199 1 -56 199 1 -97 199 2 -98 199 2 -99 199 2 -100 199 2 -137 199 1 -139 199 1 -141 199 1 -143 199 1 -197 199 1 -198 199 1 -199 199 5 -200 199 1 -205 199 -1 -210 199 -1 -64 200 1 -68 200 1 -72 200 1 -76 200 1 -97 200 2 -98 200 2 -99 200 2 -100 200 2 -146 200 1 -147 200 1 -148 200 1 -149 200 1 -197 200 1 -198 200 1 -199 200 1 -200 200 5 -205 200 -1 -210 200 -1 -1 201 -1 -2 201 -1 -3 201 -1 -4 201 -1 -21 201 -1 -22 201 -1 -23 201 -1 -24 201 -1 -41 201 -1 -42 201 -1 -43 201 -1 -44 201 -1 -61 201 -1 -62 201 -1 -63 201 -1 -64 201 -1 -81 201 -1 -82 201 -1 -83 201 -1 -84 201 -1 -101 201 -1 -102 201 -1 -103 201 -1 -104 201 -1 -121 201 -1 -122 201 -1 -123 201 -1 -136 201 -1 -137 201 -1 -146 201 -1 -151 201 -1 -156 201 -1 -157 201 -1 -166 201 -1 -167 201 -1 -168 201 -1 -181 201 -1 -182 201 -1 -183 201 -1 -184 201 -1 -201 201 5 -206 201 1 -207 201 1 -208 201 1 -209 201 1 -210 201 1 -5 202 -1 -6 202 -1 -7 202 -1 -8 202 -1 -25 202 -1 -26 202 -1 -27 202 -1 -28 202 -1 -45 202 -1 -46 202 -1 -47 202 -1 -48 202 -1 -65 202 -1 -66 202 -1 -67 202 -1 -68 202 -1 -85 202 -1 -86 202 -1 -87 202 -1 -88 202 -1 -105 202 -1 -106 202 -1 -107 202 -1 -108 202 -1 -124 202 -1 -125 202 -1 -126 202 -1 -138 202 -1 -139 202 -1 -147 202 -1 -152 202 -1 -158 202 -1 -159 202 -1 -169 202 -1 -170 202 -1 -171 202 -1 -185 202 -1 -186 202 -1 -187 202 -1 -188 202 -1 -202 202 5 -206 202 1 -207 202 1 -208 202 1 -209 202 1 -210 202 1 -9 203 -1 -10 203 -1 -11 203 -1 -12 203 -1 -29 203 -1 -30 203 -1 -31 203 -1 -32 203 -1 -49 203 -1 -50 203 -1 -51 203 -1 -52 203 -1 -69 203 -1 -70 203 -1 -71 203 -1 -72 203 -1 -89 203 -1 -90 203 -1 -91 203 -1 -92 203 -1 -109 203 -1 -110 203 -1 -111 203 -1 -112 203 -1 -127 203 -1 -128 203 -1 -129 203 -1 -140 203 -1 -141 203 -1 -148 203 -1 -153 203 -1 -160 203 -1 -161 203 -1 -172 203 -1 -173 203 -1 -174 203 -1 -189 203 -1 -190 203 -1 -191 203 -1 -192 203 -1 -203 203 5 -206 203 1 -207 203 1 -208 203 1 -209 203 1 -210 203 1 -13 204 -1 -14 204 -1 -15 204 -1 -16 204 -1 -33 204 -1 -34 204 -1 -35 204 -1 -36 204 -1 -53 204 -1 -54 204 -1 -55 204 -1 -56 204 -1 -73 204 -1 -74 204 -1 -75 204 -1 -76 204 -1 -93 204 -1 -94 204 -1 -95 204 -1 -96 204 -1 -113 204 -1 -114 204 -1 -115 204 -1 -116 204 -1 -130 204 -1 -131 204 -1 -132 204 -1 -142 204 -1 -143 204 -1 -149 204 -1 -154 204 -1 -162 204 -1 -163 204 -1 -175 204 -1 -176 204 -1 -177 204 -1 -193 204 -1 -194 204 -1 -195 204 -1 -196 204 -1 -204 204 5 -206 204 1 -207 204 1 -208 204 1 -209 204 1 -210 204 1 -17 205 -1 -18 205 -1 -19 205 -1 -20 205 -1 -37 205 -1 -38 205 -1 -39 205 -1 -40 205 -1 -57 205 -1 -58 205 -1 -59 205 -1 -60 205 -1 -77 205 -1 -78 205 -1 -79 205 -1 -80 205 -1 -97 205 -1 -98 205 -1 -99 205 -1 -100 205 -1 -117 205 -1 -118 205 -1 -119 205 -1 -120 205 -1 -133 205 -1 -134 205 -1 -135 205 -1 -144 205 -1 -145 205 -1 -150 205 -1 -155 205 -1 -164 205 -1 -165 205 -1 -178 205 -1 -179 205 -1 -180 205 -1 -197 205 -1 -198 205 -1 -199 205 -1 -200 205 -1 -205 205 5 -206 205 1 -207 205 1 -208 205 1 -209 205 1 -210 205 1 -1 206 -1 -2 206 -1 -3 206 -1 -4 206 -1 -5 206 -1 -6 206 -1 -7 206 -1 -8 206 -1 -9 206 -1 -10 206 -1 -11 206 -1 -12 206 -1 -13 206 -1 -14 206 -1 -15 206 -1 -16 206 -1 -17 206 -1 -18 206 -1 -19 206 -1 -20 206 -1 -101 206 -1 -102 206 -1 -103 206 -1 -104 206 -1 -105 206 -1 -106 206 -1 -107 206 -1 -108 206 -1 -109 206 -1 -110 206 -1 -111 206 -1 -112 206 -1 -113 206 -1 -114 206 -1 -115 206 -1 -116 206 -1 -117 206 -1 -118 206 -1 -119 206 -1 -120 206 -1 -201 206 1 -202 206 1 -203 206 1 -204 206 1 -205 206 1 -206 206 5 -21 207 -1 -22 207 -1 -23 207 -1 -24 207 -1 -25 207 -1 -26 207 -1 -27 207 -1 -28 207 -1 -29 207 -1 -30 207 -1 -31 207 -1 -32 207 -1 -33 207 -1 -34 207 -1 -35 207 -1 -36 207 -1 -37 207 -1 -38 207 -1 -39 207 -1 -40 207 -1 -121 207 -1 -122 207 -1 -123 207 -1 -124 207 -1 -125 207 -1 -126 207 -1 -127 207 -1 -128 207 -1 -129 207 -1 -130 207 -1 -131 207 -1 -132 207 -1 -133 207 -1 -134 207 -1 -135 207 -1 -151 207 -1 -152 207 -1 -153 207 -1 -154 207 -1 -155 207 -1 -201 207 1 -202 207 1 -203 207 1 -204 207 1 -205 207 1 -207 207 5 -41 208 -1 -42 208 -1 -43 208 -1 -44 208 -1 -45 208 -1 -46 208 -1 -47 208 -1 -48 208 -1 -49 208 -1 -50 208 -1 -51 208 -1 -52 208 -1 -53 208 -1 -54 208 -1 -55 208 -1 -56 208 -1 -57 208 -1 -58 208 -1 -59 208 -1 -60 208 -1 -136 208 -1 -137 208 -1 -138 208 -1 -139 208 -1 -140 208 -1 -141 208 -1 -142 208 -1 -143 208 -1 -144 208 -1 -145 208 -1 -156 208 -1 -157 208 -1 -158 208 -1 -159 208 -1 -160 208 -1 -161 208 -1 -162 208 -1 -163 208 -1 -164 208 -1 -165 208 -1 -201 208 1 -202 208 1 -203 208 1 -204 208 1 -205 208 1 -208 208 5 -61 209 -1 -62 209 -1 -63 209 -1 -64 209 -1 -65 209 -1 -66 209 -1 -67 209 -1 -68 209 -1 -69 209 -1 -70 209 -1 -71 209 -1 -72 209 -1 -73 209 -1 -74 209 -1 -75 209 -1 -76 209 -1 -77 209 -1 -78 209 -1 -79 209 -1 -80 209 -1 -146 209 -1 -147 209 -1 -148 209 -1 -149 209 -1 -150 209 -1 -166 209 -1 -167 209 -1 -168 209 -1 -169 209 -1 -170 209 -1 -171 209 -1 -172 209 -1 -173 209 -1 -174 209 -1 -175 209 -1 -176 209 -1 -177 209 -1 -178 209 -1 -179 209 -1 -180 209 -1 -201 209 1 -202 209 1 -203 209 1 -204 209 1 -205 209 1 -209 209 5 -81 210 -1 -82 210 -1 -83 210 -1 -84 210 -1 -85 210 -1 -86 210 -1 -87 210 -1 -88 210 -1 -89 210 -1 -90 210 -1 -91 210 -1 -92 210 -1 -93 210 -1 -94 210 -1 -95 210 -1 -96 210 -1 -97 210 -1 -98 210 -1 -99 210 -1 -100 210 -1 -181 210 -1 -182 210 -1 -183 210 -1 -184 210 -1 -185 210 -1 -186 210 -1 -187 210 -1 -188 210 -1 -189 210 -1 -190 210 -1 -191 210 -1 -192 210 -1 -193 210 -1 -194 210 -1 -195 210 -1 -196 210 -1 -197 210 -1 -198 210 -1 -199 210 -1 -200 210 -1 -201 210 1 -202 210 1 -203 210 1 -204 210 1 -205 210 1 -210 210 5 diff --git a/CHOLMOD/Demo/README.txt b/CHOLMOD/Demo/README.txt index 1a1f453044..8c495c0de1 100644 --- a/CHOLMOD/Demo/README.txt +++ b/CHOLMOD/Demo/README.txt @@ -1,10 +1,15 @@ Demos for CHOLMOD - cholmod_demo.c a long demo - cholmod_l_demo.c same as cholmod_demo, but with long integers + cholmod_di_demo.c double/int32 demo + cholmod_dl_demo.c double/int64 demo + cholmod_si_demo.c float/int32 demo + cholmod_sl_demo.c float/int64 demo + cholmod_demo.h include file for cholmod*demo.c - cholmod_simple.c a very short and simple demo + cholmod_simple.c a very short and simple demo (double precision) + cholmod_s_simple.c single precision version of cholmod_simple.c + gpu.sh simple test for the GPU lperf.m test the performance of CHOLMOD in MATLAB @@ -16,13 +21,15 @@ Demos for CHOLMOD README.txt this file - Matrix folder + Matrix folder with test matrices + +To compile and run the demos on the CPU, do "make demos" in the parent +directory (SuiteSparse/CHOLMOD). -To compile and run the demos on the CPU, do "make" in this directory. To run the demos on the GPU, you must first download the ND/ND6k matrix from the SuiteSparse Matrix Collection, hosted at https://sparse.tamu.edu Unpack the nd6k.mtx to your home directory. -Then do "make big" in this directory. If you want to put the nd6k.mtx +Then do "./gpu.sh" in this directory. If you want to put the nd6k.mtx file somewhere else, then simply edit the gpu.sh file. diff --git a/CHOLMOD/Demo/cholmod_demo.c b/CHOLMOD/Demo/cholmod_demo.c deleted file mode 100644 index ad5dc8c649..0000000000 --- a/CHOLMOD/Demo/cholmod_demo.c +++ /dev/null @@ -1,652 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Demo/cholmod_demo: demo program for CHOLMOD -//------------------------------------------------------------------------------ - -// CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis, -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is - * symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple - * triplet format, compatible with most files in the Matrix Market format. - * See cholmod_read.c for more details. The readhb.f program reads a - * Harwell/Boeing matrix (excluding element-types) and converts it into the - * form needed by this program. reade.f reads a matrix in Harwell/Boeing - * finite-element form. - * - * Usage: - * cholmod_demo matrixfile - * cholmod_demo < matrixfile - * - * The matrix is assumed to be positive definite (a supernodal LL' or simplicial - * LDL' factorization is used). - * - * Requires the Utility, Cholesky, MatrixOps, and Check Modules. - * Optionally uses the Partition and Supernodal Modules. - * Does not use the Modify Module. - * - * See cholmod_simple.c for a simpler demo program. - * - * cholmod_demo is the same as cholmod_l_demo, except for the size of the - * basic integer (int vs int64_t) - */ - -#include "cholmod_demo.h" -#define NTRIALS 100 - -/* ff is a global variable so that it can be closed by my_handler */ -FILE *ff ; - -/* halt if an error occurs */ -static void my_handler (int status, const char *file, int line, - const char *message) -{ - printf ("cholmod error: file: %s line: %d status: %d: %s\n", - file, line, status, message) ; - if (status < 0) - { - if (ff != NULL) fclose (ff) ; - exit (0) ; - } -} - -int main (int argc, char **argv) -{ - double resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, - anz, axbnorm, rnorm2, resid2, rcond ; - FILE *f ; - cholmod_sparse *A ; - cholmod_dense *X = NULL, *B, *W, *R = NULL ; - double one [2], zero [2], minusone [2], beta [2], xlnz ; - cholmod_common Common, *cm ; - cholmod_factor *L ; - double *Bx, *Rx, *Xx ; - int i, n, isize, xsize, ordering, xtype, s, ss, lnz ; - int trial, method, L_is_super ; - int ver [3] ; - - ts[0] = 0.; - ts[1] = 0.; - ts[2] = 0.; - - /* ---------------------------------------------------------------------- */ - /* get the file containing the input matrix */ - /* ---------------------------------------------------------------------- */ - - ff = NULL ; - if (argc > 1) - { - if ((f = fopen (argv [1], "r")) == NULL) - { - my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, - "unable to open file") ; - } - ff = f ; - } - else - { - f = stdin ; - } - - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ - - cm = &Common ; - cholmod_start (cm) ; - - /* use default parameter settings, except for the error handler. This - * demo program terminates if an error occurs (out of memory, not positive - * definite, ...). It makes the demo program simpler (no need to check - * CHOLMOD error conditions). This non-default parameter setting has no - * effect on performance. */ - cm->error_handler = my_handler ; - - /* Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by - * default, automatically selecting the latter if flop/nnz(L) < 40. */ - - /* ---------------------------------------------------------------------- */ - /* create basic scalars */ - /* ---------------------------------------------------------------------- */ - - zero [0] = 0 ; - zero [1] = 0 ; - one [0] = 1 ; - one [1] = 0 ; - minusone [0] = -1 ; - minusone [1] = 0 ; - beta [0] = 1e-6 ; - beta [1] = 0 ; - - /* ---------------------------------------------------------------------- */ - /* read in a matrix */ - /* ---------------------------------------------------------------------- */ - - printf ("\n---------------------------------- cholmod_demo:\n") ; - cholmod_version (ver) ; - printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; - SuiteSparse_version (ver) ; - printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; - A = cholmod_read_sparse (f, cm) ; - if (ff != NULL) - { - fclose (ff) ; - ff = NULL ; - } - xtype = A->xtype ; - anorm = 1 ; -#ifndef NMATRIXOPS - anorm = cholmod_norm_sparse (A, 0, cm) ; - printf ("norm (A,inf) = %g\n", anorm) ; - printf ("norm (A,1) = %g\n", cholmod_norm_sparse (A, 1, cm)) ; -#endif - cholmod_print_sparse (A, "A", cm) ; - - if (A->nrow > A->ncol) - { - /* Transpose A so that A'A+beta*I will be factorized instead */ - cholmod_sparse *C = cholmod_transpose (A, 2, cm) ; - cholmod_free_sparse (&A, cm) ; - A = C ; - printf ("transposing input matrix\n") ; - } - - /* ---------------------------------------------------------------------- */ - /* create an arbitrary right-hand-side */ - /* ---------------------------------------------------------------------- */ - - n = A->nrow ; - B = cholmod_zeros (n, 1, xtype, cm) ; - Bx = B->x ; - -#if GHS - { - /* b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments */ - cholmod_dense *X0 ; - X0 = cholmod_ones (A->ncol, 1, xtype, cm) ; - cholmod_sdmult (A, 0, one, zero, X0, B, cm) ; - cholmod_free_dense (&X0, cm) ; - } -#else - if (xtype == CHOLMOD_REAL) - { - /* real case */ - for (i = 0 ; i < n ; i++) - { - double x = n ; - Bx [i] = 1 + i / x ; - } - } - else - { - /* complex case */ - for (i = 0 ; i < n ; i++) - { - double x = n ; - Bx [2*i ] = 1 + i / x ; /* real part of B(i) */ - Bx [2*i+1] = (x/2 - i) / (3*x) ; /* imag part of B(i) */ - } - } -#endif - - cholmod_print_dense (B, "B", cm) ; - bnorm = 1 ; -#ifndef NMATRIXOPS - bnorm = cholmod_norm_dense (B, 0, cm) ; /* max norm */ - printf ("bnorm %g\n", bnorm) ; -#endif - - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ - - t = CPUTIME ; - L = cholmod_analyze (A, cm) ; - ta = CPUTIME - t ; - ta = MAX (ta, 0) ; - - printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; - - if (A->stype == 0) - { - printf ("Factorizing A*A'+beta*I\n") ; - t = CPUTIME ; - cholmod_factorize_p (A, beta, NULL, 0, L, cm) ; - tf = CPUTIME - t ; - tf = MAX (tf, 0) ; - } - else - { - printf ("Factorizing A\n") ; - t = CPUTIME ; - cholmod_factorize (A, L, cm) ; - tf = CPUTIME - t ; - tf = MAX (tf, 0) ; - } - - cholmod_print_factor (L, "L", cm) ; - - /* determine the # of integers's and reals's in L. See cholmod_free */ - if (L->is_super) - { - s = L->nsuper + 1 ; - xsize = L->xsize ; - ss = L->ssize ; - isize = - n /* L->Perm */ - + n /* L->ColCount, nz in each column of 'pure' L */ - + s /* L->pi, column pointers for L->s */ - + s /* L->px, column pointers for L->x */ - + s /* L->super, starting column index of each supernode */ - + ss ; /* L->s, the pattern of the supernodes */ - } - else - { - /* this space can increase if you change parameters to their non- - * default values (cm->final_pack, for example). */ - lnz = L->nzmax ; - xsize = lnz ; - isize = - n /* L->Perm */ - + n /* L->ColCount, nz in each column of 'pure' L */ - + n+1 /* L->p, column pointers */ - + lnz /* L->i, integer row indices */ - + n /* L->nz, nz in each column of L */ - + n+2 /* L->next, link list */ - + n+2 ; /* L->prev, link list */ - } - - /* solve with Bset will change L from simplicial to supernodal */ - rcond = cholmod_rcond (L, cm) ; - L_is_super = L->is_super ; - - /* ---------------------------------------------------------------------- */ - /* solve */ - /* ---------------------------------------------------------------------- */ - - for (method = 0 ; method <= 3 ; method++) - { - double x = n ; - resid [method] = -1 ; /* not yet computed */ - - if (method == 0) - { - /* basic solve, just once */ - t = CPUTIME ; - X = cholmod_solve (CHOLMOD_A, L, B, cm) ; - ts [0] = CPUTIME - t ; - ts [0] = MAX (ts [0], 0) ; - } - else if (method == 1) - { - /* basic solve, many times, but keep the last one */ - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - cholmod_free_dense (&X, cm) ; - Bx [0] = 1 + trial / x ; /* tweak B each iteration */ - X = cholmod_solve (CHOLMOD_A, L, B, cm) ; - } - ts [1] = CPUTIME - t ; - ts [1] = MAX (ts [1], 0) / NTRIALS ; - } - else if (method == 2) - { - /* solve with reused workspace */ - cholmod_dense *Ywork = NULL, *Ework = NULL ; - cholmod_free_dense (&X, cm) ; - - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - Bx [0] = 1 + trial / x ; /* tweak B each iteration */ - cholmod_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - } - cholmod_free_dense (&Ywork, cm) ; - cholmod_free_dense (&Ework, cm) ; - ts [2] = CPUTIME - t ; - ts [2] = MAX (ts [2], 0) / NTRIALS ; - } - else - { - /* solve with reused workspace and sparse Bset */ - cholmod_dense *Ywork = NULL, *Ework = NULL ; - cholmod_dense *X2 = NULL, *B2 = NULL ; - cholmod_sparse *Bset, *Xset = NULL ; - int *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; - double *X1x, *X2x, *B2x, err ; - FILE *timelog = fopen ("timelog.m", "w") ; - if (timelog) fprintf (timelog, "results = [\n") ; - - B2 = cholmod_zeros (n, 1, xtype, cm) ; - B2x = B2->x ; - - Bset = cholmod_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - Bsetp = Bset->p ; - Bseti = Bset->i ; - Bsetp [0] = 0 ; /* nnz(B) is 1 (it can be anything) */ - Bsetp [1] = 1 ; - resid [3] = 0 ; - - for (i = 0 ; i < MIN (100,n) ; i++) - { - /* B (i) is nonzero, all other entries are ignored - (implied to be zero) */ - Bseti [0] = i ; - if (xtype == CHOLMOD_REAL) - { - B2x [i] = 3.1 * i + 0.9 ; - } - else - { - B2x [2*i ] = i + 0.042 ; - B2x [2*i+1] = i - 92.7 ; - } - - /* first get the entire solution, to compare against */ - cholmod_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - - /* now get the sparse solutions; this will change L from - supernodal to simplicial */ - - if (i == 0) - { - /* first solve can be slower because it has to allocate - space for X2, Xset, etc, and change L. - So don't time it */ - cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - } - - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - /* solve Ax=b but only to get x(i). - b is all zero except for b(i). - This takes O(xlen) time */ - cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - } - t = CPUTIME - t ; - t = MAX (t, 0) / NTRIALS ; - - /* check the solution and log the time */ - Xsetp = Xset->p ; - Xseti = Xset->i ; - xlen = Xsetp [1] ; - X1x = X->x ; - X2x = X2->x ; - Lnz = L->nz ; - - /* - printf ("\ni %d xlen %d (%p %p)\n", i, xlen, X1x, X2x) ; - */ - - if (xtype == CHOLMOD_REAL) - { - fl = 2 * xlen ; - for (k = 0 ; k < xlen ; k++) - { - j = Xseti [k] ; - fl += 4 * Lnz [j] ; - err = X1x [j] - X2x [j] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - } - } - else - { - fl = 16 * xlen ; - for (k = 0 ; k < xlen ; k++) - { - j = Xseti [k] ; - fl += 16 * Lnz [j] ; - err = X1x [2*j ] - X2x [2*j ] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - err = X1x [2*j+1] - X2x [2*j+1] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - } - } - if (timelog) fprintf (timelog, "%g %g %g %g\n", - (double) i, (double) xlen, fl, t); - - /* clear B for the next test */ - if (xtype == CHOLMOD_REAL) - { - B2x [i] = 0 ; - } - else - { - B2x [2*i ] = 0 ; - B2x [2*i+1] = 0 ; - } - - } - - if (timelog) - { - fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; - fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; - fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; - fclose (timelog) ; - } - -#ifndef NMATRIXOPS - resid [3] = resid [3] / cholmod_norm_dense (X, 1, cm) ; -#endif - - cholmod_free_dense (&Ywork, cm) ; - cholmod_free_dense (&Ework, cm) ; - cholmod_free_dense (&X2, cm) ; - cholmod_free_dense (&B2, cm) ; - cholmod_free_sparse (&Xset, cm) ; - cholmod_free_sparse (&Bset, cm) ; - } - - /* ------------------------------------------------------------------ */ - /* compute the residual */ - /* ------------------------------------------------------------------ */ - - if (method < 3) - { -#ifndef NMATRIXOPS - - if (A->stype == 0) - { - /* (AA'+beta*I)x=b is the linear system that was solved */ - /* W = A'*X */ - W = cholmod_allocate_dense (A->ncol, 1, A->ncol, xtype, cm) ; - cholmod_sdmult (A, 2, one, zero, X, W, cm) ; - /* R = B - beta*X */ - cholmod_free_dense (&R, cm) ; - R = cholmod_zeros (n, 1, xtype, cm) ; - Rx = R->x ; - Xx = X->x ; - if (xtype == CHOLMOD_REAL) - { - for (i = 0 ; i < n ; i++) - { - Rx [i] = Bx [i] - beta [0] * Xx [i] ; - } - } - else - { - /* complex case */ - for (i = 0 ; i < n ; i++) - { - Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; - Rx [2*i+1] = Bx [2*i+1] - beta [0] * Xx [2*i+1] ; - } - } - /* R = A*W - R */ - cholmod_sdmult (A, 0, one, minusone, W, R, cm) ; - cholmod_free_dense (&W, cm) ; - } - else - { - /* Ax=b was factorized and solved, R = B-A*X */ - cholmod_free_dense (&R, cm) ; - R = cholmod_copy_dense (B, cm) ; - cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; - } - rnorm = -1 ; - xnorm = 1 ; - rnorm = cholmod_norm_dense (R, 0, cm) ; /* max abs. entry */ - xnorm = cholmod_norm_dense (X, 0, cm) ; /* max abs. entry */ - axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; - resid [method] = rnorm / axbnorm ; -#else - printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; -#endif - } - } - - tot = ta + tf + ts [0] ; - - /* ---------------------------------------------------------------------- */ - /* iterative refinement (real symmetric case only) */ - /* ---------------------------------------------------------------------- */ - - resid2 = -1 ; -#ifndef NMATRIXOPS - if (A->stype != 0 && A->xtype == CHOLMOD_REAL) - { - cholmod_dense *R2 ; - - // x = A\b - cholmod_free_dense (&X, cm) ; - X = cholmod_solve (CHOLMOD_A, L, B, cm) ; - - // R = B-A*X - cholmod_free_dense (&R, cm) ; - R = cholmod_copy_dense (B, cm) ; - cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; - - /* R2 = A\(B-A*X) */ - R2 = cholmod_solve (CHOLMOD_A, L, R, cm) ; - - /* compute X = X + A\(B-A*X) */ - Xx = X->x ; - Rx = R2->x ; - for (i = 0 ; i < n ; i++) - { - Xx [i] = Xx [i] + Rx [i] ; - } - cholmod_free_dense (&R2, cm) ; - - /* compute the new residual, R = B-A*X */ - cholmod_free_dense (&R, cm) ; - R = cholmod_copy_dense (B, cm) ; - cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; - rnorm2 = cholmod_norm_dense (R, 0, cm) ; - resid2 = rnorm2 / axbnorm ; - } -#endif - - cholmod_free_dense (&R, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print results */ - /* ---------------------------------------------------------------------- */ - - anz = cm->anz ; - for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) - { - fl = cm->method [i].fl ; - xlnz = cm->method [i].lnz ; - cm->method [i].fl = -1 ; - cm->method [i].lnz = -1 ; - ordering = cm->method [i].ordering ; - if (fl >= 0) - { - printf ("Ordering: ") ; - if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; - if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; - if (ordering == CHOLMOD_GIVEN) printf ("user ") ; - if (ordering == CHOLMOD_AMD) printf ("AMD ") ; - if (ordering == CHOLMOD_METIS) printf ("METIS ") ; - if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; - if (xlnz > 0) - { - printf ("fl/lnz %10.1f", fl / xlnz) ; - } - if (anz > 0) - { - printf (" lnz/anz %10.1f", xlnz / anz) ; - } - printf ("\n") ; - } - } - - printf ("ints in L: %15.0f, doubles in L: %15.0f\n", - (double) isize, (double) xsize) ; - printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", - cm->fl, cm->lnz) ; - if (A->stype == 0) - { - printf ("nnz(A): %15.0f\n", cm->anz) ; - } - else - { - printf ("nnz(A*A'): %15.0f\n", cm->anz) ; - } - if (cm->lnz > 0) - { - printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; - } - if (anz > 0) - { - printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; - } - printf ("analyze cputime: %12.4f\n", ta) ; - printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, - (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; - printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], - (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; - printf ("overall cputime: %12.4f mflop: %8.1f\n", - tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; - printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], - (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; - printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], - (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; - printf ("peak memory usage: %12.0f (MB)\n", - (double) (cm->memory_usage) / 1048576.) ; - printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; - for (method = 0 ; method <= 3 ; method++) - { - printf ("%8.2e ", resid [method]) ; - } - printf ("\n") ; - if (resid2 >= 0) - { - printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" - " after iterative refinement\n", resid2) ; - } - - printf ("rcond %8.1e\n\n", rcond) ; - - if (L_is_super) - { - cholmod_gpu_stats (cm) ; - } - - cholmod_free_factor (&L, cm) ; - cholmod_free_dense (&X, cm) ; - - /* ---------------------------------------------------------------------- */ - /* free matrices and finish CHOLMOD */ - /* ---------------------------------------------------------------------- */ - - cholmod_free_sparse (&A, cm) ; - cholmod_free_dense (&B, cm) ; - cholmod_finish (cm) ; - - return (0) ; -} diff --git a/CHOLMOD/Demo/cholmod_demo.h b/CHOLMOD/Demo/cholmod_demo.h index cd0c2026a7..84c96b3f4a 100644 --- a/CHOLMOD/Demo/cholmod_demo.h +++ b/CHOLMOD/Demo/cholmod_demo.h @@ -2,7 +2,7 @@ // CHOLMOD/Demo/cholmod_demo.h: include file for CHOLMOD demos //------------------------------------------------------------------------------ -// CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Demo/cholmod_di_demo.c b/CHOLMOD/Demo/cholmod_di_demo.c new file mode 100644 index 0000000000..fbd27bf507 --- /dev/null +++ b/CHOLMOD/Demo/cholmod_di_demo.c @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_di_demo: demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is +// symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple +// triplet format, compatible with most files in the Matrix Market format. +// See cholmod_read.c for more details. The readhb.f program reads a +// Harwell/Boeing matrix (excluding element-types) and converts it into the +// form needed by this program. reade.f reads a matrix in Harwell/Boeing +// finite-element form. +// +// Usage: +// cholmod_di_demo matrixfile +// cholmod_di_demo < matrixfile +// +// The matrix is assumed to be positive definite (a supernodal LL' or simplicial +// LDL' factorization is used). +// +// Requires the Utility, Cholesky, MatrixOps, and Check Modules. +// Optionally uses the Partition and Supernodal Modules. +// Does not use the Modify Module. +// +// See cholmod_simple.c for a simpler demo program. +// +// There are 4 versions of this demo: +// +// cholmod_di_demo: double or double complex values, int32_t integers +// cholmod_dl_demo: double or double complex values, int64_t integers +// cholmod_si_demo: float or float complex values, int32_t integers +// cholmod_sl_demo: float or float complex values, int64_t integers + +#include "cholmod_demo.h" +#define NTRIALS 100 + +// ff is a global variable so that it can be closed by my_handler +FILE *ff ; + +// halt if an error occurs +static void my_handler (int status, const char *file, int line, + const char *message) +{ + printf ("cholmod error: file: %s line: %d status: %d: %s\n", + file, line, status, message) ; + if (status < 0) + { + if (ff != NULL) fclose (ff) ; + exit (1) ; + } +} + +int main (int argc, char **argv) +{ + double + resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, + anz, axbnorm, rnorm2, resid2, rcond, + one [2], zero [2], minusone [2], beta [2], xlnz, + isize, xsize, s, ss, lnz ; + + double + *Bx, *Rx, *Xx, *Bz, *Xz, *Rz, xn, *X1x, *X2x, *B2x ; + int32_t + i, n, *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; + + FILE *f ; + cholmod_sparse *A ; + cholmod_dense *X = NULL, *B, *W, *R = NULL ; + cholmod_common Common, *cm ; + cholmod_factor *L ; + int trial, method, L_is_super ; + int ver [3] ; + int prefer_zomplex, nmethods ; + + ts[0] = 0.; + ts[1] = 0.; + ts[2] = 0.; + + //-------------------------------------------------------------------------- + // get the file containing the input matrix + //-------------------------------------------------------------------------- + + ff = NULL ; + prefer_zomplex = 0 ; + if (argc > 1) + { + if ((f = fopen (argv [1], "r")) == NULL) + { + my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, + "unable to open file") ; + } + ff = f ; + prefer_zomplex = (argc > 2) ; + } + else + { + f = stdin ; + } + + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- + + cm = &Common ; + cholmod_start (cm) ; + cm->print = 4 ; + + cm->prefer_zomplex = prefer_zomplex ; + + // use default parameter settings, except for the error handler. This + // demo program terminates if an error occurs (out of memory, not positive + // definite, ...). It makes the demo program simpler (no need to check + // CHOLMOD error conditions). This non-default parameter setting has no + // effect on performance. + cm->error_handler = my_handler ; + + // Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by + // default, automatically selecting the latter if flop/nnz(L) < 40. + + //-------------------------------------------------------------------------- + // create basic scalars + //-------------------------------------------------------------------------- + + zero [0] = 0 ; + zero [1] = 0 ; + one [0] = 1 ; + one [1] = 0 ; + minusone [0] = -1 ; + minusone [1] = 0 ; + beta [0] = 1e-6 ; + beta [1] = 0 ; + + //-------------------------------------------------------------------------- + // read in a matrix + //-------------------------------------------------------------------------- + + printf ("\n---------------------------------- cholmod_di_demo:\n") ; + cholmod_version (ver) ; + printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + SuiteSparse_version (ver) ; + printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + A = cholmod_read_sparse2 (f, CHOLMOD_DOUBLE, cm) ; + if (ff != NULL) + { + fclose (ff) ; + ff = NULL ; + } + anorm = 1 ; +#ifndef NMATRIXOPS + anorm = cholmod_norm_sparse (A, 0, cm) ; + printf ("norm (A,inf) = %g\n", anorm) ; + printf ("norm (A,1) = %g\n", cholmod_norm_sparse (A, 1, cm)) ; +#endif + + if (prefer_zomplex && A->xtype == CHOLMOD_COMPLEX) + { + // Convert to zomplex, just for testing. In a zomplex matrix, + // the real and imaginary parts are in separate arrays. MATLAB + // uses zomplex matrix exclusively. + cholmod_sparse_xtype (CHOLMOD_ZOMPLEX + A->dtype, A, cm) ; + } + + int xtype = A->xtype ; // real, complex, or zomplex + int dtype = A->dtype ; // single or double + int xdtype = xtype + dtype ; + cholmod_print_sparse (A, "A", cm) ; + + if (A->nrow > A->ncol) + { + // Transpose A so that A'A+beta*I will be factorized instead + cholmod_sparse *C = cholmod_transpose (A, 2, cm) ; + cholmod_free_sparse (&A, cm) ; + A = C ; + printf ("transposing input matrix\n") ; + } + + //-------------------------------------------------------------------------- + // create an arbitrary right-hand-side + //-------------------------------------------------------------------------- + + n = A->nrow ; + xn = n ; + B = cholmod_zeros (n, 1, xdtype, cm) ; + Bx = B->x ; + Bz = B->z ; + +#if GHS + { + // b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments + cholmod_dense *X0 ; + X0 = cholmod_ones (A->ncol, 1, xdtype, cm) ; + cholmod_sdmult (A, 0, one, zero, X0, B, cm) ; + cholmod_free_dense (&X0, cm) ; + } +#else + if (xtype == CHOLMOD_REAL) + { + // real case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Bx [2*i ] = 1 + i / xn ; // real part of B(i) + Bx [2*i+1] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; // real part of B(i) + Bz [i] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } +#endif + + cholmod_print_dense (B, "B", cm) ; + bnorm = 1 ; +#ifndef NMATRIXOPS + bnorm = cholmod_norm_dense (B, 0, cm) ; // max norm + printf ("bnorm %g\n", bnorm) ; +#endif + + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- + + t = CPUTIME ; + L = cholmod_analyze (A, cm) ; + ta = CPUTIME - t ; + ta = MAX (ta, 0) ; + + printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; + + if (A->stype == 0) + { + printf ("Factorizing A*A'+beta*I\n") ; + t = CPUTIME ; + cholmod_factorize_p (A, beta, NULL, 0, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + else + { + printf ("Factorizing A\n") ; + t = CPUTIME ; + cholmod_factorize (A, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + + cholmod_print_factor (L, "L", cm) ; + + // determine the # of integers's and reals's in L. See cholmod_free + if (L->is_super) + { + s = L->nsuper + 1 ; + xsize = L->xsize ; + ss = L->ssize ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + s // L->pi, column pointers for L->s + + s // L->px, column pointers for L->x + + s // L->super, starting column index of each supernode + + ss ; // L->s, the pattern of the supernodes + } + else + { + // this space can increase if you change parameters to their non- + // default values (cm->final_pack, for example). + lnz = L->nzmax ; + xsize = lnz ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + n+1 // L->p, column pointers + + lnz // L->i, integer row indices + + n // L->nz, nz in each column of L + + n+2 // L->next, link list + + n+2 ; // L->prev, link list + } + + // solve with Bset will change L from simplicial to supernodal + rcond = cholmod_rcond (L, cm) ; + L_is_super = L->is_super ; + + //-------------------------------------------------------------------------- + // solve + //-------------------------------------------------------------------------- + + if (n >= 1000) + { + nmethods = 1 ; + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + nmethods = 2 ; + } + else + { + nmethods = 3 ; + } + printf ("nmethods: %d\n", nmethods) ; + + for (method = 0 ; method <= nmethods ; method++) + { + resid [method] = -1 ; // not yet computed + + if (method == 0) + { + // basic solve, just once + t = CPUTIME ; + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + ts [0] = CPUTIME - t ; + ts [0] = MAX (ts [0], 0) ; + } + else if (method == 1) + { + // basic solve, many times, but keep the last one + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + cholmod_free_dense (&X, cm) ; + Bx [0] = 1 + trial / xn ; // tweak B each iteration + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + } + ts [1] = CPUTIME - t ; + ts [1] = MAX (ts [1], 0) / NTRIALS ; + } + else if (method == 2) + { + // solve with reused workspace + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_free_dense (&X, cm) ; + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + Bx [0] = 1 + trial / xn ; // tweak B each iteration + cholmod_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + } + cholmod_free_dense (&Ywork, cm) ; + cholmod_free_dense (&Ework, cm) ; + ts [2] = CPUTIME - t ; + ts [2] = MAX (ts [2], 0) / NTRIALS ; + } + else + { + // solve with reused workspace and sparse Bset + if (xtype == CHOLMOD_ZOMPLEX) continue ; + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_dense *X2 = NULL, *B2 = NULL ; + cholmod_sparse *Bset, *Xset = NULL ; + + double err ; + FILE *timelog = fopen ("timelog.m", "w") ; + if (timelog) fprintf (timelog, "results = [\n") ; + + // xtype is CHOLMOD_REAL or CHOLMOD_COMPLEX, not CHOLMOD_ZOMPLEX + B2 = cholmod_zeros (n, 1, xdtype, cm) ; + B2x = B2->x ; + + Bset = cholmod_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, + CHOLMOD_PATTERN + dtype, cm) ; + Bsetp = Bset->p ; + Bseti = Bset->i ; + Bsetp [0] = 0 ; // nnz(B) is 1 (it can be anything) + Bsetp [1] = 1 ; + resid [3] = 0 ; + + for (i = 0 ; i < MIN (100,n) ; i++) + { + // B (i) is nonzero, all other entries are ignored + // (implied to be zero) + Bseti [0] = i ; + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 3.1 * i + 0.9 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = i + 0.042 ; + B2x [2*i+1] = i - 92.7 ; + } + + // first get the entire solution, to compare against + cholmod_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + + // now get the sparse solutions; this will change L from + // supernodal to simplicial + + if (i == 0) + { + // first solve can be slower because it has to allocate + // space for X2, Xset, etc, and change L. + // So don't time it + cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + // solve Ax=b but only to get x(i). + // b is all zero except for b(i). + // This takes O(xlen) time + cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + t = CPUTIME - t ; + t = MAX (t, 0) / NTRIALS ; + + // check the solution and log the time + Xsetp = Xset->p ; + Xseti = Xset->i ; + xlen = Xsetp [1] ; + X1x = X->x ; + X2x = X2->x ; + Lnz = L->nz ; + + if (xtype == CHOLMOD_REAL) + { + fl = 2 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 4 * Lnz [j] ; + err = X1x [j] - X2x [j] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + else // (xtype == CHOLMOD_COMPLEX) + { + fl = 16 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 16 * Lnz [j] ; + err = X1x [2*j ] - X2x [2*j ] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + err = X1x [2*j+1] - X2x [2*j+1] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + + if (timelog) fprintf (timelog, "%g %g %g %g\n", + (double) i, (double) xlen, fl, t); + + // clear B for the next test + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 0 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = 0 ; + B2x [2*i+1] = 0 ; + } + } + + if (timelog) + { + fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; + fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; + fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; + fclose (timelog) ; + } + +#ifndef NMATRIXOPS + double xnorm1 = cholmod_norm_dense (X, 1, cm) + ((n==0)?1:0) ; + resid [3] = resid [3] / xnorm1 ; +#endif + + cholmod_free_dense (&Ywork, cm) ; + cholmod_free_dense (&Ework, cm) ; + cholmod_free_dense (&X2, cm) ; + cholmod_free_dense (&B2, cm) ; + cholmod_free_sparse (&Xset, cm) ; + cholmod_free_sparse (&Bset, cm) ; + } + + //---------------------------------------------------------------------- + // compute the residual + //---------------------------------------------------------------------- + + if (method < 3) + { +#ifndef NMATRIXOPS + if (A->stype == 0) + { + // (AA'+beta*I)x=b is the linear system that was solved + // W = A'*X + W = cholmod_allocate_dense (A->ncol, 1, A->ncol, xtype+dtype, + cm) ; + cholmod_sdmult (A, 2, one, zero, X, W, cm) ; + // R = B - beta*X + cholmod_free_dense (&R, cm) ; + R = cholmod_zeros (n, 1, xdtype, cm) ; + Rx = R->x ; + Rz = R->z ; + Xx = X->x ; + Xz = X->z ; + if (xtype == CHOLMOD_REAL) + { + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; + Rx [2*i+1] = Bx [2*i+1] - beta [1] * Xx [2*i+1] ; + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + Rz [i] = Bz [i] - beta [1] * Xz [i] ; + } + } + + // R = A*W - R + cholmod_sdmult (A, 0, one, minusone, W, R, cm) ; + cholmod_free_dense (&W, cm) ; + } + else + { + // Ax=b was factorized and solved, R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + } + rnorm = cholmod_norm_dense (R, 0, cm) ; // max abs. entry + xnorm = cholmod_norm_dense (X, 0, cm) ; // max abs. entry + axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; + resid [method] = rnorm / axbnorm ; +#else + printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + } + } + + tot = ta + tf + ts [0] ; + + //-------------------------------------------------------------------------- + // iterative refinement (real symmetric case only) + //-------------------------------------------------------------------------- + + resid2 = -1 ; +#ifndef NMATRIXOPS + if (A->stype != 0 && A->xtype == CHOLMOD_REAL) + { + cholmod_dense *R2 ; + + // x = A\b + cholmod_free_dense (&X, cm) ; + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + + // R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + + // R2 = A\(B-A*X) + R2 = cholmod_solve (CHOLMOD_A, L, R, cm) ; + + // compute X = X + A\(B-A*X) + Xx = X->x ; + Rx = R2->x ; + for (i = 0 ; i < n ; i++) + { + Xx [i] = Xx [i] + Rx [i] ; + } + cholmod_free_dense (&R2, cm) ; + + // compute the new residual, R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + rnorm2 = cholmod_norm_dense (R, 0, cm) ; + resid2 = rnorm2 / axbnorm ; + } +#endif + + cholmod_free_dense (&R, cm) ; + + //-------------------------------------------------------------------------- + // print results + //-------------------------------------------------------------------------- + + anz = cm->anz ; + for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) + { + fl = cm->method [i].fl ; + xlnz = cm->method [i].lnz ; + cm->method [i].fl = -1 ; + cm->method [i].lnz = -1 ; + int ordering = cm->method [i].ordering ; + if (fl >= 0) + { + printf ("Ordering: ") ; + if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; + if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; + if (ordering == CHOLMOD_GIVEN) printf ("user ") ; + if (ordering == CHOLMOD_AMD) printf ("AMD ") ; + if (ordering == CHOLMOD_METIS) printf ("METIS ") ; + if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; + if (xlnz > 0) + { + printf ("fl/lnz %10.1f", fl / xlnz) ; + } + if (anz > 0) + { + printf (" lnz/anz %10.1f", xlnz / anz) ; + } + printf ("\n") ; + } + } + + printf ("ints in L: %15.0f, reals in L: %15.0f\n", + (double) isize, (double) xsize) ; + printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", + cm->fl, cm->lnz) ; + if (A->stype == 0) + { + printf ("nnz(A): %15.0f\n", cm->anz) ; + } + else + { + printf ("nnz(A*A'): %15.0f\n", cm->anz) ; + } + if (cm->lnz > 0) + { + printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; + } + if (anz > 0) + { + printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; + } + printf ("analyze cputime: %12.4f\n", ta) ; + printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, + (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; + printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], + (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; + printf ("overall cputime: %12.4f mflop: %8.1f\n", + tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; + printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], + (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; + printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], + (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; + printf ("peak memory usage: %12.0f (MB)\n", + (double) (cm->memory_usage) / 1048576.) ; + printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; + double maxresid = 0 ; + for (method = 0 ; method <= nmethods ; method++) + { + printf ("%8.2e ", resid [method]) ; + if (isnan (resid [method]) || resid [method] >= 0) + { + maxresid = MAX (maxresid, resid [method]) ; + } + } + printf ("\n") ; + if (isnan (resid2) || resid2 >= 0) + { + printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" + " after iterative refinement\n", resid2) ; + maxresid = MAX (maxresid, resid2) ; + } + printf ("rcond %8.1e\n\n", rcond) ; + + if (L_is_super) + { + cholmod_gpu_stats (cm) ; + } + + cholmod_free_factor (&L, cm) ; + cholmod_free_dense (&X, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and finish CHOLMOD + //-------------------------------------------------------------------------- + + cholmod_free_sparse (&A, cm) ; + cholmod_free_dense (&B, cm) ; + cholmod_finish (cm) ; + + bool ok = !isnan (maxresid) && + maxresid < ((dtype == CHOLMOD_DOUBLE) ? 1e-7 : 1e-4) ; + printf ("maxresid: %g : %s\n", maxresid, + ok ? "All tests passed" : "test failure") ; + fprintf (stderr, "%s maxresid: %10.2g %s : %s\n", + ok ? "OK" : "FAIL", maxresid, + (dtype == CHOLMOD_DOUBLE) ? "(double)" : "(single)", + (argc > 1) ? argv [1] : "stdin") ; + return (ok ? 0 : 1) ; +} + diff --git a/CHOLMOD/Demo/cholmod_di_simple.c b/CHOLMOD/Demo/cholmod_di_simple.c new file mode 100644 index 0000000000..c997476ed9 --- /dev/null +++ b/CHOLMOD/Demo/cholmod_di_simple.c @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_di_simple: simple demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a real symmetric or complex Hermitian matrix from stdin in +// MatrixMarket format, solve Ax=b where b=[1 1 ... 1]', and print the residual. +// +// Usage: cholmod_di_simple < matrixfile +// +// There are four versions of this demo: +// cholmod_di_simple: double, int32 +// cholmod_dl_simple: double, int64 +// cholmod_si_simple: float, int32 +// cholmod_sl_simple: float, int64 + +#include "cholmod.h" +int main (void) +{ + cholmod_sparse *A ; + cholmod_dense *x, *b, *r ; + cholmod_factor *L ; + double one [2] = {1,0}, m1 [2] = {-1,0} ; // basic scalars + cholmod_common c ; + cholmod_start (&c) ; // start CHOLMOD + int dtype = CHOLMOD_DOUBLE ; // use double precision + A = cholmod_read_sparse2 (stdin, dtype, &c) ; // read in a matrix + c.precise = true ; + c.print = (A->nrow > 5) ? 3 : 5 ; + cholmod_print_sparse (A, "A", &c) ; // print the matrix + if (A == NULL || A->stype == 0) // A must be symmetric + { + cholmod_free_sparse (&A, &c) ; + cholmod_finish (&c) ; + return (0) ; + } + b = cholmod_ones (A->nrow, 1, A->xtype + dtype, &c) ; // b = ones(n,1) + + double t1 = SuiteSparse_time ( ) ; + L = cholmod_analyze (A, &c) ; // analyze + t1 = SuiteSparse_time ( ) - t1 ; + double t2 = SuiteSparse_time ( ) ; + cholmod_factorize (A, L, &c) ; // factorize + t2 = SuiteSparse_time ( ) - t2 ; + double t3 = SuiteSparse_time ( ) ; + x = cholmod_solve (CHOLMOD_A, L, b, &c) ; // solve Ax=b + t3 = SuiteSparse_time ( ) - t3 ; + printf ("analyze time: %10.3f sec\n", t1) ; + printf ("factorize time: %10.3f sec\n", t2) ; + printf ("solve time: %10.3f sec\n", t3) ; + printf ("total time: %10.3f sec\n", t1 + t2 + t3) ; + + cholmod_print_factor (L, "L", &c) ; // print the factorization + cholmod_print_dense (x, "x", &c) ; // print the solution + r = cholmod_copy_dense (b, &c) ; // r = b +#ifndef NMATRIXOPS + cholmod_sdmult (A, 0, m1, one, x, r, &c) ; // r = r-Ax + double rnorm = cholmod_norm_dense (r, 0, &c) ; // compute inf-norm of r + double anorm = cholmod_norm_sparse (A, 0, &c) ; // compute inf-norm of A + printf ("\n%s precision results:\n", dtype ? "single" : "double") ; + printf ("norm(b-Ax) %8.1e\n", rnorm) ; + printf ("norm(A) %8.1e\n", anorm) ; + double relresid = rnorm / anorm ; + printf ("resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; + fprintf (stderr, "resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; +#else + printf ("residual norm not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + cholmod_free_factor (&L, &c) ; // free matrices + cholmod_free_sparse (&A, &c) ; + cholmod_free_dense (&r, &c) ; + cholmod_free_dense (&x, &c) ; + cholmod_free_dense (&b, &c) ; + cholmod_print_common ("common", &c) ; + cholmod_gpu_stats (&c) ; + cholmod_finish (&c) ; // finish CHOLMOD + return (0) ; +} + diff --git a/CHOLMOD/Demo/cholmod_dl_demo.c b/CHOLMOD/Demo/cholmod_dl_demo.c new file mode 100644 index 0000000000..906fda8f5d --- /dev/null +++ b/CHOLMOD/Demo/cholmod_dl_demo.c @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_dl_demo: demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is +// symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple +// triplet format, compatible with most files in the Matrix Market format. +// See cholmod_read.c for more details. The readhb.f program reads a +// Harwell/Boeing matrix (excluding element-types) and converts it into the +// form needed by this program. reade.f reads a matrix in Harwell/Boeing +// finite-element form. +// +// Usage: +// cholmod_dl_demo matrixfile +// cholmod_dl_demo < matrixfile +// +// The matrix is assumed to be positive definite (a supernodal LL' or simplicial +// LDL' factorization is used). +// +// Requires the Utility, Cholesky, MatrixOps, and Check Modules. +// Optionally uses the Partition and Supernodal Modules. +// Does not use the Modify Module. +// +// See cholmod_simple.c for a simpler demo program. +// +// There are 4 versions of this demo: +// +// cholmod_di_demo: double or double complex values, int32_t integers +// cholmod_dl_demo: double or double complex values, int64_t integers +// cholmod_si_demo: float or float complex values, int32_t integers +// cholmod_sl_demo: float or float complex values, int64_t integers + +#include "cholmod_demo.h" +#define NTRIALS 100 + +// ff is a global variable so that it can be closed by my_handler +FILE *ff ; + +// halt if an error occurs +static void my_handler (int status, const char *file, int line, + const char *message) +{ + printf ("cholmod error: file: %s line: %d status: %d: %s\n", + file, line, status, message) ; + if (status < 0) + { + if (ff != NULL) fclose (ff) ; + exit (1) ; + } +} + +int main (int argc, char **argv) +{ + double + resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, + anz, axbnorm, rnorm2, resid2, rcond, + one [2], zero [2], minusone [2], beta [2], xlnz, + isize, xsize, s, ss, lnz ; + + double + *Bx, *Rx, *Xx, *Bz, *Xz, *Rz, xn, *X1x, *X2x, *B2x ; + int64_t + i, n, *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; + + FILE *f ; + cholmod_sparse *A ; + cholmod_dense *X = NULL, *B, *W, *R = NULL ; + cholmod_common Common, *cm ; + cholmod_factor *L ; + int trial, method, L_is_super ; + int ver [3] ; + int prefer_zomplex, nmethods ; + + ts[0] = 0.; + ts[1] = 0.; + ts[2] = 0.; + + //-------------------------------------------------------------------------- + // get the file containing the input matrix + //-------------------------------------------------------------------------- + + ff = NULL ; + prefer_zomplex = 0 ; + if (argc > 1) + { + if ((f = fopen (argv [1], "r")) == NULL) + { + my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, + "unable to open file") ; + } + ff = f ; + prefer_zomplex = (argc > 2) ; + } + else + { + f = stdin ; + } + + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- + + cm = &Common ; + cholmod_l_start (cm) ; + cm->print = 4 ; + + cm->prefer_zomplex = prefer_zomplex ; + + // use default parameter settings, except for the error handler. This + // demo program terminates if an error occurs (out of memory, not positive + // definite, ...). It makes the demo program simpler (no need to check + // CHOLMOD error conditions). This non-default parameter setting has no + // effect on performance. + cm->error_handler = my_handler ; + + // Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by + // default, automatically selecting the latter if flop/nnz(L) < 40. + + //-------------------------------------------------------------------------- + // create basic scalars + //-------------------------------------------------------------------------- + + zero [0] = 0 ; + zero [1] = 0 ; + one [0] = 1 ; + one [1] = 0 ; + minusone [0] = -1 ; + minusone [1] = 0 ; + beta [0] = 1e-6 ; + beta [1] = 0 ; + + //-------------------------------------------------------------------------- + // read in a matrix + //-------------------------------------------------------------------------- + + printf ("\n---------------------------------- cholmod_dl_demo:\n") ; + cholmod_l_version (ver) ; + printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + SuiteSparse_version (ver) ; + printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + A = cholmod_l_read_sparse2 (f, CHOLMOD_DOUBLE, cm) ; + if (ff != NULL) + { + fclose (ff) ; + ff = NULL ; + } + anorm = 1 ; +#ifndef NMATRIXOPS + anorm = cholmod_l_norm_sparse (A, 0, cm) ; + printf ("norm (A,inf) = %g\n", anorm) ; + printf ("norm (A,1) = %g\n", cholmod_l_norm_sparse (A, 1, cm)) ; +#endif + + if (prefer_zomplex && A->xtype == CHOLMOD_COMPLEX) + { + // Convert to zomplex, just for testing. In a zomplex matrix, + // the real and imaginary parts are in separate arrays. MATLAB + // uses zomplex matrix exclusively. + cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX + A->dtype, A, cm) ; + } + + int xtype = A->xtype ; // real, complex, or zomplex + int dtype = A->dtype ; // single or double + int xdtype = xtype + dtype ; + cholmod_l_print_sparse (A, "A", cm) ; + + if (A->nrow > A->ncol) + { + // Transpose A so that A'A+beta*I will be factorized instead + cholmod_sparse *C = cholmod_l_transpose (A, 2, cm) ; + cholmod_l_free_sparse (&A, cm) ; + A = C ; + printf ("transposing input matrix\n") ; + } + + //-------------------------------------------------------------------------- + // create an arbitrary right-hand-side + //-------------------------------------------------------------------------- + + n = A->nrow ; + xn = n ; + B = cholmod_l_zeros (n, 1, xdtype, cm) ; + Bx = B->x ; + Bz = B->z ; + +#if GHS + { + // b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments + cholmod_dense *X0 ; + X0 = cholmod_l_ones (A->ncol, 1, xdtype, cm) ; + cholmod_l_sdmult (A, 0, one, zero, X0, B, cm) ; + cholmod_l_free_dense (&X0, cm) ; + } +#else + if (xtype == CHOLMOD_REAL) + { + // real case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Bx [2*i ] = 1 + i / xn ; // real part of B(i) + Bx [2*i+1] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; // real part of B(i) + Bz [i] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } +#endif + + cholmod_l_print_dense (B, "B", cm) ; + bnorm = 1 ; +#ifndef NMATRIXOPS + bnorm = cholmod_l_norm_dense (B, 0, cm) ; // max norm + printf ("bnorm %g\n", bnorm) ; +#endif + + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- + + t = CPUTIME ; + L = cholmod_l_analyze (A, cm) ; + ta = CPUTIME - t ; + ta = MAX (ta, 0) ; + + printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; + + if (A->stype == 0) + { + printf ("Factorizing A*A'+beta*I\n") ; + t = CPUTIME ; + cholmod_l_factorize_p (A, beta, NULL, 0, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + else + { + printf ("Factorizing A\n") ; + t = CPUTIME ; + cholmod_l_factorize (A, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + + cholmod_l_print_factor (L, "L", cm) ; + + // determine the # of integers's and reals's in L. See cholmod_free + if (L->is_super) + { + s = L->nsuper + 1 ; + xsize = L->xsize ; + ss = L->ssize ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + s // L->pi, column pointers for L->s + + s // L->px, column pointers for L->x + + s // L->super, starting column index of each supernode + + ss ; // L->s, the pattern of the supernodes + } + else + { + // this space can increase if you change parameters to their non- + // default values (cm->final_pack, for example). + lnz = L->nzmax ; + xsize = lnz ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + n+1 // L->p, column pointers + + lnz // L->i, integer row indices + + n // L->nz, nz in each column of L + + n+2 // L->next, link list + + n+2 ; // L->prev, link list + } + + // solve with Bset will change L from simplicial to supernodal + rcond = cholmod_l_rcond (L, cm) ; + L_is_super = L->is_super ; + + //-------------------------------------------------------------------------- + // solve + //-------------------------------------------------------------------------- + + if (n >= 1000) + { + nmethods = 1 ; + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + nmethods = 2 ; + } + else + { + nmethods = 3 ; + } + printf ("nmethods: %d\n", nmethods) ; + + for (method = 0 ; method <= nmethods ; method++) + { + resid [method] = -1 ; // not yet computed + + if (method == 0) + { + // basic solve, just once + t = CPUTIME ; + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + ts [0] = CPUTIME - t ; + ts [0] = MAX (ts [0], 0) ; + } + else if (method == 1) + { + // basic solve, many times, but keep the last one + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + cholmod_l_free_dense (&X, cm) ; + Bx [0] = 1 + trial / xn ; // tweak B each iteration + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + } + ts [1] = CPUTIME - t ; + ts [1] = MAX (ts [1], 0) / NTRIALS ; + } + else if (method == 2) + { + // solve with reused workspace + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_l_free_dense (&X, cm) ; + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + Bx [0] = 1 + trial / xn ; // tweak B each iteration + cholmod_l_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + } + cholmod_l_free_dense (&Ywork, cm) ; + cholmod_l_free_dense (&Ework, cm) ; + ts [2] = CPUTIME - t ; + ts [2] = MAX (ts [2], 0) / NTRIALS ; + } + else + { + // solve with reused workspace and sparse Bset + if (xtype == CHOLMOD_ZOMPLEX) continue ; + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_dense *X2 = NULL, *B2 = NULL ; + cholmod_sparse *Bset, *Xset = NULL ; + + double err ; + FILE *timelog = fopen ("timelog.m", "w") ; + if (timelog) fprintf (timelog, "results = [\n") ; + + // xtype is CHOLMOD_REAL or CHOLMOD_COMPLEX, not CHOLMOD_ZOMPLEX + B2 = cholmod_l_zeros (n, 1, xdtype, cm) ; + B2x = B2->x ; + + Bset = cholmod_l_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, + CHOLMOD_PATTERN + dtype, cm) ; + Bsetp = Bset->p ; + Bseti = Bset->i ; + Bsetp [0] = 0 ; // nnz(B) is 1 (it can be anything) + Bsetp [1] = 1 ; + resid [3] = 0 ; + + for (i = 0 ; i < MIN (100,n) ; i++) + { + // B (i) is nonzero, all other entries are ignored + // (implied to be zero) + Bseti [0] = i ; + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 3.1 * i + 0.9 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = i + 0.042 ; + B2x [2*i+1] = i - 92.7 ; + } + + // first get the entire solution, to compare against + cholmod_l_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + + // now get the sparse solutions; this will change L from + // supernodal to simplicial + + if (i == 0) + { + // first solve can be slower because it has to allocate + // space for X2, Xset, etc, and change L. + // So don't time it + cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + // solve Ax=b but only to get x(i). + // b is all zero except for b(i). + // This takes O(xlen) time + cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + t = CPUTIME - t ; + t = MAX (t, 0) / NTRIALS ; + + // check the solution and log the time + Xsetp = Xset->p ; + Xseti = Xset->i ; + xlen = Xsetp [1] ; + X1x = X->x ; + X2x = X2->x ; + Lnz = L->nz ; + + if (xtype == CHOLMOD_REAL) + { + fl = 2 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 4 * Lnz [j] ; + err = X1x [j] - X2x [j] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + else // (xtype == CHOLMOD_COMPLEX) + { + fl = 16 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 16 * Lnz [j] ; + err = X1x [2*j ] - X2x [2*j ] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + err = X1x [2*j+1] - X2x [2*j+1] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + + if (timelog) fprintf (timelog, "%g %g %g %g\n", + (double) i, (double) xlen, fl, t); + + // clear B for the next test + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 0 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = 0 ; + B2x [2*i+1] = 0 ; + } + } + + if (timelog) + { + fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; + fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; + fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; + fclose (timelog) ; + } + +#ifndef NMATRIXOPS + double xnorm1 = cholmod_l_norm_dense (X, 1, cm) + ((n==0)?1:0) ; + resid [3] = resid [3] / xnorm1 ; +#endif + + cholmod_l_free_dense (&Ywork, cm) ; + cholmod_l_free_dense (&Ework, cm) ; + cholmod_l_free_dense (&X2, cm) ; + cholmod_l_free_dense (&B2, cm) ; + cholmod_l_free_sparse (&Xset, cm) ; + cholmod_l_free_sparse (&Bset, cm) ; + } + + //---------------------------------------------------------------------- + // compute the residual + //---------------------------------------------------------------------- + + if (method < 3) + { +#ifndef NMATRIXOPS + if (A->stype == 0) + { + // (AA'+beta*I)x=b is the linear system that was solved + // W = A'*X + W = cholmod_l_allocate_dense (A->ncol, 1, A->ncol, xtype+dtype, + cm) ; + cholmod_l_sdmult (A, 2, one, zero, X, W, cm) ; + // R = B - beta*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_zeros (n, 1, xdtype, cm) ; + Rx = R->x ; + Rz = R->z ; + Xx = X->x ; + Xz = X->z ; + if (xtype == CHOLMOD_REAL) + { + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; + Rx [2*i+1] = Bx [2*i+1] - beta [1] * Xx [2*i+1] ; + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + Rz [i] = Bz [i] - beta [1] * Xz [i] ; + } + } + + // R = A*W - R + cholmod_l_sdmult (A, 0, one, minusone, W, R, cm) ; + cholmod_l_free_dense (&W, cm) ; + } + else + { + // Ax=b was factorized and solved, R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + } + rnorm = cholmod_l_norm_dense (R, 0, cm) ; // max abs. entry + xnorm = cholmod_l_norm_dense (X, 0, cm) ; // max abs. entry + axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; + resid [method] = rnorm / axbnorm ; +#else + printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + } + } + + tot = ta + tf + ts [0] ; + + //-------------------------------------------------------------------------- + // iterative refinement (real symmetric case only) + //-------------------------------------------------------------------------- + + resid2 = -1 ; +#ifndef NMATRIXOPS + if (A->stype != 0 && A->xtype == CHOLMOD_REAL) + { + cholmod_dense *R2 ; + + // x = A\b + cholmod_l_free_dense (&X, cm) ; + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + + // R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + + // R2 = A\(B-A*X) + R2 = cholmod_l_solve (CHOLMOD_A, L, R, cm) ; + + // compute X = X + A\(B-A*X) + Xx = X->x ; + Rx = R2->x ; + for (i = 0 ; i < n ; i++) + { + Xx [i] = Xx [i] + Rx [i] ; + } + cholmod_l_free_dense (&R2, cm) ; + + // compute the new residual, R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + rnorm2 = cholmod_l_norm_dense (R, 0, cm) ; + resid2 = rnorm2 / axbnorm ; + } +#endif + + cholmod_l_free_dense (&R, cm) ; + + //-------------------------------------------------------------------------- + // print results + //-------------------------------------------------------------------------- + + anz = cm->anz ; + for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) + { + fl = cm->method [i].fl ; + xlnz = cm->method [i].lnz ; + cm->method [i].fl = -1 ; + cm->method [i].lnz = -1 ; + int ordering = cm->method [i].ordering ; + if (fl >= 0) + { + printf ("Ordering: ") ; + if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; + if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; + if (ordering == CHOLMOD_GIVEN) printf ("user ") ; + if (ordering == CHOLMOD_AMD) printf ("AMD ") ; + if (ordering == CHOLMOD_METIS) printf ("METIS ") ; + if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; + if (xlnz > 0) + { + printf ("fl/lnz %10.1f", fl / xlnz) ; + } + if (anz > 0) + { + printf (" lnz/anz %10.1f", xlnz / anz) ; + } + printf ("\n") ; + } + } + + printf ("ints in L: %15.0f, reals in L: %15.0f\n", + (double) isize, (double) xsize) ; + printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", + cm->fl, cm->lnz) ; + if (A->stype == 0) + { + printf ("nnz(A): %15.0f\n", cm->anz) ; + } + else + { + printf ("nnz(A*A'): %15.0f\n", cm->anz) ; + } + if (cm->lnz > 0) + { + printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; + } + if (anz > 0) + { + printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; + } + printf ("analyze cputime: %12.4f\n", ta) ; + printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, + (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; + printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], + (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; + printf ("overall cputime: %12.4f mflop: %8.1f\n", + tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; + printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], + (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; + printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], + (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; + printf ("peak memory usage: %12.0f (MB)\n", + (double) (cm->memory_usage) / 1048576.) ; + printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; + double maxresid = 0 ; + for (method = 0 ; method <= nmethods ; method++) + { + printf ("%8.2e ", resid [method]) ; + if (isnan (resid [method]) || resid [method] >= 0) + { + maxresid = MAX (maxresid, resid [method]) ; + } + } + printf ("\n") ; + if (isnan (resid2) || resid2 >= 0) + { + printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" + " after iterative refinement\n", resid2) ; + maxresid = MAX (maxresid, resid2) ; + } + printf ("rcond %8.1e\n\n", rcond) ; + + if (L_is_super) + { + cholmod_l_gpu_stats (cm) ; + } + + cholmod_l_free_factor (&L, cm) ; + cholmod_l_free_dense (&X, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and finish CHOLMOD + //-------------------------------------------------------------------------- + + cholmod_l_free_sparse (&A, cm) ; + cholmod_l_free_dense (&B, cm) ; + cholmod_l_finish (cm) ; + + bool ok = !isnan (maxresid) && + maxresid < ((dtype == CHOLMOD_DOUBLE) ? 1e-7 : 1e-4) ; + printf ("maxresid: %g : %s\n", maxresid, + ok ? "All tests passed" : "test failure") ; + fprintf (stderr, "%s maxresid: %10.2g %s : %s\n", + ok ? "OK" : "FAIL", maxresid, + (dtype == CHOLMOD_DOUBLE) ? "(double)" : "(single)", + (argc > 1) ? argv [1] : "stdin") ; + return (ok ? 0 : 1) ; +} + diff --git a/CHOLMOD/Demo/cholmod_dl_simple.c b/CHOLMOD/Demo/cholmod_dl_simple.c new file mode 100644 index 0000000000..5788168075 --- /dev/null +++ b/CHOLMOD/Demo/cholmod_dl_simple.c @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_dl_simple: simple demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a real symmetric or complex Hermitian matrix from stdin in +// MatrixMarket format, solve Ax=b where b=[1 1 ... 1]', and print the residual. +// +// Usage: cholmod_dl_simple < matrixfile +// +// There are four versions of this demo: +// cholmod_di_simple: double, int32 +// cholmod_dl_simple: double, int64 +// cholmod_si_simple: float, int32 +// cholmod_sl_simple: float, int64 + +#include "cholmod.h" +int main (void) +{ + cholmod_sparse *A ; + cholmod_dense *x, *b, *r ; + cholmod_factor *L ; + double one [2] = {1,0}, m1 [2] = {-1,0} ; // basic scalars + cholmod_common c ; + cholmod_l_start (&c) ; // start CHOLMOD + int dtype = CHOLMOD_DOUBLE ; // use double precision + A = cholmod_l_read_sparse2 (stdin, dtype, &c) ; // read in a matrix + c.precise = true ; + c.print = (A->nrow > 5) ? 3 : 5 ; + cholmod_l_print_sparse (A, "A", &c) ; // print the matrix + if (A == NULL || A->stype == 0) // A must be symmetric + { + cholmod_l_free_sparse (&A, &c) ; + cholmod_l_finish (&c) ; + return (0) ; + } + b = cholmod_l_ones (A->nrow, 1, A->xtype + dtype, &c) ; // b = ones(n,1) + + double t1 = SuiteSparse_time ( ) ; + L = cholmod_l_analyze (A, &c) ; // analyze + t1 = SuiteSparse_time ( ) - t1 ; + double t2 = SuiteSparse_time ( ) ; + cholmod_l_factorize (A, L, &c) ; // factorize + t2 = SuiteSparse_time ( ) - t2 ; + double t3 = SuiteSparse_time ( ) ; + x = cholmod_l_solve (CHOLMOD_A, L, b, &c) ; // solve Ax=b + t3 = SuiteSparse_time ( ) - t3 ; + printf ("analyze time: %10.3f sec\n", t1) ; + printf ("factorize time: %10.3f sec\n", t2) ; + printf ("solve time: %10.3f sec\n", t3) ; + printf ("total time: %10.3f sec\n", t1 + t2 + t3) ; + + cholmod_l_print_factor (L, "L", &c) ; // print the factorization + cholmod_l_print_dense (x, "x", &c) ; // print the solution + r = cholmod_l_copy_dense (b, &c) ; // r = b +#ifndef NMATRIXOPS + cholmod_l_sdmult (A, 0, m1, one, x, r, &c) ; // r = r-Ax + double rnorm = cholmod_l_norm_dense (r, 0, &c) ; // compute inf-norm of r + double anorm = cholmod_l_norm_sparse (A, 0, &c) ; // compute inf-norm of A + printf ("\n%s precision results:\n", dtype ? "single" : "double") ; + printf ("norm(b-Ax) %8.1e\n", rnorm) ; + printf ("norm(A) %8.1e\n", anorm) ; + double relresid = rnorm / anorm ; + printf ("resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; + fprintf (stderr, "resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; +#else + printf ("residual norm not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + cholmod_l_free_factor (&L, &c) ; // free matrices + cholmod_l_free_sparse (&A, &c) ; + cholmod_l_free_dense (&r, &c) ; + cholmod_l_free_dense (&x, &c) ; + cholmod_l_free_dense (&b, &c) ; + cholmod_l_print_common ("common", &c) ; + cholmod_l_gpu_stats (&c) ; + cholmod_l_finish (&c) ; // finish CHOLMOD + return (0) ; +} + diff --git a/CHOLMOD/Demo/cholmod_function.h b/CHOLMOD/Demo/cholmod_function.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/CHOLMOD/Demo/cholmod_l_demo.c b/CHOLMOD/Demo/cholmod_l_demo.c deleted file mode 100644 index 40dd31ddeb..0000000000 --- a/CHOLMOD/Demo/cholmod_l_demo.c +++ /dev/null @@ -1,740 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Demo/cholmod_l_demo: demo program for CHOLMOD -//------------------------------------------------------------------------------ - -// CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis, -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is - * symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple - * triplet format, compatible with most files in the Matrix Market format. - * See cholmod_read.c for more details. The readhb.f program reads a - * Harwell/Boeing matrix (excluding element-types) and converts it into the - * form needed by this program. reade.f reads a matrix in Harwell/Boeing - * finite-element form. - * - * Usage: - * cholmod_l_demo matrixfile - * cholmod_l_demo < matrixfile - * - * The matrix is assumed to be positive definite (a supernodal LL' or simplicial - * LDL' factorization is used). - * - * Requires the Utility, Cholesky, MatrixOps, and Check Modules. - * Optionally uses the Partition and Supernodal Modules. - * Does not use the Modify Module. - * - * See cholmod_simple.c for a simpler demo program. - */ - -#include "cholmod_demo.h" -#define NTRIALS 100 - -/* ff is a global variable so that it can be closed by my_handler */ -FILE *ff ; - -/* halt if an error occurs */ -static void my_handler (int status, const char *file, int line, - const char *message) -{ - printf ("cholmod error: file: %s line: %d status: %d: %s\n", - file, line, status, message) ; - if (status < 0) - { - if (ff != NULL) fclose (ff) ; - exit (0) ; - } -} - -int main (int argc, char **argv) -{ - double resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, - anz, axbnorm, rnorm2, resid2, rcond ; - FILE *f ; - cholmod_sparse *A ; - cholmod_dense *X = NULL, *B, *W, *R = NULL ; - double one [2], zero [2], minusone [2], beta [2], xlnz ; - cholmod_common Common, *cm ; - cholmod_factor *L ; - double *Bx, *Rx, *Xx, *Bz, *Xz, *Rz ; - int64_t i, n, isize, xsize, ordering, xtype, s, ss, lnz ; - int trial, method, L_is_super ; - int ver [3] ; - int prefer_zomplex, nmethods ; - - ts[0] = 0.; - ts[1] = 0.; - ts[2] = 0.; - - /* ---------------------------------------------------------------------- */ - /* get the file containing the input matrix */ - /* ---------------------------------------------------------------------- */ - - ff = NULL ; - prefer_zomplex = 0 ; - if (argc > 1) - { - if ((f = fopen (argv [1], "r")) == NULL) - { - my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, - "unable to open file") ; - } - ff = f ; - prefer_zomplex = (argc > 2) ; - } - else - { - f = stdin ; - } - - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ - - cm = &Common ; - cholmod_l_start (cm) ; - - /* cm->useGPU = 1; */ - cm->prefer_zomplex = prefer_zomplex ; - - /* use default parameter settings, except for the error handler. This - * demo program terminates if an error occurs (out of memory, not positive - * definite, ...). It makes the demo program simpler (no need to check - * CHOLMOD error conditions). This non-default parameter setting has no - * effect on performance. */ - cm->error_handler = my_handler ; - - /* Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by - * default, automatically selecting the latter if flop/nnz(L) < 40. */ - - /* ---------------------------------------------------------------------- */ - /* create basic scalars */ - /* ---------------------------------------------------------------------- */ - - zero [0] = 0 ; - zero [1] = 0 ; - one [0] = 1 ; - one [1] = 0 ; - minusone [0] = -1 ; - minusone [1] = 0 ; - beta [0] = 1e-6 ; - beta [1] = 0 ; - - /* ---------------------------------------------------------------------- */ - /* read in a matrix */ - /* ---------------------------------------------------------------------- */ - - printf ("\n---------------------------------- cholmod_l_demo:\n") ; - cholmod_l_version (ver) ; - printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; - SuiteSparse_version (ver) ; - printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; - A = cholmod_l_read_sparse (f, cm) ; - if (ff != NULL) - { - fclose (ff) ; - ff = NULL ; - } - anorm = 1 ; -#ifndef NMATRIXOPS - anorm = cholmod_l_norm_sparse (A, 0, cm) ; - printf ("norm (A,inf) = %g\n", anorm) ; - printf ("norm (A,1) = %g\n", cholmod_l_norm_sparse (A, 1, cm)) ; -#endif - - if (prefer_zomplex && A->xtype == CHOLMOD_COMPLEX) - { - /* Convert to zomplex, just for testing. In a zomplex matrix, - the real and imaginary parts are in separate arrays. MATLAB - uses zomplex matrix exclusively. */ - double *Ax = A->x ; - int64_t nz = cholmod_l_nnz (A, cm) ; - printf ("nz: %"PRId64"\n", nz) ; - double *Ax2 = cholmod_l_malloc (nz, sizeof (double), cm) ; - double *Az2 = cholmod_l_malloc (nz, sizeof (double), cm) ; - for (i = 0 ; i < nz ; i++) - { - Ax2 [i] = Ax [2*i ] ; - Az2 [i] = Ax [2*i+1] ; - } - cholmod_l_free (A->nzmax, 2*sizeof(double), Ax, cm) ; - A->x = Ax2 ; - A->z = Az2 ; - A->xtype = CHOLMOD_ZOMPLEX ; - /* cm->print = 5 ; */ - } - - xtype = A->xtype ; - cholmod_l_print_sparse (A, "A", cm) ; - -#if 0 - if ( 0 ) { - // scale diagonal - printf ("\n\n SCALING DIAGONAL \n\n"); - - // create diagonal - printf ("%"PRId64",%"PRId64",%d\n", A->nrow, A->ncol, A->xtype ); - - cholmod_sparse *D = cholmod_l_speye (A->nrow, A->ncol, A->xtype, cm ); - printf ("sparse done \n"); - cholmod_l_print_sparse (D, "D", cm); - - D->stype = 1; - cholmod_l_print_sparse (D, "D", cm); - - double alpha[2]; - double beta[2]; - alpha[0] = 1.0; - alpha[1] = 1.0; - beta[0] = 1.0e9; // 9 works, 467doesn't - beta[1] = 1.0e0; - - cholmod_sparse *C = cholmod_l_add (A, D, alpha, beta, 1, 0, cm ); - cholmod_l_print_sparse (C, "C", cm); - - A = C; - - } -#endif - - if (A->nrow > A->ncol) - { - /* Transpose A so that A'A+beta*I will be factorized instead */ - cholmod_sparse *C = cholmod_l_transpose (A, 2, cm) ; - cholmod_l_free_sparse (&A, cm) ; - A = C ; - printf ("transposing input matrix\n") ; - } - - /* ---------------------------------------------------------------------- */ - /* create an arbitrary right-hand-side */ - /* ---------------------------------------------------------------------- */ - - n = A->nrow ; - B = cholmod_l_zeros (n, 1, xtype, cm) ; - Bx = B->x ; - Bz = B->z ; - -#if GHS - { - /* b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments */ - cholmod_dense *X0 ; - X0 = cholmod_l_ones (A->ncol, 1, xtype, cm) ; - cholmod_l_sdmult (A, 0, one, zero, X0, B, cm) ; - cholmod_l_free_dense (&X0, cm) ; - } -#else - if (xtype == CHOLMOD_REAL) - { - /* real case */ - for (i = 0 ; i < n ; i++) - { - double x = n ; - Bx [i] = 1 + i / x ; - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - /* complex case */ - for (i = 0 ; i < n ; i++) - { - double x = n ; - Bx [2*i ] = 1 + i / x ; /* real part of B(i) */ - Bx [2*i+1] = (x/2 - i) / (3*x) ; /* imag part of B(i) */ - } - } - else /* (xtype == CHOLMOD_ZOMPLEX) */ - { - /* zomplex case */ - for (i = 0 ; i < n ; i++) - { - double x = n ; - Bx [i] = 1 + i / x ; /* real part of B(i) */ - Bz [i] = (x/2 - i) / (3*x) ; /* imag part of B(i) */ - } - } - -#endif - - cholmod_l_print_dense (B, "B", cm) ; - bnorm = 1 ; -#ifndef NMATRIXOPS - bnorm = cholmod_l_norm_dense (B, 0, cm) ; /* max norm */ - printf ("bnorm %g\n", bnorm) ; -#endif - - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ - - t = CPUTIME ; - L = cholmod_l_analyze (A, cm) ; - ta = CPUTIME - t ; - ta = MAX (ta, 0) ; - - printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; - - if (A->stype == 0) - { - printf ("Factorizing A*A'+beta*I\n") ; - t = CPUTIME ; - cholmod_l_factorize_p (A, beta, NULL, 0, L, cm) ; - tf = CPUTIME - t ; - tf = MAX (tf, 0) ; - } - else - { - printf ("Factorizing A\n") ; - t = CPUTIME ; - cholmod_l_factorize (A, L, cm) ; - tf = CPUTIME - t ; - tf = MAX (tf, 0) ; - } - - cholmod_l_print_factor (L, "L", cm) ; - - /* determine the # of integers's and reals's in L. See cholmod_free */ - if (L->is_super) - { - s = L->nsuper + 1 ; - xsize = L->xsize ; - ss = L->ssize ; - isize = - n /* L->Perm */ - + n /* L->ColCount, nz in each column of 'pure' L */ - + s /* L->pi, column pointers for L->s */ - + s /* L->px, column pointers for L->x */ - + s /* L->super, starting column index of each supernode */ - + ss ; /* L->s, the pattern of the supernodes */ - } - else - { - /* this space can increase if you change parameters to their non- - * default values (cm->final_pack, for example). */ - lnz = L->nzmax ; - xsize = lnz ; - isize = - n /* L->Perm */ - + n /* L->ColCount, nz in each column of 'pure' L */ - + n+1 /* L->p, column pointers */ - + lnz /* L->i, integer row indices */ - + n /* L->nz, nz in each column of L */ - + n+2 /* L->next, link list */ - + n+2 ; /* L->prev, link list */ - } - - /* solve with Bset will change L from simplicial to supernodal */ - rcond = cholmod_l_rcond (L, cm) ; - L_is_super = L->is_super ; - - /* ---------------------------------------------------------------------- */ - /* solve */ - /* ---------------------------------------------------------------------- */ - - if (n >= 1000) - { - nmethods = 1 ; - } - else if (xtype == CHOLMOD_ZOMPLEX) - { - nmethods = 2 ; - } - else - { - nmethods = 3 ; - } - printf ("nmethods: %d\n", nmethods) ; - - for (method = 0 ; method <= nmethods ; method++) - { - double x = n ; - resid [method] = -1 ; /* not yet computed */ - - if (method == 0) - { - /* basic solve, just once */ - t = CPUTIME ; - X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; - ts [0] = CPUTIME - t ; - ts [0] = MAX (ts [0], 0) ; - } - else if (method == 1) - { - /* basic solve, many times, but keep the last one */ - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - cholmod_l_free_dense (&X, cm) ; - Bx [0] = 1 + trial / x ; /* tweak B each iteration */ - X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; - } - ts [1] = CPUTIME - t ; - ts [1] = MAX (ts [1], 0) / NTRIALS ; - } - else if (method == 2) - { - /* solve with reused workspace */ - cholmod_dense *Ywork = NULL, *Ework = NULL ; - cholmod_l_free_dense (&X, cm) ; - - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - Bx [0] = 1 + trial / x ; /* tweak B each iteration */ - cholmod_l_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - } - cholmod_l_free_dense (&Ywork, cm) ; - cholmod_l_free_dense (&Ework, cm) ; - ts [2] = CPUTIME - t ; - ts [2] = MAX (ts [2], 0) / NTRIALS ; - - } - else - { - /* solve with reused workspace and sparse Bset */ - cholmod_dense *Ywork = NULL, *Ework = NULL ; - cholmod_dense *X2 = NULL, *B2 = NULL ; - cholmod_sparse *Bset, *Xset = NULL ; - int64_t *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; - double *X1x, *X2x, *B2x, err ; - FILE *timelog = fopen ("timelog.m", "w") ; - if (timelog) fprintf (timelog, "results = [\n") ; - - B2 = cholmod_l_zeros (n, 1, xtype, cm) ; - B2x = B2->x ; - - Bset = cholmod_l_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - Bsetp = Bset->p ; - Bseti = Bset->i ; - Bsetp [0] = 0 ; /* nnz(B) is 1 (it can be anything) */ - Bsetp [1] = 1 ; - resid [3] = 0 ; - - for (i = 0 ; i < MIN (100,n) ; i++) - { - /* B (i) is nonzero, all other entries are ignored - (implied to be zero) */ - Bseti [0] = i ; - if (xtype == CHOLMOD_REAL) - { - B2x [i] = 3.1 * i + 0.9 ; - } - else /* (xtype == CHOLMOD_COMPLEX) */ - { - B2x [2*i ] = i + 0.042 ; - B2x [2*i+1] = i - 92.7 ; - } - - /* first get the entire solution, to compare against */ - cholmod_l_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - - /* now get the sparse solutions; this will change L from - supernodal to simplicial */ - - if (i == 0) - { - /* first solve can be slower because it has to allocate - space for X2, Xset, etc, and change L. - So don't time it */ - cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - } - - t = CPUTIME ; - for (trial = 0 ; trial < NTRIALS ; trial++) - { - /* solve Ax=b but only to get x(i). - b is all zero except for b(i). - This takes O(xlen) time */ - cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - } - t = CPUTIME - t ; - t = MAX (t, 0) / NTRIALS ; - - /* check the solution and log the time */ - Xsetp = Xset->p ; - Xseti = Xset->i ; - xlen = Xsetp [1] ; - X1x = X->x ; - X2x = X2->x ; - Lnz = L->nz ; - - if (xtype == CHOLMOD_REAL) - { - fl = 2 * xlen ; - for (k = 0 ; k < xlen ; k++) - { - j = Xseti [k] ; - fl += 4 * Lnz [j] ; - err = X1x [j] - X2x [j] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - } - } - else /* (xtype == CHOLMOD_COMPLEX) */ - { - fl = 16 * xlen ; - for (k = 0 ; k < xlen ; k++) - { - j = Xseti [k] ; - fl += 16 * Lnz [j] ; - err = X1x [2*j ] - X2x [2*j ] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - err = X1x [2*j+1] - X2x [2*j+1] ; - err = ABS (err) ; - resid [3] = MAX (resid [3], err) ; - } - } - - if (timelog) fprintf (timelog, "%g %g %g %g\n", - (double) i, (double) xlen, fl, t); - - /* clear B for the next test */ - if (xtype == CHOLMOD_REAL) - { - B2x [i] = 0 ; - } - else /* (xtype == CHOLMOD_COMPLEX) */ - { - B2x [2*i ] = 0 ; - B2x [2*i+1] = 0 ; - } - } - - if (timelog) - { - fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; - fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; - fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; - fclose (timelog) ; - } - -#ifndef NMATRIXOPS - resid [3] = resid [3] / cholmod_l_norm_dense (X, 1, cm) ; -#endif - - cholmod_l_free_dense (&Ywork, cm) ; - cholmod_l_free_dense (&Ework, cm) ; - cholmod_l_free_dense (&X2, cm) ; - cholmod_l_free_dense (&B2, cm) ; - cholmod_l_free_sparse (&Xset, cm) ; - cholmod_l_free_sparse (&Bset, cm) ; - } - - /* ------------------------------------------------------------------ */ - /* compute the residual */ - /* ------------------------------------------------------------------ */ - - if (method < 3) - { -#ifndef NMATRIXOPS - if (A->stype == 0) - { - /* (AA'+beta*I)x=b is the linear system that was solved */ - /* W = A'*X */ - W = cholmod_l_allocate_dense (A->ncol, 1, A->ncol, xtype, cm) ; - cholmod_l_sdmult (A, 2, one, zero, X, W, cm) ; - /* R = B - beta*X */ - cholmod_l_free_dense (&R, cm) ; - R = cholmod_l_zeros (n, 1, xtype, cm) ; - Rx = R->x ; - Rz = R->z ; - Xx = X->x ; - Xz = X->z ; - if (xtype == CHOLMOD_REAL) - { - for (i = 0 ; i < n ; i++) - { - Rx [i] = Bx [i] - beta [0] * Xx [i] ; - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - /* complex case */ - for (i = 0 ; i < n ; i++) - { - Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; - Rx [2*i+1] = Bx [2*i+1] - beta [1] * Xx [2*i+1] ; - } - } - else /* (xtype == CHOLMOD_ZOMPLEX) */ - { - /* zomplex case */ - for (i = 0 ; i < n ; i++) - { - Rx [i] = Bx [i] - beta [0] * Xx [i] ; - Rz [i] = Bz [i] - beta [1] * Xz [i] ; - } - } - - /* R = A*W - R */ - cholmod_l_sdmult (A, 0, one, minusone, W, R, cm) ; - cholmod_l_free_dense (&W, cm) ; - } - else - { - /* Ax=b was factorized and solved, R = B-A*X */ - cholmod_l_free_dense (&R, cm) ; - R = cholmod_l_copy_dense (B, cm) ; - cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; - } - rnorm = cholmod_l_norm_dense (R, 0, cm) ; /* max abs. entry */ - xnorm = cholmod_l_norm_dense (X, 0, cm) ; /* max abs. entry */ - - axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; - resid [method] = rnorm / axbnorm ; -#else - printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; -#endif - } - } - - tot = ta + tf + ts [0] ; - - /* ---------------------------------------------------------------------- */ - /* iterative refinement (real symmetric case only) */ - /* ---------------------------------------------------------------------- */ - - resid2 = -1 ; -#ifndef NMATRIXOPS - if (A->stype != 0 && A->xtype == CHOLMOD_REAL) - { - cholmod_dense *R2 ; - - // x = A\b - cholmod_l_free_dense (&X, cm) ; - X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; - - // R = B-A*X - cholmod_l_free_dense (&R, cm) ; - R = cholmod_l_copy_dense (B, cm) ; - cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; - - /* R2 = A\(B-A*X) */ - R2 = cholmod_l_solve (CHOLMOD_A, L, R, cm) ; - /* compute X = X + A\(B-A*X) */ - Xx = X->x ; - Rx = R2->x ; - for (i = 0 ; i < n ; i++) - { - Xx [i] = Xx [i] + Rx [i] ; - } - cholmod_l_free_dense (&R2, cm) ; - - /* compute the new residual, R = B-A*X */ - cholmod_l_free_dense (&R, cm) ; - R = cholmod_l_copy_dense (B, cm) ; - cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; - rnorm2 = cholmod_l_norm_dense (R, 0, cm) ; - resid2 = rnorm2 / axbnorm ; - } -#endif - - cholmod_l_free_dense (&R, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print results */ - /* ---------------------------------------------------------------------- */ - - anz = cm->anz ; - for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) - /* for (i = 4 ; i < 3 ; i++) */ - { - fl = cm->method [i].fl ; - xlnz = cm->method [i].lnz ; - cm->method [i].fl = -1 ; - cm->method [i].lnz = -1 ; - ordering = cm->method [i].ordering ; - if (fl >= 0) - { - printf ("Ordering: ") ; - if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; - if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; - if (ordering == CHOLMOD_GIVEN) printf ("user ") ; - if (ordering == CHOLMOD_AMD) printf ("AMD ") ; - if (ordering == CHOLMOD_METIS) printf ("METIS ") ; - if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; - if (xlnz > 0) - { - printf ("fl/lnz %10.1f", fl / xlnz) ; - } - if (anz > 0) - { - printf (" lnz/anz %10.1f", xlnz / anz) ; - } - printf ("\n") ; - } - } - - printf ("ints in L: %15.0f, doubles in L: %15.0f\n", - (double) isize, (double) xsize) ; - printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", - cm->fl, cm->lnz) ; - if (A->stype == 0) - { - printf ("nnz(A): %15.0f\n", cm->anz) ; - } - else - { - printf ("nnz(A*A'): %15.0f\n", cm->anz) ; - } - if (cm->lnz > 0) - { - printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; - } - if (anz > 0) - { - printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; - } - printf ("analyze cputime: %12.4f\n", ta) ; - printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, - (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; - printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], - (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; - printf ("overall cputime: %12.4f mflop: %8.1f\n", - tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; - printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], - (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; - printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], - (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; - printf ("peak memory usage: %12.0f (MB)\n", - (double) (cm->memory_usage) / 1048576.) ; - printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; - for (method = 0 ; method <= nmethods ; method++) - { - printf ("%8.2e ", resid [method]) ; - } - printf ("\n") ; - if (resid2 >= 0) - { - printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" - " after iterative refinement\n", resid2) ; - } - printf ("rcond %8.1e\n\n", rcond) ; - - if (L_is_super) - { - cholmod_l_gpu_stats (cm) ; - } - - cholmod_l_free_factor (&L, cm) ; - cholmod_l_free_dense (&X, cm) ; - - /* ---------------------------------------------------------------------- */ - /* free matrices and finish CHOLMOD */ - /* ---------------------------------------------------------------------- */ - - cholmod_l_free_sparse (&A, cm) ; - cholmod_l_free_dense (&B, cm) ; - cholmod_l_finish (cm) ; - - return (0) ; -} diff --git a/CHOLMOD/Demo/cholmod_si_demo.c b/CHOLMOD/Demo/cholmod_si_demo.c new file mode 100644 index 0000000000..8026f4130d --- /dev/null +++ b/CHOLMOD/Demo/cholmod_si_demo.c @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_si_demo: demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is +// symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple +// triplet format, compatible with most files in the Matrix Market format. +// See cholmod_read.c for more details. The readhb.f program reads a +// Harwell/Boeing matrix (excluding element-types) and converts it into the +// form needed by this program. reade.f reads a matrix in Harwell/Boeing +// finite-element form. +// +// Usage: +// cholmod_si_demo matrixfile +// cholmod_si_demo < matrixfile +// +// The matrix is assumed to be positive definite (a supernodal LL' or simplicial +// LDL' factorization is used). +// +// Requires the Utility, Cholesky, MatrixOps, and Check Modules. +// Optionally uses the Partition and Supernodal Modules. +// Does not use the Modify Module. +// +// See cholmod_simple.c for a simpler demo program. +// +// There are 4 versions of this demo: +// +// cholmod_di_demo: double or double complex values, int32_t integers +// cholmod_dl_demo: double or double complex values, int64_t integers +// cholmod_si_demo: float or float complex values, int32_t integers +// cholmod_sl_demo: float or float complex values, int64_t integers + +#include "cholmod_demo.h" +#define NTRIALS 100 + +// ff is a global variable so that it can be closed by my_handler +FILE *ff ; + +// halt if an error occurs +static void my_handler (int status, const char *file, int line, + const char *message) +{ + printf ("cholmod error: file: %s line: %d status: %d: %s\n", + file, line, status, message) ; + if (status < 0) + { + if (ff != NULL) fclose (ff) ; + exit (1) ; + } +} + +int main (int argc, char **argv) +{ + double + resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, + anz, axbnorm, rnorm2, resid2, rcond, + one [2], zero [2], minusone [2], beta [2], xlnz, + isize, xsize, s, ss, lnz ; + + float + *Bx, *Rx, *Xx, *Bz, *Xz, *Rz, xn, *X1x, *X2x, *B2x ; + int32_t + i, n, *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; + + FILE *f ; + cholmod_sparse *A ; + cholmod_dense *X = NULL, *B, *W, *R = NULL ; + cholmod_common Common, *cm ; + cholmod_factor *L ; + int trial, method, L_is_super ; + int ver [3] ; + int prefer_zomplex, nmethods ; + + ts[0] = 0.; + ts[1] = 0.; + ts[2] = 0.; + + //-------------------------------------------------------------------------- + // get the file containing the input matrix + //-------------------------------------------------------------------------- + + ff = NULL ; + prefer_zomplex = 0 ; + if (argc > 1) + { + if ((f = fopen (argv [1], "r")) == NULL) + { + my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, + "unable to open file") ; + } + ff = f ; + prefer_zomplex = (argc > 2) ; + } + else + { + f = stdin ; + } + + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- + + cm = &Common ; + cholmod_start (cm) ; + cm->print = 4 ; + + cm->prefer_zomplex = prefer_zomplex ; + + // use default parameter settings, except for the error handler. This + // demo program terminates if an error occurs (out of memory, not positive + // definite, ...). It makes the demo program simpler (no need to check + // CHOLMOD error conditions). This non-default parameter setting has no + // effect on performance. + cm->error_handler = my_handler ; + + // Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by + // default, automatically selecting the latter if flop/nnz(L) < 40. + + //-------------------------------------------------------------------------- + // create basic scalars + //-------------------------------------------------------------------------- + + zero [0] = 0 ; + zero [1] = 0 ; + one [0] = 1 ; + one [1] = 0 ; + minusone [0] = -1 ; + minusone [1] = 0 ; + beta [0] = 1e-6 ; + beta [1] = 0 ; + + //-------------------------------------------------------------------------- + // read in a matrix + //-------------------------------------------------------------------------- + + printf ("\n---------------------------------- cholmod_si_demo:\n") ; + cholmod_version (ver) ; + printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + SuiteSparse_version (ver) ; + printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + A = cholmod_read_sparse2 (f, CHOLMOD_SINGLE, cm) ; + if (ff != NULL) + { + fclose (ff) ; + ff = NULL ; + } + anorm = 1 ; +#ifndef NMATRIXOPS + anorm = cholmod_norm_sparse (A, 0, cm) ; + printf ("norm (A,inf) = %g\n", anorm) ; + printf ("norm (A,1) = %g\n", cholmod_norm_sparse (A, 1, cm)) ; +#endif + + if (prefer_zomplex && A->xtype == CHOLMOD_COMPLEX) + { + // Convert to zomplex, just for testing. In a zomplex matrix, + // the real and imaginary parts are in separate arrays. MATLAB + // uses zomplex matrix exclusively. + cholmod_sparse_xtype (CHOLMOD_ZOMPLEX + A->dtype, A, cm) ; + } + + int xtype = A->xtype ; // real, complex, or zomplex + int dtype = A->dtype ; // single or double + int xdtype = xtype + dtype ; + cholmod_print_sparse (A, "A", cm) ; + + if (A->nrow > A->ncol) + { + // Transpose A so that A'A+beta*I will be factorized instead + cholmod_sparse *C = cholmod_transpose (A, 2, cm) ; + cholmod_free_sparse (&A, cm) ; + A = C ; + printf ("transposing input matrix\n") ; + } + + //-------------------------------------------------------------------------- + // create an arbitrary right-hand-side + //-------------------------------------------------------------------------- + + n = A->nrow ; + xn = n ; + B = cholmod_zeros (n, 1, xdtype, cm) ; + Bx = B->x ; + Bz = B->z ; + +#if GHS + { + // b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments + cholmod_dense *X0 ; + X0 = cholmod_ones (A->ncol, 1, xdtype, cm) ; + cholmod_sdmult (A, 0, one, zero, X0, B, cm) ; + cholmod_free_dense (&X0, cm) ; + } +#else + if (xtype == CHOLMOD_REAL) + { + // real case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Bx [2*i ] = 1 + i / xn ; // real part of B(i) + Bx [2*i+1] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; // real part of B(i) + Bz [i] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } +#endif + + cholmod_print_dense (B, "B", cm) ; + bnorm = 1 ; +#ifndef NMATRIXOPS + bnorm = cholmod_norm_dense (B, 0, cm) ; // max norm + printf ("bnorm %g\n", bnorm) ; +#endif + + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- + + t = CPUTIME ; + L = cholmod_analyze (A, cm) ; + ta = CPUTIME - t ; + ta = MAX (ta, 0) ; + + printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; + + if (A->stype == 0) + { + printf ("Factorizing A*A'+beta*I\n") ; + t = CPUTIME ; + cholmod_factorize_p (A, beta, NULL, 0, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + else + { + printf ("Factorizing A\n") ; + t = CPUTIME ; + cholmod_factorize (A, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + + cholmod_print_factor (L, "L", cm) ; + + // determine the # of integers's and reals's in L. See cholmod_free + if (L->is_super) + { + s = L->nsuper + 1 ; + xsize = L->xsize ; + ss = L->ssize ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + s // L->pi, column pointers for L->s + + s // L->px, column pointers for L->x + + s // L->super, starting column index of each supernode + + ss ; // L->s, the pattern of the supernodes + } + else + { + // this space can increase if you change parameters to their non- + // default values (cm->final_pack, for example). + lnz = L->nzmax ; + xsize = lnz ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + n+1 // L->p, column pointers + + lnz // L->i, integer row indices + + n // L->nz, nz in each column of L + + n+2 // L->next, link list + + n+2 ; // L->prev, link list + } + + // solve with Bset will change L from simplicial to supernodal + rcond = cholmod_rcond (L, cm) ; + L_is_super = L->is_super ; + + //-------------------------------------------------------------------------- + // solve + //-------------------------------------------------------------------------- + + if (n >= 1000) + { + nmethods = 1 ; + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + nmethods = 2 ; + } + else + { + nmethods = 3 ; + } + printf ("nmethods: %d\n", nmethods) ; + + for (method = 0 ; method <= nmethods ; method++) + { + resid [method] = -1 ; // not yet computed + + if (method == 0) + { + // basic solve, just once + t = CPUTIME ; + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + ts [0] = CPUTIME - t ; + ts [0] = MAX (ts [0], 0) ; + } + else if (method == 1) + { + // basic solve, many times, but keep the last one + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + cholmod_free_dense (&X, cm) ; + Bx [0] = 1 + trial / xn ; // tweak B each iteration + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + } + ts [1] = CPUTIME - t ; + ts [1] = MAX (ts [1], 0) / NTRIALS ; + } + else if (method == 2) + { + // solve with reused workspace + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_free_dense (&X, cm) ; + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + Bx [0] = 1 + trial / xn ; // tweak B each iteration + cholmod_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + } + cholmod_free_dense (&Ywork, cm) ; + cholmod_free_dense (&Ework, cm) ; + ts [2] = CPUTIME - t ; + ts [2] = MAX (ts [2], 0) / NTRIALS ; + } + else + { + // solve with reused workspace and sparse Bset + if (xtype == CHOLMOD_ZOMPLEX) continue ; + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_dense *X2 = NULL, *B2 = NULL ; + cholmod_sparse *Bset, *Xset = NULL ; + + double err ; + FILE *timelog = fopen ("timelog.m", "w") ; + if (timelog) fprintf (timelog, "results = [\n") ; + + // xtype is CHOLMOD_REAL or CHOLMOD_COMPLEX, not CHOLMOD_ZOMPLEX + B2 = cholmod_zeros (n, 1, xdtype, cm) ; + B2x = B2->x ; + + Bset = cholmod_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, + CHOLMOD_PATTERN + dtype, cm) ; + Bsetp = Bset->p ; + Bseti = Bset->i ; + Bsetp [0] = 0 ; // nnz(B) is 1 (it can be anything) + Bsetp [1] = 1 ; + resid [3] = 0 ; + + for (i = 0 ; i < MIN (100,n) ; i++) + { + // B (i) is nonzero, all other entries are ignored + // (implied to be zero) + Bseti [0] = i ; + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 3.1 * i + 0.9 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = i + 0.042 ; + B2x [2*i+1] = i - 92.7 ; + } + + // first get the entire solution, to compare against + cholmod_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + + // now get the sparse solutions; this will change L from + // supernodal to simplicial + + if (i == 0) + { + // first solve can be slower because it has to allocate + // space for X2, Xset, etc, and change L. + // So don't time it + cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + // solve Ax=b but only to get x(i). + // b is all zero except for b(i). + // This takes O(xlen) time + cholmod_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + t = CPUTIME - t ; + t = MAX (t, 0) / NTRIALS ; + + // check the solution and log the time + Xsetp = Xset->p ; + Xseti = Xset->i ; + xlen = Xsetp [1] ; + X1x = X->x ; + X2x = X2->x ; + Lnz = L->nz ; + + if (xtype == CHOLMOD_REAL) + { + fl = 2 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 4 * Lnz [j] ; + err = X1x [j] - X2x [j] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + else // (xtype == CHOLMOD_COMPLEX) + { + fl = 16 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 16 * Lnz [j] ; + err = X1x [2*j ] - X2x [2*j ] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + err = X1x [2*j+1] - X2x [2*j+1] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + + if (timelog) fprintf (timelog, "%g %g %g %g\n", + (double) i, (double) xlen, fl, t); + + // clear B for the next test + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 0 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = 0 ; + B2x [2*i+1] = 0 ; + } + } + + if (timelog) + { + fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; + fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; + fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; + fclose (timelog) ; + } + +#ifndef NMATRIXOPS + double xnorm1 = cholmod_norm_dense (X, 1, cm) + ((n==0)?1:0) ; + resid [3] = resid [3] / xnorm1 ; +#endif + + cholmod_free_dense (&Ywork, cm) ; + cholmod_free_dense (&Ework, cm) ; + cholmod_free_dense (&X2, cm) ; + cholmod_free_dense (&B2, cm) ; + cholmod_free_sparse (&Xset, cm) ; + cholmod_free_sparse (&Bset, cm) ; + } + + //---------------------------------------------------------------------- + // compute the residual + //---------------------------------------------------------------------- + + if (method < 3) + { +#ifndef NMATRIXOPS + if (A->stype == 0) + { + // (AA'+beta*I)x=b is the linear system that was solved + // W = A'*X + W = cholmod_allocate_dense (A->ncol, 1, A->ncol, xtype+dtype, + cm) ; + cholmod_sdmult (A, 2, one, zero, X, W, cm) ; + // R = B - beta*X + cholmod_free_dense (&R, cm) ; + R = cholmod_zeros (n, 1, xdtype, cm) ; + Rx = R->x ; + Rz = R->z ; + Xx = X->x ; + Xz = X->z ; + if (xtype == CHOLMOD_REAL) + { + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; + Rx [2*i+1] = Bx [2*i+1] - beta [1] * Xx [2*i+1] ; + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + Rz [i] = Bz [i] - beta [1] * Xz [i] ; + } + } + + // R = A*W - R + cholmod_sdmult (A, 0, one, minusone, W, R, cm) ; + cholmod_free_dense (&W, cm) ; + } + else + { + // Ax=b was factorized and solved, R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + } + rnorm = cholmod_norm_dense (R, 0, cm) ; // max abs. entry + xnorm = cholmod_norm_dense (X, 0, cm) ; // max abs. entry + axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; + resid [method] = rnorm / axbnorm ; +#else + printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + } + } + + tot = ta + tf + ts [0] ; + + //-------------------------------------------------------------------------- + // iterative refinement (real symmetric case only) + //-------------------------------------------------------------------------- + + resid2 = -1 ; +#ifndef NMATRIXOPS + if (A->stype != 0 && A->xtype == CHOLMOD_REAL) + { + cholmod_dense *R2 ; + + // x = A\b + cholmod_free_dense (&X, cm) ; + X = cholmod_solve (CHOLMOD_A, L, B, cm) ; + + // R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + + // R2 = A\(B-A*X) + R2 = cholmod_solve (CHOLMOD_A, L, R, cm) ; + + // compute X = X + A\(B-A*X) + Xx = X->x ; + Rx = R2->x ; + for (i = 0 ; i < n ; i++) + { + Xx [i] = Xx [i] + Rx [i] ; + } + cholmod_free_dense (&R2, cm) ; + + // compute the new residual, R = B-A*X + cholmod_free_dense (&R, cm) ; + R = cholmod_copy_dense (B, cm) ; + cholmod_sdmult (A, 0, minusone, one, X, R, cm) ; + rnorm2 = cholmod_norm_dense (R, 0, cm) ; + resid2 = rnorm2 / axbnorm ; + } +#endif + + cholmod_free_dense (&R, cm) ; + + //-------------------------------------------------------------------------- + // print results + //-------------------------------------------------------------------------- + + anz = cm->anz ; + for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) + { + fl = cm->method [i].fl ; + xlnz = cm->method [i].lnz ; + cm->method [i].fl = -1 ; + cm->method [i].lnz = -1 ; + int ordering = cm->method [i].ordering ; + if (fl >= 0) + { + printf ("Ordering: ") ; + if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; + if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; + if (ordering == CHOLMOD_GIVEN) printf ("user ") ; + if (ordering == CHOLMOD_AMD) printf ("AMD ") ; + if (ordering == CHOLMOD_METIS) printf ("METIS ") ; + if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; + if (xlnz > 0) + { + printf ("fl/lnz %10.1f", fl / xlnz) ; + } + if (anz > 0) + { + printf (" lnz/anz %10.1f", xlnz / anz) ; + } + printf ("\n") ; + } + } + + printf ("ints in L: %15.0f, reals in L: %15.0f\n", + (double) isize, (double) xsize) ; + printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", + cm->fl, cm->lnz) ; + if (A->stype == 0) + { + printf ("nnz(A): %15.0f\n", cm->anz) ; + } + else + { + printf ("nnz(A*A'): %15.0f\n", cm->anz) ; + } + if (cm->lnz > 0) + { + printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; + } + if (anz > 0) + { + printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; + } + printf ("analyze cputime: %12.4f\n", ta) ; + printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, + (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; + printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], + (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; + printf ("overall cputime: %12.4f mflop: %8.1f\n", + tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; + printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], + (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; + printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], + (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; + printf ("peak memory usage: %12.0f (MB)\n", + (double) (cm->memory_usage) / 1048576.) ; + printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; + double maxresid = 0 ; + for (method = 0 ; method <= nmethods ; method++) + { + printf ("%8.2e ", resid [method]) ; + if (isnan (resid [method]) || resid [method] >= 0) + { + maxresid = MAX (maxresid, resid [method]) ; + } + } + printf ("\n") ; + if (isnan (resid2) || resid2 >= 0) + { + printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" + " after iterative refinement\n", resid2) ; + maxresid = MAX (maxresid, resid2) ; + } + printf ("rcond %8.1e\n\n", rcond) ; + + if (L_is_super) + { + cholmod_gpu_stats (cm) ; + } + + cholmod_free_factor (&L, cm) ; + cholmod_free_dense (&X, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and finish CHOLMOD + //-------------------------------------------------------------------------- + + cholmod_free_sparse (&A, cm) ; + cholmod_free_dense (&B, cm) ; + cholmod_finish (cm) ; + + bool ok = !isnan (maxresid) && + maxresid < ((dtype == CHOLMOD_DOUBLE) ? 1e-7 : 1e-4) ; + printf ("maxresid: %g : %s\n", maxresid, + ok ? "All tests passed" : "test failure") ; + fprintf (stderr, "%s maxresid: %10.2g %s : %s\n", + ok ? "OK" : "FAIL", maxresid, + (dtype == CHOLMOD_DOUBLE) ? "(double)" : "(single)", + (argc > 1) ? argv [1] : "stdin") ; + return (ok ? 0 : 1) ; +} + diff --git a/CHOLMOD/Demo/cholmod_si_simple.c b/CHOLMOD/Demo/cholmod_si_simple.c new file mode 100644 index 0000000000..c358d4ca41 --- /dev/null +++ b/CHOLMOD/Demo/cholmod_si_simple.c @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_si_simple: simple demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a real symmetric or complex Hermitian matrix from stdin in +// MatrixMarket format, solve Ax=b where b=[1 1 ... 1]', and print the residual. +// +// Usage: cholmod_si_simple < matrixfile +// +// There are four versions of this demo: +// cholmod_di_simple: double, int32 +// cholmod_dl_simple: double, int64 +// cholmod_si_simple: float, int32 +// cholmod_sl_simple: float, int64 + +#include "cholmod.h" +int main (void) +{ + cholmod_sparse *A ; + cholmod_dense *x, *b, *r ; + cholmod_factor *L ; + double one [2] = {1,0}, m1 [2] = {-1,0} ; // basic scalars + cholmod_common c ; + cholmod_start (&c) ; // start CHOLMOD + int dtype = CHOLMOD_SINGLE ; // use single precision + A = cholmod_read_sparse2 (stdin, dtype, &c) ; // read in a matrix + c.precise = true ; + c.print = (A->nrow > 5) ? 3 : 5 ; + cholmod_print_sparse (A, "A", &c) ; // print the matrix + if (A == NULL || A->stype == 0) // A must be symmetric + { + cholmod_free_sparse (&A, &c) ; + cholmod_finish (&c) ; + return (0) ; + } + b = cholmod_ones (A->nrow, 1, A->xtype + dtype, &c) ; // b = ones(n,1) + + double t1 = SuiteSparse_time ( ) ; + L = cholmod_analyze (A, &c) ; // analyze + t1 = SuiteSparse_time ( ) - t1 ; + double t2 = SuiteSparse_time ( ) ; + cholmod_factorize (A, L, &c) ; // factorize + t2 = SuiteSparse_time ( ) - t2 ; + double t3 = SuiteSparse_time ( ) ; + x = cholmod_solve (CHOLMOD_A, L, b, &c) ; // solve Ax=b + t3 = SuiteSparse_time ( ) - t3 ; + printf ("analyze time: %10.3f sec\n", t1) ; + printf ("factorize time: %10.3f sec\n", t2) ; + printf ("solve time: %10.3f sec\n", t3) ; + printf ("total time: %10.3f sec\n", t1 + t2 + t3) ; + + cholmod_print_factor (L, "L", &c) ; // print the factorization + cholmod_print_dense (x, "x", &c) ; // print the solution + r = cholmod_copy_dense (b, &c) ; // r = b +#ifndef NMATRIXOPS + cholmod_sdmult (A, 0, m1, one, x, r, &c) ; // r = r-Ax + double rnorm = cholmod_norm_dense (r, 0, &c) ; // compute inf-norm of r + double anorm = cholmod_norm_sparse (A, 0, &c) ; // compute inf-norm of A + printf ("\n%s precision results:\n", dtype ? "single" : "double") ; + printf ("norm(b-Ax) %8.1e\n", rnorm) ; + printf ("norm(A) %8.1e\n", anorm) ; + double relresid = rnorm / anorm ; + printf ("resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; + fprintf (stderr, "resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; +#else + printf ("residual norm not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + cholmod_free_factor (&L, &c) ; // free matrices + cholmod_free_sparse (&A, &c) ; + cholmod_free_dense (&r, &c) ; + cholmod_free_dense (&x, &c) ; + cholmod_free_dense (&b, &c) ; + cholmod_print_common ("common", &c) ; + cholmod_gpu_stats (&c) ; + cholmod_finish (&c) ; // finish CHOLMOD + return (0) ; +} + diff --git a/CHOLMOD/Demo/cholmod_simple.c b/CHOLMOD/Demo/cholmod_simple.c deleted file mode 100644 index d305f83a94..0000000000 --- a/CHOLMOD/Demo/cholmod_simple.c +++ /dev/null @@ -1,52 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Demo/cholmod_simple: simple demo program for CHOLMOD -//------------------------------------------------------------------------------ - -// CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis, -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Read in a real symmetric or complex Hermitian matrix from stdin in - * MatrixMarket format, solve Ax=b where b=[1 1 ... 1]', and print the residual. - * Usage: cholmod_simple < matrixfile - */ - -#include "cholmod.h" -int main (void) -{ - cholmod_sparse *A ; - cholmod_dense *x, *b, *r ; - cholmod_factor *L ; - double one [2] = {1,0}, m1 [2] = {-1,0} ; /* basic scalars */ - cholmod_common c ; - cholmod_start (&c) ; /* start CHOLMOD */ - A = cholmod_read_sparse (stdin, &c) ; /* read in a matrix */ - cholmod_print_sparse (A, "A", &c) ; /* print the matrix */ - if (A == NULL || A->stype == 0) /* A must be symmetric */ - { - cholmod_free_sparse (&A, &c) ; - cholmod_finish (&c) ; - return (0) ; - } - b = cholmod_ones (A->nrow, 1, A->xtype, &c) ; /* b = ones(n,1) */ - L = cholmod_analyze (A, &c) ; /* analyze */ - cholmod_factorize (A, L, &c) ; /* factorize */ - x = cholmod_solve (CHOLMOD_A, L, b, &c) ; /* solve Ax=b */ - r = cholmod_copy_dense (b, &c) ; /* r = b */ -#ifndef NMATRIXOPS - cholmod_sdmult (A, 0, m1, one, x, r, &c) ; /* r = r-Ax */ - printf ("norm(b-Ax) %8.1e\n", - cholmod_norm_dense (r, 0, &c)) ; /* print norm(r) */ -#else - printf ("residual norm not computed (requires CHOLMOD/MatrixOps)\n") ; -#endif - cholmod_free_factor (&L, &c) ; /* free matrices */ - cholmod_free_sparse (&A, &c) ; - cholmod_free_dense (&r, &c) ; - cholmod_free_dense (&x, &c) ; - cholmod_free_dense (&b, &c) ; - cholmod_finish (&c) ; /* finish CHOLMOD */ - return (0) ; -} diff --git a/CHOLMOD/Demo/cholmod_sl_demo.c b/CHOLMOD/Demo/cholmod_sl_demo.c new file mode 100644 index 0000000000..71b3ad237f --- /dev/null +++ b/CHOLMOD/Demo/cholmod_sl_demo.c @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_sl_demo: demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a matrix from a file, and use CHOLMOD to solve Ax=b if A is +// symmetric, or (AA'+beta*I)x=b otherwise. The file format is a simple +// triplet format, compatible with most files in the Matrix Market format. +// See cholmod_read.c for more details. The readhb.f program reads a +// Harwell/Boeing matrix (excluding element-types) and converts it into the +// form needed by this program. reade.f reads a matrix in Harwell/Boeing +// finite-element form. +// +// Usage: +// cholmod_sl_demo matrixfile +// cholmod_sl_demo < matrixfile +// +// The matrix is assumed to be positive definite (a supernodal LL' or simplicial +// LDL' factorization is used). +// +// Requires the Utility, Cholesky, MatrixOps, and Check Modules. +// Optionally uses the Partition and Supernodal Modules. +// Does not use the Modify Module. +// +// See cholmod_simple.c for a simpler demo program. +// +// There are 4 versions of this demo: +// +// cholmod_di_demo: double or double complex values, int32_t integers +// cholmod_dl_demo: double or double complex values, int64_t integers +// cholmod_si_demo: float or float complex values, int32_t integers +// cholmod_sl_demo: float or float complex values, int64_t integers + +#include "cholmod_demo.h" +#define NTRIALS 100 + +// ff is a global variable so that it can be closed by my_handler +FILE *ff ; + +// halt if an error occurs +static void my_handler (int status, const char *file, int line, + const char *message) +{ + printf ("cholmod error: file: %s line: %d status: %d: %s\n", + file, line, status, message) ; + if (status < 0) + { + if (ff != NULL) fclose (ff) ; + exit (1) ; + } +} + +int main (int argc, char **argv) +{ + double + resid [4], t, ta, tf, ts [3], tot, bnorm, xnorm, anorm, rnorm, fl, + anz, axbnorm, rnorm2, resid2, rcond, + one [2], zero [2], minusone [2], beta [2], xlnz, + isize, xsize, s, ss, lnz ; + + float + *Bx, *Rx, *Xx, *Bz, *Xz, *Rz, xn, *X1x, *X2x, *B2x ; + int64_t + i, n, *Bsetp, *Bseti, *Xsetp, *Xseti, xlen, j, k, *Lnz ; + + FILE *f ; + cholmod_sparse *A ; + cholmod_dense *X = NULL, *B, *W, *R = NULL ; + cholmod_common Common, *cm ; + cholmod_factor *L ; + int trial, method, L_is_super ; + int ver [3] ; + int prefer_zomplex, nmethods ; + + ts[0] = 0.; + ts[1] = 0.; + ts[2] = 0.; + + //-------------------------------------------------------------------------- + // get the file containing the input matrix + //-------------------------------------------------------------------------- + + ff = NULL ; + prefer_zomplex = 0 ; + if (argc > 1) + { + if ((f = fopen (argv [1], "r")) == NULL) + { + my_handler (CHOLMOD_INVALID, __FILE__, __LINE__, + "unable to open file") ; + } + ff = f ; + prefer_zomplex = (argc > 2) ; + } + else + { + f = stdin ; + } + + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- + + cm = &Common ; + cholmod_l_start (cm) ; + cm->print = 4 ; + + cm->prefer_zomplex = prefer_zomplex ; + + // use default parameter settings, except for the error handler. This + // demo program terminates if an error occurs (out of memory, not positive + // definite, ...). It makes the demo program simpler (no need to check + // CHOLMOD error conditions). This non-default parameter setting has no + // effect on performance. + cm->error_handler = my_handler ; + + // Note that CHOLMOD will do a supernodal LL' or a simplicial LDL' by + // default, automatically selecting the latter if flop/nnz(L) < 40. + + //-------------------------------------------------------------------------- + // create basic scalars + //-------------------------------------------------------------------------- + + zero [0] = 0 ; + zero [1] = 0 ; + one [0] = 1 ; + one [1] = 0 ; + minusone [0] = -1 ; + minusone [1] = 0 ; + beta [0] = 1e-6 ; + beta [1] = 0 ; + + //-------------------------------------------------------------------------- + // read in a matrix + //-------------------------------------------------------------------------- + + printf ("\n---------------------------------- cholmod_sl_demo:\n") ; + cholmod_l_version (ver) ; + printf ("cholmod version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + SuiteSparse_version (ver) ; + printf ("SuiteSparse version %d.%d.%d\n", ver [0], ver [1], ver [2]) ; + A = cholmod_l_read_sparse2 (f, CHOLMOD_SINGLE, cm) ; + if (ff != NULL) + { + fclose (ff) ; + ff = NULL ; + } + anorm = 1 ; +#ifndef NMATRIXOPS + anorm = cholmod_l_norm_sparse (A, 0, cm) ; + printf ("norm (A,inf) = %g\n", anorm) ; + printf ("norm (A,1) = %g\n", cholmod_l_norm_sparse (A, 1, cm)) ; +#endif + + if (prefer_zomplex && A->xtype == CHOLMOD_COMPLEX) + { + // Convert to zomplex, just for testing. In a zomplex matrix, + // the real and imaginary parts are in separate arrays. MATLAB + // uses zomplex matrix exclusively. + cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX + A->dtype, A, cm) ; + } + + int xtype = A->xtype ; // real, complex, or zomplex + int dtype = A->dtype ; // single or double + int xdtype = xtype + dtype ; + cholmod_l_print_sparse (A, "A", cm) ; + + if (A->nrow > A->ncol) + { + // Transpose A so that A'A+beta*I will be factorized instead + cholmod_sparse *C = cholmod_l_transpose (A, 2, cm) ; + cholmod_l_free_sparse (&A, cm) ; + A = C ; + printf ("transposing input matrix\n") ; + } + + //-------------------------------------------------------------------------- + // create an arbitrary right-hand-side + //-------------------------------------------------------------------------- + + n = A->nrow ; + xn = n ; + B = cholmod_l_zeros (n, 1, xdtype, cm) ; + Bx = B->x ; + Bz = B->z ; + +#if GHS + { + // b = A*ones(n,1), used by Gould, Hu, and Scott in their experiments + cholmod_dense *X0 ; + X0 = cholmod_l_ones (A->ncol, 1, xdtype, cm) ; + cholmod_l_sdmult (A, 0, one, zero, X0, B, cm) ; + cholmod_l_free_dense (&X0, cm) ; + } +#else + if (xtype == CHOLMOD_REAL) + { + // real case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Bx [2*i ] = 1 + i / xn ; // real part of B(i) + Bx [2*i+1] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Bx [i] = 1 + i / xn ; // real part of B(i) + Bz [i] = (xn/2 - i) / (3*xn) ; // imag part of B(i) + } + } +#endif + + cholmod_l_print_dense (B, "B", cm) ; + bnorm = 1 ; +#ifndef NMATRIXOPS + bnorm = cholmod_l_norm_dense (B, 0, cm) ; // max norm + printf ("bnorm %g\n", bnorm) ; +#endif + + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- + + t = CPUTIME ; + L = cholmod_l_analyze (A, cm) ; + ta = CPUTIME - t ; + ta = MAX (ta, 0) ; + + printf ("Analyze: flop %g lnz %g\n", cm->fl, cm->lnz) ; + + if (A->stype == 0) + { + printf ("Factorizing A*A'+beta*I\n") ; + t = CPUTIME ; + cholmod_l_factorize_p (A, beta, NULL, 0, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + else + { + printf ("Factorizing A\n") ; + t = CPUTIME ; + cholmod_l_factorize (A, L, cm) ; + tf = CPUTIME - t ; + tf = MAX (tf, 0) ; + } + + cholmod_l_print_factor (L, "L", cm) ; + + // determine the # of integers's and reals's in L. See cholmod_free + if (L->is_super) + { + s = L->nsuper + 1 ; + xsize = L->xsize ; + ss = L->ssize ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + s // L->pi, column pointers for L->s + + s // L->px, column pointers for L->x + + s // L->super, starting column index of each supernode + + ss ; // L->s, the pattern of the supernodes + } + else + { + // this space can increase if you change parameters to their non- + // default values (cm->final_pack, for example). + lnz = L->nzmax ; + xsize = lnz ; + isize = + n // L->Perm + + n // L->ColCount, nz in each column of 'pure' L + + n+1 // L->p, column pointers + + lnz // L->i, integer row indices + + n // L->nz, nz in each column of L + + n+2 // L->next, link list + + n+2 ; // L->prev, link list + } + + // solve with Bset will change L from simplicial to supernodal + rcond = cholmod_l_rcond (L, cm) ; + L_is_super = L->is_super ; + + //-------------------------------------------------------------------------- + // solve + //-------------------------------------------------------------------------- + + if (n >= 1000) + { + nmethods = 1 ; + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + nmethods = 2 ; + } + else + { + nmethods = 3 ; + } + printf ("nmethods: %d\n", nmethods) ; + + for (method = 0 ; method <= nmethods ; method++) + { + resid [method] = -1 ; // not yet computed + + if (method == 0) + { + // basic solve, just once + t = CPUTIME ; + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + ts [0] = CPUTIME - t ; + ts [0] = MAX (ts [0], 0) ; + } + else if (method == 1) + { + // basic solve, many times, but keep the last one + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + cholmod_l_free_dense (&X, cm) ; + Bx [0] = 1 + trial / xn ; // tweak B each iteration + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + } + ts [1] = CPUTIME - t ; + ts [1] = MAX (ts [1], 0) / NTRIALS ; + } + else if (method == 2) + { + // solve with reused workspace + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_l_free_dense (&X, cm) ; + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + Bx [0] = 1 + trial / xn ; // tweak B each iteration + cholmod_l_solve2 (CHOLMOD_A, L, B, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + } + cholmod_l_free_dense (&Ywork, cm) ; + cholmod_l_free_dense (&Ework, cm) ; + ts [2] = CPUTIME - t ; + ts [2] = MAX (ts [2], 0) / NTRIALS ; + } + else + { + // solve with reused workspace and sparse Bset + if (xtype == CHOLMOD_ZOMPLEX) continue ; + cholmod_dense *Ywork = NULL, *Ework = NULL ; + cholmod_dense *X2 = NULL, *B2 = NULL ; + cholmod_sparse *Bset, *Xset = NULL ; + + double err ; + FILE *timelog = fopen ("timelog.m", "w") ; + if (timelog) fprintf (timelog, "results = [\n") ; + + // xtype is CHOLMOD_REAL or CHOLMOD_COMPLEX, not CHOLMOD_ZOMPLEX + B2 = cholmod_l_zeros (n, 1, xdtype, cm) ; + B2x = B2->x ; + + Bset = cholmod_l_allocate_sparse (n, 1, 1, FALSE, TRUE, 0, + CHOLMOD_PATTERN + dtype, cm) ; + Bsetp = Bset->p ; + Bseti = Bset->i ; + Bsetp [0] = 0 ; // nnz(B) is 1 (it can be anything) + Bsetp [1] = 1 ; + resid [3] = 0 ; + + for (i = 0 ; i < MIN (100,n) ; i++) + { + // B (i) is nonzero, all other entries are ignored + // (implied to be zero) + Bseti [0] = i ; + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 3.1 * i + 0.9 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = i + 0.042 ; + B2x [2*i+1] = i - 92.7 ; + } + + // first get the entire solution, to compare against + cholmod_l_solve2 (CHOLMOD_A, L, B2, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + + // now get the sparse solutions; this will change L from + // supernodal to simplicial + + if (i == 0) + { + // first solve can be slower because it has to allocate + // space for X2, Xset, etc, and change L. + // So don't time it + cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + + t = CPUTIME ; + for (trial = 0 ; trial < NTRIALS ; trial++) + { + // solve Ax=b but only to get x(i). + // b is all zero except for b(i). + // This takes O(xlen) time + cholmod_l_solve2 (CHOLMOD_A, L, B2, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + } + t = CPUTIME - t ; + t = MAX (t, 0) / NTRIALS ; + + // check the solution and log the time + Xsetp = Xset->p ; + Xseti = Xset->i ; + xlen = Xsetp [1] ; + X1x = X->x ; + X2x = X2->x ; + Lnz = L->nz ; + + if (xtype == CHOLMOD_REAL) + { + fl = 2 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 4 * Lnz [j] ; + err = X1x [j] - X2x [j] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + else // (xtype == CHOLMOD_COMPLEX) + { + fl = 16 * xlen ; + for (k = 0 ; k < xlen ; k++) + { + j = Xseti [k] ; + fl += 16 * Lnz [j] ; + err = X1x [2*j ] - X2x [2*j ] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + err = X1x [2*j+1] - X2x [2*j+1] ; + err = ABS (err) ; + resid [3] = MAX (resid [3], err) ; + } + } + + if (timelog) fprintf (timelog, "%g %g %g %g\n", + (double) i, (double) xlen, fl, t); + + // clear B for the next test + if (xtype == CHOLMOD_REAL) + { + B2x [i] = 0 ; + } + else // (xtype == CHOLMOD_COMPLEX) + { + B2x [2*i ] = 0 ; + B2x [2*i+1] = 0 ; + } + } + + if (timelog) + { + fprintf (timelog, "] ; resid = %g ;\n", resid [3]) ; + fprintf (timelog, "lnz = %g ;\n", cm->lnz) ; + fprintf (timelog, "t = %g ; %% dense solve time\n", ts [2]) ; + fclose (timelog) ; + } + +#ifndef NMATRIXOPS + double xnorm1 = cholmod_l_norm_dense (X, 1, cm) + ((n==0)?1:0) ; + resid [3] = resid [3] / xnorm1 ; +#endif + + cholmod_l_free_dense (&Ywork, cm) ; + cholmod_l_free_dense (&Ework, cm) ; + cholmod_l_free_dense (&X2, cm) ; + cholmod_l_free_dense (&B2, cm) ; + cholmod_l_free_sparse (&Xset, cm) ; + cholmod_l_free_sparse (&Bset, cm) ; + } + + //---------------------------------------------------------------------- + // compute the residual + //---------------------------------------------------------------------- + + if (method < 3) + { +#ifndef NMATRIXOPS + if (A->stype == 0) + { + // (AA'+beta*I)x=b is the linear system that was solved + // W = A'*X + W = cholmod_l_allocate_dense (A->ncol, 1, A->ncol, xtype+dtype, + cm) ; + cholmod_l_sdmult (A, 2, one, zero, X, W, cm) ; + // R = B - beta*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_zeros (n, 1, xdtype, cm) ; + Rx = R->x ; + Rz = R->z ; + Xx = X->x ; + Xz = X->z ; + if (xtype == CHOLMOD_REAL) + { + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + // complex case + for (i = 0 ; i < n ; i++) + { + Rx [2*i ] = Bx [2*i ] - beta [0] * Xx [2*i ] ; + Rx [2*i+1] = Bx [2*i+1] - beta [1] * Xx [2*i+1] ; + } + } + else // (xtype == CHOLMOD_ZOMPLEX) + { + // zomplex case + for (i = 0 ; i < n ; i++) + { + Rx [i] = Bx [i] - beta [0] * Xx [i] ; + Rz [i] = Bz [i] - beta [1] * Xz [i] ; + } + } + + // R = A*W - R + cholmod_l_sdmult (A, 0, one, minusone, W, R, cm) ; + cholmod_l_free_dense (&W, cm) ; + } + else + { + // Ax=b was factorized and solved, R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + } + rnorm = cholmod_l_norm_dense (R, 0, cm) ; // max abs. entry + xnorm = cholmod_l_norm_dense (X, 0, cm) ; // max abs. entry + axbnorm = (anorm * xnorm + bnorm + ((n == 0) ? 1 : 0)) ; + resid [method] = rnorm / axbnorm ; +#else + printf ("residual not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + } + } + + tot = ta + tf + ts [0] ; + + //-------------------------------------------------------------------------- + // iterative refinement (real symmetric case only) + //-------------------------------------------------------------------------- + + resid2 = -1 ; +#ifndef NMATRIXOPS + if (A->stype != 0 && A->xtype == CHOLMOD_REAL) + { + cholmod_dense *R2 ; + + // x = A\b + cholmod_l_free_dense (&X, cm) ; + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + + // R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + + // R2 = A\(B-A*X) + R2 = cholmod_l_solve (CHOLMOD_A, L, R, cm) ; + + // compute X = X + A\(B-A*X) + Xx = X->x ; + Rx = R2->x ; + for (i = 0 ; i < n ; i++) + { + Xx [i] = Xx [i] + Rx [i] ; + } + cholmod_l_free_dense (&R2, cm) ; + + // compute the new residual, R = B-A*X + cholmod_l_free_dense (&R, cm) ; + R = cholmod_l_copy_dense (B, cm) ; + cholmod_l_sdmult (A, 0, minusone, one, X, R, cm) ; + rnorm2 = cholmod_l_norm_dense (R, 0, cm) ; + resid2 = rnorm2 / axbnorm ; + } +#endif + + cholmod_l_free_dense (&R, cm) ; + + //-------------------------------------------------------------------------- + // print results + //-------------------------------------------------------------------------- + + anz = cm->anz ; + for (i = 0 ; i < CHOLMOD_MAXMETHODS ; i++) + { + fl = cm->method [i].fl ; + xlnz = cm->method [i].lnz ; + cm->method [i].fl = -1 ; + cm->method [i].lnz = -1 ; + int ordering = cm->method [i].ordering ; + if (fl >= 0) + { + printf ("Ordering: ") ; + if (ordering == CHOLMOD_POSTORDERED) printf ("postordered ") ; + if (ordering == CHOLMOD_NATURAL) printf ("natural ") ; + if (ordering == CHOLMOD_GIVEN) printf ("user ") ; + if (ordering == CHOLMOD_AMD) printf ("AMD ") ; + if (ordering == CHOLMOD_METIS) printf ("METIS ") ; + if (ordering == CHOLMOD_NESDIS) printf ("NESDIS ") ; + if (xlnz > 0) + { + printf ("fl/lnz %10.1f", fl / xlnz) ; + } + if (anz > 0) + { + printf (" lnz/anz %10.1f", xlnz / anz) ; + } + printf ("\n") ; + } + } + + printf ("ints in L: %15.0f, reals in L: %15.0f\n", + (double) isize, (double) xsize) ; + printf ("factor flops %g nnz(L) %15.0f (w/no amalgamation)\n", + cm->fl, cm->lnz) ; + if (A->stype == 0) + { + printf ("nnz(A): %15.0f\n", cm->anz) ; + } + else + { + printf ("nnz(A*A'): %15.0f\n", cm->anz) ; + } + if (cm->lnz > 0) + { + printf ("flops / nnz(L): %8.1f\n", cm->fl / cm->lnz) ; + } + if (anz > 0) + { + printf ("nnz(L) / nnz(A): %8.1f\n", cm->lnz / cm->anz) ; + } + printf ("analyze cputime: %12.4f\n", ta) ; + printf ("factor cputime: %12.4f mflop: %8.1f\n", tf, + (tf == 0) ? 0 : (1e-6*cm->fl / tf)) ; + printf ("solve cputime: %12.4f mflop: %8.1f\n", ts [0], + (ts [0] == 0) ? 0 : (1e-6*4*cm->lnz / ts [0])) ; + printf ("overall cputime: %12.4f mflop: %8.1f\n", + tot, (tot == 0) ? 0 : (1e-6 * (cm->fl + 4 * cm->lnz) / tot)) ; + printf ("solve cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [1], + (ts [1] == 0) ? 0 : (1e-6*4*cm->lnz / ts [1]), NTRIALS) ; + printf ("solve2 cputime: %12.4f mflop: %8.1f (%d trials)\n", ts [2], + (ts [2] == 0) ? 0 : (1e-6*4*cm->lnz / ts [2]), NTRIALS) ; + printf ("peak memory usage: %12.0f (MB)\n", + (double) (cm->memory_usage) / 1048576.) ; + printf ("residual (|Ax-b|/(|A||x|+|b|)): ") ; + double maxresid = 0 ; + for (method = 0 ; method <= nmethods ; method++) + { + printf ("%8.2e ", resid [method]) ; + if (isnan (resid [method]) || resid [method] >= 0) + { + maxresid = MAX (maxresid, resid [method]) ; + } + } + printf ("\n") ; + if (isnan (resid2) || resid2 >= 0) + { + printf ("residual %8.1e (|Ax-b|/(|A||x|+|b|))" + " after iterative refinement\n", resid2) ; + maxresid = MAX (maxresid, resid2) ; + } + printf ("rcond %8.1e\n\n", rcond) ; + + if (L_is_super) + { + cholmod_l_gpu_stats (cm) ; + } + + cholmod_l_free_factor (&L, cm) ; + cholmod_l_free_dense (&X, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and finish CHOLMOD + //-------------------------------------------------------------------------- + + cholmod_l_free_sparse (&A, cm) ; + cholmod_l_free_dense (&B, cm) ; + cholmod_l_finish (cm) ; + + bool ok = !isnan (maxresid) && + maxresid < ((dtype == CHOLMOD_DOUBLE) ? 1e-7 : 1e-4) ; + printf ("maxresid: %g : %s\n", maxresid, + ok ? "All tests passed" : "test failure") ; + fprintf (stderr, "%s maxresid: %10.2g %s : %s\n", + ok ? "OK" : "FAIL", maxresid, + (dtype == CHOLMOD_DOUBLE) ? "(double)" : "(single)", + (argc > 1) ? argv [1] : "stdin") ; + return (ok ? 0 : 1) ; +} + diff --git a/CHOLMOD/Demo/cholmod_sl_simple.c b/CHOLMOD/Demo/cholmod_sl_simple.c new file mode 100644 index 0000000000..e4e9f82c0d --- /dev/null +++ b/CHOLMOD/Demo/cholmod_sl_simple.c @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Demo/cholmod_sl_simple: simple demo program for CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a real symmetric or complex Hermitian matrix from stdin in +// MatrixMarket format, solve Ax=b where b=[1 1 ... 1]', and print the residual. +// +// Usage: cholmod_sl_simple < matrixfile +// +// There are four versions of this demo: +// cholmod_di_simple: double, int32 +// cholmod_dl_simple: double, int64 +// cholmod_si_simple: float, int32 +// cholmod_sl_simple: float, int64 + +#include "cholmod.h" +int main (void) +{ + cholmod_sparse *A ; + cholmod_dense *x, *b, *r ; + cholmod_factor *L ; + double one [2] = {1,0}, m1 [2] = {-1,0} ; // basic scalars + cholmod_common c ; + cholmod_l_start (&c) ; // start CHOLMOD + int dtype = CHOLMOD_SINGLE ; // use single precision + A = cholmod_l_read_sparse2 (stdin, dtype, &c) ; // read in a matrix + c.precise = true ; + c.print = (A->nrow > 5) ? 3 : 5 ; + cholmod_l_print_sparse (A, "A", &c) ; // print the matrix + if (A == NULL || A->stype == 0) // A must be symmetric + { + cholmod_l_free_sparse (&A, &c) ; + cholmod_l_finish (&c) ; + return (0) ; + } + b = cholmod_l_ones (A->nrow, 1, A->xtype + dtype, &c) ; // b = ones(n,1) + + double t1 = SuiteSparse_time ( ) ; + L = cholmod_l_analyze (A, &c) ; // analyze + t1 = SuiteSparse_time ( ) - t1 ; + double t2 = SuiteSparse_time ( ) ; + cholmod_l_factorize (A, L, &c) ; // factorize + t2 = SuiteSparse_time ( ) - t2 ; + double t3 = SuiteSparse_time ( ) ; + x = cholmod_l_solve (CHOLMOD_A, L, b, &c) ; // solve Ax=b + t3 = SuiteSparse_time ( ) - t3 ; + printf ("analyze time: %10.3f sec\n", t1) ; + printf ("factorize time: %10.3f sec\n", t2) ; + printf ("solve time: %10.3f sec\n", t3) ; + printf ("total time: %10.3f sec\n", t1 + t2 + t3) ; + + cholmod_l_print_factor (L, "L", &c) ; // print the factorization + cholmod_l_print_dense (x, "x", &c) ; // print the solution + r = cholmod_l_copy_dense (b, &c) ; // r = b +#ifndef NMATRIXOPS + cholmod_l_sdmult (A, 0, m1, one, x, r, &c) ; // r = r-Ax + double rnorm = cholmod_l_norm_dense (r, 0, &c) ; // compute inf-norm of r + double anorm = cholmod_l_norm_sparse (A, 0, &c) ; // compute inf-norm of A + printf ("\n%s precision results:\n", dtype ? "single" : "double") ; + printf ("norm(b-Ax) %8.1e\n", rnorm) ; + printf ("norm(A) %8.1e\n", anorm) ; + double relresid = rnorm / anorm ; + printf ("resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; + fprintf (stderr, "resid: norm(b-Ax)/norm(A) %8.1e\n", relresid) ; +#else + printf ("residual norm not computed (requires CHOLMOD/MatrixOps)\n") ; +#endif + cholmod_l_free_factor (&L, &c) ; // free matrices + cholmod_l_free_sparse (&A, &c) ; + cholmod_l_free_dense (&r, &c) ; + cholmod_l_free_dense (&x, &c) ; + cholmod_l_free_dense (&b, &c) ; + cholmod_l_print_common ("common", &c) ; + cholmod_l_gpu_stats (&c) ; + cholmod_l_finish (&c) ; // finish CHOLMOD + return (0) ; +} + diff --git a/CHOLMOD/Demo/lperf.m b/CHOLMOD/Demo/lperf.m index 934d518434..c1c890b9a2 100644 --- a/CHOLMOD/Demo/lperf.m +++ b/CHOLMOD/Demo/lperf.m @@ -2,7 +2,7 @@ % CHOLMOD/Demo/lperf: test performance of x=A\b in CHOLMOD %------------------------------------------------------------------------------- -% CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis, +% CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis, % All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Doc/CHOLMOD_UserGuide.pdf b/CHOLMOD/Doc/CHOLMOD_UserGuide.pdf index 1c93cf0fdf..dcaa7d383a 100644 Binary files a/CHOLMOD/Doc/CHOLMOD_UserGuide.pdf and b/CHOLMOD/Doc/CHOLMOD_UserGuide.pdf differ diff --git a/CHOLMOD/Doc/CHOLMOD_UserGuide.tex b/CHOLMOD/Doc/CHOLMOD_UserGuide.tex index 6db74a675f..34474a01cf 100644 --- a/CHOLMOD/Doc/CHOLMOD_UserGuide.tex +++ b/CHOLMOD/Doc/CHOLMOD_UserGuide.tex @@ -27,24 +27,21 @@ %------------------------------------------------------------------------------- \begin{abstract} - CHOLMOD\footnote{CHOLMOD is short for CHOLesky MODification, - since a key feature of the package is its ability to update/downdate - a sparse Cholesky factorization} - is a set of routines for factorizing sparse symmetric positive - definite matrices of the form $\m{A}$ or $\m{AA}\tr$, updating/downdating - a sparse Cholesky factorization, solving linear systems, updating/downdating - the solution to the triangular system $\m{Lx}=\m{b}$, and many other sparse - matrix functions for both symmetric and unsymmetric matrices. - Its supernodal Cholesky factorization - relies on LAPACK and the Level-3 BLAS, and obtains a substantial fraction - of the peak performance of the BLAS. Both real and complex matrices - are supported. - It also includes a non-supernodal $\m{LDL}^T$ factorization method - that can factorize symmetric indefinite matrices if all of their - leading submatrices are well-conditioned ($\m{D}$ is diagonal). - CHOLMOD is written in ANSI/ISO C, with both - C and MATLAB interfaces. This code works on Microsoft Windows and many - versions of Unix and Linux. + CHOLMOD\footnote{CHOLMOD is short for CHOLesky MODification, since a key + feature of the package is its ability to update/downdate a sparse Cholesky + factorization} is a set of routines for factorizing sparse symmetric + positive definite matrices of the form $\m{A}$ or $\m{AA}\tr$, + updating/downdating a sparse Cholesky factorization, solving linear + systems, updating/downdating the solution to the triangular system + $\m{Lx}=\m{b}$, and many other sparse matrix functions for both symmetric + and unsymmetric matrices. Its supernodal Cholesky factorization relies on + LAPACK and the Level-3 BLAS, and obtains a substantial fraction of the peak + performance of the BLAS. Both real and complex matrices are supported. It + also includes a non-supernodal $\m{LDL}^T$ factorization method that can + factorize symmetric indefinite matrices if all of their leading submatrices + are well-conditioned ($\m{D}$ is diagonal). CHOLMOD is written in C11, + with both C and MATLAB interfaces. The package works on Linux, Mac, and + Windows. \end{abstract} %------------------------------------------------------------------------------- @@ -66,61 +63,59 @@ \newpage \section{Overview} %------------------------------------------------------------------------------- -CHOLMOD is a set of ANSI C routines for solving systems of linear -equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and symmetric positive definite, -and $\m{x}$ and $\m{b}$ can be either sparse or dense.\footnote{Some support -is provided for symmetric indefinite matrices.} -Complex matrices are supported, in two different formats. -CHOLMOD includes high-performance left-looking supernodal factorization -and solve methods \cite{NgPeyton91b}, -based on LAPACK \cite{LAPACK} and the BLAS \cite{ACM679a}. -After a matrix is factorized, its factors can be updated or downdated using -the techniques described by Davis and Hager -in \cite{DavisHager99,DavisHager01,DavisHager05}. -Many additional sparse matrix operations are provided, for both -symmetric and unsymmetric matrices (square or rectangular), including -sparse matrix multiply, add, transpose, permutation, scaling, -norm, concatenation, sub-matrix access, and converting to alternate data structures. -Interfaces to many ordering methods are provided, including minimum degree -(AMD \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}, -COLAMD \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}), -constrained minimum degree (CSYMAMD, CCOLAMD, CAMD), and -graph-partitioning-based nested dissection (METIS \cite{KarypisKumar98}). -Most of its operations are available within MATLAB via mexFunction interfaces. - - CHOLMOD also includes a non-supernodal $\m{LDL}^T$ factorization method - that can factorize symmetric indefinite matrices if all of their - leading submatrices are well-conditioned ($\m{D}$ is diagonal). +CHOLMOD is a set of ANSI C routines for solving systems of linear equations, +$\m{Ax}=\m{b}$, when $\m{A}$ is sparse and symmetric positive definite, and +$\m{x}$ and $\m{b}$ can be either sparse or dense.\footnote{Some support is +provided for symmetric indefinite matrices.} Complex matrices are supported, in +two different formats. CHOLMOD includes high-performance left-looking +supernodal factorization and solve methods \cite{NgPeyton91b}, based on LAPACK +\cite{LAPACK} and the BLAS \cite{ACM679a}. After a matrix is factorized, its +factors can be updated or downdated using the techniques described by Davis and +Hager in \cite{DavisHager99,DavisHager01,DavisHager05}. Many additional sparse +matrix operations are provided, for both symmetric and unsymmetric matrices +(square or rectangular), including sparse matrix multiply, add, transpose, +permutation, scaling, norm, concatenation, sub-matrix access, and converting to +alternate data structures. My recent GraphBLAS package will typically be +faster for these kinds of operations, however. Interfaces to many ordering +methods are provided, including minimum degree (AMD +\cite{AmestoyDavisDuff96,AmestoyDavisDuff03}, COLAMD +\cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}), constrained +minimum degree (CSYMAMD, CCOLAMD, CAMD), and graph-partitioning-based nested +dissection (METIS \cite{KarypisKumar98}). Most of its operations are available +within MATLAB via mexFunction interfaces. + +CHOLMOD also includes a non-supernodal $\m{LDL}^T$ factorization method that +can factorize symmetric indefinite matrices if all of their leading submatrices +are well-conditioned ($\m{D}$ is diagonal). A pair of articles on CHOLMOD appears in the ACM Transactions on Mathematical Software: \cite{ChenDavisHagerRajamanickam06,DavisHager06}. -CHOLMOD 1.0 replaces {\tt chol} (the sparse case), {\tt symbfact}, and {\tt -etree} in MATLAB 7.2 (R2006a), and is used for {\tt x=A}$\backslash${\tt b} -when {\tt A} is symmetric positive definite \cite{GilbertMolerSchreiber}. It -will replace {\tt sparse} in a future version of MATLAB. +CHOLMOD appears as {\tt chol} (the sparse case), {\tt symbfact}, and {\tt +etree} in MATLAB 7.2 (R2006a) and later, and is used for {\tt +x=A}$\backslash${\tt b} when {\tt A} is symmetric positive definite +\cite{GilbertMolerSchreiber}. -The C-callable CHOLMOD library consists of 133 user-callable routines and one -include file. Each routine comes in two versions, one for {\tt int} integers -and another for {\tt long}. Many of the routines can support either real or +The C-callable CHOLMOD library consists of many user-callable routines and one +include file. Each routine comes in two versions, one for {\tt int32\_t} integers +and another for {\tt int64\_t}. Many of the routines can support either real or complex matrices, simply by passing a matrix of the appropriate type. +All of the routines support both {\tt double} and single ({\tt float}) +precision matrices (this is new in CHOLMOD 5.1). Nick Gould, Yifan Hu, and Jennifer Scott have independently tested CHOLMOD's performance, comparing it with nearly a dozen or so other solvers \cite{GouldHuScott05,GouldHuScott05b}. Its performance was quite competitive. %------------------------------------------------------------------------------- -\newpage \section{Single-precision sparse matrix support} +\section{Single-precision sparse matrix support} %------------------------------------------------------------------------------- -{\bf CHOLMOD v5.0.0}: introduces the first part of support for single - precision sparse matrices, with the introduction of the new - CHOLMOD:Utility Module. The CHOLMOD:Utility Module replaces the - CHOLMOD:Core Module that appeared in prior versions of CHOLMOD. - Single precision is not yet incorporated into the remaining Modules, - however. This feature will be implemented soon in a later version - of CHOLMOD. +{\bf CHOLMOD v5.1.0}: introduces full of support for single precision sparse +matrices, with the introduction of the new CHOLMOD:Utility Module. The +CHOLMOD:Utility Module replaces the CHOLMOD:Core Module that appeared in prior +versions of CHOLMOD. %------------------------------------------------------------------------------- \newpage \section{Primary routines and data structures} @@ -138,9 +133,10 @@ either simplicial (non-supernodal) or supernodal. \item {\tt cholmod\_factorize}: - Numerical factorization, either simplicial or supernodal, $\m{LL}\tr$ or $\m{LDL}\tr$ - using either the symbolic factorization from {\tt cholmod\_analyze} or the numerical - factorization from a prior call to {\tt cholmod\_factorize}. + Numerical factorization, either simplicial or supernodal, $\m{LL}\tr$ or + $\m{LDL}\tr$ using either the symbolic factorization from {\tt + cholmod\_analyze} or the numerical factorization from a prior call to {\tt + cholmod\_factorize}. \item {\tt cholmod\_solve}: Solves $\m{Ax}=\m{b}$, or many other related systems, where $\m{x}$ and @@ -152,95 +148,118 @@ This must be the last call to CHOLMOD. \end{enumerate} -Additional routines are also required to create and destroy -the matrices $\m{A}$, $\m{x}$, $\m{b}$, and the $\m{LL}\tr$ or $\m{LDL}\tr$ factorization. -CHOLMOD has five kinds of data structures, referred to as objects and implemented -as pointers to {\tt struct}'s: +Additional routines are also required to create and destroy the matrices +$\m{A}$, $\m{x}$, $\m{b}$, and the $\m{LL}\tr$ or $\m{LDL}\tr$ factorization. +CHOLMOD has five kinds of data structures, referred to as objects and +implemented as pointers to {\tt struct}'s: \begin{enumerate} \item {\tt cholmod\_common}: parameter settings, statistics, and workspace - used internally by CHOLMOD. - See Section~\ref{cholmod_common} for details. + used internally by CHOLMOD. See Section~\ref{cholmod_common} for details. \item {\tt cholmod\_sparse}: a sparse matrix in compressed-column form, either pattern-only, real, complex, or ``zomplex.'' In its basic form, the matrix {\tt A} contains: \begin{itemize} - \item {\tt A->p}, an integer array of size {\tt A->ncol+1}. - \item {\tt A->i}, an integer array of size {\tt A->nzmax}. - \item {\tt A->x}, a {\tt double} array of size {\tt A->nzmax} or twice that for the complex case. - This is compatible with the Fortran and ANSI C99 complex data type. - \item {\tt A->z}, a {\tt double} array of size {\tt A->nzmax} if {\tt A} is zomplex. - A zomplex matrix has a {\tt z} array, thus the name. - This is compatible with the MATLAB representation of complex matrices. + \item {\tt A->p}, an integer array of size {\tt A->ncol+1}. + \item {\tt A->i}, an integer array of size {\tt A->nzmax}. + \item {\tt A->x}, a {\tt double} or {\tt float} + array of size {\tt A->nzmax} or twice that for the complex case. + This is compatible with the Fortran and ANSI C99 complex data type. + \item {\tt A->z}, a {\tt double} or {\tt float} + array of size {\tt A->nzmax} if {\tt A} is zomplex. A zomplex + matrix has a {\tt z} array, thus the name. This is compatible with + the MATLAB representation of complex matrices. + \item {\tt A->nz}, an integer array of size {\tt A->ncol}, if + {\tt A} is in the {\em unpacked} format. In this format, + the columns of {\tt A} can appear out of order, and gaps of + unused space can appear between columns. \end{itemize} - For all four types of matrices, the row indices of entries of column {\tt j} - are located in {\tt A->i [A->p [j] ... A->p [j+1]-1]}. - For a real matrix, the corresponding numerical values are in {\tt A->x} at the same location. - For a complex matrix, the entry whose row index is {\tt A->i [p]} is contained in - {\tt A->x [2*p]} (the real part) and {\tt A->x [2*p+1]} (the imaginary part). - For a zomplex matrix, the real part is in {\tt A->x [p]} and imaginary part is in {\tt A->z [p]}. - See Section~\ref{cholmod_sparse} for more details. + + For all four types of matrices, the row indices of entries of column {\tt + j} are located in {\tt A->i [A->p [j] ... A->p [j+1]-1]}, or in {\tt A->i + [A->p [j] ... A->p [j] + A->nz [j] -1]}, if in the unpacked format. For a + real matrix, the corresponding numerical values are in {\tt A->x} at the + same location. For a complex matrix, the entry whose row index is {\tt + A->i [p]} is contained in {\tt A->x [2*p]} (the real part) and {\tt A->x + [2*p+1]} (the imaginary part). For a zomplex matrix, the real part is in + {\tt A->x [p]} and imaginary part is in {\tt A->z [p]}. See + Section~\ref{cholmod_sparse} for more details. \item {\tt cholmod\_factor}: - A symbolic or numeric factorization, either real, complex, or zomplex. - It can be either an $\m{LL}\tr$ or $\m{LDL}\tr$ factorization, and either - simplicial or supernodal. You will normally not need to examine its contents. - See Section~\ref{cholmod_factor} for more details. + A symbolic or numeric factorization, either real, complex, or zomplex. It + can be either an $\m{LL}\tr$ or $\m{LDL}\tr$ factorization, and either + simplicial or supernodal. You will normally not need to examine its + contents. See Section~\ref{cholmod_factor} for more details. \item {\tt cholmod\_dense}: A dense matrix, either real, complex or zomplex, in column-major order. - This differs from the row-major convention used in C. A dense matrix {\tt X} contains + This differs from the row-major convention used in C. A dense matrix {\tt + X} contains \begin{itemize} - \item {\tt X->x}, a double array of size {\tt X->nzmax} or twice that for the complex case. - \item {\tt X->z}, a double array of size {\tt X->nzmax} if {\tt X} is zomplex. + + \item {\tt X->x}, a {\tt double} or {\tt float} + array of size {\tt X->nzmax} or twice that for the complex case. + \item {\tt X->z}, a {\tt double} or {\tt float} + array of size {\tt X->nzmax} if {\tt X} is zomplex. \end{itemize} - For a real dense matrix $x_{ij}$ is {\tt X->x [i+j*d]} where {\tt d = X->d} is the leading dimension of {\tt X}. - For a complex dense matrix, the real part of $x_{ij}$ is {\tt X->x [2*(i+j*d)]} and the imaginary part is {\tt X->x [2*(i+j*d)+1]}. - For a zomplex dense matrix, the real part of $x_{ij}$ is {\tt X->x [i+j*d]} and the imaginary part is {\tt X->z [i+j*d]}. - Real and complex dense matrices can be passed to LAPACK and the BLAS. - See Section~\ref{cholmod_dense} for more details. + + For a real dense matrix $x_{ij}$ is {\tt X->x [i+j*d]} where {\tt d = X->d} + is the leading dimension of {\tt X}. For a complex dense matrix, the real + part of $x_{ij}$ is {\tt X->x [2*(i+j*d)]} and the imaginary part is {\tt + X->x [2*(i+j*d)+1]}. For a zomplex dense matrix, the real part of $x_{ij}$ + is {\tt X->x [i+j*d]} and the imaginary part is {\tt X->z [i+j*d]}. Real + and complex dense matrices can be passed to LAPACK and the BLAS. See + Section~\ref{cholmod_dense} for more details. \item {\tt cholmod\_triplet}: - CHOLMOD's sparse matrix ({\tt cholmod\_sparse}) is the primary input for nearly all CHOLMOD - routines, but it can be difficult for the user to construct. - A simpler method of creating a sparse matrix is to first create a {\tt cholmod\_triplet} matrix, - and then convert it to a {\tt cholmod\_sparse} matrix via - the {\tt cholmod\_triplet\_to\_sparse} routine. + CHOLMOD's sparse matrix ({\tt cholmod\_sparse}) is the primary input for + nearly all CHOLMOD routines, but it can be difficult for the user to + construct. A simpler method of creating a sparse matrix is to first create + a {\tt cholmod\_triplet} matrix, and then convert it to a {\tt + cholmod\_sparse} matrix via the {\tt cholmod\_triplet\_to\_sparse} routine. In its basic form, the triplet matrix {\tt T} contains + \begin{itemize} - \item {\tt T->i} and {\tt T->j}, integer arrays of size {\tt T->nzmax}. - \item {\tt T->x}, a double array of size {\tt T->nzmax} or twice that for the complex case. - \item {\tt T->z}, a double array of size {\tt T->nzmax} if {\tt T} is zomplex. + \item {\tt T->i} and {\tt T->j}, integer arrays of size {\tt T->nzmax}. + \item {\tt T->x}, a {\tt double} or {\tt float} + array of size {\tt T->nzmax} or twice that for the complex case. + \item {\tt T->z}, a {\tt double} or {\tt float} + array of size {\tt T->nzmax} if {\tt T} is zomplex. \end{itemize} - The {\tt k}th entry in the data structure has row index - {\tt T->i [k]} and column index {\tt T->j [k]}. - For a real triplet matrix, its numerical value is {\tt T->x [k]}. - For a complex triplet matrix, its real part is {\tt T->x [2*k]} and its imaginary part is {\tt T->x [2*k+1]}. - For a zomplex matrix, the real part is {\tt T->x [k]} and imaginary part is {\tt T->z [k]}. - The entries can be in any order, and duplicates are permitted. + + The {\tt k}th entry in the data structure has row index {\tt T->i [k]} and + column index {\tt T->j [k]}. For a real triplet matrix, its numerical + value is {\tt T->x [k]}. For a complex triplet matrix, its real part is + {\tt T->x [2*k]} and its imaginary part is {\tt T->x [2*k+1]}. For a + zomplex matrix, the real part is {\tt T->x [k]} and imaginary part is {\tt + T->z [k]}. The entries can be in any order, and duplicates are permitted. See Section~\ref{cholmod_triplet} for more details. \end{enumerate} Each of the five objects has a routine in CHOLMOD to create and destroy it. -CHOLMOD provides many other operations on these objects as well. -A few of the most important ones are illustrated in the sample program in the -next section. +CHOLMOD provides many other operations on these objects as well. A few of the +most important ones are illustrated in the sample program in the next section. %------------------------------------------------------------------------------- \newpage \section{Simple example program} %------------------------------------------------------------------------------- \input{_simple.tex} -The {\tt Demo/cholmod\_simple.c} program illustrates the -basic usage of CHOLMOD. It reads a triplet matrix from a file -(in Matrix Market format), converts it into a sparse matrix, -creates a linear system, solves it, and prints the norm of the residual. +The {\tt Demo/cholmod\_*\_simple.c} programs illustrate the basic usage of +CHOLMOD. Each of them reads a triplet matrix from a file (in Matrix Market +format), convert it into a sparse matrix, creates a linear system, solves it, +and prints the norm of the residual. See the {\tt +CHOLMOD/Demo/cholmod\_*\_demo.c} program for a more elaborate example. These +two sets of programs come in four variants: -See the {\tt CHOLMOD/Demo/cholmod\_demo.c} program for a more elaborate -example, and \newline -{\tt CHOLMOD/Demo/cholmod\_l\_demo.c} for its {\tt long} integer version. + \begin{itemize} + \item di: {\tt double} values, {\tt int32\_t} integers. + \item dl: {\tt double} values, {\tt int64\_t} integers. + \item si: {\tt float} values, {\tt int32\_t} integers. + \item sl: {\tt float} values, {\tt int64\_t} integers. + \end{itemize} %------------------------------------------------------------------------------- \newpage \section{Installation of the C-callable library} @@ -248,7 +267,9 @@ %------------------------------------------------------------------------------- CHOLMOD requires a suite of external packages, many of which are distributed -along with CHOLMOD, but three of which are not. Those included with CHOLMOD are: +along with CHOLMOD, but three of which are not. Those included with CHOLMOD +are: + \begin{itemize} \item AMD: an approximate minimum degree ordering algorithm, by Tim Davis, Patrick Amestoy, and Iain Duff @@ -257,36 +278,27 @@ by Tim Davis, Stefan Larimore, John Gilbert, and Esmond Ng \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}. \item CCOLAMD: a constrained approximate column minimum degree ordering - algorithm, - by Tim Davis and Siva Rajamanickam, based directly on COLAMD. - This package is not required if CHOLMOD is compiled with the - {\tt -DNCAMD} flag. -\item CAMD: a constrained approximate minimum degree ordering - algorithm, - by Tim Davis and Yanqing Chen, based directly on AMD. - This package is not required if CHOLMOD is compiled with the - {\tt -DNCAMD} flag. -\item {\tt SuiteSparse\_config}: - a single place where all sparse matrix packages authored - or co-authored by Davis are configured. + algorithm, by Tim Davis and Siva Rajamanickam, based directly on COLAMD. + This package is not required if CHOLMOD is compiled with the {\tt -DNCAMD} + flag. +\item CAMD: a constrained approximate minimum degree ordering algorithm, by Tim + Davis and Yanqing Chen, based directly on AMD. This package is not + required if CHOLMOD is compiled with the {\tt -DNCAMD} flag. +\item {\tt SuiteSparse\_config}: a single place where all sparse matrix + packages authored or co-authored by Davis are configured. +\item {\tt METIS 5.1.0}: a graph partitioning package by George Karypis, + Univ. of Minnesota. A slightly revised copy appears in + {\tt CHOLMOD/SuiteSparse\_metis}. Not needed if {\tt -DNPARTITION} is + used. See http://www-users.cs.umn.edu/$\sim$karypis/metis. \end{itemize} Three other packages are required for optimal performance: \begin{itemize} -\item {\tt METIS 5.1.0}: a graph partitioning package by George Karypis, - Univ. of Minnesota. Not needed if {\tt -DNPARTITION} is used. - See http://www-users.cs.umn.edu/$\sim$karypis/metis. + \item BLAS: the Basic Linear Algebra Subprograms. Not needed if {\tt -DNSUPERNODAL} is used. See http://www.netlib.org for the reference BLAS (not meant for production - use). For Kazushige Goto's optimized BLAS (highly recommended for CHOLMOD) - see \newline - http://www.tacc.utexas.edu/$\sim$kgoto/ or - http://www.cs.utexas.edu/users/flame/goto/. - I recommend that you avoid the Intel MKL BLAS; one recent - version returns NaN's, where both the Goto BLAS and the standard - Fortran reference BLAS return the correct answer. - See {\tt CHOLMOD/README} for more information. + use). I recommend the Intel MKL BLAS. \item LAPACK: the Basic Linear Algebra Subprograms. Not needed if {\tt -DNSUPERNODAL} is used. See http://www.netlib.org. @@ -295,12 +307,11 @@ \end{itemize} You must first obtain and install LAPACK, and the BLAS. -METIS 5.1.0 is optional; a copy of it is in {\tt SuiteSparse\_metis}. \noindent -CHOLMOD's specific settings are given by the {\tt CHOLMOD\_CONFIG} string: +CHOLMOD's specific settings are revised by the following compile-time flags: \begin{itemize} -\item {\tt -DNCHECK}: do not include the Check module. +\item {\tt -DNCHECK}: do not include the Check module. \item {\tt -DNCHOLESKY}: do not include the Cholesky module. \item {\tt -DNPARTITION}: do not include the interface to METIS in the Partition module. @@ -308,39 +319,30 @@ and CSYMAMD in the Partition module. \item {\tt -DNMATRIXOPS}: do not include the MatrixOps module. Note that the Demo requires the MatrixOps module. -\item {\tt -DNMODIFY}: do not include the Modify module. +\item {\tt -DNMODIFY}: do not include the Modify module. \item {\tt -DNSUPERNODAL}: do not include the Supernodal module. -\item {\tt -DNPRINT}: do not print anything. +\item {\tt -DNPRINT}: do not print anything. \end{itemize} -SuiteSparse now has a complete \verb'cmake'-based build system. -Each package (SuiteSparse\_congig, AMD, CAMD, CCOLAMD, CAMD, and CHOLMOD) has its own -\verb'CMakeLists.txt'. Use \verb'cmake' to build each package in -that order. +SuiteSparse now has a complete \verb'cmake'-based build system. Each package +(SuiteSparse\_congig, AMD, CAMD, CCOLAMD, CAMD, and CHOLMOD) has its own +\verb'CMakeLists.txt'. Use \verb'cmake' to build each package in that order. An optional \verb'Makefile' is provided at the top-level of \verb'SuiteSparse' -Type {\tt make} in that directory. The AMD, -COLAMD, CAMD, CCOLAMD, and {\tt CHOLMOD} libraries will be compiled. -To compile and run demo programs for each package, -type \verb'make demos'. For CHOLMOD, the residuals should all be small. - -CHOLMOD is now ready for use in your own applications. You must link -your programs with the -{\tt libcholmod.*}, -{\tt libamd.*}, -{\tt libcolamd.*}, -LAPACK, -and -BLAS libraries. -Unless {\tt -DNCAMD} is present at compile time, -you must link with {\tt CAMD/libcamd.*}, and {\tt CCOLAMD/libccolamd.*}. -Each library has its own \verb'Find*.cmake' script to use in -the \verb'cmake' +Type {\tt make} in that directory. The AMD, COLAMD, CAMD, CCOLAMD, and {\tt +CHOLMOD} libraries will be compiled. To compile and run demo programs for each +package, type \verb'make demos'. For CHOLMOD, the residuals should all be +small. + +CHOLMOD is now ready for use in your own applications. You must link your +programs with the {\tt libcholmod.*}, {\tt libamd.*}, {\tt libcolamd.*}, +LAPACK, and BLAS libraries. Unless {\tt -DNCAMD} is present at compile time, +you must link with {\tt CAMD/libcamd.*}, and {\tt CCOLAMD/libccolamd.*}. Each +library has its own \verb'Find*.cmake' script to use in the \verb'cmake' \verb'find_library' command. -To install CHOLMOD in default locations use -{\tt make install}. -To remove CHOLMOD, do {\tt make uninstall}. +To install CHOLMOD in default locations use {\tt make install}. To remove +CHOLMOD, do {\tt make uninstall}. %------------------------------------------------------------------------------- \newpage \section{Using CHOLMOD in MATLAB} @@ -352,70 +354,105 @@ \vspace{0.1in} \begin{tabular}{ll} \hline -{\tt analyze} & order and analyze a matrix \\ -{\tt bisect} & find a node separator \\ -{\tt chol2} & same as {\tt chol} \\ -{\tt cholmod2} & same as {\tt x=A}$\backslash${\tt b} if {\tt A} is symmetric positive definite \\ +{\tt analyze} & order and analyze a matrix \\ +{\tt bisect} & find a node separator \\ +{\tt chol2} & same as {\tt chol} \\ +{\tt cholmod2} & same as \verb'x=A\b' \verb'A' is symmetric positive + definite \\ {\tt cholmod\_demo} & a short demo program \\ {\tt cholmod\_make} & compiles CHOLMOD for use in MATLAB \\ -{\tt etree2} & same as {\tt etree} \\ +{\tt etree2} & same as {\tt etree} \\ {\tt graph\_demo} & graph partitioning demo \\ -{\tt lchol} & {\tt L*L'} factorization \\ -{\tt ldlchol} & {\tt L*D*L'} factorization \\ +{\tt lchol} & {\tt L*L'} factorization \\ +{\tt ldlchol} & {\tt L*D*L'} factorization \\ {\tt ldl\_normest} & estimate {\tt norm(A-L*D*L')} \\ -{\tt ldlsolve} & {\tt x = L'}$\backslash${\tt (D}$\backslash${\tt (L}$\backslash${\tt b))} \\ -{\tt ldlsplit} & split the output of {\tt ldlchol} into {\tt L} and {\tt D} \\ -{\tt ldlupdate} & update/downdate an {\tt L*D*L'} factorization \\ -{\tt ldlrowmod} & add/delete a row from an {\tt L*D*L'} factorization \\ -{\tt metis} & interface to {\tt METIS\_NodeND} ordering \\ -{\tt mread} & read a sparse or dense Matrix Market file \\ -{\tt mwrite} & write a sparse or dense Matrix Market file \\ -{\tt nesdis} & CHOLMOD's nested dissection ordering \\ -{\tt resymbol} & recomputes the symbolic factorization \\ -{\tt sdmult} & {\tt S*F} where {\tt S} is sparse and {\tt F} is dense \\ -{\tt spsym} & determine symmetry \\ -{\tt sparse2} & same as {\tt sparse} \\ -{\tt symbfact2} & same as {\tt symbfact} \\ +{\tt ldlsolve} & \verb"x = L'\ (D \(L \ b))" \\ +{\tt ldlsplit} & split the output of {\tt ldlchol} into {\tt L} and + {\tt D} \\ +{\tt ldlupdate} & update/downdate an {\tt L*D*L'} factorization \\ +{\tt ldlrowmod} & add/delete a row from an {\tt L*D*L'} factorization \\ +{\tt metis} & interface to {\tt METIS\_NodeND} ordering \\ +{\tt mread} & read a sparse or dense Matrix Market file \\ +{\tt mwrite} & write a sparse or dense Matrix Market file \\ +{\tt nesdis} & CHOLMOD's nested dissection ordering \\ +{\tt resymbol} & recomputes the symbolic factorization \\ +{\tt sdmult} & {\tt S*F} where {\tt S} is sparse and {\tt F} is dense \\ +{\tt spsym} & determine symmetry \\ +{\tt symbfact2} & same as {\tt symbfact} \\ \hline \end{tabular} \vspace{0.1in}\noindent Each function is described in the next sections. -\newpage -\subsection{{\tt analyze}: order and analyze} \input{_analyze_m.tex} -\subsection{{\tt bisect}: find a node separator} \input{_bisect_m.tex} -\subsection{{\tt chol2}: same as {\tt chol}} \input{_chol2_m.tex} -\subsection{{\tt cholmod2}: supernodal backslash} \input{_cholmod2_m.tex} -\newpage -\subsection{{\tt cholmod\_demo}: a short demo program} \input{_cholmod_demo_m.tex} -\subsection{{\tt cholmod\_make}: compile CHOLMOD in MATLAB} \input{_cholmod_make_m.tex} -\newpage -\subsection{{\tt etree2}: same as {\tt etree}} \input{_etree2_m.tex} -\subsection{{\tt graph\_demo}: graph partitioning demo} \input{_graph_demo_m.tex} -\subsection{{\tt lchol}: $\m{LL}\tr$ factorization} \input{_lchol_m.tex} -\subsection{{\tt ldlchol}: $\m{LDL}\tr$ factorization} \input{_ldlchol_m.tex} -\subsection{{\tt ldlsolve}: solve using an $\m{LDL}\tr$ factorization} \input{_ldlsolve_m.tex} -\subsection{{\tt ldlsplit}: split an $\m{LDL}\tr$ factorization} \input{_ldlsplit_m.tex} -\subsection{{\tt ldlupdate}: update/downdate an $\m{LDL}\tr$ factorization} \input{_ldlupdate_m.tex} -\newpage -\subsection{{\tt ldlrowmod}: add/delete a row from an $\m{LDL}\tr$ factorization} \input{_ldlrowmod_m.tex} -\newpage -\subsection{{\tt mread}: read a sparse or dense matrix from a Matrix Market file}\input{_mread_m.tex} -\subsection{{\tt mwrite}: write a sparse or dense matrix to a Matrix Market file} \input{_mwrite_m.tex} -\newpage -\subsection{{\tt metis}: order with METIS} \input{_metis_m.tex} -\newpage -\subsection{{\tt nesdis}: order with CHOLMOD nested dissection} \input{_nesdis_m.tex} -\newpage -\subsection{{\tt resymbol}: re-do symbolic factorization} \input{_resymbol_m.tex} -\subsection{{\tt sdmult}: sparse matrix times dense matrix} \input{_sdmult_m.tex} -\newpage -\subsection{{\tt spsym}: determine symmetry} \input{_spsym_m.tex} -\newpage -\subsection{{\tt sparse2}: same as {\tt sparse}} \input{_sparse2_m.tex} -\newpage -\subsection{{\tt symbfact2}: same as {\tt symbfact}} \input{_symbfact2_m.tex} +\subsection{{\tt analyze}: order and analyze} +\input{_analyze_m.tex} + +\subsection{{\tt bisect}: find a node separator} +\input{_bisect_m.tex} + +\subsection{{\tt chol2}: same as {\tt chol}} +\input{_chol2_m.tex} + +\subsection{{\tt cholmod2}: supernodal backslash} +\input{_cholmod2_m.tex} + +\subsection{{\tt cholmod\_demo}: a short demo program} +\input{_cholmod_demo_m.tex} + +\subsection{{\tt cholmod\_make}: compile CHOLMOD in MATLAB} +\input{_cholmod_make_m.tex} + +\subsection{{\tt etree2}: same as {\tt etree}} +\input{_etree2_m.tex} + +\subsection{{\tt graph\_demo}: graph partitioning demo} +\input{_graph_demo_m.tex} + +\subsection{{\tt lchol}: $\m{LL}\tr$ factorization} +\input{_lchol_m.tex} + +\subsection{{\tt ldlchol}: $\m{LDL}\tr$ factorization} +\input{_ldlchol_m.tex} + +\subsection{{\tt ldlsolve}: solve using an $\m{LDL}\tr$ factorization} +\input{_ldlsolve_m.tex} + +\subsection{{\tt ldlsplit}: split an $\m{LDL}\tr$ factorization} +\input{_ldlsplit_m.tex} + +\subsection{{\tt ldlupdate}: update/downdate an $\m{LDL}\tr$ factorization} +\input{_ldlupdate_m.tex} + +\subsection{{\tt ldlrowmod}: add/delete a row from an $\m{LDL}\tr$ +factorization} +\input{_ldlrowmod_m.tex} + +\subsection{{\tt mread}: read a sparse or dense matrix from a Matrix Market +file} +\input{_mread_m.tex} + +\subsection{{\tt mwrite}: write a sparse or dense matrix to a Matrix Market +file} +\input{_mwrite_m.tex} + +\subsection{{\tt metis}: order with METIS} +\input{_metis_m.tex} + +\subsection{{\tt nesdis}: order with CHOLMOD nested dissection} +\input{_nesdis_m.tex} + +\subsection{{\tt resymbol}: re-do symbolic factorization} +\input{_resymbol_m.tex} + +\subsection{{\tt sdmult}: sparse matrix times dense matrix} +\input{_sdmult_m.tex} + +\subsection{{\tt spsym}: determine symmetry} +\input{_spsym_m.tex} + +\subsection{{\tt symbfact2}: same as {\tt symbfact}} +\input{_symbfact2_m.tex} %------------------------------------------------------------------------------- \newpage \section{Installation for use in MATLAB} @@ -425,21 +462,17 @@ \subsection{{\tt symbfact2}: same as {\tt symbfact}} \input{_symbfact2_m.tex} \subsection{{\tt cholmod\_make}: compiling CHOLMOD in MATLAB} %------------------------------------------------------------------------------- -This is the preferred method, since it allows METIS to be reconfigured to -use the MATLAB memory-management functions instead of {\tt malloc} and {\tt free}; -this avoids the issue of METIS terminating MATLAB if it runs out of memory. - Start MATLAB, {\tt cd} to the {\tt CHOLMOD/MATLAB} directory, and type {\tt cholmod\_make} in the MATLAB command window. This will compile -the MATLAB interfaces for AMD, COLAMD, CAMD, CCOLAMD, METIS, and CHOLMOD. +the MATLAB interfaces for METIS and CHOLMOD. %------------------------------------------------------------------------------- \section{Using CHOLMOD with OpenMP acceleration} %------------------------------------------------------------------------------- -CHOLMOD includes OpenMP acceleration for some operations. -In CHOLMOD versions prior to v6.0.0, the number of threads to use was controlled -by a compile time parameter. This is now replaced with run-time controls. +CHOLMOD includes OpenMP acceleration for some operations. In CHOLMOD versions +prior to v6.0.0, the number of threads to use was controlled by a compile time +parameter. This is now replaced with run-time controls. \verb'Common->nthreads_max' defaults to \verb'omp_get_max_threads()', or 1 if OpenMP is not in use. This value controls the maximum number of threads that @@ -468,15 +501,17 @@ \section{Using CHOLMOD with GPU acceleration} GPU that supports CUDA and has at least 64MB of memory. (But substantially more memory, typically about 3 GB, is recommended for best performance.) -Only the {\tt long} integer version of CHOLMOD can leverage GPU acceleration. +Only the ({\tt double}, {\tt int64\_t}) version of CHOLMOD can leverage GPU +acceleration (both real and complex). %------------------------------------------------------------------------------- \subsection{Compiling CHOLMOD with GPU support} %------------------------------------------------------------------------------- In order to support GPU processing, CHOLMOD must be compiled with the -preprocessor macro \verb'ENABLE_CUDA' defined. It is enabled by default -but can be disabled by setting this to false when using cmake. +preprocessor macro \verb'SUITESPARSE_CUDA' defined. It is enabled by default +in {\tt cmake} if you have a GPU, but this can be disabled by setting this to +false when using cmake. %------------------------------------------------------------------------------- \subsection{Enabling GPU acceleration in CHOLMOD} @@ -538,7 +573,7 @@ \subsection{Adjustable parameters} {\tt CHOLMOD\_GPU\_SKIP} : Number of small descendant supernodes to assembled on the CPU before querying if the GPU is needs more descendant supernodes - queued + queued. \end{quote} @@ -574,11 +609,13 @@ \subsection{Adjustable parameters} \begin{quote} {\tt CHOLMOD\_GPU\_MEM\_BYTES} : Environment variable with a meaning - equivalent to {\tt Common->maxGpuMemBytes}. This will only be queried if + equivalent to \newline + {\tt Common->maxGpuMemBytes}. This will only be queried if {\tt Common->useGPU = -1}. {\tt CHOLMOD\_GPU\_MEM\_FRACTION} : Environment variable with a meaning - equivalent to {\tt Common->maxGpuMemFraction}. This will only be queried if + equivalent to \newline + {\tt Common->maxGpuMemFraction}. This will only be queried if {\tt Common->useGPU = -1}. \end{quote} @@ -587,133 +624,159 @@ \subsection{Adjustable parameters} \newpage \section{Integer and floating-point types, and notation used} %------------------------------------------------------------------------------- -CHOLMOD supports both {\tt int} and {\tt long} integers. CHOLMOD -routines with the prefix {\tt cholmod\_} use {\tt int} integers, -{\tt cholmod\_l\_} routines use {\tt long}. All floating-point -values are {\tt double}. - -The {\tt long} integer is redefinable, via {\tt SuiteSparse\_config.h}. -That file defines a C preprocessor token {\tt SuiteSparse\_long} which is -{\tt long} on all systems except for Windows-64, in which case it is -defined as {\tt \_\_int64}. The intent is that with suitable compile-time -switches, {\tt int} is a 32-bit integer and {\tt SuiteSparse\_long} is a 64-bit -integer. The term {\tt long} is used to describe the latter -integer throughout this document (except in the prototypes). - -Two kinds of complex matrices are supported: complex and zomplex. -A complex matrix is held in a manner that is compatible with the -Fortran and ANSI C99 complex data type. A complex array of size {\tt n} -is a {\tt double} array {\tt x} of size {\tt 2*n}, with the real and imaginary -parts interleaved (the real part comes first, as a {\tt double}, followed the -imaginary part, also as a {\tt double}. Thus, the real part of the {\tt k}th -entry is {\tt x[2*k]} and the imaginary part is {\tt x[2*k+1]}. - -A zomplex matrix of size {\tt n} stores its real part in one -{\tt double} array of size {\tt n} called {\tt x} and its imaginary part -in another {\tt double} array of size {\tt n} called {\tt z} (thus the -name ``zomplex''). This also how MATLAB stores its complex matrices. -The real part of the {\tt k}th entry is {\tt x[k]} and the imaginary part is -{\tt z[k]}. - -Unlike {\tt UMFPACK}, the same routine name in CHOLMOD is used for pattern-only, -real, complex, and zomplex matrices. For example, the statement +CHOLMOD supports both {\tt int32\_t} and {\tt int64\_t} integers. CHOLMOD +routines with the prefix {\tt cholmod\_} use {\tt int32\_t} integers, +{\tt cholmod\_l\_} routines use {\tt int64\_t}. Floating-point +values are {\tt double} or {\tt float}, depending on the {\tt A->dtype} +field for a sparse matrix, triplet matrix, dense matrix, or factorization +object. + +Two kinds of complex matrices are supported: complex and zomplex. A complex +matrix is held in a manner that is compatible with the Fortran and ANSI C99 +complex data type. A complex array of size {\tt n} is a {\tt double} or {\tt +float} array {\tt x} of size {\tt 2*n}, with the real and imaginary parts +interleaved, with the real part comes first, as a {\tt double} or {\tt float} +followed the imaginary part, also as a {\tt double} or {\tt float}. Thus, the +real part of the {\tt k}th entry is {\tt x[2*k]} and the imaginary part is {\tt +x[2*k+1]}. + +A zomplex matrix of size {\tt n} stores its real part in one {\tt double} or +{\tt float} array of size {\tt n} called {\tt x} and its imaginary part in +another {\tt double} or {\tt float} array of size {\tt n} called {\tt z} (thus +the name ``zomplex''). This also how MATLAB stored its complex matrices in +R2017b and earlier. The real part of the {\tt k}th entry is {\tt x[k]} and the +imaginary part is {\tt z[k]}. In MATLAB R2018a, complex matrices are stored +in the standard interleaved format. The CHOLMOD MATLAB interface uses this, +and thus requires MATLAB R2018a or later. + +Unlike {\tt UMFPACK}, the same routine name in CHOLMOD is used for +pattern-only, real, complex, and zomplex matrices, and also for both +{\tt double} and {\tt float} values. For example, the statement + \begin{verbatim} C = cholmod_copy_sparse (A, &Common) ; \end{verbatim} + creates a copy of a pattern, real, complex, or zomplex sparse matrix {\tt A}. -The xtype (pattern, real, complex, or zomplex) of the resulting sparse matrix {\tt C} -is the same as {\tt A} (a pattern-only sparse matrix contains no floating-point -values). In the above case, {\tt C} and {\tt A} use {\tt int} integers. -For {\tt long} integers, the statement would become: +The xtype (pattern, real, complex, or zomplex) of the resulting sparse matrix +{\tt C} is the same as {\tt A} (a pattern-only sparse matrix contains no +floating-point values). In the above case, {\tt C} and {\tt A} use {\tt int32\_t} +integers. For {\tt int64\_t} integers, the statement would become: + \begin{verbatim} C = cholmod_l_copy_sparse (A, &Common) ; \end{verbatim} -The last parameter of all CHOLMOD routines is always {\tt \&Common}, -a pointer to the -{\tt cholmod\_common} object, which contains parameters, statistics, -and workspace used throughout CHOLMOD. -The {\tt xtype} of a CHOLMOD object (sparse matrix, triplet matrix, dense -matrix, or factorization) determines whether it is pattern-only, -real, complex, or zomplex. +The last parameter of all CHOLMOD routines is always {\tt \&Common}, a pointer +to the {\tt cholmod\_common} object, which contains parameters, statistics, and +workspace used throughout CHOLMOD. -The names of the {\tt int} versions are primarily used in this document. -To obtain the name of the {\tt long} version of the same routine, simply +The {\tt xtype} of a CHOLMOD object (sparse matrix, triplet matrix, dense +matrix, or factorization) determines whether it is pattern-only, real, complex, +or zomplex. The {\tt dtype} of a CHOLMOD object (sparse matrix, triplet +matrix, dense matrix, or factorization) determines whether it is {\tt double} +or {\tt float}. These two terms are often added together when passing +parameters to CHOLMOD, as {\tt xtype + dtype}. This API design was chosen +for backward compatibility with CHOLMOD 4.x and earlier. + +The names of the {\tt int32\_t} versions are primarily used in this document. To +obtain the name of the {\tt int64\_t} version of the same routine, simply replace {\tt cholmod\_} with {\tt cholmod\_l\_}. -MATLAB matrix notation is used throughout this document and in -the comments in the CHOLMOD code itself. If you are not familiar with -MATLAB, here is a short introduction to the notation, and a few -minor variations used in CHOLMOD: +MATLAB matrix notation is used throughout this document and in the comments in +the CHOLMOD code itself. If you are not familiar with MATLAB, here is a short +introduction to the notation, and a few minor variations used in CHOLMOD: \begin{itemize} - \item {\tt C=A+B} and {\tt C=A*B}, respectively are a matrix add and multiply if both - {\tt A} and {\tt B} are matrices of appropriate size. If {\tt A} is - a scalar, then it is added to or multiplied with every entry in {\tt B}. + \item {\tt C=A+B} and {\tt C=A*B}, respectively are a matrix add and + multiply if both {\tt A} and {\tt B} are matrices of appropriate size. + If {\tt A} is a scalar, then it is added to or multiplied with every + entry in {\tt B}. \item {\tt a:b} where {\tt a} and {\tt b} are integers refers to the - sequence {\tt a}, {\tt a+1}, ... {\tt b}. - \item {\tt [A B]} and {\tt [A,B]} are the horizontal concatenation of {\tt A} and {\tt B}. + sequence {\tt a}, {\tt a+1}, ... {\tt b}. + \item {\tt [A B]} and {\tt [A,B]} are the horizontal concatenation of {\tt + A} and {\tt B}. \item {\tt [A;B]} is the vertical concatenation of {\tt A} and {\tt B}. \item {\tt A(i,j)} can refer either to a scalar or a submatrix. - For example: \newline - \vspace{0.05in} - \begin{tabular}{ll} - \hline - {\tt A(1,1)} & a scalar. \\ - {\tt A(:,j)} & column {\tt j} of {\tt A}. \\ - {\tt A(i,:)} & row {\tt i} of {\tt A}. \\ - {\tt A([1 2], [1 2])} & a 2-by-2 matrix containing the 2-by-2 leading minor of {\tt A}. \\ - \hline - \end{tabular} \newline - \vspace{0.1in} - If {\tt p} is a permutation of {\tt 1:n}, and {\tt A} is {\tt n}-by-{\tt n}, - then {\tt A(p,p)} corresponds to the permuted matrix $\m{PAP}\tr$. - \item {\tt tril(A)} is the lower triangular part of {\tt A}, including the diagonal. - \item {\tt tril(A,k)} is the lower triangular part of {\tt A}, including entries - on and below the $k$th diagonal. - \item {\tt triu(A)} is the upper triangular part of {\tt A}, including the diagonal. - \item {\tt triu(A,k)} is the upper triangular part of {\tt A}, including entries - on and above the $k$th diagonal. + For example: \newline + \vspace{0.05in} + \begin{tabular}{ll} + \hline + {\tt A(1,1)} & a scalar. \\ + {\tt A(:,j)} & column {\tt j} of {\tt A}. \\ + {\tt A(i,:)} & row {\tt i} of {\tt A}. \\ + {\tt A([1 2], [1 2])} & a 2-by-2 matrix containing the 2-by-2 leading + minor of {\tt A}. \\ + \hline + \end{tabular} \newline + \vspace{0.1in} + If {\tt p} is a permutation of {\tt 1:n}, and {\tt A} is {\tt + n}-by-{\tt n}, then {\tt A(p,p)} corresponds to the permuted matrix + $\m{PAP}\tr$. + + \item {\tt tril(A)} is the lower triangular part of {\tt A}, including the + diagonal. + + \item {\tt tril(A,k)} is the lower triangular part of {\tt A}, including + entries on and below the $k$th diagonal. + + \item {\tt triu(A)} is the upper triangular part of {\tt A}, including the + diagonal. + + \item {\tt triu(A,k)} is the upper triangular part of {\tt A}, including + entries on and above the $k$th diagonal. + \item {\tt size(A)} returns the dimensions of {\tt A}. - \item {\tt find(x)} if {\tt x} is a vector returns a list of indices {\tt i} - for which {\tt x(i)} is nonzero. - \item {\tt A'} is the transpose of {\tt A} if {\tt A} is real, or - the complex conjugate transpose if {\tt A} is complex. + + \item {\tt find(x)} if {\tt x} is a vector returns a list of indices {\tt + i} for which {\tt x(i)} is nonzero. + + \item {\tt A'} is the transpose of {\tt A} if {\tt A} is real, or the + complex conjugate transpose if {\tt A} is complex. + \item {\tt A.'} is the array transpose of {\tt A}. + \item {\tt diag(A)} is the diagonal of {\tt A} if {\tt A} is a matrix. + \item {\tt C=diag(s)} is a diagonal matrix if {\tt s} is a vector, - with the values of {\tt s} on the diagonal of {\tt C}. + with the values of {\tt s} on the diagonal of {\tt C}. + \item {\tt S=spones(A)} returns a binary matrix {\tt S} with the - same nonzero pattern of {\tt A}. + same nonzero pattern of {\tt A}. + \item {\tt nnz(A)} is the number of nonzero entries in {\tt A}. + \end{itemize} \noindent Variations to MATLAB notation used in this document: \begin{itemize} \item CHOLMOD uses 0-based notation (the first entry in the matrix is - {\tt A(0,0)}). MATLAB is 1-based. The context is usually clear. + {\tt A(0,0)}). MATLAB is 1-based. The context is usually clear. \item {\tt I} is the identity matrix. \item {\tt A(:,f)}, where {\tt f} is a set of columns, is interpreted - differently in CHOLMOD, but just for the set named {\tt f}. - See {\tt cholmod\_transpose\_unsym} for details. + differently in CHOLMOD, but just for the set named {\tt f}. + See {\tt cholmod\_transpose\_unsym} for details. \end{itemize} + %------------------------------------------------------------------------------- \newpage \section{The CHOLMOD Modules, objects, and functions} \label{Modules} %------------------------------------------------------------------------------- -CHOLMOD contains a total of 133 {\tt int}-based routines (and the same number -of {\tt long} routines), divided into a set of inter-related -Modules. Each Module contains a set of related functions. The functions -are divided into two types: Primary and Secondary, to reflect how a user will -typically use CHOLMOD. Most users will find the Primary routines to be -sufficient to use CHOLMOD in their programs. Each Module exists as a -sub-directory (a folder for Windows users) within the CHOLMOD directory -(or folder). +CHOLMOD contains over 150 {\tt int32\_t}-based routines and the same number of +{\tt int64\_t} routines with the same name except for {\tt \_l\_} added. These +are divided into a set of inter-related Modules. Each Module contains a set of +related functions. The functions are divided into two types: Primary and +Secondary, to reflect how a user will typically use CHOLMOD. Most users will +find the Primary routines to be sufficient to use CHOLMOD in their programs. +Each Module exists as a sub-directory (a folder for Windows users) within the +CHOLMOD directory (or folder). \vspace{0.1in} -\noindent There are seven Modules that provide user-callable routines for CHOLMOD. +\noindent There are seven Modules that provide user-callable routines for +CHOLMOD. + \begin{enumerate} \item {\tt Utility}: basic data structures and definitions \item {\tt Check}: prints/checks each of CHOLMOD's objects @@ -740,8 +803,173 @@ \subsection{Adjustable parameters} \verb'cholmod.h' include file, via cmake. \end{enumerate} + +%------------------------------------------------------------------------------- +\subsection{CHOLMOD objects} +%------------------------------------------------------------------------------- + +A CHOLMOD sparse, dense, or triplet matrix A, or a sparse factorization L can +hold numeric values of 8 different types, according to its {\tt A->xtype} and +{\tt A->dtype} parameters (or {\tt L->xtype} and {\tt L->dtype} for a sparse +factor object). These values are held in the {\tt A->x} array, and also {\tt +A->z} for zomplex matrices. + +{\bf xtype:} the matrix is real, complex, "zomplex", or pattern-only. + + \begin{itemize} + \item + (0): \verb'CHOLMOD_PATTERN': \verb'A->x' and \verb'A->z' are + \verb'NULL'. The matrix has no numerical values. Only the pattern is + stored. + + \item + (1): \verb'CHOLMOD_REAL': The matrix is real, and the values are + held in \verb'A->x', whose size (in terms of double or float values) is + given by \verb'A->nzmax'. The kth value in the matrix is held in + \verb'A->x[k]'. + + \item + (2): \verb'CHOLMOD_COMPLEX': The matrix is complex, with interleaved + real and imaginary parts. The kth value in the matrix is held in + \verb'A->x[2*k]' and \verb'A->x[2*k+1]', where \verb'A->x' can hold up + to \verb'2*A->nzmax' values. + + \item + (3): \verb'CHOLMOD_ZOMPLEX': The matrix is complex, with separate + array for the real and imaginary parts. The kth value in the matrix is + held in \verb'A->x[k]', and \verb'A->z[k]', where \verb'A->x' and + \verb'A->z' can hold up to A->nzmax values each. + \end{itemize} + + +{\bf dtype}: this parameter determines the type of values in A->x (and A->z + if zomplex). + + \begin{itemize} + \item + (0) \verb'CHOLMOD_DOUBLE': \verb'A->x' and \verb'A->z' (for zomplex + matrices) are \verb'double'. If A is real, \verb'A->x' has a size of + \verb'A->nzmax * sizeof (double)' bytes. If A is complex, \verb'A->x' + has size \verb'A->nzmax * 2 * sizeof (double)'. + If zomplex, both \verb'A->x' and \verb'A->z' have size + \verb'A->nzmax * sizeof (double)'. + + \item + (4) \verb'CHOLMOD_SINGLE': \verb'A->x' and \verb'A->z' (for zomplex + matrices) are \verb'float'. If A is real, \verb'A->x' has a size of + \verb'A->nzmax * sizeof (float)'. If A is complex, \verb'A->x' has + \verb'size A->nzmax * 2 * sizeof (float)'. + If zomplex, both \verb'A->x' and \verb'A->z' have size + \verb'A->nzmax * sizeof (float)'. + This feature is new to CHOLMOD v5. + \end{itemize} + + Unless stated otherwise, the xtype and dtypes of all inputs to a method must + be the same. + + Many methods accept an xdtype parameter, which is simply xtype + dtype, + combining the two parameters into a single number handling all 8 cases: + + \begin{itemize} + \item + (0) \verb'CHOLMOD_DOUBLE' + \verb'CHOLMOD_PATTERN': a pattern-only matrix + \item + (1) \verb'CHOLMOD_DOUBLE' + \verb'CHOLMOD_REAL': a double real matrix + \item + (2) \verb'CHOLMOD_DOUBLE' + \verb'CHOLMOD_COMPLEX': a double complex matrix + \item + (3) \verb'CHOLMOD_DOUBLE' + \verb'CHOLMOD_ZOMPLEX': a double zomplex matrix + \item + (4) \verb'CHOLMOD_SINGLE' + \verb'CHOLMOD_PATTERN': a pattern-only matrix + \item + (5) \verb'CHOLMOD_SINGLE' + \verb'CHOLMOD_REAL': a float real matrix + \item + (6) \verb'CHOLMOD_SINGLE' + \verb'CHOLMOD_COMPLEX': a float complex matrix + \item + (7) \verb'CHOLMOD_SINGLE' + \verb'CHOLMOD_ZOMPLEX': a float zomplex matrix + \end{itemize} + + This approach was selected for backward compatibility with CHOLMOD v4 and + earlier, where only the first four values were supported, and where the + parameter was called \verb'xtype' instead of \verb'xdtype'. Several + function names reflect the older parameter name (\verb'cholmod_*_xtype'), + but they have not been renamed \verb"_xdtype", for backward compatibility. + + A CHOLMOD sparse or triplet matrix A can held in three symmetry formats + according to its \verb'A->stype' parameter. Dense matrices do not have this + parameter and are always treated as unsymmetric. A sparse factor object L + is always held in lower triangular form, with no entries ever held in the + strictly upper triangular part. + + \begin{itemize} + \item + 0: the matrix is unsymmetric with both lower and upper parts stored. + + \item + $<0$: the matrix is symmetric, with just the lower triangular part and + diagonal stored. Any entries in the upper part are ignored. + + \item + $>0$: the matrix is symmetric, with just the upper triangular part + stored and diagonal. Any entries in the upper part are ignored. + \end{itemize} + + If a sparse or triplet matrix A is complex or zomplex, most methods treat + the matrix as Hermitian, where A(i,j) is the complex conjugate of A(j,i), + when i is not equal to j. Some methods can also interpret the matrix as + complex symmetric, where A(i,j) == A(j,i) when i != j. This is not + determined by the matrix itself, but by a "mode" parameter of the function. + This mode parameter also determines if the values of any matrix are to be + ignored entirely, in which case only the pattern is operated on. Any output + matrix will have an xtype of \verb'CHOLMOD_PATTERN'. + + The valid mode values are given below, except that many methods do not + handle the negative cases. Values below the range accepted by the method + are treated as its lowest accepted value, and values above the range + accepted by the method are treated as its highest accepted value. + + \begin{itemize} + \item + mode = 2: the numerical values of a real, complex, or zomplex matrix are + handled. If the matrix is complex or zomplex, an entry A(i,j) + that not stored (or in the ignored part) is treated as the + complex conjugate of A (j,i). Use this mode to treat a + complex or zomplex matrix as Hermitian. + + \item + mode = 1: the numerical values of a real, complex, or zomplex matrix are + handled. If the matrix is complex or zomplex, an entry A(i,j) + that not stored (or in the ignored part) is treated as equal A + (j,i). Use this mode to treat a complex or zomplex matrix as + complex symmetric. + + \item + mode = 0: the numerical values are ignored. Any output matrix will have + an xtype of \verb'CHOLMOD_PATTERN'. This mode allows inputs to + have different dtypes. + + \item + mode = -1: the same as mode = 0, except that the diagonal entries are + ignored, and do not appear in any output matrix. + + \item + mode = -2: the same as mode = -1, except that the output matrix is given an + additional slack space so that it can hold about 50% more + entries. This mode is documented here but it is primarily + meant for internal use, for CHOLMOD's interface to the AMD, + CAMD, COLAMD, and CCOLAMD ordering methods. + \end{itemize} + + The integer arrays in all objects are either int32 or int64, as determined + by \verb'A->type'. This integer type must be identical for all inputs, and + must also match both the function name (\verb'cholmod_method' for int32, or + \verb'cholmod_l_method' for int64) and the \verb'Common->itype' as defined + when CHOLMOD was initialized (via \verb'cholmod_start' for int32, or + \verb'cholmod_l_start' for int64). + %------------------------------------------------------------------------------- -\newpage \subsection{{\tt Utility} Module: basic data structures and definitions} +\subsection{{\tt Utility} Module: basic data structures and +definitions} %------------------------------------------------------------------------------- CHOLMOD includes five basic objects, defined in the {\tt Utility} Module. @@ -749,61 +977,70 @@ \subsection{Adjustable parameters} and is required by all six other CHOLMOD library Modules: \subsubsection{{\tt cholmod\_common}: parameters, statistics, and workspace} - You must call {\tt cholmod\_start} before calling any other - CHOLMOD routine, and you must call {\tt cholmod\_finish} as your - last call to CHOLMOD (with the exception of - {\tt cholmod\_print\_common} and {\tt cholmod\_check\_common} - in the {\tt Check} Module). - Once the {\tt cholmod\_common} object is initialized, - the user may modify CHOLMOD's parameters held in this object, - and obtain statistics on CHOLMOD's activity. + You must call {\tt cholmod\_start} before calling any other CHOLMOD + routine, and you must call {\tt cholmod\_finish} as your last call to + CHOLMOD (with the exception of {\tt cholmod\_print\_common} and {\tt + cholmod\_check\_common} in the {\tt Check} Module). Once the {\tt + cholmod\_common} object is initialized, the user may modify CHOLMOD's + parameters held in this object, and obtain statistics on CHOLMOD's + activity. + + When using 64-bit integers, use {\tt cholmod\_l\_start} and {\tt + cholmod\_l\_finish} instead. Matrices and other objects from different + integer sizes cannot be mixed \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_common} object: % 2 \begin{itemize} \item {\tt cholmod\_start}: the first call to CHOLMOD. - \item {\tt cholmod\_finish}: the last call to CHOLMOD (frees workspace in the {\tt cholmod\_common} object). + \item {\tt cholmod\_finish}: the last call to CHOLMOD (frees workspace in + the {\tt cholmod\_common} object). \end{itemize} \noindent Secondary routines for the {\tt cholmod\_common} object: -% 9 +% 11 \begin{itemize} \item {\tt cholmod\_defaults}: restores default parameters \item {\tt cholmod\_maxrank}: determine maximum rank for update/downdate. - \item {\tt cholmod\_allocate\_work}: allocate workspace. + \item {\tt cholmod\_allocate\_work}: allocate workspace ({\tt double} only). + \item {\tt cholmod\_alloc\_work}: allocate workspace, + {\tt double} or {\tt float}. \item {\tt cholmod\_free\_work}: free workspace. \item {\tt cholmod\_clear\_flag}: clear {\tt Flag} array. \item {\tt cholmod\_error}: called when CHOLMOD encounters and error. - \item {\tt cholmod\_dbound}: bounds the diagonal of $\m{L}$ or $\m{D}$. + \item {\tt cholmod\_dbound}: bounds the diagonal of $\m{L}$ or $\m{D}$ + ({\tt double} case). + \item {\tt cholmod\_sbound}: bounds the diagonal of $\m{L}$ or $\m{D}$. + ({\tt float} case). \item {\tt cholmod\_hypot}: compute {\tt sqrt(x*x+y*y)} accurately. \item {\tt cholmod\_divcomplex}: complex divide. \end{itemize} %------------------------------------------------------------------------------- -\newpage \subsubsection{{\tt cholmod\_sparse}: a sparse matrix in compressed column form} +\subsubsection{{\tt cholmod\_sparse}: a sparse matrix in compressed +column form} %------------------------------------------------------------------------------- + A sparse matrix {\tt A} is held in compressed column form. In the basic type (``packed,'' which corresponds to how MATLAB stores its sparse - matrices), and {\tt nrow}-by-{\tt ncol} matrix with {\tt nzmax} entries - is held in three arrays: {\tt p} of size {\tt ncol+1}, - {\tt i} of size {\tt nzmax}, and {\tt x} of size {\tt nzmax}. - Row indices of nonzero entries in column {\tt j} are held in - {\tt i [p[j] ... p[j+1]-1]}, and their corresponding numerical values - are held in {\tt x [p[j] ... p[j+1]-1]}. The first column starts at - location zero ({\tt p[0]=0}). - There may be no duplicate entries. Row indices in each column may - be sorted or unsorted (the {\tt A->sorted} flag must be false if - the columns are unsorted). The {\tt A->stype} determines the - storage mode: 0 if the matrix is unsymmetric, 1 if the matrix is - symmetric with just the upper triangular part stored, and -1 if - the matrix is symmetric with just the lower triangular part stored. - - In ``unpacked'' form, an additional array {\tt nz} of size {\tt ncol} - is used. The end of column {\tt j} in {\tt i} and {\tt x} - is given by {\tt p[j]+nz[j]}. Columns not need be in any particular - order ({\tt p[0]} need not be zero), and there may be gaps between - the columns. + matrices), and {\tt nrow}-by-{\tt ncol} matrix with {\tt nzmax} entries is + held in three arrays: {\tt p} of size {\tt ncol+1}, {\tt i} of size {\tt + nzmax}, and {\tt x} of size {\tt nzmax}. Row indices of nonzero entries in + column {\tt j} are held in {\tt i [p[j] ... p[j+1]-1]}, and their + corresponding numerical values are held in {\tt x [p[j] ... p[j+1]-1]}. + The first column starts at location zero ({\tt p[0]=0}). There may be no + duplicate entries. Row indices in each column may be sorted or unsorted + (the {\tt A->sorted} flag must be false if the columns are unsorted). The + {\tt A->stype} determines the storage: 0 if the matrix is unsymmetric, + 1 if the matrix is symmetric with just the upper triangular part stored, + and -1 if the matrix is symmetric with just the lower triangular part + stored. + + In ``unpacked'' form, an additional array {\tt nz} of size {\tt ncol} is + used. The end of column {\tt j} in {\tt i} and {\tt x} is given by {\tt + p[j]+nz[j]}. Columns not need be in any particular order ({\tt p[0]} need + not be zero), and there may be gaps between the columns. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_sparse} object: @@ -814,35 +1051,42 @@ \subsubsection{{\tt cholmod\_common}: parameters, statistics, and workspace} \end{itemize} \noindent Secondary routines for the {\tt cholmod\_sparse} object: -% 16 +% 17 \begin{itemize} - \item {\tt cholmod\_reallocate\_sparse}: change the size (number of entries) of a sparse matrix. + \item {\tt cholmod\_reallocate\_sparse}: change the size (number of + entries) of a sparse matrix. \item {\tt cholmod\_nnz}: number of nonzeros in a sparse matrix. \item {\tt cholmod\_speye}: sparse identity matrix. \item {\tt cholmod\_spzeros}: sparse zero matrix. \item {\tt cholmod\_transpose}: transpose a sparse matrix. + \item {\tt cholmod\_transpose\_unsym}: transpose/permute an unsymmetric + sparse matrix. + \item {\tt cholmod\_transpose\_sym}: transpose/permute a symmetric sparse + matrix. \item {\tt cholmod\_ptranspose}: transpose/permute a sparse matrix. - \item {\tt cholmod\_transpose\_unsym}: transpose/permute an unsymmetric sparse matrix. - \item {\tt cholmod\_transpose\_sym}: transpose/permute a symmetric sparse matrix. - \item {\tt cholmod\_sort}: sort row indices in each column of a sparse matrix. + \item {\tt cholmod\_sort}: sort row indices in each column of a sparse + matrix. + \item {\tt cholmod\_band\_nnz}: number of entries in a band of a sparse + matrix. \item {\tt cholmod\_band}: extract a band of a sparse matrix. \item {\tt cholmod\_band\_inplace}: remove entries not with a band. \item {\tt cholmod\_aat}: {\tt C = A*A'}. - \item {\tt cholmod\_copy\_sparse}: {\tt C = A}, create an exact copy of a sparse matrix. + \item {\tt cholmod\_copy\_sparse}: {\tt C = A}, create an exact copy of a + sparse matrix. \item {\tt cholmod\_copy}: {\tt C = A}, with possible change of {\tt stype}. \item {\tt cholmod\_add}: {\tt C = alpha*A + beta*B}. - \item {\tt cholmod\_sparse\_xtype}: change the {\tt xtype} of a sparse matrix. + \item {\tt cholmod\_sparse\_xtype}: change the {\tt xtype} and/or + {\tt dtype} of a sparse matrix. \end{itemize} %------------------------------------------------------------------------------- -\newpage \subsubsection{{\tt cholmod\_factor}: a symbolic or numeric factorization} +\subsubsection{{\tt cholmod\_factor}: a symbolic or numeric factorization} %------------------------------------------------------------------------------- - A factor can be in $\m{LL}\tr$ or $\m{LDL}\tr$ form, and either supernodal - or simplicial form. In simplicial form, this is very much like a - packed or unpacked {\tt cholmod\_sparse} matrix. In supernodal - form, adjacent columns with similar nonzero pattern are stored as - a single block (a supernode). +A factor can be in $\m{LL}\tr$ or $\m{LDL}\tr$ form, and either supernodal or +simplicial form. In simplicial form, this is very much like a packed or +unpacked {\tt cholmod\_sparse} matrix. In supernodal form, adjacent columns +with similar nonzero pattern are stored as a single block (a supernode). \vspace{0.1in} \noindent Primary routine for the {\tt cholmod\_factor} object: @@ -852,16 +1096,24 @@ \subsubsection{{\tt cholmod\_common}: parameters, statistics, and workspace} \end{itemize} \noindent Secondary routines for the {\tt cholmod\_factor} object: -% 8 +% 9 \begin{itemize} - \item {\tt cholmod\_allocate\_factor}: allocate a factor. You will normally use {\tt cholmod\_analyze} to create a factor. - \item {\tt cholmod\_reallocate\_factor}: change the number of entries in a factor. - \item {\tt cholmod\_change\_factor}: change the type of a factor ($\m{LDL}\tr$ to $\m{LL}\tr$, supernodal to simplicial, etc.). + \item {\tt cholmod\_allocate\_factor}: allocate a factor. + ({\tt double} or {\tt float}). + You will normally use {\tt cholmod\_analyze} to create a factor. + \item {\tt cholmod\_alloc\_factor}: allocate a factor + ({\tt double} or {\tt float}). + \item {\tt cholmod\_reallocate\_factor}: change the number of entries in a + factor. + \item {\tt cholmod\_change\_factor}: change the type of a factor + ($\m{LDL}\tr$ to $\m{LL}\tr$, supernodal to simplicial, etc.). \item {\tt cholmod\_pack\_factor}: pack the columns of a factor. \item {\tt cholmod\_reallocate\_column}: resize a single column of a factor. - \item {\tt cholmod\_factor\_to\_sparse}: create a sparse matrix copy of a factor. + \item {\tt cholmod\_factor\_to\_sparse}: create a sparse matrix copy of a + factor. \item {\tt cholmod\_copy\_factor}: create a copy of a factor. - \item {\tt cholmod\_factor\_xtype}: change the xtype of a factor. + \item {\tt cholmod\_factor\_xtype}: change the {\tt xtype} and/or + {\tt dtype} of a factor. \end{itemize} %------------------------------------------------------------------------------- @@ -879,28 +1131,34 @@ \subsubsection{{\tt cholmod\_dense}: a dense matrix} \vspace{0.1in} \noindent Secondary routines for the {\tt cholmod\_dense} object: -% 8 +% 10 \begin{itemize} \item {\tt cholmod\_zeros}: allocate a dense matrix of all zeros. \item {\tt cholmod\_ones}: allocate a dense matrix of all ones. \item {\tt cholmod\_eye}: allocate a dense identity matrix . - \item {\tt cholmod\_sparse\_to\_dense}: create a dense matrix copy of a sparse matrix. - \item {\tt cholmod\_dense\_to\_sparse}: create a sparse matrix copy of a dense matrix. + \item {\tt cholmod\_ensure\_dense}: ensure a dense matrix has a given + size and type. + \item {\tt cholmod\_sparse\_to\_dense}: create a dense matrix copy of a + sparse matrix. + \item {\tt cholmod\_dense\_nnz}: number of nonzeros in a dense matrix. + \item {\tt cholmod\_dense\_to\_sparse}: create a sparse matrix copy of a + dense matrix. \item {\tt cholmod\_copy\_dense}: create a copy of a dense matrix. \item {\tt cholmod\_copy\_dense2}: copy a dense matrix (pre-allocated). - \item {\tt cholmod\_dense\_xtype}: change the {\tt xtype} of a dense matrix. + \item {\tt cholmod\_dense\_xtype}: change the {\tt xtype} + and/or {\tt dtype} of a dense matrix. \end{itemize} %------------------------------------------------------------------------------- -\newpage \subsubsection{{\tt cholmod\_triplet}: a sparse matrix in ``triplet'' form} +\subsubsection{{\tt cholmod\_triplet}: a sparse matrix in ``triplet'' form} %------------------------------------------------------------------------------- - The {\tt cholmod\_sparse} matrix is the basic sparse matrix used in - CHOLMOD, but it can be difficult for the user to construct. It also - does not easily support the inclusion of new entries in the matrix. - The {\tt cholmod\_triplet} matrix is provided to address these issues. - A sparse matrix in triplet form consists of three arrays of size - {\tt nzmax}: {\tt i}, {\tt j}, and {\tt x}, and a {\tt z} array - for the zomplex case. + +The {\tt cholmod\_sparse} matrix is the basic sparse matrix used in CHOLMOD, +but it can be difficult for the user to construct. It also does not easily +support the inclusion of new entries in the matrix. The {\tt cholmod\_triplet} +matrix is provided to address these issues. A sparse matrix in triplet form +consists of three arrays of size {\tt nzmax}: {\tt i}, {\tt j}, and {\tt x}, +and a {\tt z} array for the zomplex case. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_triplet} object: @@ -908,24 +1166,30 @@ \subsubsection{{\tt cholmod\_dense}: a dense matrix} \begin{itemize} \item {\tt cholmod\_allocate\_triplet}: allocate a triplet matrix. \item {\tt cholmod\_free\_triplet}: free a triplet matrix. - \item {\tt cholmod\_triplet\_to\_sparse}: create a sparse matrix copy of a triplet matrix. + \item {\tt cholmod\_triplet\_to\_sparse}: create a sparse matrix copy of a + triplet matrix. \end{itemize} \noindent Secondary routines for the {\tt cholmod\_triplet} object: % 4 \begin{itemize} - \item {\tt cholmod\_reallocate\_triplet}: change the number of entries in a triplet matrix. - \item {\tt cholmod\_sparse\_to\_triplet}: create a triplet matrix copy of a sparse matrix. + \item {\tt cholmod\_reallocate\_triplet}: change the number of entries in a + triplet matrix. + \item {\tt cholmod\_sparse\_to\_triplet}: create a triplet matrix copy of a + sparse matrix. \item {\tt cholmod\_copy\_triplet}: create a copy of a triplet matrix. - \item {\tt cholmod\_triplet\_xtype}: change the {\tt xtype} of a triplet matrix. + \item {\tt cholmod\_triplet\_xtype}: change the {\tt xtype} and/or + {\tt dtype} of a triplet matrix. \end{itemize} %------------------------------------------------------------------------------- \subsubsection{Memory management routines} %------------------------------------------------------------------------------- - By default, CHOLMOD uses the ANSI C {\tt malloc}, {\tt free}, - {\tt calloc}, and {\tt realloc} routines. You may use different - routines by modifying function pointers in the {\tt cholmod\_common} object. + +By default, CHOLMOD uses the ANSI C {\tt malloc}, {\tt free}, +{\tt calloc}, and {\tt realloc} routines. You may use different +routines by modifying function pointers in the {\tt SuiteSparse\_config} +package. Refer to the user guide for that package for more details. \vspace{0.1in} \noindent Primary routines: @@ -940,41 +1204,47 @@ \subsubsection{Memory management routines} \begin{itemize} \item {\tt cholmod\_calloc}: {\tt calloc} wrapper. \item {\tt cholmod\_realloc}: {\tt realloc} wrapper. - \item {\tt cholmod\_realloc\_multiple}: {\tt realloc} wrapper for multiple objects. + \item {\tt cholmod\_realloc\_multiple}: {\tt realloc} wrapper for multiple + objects. \end{itemize} %------------------------------------------------------------------------------- \subsubsection{{\tt cholmod\_version:} Version control} %------------------------------------------------------------------------------- + The {\tt cholmod\_version} function returns the current version of CHOLMOD. %------------------------------------------------------------------------------- -\newpage \subsection{{\tt Check} Module: print/check the CHOLMOD objects} +\subsection{{\tt Check} Module: print/check the CHOLMOD objects} %------------------------------------------------------------------------------- - The {\tt Check} Module contains routines that check and print the five - basic objects in CHOLMOD, and three kinds of integer vectors (a set, - a permutation, and a tree). It also provides a routine to read a sparse - matrix from a file in Matrix Market format (http://www.nist.gov/MatrixMarket). - Requires the {\tt Utility} Module. + +The {\tt Check} Module contains routines that check and print the five basic +objects in CHOLMOD, and three kinds of integer vectors (a set, a permutation, +and a tree). It also provides a routine to read a sparse matrix from a file in +Matrix Market format (http://www.nist.gov/MatrixMarket). Requires the {\tt +Utility} Module. \vspace{0.1in} \noindent Primary routines: -% 4 +% 5 \begin{itemize} \item {\tt cholmod\_print\_common}: print the {\tt cholmod\_common} object, - including statistics on CHOLMOD's behavior (fill-in, flop count, - ordering methods used, and so on). + including statistics on CHOLMOD's behavior (fill-in, flop count, + ordering methods used, and so on). \item {\tt cholmod\_write\_sparse}: write a sparse matrix to a file - in Matrix Market format. + in Matrix Market format. \item {\tt cholmod\_write\_dense}: write a sparse matrix to a file - in Matrix Market format. + in Matrix Market format. \item {\tt cholmod\_read\_matrix}: read a sparse or dense matrix from a file - in Matrix Market format. + in Matrix Market format. + \item {\tt cholmod\_read\_matrix2}: read a sparse or dense matrix from a + file in Matrix Market format + ({\tt double} or {\tt float}). \end{itemize} \vspace{0.1in} \noindent Secondary routines: -% 18 +% 19 \begin{itemize} \item {\tt cholmod\_check\_common}: check the {\tt cholmod\_common} object \item {\tt cholmod\_check\_sparse}: check a sparse matrix @@ -985,119 +1255,154 @@ \subsubsection{{\tt cholmod\_version:} Version control} \item {\tt cholmod\_print\_factor}: print a Cholesky factorization \item {\tt cholmod\_check\_triplet}: check a triplet matrix \item {\tt cholmod\_print\_triplet}: print a triplet matrix - \item {\tt cholmod\_check\_subset}: check a subset (integer vector in given range) - \item {\tt cholmod\_print\_subset}: print a subset (integer vector in given range) + \item {\tt cholmod\_check\_subset}: check a subset (integer vector in given + range) + \item {\tt cholmod\_print\_subset}: print a subset (integer vector in given + range) \item {\tt cholmod\_check\_perm}: check a permutation (an integer vector) \item {\tt cholmod\_print\_perm}: print a permutation (an integer vector) - \item {\tt cholmod\_check\_parent}: check an elimination tree (an integer vector) - \item {\tt cholmod\_print\_parent}: print an elimination tree (an integer vector) + \item {\tt cholmod\_check\_parent}: check an elimination tree (an integer + vector) + \item {\tt cholmod\_print\_parent}: print an elimination tree (an integer + vector) \item {\tt cholmod\_read\_triplet}: read a triplet matrix from a file + \item {\tt cholmod\_read\_triplet2}: read a triplet matrix from a file + ({\tt double} or {\tt float}) \item {\tt cholmod\_read\_sparse}: read a sparse matrix from a file + \item {\tt cholmod\_read\_sparse2}: read a sparse matrix from a file + ({\tt double} or {\tt float}) \item {\tt cholmod\_read\_dense}: read a dense matrix from a file + \item {\tt cholmod\_read\_dense2}: read a dense matrix from a file + ({\tt double} or {\tt float}) + % + \item {\tt cholmod\_gpu\_stats}: print GPU timing statistics \end{itemize} %------------------------------------------------------------------------------- -\newpage \subsection{{\tt Cholesky} Module: sparse Cholesky factorization} +\subsection{{\tt Cholesky} Module: sparse Cholesky factorization} %------------------------------------------------------------------------------- The primary routines are all that a user requires to order, analyze, and -factorize a sparse symmetric positive definite matrix $\m{A}$ (or $\m{AA}\tr$), and -to solve $\m{Ax}=\m{b}$ (or $\m{AA}\tr\m{x}=\m{b}$). The primary routines rely on the secondary -routines, the {\tt Utility} Module, and the AMD and COLAMD packages. They -make optional use of the {\tt Supernodal} and {\tt Partition} Modules, the -METIS package, the CAMD package, and -the CCOLAMD package. The {\tt Cholesky} Module is -required by the {\tt Partition} Module. +factorize a sparse symmetric positive definite matrix $\m{A}$ (or $\m{AA}\tr$), +and to solve $\m{Ax}=\m{b}$ (or $\m{AA}\tr\m{x}=\m{b}$). The primary routines +rely on the secondary routines, the {\tt Utility} Module, and the AMD and +COLAMD packages. They make optional use of the {\tt Supernodal} and {\tt +Partition} Modules, the METIS package, the CAMD package, and the CCOLAMD +package. The {\tt Cholesky} Module is required by the {\tt Partition} Module. \vspace{0.1in} \noindent Primary routines: -% 4 + \begin{itemize} \item {\tt cholmod\_analyze}: order and analyze (simplicial or supernodal). - \item {\tt cholmod\_factorize}: simplicial or supernodal Cholesky factorization. - \item {\tt cholmod\_solve}: solve a linear system (simplicial or supernodal, dense $\m{x}$ and $\m{b}$). - \item {\tt cholmod\_spsolve}: solve a linear system (simplicial or supernodal, sparse $\m{x}$ and $\m{b}$ ). + \item {\tt cholmod\_factorize}: simplicial or supernodal Cholesky + factorization. + \item {\tt cholmod\_solve}: solve a linear system (simplicial or + supernodal, dense $\m{x}$ and $\m{b}$). + \item {\tt cholmod\_spsolve}: solve a linear system (simplicial or + supernodal, sparse $\m{x}$ and $\m{b}$ ). \end{itemize} \noindent Secondary routines: -% 15 + \begin{itemize} - \item {\tt cholmod\_analyze\_p}: analyze, with user-provided permutation or $\m{f}$ set. - \item {\tt cholmod\_factorize\_p}: factorize, with user-provided permutation or $\m{f}$. + \item {\tt cholmod\_analyze\_p}: analyze, with user-provided permutation or + $\m{f}$ set. +% \item {\tt cholmod\_analyze\_p2}: analyze for sparse QR or Cholesky. + \item {\tt cholmod\_factorize\_p}: factorize, with user-provided + permutation or $\m{f}$. \item {\tt cholmod\_analyze\_ordering}: analyze a permutation \item {\tt cholmod\_solve2}: solve a linear system, reusing workspace. \item {\tt cholmod\_etree}: find the elimination tree. - \item {\tt cholmod\_rowcolcounts}: compute the row/column counts of $\m{L}$. + \item {\tt cholmod\_rowcolcounts}: compute the row/column counts of + $\m{L}$. \item {\tt cholmod\_amd}: order using AMD. \item {\tt cholmod\_colamd}: order using COLAMD. \item {\tt cholmod\_rowfac}: incremental simplicial factorization. - \item {\tt cholmod\_row\_subtree}: find the nonzero pattern of a row of $\m{L}$. - \item {\tt cholmod\_row\_lsubtree}: find the nonzero pattern of a row of $\m{L}$. - \item {\tt cholmod\_row\_lsubtree}: find the nonzero pattern of $\m{L}^{-1}b$. + \item {\tt cholmod\_row\_subtree}: find the nonzero pattern of a row of + $\m{L}$. + \item {\tt cholmod\_lsolve\_pattern}: find the nonzero pattern of + $\m{L}^{-1}b$. + \item {\tt cholmod\_row\_lsubtree}: find the nonzero pattern of a row of + $\m{L}$. \item {\tt cholmod\_resymbol}: recompute the symbolic pattern of $\m{L}$. - \item {\tt cholmod\_resymbol\_noperm}: recompute the symbolic pattern of $\m{L}$, no permutation. + \item {\tt cholmod\_resymbol\_noperm}: recompute the symbolic pattern of + $\m{L}$, no permutation. + \item {\tt cholmod\_rcond}: compute the reciprocal condition number \item {\tt cholmod\_postorder}: postorder a tree. - \item {\tt cholmod\_rcond}: compute the reciprocal condition number estimate. - \item {\tt cholmod\_rowfac\_mask}: for use in LPDASA only. + estimate. +% \item {\tt cholmod\_rowfac\_mask}: for use in LPDASA only. \end{itemize} %------------------------------------------------------------------------------- -\newpage \subsection{{\tt Modify} Module: update/downdate a sparse Cholesky factorization} +\subsection{{\tt Modify} Module: update/downdate a sparse Cholesky +factorization} %------------------------------------------------------------------------------- -The {\tt Modify} Module contains sparse Cholesky modification routines: -update, downdate, row-add, and row-delete. -It can also modify a corresponding solution to $\m{Lx}=\m{b}$ when L is modified. -This module is most useful when applied on a Cholesky factorization computed by -the {\tt Cholesky} module, but it does not actually require the {\tt Cholesky} module. -The {\tt Utility} module can create an identity Cholesky factorization ($\m{LDL}\tr$ where -$\m{L}=\m{D}=\m{I}$) that can then be modified by these routines. -Requires the {\tt Utility} module. Not required by any other CHOLMOD Module. +The {\tt Modify} Module contains sparse Cholesky modification routines: update, +downdate, row-add, and row-delete. It can also modify a corresponding solution +to $\m{Lx}=\m{b}$ when L is modified. This module is most useful when applied +on a Cholesky factorization computed by the {\tt Cholesky} module, but it does +not actually require the {\tt Cholesky} module. The {\tt Utility} module can +create an identity Cholesky factorization ($\m{LDL}\tr$ where +$\m{L}=\m{D}=\m{I}$) that can then be modified by these routines. Requires the +{\tt Utility} module. Not required by any other CHOLMOD Module. \vspace{0.1in} \noindent Primary routine: -% 1 + \begin{itemize} \item {\tt cholmod\_updown}: multiple rank update/downdate \end{itemize} \noindent Secondary routines: -% 8 + \begin{itemize} - \item {\tt cholmod\_updown\_solve}: update/downdate, and modify solution to $\m{Lx=b}$ - \item {\tt cholmod\_updown\_mark}: update/downdate, and modify solution to partial $\m{Lx=b}$ - \item {\tt cholmod\_updown\_mask}: for use in LPDASA only. + \item {\tt cholmod\_updown\_solve}: update/downdate, and modify solution to + $\m{Lx=b}$ +% \item {\tt cholmod\_updown\_mark}: update/downdate, and modify solution to +% partial $\m{Lx=b}$ +% \item {\tt cholmod\_updown\_mask}: for use in LPDASA only. \item {\tt cholmod\_rowadd}: add a row to an $\m{LDL}\tr$ factorization - \item {\tt cholmod\_rowadd\_solve}: add a row, and update solution to $\m{Lx=b}$ - \item {\tt cholmod\_rowadd\_mark}: add a row, and update solution to partial $\m{Lx=b}$ + \item {\tt cholmod\_rowadd\_solve}: add a row, and update solution to + $\m{Lx=b}$ +% \item {\tt cholmod\_rowadd\_mark}: add a row, and update solution to +% partial $\m{Lx=b}$ \item {\tt cholmod\_rowdel}: delete a row from an $\m{LDL}\tr$ factorization \item {\tt cholmod\_rowdel\_solve}: delete a row, and downdate $\m{Lx=b}$ - \item {\tt cholmod\_rowdel\_mark}: delete a row, and downdate solution to partial $\m{Lx=b}$ +% \item {\tt cholmod\_rowdel\_mark}: delete a row, and downdate solution to +% partial $\m{Lx=b}$ \end{itemize} %------------------------------------------------------------------------------- \subsection{{\tt MatrixOps} Module: basic sparse matrix operations} %------------------------------------------------------------------------------- -The {\tt MatrixOps} Module provides -basic operations on sparse and dense matrices. -Requires the {\tt Utility} module. Not required by any other CHOLMOD module. -In the descriptions below, -{\tt A}, {\tt B}, and {\tt C:} are sparse matrices ({\tt cholmod\_sparse}), -{\tt X} and {\tt Y} are dense matrices ({\tt cholmod\_dense}), -{\tt s} is a scalar or vector, and -{\tt alpha} {\tt beta} are scalars. +The {\tt MatrixOps} Module provides basic operations on sparse and dense +matrices. Requires the {\tt Utility} module. Not required by any other +CHOLMOD module. In the descriptions below, {\tt A}, {\tt B}, and {\tt C:} are +sparse matrices ({\tt cholmod\_sparse}), {\tt X} and {\tt Y} are dense matrices +({\tt cholmod\_dense}), {\tt s} is a scalar or vector, and {\tt alpha} {\tt +beta} are scalars. + +Many of these operations are also available in GraphBLAS, with better +performance. -% 10 \begin{itemize} - \item {\tt cholmod\_drop}: drop entries from A with absolute value $\ge$ a given tolerance. - \item {\tt cholmod\_norm\_dense}: {\tt s = norm (X)}, 1-norm, infinity-norm, or 2-norm - \item {\tt cholmod\_norm\_sparse}: {\tt s = norm (A)}, 1-norm or infinity-norm - \item {\tt cholmod\_horzcat}: {\tt C = [A,B]} - \item {\tt cholmod\_scale}: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A} or {\tt diag(s)*A*diag(s)}. - \item {\tt cholmod\_sdmult}: {\tt Y = alpha*(A*X) + beta*Y} or {\tt alpha*(A'*X) + beta*Y}. + \item {\tt cholmod\_drop}: drop entries from A with absolute value $\ge$ a + given tolerance. + \item {\tt cholmod\_norm\_dense}: {\tt s = norm (X)}, 1-norm, + infinity-norm, or 2-norm + \item {\tt cholmod\_norm\_sparse}: {\tt s = norm (A)}, 1-norm or + infinity-norm + \item {\tt cholmod\_scale}: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A} + or {\tt diag(s)*A*diag(s)}. + \item {\tt cholmod\_sdmult}: {\tt Y = alpha*(A*X) + beta*Y} or {\tt + alpha*(A'*X) + beta*Y}. \item {\tt cholmod\_ssmult}: {\tt C = A*B} - \item {\tt cholmod\_submatrix}: {\tt C = A (i,j)}, where {\tt i} and {\tt j} are arbitrary integer vectors. + \item {\tt cholmod\_submatrix}: {\tt C = A (i,j)}, where {\tt i} and {\tt + j} are arbitrary integer vectors. + \item {\tt cholmod\_horzcat}: {\tt C = [A,B]} \item {\tt cholmod\_vertcat}: {\tt C = [A ; B]}. \item {\tt cholmod\_symmetry}: determine symmetry of a matrix. \end{itemize} @@ -1106,21 +1411,21 @@ \subsection{{\tt MatrixOps} Module: basic sparse matrix operations} \subsection{{\tt Supernodal} Module: supernodal sparse Cholesky factorization} %------------------------------------------------------------------------------- -The {\tt Supernodal} Module performs -supernodal analysis, factorization, and solve. The simplest way to use -these routines is via the {\tt Cholesky} Module. This Module does not provide any -fill-reducing orderings. It normally operates on matrices ordered by the -{\tt Cholesky} Module. -It does not require the {\tt Cholesky} Module itself, however. -Requires the {\tt Utility} Module, and two external packages: LAPACK and the BLAS. -Optionally used by the {\tt Cholesky} Module. All are secondary routines -since these functions are more easily used via the {\tt Cholesky} Module. +The {\tt Supernodal} Module performs supernodal analysis, factorization, and +solve. The simplest way to use these routines is via the {\tt Cholesky} +Module. This Module does not provide any fill-reducing orderings. It normally +operates on matrices ordered by the {\tt Cholesky} Module. It does not require +the {\tt Cholesky} Module itself, however. Requires the {\tt Utility} Module, +and two external packages: LAPACK and the BLAS. Optionally used by the {\tt +Cholesky} Module. All are secondary routines since these functions are more +easily used via the {\tt Cholesky} Module. \vspace{0.1in} \noindent Secondary routines: -% 4 + \begin{itemize} \item {\tt cholmod\_super\_symbolic}: supernodal symbolic analysis +% \item {\tt cholmod\_super\_symbolic2}: for sparse QR \item {\tt cholmod\_super\_numeric}: supernodal numeric factorization \item {\tt cholmod\_super\_lsolve}: supernodal $\m{Lx}=\m{b}$ solve \item {\tt cholmod\_super\_ltsolve}: supernodal $\m{L}\tr\m{x}=\m{b}$ solve @@ -1130,30 +1435,28 @@ \subsection{{\tt Supernodal} Module: supernodal sparse Cholesky factorization} \subsection{{\tt Partition} Module: graph-partitioning-based orderings} %------------------------------------------------------------------------------- -The {\tt Partition} Module provides -graph partitioning and graph-partition-based orderings. It includes an -interface to CAMD, CCOLAMD, and CSYMAMD, constrained minimum degree ordering -methods which order a matrix following constraints determined via nested -dissection. -Requires the {\tt Utility} and {\tt Cholesky} Modules, and two packages: {\tt METIS 5.1.0}, CAMD, and CCOLAMD. -Optionally used by the {\tt Cholesky} Module. All are secondary routines since -these are more easily used by the {\tt Cholesky} Module. - -Note that METIS does not have a version that uses {\tt long} integers. If you try to use -these routines (except the CAMD, CCOLAMD, and CSYMAMD interfaces) -on a matrix that is too large, an error code will be returned. +The {\tt Partition} Module provides graph partitioning and +graph-partition-based orderings. It includes an interface to CAMD, CCOLAMD, +and CSYMAMD, constrained minimum degree ordering methods which order a matrix +following constraints determined via nested dissection. Requires the {\tt +Utility} and {\tt Cholesky} Modules, and two packages: {\tt METIS 5.1.0}, CAMD, +and CCOLAMD. Optionally used by the {\tt Cholesky} Module. All are secondary +routines since these are more easily used by the {\tt Cholesky} Module. \vspace{0.1in} \noindent Secondary routines: -% 8 + \begin{itemize} - \item {\tt cholmod\_nested\_dissection}: CHOLMOD nested dissection ordering - \item {\tt cholmod\_metis}: METIS nested dissection ordering ({\tt METIS\_NodeND}) - \item {\tt cholmod\_camd}: interface to CAMD ordering \item {\tt cholmod\_ccolamd}: interface to CCOLAMD ordering \item {\tt cholmod\_csymamd}: interface to CSYMAMD ordering + \item {\tt cholmod\_camd}: interface to CAMD ordering + % + \item {\tt cholmod\_nested\_dissection}: CHOLMOD nested dissection ordering + \item {\tt cholmod\_metis}: METIS nested dissection ordering ({\tt + METIS\_NodeND}) \item {\tt cholmod\_bisect}: graph partitioner (currently based on METIS) - \item {\tt cholmod\_metis\_bisector}: direct interface to {\tt METIS\_NodeComputeSeparator}. + \item {\tt cholmod\_metis\_bisector}: direct interface to {\tt + METIS\_NodeComputeSeparator}. \item {\tt cholmod\_collapse\_septree}: pruned a separator tree from {\tt cholmod\_nested\_dissection}. \end{itemize} @@ -1162,10 +1465,10 @@ \subsection{{\tt Partition} Module: graph-partitioning-based orderings} \newpage \section{CHOLMOD naming convention, parameters, and return values} %------------------------------------------------------------------------------- -All routine names, data types, and CHOLMOD library files use the -{\tt cholmod\_} prefix. All macros and other {\tt \#define} statements -visible to the user program use the {\tt CHOLMOD} prefix. -The {\tt cholmod.h} file must be included in user programs that use CHOLMOD: +All routine names, data types, and CHOLMOD library files use the {\tt +cholmod\_} prefix. All macros and other {\tt \#define} statements visible to +the user program use the {\tt CHOLMOD} prefix. The {\tt cholmod.h} file must +be included in user programs that use CHOLMOD: {\footnotesize \begin{verbatim} @@ -1176,35 +1479,44 @@ \subsection{{\tt Partition} Module: graph-partitioning-based orderings} \noindent All CHOLMOD routines (in all modules) use the following protocol for return values: \begin{itemize} -\item {\tt int}: {\tt TRUE} (1) if successful, or {\tt FALSE} (0) otherwise. (exception: {\tt cholmod\_divcomplex}). -\item {\tt long}: a value $\ge 0$ if successful, or -1 otherwise. -\item {\tt double}: a value $\ge 0$ if successful, or -1 otherwise. +\item {\tt int}: {\tt TRUE} (1) if successful, or {\tt FALSE} (0) otherwise. +(exception: {\tt cholmod\_divcomplex}). +\item {\tt int32\_t} or {\tt int64\_t}: + a value $\ge 0$ if successful, or -1 otherwise. +\item {\tt float} or {\tt double}: + a value $\ge 0$ if successful, or -1 otherwise. \item {\tt size\_t}: a value $>$ 0 if successful, or 0 otherwise. -\item {\tt void *}: a non-{\tt NULL} pointer to newly allocated memory if successful, or {\tt NULL} otherwise. -\item {\tt cholmod\_sparse *}: a non-{\tt NULL} pointer to a newly allocated sparse matrix if successful, or {\tt NULL} otherwise. -\item {\tt cholmod\_factor *}: a non-{\tt NULL} pointer to a newly allocated factor if successful, or {\tt NULL} otherwise. -\item {\tt cholmod\_triplet *}: a non-{\tt NULL} pointer to a newly allocated triplet matrix if successful, or {\tt NULL} otherwise. -\item {\tt cholmod\_dense *}: a non-{\tt NULL} pointer to a newly allocated dense matrix if successful, or {\tt NULL} otherwise. +\item {\tt void *}: a non-{\tt NULL} pointer to newly allocated memory if + successful, or {\tt NULL} otherwise. +\item {\tt cholmod\_sparse *}: a non-{\tt NULL} pointer to a newly allocated + sparse matrix if successful, or {\tt NULL} otherwise. +\item {\tt cholmod\_factor *}: a non-{\tt NULL} pointer to a newly allocated + factor if successful, or {\tt NULL} otherwise. +\item {\tt cholmod\_triplet *}: a non-{\tt NULL} pointer to a newly allocated + triplet matrix if successful, or {\tt NULL} otherwise. +\item {\tt cholmod\_dense *}: a non-{\tt NULL} pointer to a newly allocated + dense matrix if successful, or {\tt NULL} otherwise. \end{itemize} -{\tt TRUE} and {\tt FALSE} are not defined in {\tt cholmod.h}, -since they may conflict with the user program. A routine that described -here returning {\tt TRUE} or {\tt FALSE} returns 1 or 0, respectively. -Any {\tt TRUE}/{\tt FALSE} parameter is true if nonzero, false if zero. +{\tt TRUE} and {\tt FALSE} are not defined in {\tt cholmod.h}, since they may +conflict with the user program. A routine that described here returning {\tt +TRUE} or {\tt FALSE} returns 1 or 0, respectively. Any {\tt TRUE}/{\tt FALSE} +parameter is true if nonzero, false if zero. \noindent Input, output, and input/output parameters: \begin{itemize} -\item Input parameters appear first in the parameter lists of all CHOLMOD routines. -They are not modified by CHOLMOD. +\item Input parameters appear first in the parameter lists of all CHOLMOD +routines. They are not modified by CHOLMOD. \item Input/output parameters (except for {\tt Common}) appear next. They must be defined on input, and are modified on output. \item Output parameters are listed next. If they are pointers, they must point to allocated space on input, but their contents are not defined on input. -\item Workspace parameters appear next. They are used in only two routines in the Supernodal module. -\item The {\tt cholmod\_common *Common} parameter always appears as the last parameter -(with two exceptions: {\tt cholmod\_hypot} and {\tt cholmod\_divcomplex}). -It is always an input/output parameter. +\item Workspace parameters appear next. They are used in only two routines in +the Supernodal module. +\item The {\tt cholmod\_common *Common} parameter always appears as the last +parameter (with two exceptions: {\tt cholmod\_hypot} and {\tt +cholmod\_divcomplex}). It is always an input/output parameter. \end{itemize} A floating-point scalar is passed to CHOLMOD as a pointer to a {\tt double} @@ -1212,20 +1524,14 @@ \subsection{{\tt Partition} Module: graph-partitioning-based orderings} scalar, and the second entry is the imaginary part. The imaginary part is only accessed if the other inputs are complex or zomplex. In some cases the imaginary part is always ignored ({\tt cholmod\_factor\_p}, for example). +This method for passing scalars is used when the computations are done +both in {\tt double} and single ({\tt float}) precision. %------------------------------------------------------------------------------- \newpage \section{{\tt Utility} Module: {\tt cholmod\_common} object} \label{cholmod_common} %------------------------------------------------------------------------------- -%--------------------------------------- -\subsection{Constant definitions} -%--------------------------------------- - -\input{_defn.tex} -These definitions are used within the {\tt cholmod\_common} object, -called {\tt Common} both here and throughout the code. - %--------------------------------------- \subsection{{\tt cholmod\_common}: parameters, statistics, and workspace} %--------------------------------------- @@ -1236,12 +1542,12 @@ \subsection{{\tt cholmod\_common}: parameters, statistics, and workspace} {\tt cholmod\_start}, which initializes this object. %--------------------------------------- -\newpage \subsection{{\tt cholmod\_start}: start CHOLMOD} +\subsection{{\tt cholmod\_start}: start CHOLMOD} %--------------------------------------- \input{_start.tex} Sets the default parameters, clears the statistics, and initializes all -workspace pointers to {\tt NULL}. The {\tt int}/{\tt long} type +workspace pointers to {\tt NULL}. The {\tt int32}/{\tt int64\_t} type is set in {\tt Common->itype}. %--------------------------------------- @@ -1270,26 +1576,23 @@ \subsection{{\tt cholmod\_allocate\_work}: allocate workspace} %--------------------------------------- \input{_allocate_work.tex} -Allocates workspace in {\tt Common}. The workspace consists -of the integer {\tt Head}, {\tt Flag}, and {\tt Iwork} arrays, -of size {\tt nrow+1}, {\tt nrow}, and {\tt iworksize}, -respectively, and a {\tt double} array {\tt Xwork} of size -{\tt xworksize} entries. The {\tt Head} array is normally equal to -1 -when it is cleared. If the {\tt Flag} array is cleared, -all entries are less than {\tt Common->mark}. The {\tt Iwork} array is -not kept in any particular state. -The integer type is {\tt int} or {\tt long}, depending -on whether the {\tt cholmod\_} or {\tt cholmod\_l\_} routines -are used. +Allocates workspace in {\tt Common}. The workspace consists of the integer +{\tt Head}, {\tt Flag}, and {\tt Iwork} arrays, of size {\tt nrow+1}, {\tt +nrow}, and {\tt iworksize}, respectively, and a {\tt double} array {\tt Xwork} +of size {\tt xworksize} entries. The {\tt Head} array is normally equal to -1 +when it is cleared. If the {\tt Flag} array is cleared, all entries are less +than {\tt Common->mark}. The {\tt Iwork} array is not kept in any particular +state. The integer type is {\tt int32\_t} or {\tt int64\_t}, depending on +whether the {\tt cholmod\_} or {\tt cholmod\_l\_} routines are used. %--------------------------------------- -% \subsection{{\tt cholmod\_alloc\_work}: allocate workspace} +\subsection{{\tt cholmod\_alloc\_work}: allocate workspace} %--------------------------------------- -% \input{_alloc_work.tex} -% This is the same as {\tt cholmod\_allocate\_work}, except that -% the {\tt Xwork} array can be {\tt float} or {\tt double}, as -% determined by the {\tt dtype} input parameter. +\input{_alloc_work.tex} +This is the same as {\tt cholmod\_allocate\_work}, except that +the {\tt Xwork} array can be {\tt float} or {\tt double}, as +determined by the {\tt dtype} input parameter. %--------------------------------------- \subsection{{\tt cholmod\_free\_work}: free workspace} @@ -1310,11 +1613,9 @@ \subsection{{\tt cholmod\_error}: report error} %--------------------------------------- \input{_error.tex} -This routine is called when CHOLMOD encounters an error. -It prints a message (if printing is enabled), sets -{\tt Common->status}. It then calls the -user error handler routine {\tt Common->error\_handler}, -if it is not {\tt NULL}. +This routine is called when CHOLMOD encounters an error. It prints a message +(if printing is enabled), sets {\tt Common->status}. It then calls the user +error handler routine {\tt Common->error\_handler}, if it is not {\tt NULL}. %--------------------------------------- \subsection{{\tt cholmod\_dbound}: bound diagonal of $\m{L}$} @@ -1322,33 +1623,39 @@ \subsection{{\tt cholmod\_dbound}: bound diagonal of $\m{L}$} \input{_dbound.tex} Ensures that entries on the diagonal of $\m{L}$ for an $\m{LL}\tr$ -factorization are greater than or equal to {\tt Common->dbound}. +factorization are greater than or equal to {\tt Common->dbound}, +when computing in double precision ({\tt double}). For an $\m{LDL}\tr$ factorization, it ensures that the magnitude of the entries of $\m{D}$ are greater than or equal to {\tt Common->dbound}. +%--------------------------------------- +\subsection{{\tt cholmod\_sbound}: bound diagonal of $\m{L}$} +%--------------------------------------- + +\input{_sbound.tex} +Ensures that entries on the diagonal of $\m{L}$ for an $\m{LL}\tr$ +factorization are greater than or equal to {\tt Common->sbound}, when computing +in single precision ({\tt float}). For an $\m{LDL}\tr$ factorization, it +ensures that the magnitude of the entries of $\m{D}$ are greater than or equal +to {\tt Common->sbound}. + %--------------------------------------- \subsection{{\tt cholmod\_hypot}: {\tt sqrt(x*x+y*y)}} %--------------------------------------- \input{_hypot.tex} Computes the magnitude of a complex number. -This routine is the default value for the {\tt Common->hypotenuse} function pointer. -See also {\tt hypot}, in the standard {\tt math.h} header. If you have -the ANSI C99 {\tt hypot}, you can use {\tt Common->hypotenuse = hypot}. -The {\tt cholmod\_hypot} routine is provided in case you are using the -ANSI C89 standard, which does not have {\tt hypot}. +This routine calls {\tt SuiteSparse\_config\_hypot}. Refer to the +{\tt SuiteSparse\_config} package for details. %--------------------------------------- \subsection{{\tt cholmod\_divcomplex}: complex divide} %--------------------------------------- \input{_divcomplex.tex} -Divides two complex numbers. It returns 1 if a divide-by-zero occurred, or 0 otherwise. -This routine is the default value for the {\tt Common->complex\_divide} function pointer. -This return value is the single exception to the CHOLMOD rule that states all {\tt int} return -values are {\tt TRUE} if successful or {\tt FALSE} otherwise. -The exception is made to match the return value of a different complex divide routine -that is not a part of CHOLMOD, but can be used via the function pointer. +Divides two complex numbers. +This routine calls {\tt SuiteSparse\_config\_divcomplex}. Refer to the +{\tt SuiteSparse\_config} package for details. %------------------------------------------------------------------------------- \newpage \section{{\tt Utility} Module: {\tt cholmod\_sparse} object} @@ -1367,8 +1674,9 @@ \subsection{{\tt cholmod\_allocate\_sparse}: allocate sparse matrix} %--------------------------------------- \input{_allocate_sparse.tex} -Allocates a sparse matrix. {\tt A->i}, {\tt A->x}, and {\tt A->z} are not initialized. -The matrix returned is all zero, but it contains space enough for {\tt nzmax} entries. +Allocates a sparse matrix. Indices and values ({\tt A->i}, {\tt A->x}, and +{\tt A->z}) are allocated but not initialized. The matrix returned is valid, +has no entries, but contains space enough for {\tt nzmax} entries. %--------------------------------------- \subsection{{\tt cholmod\_free\_sparse}: free sparse matrix} @@ -1413,53 +1721,35 @@ \subsection{{\tt cholmod\_transpose}: transpose sparse matrix} \input{_transpose.tex} Returns the transpose or complex conjugate transpose of a sparse matrix. +Three kinds of transposes are available, depending on the {\tt mode} +parameter: -%--------------------------------------- -\subsection{{\tt cholmod\_ptranspose}: transpose/permute sparse matrix} -%--------------------------------------- - -\input{_ptranspose.tex} -Returns {\tt A'} or {\tt A(p,p)'} if {\tt A} is symmetric. -Returns {\tt A'}, {\tt A(:,f)'}, or {\tt A(p,f)'} if {\tt A} is unsymmetric. -See {\tt cholmod\_transpose\_unsym} for a discussion of how {\tt f} is used; -this usage deviates from the MATLAB notation. -Can also return the array transpose. - -%--------------------------------------- -\subsection{{\tt cholmod\_sort}: sort columns of a sparse matrix} -%--------------------------------------- - -\input{_sort.tex} -Sorts the columns of the matrix {\tt A}. Returns {\tt A} in packed form, even if it -starts as unpacked. Removes entries in the ignored part of a symmetric matrix. +\begin{itemize} +\item 0: do not compute the numerical values; create a + {\tt CHOLMOD\_PATTERN} matrix +\item 1: array transpose +\item 2: complex conjugate transpose (same as 2 if input is real or pattern) +\end{itemize} %--------------------------------------- -\subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric sparse matrix} +\subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric +sparse matrix} %--------------------------------------- \input{_transpose_unsym.tex} -Transposes and optionally permutes an unsymmetric sparse matrix. -The output matrix must be preallocated before calling this routine. +Transposes and optionally permutes an unsymmetric sparse matrix. The output +matrix must be preallocated before calling this routine. +The \verb'mode' parameter is the same as for \verb'cholmod_transpose'. Computes {\tt F=A'}, {\tt F=A(:,f)'} or {\tt F=A(p,f)'}, except that the indexing by {\tt f} does not work the same as the MATLAB notation (see below). -{\tt A->stype} is zero, which denotes that both the upper and lower triangular -parts of A are present (and used). The matrix {\tt A} may in fact be symmetric in pattern -and/or value; {\tt A->stype} just denotes which part of {\tt A} are stored. {\tt A} may be -rectangular. - -The integer vector -{\tt p} is a permutation of {\tt 0:m-1}, and {\tt f} is a subset of {\tt 0:n-1}, -where A is {\tt m}-by-{\tt n}. -There can be no duplicate entries in {\tt p} or {\tt f}. +{\tt A->stype} must be zero on input, which denotes that the matrix is +unsymmetric, with both the upper and lower triangular parts of A are present. +{\tt A} may be rectangular. -\noindent -Three kinds of transposes are available, depending on the {\tt values} parameter: -\begin{itemize} -\item 0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix -\item 1: array transpose -\item 2: complex conjugate transpose (same as 2 if input is real or pattern) -\end{itemize} +The integer vector {\tt p} is a permutation of {\tt 0:m-1}, and {\tt f} is a +subset of {\tt 0:n-1}, where A is {\tt m}-by-{\tt n}. There can be no +duplicate entries in {\tt p} or {\tt f}. \noindent The set {\tt f} is held in fset and fsize: @@ -1468,7 +1758,7 @@ \subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric spars \item {\tt fset != NULL} means {\tt f = fset [0..fsize-1]}. \item {\tt fset != NULL} and {\tt fsize = 0} means {\tt f} is the empty set. \end{itemize} - + Columns not in the set {\tt f} are considered to be zero. That is, if {\tt A} is 5-by-10 then {\tt F=A(:,[3 4])'} is not 2-by-5, but 10-by-5, and rows 3 and 4 of {\tt F} are equal to columns 3 and 4 of {\tt A} (the other @@ -1483,86 +1773,118 @@ \subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric spars F = F' \end{verbatim} -If you want the MATLAB equivalent {\tt F=A(p,f)} operation, use -{\tt cholmod\_submatrix} instead (which does not compute the transpose). -{\tt F->nzmax} must be large enough to hold the matrix {\tt F}. -If {\tt F->nz} is present then {\tt F->nz [j]} is equal to the number of entries in column {\tt j} of {\tt F}. -{\tt A} can be sorted or unsorted, with packed or unpacked columns. -If {\tt f} is present and not sorted in ascending order, then {\tt F} is unsorted -(that is, it may contain columns whose row indices do not appear in -ascending order). Otherwise, {\tt F} is sorted (the row indices in each -column of {\tt F} appear in strictly ascending order). +If you want the MATLAB equivalent {\tt F=A(p,f)} operation, use {\tt +cholmod\_submatrix} instead (which does not compute the transpose). {\tt +F->nzmax} must be large enough to hold the matrix {\tt F}. If {\tt F->nz} is +present then {\tt F->nz [j]} is equal to the number of entries in column {\tt +j} of {\tt F}. {\tt A} can be sorted or unsorted, with packed or unpacked +columns. If {\tt f} is present and not sorted in ascending order, then {\tt F} +is unsorted (that is, it may contain columns whose row indices do not appear in +ascending order). Otherwise, {\tt F} is sorted (the row indices in each column +of {\tt F} appear in strictly ascending order). -{\tt F} is returned in packed or unpacked form, depending on {\tt F->packed} on input. -If {\tt F->packed} is {\tt FALSE}, then {\tt F} is returned in unpacked form ({\tt F->nz} must be -present). Each row {\tt i} of {\tt F} is large enough to hold all the entries in row {\tt i} -of {\tt A}, even if {\tt f} is provided. That is, {\tt F->i} and -{\tt F->x [F->p [i] .. F->p [i] + F->nz [i] - 1]} contain all entries in {\tt A(i,f)}, -but {\tt F->p [i+1] - F->p [i]} is equal to the number of nonzeros in {\tt A (i,:)}, -not just {\tt A (i,f)}. -The {\tt cholmod\_transpose\_unsym} routine is the only operation in CHOLMOD that -can produce an unpacked matrix. +{\tt F} is returned in packed or unpacked form, depending on {\tt F->packed} on +input. If {\tt F->packed} is {\tt FALSE}, then {\tt F} is returned in unpacked +form ({\tt F->nz} must be present). Each row {\tt i} of {\tt F} is large +enough to hold all the entries in row {\tt i} of {\tt A}, even if {\tt f} is +provided. That is, {\tt F->i} and {\tt F->x [F->p [i] .. F->p [i] + F->nz [i] +- 1]} contain all entries in {\tt A(i,f)}, but {\tt F->p [i+1] - F->p [i]} is +equal to the number of nonzeros in {\tt A (i,:)}, not just {\tt A (i,f)}. The +{\tt cholmod\_transpose\_unsym} routine is the only operation in CHOLMOD that +can produce an unpacked sparse matrix. %--------------------------------------- -\subsection{{\tt cholmod\_transpose\_sym}: transpose/permute symmetric sparse matrix} +\subsection{{\tt cholmod\_transpose\_sym}: transpose/permute symmetric sparse +matrix} %--------------------------------------- \input{_transpose_sym.tex} -Computes {\tt F = A'} or {\tt F = A(p,p)'}, the transpose or permuted transpose, where -{\tt A->stype} is nonzero. {\tt A} must be square and symmetric. -If {\tt A->stype} $> 0$, then {\tt A} is a symmetric matrix where just the upper part -of the matrix is stored. Entries in the lower triangular part may be -present, but are ignored. -If {\tt A->stype} $< 0$, then {\tt A} is a symmetric matrix where just the lower part -of the matrix is stored. Entries in the upper triangular part may be present, but are ignored. -If {\tt F=A'}, then {\tt F} is returned -sorted; otherwise {\tt F} is unsorted for the {\tt F=A(p,p)'} case. -There can be no duplicate entries in {\tt p}. - -Three kinds of transposes are available, depending on the {\tt values} parameter: -\begin{itemize} -\item 0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix -\item 1: array transpose -\item 2: complex conjugate transpose (same as 2 if input is real or pattern) -\end{itemize} +Computes {\tt F = A'} or {\tt F = A(p,p)'}, the transpose or permuted +transpose, where {\tt A->stype} is nonzero. {\tt A} must be square and +symmetric. If {\tt A->stype} $> 0$, then {\tt A} is a symmetric matrix where +just the upper part of the matrix is stored. Entries in the lower triangular +part may be present, but are ignored. If {\tt A->stype} $< 0$, then {\tt A} is +a symmetric matrix where just the lower part of the matrix is stored. Entries +in the upper triangular part may be present, but are ignored. If {\tt F=A'}, +then {\tt F} is returned sorted; otherwise {\tt F} is unsorted for the {\tt +F=A(p,p)'} case. There can be no duplicate entries in {\tt p}. + +The \verb'mode' parameter is the same as for \verb'cholmod_transpose'. + +For {\tt cholmod\_transpose\_unsym} and {\tt cholmod\_transpose\_sym}, the +output matrix {\tt F} must already be pre-allocated by the caller, with the +correct dimensions. If {\tt F} is not valid or has the wrong dimensions, it is +not modified. Otherwise, if {\tt F} is too small, the transpose is not +computed; the contents of {\tt F->p} contain the column pointers of the +resulting matrix, where {\tt F->p [F->ncol] > F->nzmax}. In this case, the +remaining contents of {\tt F} are not modified. {\tt F} can still be properly +freed with {\tt cholmod\_free\_sparse}. -For {\tt cholmod\_transpose\_unsym} and {\tt cholmod\_transpose\_sym}, the output matrix -{\tt F} must already be pre-allocated by the caller, with the correct dimensions. -If {\tt F} is not valid or has the wrong dimensions, it is not modified. -Otherwise, if {\tt F} is too small, the transpose is not computed; the contents -of {\tt F->p} contain the column pointers of the resulting matrix, where -{\tt F->p [F->ncol] > F->nzmax}. In this case, the remaining contents of {\tt F} are -not modified. {\tt F} can still be properly freed with {\tt cholmod\_free\_sparse}. +%--------------------------------------- +\subsection{{\tt cholmod\_ptranspose}: transpose/permute sparse matrix} +%--------------------------------------- + +\input{_ptranspose.tex} +Returns {\tt A'} or {\tt A(p,p)'} if {\tt A} is symmetric. +Returns {\tt A'}, {\tt A(:,f)'}, or {\tt A(p,f)'} if {\tt A} is unsymmetric. +The \verb'mode' parameter is the same as for \verb'cholmod_transpose'. +See {\tt cholmod\_transpose\_unsym} for a discussion of how {\tt f} is used; +this usage deviates from the MATLAB notation. +Can also return the array transpose. + +%--------------------------------------- +\subsection{{\tt cholmod\_sort}: sort columns of a sparse matrix} +%--------------------------------------- + +\input{_sort.tex} +Sorts the columns of the matrix {\tt A}. Returns {\tt A} in packed form, even +if it starts as unpacked. Removes entries in the ignored part of a symmetric +matrix. + +%--------------------------------------- +\subsection{{\tt cholmod\_band\_nnz}: count entries in a band of a sparse +matrix} +%--------------------------------------- + +\input{_band_nnz.tex} +This method has the same inputs as \verb'cholmod_band', except that it +returns the count of entries instead of returning the new matrix. +The \verb'mode' parameter has no effect on this count. %--------------------------------------- \subsection{{\tt cholmod\_band}: extract band of a sparse matrix} %--------------------------------------- \input{_band.tex} -Returns {\tt C = tril (triu (A,k1), k2)}. -{\tt C} is a matrix consisting of the diagonals of A from {\tt k1} to {\tt k2}. -{\tt k=0} is the main diagonal of {\tt A}, {\tt k=1} is the superdiagonal, {\tt k=-1} is the -subdiagonal, and so on. If {\tt A} is {\tt m}-by-{\tt n}, then: +Returns {\tt C = tril (triu (A,k1), k2)}. {\tt C} is a matrix consisting of +the diagonals of A from {\tt k1} to {\tt k2}. {\tt k=0} is the main diagonal +of {\tt A}, {\tt k=1} is the superdiagonal, {\tt k=-1} is the subdiagonal, and +so on. If {\tt A} is {\tt m}-by-{\tt n}, then: + \begin{itemize} \item {\tt k1=-m} means {\tt C = tril (A,k2)} \item {\tt k2=n} means {\tt C = triu (A,k1)} -\item {\tt k1=0} and {\tt k2=0} means {\tt C = diag(A)}, except {\tt C} is a matrix, not a vector +\item {\tt k1=0} and {\tt k2=0} means {\tt C = diag(A)}, except {\tt C} is a +matrix, not a vector \end{itemize} -Values of {\tt k1} and {\tt k2} less than {\tt -m} are treated as {\tt -m}, and values greater -than {\tt n} are treated as {\tt n}. -{\tt A} can be of any symmetry (upper, lower, or unsymmetric); {\tt C} is returned in -the same form, and packed. If {\tt A->stype} $> 0$, entries in the lower -triangular part of {\tt A} are ignored, and the opposite is true if -{\tt A->stype} $< 0$. If {\tt A} has sorted columns, then so does {\tt C}. -{\tt C} has the same size as {\tt A}. +Values of {\tt k1} and {\tt k2} less than {\tt -m} are treated as {\tt -m}, and +values greater than {\tt n} are treated as {\tt n}. -{\tt C} can be returned as a numerical valued matrix (if {\tt A} has numerical values -and {\tt mode} $> 0$), as a pattern-only ({\tt mode} $=0$), or as a pattern-only but with -the diagonal entries removed ({\tt mode} $< 0$). +{\tt A} can be of any symmetry (upper, lower, or unsymmetric); {\tt C} is +returned in the same form, and packed. If {\tt A->stype} $> 0$, entries in the +lower triangular part of {\tt A} are ignored, and the opposite is true if {\tt +A->stype} $< 0$. If {\tt A} has sorted columns, then so does {\tt C}. {\tt C} +has the same size as {\tt A}. -The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only -if {\tt mode} is $\le 0$ (in which case the numerical values are ignored). +The \verb'mode' parameter determines how the numerical values are handled. +{\tt C} can be returned as a numerical valued matrix (if {\tt A} has numerical +values and {\tt mode} $> 0$), as a pattern-only ({\tt mode} $=0$), or as a +pattern-only but with the diagonal entries removed ({\tt mode} $< 0$). + +The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are +supported only if {\tt mode} is $\le 0$ (in which case the numerical values are +ignored). %--------------------------------------- \subsection{{\tt cholmod\_band\_inplace}: extract band, in place} @@ -1579,14 +1901,14 @@ \subsection{{\tt cholmod\_aat}: compute $\m{AA}\tr$} \input{_aat.tex} Computes {\tt C = A*A'} or {\tt C = A(:,f)*A(:,f)'}. {\tt A} can be packed or unpacked, sorted or unsorted, but must be stored with -both upper and lower parts ({\tt A->stype} of zero). {\tt C} is returned as packed, -{\tt C->stype} of zero (both upper and lower parts present), and unsorted. See -{\tt cholmod\_ssmult} in the {\tt MatrixOps} Module for a more general matrix-matrix -multiply. -The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only -if {\tt mode} is $\le 0$ (in which case the numerical values are ignored). -You can trivially convert {\tt C} to a symmetric upper/lower matrix -by changing {\tt C->stype} to 1 or -1, respectively, after calling this routine. +both upper and lower parts ({\tt A->stype} of zero). {\tt C} is returned as +packed, {\tt C->stype} of zero (both upper and lower parts present), and +unsorted. See {\tt cholmod\_ssmult} in the {\tt MatrixOps} Module for a more +general matrix-matrix multiply. The xtype of {\tt A} can be pattern or real. +Complex or zomplex cases are supported only if {\tt mode} is $\le 0$ (in which +case the numerical values are ignored). You can trivially convert {\tt C} to a +symmetric upper/lower matrix by changing {\tt C->stype} to 1 or -1, +respectively, after calling this routine. %--------------------------------------- \subsection{{\tt cholmod\_copy\_sparse}: copy sparse matrix} @@ -1600,26 +1922,30 @@ \subsection{{\tt cholmod\_copy}: copy (and change) sparse matrix} %--------------------------------------- \input{_copy.tex} -{\tt C = A}, which allocates {\tt C} and copies {\tt A} into {\tt C}, with possible change of -{\tt stype}. The diagonal can optionally be removed. The numerical entries -can optionally be copied. This routine differs from {\tt cholmod\_copy\_sparse}, -which makes an exact copy of a sparse matrix. +{\tt C = A}, which allocates {\tt C} and copies {\tt A} into {\tt C}, with +possible change of {\tt stype}. The diagonal can optionally be removed. The +numerical entries can optionally be copied. This routine differs from {\tt +cholmod\_copy\_sparse}, which makes an exact copy of a sparse matrix. -{\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric). {\tt C} is -packed and can be of any stype (upper/lower/unsymmetric), except that if -{\tt A} is rectangular {\tt C} can only be unsymmetric. If the stype of A and C -differ, then the appropriate conversion is made. +{\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric). {\tt C} +is packed and can be of any stype (upper/lower/unsymmetric), except that if +{\tt A} is rectangular {\tt C} can only be unsymmetric. If the stype of A and +C differ, then the appropriate conversion is made. \noindent There are three cases for {\tt A->stype}: \begin{itemize} -\item $<0$, lower: assume {\tt A} is symmetric with just {\tt tril(A)} stored; the rest of {\tt A} is ignored -\item $ 0$, unsymmetric: assume {\tt A} is unsymmetric; consider all entries in A -\item $>0$, upper: assume {\tt A} is symmetric with just {\tt triu(A)} stored; the rest of {\tt A} is ignored +\item $<0$, lower: assume {\tt A} is symmetric with just {\tt tril(A)} stored; +the rest of {\tt A} is ignored +\item $ 0$, unsymmetric: assume {\tt A} is unsymmetric; consider all entries +in A +\item $>0$, upper: assume {\tt A} is symmetric with just {\tt triu(A)} stored; +the rest of {\tt A} is ignored \end{itemize} \noindent -There are three cases for the requested symmetry of {\tt C} ({\tt stype} parameter): +There are three cases for the requested symmetry of {\tt C} ({\tt stype} +parameter): \begin{itemize} \item $<0$, lower: return just {\tt tril(C)} \item $0$, unsymmetric: return all of {\tt C} @@ -1628,25 +1954,31 @@ \subsection{{\tt cholmod\_copy}: copy (and change) sparse matrix} \noindent This gives a total of nine combinations: \newline + +{\small \begin{tabular}{ll} \hline -Equivalent MATLAB statements & Using {\tt cholmod\_copy} \\ +Equivalent MATLAB statements & Using {\tt cholmod\_copy} \\ \hline -{\tt C = A ; }& {\tt A} unsymmetric, {\tt C} unsymmetric \\ -{\tt C = tril (A) ; }& {\tt A} unsymmetric, {\tt C} lower \\ -{\tt C = triu (A) ; }& {\tt A} unsymmetric, {\tt C} upper \\ -{\tt U = triu (A) ; L = tril (U',-1) ; C = L+U ; }& {\tt A} upper, {\tt C} unsymmetric \\ -{\tt C = triu (A)' ; }& {\tt A} upper, {\tt C} lower \\ -{\tt C = triu (A) ; }& {\tt A} upper, {\tt C} upper \\ -{\tt L = tril (A) ; U = triu (L',1) ; C = L+U ; }& {\tt A} lower, {\tt C} unsymmetric \\ -{\tt C = tril (A) ; }& {\tt A} lower, {\tt C} lower \\ -{\tt C = tril (A)' ; }& {\tt A} lower, {\tt C} upper \\ +{\tt C = A ; }& {\tt A} unsymmetric, {\tt C} unsymmetric \\ +{\tt C = tril (A) ; }& {\tt A} unsymmetric, {\tt C} lower \\ +{\tt C = triu (A) ; }& {\tt A} unsymmetric, {\tt C} upper \\ +{\tt U = triu (A) ; L = tril (U',-1) ; C = L+U ;} + & {\tt A} upper, {\tt C} unsymmetric \\ +{\tt C = triu (A)' ; }& {\tt A} upper, {\tt C} lower \\ +{\tt C = triu (A) ; }& {\tt A} upper, {\tt C} upper \\ +{\tt L = tril (A) ; U = triu (L',1) ; C = L+U ;} + & {\tt A} lower, {\tt C} unsymmetric \\ +{\tt C = tril (A) ; }& {\tt A} lower, {\tt C} lower \\ +{\tt C = tril (A)' ; }& {\tt A} lower, {\tt C} upper \\ \hline -\end{tabular} +\end{tabular}} \vspace{0.1in} -The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only -if {\tt values} is {\tt FALSE} (in which case the numerical values are ignored). +The \verb'mode' parameter determines whether a pattern-only copy is made, or +whether a numerical copy is make, and also how the transpose is done above for +the complex case (conjugate matrix transpose, or non-conjugate array +transpose). %--------------------------------------- \subsection{{\tt cholmod\_add}: add sparse matrices} @@ -1654,17 +1986,19 @@ \subsection{{\tt cholmod\_add}: add sparse matrices} \input{_add.tex} Returns {\tt C = alpha*A + beta*B}. -If the {\tt stype} of {\tt A} and {\tt B} match, then {\tt C} has -the same {\tt stype}. Otherwise, {\tt C->stype} is zero ({\tt C} is -unsymmetric). +If the {\tt stype} of {\tt A} and {\tt B} match, then {\tt C} has the same {\tt +stype}. Otherwise, {\tt C->stype} is zero ({\tt C} is unsymmetric). If the +\verb'stype' of any input matrix is nonzero, it must be converted to +unsymmetric, controlled by the \verb'mode' parameter. %--------------------------------------- \subsection{{\tt cholmod\_sparse\_xtype}: change sparse xtype} %--------------------------------------- \input{_sparse_xtype.tex} -Changes the {\tt xtype} of a sparse matrix, to pattern, real, complex, or zomplex. -Changing from complex or zomplex to real discards the imaginary part. +Changes the {\tt xtype} and/or \verb'dtype' of a sparse matrix, to pattern, +real, complex, or zomplex. Changing from complex or zomplex to real discards +the imaginary part. %------------------------------------------------------------------------------- \newpage \section{{\tt Utility} Module: {\tt cholmod\_factor} object} @@ -1695,6 +2029,14 @@ \subsection{{\tt cholmod\_allocate\_factor}: allocate factor} \input{_allocate_factor.tex} Allocates a factor and sets it to identity. +%--------------------------------------- +\subsection{{\tt cholmod\_alloc\_factor}: allocate factor} +%--------------------------------------- + +\input{_alloc_factor.tex} +Allocates a factor and sets it to identity +({\tt double} or {\tt float}). + %--------------------------------------- \subsection{{\tt cholmod\_reallocate\_factor}: reallocate factor} %--------------------------------------- @@ -1707,75 +2049,83 @@ \subsection{{\tt cholmod\_change\_factor}: change factor} %--------------------------------------- \input{_change_factor.tex} -Change the numeric or symbolic, $\m{LL}\tr$ or $\m{LDL}\tr$, simplicial or super, packed or unpacked, and -monotonic or non-monotonic status of a {\tt cholmod\_factor} object. +Change the numeric or symbolic, $\m{LL}\tr$ or $\m{LDL}\tr$, simplicial or +super, packed or unpacked, and monotonic or non-monotonic status of a {\tt +cholmod\_factor} object. There are four basic classes of factor types: \begin{enumerate} -\item simplicial symbolic: Consists of two size-{\tt n} arrays: the fill-reducing - permutation ({\tt L->Perm}) and the nonzero count for each column of L - ({\tt L->ColCount}). All other factor types also include this information. - {\tt L->ColCount} may be exact (obtained from the analysis routines), or it - may be a guess. During factorization, and certainly after update/downdate, - the columns of {\tt L} can have a different number of nonzeros. {\tt - L->ColCount} is used to allocate space. {\tt L->ColCount} is exact for the - supernodal factorizations. The nonzero pattern of {\tt L} is not kept. - -\item simplicial numeric: These represent {\tt L} in a compressed column form. The - variants of this type are: +\item simplicial symbolic: Consists of two size-{\tt n} arrays: the + fill-reducing permutation ({\tt L->Perm}) and the nonzero count for each + column of L ({\tt L->ColCount}). All other factor types also include this + information. {\tt L->ColCount} may be exact (obtained from the analysis + routines), or it may be a guess. During factorization, and certainly after + update/downdate, the columns of {\tt L} can have a different number of + nonzeros. {\tt L->ColCount} is used to allocate space. {\tt L->ColCount} + is exact for the supernodal factorizations. The nonzero pattern of {\tt L} + is not kept. + +\item simplicial numeric: These represent {\tt L} in a compressed column form. + The variants of this type are: \begin{itemize} - \item $\m{LDL}\tr$: {\tt L} is unit diagonal. Row indices in column {\tt j} are located in - {\tt L->i [L->p [j] ... L->p [j] + L->nz [j]]}, and corresponding numeric - values are in the same locations in {\tt L->x}. The total number of - entries is the sum of {\tt L->nz [j]}. The unit diagonal is not stored; - {\tt D} is stored on the diagonal of {\tt L} instead. {\tt L->p} may or may not be - monotonic. The order of storage of the columns in {\tt L->i} and {\tt L->x} is - given by a doubly-linked list ({\tt L->prev} and {\tt L->next}). {\tt L->p} is of - size {\tt n+1}, but only the first {\tt n} entries are used. - - For the complex case, {\tt L->x} is stored interleaved with real and imaginary - parts, and is of size {\tt 2*lnz*sizeof(double)}. For the zomplex case, - {\tt L->x} is of size {\tt lnz*sizeof(double)} and holds the real part; {\tt L->z} - is the same size and holds the imaginary part. - - \item $\m{LL}\tr$: This is identical to the $\m{LDL}\tr$ form, except that the non-unit - diagonal of {\tt L} is stored as the first entry in each column of {\tt L}. + \item $\m{LDL}\tr$: {\tt L} is unit diagonal. Row indices in column {\tt + j} are located in {\tt L->i [L->p [j] ... L->p [j] + L->nz [j]]}, and + corresponding numeric values are in the same locations in {\tt L->x}. + The total number of entries is the sum of {\tt L->nz [j]}. The unit + diagonal is not stored; {\tt D} is stored on the diagonal of {\tt L} + instead. {\tt L->p} may or may not be monotonic. The order of storage + of the columns in {\tt L->i} and {\tt L->x} is given by a doubly-linked + list ({\tt L->prev} and {\tt L->next}). {\tt L->p} is of size {\tt + n+1}, but only the first {\tt n} entries are used. + + For the complex case, {\tt L->x} is stored interleaved with real and + imaginary parts, and is of size {\tt 2*lnz*sizeof(double)} or {\tt + 2*lnz*sizeof(float)}. For the zomplex case, {\tt L->x} is of size {\tt + lnz*sizeof(double)} or {\tt lnz*sizeof(float)} and holds the real part; + {\tt L->z} is the same size and holds the imaginary part. + + \item $\m{LL}\tr$: This is identical to the $\m{LDL}\tr$ form, except that + the non-unit diagonal of {\tt L} is stored as the first entry in each + column of {\tt L}. + \end{itemize} \item supernodal symbolic: A representation of the nonzero pattern of the supernodes for a supernodal factorization. There are {\tt L->nsuper} - supernodes. Columns {\tt L->super [k]} to {\tt L->super [k+1]-1} are in the {\tt k}th - supernode. The row indices for the {\tt k}th supernode are in - {\tt L->s [L->pi [k] ... L->pi [k+1]-1]}. The numerical values are not - allocated ({\tt L->x}), but when they are they will be located in - {\tt L->x [L->px [k] ... L->px [k+1]-1]}, and the {\tt L->px} array is defined - in this factor type. - - For the complex case, {\tt L->x} is stored interleaved with real/imaginary parts, - and is of size \newline - {\tt 2*L->xsize*sizeof(double)}. The zomplex supernodal case - is not supported, since it is not compatible with LAPACK and the BLAS. - -\item supernodal numeric: Always an $\m{LL}\tr$ factorization. {\tt L} has a non-unit - diagonal. {\tt L->x} contains the numerical values of the supernodes, as - described above for the supernodal symbolic factor. - For the complex case, {\tt L->x} is stored interleaved, and is of size - {\tt 2*L->xsize*sizeof(double)}. The zomplex supernodal case is not - supported, since it is not compatible with LAPACK and the BLAS. + supernodes. Columns {\tt L->super [k]} to {\tt L->super [k+1]-1} are in + the {\tt k}th supernode. The row indices for the {\tt k}th supernode are + in {\tt L->s [L->pi [k] ... L->pi [k+1]-1]}. The numerical values are not + allocated ({\tt L->x}), but when they are they will be located in {\tt L->x + [L->px [k] ... L->px [k+1]-1]}, and the {\tt L->px} array is defined in + this factor type. + + For the complex case, {\tt L->x} is stored interleaved with real/imaginary + parts, and is of size \newline {\tt 2*L->xsize*sizeof(double)} or {\tt + 2*L->xsize*sizeof(float)}. The zomplex supernodal case is not + supported, since it is not compatible with LAPACK and the BLAS. + +\item supernodal numeric: Always an $\m{LL}\tr$ factorization. {\tt L} has a + non-unit diagonal. {\tt L->x} contains the numerical values of the + supernodes, as described above for the supernodal symbolic factor. For the + complex case, {\tt L->x} is stored interleaved, and is of size {\tt + 2*L->xsize*sizeof(double)} or {\tt 2*L->xsize*sizeof(double)}. The zomplex + supernodal case is not supported, since it is not compatible with LAPACK + and the BLAS. + \end{enumerate} -In all cases, the row indices in each column ({\tt L->i} for simplicial {\tt L} and -{\tt L->s} for supernodal {\tt L}) are kept sorted from low indices to high indices. -This means the diagonal of {\tt L} (or {\tt D} for a $\m{LDL}\tr$ factorization) is always kept as the -first entry in each column. The elimination tree is not kept. The parent -of node {\tt j} can be found as the second row index in the {\tt j}th column. -If column {\tt j} has no off-diagonal entries then node {\tt j} is a root -of the elimination tree. +In all cases, the row indices in each column ({\tt L->i} for simplicial {\tt L} +and {\tt L->s} for supernodal {\tt L}) are kept sorted from low indices to high +indices. This means the diagonal of {\tt L} (or {\tt D} for a $\m{LDL}\tr$ +factorization) is always kept as the first entry in each column. The +elimination tree is not kept. The parent of node {\tt j} can be found as the +second row index in the {\tt j}th column. If column {\tt j} has no +off-diagonal entries then node {\tt j} is a root of the elimination tree. -The {\tt cholmod\_change\_factor} routine can do almost all possible conversions. -It cannot do the following conversions: +The {\tt cholmod\_change\_factor} routine can do almost all possible +conversions. It cannot do the following conversions: \begin{itemize} \item Simplicial numeric types cannot be converted to a supernodal @@ -1798,9 +2148,9 @@ \subsection{{\tt cholmod\_change\_factor}: change factor} Supports all xtypes, except that there is no supernodal zomplex L. -The {\tt to\_xtype} parameter is used only when converting from symbolic to numeric -or numeric to symbolic. It cannot be used to convert a numeric xtype (real, -complex, or zomplex) to a different numeric xtype. For that conversion, +The {\tt to\_xdtype} parameter is used only when converting from symbolic to +numeric or numeric to symbolic. It cannot be used to convert a numeric xtype +(real, complex, or zomplex) to a different numeric xtype. For that conversion, use {\tt cholmod\_factor\_xtype} instead. %--------------------------------------- @@ -1808,21 +2158,24 @@ \subsection{{\tt cholmod\_pack\_factor}: pack the columns of a factor} %--------------------------------------- \input{_pack_factor.tex} -Pack the columns of a simplicial $\m{LDL}\tr$ or $\m{LL}\tr$ factorization. This can be followed -by a call to {\tt cholmod\_reallocate\_factor} to reduce the size of {\tt L} to the exact -size required by the factor, if desired. Alternatively, you can leave the -size of {\tt L->i} and {\tt L->x} the same, to allow space for future updates/rowadds. -Each column is reduced in size so that it has at most {\tt Common->grow2} free -space at the end of the column. -Does nothing and returns silently if given any other type of factor. -Does not force the columns of {\tt L} to be monotonic. It thus differs from +Pack the columns of a simplicial $\m{LDL}\tr$ or $\m{LL}\tr$ factorization. +This can be followed by a call to {\tt cholmod\_reallocate\_factor} to reduce +the size of {\tt L} to the exact size required by the factor, if desired. +Alternatively, you can leave the size of {\tt L->i} and {\tt L->x} the same, to +allow space for future updates/rowadds. Each column is reduced in size so that +it has at most {\tt Common->grow2} free space at the end of the column. Does +nothing and returns silently if given any other type of factor. Does not force +the columns of {\tt L} to be monotonic. It thus differs from + \begin{verbatim} cholmod_change_factor (xtype, L->is_ll, FALSE, TRUE, TRUE, L, Common) \end{verbatim} + which packs the columns and ensures that they appear in monotonic order. %--------------------------------------- -\subsection{{\tt cholmod\_reallocate\_column}: reallocate one column of a factor} +\subsection{{\tt cholmod\_reallocate\_column}: reallocate one column of a +factor} %--------------------------------------- \input{_reallocate_column.tex} @@ -1885,14 +2238,6 @@ \subsection{{\tt cholmod\_free\_dense}: free dense matrix} \input{_free_dense.tex} Frees a dense matrix. -%--------------------------------------- -\subsection{{\tt cholmod\_ensure\_dense}: ensure dense matrix has a given size -and type} -%--------------------------------------- - -\input{_ensure_dense.tex} -Ensures a dense matrix has a given size and type. - %--------------------------------------- %--------------------------------------- @@ -1916,6 +2261,14 @@ \subsection{{\tt cholmod\_eye}: dense identity matrix} \input{_eye.tex} Returns a dense identity matrix. +%--------------------------------------- +\subsection{{\tt cholmod\_ensure\_dense}: ensure dense matrix has a given size +and type} +%--------------------------------------- + +\input{_ensure_dense.tex} +Ensures a dense matrix has a given size and type. + %--------------------------------------- \subsection{{\tt cholmod\_sparse\_to\_dense}: dense matrix copy of a sparse matrix} %--------------------------------------- @@ -1949,15 +2302,17 @@ \subsection{{\tt cholmod\_copy\_dense2}: copy dense matrix (preallocated)} %--------------------------------------- \input{_copy_dense2.tex} -Returns a copy of a dense matrix, placing the result in a preallocated matrix {\tt Y}. +Returns a copy of a dense matrix, placing the result in a preallocated matrix +{\tt Y}. %--------------------------------------- \subsection{{\tt cholmod\_dense\_xtype}: change dense matrix xtype} %--------------------------------------- \input{_dense_xtype.tex} -Changes the {\tt xtype} of a dense matrix, to real, complex, or zomplex. -Changing from complex or zomplex to real discards the imaginary part. +Changes the {\tt xtype} and/or {\tt dtype} of a dense matrix, to real, complex, +or zomplex. Changing from complex or zomplex to real discards the imaginary +part. A dense matrix cannot be converted to an xtype of pattern-only. %------------------------------------------------------------------------------- \newpage \section{{\tt Utility} Module: {\tt cholmod\_triplet} object} @@ -1985,6 +2340,20 @@ \subsection{{\tt cholmod\_free\_triplet}: free triplet matrix} \input{_free_triplet.tex} Frees a triplet matrix. +%--------------------------------------- +\subsection{{\tt cholmod\_triplet\_to\_sparse}: sparse matrix copy of a triplet +matrix} +%--------------------------------------- + +\input{_triplet_to_sparse.tex} +Returns a sparse matrix copy of a triplet matrix. If the triplet matrix is +symmetric with just the lower part present ({\tt T->stype} $< 0$), then entries +in the upper part are transposed and placed in the lower part when converting +to a sparse matrix. Similarly, if the triplet matrix is symmetric with just +the upper part present ({\tt T->stype} $> 0$), then entries in the lower part +are transposed and placed in the upper part when converting to a sparse matrix. +Any duplicate entries are summed. + %--------------------------------------- \subsection{{\tt cholmod\_reallocate\_triplet}: reallocate triplet matrix} %--------------------------------------- @@ -1999,20 +2368,6 @@ \subsection{{\tt cholmod\_sparse\_to\_triplet}: triplet matrix copy of a sparse \input{_sparse_to_triplet.tex} Returns a triplet matrix copy of a sparse matrix. -%--------------------------------------- -\subsection{{\tt cholmod\_triplet\_to\_sparse}: sparse matrix copy of a triplet matrix} -%--------------------------------------- - -\input{_triplet_to_sparse.tex} -Returns a sparse matrix copy of a triplet matrix. -If the triplet matrix is symmetric with just the lower part present ({\tt T->stype} $< 0$), -then entries in the upper part are transposed and placed in the lower part when -converting to a sparse matrix. Similarly, -if the triplet matrix is symmetric with just the upper part present ({\tt T->stype} $> 0$), -then entries in the lower part are transposed and placed in the upper part when -converting to a sparse matrix. -Any duplicate entries are summed. - %--------------------------------------- \subsection{{\tt cholmod\_copy\_triplet}: copy triplet matrix} %--------------------------------------- @@ -2037,63 +2392,61 @@ \subsection{{\tt cholmod\_malloc}: allocate memory} %--------------------------------------- \input{_malloc.tex} -Allocates a block of memory of size {\tt n*size}, -using the {\tt SuiteSparse\_config.malloc\_func} -function pointer (default is to use the ANSI C {\tt malloc} routine). -A value of {\tt n=0} is treated as {\tt n=1}. -If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. +Allocates a block of memory of size {\tt n*size}, using the {\tt +SuiteSparse\_config.malloc\_func} function pointer (default is to use the ANSI +C {\tt malloc} routine). A value of {\tt n=0} is treated as {\tt n=1}. +If not successful, {\tt NULL} is returned and {\tt Common->status} is set to +{\tt CHOLMOD\_OUT\_OF\_MEMORY}. %--------------------------------------- \subsection{{\tt cholmod\_calloc}: allocate and clear memory} %--------------------------------------- \input{_calloc.tex} -Allocates a block of memory of size {\tt n*size}, -using the {\tt SuiteSparse\_config.calloc\_func} -function pointer (default is to use the ANSI C {\tt calloc} routine). -A value of {\tt n=0} is treated as {\tt n=1}. -If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. +Allocates a block of memory of size {\tt n*size}, using the {\tt +SuiteSparse\_config.calloc\_func} function pointer (default is to use the ANSI +C {\tt calloc} routine). A value of {\tt n=0} is treated as {\tt n=1}. If not +successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt +CHOLMOD\_OUT\_OF\_MEMORY}. %--------------------------------------- \subsection{{\tt cholmod\_free}: free memory} %--------------------------------------- \input{_free.tex} -Frees a block of memory of size {\tt n*size}, -using the {\tt SuiteSparse\_config.free\_func} -function pointer (default is to use the ANSI C {\tt free} routine). -The size of the block ({\tt n} and {\tt size}) is only required so that CHOLMOD -can keep track of its current and peak memory usage. This is a useful statistic, -and it can also help in tracking down memory leaks. After the call to -{\tt cholmod\_finish}, the count of allocated blocks ({\tt Common->malloc\_count}) -should be zero, and the count of bytes in use ({\tt Common->memory\_inuse}) also -should be zero. If you allocate a block with one size and free it with another, -the {\tt Common->memory\_inuse} count will be wrong, but CHOLMOD will not -have a memory leak. +Frees a block of memory of size {\tt n*size}, using the {\tt +SuiteSparse\_config.free\_func} function pointer (default is to use the ANSI C +{\tt free} routine). The size of the block ({\tt n} and {\tt size}) is only +required so that CHOLMOD can keep track of its current and peak memory usage. +This is a useful statistic, and it can also help in tracking down memory leaks. +After the call to {\tt cholmod\_finish}, the count of allocated blocks ({\tt +Common->malloc\_count}) should be zero, and the count of bytes in use ({\tt +Common->memory\_inuse}) also should be zero. If you allocate a block with one +size and free it with another, the {\tt Common->memory\_inuse} count will be +wrong, but CHOLMOD will not have a memory leak. %--------------------------------------- \subsection{{\tt cholmod\_realloc}: reallocate memory} %--------------------------------------- \input{_realloc.tex} -Reallocates a block of memory whose current size {\tt n*size}, -and whose new size will be {\tt nnew*size} if successful, -using the {\tt SuiteSparse\_config.calloc\_func} -function pointer (default is to use the ANSI C {\tt realloc} routine). -If the reallocation is not successful, {\tt p} is returned unchanged -and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. -The value of {\tt n} is set to {\tt nnew} if successful, or left -unchanged otherwise. -A value of {\tt nnew=0} is treated as {\tt nnew=1}. +Reallocates a block of memory whose current size {\tt n*size}, and whose new +size will be {\tt nnew*size} if successful, using the {\tt +SuiteSparse\_config.calloc\_func} function pointer (default is to use the ANSI +C {\tt realloc} routine). If the reallocation is not successful, {\tt p} is +returned unchanged and {\tt Common->status} is set to {\tt +CHOLMOD\_OUT\_OF\_MEMORY}. The value of {\tt n} is set to {\tt nnew} if +successful, or left unchanged otherwise. A value of {\tt nnew=0} is treated as +{\tt nnew=1}. %--------------------------------------- \subsection{{\tt cholmod\_realloc\_multiple}: reallocate memory} %--------------------------------------- \input{_realloc_multiple.tex} -Reallocates multiple blocks of memory, all with the same number of items -(but with different item sizes). Either all reallocations succeed, -or all are returned to their original size. +Reallocates multiple blocks of memory, all with the same number of items (but +with different item sizes). Either all reallocations succeed, or all are +returned to their original size. %------------------------------------------------------------------------------- \newpage \section{{\tt Utility} Module: version control} @@ -2119,13 +2472,7 @@ \subsection{{\tt cholmod\_version}: return current CHOLMOD version} Note that {\tt cholmod\_version} and {\tt cholmod\_l\_version} have identical prototypes. Both use {\tt int}'s. Unlike all other CHOLMOD functions, this -function does not take the {\tt Common} object as an input parameter, and it -does not use any definitions from any include files. Thus, the caller can -access this function even if the caller does not include any CHOLMOD include -files. - -The above code fragment does require the {\tt \#include "cholmod.h"}, -of course, but {\tt cholmod\_version} can be called without it, if necessary. +function does not take the {\tt Common} object as an input parameter. %------------------------------------------------------------------------------- \newpage \section{{\tt Check} Module routines} @@ -2133,15 +2480,17 @@ \subsection{{\tt cholmod\_version}: return current CHOLMOD version} No CHOLMOD routines print anything, except for the {\tt cholmod\_print\_*} routines in the {\tt Check} Module, and the {\tt cholmod\_error} routine. The -{\tt SuiteSparse\_config.printf\_function} is a pointer to {\tt printf} by default; -you can redirect the output of CHOLMOD by redefining this pointer. -If the function pointer is {\tt NULL}, CHOLMOD does not print anything. +{\tt SuiteSparse\_config.printf\_function} is a pointer to {\tt printf} by +default; you can redirect the output of CHOLMOD by redefining this pointer. If +the function pointer is {\tt NULL}, CHOLMOD does not print anything. + +The {\tt Common->print} parameter determines how much detail is printed. Each +value of {\tt Common->print} listed below also prints the items listed for +smaller values of {\tt Common->print}: -The {\tt Common->print} parameter determines how much detail is printed. -Each value of {\tt Common->print} listed below also prints the items listed -for smaller values of {\tt Common->print}: \begin{itemize} -\item 0: print nothing; check the data structures and return {\tt TRUE} or {\tt FALSE}. +\item 0: print nothing; check the data structures and return {\tt TRUE} or {\tt +FALSE}. \item 1: print error messages. \item 2: print warning messages. \item 3: print a one-line summary of the object. @@ -2269,14 +2618,13 @@ \subsection{{\tt cholmod\_read\_triplet}: read triplet matrix from file} %--------------------------------------- \input{_read_triplet.tex} -Read a sparse matrix in triplet form, using the the {\tt coord} -Matrix Market format (http://www.nist.gov/MatrixMarket). -Skew-symmetric and complex symmetric matrices are returned with -both upper and lower triangular parts present (an stype of zero). -Real symmetric and complex Hermitian matrices are returned with just -their upper or lower triangular part, depending on their stype. -The Matrix Market {\tt array} data type for dense matrices is not supported -(use {\tt cholmod\_read\_dense} for that case). +Read a sparse matrix in triplet form, using the the {\tt coord} Matrix Market +format (http://www.nist.gov/MatrixMarket). Skew-symmetric and complex +symmetric matrices are returned with both upper and lower triangular parts +present (an stype of zero). Real symmetric and complex Hermitian matrices are +returned with just their upper or lower triangular part, depending on their +stype. The Matrix Market {\tt array} data type for dense matrices is not +supported (use {\tt cholmod\_read\_dense} for that case). If the first line of the file starts with {\tt \%\%MatrixMarket}, then it is interpreted as a file in Matrix Market format. The header line is optional. @@ -2287,121 +2635,160 @@ \subsection{{\tt cholmod\_read\_triplet}: read triplet matrix from file} \vspace{0.1in} \noindent -where {\em type} is one of: {\tt real}, {\tt complex}, {\tt pattern}, -or {\tt integer}, and {\em storage} is one of: {\tt general}, {\tt hermitian}, -{\tt symmetric}, or {\tt skew-symmetric}. -In CHOLMOD, these roughly correspond to the {\tt xtype} -(pattern, real, complex, or zomplex) and {\tt stype} -(unsymmetric, symmetric/upper, and symmetric/lower). -The strings are case-insensitive. Only the first character (or the -first two for skew-symmetric) is significant. -The {\tt coord} token can be replaced with {\tt array} in the Matrix Market format, but -this format not supported by {\tt cholmod\_read\_triplet}. -The {\tt integer} type is converted to real. -The {\em type} is ignored; the actual type (real, complex, or pattern) is -inferred from the number of tokens in each line of the file (2: pattern, -3: real, 4: complex). This is compatible with the Matrix Market format. - -A storage of {\tt general} implies an stype of zero -(see below). A storage of {\tt symmetric} and {\tt hermitian} imply an stype of -1. -Skew-symmetric and complex symmetric matrices are returned with an stype of 0. -Blank lines, any other lines starting with ``{\tt \%}'' are treated as comments, and are ignored. +where {\em type} is one of: {\tt real}, {\tt complex}, {\tt pattern}, or {\tt +integer}, and {\em storage} is one of: {\tt general}, {\tt hermitian}, {\tt +symmetric}, or {\tt skew-symmetric}. In CHOLMOD, these roughly correspond to +the {\tt xtype} (pattern, real, complex, or zomplex) and {\tt stype} +(unsymmetric, symmetric/upper, and symmetric/lower). The strings are +case-insensitive. Only the first character (or the first two for +skew-symmetric) is significant. The {\tt coord} token can be replaced with +{\tt array} in the Matrix Market format, but this format not supported by {\tt +cholmod\_read\_triplet}. The {\tt integer} type is converted to real. The +{\em type} is ignored; the actual type (real, complex, or pattern) is inferred +from the number of tokens in each line of the file (2: pattern, 3: real, 4: +complex). This is compatible with the Matrix Market format. + +The matrix is read in {\tt double} precision. To read a matrix +in either double or single precision ({\tt double} or {\tt float}), +use \verb'cholmod_read_triplet2'. + +A storage of {\tt general} implies an stype of zero (see below). A storage of +{\tt symmetric} and {\tt hermitian} imply an stype of -1. Skew-symmetric and +complex symmetric matrices are returned with an stype of 0. Blank lines, any +other lines starting with ``{\tt \%}'' are treated as comments, and are +ignored. The first non-comment line contains 3 or 4 integers: \vspace{0.1in} - {\em nrow ncol nnz stype} + {\em nrow ncol nnz stype} \vspace{0.1in} \noindent -where {\em stype} is optional (stype does not appear in the Matrix Market format). -The matrix is {\em nrow}-by-{\em ncol}. The following {\em nnz} lines (excluding comments) -each contain a single entry. Duplicates are permitted, and are summed in -the output matrix. +where {\em stype} is optional (stype does not appear in the Matrix Market +format). The matrix is {\em nrow}-by-{\em ncol}. The following {\em nnz} +lines (excluding comments) each contain a single entry. Duplicates are +permitted, and are summed in the output matrix. If stype is present, it denotes the storage format for the matrix. \begin{itemize} \item stype = 0 denotes an unsymmetric matrix (same as Matrix Market {\tt general}). -\item stype = -1 denotes a symmetric or Hermitian matrix whose lower triangular - entries are stored. Entries may be present in the upper triangular - part, but these are ignored (same as Matrix Market {\tt symmetric} - for the real case, {\tt hermitian} for the complex case). -\item stype = 1 denotes a symmetric or Hermitian matrix whose upper triangular - entries are stored. Entries may be present in the lower triangular - part, but these are ignored. This format is not available in the Matrix - Market format. +\item stype = -1 denotes a symmetric or Hermitian matrix whose lower triangular + entries are stored. Entries may be present in the upper triangular + part, but these are ignored (same as Matrix Market {\tt symmetric} + for the real case, {\tt hermitian} for the complex case). +\item stype = 1 denotes a symmetric or Hermitian matrix whose upper triangular + entries are stored. Entries may be present in the lower triangular + part, but these are ignored. This format is not available in the Matrix + Market format. \end{itemize} -If neither the stype nor the Matrix Market header are present, then -the stype is inferred from the rest of the data. If the matrix is -rectangular, or has -entries in both the upper and lower triangular parts, then it is assumed to -be unsymmetric (stype=0). If only entries in the lower triangular part are +If neither the stype nor the Matrix Market header are present, then the stype +is inferred from the rest of the data. If the matrix is rectangular, or has +entries in both the upper and lower triangular parts, then it is assumed to be +unsymmetric (stype=0). If only entries in the lower triangular part are present, the matrix is assumed to have stype = -1. If only entries in the upper triangular part are present, the matrix is assumed to have stype = 1. -Each nonzero consists of one line with 2, 3, or 4 entries. All lines must -have the same number of entries. The first two entries are the row and -column indices of the nonzero. If 3 entries are present, the 3rd entry is -the numerical value, and the matrix is real. If 4 entries are present, -the 3rd and 4th entries in the line are the real and imaginary parts of -a complex value. +Each nonzero consists of one line with 2, 3, or 4 entries. All lines must have +the same number of entries. The first two entries are the row and column +indices of the nonzero. If 3 entries are present, the 3rd entry is the +numerical value, and the matrix is real. If 4 entries are present, the 3rd and +4th entries in the line are the real and imaginary parts of a complex value. The matrix can be either 0-based or 1-based. It is first assumed to be -one-based (compatible with Matrix Market), with row indices in the range -1 to ncol and column indices in the range 1 to nrow. If a row or column -index of zero is found, the matrix is assumed to be zero-based (with row -indices in the range 0 to ncol-1 and column indices in the range 0 to -nrow-1). This test correctly determines that all Matrix Market -matrices are in 1-based form. +one-based (compatible with Matrix Market), with row indices in the range 1 to +ncol and column indices in the range 1 to nrow. If a row or column index of +zero is found, the matrix is assumed to be zero-based (with row indices in the +range 0 to ncol-1 and column indices in the range 0 to nrow-1). This test +correctly determines that all Matrix Market matrices are in 1-based form. For symmetric pattern-only matrices, the kth diagonal (if present) is set to one plus the degree of the row k or column k (whichever is larger), and the -off-diagonals are set to -1. A symmetric pattern-only matrix with a -zero-free diagonal is thus converted into a symmetric positive definite -matrix. All entries are set to one for an unsymmetric pattern-only matrix. -This differs from the MatrixMarket format ({\tt A = mmread ('file')} returns -a binary pattern for A for symmetric pattern-only matrices). -To return a binary format for all pattern-only matrices, use -{\tt A = mread('file',1)}. +off-diagonals are set to -1. A symmetric pattern-only matrix with a zero-free +diagonal is thus converted into a symmetric positive definite matrix. All +entries are set to one for an unsymmetric pattern-only matrix. This differs +from the MatrixMarket format ({\tt A = mmread ('file')} returns a binary +pattern for A for symmetric pattern-only matrices). To return a binary format +for all pattern-only matrices, use {\tt A = mread('file',1)}. -Example matrices that follow this format can be found in the -{\tt CHOLMOD/Demo/Matrix} and \newline -{\tt CHOLMOD/Tcov/Matrix} directories. -You can also try any of the matrices in the Matrix Market collection -at http://www.nist.gov/MatrixMarket. +Example matrices that follow this format can be found in the {\tt +CHOLMOD/Demo/Matrix} and \newline {\tt CHOLMOD/Tcov/Matrix} directories. You +can also try any of the matrices in the Matrix Market collection at +http://www.nist.gov/MatrixMarket. + +%--------------------------------------- +\subsection{{\tt cholmod\_read\_triplet2}: read triplet matrix from file} +%--------------------------------------- + +\input{_read_triplet2.tex} +Identical to \verb'cholmod_read_triplet', except that the dtype can be +specified (\verb'CHOLMOD_DOUBLE' or \verb'CHOLMOD_SINGLE'). %--------------------------------------- \subsection{{\tt cholmod\_read\_sparse}: read sparse matrix from file} %--------------------------------------- \input{_read_sparse.tex} -Read a sparse matrix in triplet form from a file (using {\tt cholmod\_read\_triplet}) -and convert to a CHOLMOD sparse matrix. -The Matrix Market format is used. -If {\tt Common->prefer\_upper} is {\tt TRUE} (the default case), a symmetric matrix is -returned stored in upper-triangular form ({\tt A->stype} is 1). -Otherwise, it is left in its original form, either upper or lower. +Read a sparse matrix in triplet form from a file (using {\tt +cholmod\_read\_triplet}) and convert to a CHOLMOD sparse matrix. The Matrix +Market format is used. If {\tt Common->prefer\_upper} is {\tt TRUE} (the +default case), a symmetric matrix is returned stored in upper-triangular form +({\tt A->stype} is 1). Otherwise, it is left in its original form, either +upper or lower. +% +The matrix is read in {\tt double} precision. To read a matrix +in either double or single precision ({\tt double} or {\tt float}), +use \verb'cholmod_read_sparse2'. + +%--------------------------------------- +\subsection{{\tt cholmod\_read\_sparse2}: read sparse matrix from file} +%--------------------------------------- + +\input{_read_sparse2.tex} +Identical to \verb'cholmod_read_sparse', except that the dtype can be +specified (\verb'CHOLMOD_DOUBLE' or \verb'CHOLMOD_SINGLE'). %--------------------------------------- \subsection{{\tt cholmod\_read\_dense}: read dense matrix from file} %--------------------------------------- \input{_read_dense.tex} -Read a dense matrix from a file, using the the {\tt array} -Matrix Market format +Read a dense matrix from a file, using the {\tt array} Matrix Market format \newline (http://www.nist.gov/MatrixMarket). +% +The matrix is read in {\tt double} precision. To read a matrix +in either double or single precision ({\tt double} or {\tt float}), +use \verb'cholmod_read_dense2'. + +%--------------------------------------- +\subsection{{\tt cholmod\_read\_dense2}: read dense matrix from file} +%--------------------------------------- + +\input{_read_dense2.tex} +Identical to \verb'cholmod_read_dense', except that the dtype can be +specified (\verb'CHOLMOD_DOUBLE' or \verb'CHOLMOD_SINGLE'). %--------------------------------------- \subsection{{\tt cholmod\_read\_matrix}: read a matrix from file} %--------------------------------------- \input{_read_matrix.tex} -Read a sparse or dense matrix from a file, in Matrix Market format. -Returns a {\tt void} pointer to either a -{\tt cholmod\_triplet}, -{\tt cholmod\_sparse}, or -{\tt cholmod\_dense} object. +Read a sparse or dense matrix from a file, in Matrix Market format. Returns a +{\tt void} pointer to either a {\tt cholmod\_triplet}, {\tt cholmod\_sparse}, +or {\tt cholmod\_dense} object. +% +The matrix is read in {\tt double} precision. To read a matrix +in either double or single precision ({\tt double} or {\tt float}), +use \verb'cholmod_read_matrix2'. + +%--------------------------------------- +\subsection{{\tt cholmod\_read\_matrix2}: read a matrix from file} +%--------------------------------------- + +\input{_read_matrix2.tex} +Identical to \verb'cholmod_read_matrix', except that the dtype can be +specified (\verb'CHOLMOD_DOUBLE' or \verb'CHOLMOD_SINGLE'). %--------------------------------------- \subsection{{\tt cholmod\_write\_sparse}: write a sparse matrix to a file} @@ -2413,16 +2800,14 @@ \subsection{{\tt cholmod\_write\_sparse}: write a sparse matrix to a file} matrix. If not NULL, the {\tt Z} matrix must have the same dimensions and stype as {\tt A}. -Returns the symmetry in which the matrix was printed -(1 to 7) or -1 on failure. See the {\tt cholmod\_symmetry} function for -a description of the return codes. +Returns the symmetry in which the matrix was printed (1 to 7) or -1 on failure. +See the {\tt cholmod\_symmetry} function for a description of the return codes. -If {\tt A} and {\tt Z} are sorted on input, and either unsymmetric (stype = 0) or -symmetric-lower (stype < 0), and if {\tt A} and {\tt Z} do not overlap, -then the triplets -are sorted, first by column and then by row index within each column, with -no duplicate entries. If all the above holds except stype > 0, then the -triplets are sorted by row first and then column. +If {\tt A} and {\tt Z} are sorted on input, and either unsymmetric (stype = 0) +or symmetric-lower (stype $< 0$), and if {\tt A} and {\tt Z} do not overlap, +then the triplets are sorted, first by column and then by row index within each +column, with no duplicate entries. If all the above holds except stype $> 0$, +then the triplets are sorted by row first and then column. %--------------------------------------- \subsection{{\tt cholmod\_write\_dense}: write a dense matrix to a file} @@ -2430,10 +2815,9 @@ \subsection{{\tt cholmod\_write\_dense}: write a dense matrix to a file} \input{_write_dense.tex} Write a dense matrix to a file in Matrix Market format. Optionally include -comments. Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if -square). -A dense matrix is written in "general" format; symmetric formats in the -Matrix Market standard are not exploited. +comments. Returns $> 0$ if successful, -1 otherwise (1 if rectangular, 2 if +square). A dense matrix is written in "general" format; symmetric formats in +the Matrix Market standard are not exploited. %------------------------------------------------------------------------------- \newpage \section{{\tt Cholesky} Module routines} @@ -2448,60 +2832,60 @@ \subsection{{\tt cholmod\_analyze}: symbolic factorization} for numerical factorization via {\tt cholmod\_factorize} or via the ``expert'' routines {\tt cholmod\_rowfac} and {\tt cholmod\_super\_numeric}. -In the symmetric case, {\tt A} or {\tt A(p,p)} is analyzed, -where {\tt p} is the fill-reducing ordering. -In the unsymmetric case, {\tt A*A'} or {\tt A(p,:)*A(p,:)'} is analyzed. -The {\tt cholmod\_analyze\_p} routine can be given a user-provided permutation {\tt p} -(see below). - -The default ordering strategy is to first try AMD. -The ordering quality is analyzed, and if AMD obtains an ordering where -{\tt nnz(L)} is greater than or equal to {\tt 5*nnz(tril(A))} -(or {\tt 5*nnz(tril(A*A'))} if {\tt A} is unsymmetric) and -the floating-point operation count for the subsequent factorization is -greater than or equal to {\tt 500*nnz(L)}, then METIS is tried (if installed). -For {\tt cholmod\_analyze\_p}, the user-provided ordering is also tried. -This default behavior is obtained when {\tt Common->nmethods} is zero. -In this case, methods 0, 1, and 2 in {\tt Common->method[...]} are reset -to user-provided, AMD, and METIS, respectively. -The ordering with the smallest {\tt nnz(L)} is kept. - -If {\tt Common->default\_nesdis} is true (nonzero), then CHOLMOD's -nested dissection (NESDIS) is used for the default strategy described -above, in place of METIS. +In the symmetric case, {\tt A} or {\tt A(p,p)} is analyzed, where {\tt p} is +the fill-reducing ordering. In the unsymmetric case, {\tt A*A'} or {\tt +A(p,:)*A(p,:)'} is analyzed. The {\tt cholmod\_analyze\_p} routine can be +given a user-provided permutation {\tt p} (see below). + +The default ordering strategy is to first try AMD. The ordering quality is +analyzed, and if AMD obtains an ordering where {\tt nnz(L)} is greater than or +equal to {\tt 5*nnz(tril(A))} (or {\tt 5*nnz(tril(A*A'))} if {\tt A} is +unsymmetric) and the floating-point operation count for the subsequent +factorization is greater than or equal to {\tt 500*nnz(L)}, then METIS is tried +(if installed). For {\tt cholmod\_analyze\_p}, the user-provided ordering is +also tried. This default behavior is obtained when {\tt Common->nmethods} is +zero. In this case, methods 0, 1, and 2 in {\tt Common->method[...]} are reset +to user-provided, AMD, and METIS, respectively. The ordering with the smallest +{\tt nnz(L)} is kept. + +If {\tt Common->default\_nesdis} is true (nonzero), then CHOLMOD's nested +dissection (NESDIS) is used for the default strategy described above, in place +of METIS. Other ordering options can be requested. These include: \begin{enumerate} -\item natural: A is not permuted to reduce fill-in. -\item user-provided: a permutation can be provided to {\tt cholmod\_analyze\_p}. -\item AMD: approximate minimum degree (AMD for the symmetric case, COLAMD for the {\tt A*A'} case). -\item METIS: nested dissection with {\tt METIS\_NodeND} -\item {\tt NESDIS}: CHOLMOD's nested dissection using - {\tt METIS\_NodeComputeSeparator}, - followed by a constrained minimum degree +\item natural: A is not permuted to reduce fill-in. +\item user-provided: a permutation can be provided to {\tt + cholmod\_analyze\_p}. +\item AMD: approximate minimum degree (AMD for the symmetric case, + COLAMD for the {\tt A*A'} case). +\item METIS: nested dissection with {\tt METIS\_NodeND} +\item {\tt NESDIS}: CHOLMOD's nested dissection using + {\tt METIS\_NodeComputeSeparator}, followed by a constrained minimum degree (CAMD or CSYMAMD for the symmetric case, CCOLAMD for the {\tt A*A'} case). - This is typically slower than METIS, but typically provides better orderings. + This is typically slower than METIS, but typically provides better + orderings. \end{enumerate} -Multiple ordering options can be tried (up to 9 of them), and the best one -is selected (the one that gives the smallest number of nonzeros in the -simplicial factor L). If one method fails, {\tt cholmod\_analyze} keeps going, and -picks the best among the methods that succeeded. This routine fails (and -returns {\tt NULL}) if either the initial memory allocation fails, all ordering methods -fail, or the supernodal analysis (if requested) fails. Change {\tt Common->nmethods} to the -number of methods you wish to try. By default, the 9 methods available are: +Multiple ordering options can be tried (up to 9 of them), and the best one is +selected (the one that gives the smallest number of nonzeros in the simplicial +factor L). If one method fails, {\tt cholmod\_analyze} keeps going, and picks +the best among the methods that succeeded. This routine fails (and returns +{\tt NULL}) if either the initial memory allocation fails, all ordering methods +fail, or the supernodal analysis (if requested) fails. Change {\tt +Common->nmethods} to the number of methods you wish to try. By default, the 9 +methods available are: \begin{enumerate} \item user-provided permutation (only for {\tt cholmod\_analyze\_p}). \item AMD with default parameters. \item METIS with default parameters. \item {\tt NESDIS} with default parameters: stopping the partitioning when - the graph is of size {\tt nd\_small} = 200 or less, remove nodes with - more than {\tt max (16, prune\_dense * sqrt (n))} nodes where - {\tt prune\_dense} = 10, and follow partitioning with - constrained minimum degree ordering - (CAMD for the symmetric case, - CCOLAMD for the unsymmetric case). + the graph is of size {\tt nd\_small} = 200 or less, remove nodes + with more than {\tt max (16, prune\_dense * sqrt (n))} nodes where + {\tt prune\_dense} = 10, and follow partitioning with constrained + minimum degree ordering (CAMD for the symmetric case, CCOLAMD for + the unsymmetric case). \item natural ordering (with weighted postorder). \item NESDIS, {\tt nd\_small} = 20000, {\tt prune\_dense} = 10. \item NESDIS, {\tt nd\_small} = 4, {\tt prune\_dense} = 10, @@ -2511,24 +2895,24 @@ \subsection{{\tt cholmod\_analyze}: symbolic factorization} \end{enumerate} You can modify these 9 methods and the number of methods tried by changing -parameters in the {\tt Common} argument. If you know the best ordering for your -matrix, set {\tt Common->nmethods} to 1 and set {\tt Common->method[0].ordering} to the -requested ordering method. Parameters for each method can also be modified -(refer to the description of {\tt cholmod\_common} for details). +parameters in the {\tt Common} argument. If you know the best ordering for +your matrix, set {\tt Common->nmethods} to 1 and set {\tt +Common->method[0].ordering} to the requested ordering method. Parameters for +each method can also be modified (refer to the description of {\tt +cholmod\_common} for details). -Note that it is possible for METIS to terminate your program if it runs out -of memory. This is not the case for any CHOLMOD or minimum degree ordering -routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). -Since {\tt NESDIS} relies on METIS, it too can terminate your program. +Note that it is possible for METIS to terminate your program if it runs out of +memory. This is not the case for any CHOLMOD or minimum degree ordering +routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since {\tt NESDIS} relies on +METIS, it too can terminate your program. The selected ordering is followed by a weighted postorder of the elimination -tree by default (see {\tt cholmod\_postorder} for details), -unless {\tt Common->postorder} is set to {\tt FALSE}. -The postorder does not change the number of nonzeros in $\m{L}$ or -the floating-point operation count. It does improve performance, -particularly for the supernodal factorization. -If you truly want the natural ordering with no postordering, -you must set {\tt Common->postorder} to {\tt FALSE}. +tree by default (see {\tt cholmod\_postorder} for details), unless {\tt +Common->postorder} is set to {\tt FALSE}. The postorder does not change the +number of nonzeros in $\m{L}$ or the floating-point operation count. It does +improve performance, particularly for the supernodal factorization. If you +truly want the natural ordering with no postordering, you must set {\tt +Common->postorder} to {\tt FALSE}. The factor {\tt L} is returned as simplicial symbolic if {\tt Common->supernodal} is {\tt CHOLMOD\_SIMPLICIAL} (zero) or as supernodal @@ -2581,48 +2965,56 @@ \subsection{{\tt cholmod\_factorize}: numeric factorization} $\m{LDL}\tr$ factorization). Once the factorization is complete, it can be left as is or optionally -converted into any simplicial numeric type, depending on the -{\tt Common->final\_*} parameters. If converted from a supernodal to simplicial -type, and {\tt Common->final\_resymbol} is {\tt TRUE}, then numerically -zero entries in {\tt L} due to relaxed supernodal amalgamation are removed from -the simplicial factor (they are always left in the supernodal form of {\tt L}). +converted into any simplicial numeric type, depending on the {\tt +Common->final\_*} parameters. If converted from a supernodal to simplicial +type, and {\tt Common->final\_resymbol} is {\tt TRUE}, then numerically zero +entries in {\tt L} due to relaxed supernodal amalgamation are removed from the +simplicial factor (they are always left in the supernodal form of {\tt L}). Entries that are numerically zero but present in the simplicial symbolic pattern of {\tt L} are left in place (the graph of {\tt L} remains chordal). This is required for the update/downdate/rowadd/rowdel routines to work properly. -If the matrix is not positive definite the routine returns {\tt TRUE}, but -{\tt Common->status} is set to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the -column at which the failure occurred. Columns {\tt L->minor} to {\tt L->n-1} -are set to zero. +If the matrix is not positive definite the routine returns {\tt TRUE}, but {\tt +Common->status} is set to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set +to the column at which the failure occurred. Columns {\tt L->minor} to {\tt +L->n-1} are set to zero. + +Supports any xtype (pattern, real, complex, or zomplex), except that the input +matrix {\tt A} cannot be pattern-only and any dtype (double or single). If +{\tt L} is simplicial, its numeric xtype matches {\tt A} on output. If {\tt L} +is supernodal, its xtype is real if {\tt A} is real, or complex if {\tt A} is +complex or zomplex. CHOLMOD does not provide a supernodal zomplex factor, +since it is incompatible with how complex numbers are stored in LAPACK and the +BLAS. -Supports any xtype (pattern, real, complex, or zomplex), except that the -input matrix {\tt A} cannot be pattern-only. If {\tt L} is simplicial, its numeric -xtype matches {\tt A} on output. If {\tt L} is supernodal, its xtype is real if {\tt A} is -real, or complex if {\tt A} is complex or zomplex. CHOLMOD does not provide -a supernodal zomplex factor, since it is incompatible with how complex numbers are -stored in LAPACK and the BLAS. +If the \verb'L' factor on input is a purely symbolic factorizatin (with +\verb'L->xtype' of \verb'CHOLMOD_PATTERN', then it is converted to a numeric +factorization with same dtype as A. Otherwise, the dtypes of L and A must +match. %--------------------------------------- -\subsection{{\tt cholmod\_analyze\_p}: symbolic factorization, given permutation} +\subsection{{\tt cholmod\_analyze\_p}: symbolic factorization, given +permutation} %--------------------------------------- \input{_analyze_p.tex} -Identical to {\tt cholmod\_analyze}, except that a user-provided -permutation {\tt p} can be provided, and the set {\tt f} for the unsymmetric case -can be provided. The matrices {\tt A(:,f)*A(:,f)'} or {\tt A(p,f)*A(p,f)'} -can be analyzed in the the unsymmetric case. +Identical to {\tt cholmod\_analyze}, except that a user-provided permutation +{\tt p} can be provided, and the set {\tt f} for the unsymmetric case can be +provided. The matrices {\tt A(:,f)*A(:,f)'} or {\tt A(p,f)*A(p,f)'} can be +analyzed in the the unsymmetric case. %--------------------------------------- -\subsection{{\tt cholmod\_factorize\_p}: numeric factorization, given permutation} +\subsection{{\tt cholmod\_factorize\_p}: numeric factorization, given +permutation} %--------------------------------------- \input{_factorize_p.tex} -Identical to {\tt cholmod\_factorize}, but with additional options. -The set {\tt f} can be provided for the unsymmetric case; -{\tt A(p,f)*A(p,f)'} is factorized. The term {\tt beta*I} can be added to -the matrix before it is factorized, where {\tt beta} is real. -Only the real part, {\tt beta[0]}, is used. +Identical to {\tt cholmod\_factorize}, but with additional options. The set +{\tt f} can be provided for the unsymmetric case; {\tt A(p,f)*A(p,f)'} is +factorized. The term {\tt beta*I} can be added to the matrix before it is +factorized, where {\tt beta} is real. Only the real part, {\tt beta[0]}, is +used. %--------------------------------------- \subsection{{\tt cholmod\_solve}: solve a linear system} @@ -2632,36 +3024,39 @@ \subsection{{\tt cholmod\_solve}: solve a linear system} Returns a solution {\tt X} that solves one of the following systems: \begin{tabular}{ll|ll} - \hline - system & {\tt sys} parameter & system & {\tt sys} parameter \\ - $\m{Ax}=\m{b}$ & 0: {\tt CHOLMOD\_A} & & \\ - $\m{LDL}\tr\m{x}=\m{b}$ & 1: {\tt CHOLMOD\_LDLt} & $\m{L}\tr\m{x}=\m{b}$ & 5: {\tt CHOLMOD\_Lt} \\ - $\m{LDx}=\m{b}$ & 2: {\tt CHOLMOD\_LD} & $\m{Dx}=\m{b}$ & 6: {\tt CHOLMOD\_D} \\ - $\m{DL}\tr\m{x}=\m{b}$ & 3: {\tt CHOLMOD\_DLt} & $\m{x}=\m{Pb}$ & 7: {\tt CHOLMOD\_P} \\ - $\m{Lx}=\m{b}$ & 4: {\tt CHOLMOD\_L} & $\m{x}=\m{P}\tr\m{b}$ & 8: {\tt CHOLMOD\_Pt} \\ - \hline +\hline +system & {\tt sys} parameter & system & {\tt sys} parameter \\ +$\m{Ax}=\m{b}$ & 0: {\tt CHOLMOD\_A} & & \\ +$\m{LDL}\tr\m{x}=\m{b}$ & 1: {\tt CHOLMOD\_LDLt} & $\m{L}\tr\m{x}=\m{b}$ & 5: {\tt CHOLMOD\_Lt} \\ +$\m{LDx}=\m{b}$ & 2: {\tt CHOLMOD\_LD} & $\m{Dx}=\m{b}$ & 6: {\tt CHOLMOD\_D} \\ +$\m{DL}\tr\m{x}=\m{b}$ & 3: {\tt CHOLMOD\_DLt} & $\m{x}=\m{Pb}$ & 7: {\tt CHOLMOD\_P} \\ +$\m{Lx}=\m{b}$ & 4: {\tt CHOLMOD\_L} & $\m{x}=\m{P}\tr\m{b}$ & 8: {\tt CHOLMOD\_Pt} \\ +\hline \end{tabular} -The factorization can be simplicial $\m{LDL}\tr$, simplicial $\m{LL}\tr$, or supernodal $\m{LL}\tr$. -For an $\m{LL}\tr$ factorization, $\m{D}$ is the identity matrix. Thus {\tt CHOLMOD\_LD} and -{\tt CHOLMOD\_L} solve the same system if an $\m{LL}\tr$ factorization was performed, -for example. -This is one of the few routines in CHOLMOD for which the xtype of the input -arguments need not match. -If both {\tt L} and {\tt B} are real, then {\tt X} is returned real. If either is complex -or zomplex, {\tt X} is returned as either complex or zomplex, depending on the -{\tt Common->prefer\_zomplex} parameter (default is complex). - -This routine does not check to see if the diagonal of $\m{L}$ or $\m{D}$ is zero, -because sometimes a partial solve can be done with an indefinite or singular -matrix. If you wish to check in your own code, test {\tt L->minor}. If -{\tt L->minor == L->n}, then the matrix has no zero diagonal entries. -If {\tt k = L->minor < L->n}, then {\tt L(k,k)} is zero for an $\m{LL}\tr$ factorization, or -{\tt D(k,k)} is zero for an $\m{LDL}\tr$ factorization. +The factorization can be simplicial $\m{LDL}\tr$, simplicial $\m{LL}\tr$, or +supernodal $\m{LL}\tr$. For an $\m{LL}\tr$ factorization, $\m{D}$ is the +identity matrix. Thus {\tt CHOLMOD\_LD} and {\tt CHOLMOD\_L} solve the same +system if an $\m{LL}\tr$ factorization was performed, for example. This is one +of the few routines in CHOLMOD for which the xtype of the input arguments need +not match. If both {\tt L} and {\tt B} are real, then {\tt X} is returned +real. If either is complex or zomplex, {\tt X} is returned as either complex +or zomplex, depending on the {\tt Common->prefer\_zomplex} parameter (default +is complex). + +This routine does not check to see if the diagonal of $\m{L}$ or $\m{D}$ is +zero, because sometimes a partial solve can be done with an indefinite or +singular matrix. If you wish to check in your own code, test {\tt L->minor}. +If {\tt L->minor == L->n}, then the matrix has no zero diagonal entries. If +{\tt k = L->minor < L->n}, then {\tt L(k,k)} is zero for an $\m{LL}\tr$ +factorization, or {\tt D(k,k)} is zero for an $\m{LDL}\tr$ factorization. Iterative refinement is not performed, but this can be easily done with the {\tt MatrixOps} Module. See {\tt Demo/cholmod\_demo.c} for an example. +The dtypes of \verb'L' and \verb'B' must match, and \verb'X' is returned +with the same dtype. + %--------------------------------------- \subsection{{\tt cholmod\_spsolve}: solve a linear system} %--------------------------------------- @@ -2681,33 +3076,20 @@ \subsection{{\tt cholmod\_solve2}: solve a linear system, reusing workspace} Solve a linear system, optionally reusing workspace from a prior call to {\tt cholmod\_solve2}. -The inputs to this function are the same as {\tt cholmod\_solve}, -with the addition of three parameters: -{\tt X}, -{\tt Y}, -and -{\tt E}. The dense matrix {\tt X} is the solution on output. -On input, {\tt \&X} can point to a NULL matrix, or be the wrong size. -If that is the case, it is freed and allocated to be the proper size. -If {\tt X} has the right size and type on input, then the allocation -is skipped. In contrast, the {\tt cholmod\_solve} function always -allocates its output {\tt X}. This {\tt cholmod\_solve2} function -allows you to reuse the memory space of a prior {\tt X}, thereby -saving time. - -The two workspace matrices {\tt Y} and {\tt E} can also be reused -between calls. -You must free -{\tt X} -{\tt Y}, -and -{\tt E} yourself, when your computations are done. Below is an -example of usage. -Note that -{\tt X} -{\tt Y}, -and -{\tt E} must be defined on input (either NULL, or valid dense matrices). +The inputs to this function are the same as {\tt cholmod\_solve}, with the +addition of three parameters: {\tt X}, {\tt Y}, and {\tt E}. The dense matrix +{\tt X} is the solution on output. On input, {\tt \&X} can point to a NULL +matrix, or be the wrong size. If that is the case, it is freed and allocated +to be the proper size. If {\tt X} has the right size and type on input, then +the allocation is skipped. In contrast, the {\tt cholmod\_solve} function +always allocates its output {\tt X}. This {\tt cholmod\_solve2} function +allows you to reuse the memory space of a prior {\tt X}, thereby saving time. + +The two workspace matrices {\tt Y} and {\tt E} can also be reused between +calls. You must free {\tt X} {\tt Y}, and {\tt E} yourself, when your +computations are done. Below is an example of usage. Note that {\tt X} {\tt +Y}, and {\tt E} must be defined on input (either NULL, or valid dense +matrices). \begin{verbatim} cholmod_dense *X = NULL, *Y = NULL, *E = NULL ; @@ -2733,9 +3115,9 @@ \subsection{{\tt cholmod\_solve2}: solve a linear system, reusing workspace} cholmod_l_free_dense (&X, Common) ; \end{verbatim} -Both methods work fine, but in the second method with {\tt cholmod\_solve}, -the internal workspaces ({\tt Y} and {\tt E}) and the solution ({\tt X}) -are allocated and freed on each call. +Both methods work fine, but in the second method with {\tt cholmod\_solve}, the +internal workspaces ({\tt Y} and {\tt E}) and the solution ({\tt X}) are +allocated and freed on each call. The {\tt cholmod\_solve2 function} can also solve for a subset of the solution vector {\tt X}, if the optional {\tt Bset} parameter is non-NULL. The @@ -2745,65 +3127,65 @@ \subsection{{\tt cholmod\_solve2}: solve a linear system, reusing workspace} Bset}. The vector {\tt Bset} must be a sparse column vector, of dimension the same as {\tt B}. Only the pattern of {\tt Bset} is used. The solution {\tt X} (a dense column vector) is modified on output, but is defined only in the rows -defined by the sparse vector {\tt Xset}. The entries in {\tt Bset} are a -subset of {\tt Xset} (except if {\tt sys} is {\tt CHOLMOD\_P} or {\tt -CHOLMOD\_Pt}). - -No memory allocations are done if the outputs and internal -workspaces ({\tt X}, {\tt Xset}, {\tt Y}, and {\tt E}) have been allocated -by a prior call (or if allocated by the user). To let {\tt cholmod\_solve2} -allocate these outputs and workspaces for you, simply initialize them to -NULL (as in the example above). Since it is possible for this function -to reallocate these 4 arrays, you should always re-acquire the pointers to -their internal data ({\tt X->x} for example) after calling -{\tt cholmod\_solve2}), since they may change. They normally will not -change except in the first call to this function. - -On the first call to {\tt cholmod\_solve2} when {\tt Bset} is NULL, -the factorization is converted from supernodal to simplicial, if needed. -The inverse permutation is also computed and stored in the factorization -object, {\tt L}. This can take a modest amount of time. Subsequent -calls to {\tt cholmod\_solve2} with a small {\tt Bset} -are very fast (both asymptotically and in practice). +defined by the sparse vector {\tt Xset}. {\tt Bset} is ignored when solving +with {\tt sys} equal to {\tt CHOLMOD\_P} or {\tt CHOLMOD\_Pt}). The entries in +{\tt Bset} are a subset of {\tt Xset} (except if {\tt sys} is {\tt CHOLMOD\_P} +or {\tt CHOLMOD\_Pt}). + +No memory allocations are done if the outputs and internal workspaces ({\tt X}, +{\tt Xset}, {\tt Y}, and {\tt E}) have been allocated by a prior call (or if +allocated by the user). To let {\tt cholmod\_solve2} allocate these outputs +and workspaces for you, simply initialize them to NULL (as in the example +above). Since it is possible for this function to reallocate these 4 arrays, +you should always re-acquire the pointers to their internal data ({\tt X->x} +for example) after calling {\tt cholmod\_solve2}, since they may change. They +normally will not change except in the first call to this function. + +On the first call to {\tt cholmod\_solve2} when {\tt Bset} is NULL, the +factorization is converted from supernodal to simplicial, if needed. The +inverse permutation is also computed and stored in the factorization object, +{\tt L}. This can take a modest amount of time. Subsequent calls to {\tt +cholmod\_solve2} with a small {\tt Bset} are very fast (both asymptotically and +in practice). + +The dtypes of all parameters must match. You can find an example of how to use {\tt cholmod\_solve2} in the -two demo programs, {\tt cholmod\_demo} and {\tt cholmod\_l\_demo}. +four demo programs, {\tt cholmod\_*\_demo}. %--------------------------------------- \subsection{{\tt cholmod\_etree}: find elimination tree} %--------------------------------------- \input{_etree.tex} -Computes the elimination tree of {\tt A} or {\tt A'*A}. -In the symmetric case, the upper triangular part of {\tt A} is used. Entries not -in this part of the matrix are ignored. Computing the etree of a symmetric -matrix from just its lower triangular entries is not supported. -In the unsymmetric case, all of {\tt A} is used, and the etree of {\tt A'*A} is computed. -Refer to \cite{Liu90a} for a discussion of the elimination tree -and its use in sparse Cholesky factorization. -% J. Liu, "The role of elimination trees in sparse factorization", SIAM J. -% Matrix Analysis \& Applic., vol 11, 1990, pp. 134-172. +Computes the elimination tree of {\tt A} or {\tt A'*A}. In the symmetric case, +the upper triangular part of {\tt A} is used. Entries not in this part of the +matrix are ignored. Computing the etree of a symmetric matrix from just its +lower triangular entries is not supported. In the unsymmetric case, all of +{\tt A} is used, and the etree of {\tt A'*A} is computed. Refer to +\cite{Liu90a} for a discussion of the elimination tree and its use in sparse +Cholesky factorization. %--------------------------------------- \subsection{{\tt cholmod\_rowcolcounts}: nonzeros counts of a factor} %--------------------------------------- \input{_rowcolcounts.tex} -Compute the row and column counts of the Cholesky factor {\tt L} of the matrix -{\tt A} or {\tt A*A'}. The etree and its postordering must already be computed (see -{\tt cholmod\_etree} and {\tt cholmod\_postorder}) and given as inputs to this routine. -For the symmetric case ($\m{LL}\tr=\m{A}$), {\tt A} must be stored in -symmetric/lower form ({\tt A->stype = -1}). -In the unsymmetric case, {\tt A*A'} or {\tt A(:,f)*A(:,f)'} can be analyzed. -The fundamental floating-point operation count is returned in {\tt Common->fl} -(this excludes extra flops due to relaxed supernodal amalgamation). -Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. -The algorithm is described in \cite{GilbertLiNgPeyton01,GilbertNgPeyton94}. +Computes the row and column counts of the Cholesky factor {\tt L} of the matrix +{\tt A} or {\tt A*A'}. The etree and its postordering must already be computed +(see {\tt cholmod\_etree} and {\tt cholmod\_postorder}) and given as inputs to +this routine. For the symmetric case ($\m{LL}\tr=\m{A}$), {\tt A} must be +stored in symmetric/lower form ({\tt A->stype = -1}). In the unsymmetric case, +{\tt A*A'} or {\tt A(:,f)*A(:,f)'} can be analyzed. The fundamental +floating-point operation count is returned in {\tt Common->fl} (this excludes +extra flops due to relaxed supernodal amalgamation). Refer to {\tt +cholmod\_transpose\_unsym} for a description of {\tt f}. The algorithm is +described in \cite{GilbertLiNgPeyton01,GilbertNgPeyton94}. % J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and % column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis \& % Applic., vol 15, 1994, pp. 1075-1091. -% +% % J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for % sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. @@ -2812,13 +3194,13 @@ \subsection{{\tt cholmod\_analyze\_ordering}: analyze a permutation} %--------------------------------------- \input{_analyze_ordering.tex} -Given a matrix {\tt A} and its fill-reducing permutation, compute the elimination -tree, its (non-weighted) postordering, and the number of nonzeros in each -column of {\tt L}. Also computes the flop count, the total nonzeros in {\tt L}, and -the nonzeros in {\tt tril(A)} ({\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}). -In the unsymmetric case, {\tt A(p,f)*A(p,f)'} is analyzed, and {\tt Common->anz} -is the number of nonzero entries in the lower triangular part of the product, -not in {\tt A} itself. +Given a matrix {\tt A} and its fill-reducing permutation, compute the +elimination tree, its (non-weighted) postordering, and the number of nonzeros +in each column of {\tt L}. Also computes the flop count, the total nonzeros in +{\tt L}, and the nonzeros in {\tt tril(A)} ({\tt Common->fl}, {\tt +Common->lnz}, and {\tt Common->anz}). In the unsymmetric case, {\tt +A(p,f)*A(p,f)'} is analyzed, and {\tt Common->anz} is the number of nonzero +entries in the lower triangular part of the product, not in {\tt A} itself. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. @@ -2831,88 +3213,85 @@ \subsection{{\tt cholmod\_amd}: interface to AMD} \input{_amd.tex} CHOLMOD interface to the AMD ordering package. Orders {\tt A} if the matrix is -symmetric. On output, {\tt Perm [k] = i} if row/column {\tt i} of {\tt A} is the {\tt k}th -row/column of {\tt P*A*P'}. This corresponds to {\tt A(p,p)} in MATLAB notation. -If A is unsymmetric, {\tt cholmod\_amd} orders {\tt A*A'} or {\tt A(:,f)*A(:,f)'}. -On output, {\tt Perm [k] = i} if -row/column {\tt i} of {\tt A*A'} is the {\tt k}th row/column of {\tt P*A*A'*P'}. -This corresponds to {\tt A(p,:)*A(p,:)'} in MATLAB notation. -If {\tt f} is present, {\tt A(p,f)*A(p,f)'} is the permuted matrix. -Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. +symmetric. On output, {\tt Perm [k] = i} if row/column {\tt i} of {\tt A} is +the {\tt k}th row/column of {\tt P*A*P'}. This corresponds to {\tt A(p,p)} in +MATLAB notation. If A is unsymmetric, {\tt cholmod\_amd} orders {\tt A*A'} or +{\tt A(:,f)*A(:,f)'}. On output, {\tt Perm [k] = i} if row/column {\tt i} of +{\tt A*A'} is the {\tt k}th row/column of {\tt P*A*A'*P'}. This corresponds to +{\tt A(p,:)*A(p,:)'} in MATLAB notation. If {\tt f} is present, {\tt +A(p,f)*A(p,f)'} is the permuted matrix. Refer to {\tt +cholmod\_transpose\_unsym} for a description of {\tt f}. Computes the flop count for a subsequent $\m{LL}\tr$ factorization, the number -of nonzeros in {\tt L}, and the number of nonzeros in the matrix ordered -({\tt A}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'}). -These statistics are returned in -{\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}, respectively. +of nonzeros in {\tt L}, and the number of nonzeros in the matrix ordered ({\tt +A}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'}). These statistics are returned in {\tt +Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}, respectively. %--------------------------------------- \subsection{{\tt cholmod\_colamd}: interface to COLAMD} %--------------------------------------- \input{_colamd.tex} -CHOLMOD interface to the COLAMD ordering package. -Finds a permutation {\tt p} such that the Cholesky factorization of {\tt P*A*A'*P'} is -sparser than {\tt A*A'}, using COLAMD. If the {\tt postorder} input parameter is {\tt TRUE}, -the column elimination tree is found and postordered, and the COLAMD ordering is then -combined with its postordering (COLAMD itself does not perform this postordering). -{\tt A} must be unsymmetric ({\tt A->stype = 0}). +CHOLMOD interface to the COLAMD ordering package. Finds a permutation {\tt p} +such that the Cholesky factorization of {\tt P*A*A'*P'} is sparser than {\tt +A*A'}, using COLAMD. If the {\tt postorder} input parameter is {\tt TRUE}, the +column elimination tree is found and postordered, and the COLAMD ordering is +then combined with its postordering (COLAMD itself does not perform this +postordering). {\tt A} must be unsymmetric ({\tt A->stype = 0}). %--------------------------------------- \subsection{{\tt cholmod\_rowfac}: row-oriented Cholesky factorization} %--------------------------------------- \input{_rowfac.tex} -Full or incremental numerical $\m{LDL}\tr$ or $\m{LL}\tr$ factorization (simplicial, not -supernodal). {\tt cholmod\_factorize} is the ``easy'' wrapper for this code, but it -does not provide access to incremental factorization. -The algorithm is the row-oriented, up-looking method described in \cite{Davis05}. -See also \cite{Liu86c}. No 2-by-2 pivoting (or any other pivoting) is performed. - -{\tt cholmod\_rowfac} computes the full or incremental $\m{LDL}\tr$ or $\m{LL}\tr$ factorization of -{\tt A+beta*I} (where {\tt A} is symmetric) or {\tt A*F+beta*I} -(where {\tt A} and {\tt F} are unsymmetric -and only the upper triangular part of {\tt A*F+beta*I} is used). It computes -{\tt L} (and {\tt D}, for $\m{LDL}\tr$) one row at a time. -The input scalar {\tt beta} is real; only the real part ({\tt beta[0]}) is used. - -{\tt L} can be a simplicial symbolic or numeric ({\tt L->is\_super} must be {\tt FALSE}). -A symbolic factor is converted immediately into a numeric factor containing -the identity matrix. - -For a full factorization, use {\tt kstart = 0} and {\tt kend = nrow}. The existing nonzero -entries (numerical values in {\tt L->x} and {\tt L->z} for the zomplex case, and indices -in {\tt L->i}) are overwritten. - -To compute an incremental factorization, select {\tt kstart} and {\tt kend} as the range -of rows of {\tt L} you wish to compute. Rows {\tt kstart} to {\tt kend-1} of {\tt L} -will be computed. A correct factorization will be computed -only if all descendants of all nodes {\tt kstart} to {\tt kend-1} in the elimination tree have -been factorized by a prior call to this routine, and if rows {\tt kstart} to {\tt kend-1} -have not been factorized. This condition is {\bf not} checked on input. - -In the symmetric case, {\tt A} must be stored in upper form ({\tt A->stype} is greater than zero). -The matrix {\tt F} is not accessed and may be {\tt NULL}. Only -columns {\tt kstart} to {\tt kend-1} of {\tt A} are accessed. - -In the unsymmetric case, - the typical case is {\tt F=A'}. Alternatively, if {\tt F=A(:,f)'}, then this - routine factorizes the matrix {\tt S = beta*I + A(:,f)*A(:,f)'}. - The product {\tt A*F} is assumed to be symmetric; - only the upper triangular part of {\tt A*F} is used. - {\tt F} must be of size {\tt A->ncol} by {\tt A->nrow}. +Full or incremental numerical $\m{LDL}\tr$ or $\m{LL}\tr$ factorization +(simplicial, not supernodal). {\tt cholmod\_factorize} is the ``easy'' wrapper +for this code, but it does not provide access to incremental factorization. +The algorithm is the row-oriented, up-looking method described in +\cite{Davis05}. See also \cite{Liu86c}. No 2-by-2 pivoting (or any other +pivoting) is performed. + +{\tt cholmod\_rowfac} computes the full or incremental $\m{LDL}\tr$ or +$\m{LL}\tr$ factorization of {\tt A+beta*I} (where {\tt A} is symmetric) or +{\tt A*F+beta*I} (where {\tt A} and {\tt F} are unsymmetric and only the upper +triangular part of {\tt A*F+beta*I} is used). It computes {\tt L} (and {\tt +D}, for $\m{LDL}\tr$) one row at a time. The input scalar {\tt beta} is real; +only the real part ({\tt beta[0]}) is used. + +{\tt L} can be a simplicial symbolic or numeric ({\tt L->is\_super} must be +{\tt FALSE}). A symbolic factor is converted immediately into a numeric factor +containing the identity matrix. + +For a full factorization, use {\tt kstart = 0} and {\tt kend = nrow}. The +existing nonzero entries (numerical values in {\tt L->x} and {\tt L->z} for the +zomplex case, and indices in {\tt L->i}) are overwritten. + +To compute an incremental factorization, select {\tt kstart} and {\tt kend} as +the range of rows of {\tt L} you wish to compute. Rows {\tt kstart} to {\tt +kend-1} of {\tt L} will be computed. A correct factorization will be computed +only if all descendants of all nodes {\tt kstart} to {\tt kend-1} in the +elimination tree have been factorized by a prior call to this routine, and if +rows {\tt kstart} to {\tt kend-1} have not been factorized. This condition is +{\bf not} checked on input. + +In the symmetric case, {\tt A} must be stored in upper form ({\tt A->stype} is +greater than zero). The matrix {\tt F} is not accessed and may be {\tt NULL}. +Only columns {\tt kstart} to {\tt kend-1} of {\tt A} are accessed. + +In the unsymmetric case, the typical case is {\tt F=A'}. Alternatively, if +{\tt F=A(:,f)'}, then this routine factorizes the matrix {\tt S = beta*I + +A(:,f)*A(:,f)'}. The product {\tt A*F} is assumed to be symmetric; only the +upper triangular part of {\tt A*F} is used. {\tt F} must be of size {\tt +A->ncol} by {\tt A->nrow}. + +If the \verb'L' factor on input is a purely symbolic factorization (with +\verb'L->xtype' of \verb'CHOLMOD_PATTERN'), then it is converted to a numeric +factorization with same dtype as A. Otherwise, the dtypes of L and A must +match. % J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans. % Math. Software, vol 12, 1986, pp. 127-148. -%--------------------------------------- -\subsection{{\tt cholmod\_rowfac\_mask}: row-oriented Cholesky factorization} -%--------------------------------------- - -\input{_rowfac_mask.tex} -For use in LPDASA only. - - %--------------------------------------- \subsection{{\tt cholmod\_row\_subtree}: pattern of row of a factor} %--------------------------------------- @@ -2926,26 +3305,26 @@ \subsection{{\tt cholmod\_row\_subtree}: pattern of row of a factor} \begin{verbatim} L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' \end{verbatim} -if {\tt A} is unsymmetric. -This gives the nonzero pattern of row {\tt k} of {\tt L} (excluding the diagonal). -The pattern is returned postordered, according to the subtree of the elimination -tree rooted at node {\tt k}. +if {\tt A} is unsymmetric. This gives the nonzero pattern of row {\tt k} of +{\tt L} (excluding the diagonal). The pattern is returned postordered, +according to the subtree of the elimination tree rooted at node {\tt k}. The symmetric case requires {\tt A} to be in symmetric-upper form. -The result is returned in {\tt R}, a pre-allocated sparse matrix of size {\tt nrow}-by-1, -with {\tt R->nzmax >= nrow}. {\tt R} is assumed to be packed ({\tt Rnz [0]} is not updated); -the number of entries in {\tt R} is given by {\tt Rp [0]}. +The result is returned in {\tt R}, a pre-allocated sparse matrix of size {\tt +nrow}-by-1, with {\tt R->nzmax >= nrow}. {\tt R} is assumed to be packed ({\tt +Rnz [0]} is not updated); the number of entries in {\tt R} is given by {\tt Rp +[0]}. %--------------------------------------- \subsection{{\tt cholmod\_row\_lsubtree}: pattern of row of a factor} %--------------------------------------- \input{_row_lsubtree.tex} -Identical to {\tt cholmod\_row\_subtree}, except the elimination tree is -found from {\tt L} itself, not {\tt Parent}. Also, {\tt F=A'} is not provided; -the nonzero pattern of the {\tt k}th column of {\tt F} is given by -{\tt Fi} and {\tt fnz} instead. +Identical to {\tt cholmod\_row\_subtree}, except the elimination tree is found +from {\tt L} itself, not {\tt Parent}. Also, {\tt F=A'} is not provided; the +nonzero pattern of the {\tt k}th column of {\tt F} is given by {\tt Fi} and +{\tt fnz} instead. %--------------------------------------- \subsection{{\tt cholmod\_resymbol}: re-do symbolic factorization} @@ -2953,9 +3332,9 @@ \subsection{{\tt cholmod\_resymbol}: re-do symbolic factorization} \input{_resymbol.tex} Recompute the symbolic pattern of {\tt L}. Entries not in the symbolic pattern -of the factorization of {\tt A(p,p)} or {\tt F*F'}, where -{\tt F=A(p,f)} or {\tt F=A(:,f)}, are dropped, where -{\tt p = L->Perm} is used to permute the input matrix {\tt A}. +of the factorization of {\tt A(p,p)} or {\tt F*F'}, where {\tt F=A(p,f)} or +{\tt F=A(:,f)}, are dropped, where {\tt p = L->Perm} is used to permute the +input matrix {\tt A}. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. @@ -2973,53 +3352,54 @@ \subsection{{\tt cholmod\_resymbol\_noperm}: re-do symbolic factorization} %--------------------------------------- \input{_resymbol_noperm.tex} -Identical to {\tt cholmod\_resymbol}, except that the fill-reducing -ordering {\tt L->Perm} is not used. +Identical to {\tt cholmod\_resymbol}, except that the fill-reducing ordering +{\tt L->Perm} is not used. %--------------------------------------- \subsection{{\tt cholmod\_postorder}: tree postorder} %--------------------------------------- \input{_postorder.tex} -Postorder a tree. The tree is either an elimination tree (the output from -{\tt cholmod\_etree}) or a component tree (from {\tt cholmod\_nested\_dissection}). - -An elimination tree is a complete tree of {\tt n} nodes with {\tt Parent [j] > j} or -{\tt Parent [j] = -1} if j is a root. On output {\tt Post [0..n-1]} is a complete -permutation vector; -{\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the -postordered elimination tree, where {\tt k} is in the range 0 to {\tt n-1}. - -A component tree is a subset of {\tt 0:n-1}. {\tt Parent [j] = -2} if node {\tt j} is not -in the component tree. {\tt Parent [j] = -1} if {\tt j} is a root of the component -tree, and {\tt Parent [j]} is in the range 0 to {\tt n-1} if {\tt j} is in the component -tree but not a root. On output, {\tt Post [k]} is defined only for nodes in -the component tree. {\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the -postordered component tree, where {\tt k} is in the range 0 to the number of -components minus 1. -Node {\tt j} is ignored and not included in the postorder if {\tt Parent [j] < -1}. -As a result, {\tt cholmod\_check\_parent (Parent, ...)} and {\tt cholmod\_check\_perm (Post, ...)} -fail if used for a component tree and its postordering. - -An optional node weight can be given. When starting a postorder at node {\tt j}, -the children of {\tt j} are ordered in decreasing order of their weight. -If no weights are given ({\tt Weight} is {\tt NULL}) then children are ordered in -decreasing order of their node number. The weight of a node must be in the -range 0 to {\tt n-1}. Weights outside that range are silently converted to that -range (weights $<$ 0 are treated as zero, and weights $\ge$ {\tt n} are treated as {\tt n-1}). +Postorder a tree. The tree is either an elimination tree (the output from {\tt +cholmod\_etree}) or a component tree (from {\tt cholmod\_nested\_dissection}). + +An elimination tree is a complete tree of {\tt n} nodes with {\tt Parent [j] > +j} or {\tt Parent [j] = -1} if j is a root. On output {\tt Post [0..n-1]} is a +complete permutation vector; {\tt Post [k] = j} if node {\tt j} is the {\tt +k}th node in the postordered elimination tree, where {\tt k} is in the range 0 +to {\tt n-1}. + +A component tree is a subset of {\tt 0:n-1}. {\tt Parent [j] = -2} if node +{\tt j} is not in the component tree. {\tt Parent [j] = -1} if {\tt j} is a +root of the component tree, and {\tt Parent [j]} is in the range 0 to {\tt n-1} +if {\tt j} is in the component tree but not a root. On output, {\tt Post [k]} +is defined only for nodes in the component tree. {\tt Post [k] = j} if node +{\tt j} is the {\tt k}th node in the postordered component tree, where {\tt k} +is in the range 0 to the number of components minus 1. Node {\tt j} is ignored +and not included in the postorder if {\tt Parent [j] < -1}. As a result, {\tt +cholmod\_check\_parent (Parent, ...)} and {\tt cholmod\_check\_perm (Post, +...)} fail if used for a component tree and its postordering. + +An optional node weight can be given. When starting a postorder at node {\tt +j}, the children of {\tt j} are ordered in decreasing order of their weight. +If no weights are given ({\tt Weight} is {\tt NULL}) then children are ordered +in decreasing order of their node number. The weight of a node must be in the +range 0 to {\tt n-1}. Weights outside that range are silently converted to +that range (weights $<$ 0 are treated as zero, and weights $\ge$ {\tt n} are +treated as {\tt n-1}). %--------------------------------------- \subsection{{\tt cholmod\_rcond}: reciprocal condition number} %--------------------------------------- \input{_rcond.tex} -Returns a rough estimate of the reciprocal of the condition number: -the minimum entry on the diagonal of {\tt L} (or absolute entry of {\tt D} for an $\m{LDL}\tr$ -factorization) divided by the maximum entry. {\tt L} can be real, complex, or -zomplex. Returns -1 on error, 0 if the matrix is singular or has a zero or NaN -entry on the diagonal of {\tt L}, 1 if the matrix is 0-by-0, or -{\tt min(diag(L))/max(diag(L))} otherwise. Never returns NaN; if {\tt L} has a NaN on -the diagonal it returns zero instead. +Returns a rough estimate of the reciprocal of the condition number: the minimum +entry on the diagonal of {\tt L} (or absolute entry of {\tt D} for an +$\m{LDL}\tr$ factorization) divided by the maximum entry. {\tt L} can be real, +complex, or zomplex. Returns -1 on error, 0 if the matrix is singular or has a +zero or NaN entry on the diagonal of {\tt L}, 1 if the matrix is 0-by-0, or +{\tt min(diag(L))/max(diag(L))} otherwise. Never returns NaN; if {\tt L} has a +NaN on the diagonal it returns zero instead. %------------------------------------------------------------------------------- \newpage \section{{\tt Modify} Module routines} @@ -3035,14 +3415,13 @@ \subsection{{\tt cholmod\_updown}: update/downdate} \[ \new{\m{L}}\new{\m{D}}\new{\m{L}}\tr = \m{LDL}\tr \pm \m{CC}\tr \] -where $\new{\m{L}}$ denotes the new factor. -{\tt C} must be sorted. It can be either packed or unpacked. As in all CHOLMOD -routines, the columns of {\tt L} are sorted on input, and also on output. -If {\tt L} does not contain a simplicial numeric $\m{LDL}\tr$ factorization, it -is converted into one. Thus, a supernodal $\m{LL}\tr$ factorization -can be passed to {\tt cholmod\_updown}. -A symbolic {\tt L} is converted into a numeric identity matrix. -If the initial conversion fails, the factor is returned unchanged. +where $\new{\m{L}}$ denotes the new factor. {\tt C} must be sorted. It can be +either packed or unpacked. As in all CHOLMOD routines, the columns of {\tt L} +are sorted on input, and also on output. If {\tt L} does not contain a +simplicial numeric $\m{LDL}\tr$ factorization, it is converted into one. Thus, +a supernodal $\m{LL}\tr$ factorization can be passed to {\tt cholmod\_updown}. +A symbolic {\tt L} is converted into a numeric identity matrix. If the initial +conversion fails, the factor is returned unchanged. If memory runs out during the update, the factor is returned as a simplicial symbolic factor. That is, everything is freed except for the fill-reducing @@ -3050,10 +3429,10 @@ \subsection{{\tt cholmod\_updown}: update/downdate} {\tt cholmod\_analyze}). Note that the fill-reducing permutation {\tt L->Perm} is not used. The row -indices of {\tt C} refer to the rows of {\tt L}, not {\tt A}. If your original system is -$\m{LDL}\tr = \m{PAP}\tr$ (where $\m{P} =$ {\tt L->Perm}), and you want to compute the $\m{LDL}\tr$ -factorization of $\m{A}+\m{CC}\tr$, then you must permute $\m{C}$ first. That is, -if +indices of {\tt C} refer to the rows of {\tt L}, not {\tt A}. If your original +system is $\m{LDL}\tr = \m{PAP}\tr$ (where $\m{P} =$ {\tt L->Perm}), and you +want to compute the $\m{LDL}\tr$ factorization of $\m{A}+\m{CC}\tr$, then you +must permute $\m{C}$ first. That is, if \[ \m{PAP}\tr = \m{LDL}\tr \] @@ -3064,107 +3443,71 @@ \subsection{{\tt cholmod\_updown}: update/downdate} = \m{LDL}\tr + (\m{PC})(\m{PC})\tr = \m{LDL}\tr + \new{\m{C}}\new{\m{C}}\tr \] -where $\new{\m{C}} = \m{PC}$. - -You can use the {\tt cholmod\_submatrix} routine in the {\tt MatrixOps} Module -to permute {\tt C}, with: +where $\new{\m{C}} = \m{PC}$. You can use the {\tt cholmod\_submatrix} routine +in the {\tt MatrixOps} Module to permute {\tt C}, with: \begin{verbatim} Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ; \end{verbatim} - -Note that the {\tt sorted} input parameter to {\tt cholmod\_submatrix} must be {\tt TRUE}, -because {\tt cholmod\_updown} requires {\tt C} with sorted columns. -Only real matrices are supported. -The algorithms are described in \cite{DavisHager99,DavisHager01}. +Note that the {\tt sorted} input parameter to {\tt cholmod\_submatrix} must be +{\tt TRUE}, because {\tt cholmod\_updown} requires {\tt C} with sorted columns. +Only real matrices are supported (double or single). The algorithms are +described in \cite{DavisHager99,DavisHager01}. %--------------------------------------- -\subsection{{\tt cholmod\_updown\_solve}: update/downdate} +\subsection{{\tt cholmod\_updown\_solve}: update/downdate of a factorization +and a solution} %--------------------------------------- \input{_updown_solve.tex} -Identical to {\tt cholmod\_updown}, except -the system $\m{Lx}=\m{b}$ is also updated/downdated. -The new system is $\new{\m{L}}\new{\m{x}}=\m{b} + \Delta \m{b}$. The old solution $\m{x}$ is overwritten -with $\new{\m{x}}$. Note that as in the update/downdate of $\m{L}$ itself, the fill- -reducing permutation {\tt L->Perm} is not used. The vectors $\m{x}$ and $\m{b}$ are in the permuted -ordering, not your original ordering. This routine does not handle multiple right-hand-sides. - -%--------------------------------------- -\subsection{{\tt cholmod\_updown\_mark}: update/downdate} -%--------------------------------------- - -\input{_updown_mark.tex} -Identical to {\tt cholmod\_updown\_solve}, except that only part of $\m{L}$ -is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, -see the source code file {\tt CHOLMOD/Modify/cholmod\_updown.c}. -This routine is meant for use in the {\tt LPDASA} linear program solver only, -by Hager and Davis. - -%--------------------------------------- -\subsection{{\tt cholmod\_updown\_mask}: update/downdate} -%--------------------------------------- - -\input{_updown_mask.tex} -For use in LPDASA only. +Identical to {\tt cholmod\_updown}, except the system $\m{Lx}=\m{b}$ is also +updated/downdated. The new system is $\new{\m{L}}\new{\m{x}}=\m{b} + \Delta +\m{b}$. The old solution $\m{x}$ is overwritten with $\new{\m{x}}$. Note that +as in the update/downdate of $\m{L}$ itself, the fill-reducing permutation +{\tt L->Perm} is not used. The vectors $\m{x}$ and $\m{b}$ are in the permuted +ordering. %--------------------------------------- \subsection{{\tt cholmod\_rowadd}: add row to factor} %--------------------------------------- \input{_rowadd.tex} -Adds a row and column to an $\m{LDL}\tr$ factorization. The {\tt k}th -row and column of {\tt L} must be equal to the {\tt k}th row and -column of the identity matrix on input. -Only real matrices are supported. -The algorithm is described in \cite{DavisHager05}. +Adds a row and column to an $\m{LDL}\tr$ factorization. The {\tt k}th row and +column of {\tt L} must be equal to the {\tt k}th row and column of the identity +matrix on input. Only real matrices are supported (double or single). The +dtypes of all matrices must match, except when \verb'L' is symbolic (with an +xtype of \verb'CHOLMOD_PATTERN'). In this case, \verb'L' is converted to the +dtype of \verb'R'. The algorithm is described in \cite{DavisHager05}. %--------------------------------------- -\subsection{{\tt cholmod\_rowadd\_solve}: add row to factor} +\subsection{{\tt cholmod\_rowadd\_solve}: add row to factor and update a +solution} %--------------------------------------- \input{_rowadd_solve.tex} -Identical to {\tt cholmod\_rowadd}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}. +Identical to {\tt cholmod\_rowadd}, except the system $\m{Lx}=\m{b}$ is also +updated/downdated, just like {\tt cholmod\_updown\_solve}. %--------------------------------------- \subsection{{\tt cholmod\_rowdel}: delete row from factor} %--------------------------------------- \input{_rowdel.tex} -Deletes a row and column from an $\m{LDL}\tr$ factorization. The {\tt k}th -row and column of {\tt L} is equal to the {\tt k}th row and -column of the identity matrix on output. -Only real matrices are supported. +Deletes a row and column from an $\m{LDL}\tr$ factorization. The {\tt k}th row +and column of {\tt L} is equal to the {\tt k}th row and column of the identity +matrix on output. The dtypes of all matrices must match. Only real matrices +are supported (double or single). %--------------------------------------- -\subsection{{\tt cholmod\_rowdel\_solve}: delete row from factor} +\subsection{{\tt cholmod\_rowdel\_solve}: delete row from factor and update a solution} %--------------------------------------- \input{_rowdel_solve.tex} -Identical to {\tt cholmod\_rowdel}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}. -When row/column $k$ of $\m{A}$ is deleted from the system $\m{Ay}=\m{b}$, this can induce -a change to $\m{x}$, in addition to changes arising when $\m{L}$ and $\m{b}$ are modified. -If this is the case, the kth entry of $\m{y}$ is required as input ({\tt yk}). -The algorithm is described in \cite{DavisHager05}. - -%--------------------------------------- -\subsection{{\tt cholmod\_rowadd\_mark}: add row to factor} -%--------------------------------------- - -\input{_rowadd_mark.tex} -Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$ -is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, -see the source code file {\tt CHOLMOD/Modify/cholmod\_rowadd.c}. -This routine is meant for use in the {\tt LPDASA} linear program solver only. - -%--------------------------------------- -\subsection{{\tt cholmod\_rowdel\_mark}: delete row from factor} -%--------------------------------------- - -\input{_rowdel_mark.tex} -Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$ -is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, -see the source code file {\tt CHOLMOD/Modify/cholmod\_rowdel.c}. -This routine is meant for use in the {\tt LPDASA} linear program solver only. +Identical to {\tt cholmod\_rowdel}, except the system $\m{Lx}=\m{b}$ is also +updated/downdated, just like {\tt cholmod\_updown\_solve}. When row/column $k$ +of $\m{A}$ is deleted from the system $\m{Ay}=\m{b}$, this can induce a change +to $\m{x}$, in addition to changes arising when $\m{L}$ and $\m{b}$ are +modified. If this is the case, the kth entry of $\m{y}$ is required as input +({\tt yk}). The algorithm is described in \cite{DavisHager05}. %------------------------------------------------------------------------------- \newpage \section{{\tt MatrixOps} Module routines} @@ -3175,11 +3518,9 @@ \subsection{{\tt cholmod\_drop}: drop small entries} %--------------------------------------- \input{_drop.tex} -Drop small entries from {\tt A}, and entries in the ignored part of {\tt A} if {\tt A} -is symmetric. No CHOLMOD routine drops small numerical entries -from a matrix, except for this one. NaN's and Inf's are kept. - -Supports pattern and real matrices; complex and zomplex matrices are not supported. +Drop small entries from {\tt A}, and entries in the ignored part of {\tt A} if +{\tt A} is symmetric. No CHOLMOD routine drops small numerical entries from a +matrix, except for this one. NaN's and Inf's are kept. %--------------------------------------- \subsection{{\tt cholmod\_norm\_dense}: dense matrix norm} @@ -3188,7 +3529,6 @@ \subsection{{\tt cholmod\_norm\_dense}: dense matrix norm} \input{_norm_dense.tex} Returns the infinity-norm, 1-norm, or 2-norm of a dense matrix. Can compute the 2-norm only for a dense column vector. -All xtypes are supported. %--------------------------------------- \subsection{{\tt cholmod\_norm\_sparse}: sparse matrix norm} @@ -3196,151 +3536,157 @@ \subsection{{\tt cholmod\_norm\_sparse}: sparse matrix norm} \input{_norm_sparse.tex} Returns the infinity-norm or 1-norm of a sparse matrix. -All xtypes are supported. %--------------------------------------- \subsection{{\tt cholmod\_scale}: scale sparse matrix} %--------------------------------------- \input{_scale.tex} -Scales a matrix: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A}, or {\tt diag(s)*A*diag(s)}. +Scales a matrix: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A}, or {\tt +diag(s)*A*diag(s)}. {\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric). The symmetry of {\tt A} is ignored; all entries in the matrix are modified. -If {\tt A} is {\tt m}-by-{\tt n} unsymmetric but scaled symmetrically, the result is +If {\tt A} is {\tt m}-by-{\tt n} unsymmetric but scaled symmetrically, the +result is + \begin{verbatim} A = diag (s (1:m)) * A * diag (s (1:n)) \end{verbatim} Row or column scaling of a symmetric matrix still results in a symmetric -matrix, since entries are still ignored by other routines. -For example, when row-scaling a symmetric matrix where just the upper -triangular part is stored (and lower triangular entries ignored) -{\tt A = diag(s)*triu(A)} is performed, where the result {\tt A} is also -symmetric-upper. This has the effect of modifying the implicit lower -triangular part. In MATLAB notation: +matrix, since entries are still ignored by other routines. For example, when +row-scaling a symmetric matrix where just the upper triangular part is stored +(and lower triangular entries ignored) {\tt A = diag(s)*triu(A)} is performed, +where the result {\tt A} is also symmetric-upper. This has the effect of +modifying the implicit lower triangular part. In MATLAB notation: + \begin{verbatim} U = diag(s)*triu(A) ; L = tril (U',-1) A = L + U ; \end{verbatim} -The scale parameter determines the kind of scaling to perform and the size of {\tt S}: +The scale parameter determines the kind of scaling to perform and the size of +{\tt S}: \begin{tabular}{lll} \hline {\tt scale} & operation & size of {\tt S} \\ \hline -{\tt CHOLMOD\_SCALAR} & {\tt s[0]*A} & 1 \\ -{\tt CHOLMOD\_ROW} & {\tt diag(s)*A} & {\tt nrow}-by-1 or 1-by-{\tt nrow} \\ -{\tt CHOLMOD\_COL} & {\tt A*diag(s)} & {\tt ncol}-by-1 or 1-by-{\tt ncol} \\ -{\tt CHOLMOD\_SYM} & {\tt diag(s)*A*diag(s)} & {\tt max(nrow,ncol)}-by-1, or 1-by-{\tt max(nrow,ncol)} \\ +{\tt CHOLMOD\_SCALAR} & {\tt s[0]*A} & 1 \\ +{\tt CHOLMOD\_ROW} & {\tt diag(s)*A} & {\tt nrow}-by-1 or 1-by-{\tt nrow} \\ +{\tt CHOLMOD\_COL} & {\tt A*diag(s)} & {\tt ncol}-by-1 or 1-by-{\tt ncol} \\ +{\tt CHOLMOD\_SYM} & {\tt diag(s)*A*diag(s)} & {\tt max(nrow,ncol)}-by-1, or 1-by-{\tt max(nrow,ncol)} \\ \hline \end{tabular} -Only real matrices are supported. - %--------------------------------------- \subsection{{\tt cholmod\_sdmult}: sparse-times-dense matrix} %--------------------------------------- \input{_sdmult.tex} -Sparse matrix times dense matrix: -{\tt Y = alpha*(A*X) + beta*Y} or {\tt Y = alpha*(A'*X) + beta*Y}, -where {\tt A} is sparse and {\tt X} and {\tt Y} are dense. -When using {\tt A}, -{\tt X} has {\tt A->ncol} rows and -{\tt Y} has {\tt A->nrow} rows. -When using {\tt A'}, -{\tt X} has {\tt A->nrow} rows and -{\tt Y} has {\tt A->ncol} rows. -If {\tt transpose = 0}, then {\tt A} is used; +Sparse matrix times dense matrix: {\tt Y = alpha*(A*X) + beta*Y} or {\tt Y = +alpha*(A'*X) + beta*Y}, where {\tt A} is sparse and {\tt X} and {\tt Y} are +dense. When using {\tt A}, {\tt X} has {\tt A->ncol} rows and {\tt Y} has {\tt +A->nrow} rows. When using {\tt A'}, {\tt X} has {\tt A->nrow} rows and {\tt Y} +has {\tt A->ncol} rows. If {\tt transpose = 0}, then {\tt A} is used; otherwise, {\tt A'} is used (the complex conjugate transpose). -The {\tt transpose} parameter is ignored if the matrix is symmetric or Hermitian. -(the array transpose {\tt A.'} is not supported). -Supports real, complex, and zomplex matrices, but the xtypes of {\tt A}, {\tt X}, and {\tt Y} must all match. + +The {\tt transpose} parameter is ignored if the matrix is symmetric or +Hermitian. Supports real, complex, and zomplex matrices, but the xtypes and +dtypes of {\tt A}, {\tt X}, and {\tt Y} must all match. %--------------------------------------- \subsection{{\tt cholmod\_ssmult}: sparse-times-sparse matrix} %--------------------------------------- \input{_ssmult.tex} -Computes {\tt C = A*B}; multiplying two sparse matrices. -{\tt C} is returned as packed, and either unsorted or sorted, depending on the -{\tt sorted} input parameter. If {\tt C} is returned sorted, then either {\tt C = (B'*A')'} -or {\tt C = (A*B)''} is computed, depending on the number of nonzeros in {\tt A}, {\tt B}, and {\tt C}. -The stype of {\tt C} is determined by the {\tt stype} parameter. -Only pattern and real matrices are supported. Complex and zomplex matrices -are supported only when the numerical values are not computed ({\tt values} -is {\tt FALSE}). +Computes {\tt C = A*B}; multiplying two sparse matrices. {\tt C} is returned +as packed, and either unsorted or sorted, depending on the {\tt sorted} input +parameter. If {\tt C} is returned sorted, then either {\tt C = (B'*A')'} or +{\tt C = (A*B)''} is computed, depending on the number of nonzeros in {\tt A}, +{\tt B}, and {\tt C}. The stype of {\tt C} is determined by the {\tt stype} +parameter. The xtypes and dtypes of \verb'A' and \verb'B' must match, +unless \verb'mode' is 0. +% +If \verb'A' and/or \verb'B' are symmetric, a temporary unsymmetric copy is +made, and the conversion is controlled by the \verb'mode' parameter. %--------------------------------------- \subsection{{\tt cholmod\_submatrix}: sparse submatrix} %--------------------------------------- \input{_submatrix.tex} -Returns {\tt C = A (rset,cset)}, where {\tt C} becomes {\tt length(rset)}-by-{\tt length(cset)} in dimension. -{\tt rset} and {\tt cset} can have duplicate entries. {\tt A} must be unsymmetric. {\tt C} unsymmetric and -is packed. If {\tt sorted} is {\tt TRUE} on input, or {\tt rset} is sorted and {\tt A} is -sorted, then {\tt C} is sorted; otherwise {\tt C} is unsorted. - -If {\tt rset} is {\tt NULL}, it means ``{\tt [ ]}'' in MATLAB notation, the empty set. -The number of rows in the result {\tt C} will be zero if {\tt rset} is {\tt NULL}. -Likewise if {\tt cset} means the empty set; the number of columns in the result {\tt C} will be zero if {\tt cset} is {\tt NULL}. -If {\tt rsize} or {\tt csize} is negative, it denotes ``{\tt :}'' in MATLAB notation. -Thus, if both {\tt rsize} and {\tt csize} are negative {\tt C = A(:,:) = A} is returned. - -For permuting a matrix, this routine is an alternative to {\tt cholmod\_ptranspose} -(which permutes and transposes a matrix and can work on symmetric matrices). - -The time taken by this routine is O({\tt A->nrow}) if the {\tt Common} workspace needs -to be initialized, plus O({\tt C->nrow + C->ncol + nnz (A (:,cset))}). Thus, if {\tt C} -is small and the workspace is not initialized, the time can be dominated by -the call to {\tt cholmod\_allocate\_work}. However, once the workspace is -allocated, subsequent calls take less time. - -Only pattern and real matrices are supported. Complex and zomplex matrices -are supported only when {\tt values} is {\tt FALSE}. +Returns {\tt C = A (rset,cset)}, where {\tt C} becomes {\tt +length(rset)}-by-{\tt length(cset)} in dimension. {\tt rset} and {\tt cset} +can have duplicate entries. {\tt A} must be unsymmetric. {\tt C} unsymmetric +and is packed. If {\tt sorted} is {\tt TRUE} on input, or {\tt rset} is sorted +and {\tt A} is sorted, then {\tt C} is sorted; otherwise {\tt C} is unsorted. +% +If \verb'A' and/or \verb'B' are symmetric, a temporary unsymmetric copy is +made, and the conversion is controlled by the \verb'mode' parameter. + +If {\tt rset} is {\tt NULL}, it means ``{\tt [ ]}'' in MATLAB notation, the +empty set. The number of rows in the result {\tt C} will be zero if {\tt rset} +is {\tt NULL}. Likewise if {\tt cset} means the empty set; the number of +columns in the result {\tt C} will be zero if {\tt cset} is {\tt NULL}. If +{\tt rsize} or {\tt csize} is negative, it denotes ``{\tt :}'' in MATLAB +notation. Thus, if both {\tt rsize} and {\tt csize} are negative {\tt C = +A(:,:) = A} is returned. + +For permuting a matrix, this routine is an alternative to {\tt +cholmod\_ptranspose} (which permutes and transposes a matrix and can work on +symmetric matrices). + +The time taken by this routine is O({\tt A->nrow}) if the {\tt Common} +workspace needs to be initialized, plus O({\tt C->nrow + C->ncol + nnz (A +(:,cset))}). Thus, if {\tt C} is small and the workspace is not initialized, +the time can be dominated by the call to {\tt cholmod\_allocate\_work}. +However, once the workspace is allocated, subsequent calls take less time. %--------------------------------------- \subsection{{\tt cholmod\_horzcat}: horizontal concatenation} %--------------------------------------- \input{_horzcat.tex} -Horizontal concatenation, returns {\tt C = [A,B]} in MATLAB notation. -{\tt A} and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. -{\tt A} and {\tt B} must have the same number of rows. -{\tt C} is sorted if both {\tt A} and {\tt B} are sorted. -{\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}. -{\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}. +Horizontal concatenation, returns {\tt C = [A,B]} in MATLAB notation. {\tt A} +and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. +{\tt A} and {\tt B} must have the same number of rows. {\tt C} is sorted if +both {\tt A} and {\tt B} are sorted. {\tt A} and {\tt B} must have the same +xtype and dtype, unless {\tt mode} is 0. +% +If \verb'A' and/or \verb'B' are symmetric, a temporary unsymmetric copy is +made, and the conversion is controlled by the \verb'mode' parameter. %--------------------------------------- \subsection{{\tt cholmod\_vertcat}: vertical concatenation} %--------------------------------------- \input{_vertcat.tex} -Vertical concatenation, returns {\tt C = [A;B]} in MATLAB notation. -{\tt A} and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. -{\tt A} and {\tt B} must have the same number of columns. -{\tt C} is sorted if both {\tt A} and {\tt B} are sorted. -{\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}. -{\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}. +Vertical concatenation, returns {\tt C = [A;B]} in MATLAB notation. {\tt A} +and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. +{\tt A} and {\tt B} must have the same number of columns. {\tt C} is sorted if +both {\tt A} and {\tt B} are sorted. {\tt A} and {\tt B} must have the same +xtype and dtype, unless {\tt mode} is 0. +% +If \verb'A' and/or \verb'B' are symmetric, a temporary unsymmetric copy is +made, and the conversion is controlled by the \verb'mode' parameter. %--------------------------------------- \subsection{{\tt cholmod\_symmetry}: compute the symmetry of a matrix} %--------------------------------------- \input{_symmetry.tex} - Determines if a sparse matrix is rectangular, unsymmetric, symmetric, skew-symmetric, or Hermitian. It does so by looking at its numerical values of both upper and lower triangular parts of a CHOLMOD "unsymmetric" -matrix, where A->stype == 0. The transpose of A is NOT constructed. +matrix, where \verb'A->stype' == 0. The transpose of A is NOT constructed. If not unsymmetric, it also determines if the matrix has a diagonal whose entries are all real and positive (and thus a candidate for sparse Cholesky -if A->stype is changed to a nonzero value). +if \verb'A->stype' is changed to a nonzero value). Note that a Matrix Market "general" matrix is either rectangular or unsymmetric. @@ -3352,12 +3698,12 @@ \subsection{{\tt cholmod\_symmetry}: compute the symmetry of a matrix} If option == 0, then this routine returns immediately when it finds a non-positive diagonal entry (or one with nonzero imaginary part). If the -matrix is not a candidate for sparse Cholesky, it returns the value -{\tt CHOLMOD\_MM\_UNSYMMETRIC}, even if the matrix might in fact be symmetric or +matrix is not a candidate for sparse Cholesky, it returns the value {\tt +CHOLMOD\_MM\_UNSYMMETRIC}, even if the matrix might in fact be symmetric or Hermitian. This routine is useful inside the MATLAB backslash, which must look at an -arbitrary matrix (A->stype == 0) and determine if it is a candidate for +arbitrary matrix (\verb'A->stype' == 0) and determine if it is a candidate for sparse Cholesky. In that case, option should be 0. This routine is also useful when writing a MATLAB matrix to a file in @@ -3371,112 +3717,118 @@ \subsection{{\tt cholmod\_symmetry}: compute the symmetry of a matrix} perfectly symmetric matrix. This option is used when computing the following statistics for the matrices in the SuiteSparse Matrix Collection. - numerical symmetry: number of matched off-diagonal nonzeros over - the total number of off-diagonal entries. A real entry $a_{ij}$, $i \ne j$, - is matched if $a_{ji} = a_{ij}$, but this is only counted if both - $a_{ji}$ and $a_{ij}$ are nonzero. This does not depend on {\tt Z}. - (If A is complex, then the above test is modified; $a_{ij}$ is matched - if $\mbox{conj}(a_{ji}) = a_{ij}$). - - Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0. - - pattern symmetry: number of matched offdiagonal entries over the - total number of offdiagonal entries. An entry $a_{ij}$, $i \ne j$, is - matched if $a_{ji}$ is also an entry. - - Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0. - -The symmetry of a matrix with no offdiagonal entries is equal to 1. +\begin{itemize} + + \item {\bf numerical symmetry}: number of matched off-diagonal nonzeros over + the total number of off-diagonal entries. A real entry $a_{ij}$, $i + \ne j$, is matched if $a_{ji} = a_{ij}$, but this is only counted if + both $a_{ji}$ and $a_{ij}$ are nonzero. This does not depend on {\tt + Z}. (If A is complex, then the above test is modified; $a_{ij}$ is + matched if $\mbox{conj}(a_{ji}) = a_{ij}$). + + Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0. -A workspace of size ncol integers is allocated; EMPTY is returned if this -allocation fails. + \item {\bf pattern symmetry}: number of matched offdiagonal entries over + the total number of offdiagonal entries. An entry $a_{ij}$, $i \ne j$, + is matched if $a_{ji}$ is also an entry. + + Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0. +\end{itemize} + +The symmetry of a matrix with no offdiagonal entries is equal to 1. Summary of return values: \begin{tabular}{ll} -{\tt EMPTY (-1)} & out of memory, stype not zero, A not sorted \\ -{\tt CHOLMOD\_MM\_RECTANGULAR 1} & A is rectangular \\ -{\tt CHOLMOD\_MM\_UNSYMMETRIC 2} & A is unsymmetric \\ -{\tt CHOLMOD\_MM\_SYMMETRIC 3} & A is symmetric, but with non-pos. diagonal \\ -{\tt CHOLMOD\_MM\_HERMITIAN 4} & A is Hermitian, but with non-pos. diagonal \\ +{\tt EMPTY (-1)} & out of memory, stype not zero, A not sorted \\ +{\tt CHOLMOD\_MM\_RECTANGULAR 1} & A is rectangular \\ +{\tt CHOLMOD\_MM\_UNSYMMETRIC 2} & A is unsymmetric \\ +{\tt CHOLMOD\_MM\_SYMMETRIC 3} & A is symmetric, but with non-pos. diagonal \\ +{\tt CHOLMOD\_MM\_HERMITIAN 4} & A is Hermitian, but with non-pos. diagonal \\ {\tt CHOLMOD\_MM\_SKEW\_SYMMETRIC 5} & A is skew symmetric \\ {\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG 6} & A is symmetric with positive diagonal \\ {\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG 7} & A is Hermitian with positive diagonal \\ \end{tabular} -See also the {\tt spsym} mexFunction, which is a MATLAB interface for this code. - -If the matrix is a candidate for sparse Cholesky, it will return a result -\newline -{\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG} if real, or {\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG} if -complex. Otherwise, it will return a value less than this. This is true -regardless of the value of the option parameter. - +See also the {\tt spsym} mexFunction, which is a MATLAB interface for this +code. If the matrix is a candidate for sparse Cholesky, it will return a +result \newline {\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG} if real, or {\tt +CHOLMOD\_MM\_HERMITIAN\_POSDIAG} if complex. Otherwise, it will return a value +less than this. This is true regardless of the value of the option parameter. %------------------------------------------------------------------------------- \newpage \section{{\tt Supernodal} Module routines} %------------------------------------------------------------------------------- +Normally these methods are not called directly, but are accessed via the +\verb'cholmod_analyze', \verb'cholmod_factorize', and \verb'cholmod_solve' +methods. + %--------------------------------------- \subsection{{\tt cholmod\_super\_symbolic}: supernodal symbolic factorization} %--------------------------------------- \input{_super_symbolic.tex} -Supernodal symbolic analysis of the $\m{LL}\tr$ factorization of {\tt A}, {\tt A*A'}, or {\tt A(:,f)*A(:,f)'}. -This routine must be preceded by a simplicial symbolic analysis -({\tt cholmod\_rowcolcounts}). See {\tt Cholesky/cholmod\_analyze.c} for an example of how to use -this routine. -The user need not call this directly; {\tt cholmod\_analyze} is a ``simple'' wrapper for this routine. -{\tt A} can be symmetric (upper), or unsymmetric. The symmetric/lower form is not supported. -In the unsymmetric case {\tt F} is the normally transpose of {\tt A}. -Alternatively, if {\tt F=A(:,f)'} then {\tt F*F'} is analyzed. -Requires {\tt Parent} and {\tt L->ColCount} to be defined on input; these are the -simplicial {\tt Parent} and {\tt ColCount} arrays as computed by {\tt cholmod\_rowcolcounts}. -Does not use {\tt L->Perm}; the input matrices {\tt A} and {\tt F} must already be properly -permuted. Allocates and computes the supernodal pattern of {\tt L} -({\tt L->super}, {\tt L->pi}, {\tt L->px}, and {\tt L->s}). -Does not allocate the real part ({\tt L->x}). +Supernodal symbolic analysis of the $\m{LL}\tr$ factorization of {\tt A}, {\tt +A*A'}, or {\tt A(:,f)*A(:,f)'}. This routine must be preceded by a simplicial +symbolic analysis ({\tt cholmod\_rowcolcounts}). See {\tt +Cholesky/cholmod\_analyze.c} for an example of how to use this routine. The +user need not call this directly; {\tt cholmod\_analyze} is a ``simple'' +wrapper for this routine. {\tt A} can be symmetric (upper), or unsymmetric. +The symmetric/lower form is not supported. In the unsymmetric case {\tt F} is +the normally transpose of {\tt A}. Alternatively, if {\tt F=A(:,f)'} then {\tt +F*F'} is analyzed. Requires {\tt Parent} and {\tt L->ColCount} to be defined +on input; these are the simplicial {\tt Parent} and {\tt ColCount} arrays as +computed by {\tt cholmod\_rowcolcounts}. Does not use {\tt L->Perm}; the input +matrices {\tt A} and {\tt F} must already be properly permuted. Allocates and +computes the supernodal pattern of {\tt L} ({\tt L->super}, {\tt L->pi}, {\tt +L->px}, and {\tt L->s}). Does not allocate the real part ({\tt L->x}). %--------------------------------------- \subsection{{\tt cholmod\_super\_numeric}: supernodal numeric factorization} %--------------------------------------- \input{_super_numeric.tex} -Computes the numerical Cholesky factorization of {\tt A+beta*I} or {\tt A*F+beta*I}. Only the -lower triangular part of {\tt A+beta*I} or {\tt A*F+beta*I} is accessed. The -matrices {\tt A} and {\tt F} must already be permuted according to the fill-reduction -permutation {\tt L->Perm}. {\tt cholmod\_factorize} is an "easy" wrapper for this code -which applies that permutation. -The input scalar {\tt beta} is real; only the real part ({\tt beta[0]}) is used. - -Symmetric case: {\tt A} is a symmetric (lower) matrix. {\tt F} is not accessed and may be {\tt NULL}. -With a fill-reducing permutation, {\tt A(p,p)} should be passed for {\tt A}, where is -{\tt p} is {\tt L->Perm}. - -Unsymmetric case: {\tt A} is unsymmetric, and {\tt F} must be present. Normally, {\tt F=A'}. -With a fill-reducing permutation, {\tt A(p,f)} and {\tt A(p,f)'} should be passed as the -parameters {\tt A} and {\tt F}, respectively, where {\tt f} is a list of the subset of the columns of {\tt A}. - -The input factorization {\tt L} must be supernodal ({\tt L->is\_super} is {\tt TRUE}). It can -either be symbolic or numeric. In the first case, {\tt L} has been analyzed by -{\tt cholmod\_analyze} or {\tt cholmod\_super\_symbolic}, but the matrix has not yet been -numerically factorized. The numerical values are allocated here and the -factorization is computed. In the second case, a prior matrix has been -analyzed and numerically factorized, and a new matrix is being factorized. -The numerical values of {\tt L} are replaced with the new numerical factorization. - -{\tt L->is\_ll} is ignored on input, and set to {\tt TRUE} on output. This routine always computes an $\m{LL}\tr$ -factorization. Supernodal $\m{LDL}\tr$ factorization is not supported. +Computes the numerical Cholesky factorization of {\tt A+beta*I} or {\tt +A*F+beta*I}. Only the lower triangular part of {\tt A+beta*I} or {\tt +A*F+beta*I} is accessed. The matrices {\tt A} and {\tt F} must already be +permuted according to the fill-reduction permutation {\tt L->Perm}. {\tt +cholmod\_factorize} is an "easy" wrapper for this code which applies that +permutation. The input scalar {\tt beta} is real; only the real part ({\tt +beta[0]}) is used. + +Symmetric case: {\tt A} is a symmetric (lower) matrix. {\tt F} is not accessed +and may be {\tt NULL}. With a fill-reducing permutation, {\tt A(p,p)} should +be passed for {\tt A}, where is {\tt p} is {\tt L->Perm}. + +Unsymmetric case: {\tt A} is unsymmetric, and {\tt F} must be present. +Normally, {\tt F=A'}. With a fill-reducing permutation, {\tt A(p,f)} and {\tt +A(p,f)'} should be passed as the parameters {\tt A} and {\tt F}, respectively, +where {\tt f} is a list of the subset of the columns of {\tt A}. + +The input factorization {\tt L} must be supernodal ({\tt L->is\_super} is {\tt +TRUE}). It can either be symbolic or numeric. In the first case, {\tt L} has +been analyzed by {\tt cholmod\_analyze} or {\tt cholmod\_super\_symbolic}, but +the matrix has not yet been numerically factorized. The numerical values are +allocated here and the factorization is computed. In the second case, a prior +matrix has been analyzed and numerically factorized, and a new matrix is being +factorized. The numerical values of {\tt L} are replaced with the new +numerical factorization. + +{\tt L->is\_ll} is ignored on input, and set to {\tt TRUE} on output. This +routine always computes an $\m{LL}\tr$ factorization. Supernodal $\m{LDL}\tr$ +factorization is not supported. If the matrix is not positive definite the routine returns {\tt TRUE}, but sets -{\tt Common->status} to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the column at -which the failure occurred. Columns {\tt L->minor} to {\tt L->n-1} are set to zero. +{\tt Common->status} to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to +the column at which the failure occurred. Columns {\tt L->minor} to {\tt +L->n-1} are set to zero. -If {\tt L} is supernodal symbolic on input, it is converted to a supernodal numeric -factor on output, with an xtype of real if {\tt A} is real, or complex if {\tt A} is -complex or zomplex. If {\tt L} is supernodal numeric on input, its xtype must -match {\tt A} (except that {\tt L} can be complex and {\tt A} zomplex). The xtype of {\tt A} and {\tt F} -must match. +If {\tt L} is supernodal symbolic on input, it is converted to a supernodal +numeric factor on output, with an xtype of real if {\tt A} is real, or complex +if {\tt A} is complex or zomplex. If {\tt L} is supernodal numeric on input, +its xtype must match {\tt A} (except that {\tt L} can be complex and {\tt A} +zomplex). The xtype of {\tt A} and {\tt F} must match. %--------------------------------------- \subsection{{\tt cholmod\_super\_lsolve}: supernodal forward solve} @@ -3484,21 +3836,19 @@ \subsection{{\tt cholmod\_super\_lsolve}: supernodal forward solve} \input{_super_lsolve.tex} Solve $\m{Lx}=\m{b}$ for a supernodal factorization. This routine does not -apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more general -interface that performs that operation. -Only real and complex xtypes are supported. -{\tt L}, {\tt X}, and {\tt E} must have the same xtype. +apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more +general interface that performs that operation. Only real and complex xtypes +are supported. {\tt L}, {\tt X}, and {\tt E} must have the same xtype. %--------------------------------------- \subsection{{\tt cholmod\_super\_ltsolve}: supernodal backsolve} %--------------------------------------- \input{_super_ltsolve.tex} -Solve $\m{L}\tr\m{x}=\m{b}$ for a supernodal factorization. This routine does not -apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more general -interface that performs that operation. -Only real and complex xtypes are supported. -{\tt L}, {\tt X}, and {\tt E} must have the same xtype. +Solve $\m{L}\tr\m{x}=\m{b}$ for a supernodal factorization. This routine does +not apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more +general interface that performs that operation. Only real and complex xtypes +are supported. {\tt L}, {\tt X}, and {\tt E} must have the same xtype. %------------------------------------------------------------------------------- \newpage \section{{\tt Partition} Module routines} @@ -3509,93 +3859,89 @@ \subsection{{\tt cholmod\_nested\_dissection}: nested dissection ordering} %--------------------------------------- \input{_nested_dissection.tex} -CHOLMOD's nested dissection algorithm: - using its own compression and connected-components - algorithms, an external graph partitioner (METIS), and a constrained - minimum degree ordering algorithm (CAMD, CCOLAMD, or CSYMAMD). Typically - gives better orderings than {\tt METIS\_NodeND} (about 5\% to 10\% fewer - nonzeros in {\tt L}). +CHOLMOD's nested dissection algorithm: using its own compression and +connected-components algorithms, an external graph partitioner (METIS), and a +constrained minimum degree ordering algorithm (CAMD, CCOLAMD, or CSYMAMD). +Typically gives better orderings than {\tt METIS\_NodeND} (about 5\% to 10\% +fewer nonzeros in {\tt L}). This method uses a node bisector, applied recursively (but using a non-recursive implementation). Once the graph is partitioned, it calls a -constrained minimum degree code (CAMD or CSYMAMD for {\tt A+A'}, -and CCOLAMD for {\tt A*A'}) to -order all the nodes in the graph - but obeying the constraints determined -by the separators. This routine is similar to {\tt METIS\_NodeND}, except for -how -it treats the leaf nodes. {\tt METIS\_NodeND} orders the leaves of the separator -tree with {\tt MMD}, ignoring the rest of the matrix when ordering a single leaf. -This routine orders the whole matrix with CAMD, CSYMAMD, or CCOLAMD, all at once, -when the graph partitioning is done. +constrained minimum degree code (CAMD or CSYMAMD for {\tt A+A'}, and CCOLAMD +for {\tt A*A'}) to order all the nodes in the graph - but obeying the +constraints determined by the separators. This routine is similar to {\tt +METIS\_NodeND}, except for how it treats the leaf nodes. {\tt METIS\_NodeND} +orders the leaves of the separator tree with {\tt MMD}, ignoring the rest of +the matrix when ordering a single leaf. This routine orders the whole matrix +with CAMD, CSYMAMD, or CCOLAMD, all at once, when the graph partitioning is +done. %--------------------------------------- \subsection{{\tt cholmod\_metis}: interface to METIS nested dissection} %--------------------------------------- \input{_metis.tex} -CHOLMOD wrapper for the {\tt METIS\_NodeND} ordering routine. Creates {\tt A+A'}, -{\tt A*A'} or {\tt A(:,f)*A(:,f)'} and then calls {\tt METIS\_NodeND} on the resulting graph. -This routine is comparable to {\tt cholmod\_nested\_dissection}, except that it -calls {\tt METIS\_NodeND} directly, and it does not return the separator tree. +CHOLMOD wrapper for the {\tt METIS\_NodeND} ordering routine. Creates {\tt +A+A'}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'} and then calls {\tt METIS\_NodeND} on +the resulting graph. This routine is comparable to {\tt +cholmod\_nested\_dissection}, except that it calls {\tt METIS\_NodeND} +directly, and it does not return the separator tree. %--------------------------------------- \subsection{{\tt cholmod\_camd}: interface to CAMD} %--------------------------------------- \input{_camd.tex} -CHOLMOD interface to the CAMD ordering routine. Finds a permutation -{\tt p} such that the Cholesky factorization of {\tt A(p,p)} -is sparser than {\tt A}. If {\tt A} is unsymmetric, -{\tt A*A'} is ordered. -If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. -All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. +CHOLMOD interface to the CAMD ordering routine. Finds a permutation {\tt p} +such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}. +If {\tt A} is unsymmetric, {\tt A*A'} is ordered. If {\tt Cmember[i]=c} then +node {\tt i} is in set {\tt c}. All nodes in set 0 are ordered first, followed +by all nodes in set 1, and so on. %--------------------------------------- \subsection{{\tt cholmod\_ccolamd}: interface to CCOLAMD} %--------------------------------------- \input{_ccolamd.tex} -CHOLMOD interface to the CCOLAMD ordering routine. Finds a permutation -{\tt p} such that the Cholesky factorization of {\tt A(p,:)*A(p,:)'} is sparser than {\tt A*A'}. -The column elimination is found and postordered, and the CCOLAMD ordering is then -combined with its postordering. {\tt A} must be unsymmetric. -If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. -All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. +CHOLMOD interface to the CCOLAMD ordering routine. Finds a permutation {\tt p} +such that the Cholesky factorization of {\tt A(p,:)*A(p,:)'} is sparser than +{\tt A*A'}. The column elimination is found and postordered, and the CCOLAMD +ordering is then combined with its postordering. {\tt A} must be unsymmetric. +If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. All nodes in set 0 +are ordered first, followed by all nodes in set 1, and so on. %--------------------------------------- \subsection{{\tt cholmod\_csymamd}: interface to CSYMAMD} %--------------------------------------- \input{_csymamd.tex} -CHOLMOD interface to the CSYMAMD ordering routine. Finds a permutation -{\tt p} such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}. -The elimination tree is found and postordered, and the CSYMAMD -ordering is then combined with its postordering. If {\tt A} is unsymmetric, -{\tt A+A'} is ordered ({\tt A} must be square). -If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. -All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. +CHOLMOD interface to the CSYMAMD ordering routine. Finds a permutation {\tt p} +such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}. +The elimination tree is found and postordered, and the CSYMAMD ordering is then +combined with its postordering. If {\tt A} is unsymmetric, {\tt A+A'} is +ordered ({\tt A} must be square). If {\tt Cmember[i]=c} then node {\tt i} is +in set {\tt c}. All nodes in set 0 are ordered first, followed by all nodes in +set 1, and so on. %--------------------------------------- \subsection{{\tt cholmod\_bisect}: graph bisector} %--------------------------------------- \input{_bisect.tex} -Finds a node bisector of {\tt A}, {\tt A*A'}, {\tt A(:,f)*A(:,f)'}: -a set of nodes that partitions the graph into two parts. -Compresses the graph first, ensures the graph is symmetric with -no diagonal entries, and then calls METIS. +Finds a node bisector of {\tt A}, {\tt A*A'}, {\tt A(:,f)*A(:,f)'}: a set of +nodes that partitions the graph into two parts. Compresses the graph first, +ensures the graph is symmetric with no diagonal entries, and then calls METIS. %--------------------------------------- \subsection{{\tt cholmod\_metis\_bisector}: interface to METIS node bisector} %--------------------------------------- \input{_metis_bisector.tex} -Finds a set of nodes that bisects the graph of {\tt A} or {\tt A*A'} (a direct interface to \newline -{\tt METIS\_NodeComputeSeparator}). - -The input matrix {\tt A} must be square, symmetric (with both upper and lower -parts present) and with no diagonal entries. These conditions are not -checked. Use cholmod\_bisect to check these conditions. +Finds a set of nodes that bisects the graph of {\tt A} or {\tt A*A'} (a direct +interface to \newline {\tt METIS\_NodeComputeSeparator}). The input matrix +{\tt A} must be square, symmetric (with both upper and lower parts present) and +with no diagonal entries. These conditions are not checked. Use +{\tt cholmod\_bisect} to check these conditions. %--------------------------------------- \subsection{{\tt cholmod\_collapse\_septree}: prune a separator tree} @@ -3608,3 +3954,4 @@ \subsection{{\tt cholmod\_collapse\_septree}: prune a separator tree} \bibliographystyle{plain} \bibliography{UserGuide} \end{document} + diff --git a/CHOLMOD/Doc/ChangeLog b/CHOLMOD/Doc/ChangeLog index 3c86574337..82a4233c72 100644 --- a/CHOLMOD/Doc/ChangeLog +++ b/CHOLMOD/Doc/ChangeLog @@ -1,3 +1,9 @@ +Nov 30, 2023, version 5.1.0 + + * support for single precision matrices: for all Modules, except for the + GPU kernels (which are only supported for double and complex double + matrices). + Oct 31, 2023, version 5.0.1 * cholmod.h: remove use of "I" which conflicts with diff --git a/CHOLMOD/Doc/Makefile b/CHOLMOD/Doc/Makefile index 365c4d142f..69b30b345c 100644 --- a/CHOLMOD/Doc/Makefile +++ b/CHOLMOD/Doc/Makefile @@ -3,7 +3,7 @@ all: CHOLMOD_UserGuide.pdf I = ../Include/cholmod.h -C = ../Demo/cholmod_simple.c +C = ../Demo/cholmod_di_simple.c M = \ ../MATLAB/analyze.m \ @@ -25,7 +25,6 @@ M = \ ../MATLAB/nesdis.m \ ../MATLAB/resymbol.m \ ../MATLAB/sdmult.m \ - ../MATLAB/sparse2.m \ ../MATLAB/spsym.m \ ../MATLAB/mread.m \ ../MATLAB/mwrite.m \ @@ -54,19 +53,20 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getmproto ../MATLAB/nesdis.m > _nesdis_m.tex ./getmproto ../MATLAB/resymbol.m > _resymbol_m.tex ./getmproto ../MATLAB/sdmult.m > _sdmult_m.tex - ./getmproto ../MATLAB/sparse2.m > _sparse2_m.tex ./getmproto ../MATLAB/symbfact2.m > _symbfact2_m.tex - ./getproto '/include/, /^}/' ../Demo/cholmod_simple.c > _simple.tex + ./getproto '/include/, /^}/' ../Demo/cholmod_di_simple.c > _simple.tex ./getproto '/typedef struct cholmod_common/, /^}/' ../Include/cholmod.h > _common.tex ./getproto '/int cholmod_start/, /\*\) ;/' ../Include/cholmod.h > _start.tex ./getproto '/int cholmod_finish/, /\*\) ;/' ../Include/cholmod.h > _finish.tex ./getproto '/int cholmod_defaults/, /\*\) ;/' ../Include/cholmod.h > _defaults.tex ./getproto '/size_t cholmod_maxrank/, /\*\) ;/' ../Include/cholmod.h > _maxrank.tex ./getproto '/int cholmod_allocate_work/, /\*\) ;/' ../Include/cholmod.h > _allocate_work.tex + ./getproto '/int cholmod_alloc_work/, /\*\) ;/' ../Include/cholmod.h > _alloc_work.tex ./getproto '/int cholmod_free_work/, /\*\) ;/' ../Include/cholmod.h > _free_work.tex ./getproto '/int64_t cholmod_clear_flag/, /\*\) ;/' ../Include/cholmod.h > _clear_flag.tex ./getproto '/int cholmod_error/, /\*\) ;/' ../Include/cholmod.h > _error.tex - ./getproto '/double cholmod_dbound/, /l_sbound/' ../Include/cholmod.h > _dbound.tex + ./getproto '/double cholmod_dbound/, /l_dbound/' ../Include/cholmod.h > _dbound.tex + ./getproto '/float cholmod_sbound/, /l_sbound/' ../Include/cholmod.h > _sbound.tex ./getproto '/double cholmod_hypot/, /double\) ;/' ../Include/cholmod.h > _hypot.tex ./getproto '/int cholmod_divcomplex/, /\*\) ;/' ../Include/cholmod.h > _divcomplex.tex ./getproto '/typedef struct cholmod_sparse/, /^}/' ../Include/cholmod.h > _sparse.tex @@ -83,6 +83,7 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/cholmod_sparse \*cholmod_ptranspose/, /\*\) ;/' ../Include/cholmod.h > _ptranspose.tex ./getproto '/int cholmod_sort/, /\*\) ;/' ../Include/cholmod.h > _sort.tex ./getproto '/cholmod_sparse \*cholmod_band/, /\*\) ;/' ../Include/cholmod.h > _band.tex + ./getproto '/int64_t cholmod_band_nnz/, /\*\) ;/' ../Include/cholmod.h > _band_nnz.tex ./getproto '/int cholmod_band_inplace/, /\*\) ;/' ../Include/cholmod.h > _band_inplace.tex ./getproto '/cholmod_sparse \*cholmod_aat/, /\*\) ;/' ../Include/cholmod.h > _aat.tex ./getproto '/cholmod_sparse \*cholmod_copy_sparse/, /\*\) ;/' ../Include/cholmod.h > _copy_sparse.tex @@ -91,6 +92,7 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/int cholmod_sparse_xtype/, /\*\) ;/' ../Include/cholmod.h > _sparse_xtype.tex ./getproto '/typedef struct cholmod_factor/, /^}/' ../Include/cholmod.h > _factor.tex ./getproto '/cholmod_factor \*cholmod_allocate_factor/, /\*\) ;/' ../Include/cholmod.h > _allocate_factor.tex + ./getproto '/cholmod_factor \*cholmod_alloc_factor/, /\*\) ;/' ../Include/cholmod.h > _alloc_factor.tex ./getproto '/int cholmod_free_factor/, /\*\) ;/' ../Include/cholmod.h > _free_factor.tex ./getproto '/int cholmod_reallocate_factor/, /\*\) ;/' ../Include/cholmod.h > _reallocate_factor.tex ./getproto '/int cholmod_change_factor/, /\*\) ;/' ../Include/cholmod.h > _change_factor.tex @@ -125,7 +127,6 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/void \*cholmod_realloc/, /\*\) ;/' ../Include/cholmod.h > _realloc.tex ./getproto '/int cholmod_realloc_multiple/, /\*\) ;/' ../Include/cholmod.h > _realloc_multiple.tex ./getproto '/int cholmod_version/, /l_version/' ../Include/cholmod.h > _version.tex - ./getproto '/itype: integer sizes/, /define CHOLMOD_SUPERNODAL/' ../Include/cholmod.h > _defn.tex ./getproto '/int cholmod_check_common/, /\*\) ;/' ../Include/cholmod.h > _check_common.tex ./getproto '/int cholmod_print_common/, /\*\) ;/' ../Include/cholmod.h > _print_common.tex ./getproto '/int cholmod_check_sparse/, /\*\) ;/' ../Include/cholmod.h > _check_sparse.tex @@ -142,10 +143,14 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/int cholmod_print_perm/, /\*\) ;/' ../Include/cholmod.h > _print_perm.tex ./getproto '/int cholmod_check_parent/, /\*\) ;/' ../Include/cholmod.h > _check_parent.tex ./getproto '/int cholmod_print_parent/, /\*\) ;/' ../Include/cholmod.h > _print_parent.tex - ./getproto '/cholmod_triplet \*cholmod_read_triplet/, /\*\) ;/' ../Include/cholmod.h > _read_triplet.tex - ./getproto '/cholmod_sparse \*cholmod_read_sparse/, /\*\) ;/' ../Include/cholmod.h > _read_sparse.tex - ./getproto '/cholmod_dense \*cholmod_read_dense/, /\*\) ;/' ../Include/cholmod.h > _read_dense.tex - ./getproto '/void \*cholmod_read_matrix/, /\*\) ;/' ../Include/cholmod.h > _read_matrix.tex + ./getproto '/cholmod_triplet \*cholmod_read_triplet /, /\*\) ;/' ../Include/cholmod.h > _read_triplet.tex + ./getproto '/cholmod_triplet \*cholmod_read_triplet2/, /\*\) ;/' ../Include/cholmod.h > _read_triplet2.tex + ./getproto '/cholmod_sparse \*cholmod_read_sparse /, /\*\) ;/' ../Include/cholmod.h > _read_sparse.tex + ./getproto '/cholmod_sparse \*cholmod_read_sparse2/, /\*\) ;/' ../Include/cholmod.h > _read_sparse2.tex + ./getproto '/cholmod_dense \*cholmod_read_dense /, /\*\) ;/' ../Include/cholmod.h > _read_dense.tex + ./getproto '/cholmod_dense \*cholmod_read_dense2/, /\*\) ;/' ../Include/cholmod.h > _read_dense2.tex + ./getproto '/void \*cholmod_read_matrix /, /\*\) ;/' ../Include/cholmod.h > _read_matrix.tex + ./getproto '/void \*cholmod_read_matrix2/, /\*\) ;/' ../Include/cholmod.h > _read_matrix2.tex ./getproto '/int cholmod_write_sparse/, /\*\) ;/' ../Include/cholmod.h > _write_sparse.tex ./getproto '/int cholmod_write_dense/, /\*\) ;/' ../Include/cholmod.h > _write_dense.tex ./getproto '/cholmod_factor \*cholmod_analyze /, /\*\) ;/' ../Include/cholmod.h > _analyze.tex @@ -160,8 +165,7 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/int cholmod_analyze_ordering/, /\*\) ;/' ../Include/cholmod.h > _analyze_ordering.tex ./getproto '/int cholmod_amd/, /\*\) ;/' ../Include/cholmod.h > _amd.tex ./getproto '/int cholmod_colamd/, /\*\) ;/' ../Include/cholmod.h > _colamd.tex - ./getproto '/int cholmod_rowfac/, /\*\) ;/' ../Include/cholmod.h > _rowfac.tex - ./getproto '/int cholmod_rowfac_mask/, /\*\) ;/' ../Include/cholmod.h > _rowfac_mask.tex + ./getproto '/int cholmod_rowfac /, /\*\) ;/' ../Include/cholmod.h > _rowfac.tex ./getproto '/int cholmod_row_subtree/, /\*\) ;/' ../Include/cholmod.h > _row_subtree.tex ./getproto '/int cholmod_row_lsubtree/, /\*\) ;/' ../Include/cholmod.h > _row_lsubtree.tex ./getproto '/int cholmod_lsolve_pattern/, /\*\) ;/' ../Include/cholmod.h > _lsolve_pattern.tex @@ -171,14 +175,10 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/int32_t cholmod_postorder/, /\*\) ;/' ../Include/cholmod.h > _postorder.tex ./getproto '/int cholmod_updown /, /\*\) ;/' ../Include/cholmod.h > _updown.tex ./getproto '/int cholmod_updown_solve/, /\*\) ;/' ../Include/cholmod.h > _updown_solve.tex - ./getproto '/int cholmod_updown_mark/, /\*\) ;/' ../Include/cholmod.h > _updown_mark.tex - ./getproto '/int cholmod_updown_mask/, /\*\) ;/' ../Include/cholmod.h > _updown_mask.tex ./getproto '/int cholmod_rowadd /, /\*\) ;/' ../Include/cholmod.h > _rowadd.tex ./getproto '/int cholmod_rowadd_solve/, /\*\) ;/' ../Include/cholmod.h > _rowadd_solve.tex - ./getproto '/int cholmod_rowadd_mark/, /\*\) ;/' ../Include/cholmod.h > _rowadd_mark.tex ./getproto '/int cholmod_rowdel /, /\*\) ;/' ../Include/cholmod.h > _rowdel.tex ./getproto '/int cholmod_rowdel_solve/, /\*\) ;/' ../Include/cholmod.h > _rowdel_solve.tex - ./getproto '/int cholmod_rowdel_mark/, /\*\) ;/' ../Include/cholmod.h > _rowdel_mark.tex ./getproto '/int cholmod_drop/, /\*\) ;/' ../Include/cholmod.h > _drop.tex ./getproto '/double cholmod_norm_dense/, /\*\) ;/' ../Include/cholmod.h > _norm_dense.tex ./getproto '/double cholmod_norm_sparse/, /\*\) ;/' ../Include/cholmod.h > _norm_sparse.tex @@ -189,7 +189,7 @@ CHOLMOD_UserGuide.pdf: CHOLMOD_UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefi ./getproto '/cholmod_sparse \*cholmod_submatrix/, /\*\) ;/' ../Include/cholmod.h > _submatrix.tex ./getproto '/cholmod_sparse \*cholmod_vertcat/, /\*\) ;/' ../Include/cholmod.h > _vertcat.tex ./getproto '/int cholmod_symmetry/, /\*\) ;/' ../Include/cholmod.h > _symmetry.tex - ./getproto '/int cholmod_super_symbolic/, /\*\) ;/' ../Include/cholmod.h > _super_symbolic.tex + ./getproto '/int cholmod_super_symbolic /, /\*\) ;/' ../Include/cholmod.h > _super_symbolic.tex ./getproto '/int cholmod_super_numeric/, /\*\) ;/' ../Include/cholmod.h > _super_numeric.tex ./getproto '/int cholmod_super_lsolve/, /\*\) ;/' ../Include/cholmod.h > _super_lsolve.tex ./getproto '/int cholmod_super_ltsolve/, /\*\) ;/' ../Include/cholmod.h > _super_ltsolve.tex diff --git a/CHOLMOD/Doc/cholmod_version.tex b/CHOLMOD/Doc/cholmod_version.tex index 595148b69f..469a41a77c 100644 --- a/CHOLMOD/Doc/cholmod_version.tex +++ b/CHOLMOD/Doc/cholmod_version.tex @@ -1,2 +1,2 @@ % version of SuiteSparse/CHOLMOD -\date{VERSION 5.0.1, Oct 31, 2023} +\date{VERSION 5.1.0, Nov 30, 2023} diff --git a/CHOLMOD/GPU/t_cholmod_gpu.c b/CHOLMOD/GPU/t_cholmod_gpu.c index e206ba65af..4eb037a443 100644 --- a/CHOLMOD/GPU/t_cholmod_gpu.c +++ b/CHOLMOD/GPU/t_cholmod_gpu.c @@ -431,7 +431,7 @@ int TEMPLATE2 (CHOLMOD (gpu_updateC)) int icol, irow; int iHostBuff, iDevBuff ; -#ifndef NTIMER +#ifdef BLAS_TIMER double tstart = 0; #endif @@ -444,7 +444,7 @@ int TEMPLATE2 (CHOLMOD (gpu_updateC)) ndrow3 = ndrow2 - ndrow1 ; -#ifndef NTIMER +#ifdef BLAS_TIMER Common->syrkStart = SuiteSparse_time ( ) ; Common->CHOLMOD_GPU_SYRK_CALLS++ ; #endif @@ -553,7 +553,7 @@ int TEMPLATE2 (CHOLMOD (gpu_updateC)) ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ; } -#ifndef NTIMER +#ifdef BLAS_TIMER Common->CHOLMOD_GPU_SYRK_TIME += SuiteSparse_time() - Common->syrkStart; #endif @@ -561,7 +561,7 @@ int TEMPLATE2 (CHOLMOD (gpu_updateC)) /* compute remaining (ndrow2-ndrow1)-by-ndrow1 block of C, C2 = L2*L1' */ /* ---------------------------------------------------------------------- */ -#ifndef NTIMER +#ifdef BLAS_TIMER Common->CHOLMOD_GPU_GEMM_CALLS++ ; tstart = SuiteSparse_time(); #endif @@ -612,7 +612,7 @@ int TEMPLATE2 (CHOLMOD (gpu_updateC)) } -#ifndef NTIMER +#ifdef BLAS_TIMER Common->CHOLMOD_GPU_GEMM_TIME += SuiteSparse_time() - tstart; #endif @@ -818,7 +818,7 @@ int TEMPLATE2 (CHOLMOD (gpu_lower_potrf)) int64_t j, nsrow2, nb, n, gpu_lda, lda, gpu_ldb ; int ilda, ijb ; int64_t iinfo ; -#ifndef NTIMER +#ifdef BLAS_TIMER double tstart ; #endif @@ -828,7 +828,7 @@ int TEMPLATE2 (CHOLMOD (gpu_lower_potrf)) return (0) ; } -#ifndef NTIMER +#ifdef BLAS_TIMER tstart = SuiteSparse_time ( ) ; Common->CHOLMOD_GPU_POTRF_CALLS++ ; #endif @@ -1146,7 +1146,7 @@ int TEMPLATE2 (CHOLMOD (gpu_lower_potrf)) } } -#ifndef NTIMER +#ifdef BLAS_TIMER Common->CHOLMOD_GPU_POTRF_TIME += SuiteSparse_time ( ) - tstart ; #endif @@ -1194,7 +1194,7 @@ int TEMPLATE2 (CHOLMOD (gpu_triangular_solve)) int64_t iidx; int iwrap; -#ifndef NTIMER +#ifdef BLAS_TIMER double tstart ; #endif @@ -1211,7 +1211,7 @@ int TEMPLATE2 (CHOLMOD (gpu_triangular_solve)) return (0) ; } -#ifndef NTIMER +#ifdef BLAS_TIMER tstart = SuiteSparse_time ( ) ; Common->CHOLMOD_GPU_TRSM_CALLS++ ; #endif @@ -1400,7 +1400,7 @@ private ( iidx ) if ( nscol2 > 32 ) /* return */ /* ---------------------------------------------------------------------- */ -#ifndef NTIMER +#ifdef BLAS_TIMER Common->CHOLMOD_GPU_TRSM_TIME += SuiteSparse_time ( ) - tstart ; #endif diff --git a/CHOLMOD/Include/cholmod.h b/CHOLMOD/Include/cholmod.h index a2a25c16c7..b2aaa2b973 100644 --- a/CHOLMOD/Include/cholmod.h +++ b/CHOLMOD/Include/cholmod.h @@ -21,14 +21,16 @@ // CHOLMOD/Tcov: SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -// CHOLMOD consists of a set of Modules, each with their own license: either -// LGPL-2.1+ or GPL-2.0+. This cholmod.h file includes defintions of the -// CHOLMOD API for all Modules, and this cholmod.h file itself is provided to -// you with a permissive license (Apache-2.0). You are permitted to provide -// the hooks for an optional interface to CHOLMOD in a non-GPL/non-LGPL code, -// without requiring you to agree to the GPL/LGPL license of the Modules, as -// long as you don't use the *.c files in the relevant Modules. The Modules -// themselves can only be functional if their GPL or LGPL licenses are used. +// CHOLMOD consists of a set of Modules, each with their own Copyright and +// license: either LGPL-2.1+ or GPL-2.0+. This cholmod.h file includes +// defintions of the CHOLMOD API for all Modules, and this cholmod.h file +// itself is provided to you with a permissive license (Apache-2.0). You are +// permitted to provide the hooks for an optional interface to CHOLMOD in a +// non-GPL/non-LGPL code, without requiring you to agree to the GPL/LGPL +// license of the Modules, as long as you don't use the *.c files in the +// relevant Modules. The Modules themselves can only be functional if their +// GPL or LGPL licenses are used, or if you obtain a different license from the +// respective copyright holders. // // The Modify Module is co-authored by William W. Hager. // @@ -38,14 +40,20 @@ // CHOLMOD's Partition Module. // ----------------------------------------------------------------------------- -// Each routine in CHOLMOD has a consistent interface. +#ifndef CHOLMOD_H +#define CHOLMOD_H + +//------------------------------------------------------------------------------ +// CHOLMOD conventions +//------------------------------------------------------------------------------ + +// Each routine in CHOLMOD follows the following conventions: // // Naming convention: // ------------------ // -// All routine names, data types, and CHOLMOD library files use the -// cholmod_ prefix. All macros and other #define's use the CHOLMOD -// prefix. +// All routine names, data types, and CHOLMOD library files use the cholmod_ +// prefix. All macros and other #define's use the CHOLMOD prefix. // // Return value: // ------------- @@ -85,17 +93,157 @@ // The cholmod_common *Common parameter always appears as the last // parameter. It is always an input/output parameter. -#ifndef CHOLMOD_H -#define CHOLMOD_H +//------------------------------------------------------------------------------ +// CHOLMOD matrix formats +//------------------------------------------------------------------------------ -//============================================================================== +// A CHOLMOD sparse, dense, or triplet matrix A, or a sparse factorization L +// can hold numeric values of 8 different types, according to its A->xtype and +// A->dtype parameters (or L->xtype and L->dtype for a sparse factor object). +// These values are held in the A->x array, and also A->z for "zomplex" +// matrices. +// +// A->xtype: the matrix is real, complex, "zomplex", or pattern-only. +// +// (0): CHOLMOD_PATTERN: A->x and A->z are NULL. The matrix has no +// numerical values. Only the pattern is stored. +// +// (1): CHOLMOD_REAL: The matrix is real, and the values are held in +// A->x, whose size (in terms of double or float +// values) is given by A->nzmax. The kth value in +// the matrix is held in A->x [k]. +// +// (2): CHOLMOD_COMPLEX: The matrix is complex, with interleaved real and +// imaginary parts. The kth value in the matrix +// is held in A->x [2*k] and A->x [2*k+1], where +// A->x can hold up to 2*A->nzmax values. +// +// (3): CHOLMOD_ZOMPLEX: The matrix is complex, with separate array for +// the real and imaginary parts. The kth value in +// the matrix is held in A->x [k] and A->z [k], +// where A->x and A->z can hold up to A->nzmax +// values each. + + // A->xtype values: + #define CHOLMOD_PATTERN 0 + #define CHOLMOD_REAL 1 + #define CHOLMOD_COMPLEX 2 + #define CHOLMOD_ZOMPLEX 3 + +// A->dtype: this parameter determines the type of values in A->x (and A->z +// if zomplex). +// +// (0) CHOLMOD_DOUBLE: A->x (and A->z for zomplex matrices) is double. +// If A is real, A->x has a size of A->nzmax * +// sizeof (double). If A is complex, A->x has +// size A->nzmax * 2 * sizeof (double). If +// zomplex, both A->x and A->z have size A->nzmax +// * sizeof (double). +// +// (4) CHOLMOD_SINGLE: A->x (and A->z for zomplex matrices) is float. +// If A is real, A->x has a size of A->nzmax * +// sizeof (float). If A is complex, A->x has size +// A->nzmax * 2 * sizeof (float). If zomplex, +// both A->x and A->z have size A->nzmax * sizeof +// (float). This feature is new to CHOLMOD v5. +// + + // A->dtype values: + #define CHOLMOD_DOUBLE 0 + #define CHOLMOD_SINGLE 4 + +// Unless stated otherwise, the xtype and dtypes of all inputs to a method must +// be the same. +// +// Many methods accept an xdtype parameter, which is simply xtype + dtype, +// combining the two parameters into a single number handling all 8 cases: +// +// (0) CHOLMOD_DOUBLE + CHOLMOD_PATTERN a pattern-only matrix +// (1) CHOLMOD_DOUBLE + CHOLMOD_REAL a double real matrix +// (2) CHOLMOD_DOUBLE + CHOLMOD_COMPLEX a double complex matrix +// (3) CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX a double zomplex matrix +// (4) CHOLMOD_SINGLE + CHOLMOD_PATTERN a pattern-only matrix +// (5) CHOLMOD_SINGLE + CHOLMOD_REAL a float real matrix +// (6) CHOLMOD_SINGLE + CHOLMOD_COMPLEX a float complex matrix +// (7) CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX a float zomplex matrix +// +// This approach was selected for backward compatibility with CHOLMOD v4 and +// earlier, where only the first four values were supported, and where the +// parameter was called "xtype" instead of "xdtype". Several function names +// reflect the older parameter name (cholmod_*_xtype), but they have not been +// renamed "_xdtype", for backward compatibility. +// +// A CHOLMOD sparse or triplet matrix A can held in three symmetry formats +// according to its A->stype parameter. Dense matrices do not have this +// parameter and are always treated as unsymmetric. A sparse factor object L +// is always held in lower triangular form, with no entries ever held in the +// strictly upper triangular part. +// +// 0: the matrix is unsymmetric with both lower and upper parts stored. +// +// <0: the matrix is symmetric, with just the lower triangular part and +// diagonal stored. Any entries in the upper part are ignored. +// +// >0: the matrix is symmetric, with just the upper triangular part stored +// and diagonal. Any entries in the upper part are ignored. +// +// If a sparse or triplet matrix A is complex or zomplex, most methods treat +// the matrix as Hermitian, where A(i,j) is the complex conjugate of A(j,i), +// when i is not equal to j. Some methods can also interpret the matrix as +// complex symmetric, where A(i,j) == A(j,i) when i != j. This is not +// determined by the matrix itself, but by a "mode" parameter of the function. +// This mode parameter also determines if the values of any matrix are to be +// ignored entirely, in which case only the pattern is operated on. Any output +// matrix will have an xtype of CHOLMOD_PATTERN. +// +// The valid mode values are given below, except that many methods do not +// handle the negative cases. Values below the range accepted by the method +// are treated as its lowest accepted value, and values above the range +// accepted by the method are treated as its highest accepted value. +// +// mode = 2: the numerical values of a real, complex, or zomplex matrix are +// handled. If the matrix is complex or zomplex, an entry A(i,j) +// that not stored (or in the ignored part) is treated as the +// complex conjugate of A (j,i). Use this mode to treat a +// complex or zomplex matrix as Hermitian. +// +// mode = 1: the numerical values of a real, complex, or zomplex matrix are +// handled. If the matrix is complex or zomplex, an entry A(i,j) +// that not stored (or in the ignored part) is treated as equal A +// (j,i). Use this mode to treat a complex or zomplex matrix as +// complex symmetric. +// +// mode = 0: the numerical values are ignored. Any output matrix will have +// an xtype of CHOLMOD_PATTERN. This mode allows inputs to have +// different dtypes. +// +// mode = -1: the same as mode = 0, except that the diagonal entries are +// ignored, and do not appear in any output matrix. +// +// mode = -2: the same as mode = -1, except that the output matrix is given an +// additional slack space so that it can hold about 50% more +// entries. This mode is documented here but it is primarily +// meant for internal use, for CHOLMOD's interface to the AMD, +// CAMD, COLAMD, and CCOLAMD ordering methods. +// +// The integer arrays in all objects are either int32 or int64, as determined +// by A->type. This integer type must be identical for all inputs, and must +// also match both the function name (cholmod_method for int32, or +// cholmod_l_method for int64) and the Common->itype as defined when CHOLMOD +// was initialized (via cholmod_start for int32, or cholmod_l_start for int64). + + // itype values: + #define CHOLMOD_INT 0 /* int32, for cholmod_* methods (no _l_) */ + #define CHOLMOD_LONG 2 /* int64, for cholmod_l_* methods */ + +//------------------------------------------------------------------------------ // version control -//============================================================================== +//------------------------------------------------------------------------------ -#define CHOLMOD_DATE "Oct 31, 2023" +#define CHOLMOD_DATE "Nov 30, 2023" #define CHOLMOD_MAIN_VERSION 5 -#define CHOLMOD_SUB_VERSION 0 -#define CHOLMOD_SUBSUB_VERSION 1 +#define CHOLMOD_SUB_VERSION 1 +#define CHOLMOD_SUBSUB_VERSION 0 #define CHOLMOD_VER_CODE(main,sub) ((main) * 1000 + (sub)) #define CHOLMOD_VERSION \ @@ -120,9 +268,9 @@ int cholmod_l_version (int version [3]) ; } #endif -//============================================================================== +//------------------------------------------------------------------------------ // Large file support -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD assumes large file support. If problems occur, compile with // -DNLARGEFILE @@ -148,15 +296,15 @@ int cholmod_l_version (int version [3]) ; #endif #endif -//============================================================================== -// SuiteSparse_config -//============================================================================== +//------------------------------------------------------------------------------ +// SuiteSparse_config: definitions for all SuiteSparse packages +//------------------------------------------------------------------------------ #include "SuiteSparse_config.h" -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD configuration -//============================================================================== +//------------------------------------------------------------------------------ // You do not have to edit any CHOLMOD files to compile and install CHOLMOD. // However, if you do not use all of CHOLMOD's modules, you need to compile @@ -231,83 +379,16 @@ int cholmod_l_version (int version [3]) ; //------------------------------------------------------------------------------ // CHOLMOD object enums -#define CHOLMOD_COMMON 0 -#define CHOLMOD_SPARSE 1 -#define CHOLMOD_FACTOR 2 -#define CHOLMOD_DENSE 3 -#define CHOLMOD_TRIPLET 4 - -// enums used by cholmod_symmetry and cholmod_write -#define CHOLMOD_MM_RECTANGULAR 1 -#define CHOLMOD_MM_UNSYMMETRIC 2 -#define CHOLMOD_MM_SYMMETRIC 3 -#define CHOLMOD_MM_HERMITIAN 4 -#define CHOLMOD_MM_SKEW_SYMMETRIC 5 -#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 -#define CHOLMOD_MM_HERMITIAN_POSDIAG 7 +#define CHOLMOD_COMMON 0 /* parameters, statistics, and workspace */ +#define CHOLMOD_SPARSE 1 /* a sparse matrix in CSC form (and variants) */ +#define CHOLMOD_FACTOR 2 /* a sparse factorization */ +#define CHOLMOD_DENSE 3 /* a dense matrix in column-oriented form */ +#define CHOLMOD_TRIPLET 4 /* a sparse matrix in triplet form */ //------------------------------------------------------------------------------ // CHOLMOD Common object //------------------------------------------------------------------------------ -// itype: integer sizes -// The itype is held in the Common object and must match the method used. -#define CHOLMOD_INT 0 /* int32, for cholmod_* methods (no _l_) */ -#define CHOLMOD_LONG 2 /* int64, for cholmod_l_* methods */ - -// dtype: floating point sizes (double or float) -// The dtype of all parameters for all CHOLMOD routines must match. -// NOTE: CHOLMOD_SINGLE is still under development. -#define CHOLMOD_DOUBLE 0 /* matrix or factorization is double precision */ -#define CHOLMOD_SINGLE 4 /* matrix or factorization is single precision */ - -// xtype: pattern, real, complex, or zomplex -#define CHOLMOD_PATTERN 0 /* no numerical values */ -#define CHOLMOD_REAL 1 /* real (double or single), not complex */ -#define CHOLMOD_COMPLEX 2 /* complex (double or single), interleaved */ -#define CHOLMOD_ZOMPLEX 3 /* complex (double or single), with real and imag */ - /* parts held in different arrays */ - -// xdtype is (xtype + dtype), which combines the two type parameters into -// a single number handling all 8 cases: -// -// (0) CHOLMOD_DOUBLE + CHOLMOD_PATTERN a pattern-only matrix -// (1) CHOLMOD_DOUBLE + CHOLMOD_REAL a double real matrix -// (2) CHOLMOD_DOUBLE + CHOLMOD_COMPLEX a double complex matrix -// (3) CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX a double zomplex matrix -// (4) CHOLMOD_SINGLE + CHOLMOD_PATTERN a pattern-only matrix -// (5) CHOLMOD_SINGLE + CHOLMOD_REAL a float real matrix -// (6) CHOLMOD_SINGLE + CHOLMOD_COMPLEX a float complex matrix -// (7) CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX a float zomplex matrix - -// max # of ordering methods in Common -#define CHOLMOD_MAXMETHODS 9 - -// Common->status for error handling: 0 is ok, negative is a fatal error, -// and positive is a warning -#define CHOLMOD_OK (0) -#define CHOLMOD_NOT_INSTALLED (-1) /* module not installed */ -#define CHOLMOD_OUT_OF_MEMORY (-2) /* malloc, calloc, or realloc failed */ -#define CHOLMOD_TOO_LARGE (-3) /* integer overflow */ -#define CHOLMOD_INVALID (-4) /* input invalid */ -#define CHOLMOD_GPU_PROBLEM (-5) /* CUDA error */ -#define CHOLMOD_NOT_POSDEF (1) /* matrix not positive definite */ -#define CHOLMOD_DSMALL (2) /* diagonal entry very small */ - -// ordering method -#define CHOLMOD_NATURAL 0 /* no preordering */ -#define CHOLMOD_GIVEN 1 /* user-provided permutation */ -#define CHOLMOD_AMD 2 /* AMD: approximate minimum degree */ -#define CHOLMOD_METIS 3 /* METIS: mested dissection */ -#define CHOLMOD_NESDIS 4 /* CHOLMOD's nested dissection */ -#define CHOLMOD_COLAMD 5 /* AMD for A, COLAMD for AA' or A'A */ -#define CHOLMOD_POSTORDERED 6 /* natural then postordered */ - -// supernodal strategy -#define CHOLMOD_SIMPLICIAL 0 /* always use simplicial method */ -#define CHOLMOD_AUTO 1 /* auto select simplicial vs supernodal */ -#define CHOLMOD_SUPERNODAL 2 /* always use supernoda method */ - #ifdef __cplusplus extern "C" { #endif @@ -321,22 +402,22 @@ typedef struct cholmod_common_struct double dbound ; // Bounds the diagonal entries of D for LDL' // factorization and update/downdate/rowadd. Entries outside this - // bound are replaced with dbound. Default: 0. - // dbound is used for double precision factorization only. - // See sbound for single precision factorization. + // bound are replaced with dbound. Default: 0. dbound is used for + // double precision factorization only. See sbound for single + // precision factorization. double grow0 ; // default: 1.2 double grow1 ; // default: 1.2 size_t grow2 ; // default: 5 // Initial space for simplicial factorization is max(grow0,1) times the - // required space. If space is exhausted, L is grown by - // max(grow0,1.2) times the required space. grow1 and grow2 control - // how each column of L can grow in an update/downdate; if space runs - // out, then grow1*(required space) + grow2 is allocated. + // required space. If space is exhausted, L is grown by max(grow0,1.2) + // times the required space. grow1 and grow2 control how each column + // of L can grow in an update/downdate; if space runs out, then + // grow1*(required space) + grow2 is allocated. size_t maxrank ; // maximum rank for update/downdate. Valid values are - // 2, 4, and 8. Default is 8. If a larger update/downdate is done, - // it is done in steps of maxrank. + // 2, 4, and 8. Default is 8. If a larger update/downdate is done, it + // is done in steps of maxrank. double supernodal_switch ; // default: 40 int supernodal ; // default: CHOLMOD_AUTO. @@ -346,6 +427,10 @@ typedef struct cholmod_common_struct // always done. If CHOLMOD_AUTO, then a simplicial factorization is // down if flops/nnz(L) < Common->supernodal_switch. + #define CHOLMOD_SIMPLICIAL 0 /* always use simplicial method */ + #define CHOLMOD_AUTO 1 /* auto select simplicial vs supernodal */ + #define CHOLMOD_SUPERNODAL 2 /* always use supernoda method */ + int final_asis ; // if true, other final_* parameters are ignored, // except for final_pack and the factors are left as-is when done. // Default: true. @@ -411,6 +496,10 @@ typedef struct cholmod_common_struct // entries in row/column k, and off-diagonals are set to -1. // Default: false. + //-------------------------------------------------------------------------- + // printing and error handling options + //-------------------------------------------------------------------------- + int print ; // print level. Default is 3. int precise ; // if true, print 16 digits, otherwise 5. Default: false. @@ -543,11 +632,20 @@ typedef struct cholmod_common_struct // components is partitioned separately. If false, the whole // subgraph is partitioned. Default: false. - int ordering ; // ordering method to use + int ordering ; // ordering method to use: + + #define CHOLMOD_NATURAL 0 /* no preordering */ + #define CHOLMOD_GIVEN 1 /* user-provided permutation */ + #define CHOLMOD_AMD 2 /* AMD: approximate minimum degree */ + #define CHOLMOD_METIS 3 /* METIS: mested dissection */ + #define CHOLMOD_NESDIS 4 /* CHOLMOD's nested dissection */ + #define CHOLMOD_COLAMD 5 /* AMD for A, COLAMD for AA' or A'A */ + #define CHOLMOD_POSTORDERED 6 /* natural then postordered */ size_t other_3 [4] ; // unused, for future expansion } + #define CHOLMOD_MAXMETHODS 9 /* max # of methods in Common->method */ method [CHOLMOD_MAXMETHODS + 1] ; int postorder ; // if true, CHOLMOD performs a weighted postordering @@ -586,9 +684,8 @@ typedef struct cholmod_common_struct int64_t mark ; // Flag is cleared if Flag [0..nrow-1] < mark. size_t iworksize ; // size of Iwork, in Ints (int32 or int64). // This is at most 6*nrow + ncol. - size_t xworkbytes ; // size of Xwork, in bytes. for update/downdate: - // maxrank*nrow*sizeof(double or float), 2*nrow*sizeof(double or float) - // otherwise. NOTE: in CHOLMOD v4 and earlier, xworkwise was in terms + size_t xworkbytes ; // size of Xwork, in bytes. + // NOTE: in CHOLMOD v4 and earlier, xworkwise was in terms // of # of doubles, not # of bytes. void *Flag ; // size nrow. If this is "cleared" then @@ -624,7 +721,19 @@ typedef struct cholmod_common_struct // statistics //-------------------------------------------------------------------------- - int status ; // status code (0: ok, negative: error, pos: warning + int status ; // status code (0: ok, negative: error, pos: warning) + + // Common->status for error handling: 0 is ok, negative is a fatal + // error, and positive is a warning + #define CHOLMOD_OK (0) + #define CHOLMOD_NOT_INSTALLED (-1) /* module not installed */ + #define CHOLMOD_OUT_OF_MEMORY (-2) /* malloc/calloc/realloc failed */ + #define CHOLMOD_TOO_LARGE (-3) /* integer overflow */ + #define CHOLMOD_INVALID (-4) /* input invalid */ + #define CHOLMOD_GPU_PROBLEM (-5) /* CUDA error */ + #define CHOLMOD_NOT_POSDEF (1) /* matrix not positive definite */ + #define CHOLMOD_DSMALL (2) /* diagonal entry very small */ + double fl ; // flop count from last analysis double lnz ; // nnz(L) from last analysis double anz ; // in last analysis: nnz(tril(A)) or nnz(triu(A)) if A @@ -692,11 +801,12 @@ typedef struct cholmod_common_struct // as well. This mitigates any changes between v4.0 and v5.0, and may make // it easier to upgrade from v4 to v5. - double nsbounds_hit ; // # of times diagonal modified by sbound. This - // ought to be int64_t, but ndbounds_hit was double in v4 - // (see above), so nsbounds_hit is made the same type for - // consistency. - float sbound ; // Same as dbound, but for single precision factorization. + double nsbounds_hit ; // # of times diagonal modified by sbound. + // This ought to be int64_t, but ndbounds_hit was double in + // v4 (see above), so nsbounds_hit is made the same type + // for consistency. + float sbound ; // Same as dbound, + // but for single precision factorization. float other_6 ; // for future expansion //-------------------------------------------------------------------------- @@ -777,6 +887,8 @@ typedef struct cholmod_common_struct int nthreads_max ; // max # of OpenMP threads to use in CHOLMOD. // Defaults to SUITESPARSE_OPENMP_MAX_THREADS. + FILE *blas_dump ; // only used if CHOLMOD is compiled with -DBLAS_DUMP + } cholmod_common ; // size_t BLAS statistcs in Common: @@ -801,11 +913,6 @@ typedef struct cholmod_common_struct #define CHOLMOD_ASSEMBLE_TIME cholmod_assemble_time #define CHOLMOD_ASSEMBLE_TIME2 cholmod_assemble_time2 -// for supernodal analysis: -#define CHOLMOD_ANALYZE_FOR_SPQR 0 -#define CHOLMOD_ANALYZE_FOR_CHOLESKY 1 -#define CHOLMOD_ANALYZE_FOR_SPQRGPU 2 - //------------------------------------------------------------------------------ // cholmod_start: first call to CHOLMOD //------------------------------------------------------------------------------ @@ -833,6 +940,7 @@ int cholmod_l_defaults (cholmod_common *) ; size_t cholmod_maxrank // return validated Common->maxrank ( + // input: size_t n, // # of rows of L and A cholmod_common *Common ) ; @@ -847,6 +955,7 @@ size_t cholmod_l_maxrank (size_t, cholmod_common *) ; int cholmod_allocate_work ( + // input: size_t nrow, // size of Common->Flag (nrow int32's) // and Common->Head (nrow+1 int32's) size_t iworksize, // size of Common->Iwork (# of int32's) @@ -863,6 +972,7 @@ int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ; int cholmod_alloc_work ( + // input: size_t nrow, // size of Common->Flag (nrow int32's) // and Common->Head (nrow+1 int32's) size_t iworksize, // size of Common->Iwork (# of int32's) @@ -903,6 +1013,7 @@ int64_t cholmod_l_clear_flag (cholmod_common *) ; int cholmod_error ( + // input: int status, // Common->status const char *file, // source file where error occurred int line, // line number where error occurred @@ -920,8 +1031,8 @@ int cholmod_l_error (int, const char *, int, const char *, cholmod_common *) ; double cholmod_dbound (double, cholmod_common *) ; double cholmod_l_dbound (double, cholmod_common *) ; -float cholmod_sbound (float, cholmod_common *) ; -float cholmod_l_sbound (float, cholmod_common *) ; +float cholmod_sbound (float, cholmod_common *) ; +float cholmod_l_sbound (float, cholmod_common *) ; //------------------------------------------------------------------------------ // cholmod_hypot: compute sqrt (x*x + y*y) accurately @@ -936,6 +1047,7 @@ double cholmod_l_hypot (double, double) ; int cholmod_divcomplex // return 1 if divide-by-zero, 0 if OK ( + // input: double ar, double ai, // a (real, imaginary) double br, double bi, // b (real, imaginary) double *cr, double *ci // c (real, imaginary) @@ -992,6 +1104,7 @@ typedef struct cholmod_sparse_struct cholmod_sparse *cholmod_allocate_sparse ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1012,6 +1125,7 @@ cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int, int cholmod_free_sparse ( + // input/output: cholmod_sparse **A, // handle of sparse matrix to free cholmod_common *Common ) ; @@ -1023,7 +1137,9 @@ int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ; int cholmod_reallocate_sparse ( + // input: size_t nznew, // new max # of nonzeros the sparse matrix can hold + // input/output: cholmod_sparse *A, // sparse matrix to reallocate cholmod_common *Common ) ; @@ -1035,6 +1151,7 @@ int cholmod_l_reallocate_sparse (size_t, cholmod_sparse *, cholmod_common *) ; int64_t cholmod_nnz // return # of entries in the sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to query cholmod_common *Common ) ; @@ -1046,6 +1163,7 @@ int64_t cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ; cholmod_sparse *cholmod_speye ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1064,6 +1182,7 @@ cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ; cholmod_sparse *cholmod_spzeros // return a sparse matrix with no entries ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1081,9 +1200,11 @@ cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int, cholmod_sparse *cholmod_transpose // return new sparse matrix C ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) cholmod_common *Common ) ; cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; @@ -1098,12 +1219,15 @@ cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; int cholmod_transpose_unsym ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,f)', or NULL int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) ; @@ -1120,10 +1244,13 @@ int cholmod_l_transpose_unsym (cholmod_sparse *, int, int64_t *, int64_t *, int cholmod_transpose_sym ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,p)', or NULL + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) ; @@ -1136,9 +1263,11 @@ int cholmod_l_transpose_sym (cholmod_sparse *, int, int64_t *, cholmod_sparse *, cholmod_sparse *cholmod_ptranspose // return new sparse matrix C ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) int32_t *Perm, // permutation for C=A(p,f)', or NULL int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset @@ -1148,11 +1277,12 @@ cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, int64_t *, int64_t *, size_t, cholmod_common *) ; //------------------------------------------------------------------------------ -// cholmod_sort: sort the indices of a sparse matrix +// cholmod_sort: sort the indices of a sparse matrix //------------------------------------------------------------------------------ int cholmod_sort ( + // input/output: cholmod_sparse *A, // input/output matrix to sort cholmod_common *Common ) ; @@ -1164,6 +1294,7 @@ int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ; int64_t cholmod_band_nnz // return # of entries in a band (-1 if error) ( + // input: cholmod_sparse *A, // matrix to examine int64_t k1, // count entries in k1:k2 diagonals int64_t k2, @@ -1179,6 +1310,7 @@ int64_t cholmod_l_band_nnz (cholmod_sparse *, int64_t, int64_t, bool, cholmod_sparse *cholmod_band // return a new matrix C ( + // input: cholmod_sparse *A, // input matrix int64_t k1, // count entries in k1:k2 diagonals int64_t k2, @@ -1189,14 +1321,16 @@ cholmod_sparse *cholmod_l_band (cholmod_sparse *, int64_t, int64_t, int, cholmod_common *) ; //------------------------------------------------------------------------------ -// cholmod_band_inplace: A = tril (triu (A,k1), k2) */ +// cholmod_band_inplace: A = tril (triu (A,k1), k2) //------------------------------------------------------------------------------ int cholmod_band_inplace ( + // input: int64_t k1, // count entries in k1:k2 diagonals int64_t k2, int mode, // >0: numerical, 0: pattern, <0: pattern (no diag) + // input/output: cholmod_sparse *A, // input/output matrix cholmod_common *Common ) ; @@ -1209,11 +1343,14 @@ int cholmod_l_band_inplace (int64_t, int64_t, int, cholmod_sparse *, cholmod_sparse *cholmod_aat // return sparse matrix C ( + // input: cholmod_sparse *A, // input matrix int32_t *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.), + // 0: pattern (with diag) + // -1: pattern (remove diag), // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) ; @@ -1230,6 +1367,7 @@ cholmod_sparse *cholmod_l_aat (cholmod_sparse *, int64_t *, size_t, int, cholmod_sparse *cholmod_copy_sparse // return new sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to copy cholmod_common *Common ) ; @@ -1241,10 +1379,13 @@ cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ; cholmod_sparse *cholmod_copy // return new sparse matrix ( + // input: cholmod_sparse *A, // input matrix, not modified int stype, // stype of C - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) + // -1: pattern (remove diag) // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) ; @@ -1256,11 +1397,14 @@ cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ; cholmod_sparse *cholmod_add // return C = alpha*A + beta*B ( + // input: cholmod_sparse *A, // input matrix cholmod_sparse *B, // input matrix double alpha [2], // scale factor for A (two entires used if complex) double beta [2], // scale factor for A (two entires used if complex) - int values, // if TRUE compute the numerical values of C + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern int sorted, // ignored; C is now always returned as sorted cholmod_common *Common ) ; @@ -1273,7 +1417,9 @@ cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *, int cholmod_sparse_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_sparse *A, // sparse matrix to change cholmod_common *Common ) ; @@ -1305,24 +1451,19 @@ typedef struct cholmod_factor_struct // simplicial factorization (not supernodal) //-------------------------------------------------------------------------- - size_t nzmax ; // # of entries that L->i, L->x, and L->z can hold + // The row indices of L(:,j) are held in L->i [L->p [j] ... L->p [j] + + // L->nz [j] - 1]. The numeical values of L(:,j) are held in the same + // positions in L->x (and L->z if L is zomplex). L->next and L->prev hold + // a link list of columns of L, that tracks the order they appear in the + // arrays L->i, L->x, and L->z. The head and tail of the list is n+1 and + // n, respectively. + size_t nzmax ; // # of entries that L->i, L->x, and L->z can hold void *p ; // int32/int64, size n+1, column pointers void *i ; // int32/int64, size nzmax, row indices void *x ; // float/double, size nzmax or 2*nzmax, numerical values void *z ; // float/double, size nzmax or empty, imaginary values void *nz ; // int32/int64, size ncol, # of entries in each column - - // The row indices of L(:,j) are held in - // L->i [L->p [j] ... L->p [j] + L->nz [j] - 1]. - - // The numeical values of L(:,j) are held in the same positions in L->x - // (and L->z if L is zomplex) - - // L->next and L->prev hold a link list of columns of L, that tracks the - // order they appear in the arrays L->i, L->x, and L->z. The head and tail - // of the list is n+1 and n, respectively. - void *next ; // int32/int64, size n+2 void *prev ; // int32/int64, size n+2 @@ -1338,13 +1479,12 @@ typedef struct cholmod_factor_struct size_t xsize ; // # of entries in L->x size_t maxcsize ; // size of largest update matrix size_t maxesize ; // max # of rows in supernodes, excl. triangular part - // the following are int32/int64 and are size nsuper+1: void *super ; // first column in each supernode void *pi ; // index into L->s for integer part of a supernode void *px ; // index into L->x for numeric part of a supernode - - void *s ; // int32/int64, ssize, integer part of supernodes + // int32/int64, of size ssize: + void *s ; // integer part of supernodes //-------------------------------------------------------------------------- // type of the factorization @@ -1378,7 +1518,6 @@ typedef struct cholmod_factor_struct // If L->xtype is CHOLMOD_REAL, CHOLMOD_COMPLEX, or CHOLMOD_ZOMPLEX, // then L is a numeric factor: // - // // simplicial LDL': (is_ll false, is_super false). Stored in compressed // column form, using the simplicial components above (nzmax, p, i, // x, z, nz, next, and prev). The unit diagonal of L is not stored, @@ -1414,6 +1553,7 @@ typedef struct cholmod_factor_struct cholmod_factor *cholmod_allocate_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix cholmod_common *Common ) ; @@ -1423,8 +1563,9 @@ cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ; // cholmod_alloc_factor: allocate a numerical factor (double or single) //------------------------------------------------------------------------------ -cholmod_factor *cholmod_alloc_factor // return the new factor L +cholmod_factor *cholmod_alloc_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix int dtype, // CHOLMOD_SINGLE or CHOLMOD_DOUBLE cholmod_common *Common @@ -1437,6 +1578,7 @@ cholmod_factor *cholmod_l_alloc_factor (size_t, int, cholmod_common *) ; int cholmod_free_factor ( + // input/output: cholmod_factor **L, // handle of sparse factorization to free cholmod_common *Common ) ; @@ -1448,7 +1590,9 @@ int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ; int cholmod_reallocate_factor ( + // input: size_t nznew, // new max # of nonzeros the factor matrix can hold + // input/output: cholmod_factor *L, // factor to reallocate cholmod_common *Common ) ; @@ -1460,11 +1604,14 @@ int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ; int cholmod_change_factor ( - int to_xtype, // CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX + // input: + int to_xtype, // CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX; + // L->dtype remains unchanged. int to_ll, // if true: convert to LL'; else to LDL' int to_super, // if true: convert to supernodal; else to simplicial int to_packed, // if true: pack simplicial columns' else: do not pack int to_monotonic, // if true, put simplicial columns in order + // input/output: cholmod_factor *L, // factor to change. cholmod_common *Common ) ; @@ -1479,6 +1626,7 @@ int cholmod_l_change_factor (int, int, int, int, int, cholmod_factor *, int cholmod_pack_factor ( + // input/output: cholmod_factor *L, // factor to pack cholmod_common *Common ) ; @@ -1490,8 +1638,10 @@ int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ; int cholmod_reallocate_column ( + // input: size_t j, // reallocate L(:,j) size_t need, // space in L(:,j) for this # of entries + // input/output: cholmod_factor *L, // L factor modified, L(:,j) resized cholmod_common *Common ) ; @@ -1504,6 +1654,7 @@ int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *, cholmod_sparse *cholmod_factor_to_sparse // return a new sparse matrix ( + // input/output: cholmod_factor *L, // input: factor to convert; output: L is converted // to a simplicial symbolic factor cholmod_common *Common @@ -1517,6 +1668,7 @@ cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *, cholmod_factor *cholmod_copy_factor // return a copy of the factor ( + // input: cholmod_factor *L, // factor to copy (not modified) cholmod_common *Common ) ; @@ -1528,7 +1680,9 @@ cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ; int cholmod_factor_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_factor *L, // factor to change cholmod_common *Common ) ; @@ -1557,6 +1711,7 @@ typedef struct cholmod_dense_struct cholmod_dense *cholmod_allocate_dense ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension @@ -1574,6 +1729,7 @@ cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int, cholmod_dense *cholmod_zeros ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1589,6 +1745,7 @@ cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ; cholmod_dense *cholmod_ones ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1604,6 +1761,7 @@ cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ; cholmod_dense *cholmod_eye // return a dense identity matrix ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -1619,6 +1777,7 @@ cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ; int cholmod_free_dense ( + // input/output: cholmod_dense **X, // handle of dense matrix to free cholmod_common *Common ) ; @@ -1630,7 +1789,9 @@ int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ; cholmod_dense *cholmod_ensure_dense ( + // input/output: cholmod_dense **X, // matrix to resize as needed (*X may be NULL) + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension @@ -1648,6 +1809,7 @@ cholmod_dense *cholmod_l_ensure_dense (cholmod_dense **, size_t, size_t, cholmod_dense *cholmod_sparse_to_dense // return a dense matrix ( + // input: cholmod_sparse *A, // input matrix cholmod_common *Common ) ; @@ -1659,6 +1821,7 @@ cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *, cholmod_common *) ; int64_t cholmod_dense_nnz // return # of entries in the dense matrix ( + // input: cholmod_dense *X, // input matrix cholmod_common *Common ) ; @@ -1670,8 +1833,10 @@ int64_t cholmod_l_dense_nnz (cholmod_dense *, cholmod_common *) ; cholmod_sparse *cholmod_dense_to_sparse // return a sparse matrix C ( + // input: cholmod_dense *X, // input matrix - int values, // if true, copy the values; if false, C is pattern + int mode, // 1: copy the values + // 0: C is pattern cholmod_common *Common ) ; cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, @@ -1683,6 +1848,7 @@ cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, cholmod_dense *cholmod_copy_dense // returns new dense matrix ( + // input: cholmod_dense *X, // input dense matrix cholmod_common *Common ) ; @@ -1694,7 +1860,9 @@ cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ; int cholmod_copy_dense2 ( + // input: cholmod_dense *X, // input dense matrix + // input/output: cholmod_dense *Y, // output dense matrix (already allocated on input) cholmod_common *Common ) ; @@ -1706,7 +1874,9 @@ int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ; int cholmod_dense_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_dense *X, // dense matrix to change cholmod_common *Common ) ; @@ -1760,6 +1930,7 @@ typedef struct cholmod_triplet_struct cholmod_triplet *cholmod_allocate_triplet // return triplet matrix T ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -1778,6 +1949,7 @@ cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int, int cholmod_free_triplet ( + // input/output: cholmod_triplet **T, // handle of triplet matrix to free cholmod_common *Common ) ; @@ -1789,7 +1961,9 @@ int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ; int cholmod_reallocate_triplet ( + // input: size_t nznew, // new max # of nonzeros the triplet matrix can hold + // input/output: cholmod_triplet *T, // triplet matrix to reallocate cholmod_common *Common ) ; @@ -1801,6 +1975,7 @@ int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ; cholmod_triplet *cholmod_sparse_to_triplet ( + // input: cholmod_sparse *A, // matrix to copy into triplet form T cholmod_common *Common ) ; @@ -1813,6 +1988,7 @@ cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *, cholmod_sparse *cholmod_triplet_to_sparse // return sparse matrix A ( + // input: cholmod_triplet *T, // input triplet matrix size_t nzmax, // allocate space for max(nzmax,nnz(A)) entries cholmod_common *Common @@ -1826,6 +2002,7 @@ cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t, cholmod_triplet *cholmod_copy_triplet // return new triplet matrix ( + // input: cholmod_triplet *T, // triplet matrix to copy cholmod_common *Common ) ; @@ -1837,15 +2014,17 @@ cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ; int cholmod_triplet_xtype ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_triplet *T, // triplet matrix to change cholmod_common *Common ) ; int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; -//============================================================================== -// memory allocation -//============================================================================== +//------------------------------------------------------------------------------ +// memory allocation: malloc/calloc/realloc/free +//------------------------------------------------------------------------------ // These methods act like malloc/calloc/realloc/free, with some differences. // They are simple wrappers around the memory management functions in @@ -1858,6 +2037,7 @@ int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; void *cholmod_malloc // return pointer to newly allocated memory ( + // input: size_t n, // number of items size_t size, // size of each item cholmod_common *Common @@ -1866,6 +2046,7 @@ void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ; void *cholmod_calloc // return pointer to newly allocated memory ( + // input: size_t n, // number of items size_t size, // size of each item cholmod_common *Common @@ -1874,8 +2055,10 @@ void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ; void *cholmod_free // returns NULL to simplify its usage ( + // input: size_t n, // number of items size_t size, // size of each item + // input/output: void *p, // memory to free cholmod_common *Common ) ; @@ -1883,8 +2066,10 @@ void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ; void *cholmod_realloc // return newly reallocated block of memory ( + // input: size_t nnew, // # of items in newly reallocate memory size_t size, // size of each item + // input/output: void *p, // pointer to memory to reallocate (may be NULL) size_t *n, // # of items in p on input; nnew on output if success cholmod_common *Common @@ -1893,6 +2078,7 @@ void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ; int cholmod_realloc_multiple // returns true if successful, false otherwise ( + // input: size_t nnew, // # of items in newly reallocate memory int nint, // 0: do not allocate I_block or J_block, 1: just I_block, // 2: both I_block and J_block @@ -1911,9 +2097,9 @@ int cholmod_realloc_multiple // returns true if successful, false otherwise int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, void **, size_t *, cholmod_common *) ; -//============================================================================== +//------------------------------------------------------------------------------ // numerical comparisons -//============================================================================== +//------------------------------------------------------------------------------ // These macros were different on Windows for older versions of CHOLMOD. // They are no longer needed but are kept for backward compatibility. @@ -1933,411 +2119,427 @@ int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, #ifndef NCHECK -/* Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds - * of integer vectors (subset, perm, and parent), and read in matrices from a - * file: - * - * cholmod_check_common check/print the Common object - * cholmod_print_common - * - * cholmod_check_sparse check/print a sparse matrix in column-oriented form - * cholmod_print_sparse - * - * cholmod_check_dense check/print a dense matrix - * cholmod_print_dense - * - * cholmod_check_factor check/print a Cholesky factorization - * cholmod_print_factor - * - * cholmod_check_triplet check/print a sparse matrix in triplet form - * cholmod_print_triplet - * - * cholmod_check_subset check/print a subset (integer vector in given range) - * cholmod_print_subset - * - * cholmod_check_perm check/print a permutation (an integer vector) - * cholmod_print_perm - * - * cholmod_check_parent check/print an elimination tree (an integer vector) - * cholmod_print_parent - * - * cholmod_read_triplet read a matrix in triplet form (any Matrix Market - * "coordinate" format, or a generic triplet format). - * - * cholmod_read_sparse read a matrix in sparse form (same file format as - * cholmod_read_triplet). - * - * cholmod_read_dense read a dense matrix (any Matrix Market "array" - * format, or a generic dense format). - * - * cholmod_write_sparse write a sparse matrix to a Matrix Market file. - * - * cholmod_write_dense write a dense matrix to a Matrix Market file. - * - * cholmod_print_common and cholmod_check_common are the only two routines that - * you may call after calling cholmod_finish. - * - * Requires the Utility module. Not required by any CHOLMOD module, except when - * debugging is enabled (in which case all modules require the Check module). - * - * See cholmod_read.c for a description of the file formats supported by the - * cholmod_read_* routines. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_check_common: check the Common object */ -/* -------------------------------------------------------------------------- */ +// Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds +// of integer vectors (subset, perm, and parent), and read in matrices from a +// file: +// +// cholmod_check_common check/print the Common object +// cholmod_print_common +// +// cholmod_check_sparse check/print a sparse matrix in column-oriented form +// cholmod_print_sparse +// +// cholmod_check_dense check/print a dense matrix +// cholmod_print_dense +// +// cholmod_check_factor check/print a Cholesky factorization +// cholmod_print_factor +// +// cholmod_check_triplet check/print a sparse matrix in triplet form +// cholmod_print_triplet +// +// cholmod_check_subset check/print a subset (integer vector in given range) +// cholmod_print_subset +// +// cholmod_check_perm check/print a permutation (an integer vector) +// cholmod_print_perm +// +// cholmod_check_parent check/print an elimination tree (an integer vector) +// cholmod_print_parent +// +// cholmod_read_triplet read a matrix in triplet form (any Matrix Market +// "coordinate" format, or a generic triplet format). +// +// cholmod_read_sparse read a matrix in sparse form (same file format as +// cholmod_read_triplet). +// +// cholmod_read_dense read a dense matrix (any Matrix Market "array" +// format, or a generic dense format). +// +// cholmod_write_sparse write a sparse matrix to a Matrix Market file. +// +// cholmod_write_dense write a dense matrix to a Matrix Market file. +// +// cholmod_print_common and cholmod_check_common are the only two routines that +// you may call after calling cholmod_finish. +// +// Requires the Utility module. Not required by any CHOLMOD module, except when +// debugging is enabled (in which case all modules require the Check module). +// +// See cholmod_read.c for a description of the file formats supported by the +// cholmod_read_* routines. + +//------------------------------------------------------------------------------ +// cholmod_check_common: check the Common object +//------------------------------------------------------------------------------ int cholmod_check_common ( cholmod_common *Common ) ; - int cholmod_l_check_common (cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_common: print the Common object */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_common: print the Common object +//------------------------------------------------------------------------------ int cholmod_print_common ( - /* ---- input ---- */ - const char *name, /* printed name of Common object */ - /* --------------- */ + // input: + const char *name, // printed name of Common object cholmod_common *Common ) ; int cholmod_l_print_common (const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_gpu_stats: print the GPU / CPU statistics */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_gpu_stats: print the GPU / CPU statistics +//------------------------------------------------------------------------------ int cholmod_gpu_stats (cholmod_common *) ; int cholmod_l_gpu_stats (cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_sparse: check a sparse matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_sparse: check a sparse matrix +//------------------------------------------------------------------------------ int cholmod_check_sparse ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to check */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to check cholmod_common *Common ) ; - int cholmod_l_check_sparse (cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_sparse */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_sparse +//------------------------------------------------------------------------------ int cholmod_print_sparse ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to print */ - const char *name, /* printed name of sparse matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to print + const char *name, // printed name of sparse matrix cholmod_common *Common ) ; - int cholmod_l_print_sparse (cholmod_sparse *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_dense: check a dense matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_dense: check a dense matrix +//------------------------------------------------------------------------------ int cholmod_check_dense ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to check */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to check cholmod_common *Common ) ; - int cholmod_l_check_dense (cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_dense: print a dense matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_dense: print a dense matrix +//------------------------------------------------------------------------------ int cholmod_print_dense ( - /* ---- input ---- */ - cholmod_dense *X, /* dense matrix to print */ - const char *name, /* printed name of dense matrix */ - /* --------------- */ + // input: + cholmod_dense *X, // dense matrix to print + const char *name, // printed name of dense matrix cholmod_common *Common ) ; - int cholmod_l_print_dense (cholmod_dense *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_factor: check a factor */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_factor: check a factor +//------------------------------------------------------------------------------ int cholmod_check_factor ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to check */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to check cholmod_common *Common ) ; - int cholmod_l_check_factor (cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_factor: print a factor */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_factor: print a factor +//------------------------------------------------------------------------------ int cholmod_print_factor ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to print */ - const char *name, /* printed name of factor */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to print + const char *name, // printed name of factor cholmod_common *Common ) ; - int cholmod_l_print_factor (cholmod_factor *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_triplet: check a sparse matrix in triplet form */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_triplet: check a sparse matrix in triplet form +//------------------------------------------------------------------------------ int cholmod_check_triplet ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to check */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to check cholmod_common *Common ) ; - int cholmod_l_check_triplet (cholmod_triplet *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_triplet: print a triplet matrix */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_triplet: print a triplet matrix +//------------------------------------------------------------------------------ int cholmod_print_triplet ( - /* ---- input ---- */ - cholmod_triplet *T, /* triplet matrix to print */ - const char *name, /* printed name of triplet matrix */ - /* --------------- */ + // input: + cholmod_triplet *T, // triplet matrix to print + const char *name, // printed name of triplet matrix cholmod_common *Common ) ; - int cholmod_l_print_triplet (cholmod_triplet *, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_subset: check a subset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_subset: check a subset +//------------------------------------------------------------------------------ int cholmod_check_subset ( - /* ---- input ---- */ - int32_t *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + int32_t *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array) + size_t n, // 0:n-1 is valid range cholmod_common *Common ) ; +int cholmod_l_check_subset (int64_t *, int64_t, size_t, cholmod_common *) ; -int cholmod_l_check_subset (int64_t *, int64_t, size_t, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_print_subset: print a subset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_subset: print a subset +//------------------------------------------------------------------------------ int cholmod_print_subset ( - /* ---- input ---- */ - int32_t *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ - int64_t len, /* size of Set (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Set */ - /* --------------- */ + // input: + int32_t *Set, // Set [0:len-1] is a subset of 0:n-1. Duplicates OK + int64_t len, // size of Set (an integer array) + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Set cholmod_common *Common ) ; +int cholmod_l_print_subset (int64_t *, int64_t, size_t, const char *, + cholmod_common *) ; -int cholmod_l_print_subset (int64_t *, int64_t, size_t, - const char *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_check_perm: check a permutation */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_perm: check a permutation +//------------------------------------------------------------------------------ int cholmod_check_perm ( - /* ---- input ---- */ - int32_t *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - /* --------------- */ + // input: + int32_t *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range cholmod_common *Common ) ; +int cholmod_l_check_perm (int64_t *, size_t, size_t, cholmod_common *) ; -int cholmod_l_check_perm (int64_t *, size_t, size_t, cholmod_common *); - -/* -------------------------------------------------------------------------- */ -/* cholmod_print_perm: print a permutation vector */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_perm: print a permutation vector +//------------------------------------------------------------------------------ int cholmod_print_perm ( - /* ---- input ---- */ - int32_t *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ - size_t len, /* size of Perm (an integer array) */ - size_t n, /* 0:n-1 is valid range */ - const char *name, /* printed name of Perm */ - /* --------------- */ + // input: + int32_t *Perm, // Perm [0:len-1] is a permutation of subset of 0:n-1 + size_t len, // size of Perm (an integer array) + size_t n, // 0:n-1 is valid range + const char *name, // printed name of Perm cholmod_common *Common ) ; - int cholmod_l_print_perm (int64_t *, size_t, size_t, const char *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_check_parent: check an elimination tree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_check_parent: check an elimination tree +//------------------------------------------------------------------------------ int cholmod_check_parent ( - /* ---- input ---- */ - int32_t *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - /* --------------- */ + // input: + int32_t *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent cholmod_common *Common ) ; - int cholmod_l_check_parent (int64_t *, size_t, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_print_parent */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_print_parent +//------------------------------------------------------------------------------ int cholmod_print_parent ( - /* ---- input ---- */ - int32_t *Parent, /* Parent [0:n-1] is an elimination tree */ - size_t n, /* size of Parent */ - const char *name, /* printed name of Parent */ - /* --------------- */ + // input: + int32_t *Parent, // Parent [0:n-1] is an elimination tree + size_t n, // size of Parent + const char *name, // printed name of Parent cholmod_common *Common ) ; +int cholmod_l_print_parent (int64_t *, size_t, const char *, cholmod_common *) ; -int cholmod_l_print_parent (int64_t *, size_t, const char *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_read_sparse: read a sparse matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_sparse: read a sparse matrix from a file (double only) +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_read_sparse +cholmod_sparse *cholmod_read_sparse // return sparse matrix (double) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_read_sparse (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_triplet: read a triplet matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_sparse2: read a sparse matrix from a file (float or double) +//------------------------------------------------------------------------------ -cholmod_triplet *cholmod_read_triplet +cholmod_sparse *cholmod_read_sparse2 // return sparse matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_sparse *cholmod_l_read_sparse2 (FILE *, int, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_read_triplet: read a triplet matrix from a file (double only) +//------------------------------------------------------------------------------ + +cholmod_triplet *cholmod_read_triplet // return triplet matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) ; cholmod_triplet *cholmod_l_read_triplet (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_dense: read a dense matrix from a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_triplet: read a triplet matrix from a file (float or double) +//------------------------------------------------------------------------------ -cholmod_dense *cholmod_read_dense +cholmod_triplet *cholmod_read_triplet2 // return triplet matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_triplet *cholmod_l_read_triplet2 (FILE *, int, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_read_dense: read a dense matrix from a file (double only) +//------------------------------------------------------------------------------ + +cholmod_dense *cholmod_read_dense // return dense matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + cholmod_common *Common +) ; cholmod_dense *cholmod_l_read_dense (FILE *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_read_matrix: read a sparse or dense matrix from a file */ -/* -------------------------------------------------------------------------- */ - -void *cholmod_read_matrix -( - /* ---- input ---- */ - FILE *f, /* file to read from, must already be open */ - int prefer, /* If 0, a sparse matrix is always return as a - * cholmod_triplet form. It can have any stype - * (symmetric-lower, unsymmetric, or - * symmetric-upper). - * If 1, a sparse matrix is returned as an unsymmetric - * cholmod_sparse form (A->stype == 0), with both - * upper and lower triangular parts present. - * This is what the MATLAB mread mexFunction does, - * since MATLAB does not have an stype. - * If 2, a sparse matrix is returned with an stype of 0 - * or 1 (unsymmetric, or symmetric with upper part - * stored). - * This argument has no effect for dense matrices. - */ - /* ---- output---- */ - int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */ - /* --------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_dense2: read a dense matrix from a file (float or double) +//------------------------------------------------------------------------------ + +cholmod_dense *cholmod_read_dense2 // return dense matrix (double/single) +( + // input: + FILE *f, // file to read from, must already be open + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE cholmod_common *Common ) ; +cholmod_dense *cholmod_l_read_dense2 (FILE *, int, cholmod_common *) ; + +//------------------------------------------------------------------------------ +// cholmod_read_matrix: read a sparse or dense matrix from a file (double only) +//------------------------------------------------------------------------------ +void *cholmod_read_matrix // return sparse/triplet/double matrix (double) +( + // input: + FILE *f, // file to read from, must already be open + int prefer, // If 0, a sparse matrix is always return as a + // cholmod_triplet form. It can have any stype + // (symmetric-lower, unsymmetric, or symmetric-upper). + // If 1, a sparse matrix is returned as an unsymmetric + // cholmod_sparse form (A->stype == 0), with both upper and + // lower triangular parts present. This is what the MATLAB + // mread mexFunction does, since MATLAB does not have an + // stype. + // If 2, a sparse matrix is returned with an stype of 0 or + // 1 (unsymmetric, or symmetric with upper part stored). + // This argument has no effect for dense matrices. + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE + cholmod_common *Common +) ; void *cholmod_l_read_matrix (FILE *, int, int *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_write_sparse: write a sparse matrix to a file */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_read_matrix2: read a sparse or dense matrix (float or double) +//------------------------------------------------------------------------------ -int cholmod_write_sparse // returns the same result as cholmod_symmetry +void *cholmod_read_matrix2 // sparse/triplet/double matrix (double/single) ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_sparse *A, /* matrix to print */ - cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to read from, must already be open + int prefer, // see cholmod_read_matrix + int dtype, // CHOLMOD_DOUBLE or CHOLMOD_SINGLE + // output: + int *mtype, // CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE cholmod_common *Common ) ; +void *cholmod_l_read_matrix2 (FILE *, int, int, int *, cholmod_common *) ; -int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *, - const char *c, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_write_sparse: write a sparse matrix to a file +//------------------------------------------------------------------------------ -/* -------------------------------------------------------------------------- */ -/* cholmod_write_dense: write a dense matrix to a file */ -/* -------------------------------------------------------------------------- */ +// return values of cholmod_symmetry and cholmod_write: +#define CHOLMOD_MM_RECTANGULAR 1 +#define CHOLMOD_MM_UNSYMMETRIC 2 +#define CHOLMOD_MM_SYMMETRIC 3 +#define CHOLMOD_MM_HERMITIAN 4 +#define CHOLMOD_MM_SKEW_SYMMETRIC 5 +#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 +#define CHOLMOD_MM_HERMITIAN_POSDIAG 7 -int cholmod_write_dense +int cholmod_write_sparse // see above, or -1 on error ( - /* ---- input ---- */ - FILE *f, /* file to write to, must already be open */ - cholmod_dense *X, /* matrix to print */ - const char *comments, /* optional filename of comments to include */ - /* --------------- */ + // input: + FILE *f, // file to write to, must already be open + cholmod_sparse *A, // matrix to print + cholmod_sparse *Z, // optional matrix with pattern of explicit zeros + const char *comments, // optional filename of comments to include cholmod_common *Common ) ; +int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *, + const char *c, cholmod_common *) ; + +//------------------------------------------------------------------------------ +// cholmod_write_dense: write a dense matrix to a file +//------------------------------------------------------------------------------ +int cholmod_write_dense // CHOLMOD_MM_UNSYMMETRIC or _RECTANGULAR, or +( // -1 on error + // input: + FILE *f, // file to write to, must already be open + cholmod_dense *X, // matrix to print + const char *comments, // optional filename of comments to include + cholmod_common *Common +) ; int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *, cholmod_common *) ; @@ -2349,562 +2551,517 @@ int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *, #ifndef NCHOLESKY -/* Sparse Cholesky routines: analysis, factorization, and solve. - * - * The primary routines are all that a user requires to order, analyze, and - * factorize a sparse symmetric positive definite matrix A (or A*A'), and - * to solve Ax=b (or A*A'x=b). The primary routines rely on the secondary - * routines, the CHOLMOD Utility module, and the AMD and COLAMD packages. They - * make optional use of the CHOLMOD Supernodal and Partition modules, the - * METIS package, and the CCOLAMD package. - * - * Primary routines: - * ----------------- - * - * cholmod_analyze order and analyze (simplicial or supernodal) - * cholmod_factorize simplicial or supernodal Cholesky factorization - * cholmod_solve solve a linear system (simplicial or supernodal) - * cholmod_solve2 like cholmod_solve, but reuse workspace - * cholmod_spsolve solve a linear system (sparse x and b) - * - * Secondary routines: - * ------------------ - * - * cholmod_analyze_p analyze, with user-provided permutation or f set - * cholmod_factorize_p factorize, with user-provided permutation or f - * cholmod_analyze_ordering analyze a fill-reducing ordering - * cholmod_etree find the elimination tree - * cholmod_rowcolcounts compute the row/column counts of L - * cholmod_amd order using AMD - * cholmod_colamd order using COLAMD - * cholmod_rowfac incremental simplicial factorization - * cholmod_rowfac_mask rowfac, specific to LPDASA - * cholmod_rowfac_mask2 rowfac, specific to LPDASA - * cholmod_row_subtree find the nonzero pattern of a row of L - * cholmod_resymbol recompute the symbolic pattern of L - * cholmod_resymbol_noperm recompute the symbolic pattern of L, no L->Perm - * cholmod_postorder postorder a tree - * - * Requires the Utility module, and two packages: AMD and COLAMD. - * Optionally uses the Supernodal and Partition modules. - * Required by the Partition module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze: order and analyze (simplicial or supernodal) */ -/* -------------------------------------------------------------------------- */ - -/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor - * that can later be passed to cholmod_factorize. */ - -cholmod_factor *cholmod_analyze // order and analyze -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - /* --------------- */ +// Sparse Cholesky routines: analysis, factorization, and solve. +// +// The primary routines are all that a user requires to order, analyze, and +// factorize a sparse symmetric positive definite matrix A (or A*A'), and +// to solve Ax=b (or A*A'x=b). The primary routines rely on the secondary +// routines, the CHOLMOD Utility module, and the AMD and COLAMD packages. They +// make optional use of the CHOLMOD Supernodal and Partition modules, the +// METIS package, and the CCOLAMD package. +// +// Primary routines: +// ----------------- +// +// cholmod_analyze order and analyze (simplicial or supernodal) +// cholmod_factorize simplicial or supernodal Cholesky factorization +// cholmod_solve solve a linear system (simplicial or supernodal) +// cholmod_solve2 like cholmod_solve, but reuse workspace +// cholmod_spsolve solve a linear system (sparse x and b) +// +// Secondary routines: +// ------------------ +// +// cholmod_analyze_p analyze, with user-provided permutation or f set +// cholmod_factorize_p factorize, with user-provided permutation or f +// cholmod_analyze_ordering analyze a fill-reducing ordering +// cholmod_etree find the elimination tree +// cholmod_rowcolcounts compute the row/column counts of L +// cholmod_amd order using AMD +// cholmod_colamd order using COLAMD +// cholmod_rowfac incremental simplicial factorization +// cholmod_rowfac_mask rowfac, specific to LPDASA +// cholmod_rowfac_mask2 rowfac, specific to LPDASA +// cholmod_row_subtree find the nonzero pattern of a row of L +// cholmod_resymbol recompute the symbolic pattern of L +// cholmod_resymbol_noperm recompute the symbolic pattern of L, no L->Perm +// cholmod_postorder postorder a tree +// +// Requires the Utility module, and two packages: AMD and COLAMD. +// Optionally uses the Supernodal and Partition modules. +// Required by the Partition module. + +//------------------------------------------------------------------------------ +// cholmod_analyze: order and analyze (simplicial or supernodal) +//------------------------------------------------------------------------------ + +// Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor +// that can later be passed to cholmod_factorize. + +cholmod_factor *cholmod_analyze // returns symbolic factor L +( + // input: + cholmod_sparse *A, // matrix to order and analyze cholmod_common *Common ) ; - cholmod_factor *cholmod_l_analyze (cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_p: analyze, with user-provided permutation or f set */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_analyze_p: analyze, with user-provided permutation or f set +//------------------------------------------------------------------------------ -/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a - * symbolic factor that can later be passed to cholmod_factorize, where - * F = A(:,fset) if fset is not NULL and A->stype is zero. - * UserPerm is tried if non-NULL. */ +// Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a +// symbolic factor that can later be passed to cholmod_factorize, where +// F = A(:,fset) if fset is not NULL and A->stype is zero. +// UserPerm is tried if non-NULL. -cholmod_factor *cholmod_analyze_p +cholmod_factor *cholmod_analyze_p // returns symbolic factor L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order and analyze */ - int32_t *UserPerm, /* user-provided permutation, size A->nrow */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order and analyze + int32_t *UserPerm, // user-provided permutation, size A->nrow + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) ; +cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, int64_t *, int64_t *, + size_t, cholmod_common *) ; -cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, int64_t *, - int64_t *, size_t, cholmod_common *) ; +//------------------------------------------------------------------------------ +// cholmod_analyze_p2: analyze for sparse Cholesky or sparse QR +//------------------------------------------------------------------------------ -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_p2: analyze for sparse Cholesky or sparse QR */ -/* -------------------------------------------------------------------------- */ +// This is normally not need by the user application. cholmod_factor *cholmod_analyze_p2 ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to order and analyze */ - int32_t *UserPerm, /* user-provided permutation, size A->nrow */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to order and analyze + int32_t *UserPerm, // user-provided permutation, size A->nrow + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset cholmod_common *Common ) ; - cholmod_factor *cholmod_l_analyze_p2 (int, cholmod_sparse *, int64_t *, int64_t *, size_t, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_factorize: simplicial or supernodal Cholesky factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_factorize: simplicial or supernodal Cholesky factorization +//------------------------------------------------------------------------------ -/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained - * from cholmod_analyze. The analysis can be re-used simply by calling this - * routine a second time with another matrix. A must have the same nonzero - * pattern as that passed to cholmod_analyze. */ +// Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained +// from cholmod_analyze. The analysis can be re-used simply by calling this +// routine a second time with another matrix. A must have the same nonzero +// pattern as that passed to cholmod_analyze. int cholmod_factorize // simplicial or superodal Cholesky factorization ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) ; - int cholmod_l_factorize (cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_factorize_p: factorize, with user-provided permutation or fset */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_factorize_p: factorize, with user-provided permutation or fset +//------------------------------------------------------------------------------ -/* Same as cholmod_factorize, but with more options. */ +// Same as cholmod_factorize, but with more options. int cholmod_factorize_p ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- in/out --- */ - cholmod_factor *L, /* resulting factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + double beta [2], // factorize beta*I+A or beta*I+A'*A + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // input/output: + cholmod_factor *L, // resulting factorization cholmod_common *Common ) ; +int cholmod_l_factorize_p (cholmod_sparse *, double *, int64_t *, size_t, + cholmod_factor *, cholmod_common *) ; -int cholmod_l_factorize_p (cholmod_sparse *, double *, int64_t *, - size_t, cholmod_factor *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_solve: solve a linear system (simplicial or supernodal) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_solve: solve a linear system (simplicial or supernodal) +//------------------------------------------------------------------------------ -/* Solves one of many linear systems with a dense right-hand-side, using the - * factorization from cholmod_factorize (or as modified by any other CHOLMOD - * routine). D is identity for LL' factorizations. */ +// Solves one of many linear systems with a dense right-hand-side, using the +// factorization from cholmod_factorize (or as modified by any other CHOLMOD +// routine). D is identity for LL' factorizations. -#define CHOLMOD_A 0 /* solve Ax=b */ -#define CHOLMOD_LDLt 1 /* solve LDL'x=b */ -#define CHOLMOD_LD 2 /* solve LDx=b */ -#define CHOLMOD_DLt 3 /* solve DL'x=b */ -#define CHOLMOD_L 4 /* solve Lx=b */ -#define CHOLMOD_Lt 5 /* solve L'x=b */ -#define CHOLMOD_D 6 /* solve Dx=b */ -#define CHOLMOD_P 7 /* permute x=Px */ -#define CHOLMOD_Pt 8 /* permute x=P'x */ +#define CHOLMOD_A 0 /* solve Ax=b */ +#define CHOLMOD_LDLt 1 /* solve LDL'x=b */ +#define CHOLMOD_LD 2 /* solve LDx=b */ +#define CHOLMOD_DLt 3 /* solve DL'x=b */ +#define CHOLMOD_L 4 /* solve Lx=b */ +#define CHOLMOD_Lt 5 /* solve L'x=b */ +#define CHOLMOD_D 6 /* solve Dx=b */ +#define CHOLMOD_P 7 /* permute x=Px */ +#define CHOLMOD_Pt 8 /* permute x=P'x */ -cholmod_dense *cholmod_solve /* returns the solution X */ +cholmod_dense *cholmod_solve // returns the solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_common *Common ) ; - cholmod_dense *cholmod_l_solve (int, cholmod_factor *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_solve2: like cholmod_solve, but with reusable workspace */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_solve2: like cholmod_solve, but with reusable workspace +//------------------------------------------------------------------------------ -int cholmod_solve2 /* returns TRUE on success, FALSE on failure */ +int cholmod_solve2 // returns TRUE on success, FALSE on failure ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_dense *B, /* right-hand-side */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_dense *B, // right-hand-side cholmod_sparse *Bset, - /* ---- output --- */ - cholmod_dense **X_Handle, /* solution, allocated if need be */ + // output: + cholmod_dense **X_Handle, // solution, allocated if need be cholmod_sparse **Xset_Handle, - /* ---- workspace */ - cholmod_dense **Y_Handle, /* workspace, or NULL */ - cholmod_dense **E_Handle, /* workspace, or NULL */ - /* --------------- */ + // workspace: + cholmod_dense **Y_Handle, // workspace, or NULL + cholmod_dense **E_Handle, // workspace, or NULL cholmod_common *Common ) ; - int cholmod_l_solve2 (int, cholmod_factor *, cholmod_dense *, cholmod_sparse *, cholmod_dense **, cholmod_sparse **, cholmod_dense **, cholmod_dense **, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_spsolve: solve a linear system with a sparse right-hand-side */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_spsolve: solve a linear system with a sparse right-hand-side +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_spsolve +cholmod_sparse *cholmod_spsolve // returns the sparse solution X ( - /* ---- input ---- */ - int sys, /* system to solve */ - cholmod_factor *L, /* factorization to use */ - cholmod_sparse *B, /* right-hand-side */ - /* --------------- */ + // input: + int sys, // system to solve + cholmod_factor *L, // factorization to use + cholmod_sparse *B, // right-hand-side cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_spsolve (int, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_etree: find the elimination tree of A or A'*A */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_etree: find the elimination tree of A or A'*A +//------------------------------------------------------------------------------ int cholmod_etree ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - /* ---- output --- */ - int32_t *Parent, /* size ncol. Parent [j] = p if p is the parent of j */ - /* --------------- */ + // output: + int32_t *Parent, // size ncol. Parent [j] = p if p is the parent of j cholmod_common *Common ) ; - int cholmod_l_etree (cholmod_sparse *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowcolcounts: compute the row/column counts of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowcolcounts: compute the row/column counts of L +//------------------------------------------------------------------------------ int cholmod_rowcolcounts ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int32_t *Parent, /* size nrow. Parent [i] = p if p is the parent of i */ - int32_t *Post, /* size nrow. Post [k] = i if i is the kth node in - * the postordered etree. */ - /* ---- output --- */ - int32_t *RowCount, /* size nrow. RowCount [i] = # entries in the ith row of - * L, including the diagonal. */ - int32_t *ColCount, /* size nrow. ColCount [i] = # entries in the ith - * column of L, including the diagonal. */ - int32_t *First, /* size nrow. First [i] = k is the least postordering - * of any descendant of i. */ - int32_t *Level, /* size nrow. Level [i] is the length of the path from - * i to the root, with Level [root] = 0. */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_rowcolcounts (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, int64_t *, - int64_t *, int64_t *, int64_t *, - cholmod_common *) ; + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Parent, // size nrow. Parent [i] = p if p is the parent of i + int32_t *Post, // size nrow. Post [k] = i if i is the kth node in + // the postordered etree. + // output: + int32_t *RowCount, // size nrow. RowCount [i] = # entries in the ith + // row of L, including the diagonal. + int32_t *ColCount, // size nrow. ColCount [i] = # entries in the ith + // column of L, including the diagonal. + int32_t *First, // size nrow. First [i] = k is the least + // postordering of any descendant of i. + int32_t *Level, // size nrow. Level [i] is the length of the path + // from i to the root, with Level [root] = 0. + cholmod_common *Common +) ; +int cholmod_l_rowcolcounts (cholmod_sparse *, int64_t *, size_t, int64_t *, + int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_analyze_ordering: analyze a fill-reducing ordering */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_analyze_ordering: analyze a fill-reducing ordering +//------------------------------------------------------------------------------ int cholmod_analyze_ordering ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int ordering, /* ordering method used */ - int32_t *Perm, /* size n, fill-reducing permutation to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Parent, /* size n, elimination tree */ - int32_t *Post, /* size n, postordering of elimination tree */ - int32_t *ColCount, /* size n, nnz in each column of L */ - /* ---- workspace */ - int32_t *First, /* size nworkspace for cholmod_postorder */ - int32_t *Level, /* size n workspace for cholmod_postorder */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_analyze_ordering (cholmod_sparse *, int, int64_t *, - int64_t *, size_t, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, + // input: + cholmod_sparse *A, // matrix to analyze + int ordering, // ordering method used + int32_t *Perm, // size n, fill-reducing permutation to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Parent, // size n, elimination tree + int32_t *Post, // size n, postordering of elimination tree + int32_t *ColCount, // size n, nnz in each column of L + // workspace: + int32_t *First, // size n workspace for cholmod_postorder + int32_t *Level, // size n workspace for cholmod_postorder + cholmod_common *Common +) ; +int cholmod_l_analyze_ordering (cholmod_sparse *, int, int64_t *, int64_t *, + size_t, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_amd: order using AMD */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_amd: order using AMD +//------------------------------------------------------------------------------ -/* Finds a permutation P to reduce fill-in in the factorization of P*A*P' - * or P*A*A'P' */ +// Finds a permutation P to reduce fill-in in the factorization of P*A*P' +// or P*A*A'P' int cholmod_amd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_amd (cholmod_sparse *, int64_t *, size_t, int64_t *, + cholmod_common *) ; -int cholmod_l_amd (cholmod_sparse *, int64_t *, size_t, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_colamd: order using COLAMD */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_colamd: order using COLAMD +//------------------------------------------------------------------------------ -/* Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'. - * Orders F*F' where F = A (:,fset) if fset is not NULL */ +// Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'. +// Orders F*F' where F = A (:,fset) if fset is not NULL int cholmod_colamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with a coletree postorder */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with a coletree postorder + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_colamd (cholmod_sparse *, int64_t *, size_t, int, int64_t *, + cholmod_common *) ; -int cholmod_l_colamd (cholmod_sparse *, int64_t *, size_t, int, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowfac: incremental simplicial factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowfac: incremental simplicial factorization +//------------------------------------------------------------------------------ -/* Partial or complete simplicial factorization. Rows and columns kstart:kend-1 - * of L and D must be initially equal to rows/columns kstart:kend-1 of the - * identity matrix. Row k can only be factorized if all descendants of node - * k in the elimination tree have been factorized. */ +// Partial or complete simplicial factorization. Rows and columns kstart:kend-1 +// of L and D must be initially equal to rows/columns kstart:kend-1 of the +// identity matrix. Row k can only be factorized if all descendants of node +// k in the elimination tree have been factorized. -int cholmod_rowfac +int cholmod_rowfac ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - int cholmod_l_rowfac (cholmod_sparse *, cholmod_sparse *, double *, size_t, size_t, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowfac_mask: incremental simplicial factorization */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowfac_mask: incremental simplicial factorization +//------------------------------------------------------------------------------ -/* cholmod_rowfac_mask is a version of cholmod_rowfac that is specific to - * LPDASA. It is unlikely to be needed by any other application. */ +// cholmod_rowfac_mask and cholmod_rowfac_mask2 are version of cholmod_rowfac +// that are specific to LPDASA. It is unlikely to be needed by any other +// application, and is not documented in the CHOLMOD User Guide. int cholmod_rowfac_mask ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - int32_t *mask, /* if mask[i] >= 0, then set row i to zero */ - int32_t *RLinkUp, /* link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + int32_t *mask, // size A->nrow. if mask[i] >= 0 row i is set to zero + int32_t *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - -int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, size_t, - size_t, int64_t *, int64_t *, cholmod_factor *, - cholmod_common *) ; +int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, + size_t, size_t, int64_t *, int64_t *, cholmod_factor *, cholmod_common *) ; int cholmod_rowfac_mask2 ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - double beta [2], /* factorize beta*I+A or beta*I+A'*A */ - size_t kstart, /* first row to factorize */ - size_t kend, /* last row to factorize is kend-1 */ - int32_t *mask, /* if mask[i] >= maskmark, then set row i to zero */ - int32_t maskmark, - int32_t *RLinkUp, /* link list of rows to compute */ - /* ---- in/out --- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + double beta [2], // factorize beta*I+A or beta*I+AA' + size_t kstart, // first row to factorize + size_t kend, // last row to factorize is kend-1 + int32_t *mask, // size A->nrow. if mask[i] >= maskmark row i is set + // to zero + int32_t maskmark, // for mask [i] test + int32_t *RLinkUp, // size A->nrow. link list of rows to compute + // input/output: cholmod_factor *L, - /* --------------- */ cholmod_common *Common ) ; - int cholmod_l_rowfac_mask2 (cholmod_sparse *, cholmod_sparse *, double *, - size_t, size_t, int64_t *, int64_t, int64_t *, - cholmod_factor *, cholmod_common *) ; + size_t, size_t, int64_t *, int64_t, int64_t *, cholmod_factor *, + cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_row_subtree: find the nonzero pattern of a row of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_row_subtree: find the nonzero pattern of a row of L +//------------------------------------------------------------------------------ -/* Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1) - * and b = kth column of A or A*A' (rows 0 to k-1 only) */ +// Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1) +// and b = kth column of A or A*A' (rows 0 to k-1 only) int cholmod_row_subtree ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ - size_t k, /* row k of L */ - int32_t *Parent, /* elimination tree */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), n-by-1 with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // used for A*A' case only. F=A' or A(:,f)' + size_t krow, // row k of L + int32_t *Parent, // elimination tree + // output: + cholmod_sparse *R, // pattern of L(k,:), 1-by-n with R->nzmax >= n cholmod_common *Common ) ; - int cholmod_l_row_subtree (cholmod_sparse *, cholmod_sparse *, size_t, int64_t *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_lsolve_pattern: find the nonzero pattern of x=L\b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_lsolve_pattern: find the nonzero pattern of y=L\b +//------------------------------------------------------------------------------ int cholmod_lsolve_pattern ( - /* ---- input ---- */ - cholmod_sparse *B, /* sparse right-hand-side (a single sparse column) */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *X, /* pattern of X=L\B, n-by-1 with X->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *B, // sparse right-hand-side (a single sparse column) + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *Yset, // pattern of Y=L\B, n-by-1 with Y->nzmax >= n cholmod_common *Common ) ; - int cholmod_l_lsolve_pattern (cholmod_sparse *, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_row_lsubtree: find the nonzero pattern of a row of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_row_lsubtree: find the nonzero pattern of a row of L +//------------------------------------------------------------------------------ -/* Identical to cholmod_row_subtree, except that it finds the elimination tree - * from L itself. */ +// Identical to cholmod_row_subtree, except that it finds the elimination tree +// from L itself. int cholmod_row_lsubtree ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required - * for the symmetric case. Need not be sorted. */ - size_t k, /* row k of L */ - cholmod_factor *L, /* the factor L from which parent(i) is derived */ - /* ---- output --- */ - cholmod_sparse *R, /* pattern of L(k,:), n-by-1 with R->nzmax >= n */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *Fi, // nonzero pattern of kth row of A', not required + // for the symmetric case. Need not be sorted. + size_t fnz, // size of Fi + size_t krow, // row k of L + cholmod_factor *L, // the factor L from which parent(i) is derived + // output: + cholmod_sparse *R, // pattern of L(k,:), n-by-1 with R->nzmax >= n cholmod_common *Common ) ; +int cholmod_l_row_lsubtree (cholmod_sparse *, int64_t *, size_t, size_t, + cholmod_factor *, cholmod_sparse *, cholmod_common *) ; -int cholmod_l_row_lsubtree (cholmod_sparse *, int64_t *, size_t, - size_t, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_resymbol: recompute the symbolic pattern of L */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_resymbol: recompute the symbolic pattern of L +//------------------------------------------------------------------------------ -/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', - * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). - * - * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it - * first permutes A according to L->Perm. A can be upper/lower/unsymmetric, - * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */ +// Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', +// or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). +// +// cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it +// first permutes A according to L->Perm. A can be upper/lower/unsymmetric, +// in contrast to cholmod_resymbol_noperm (which can be lower or unsym). int cholmod_resymbol // recompute symbolic pattern of L ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) ; - int cholmod_l_resymbol (cholmod_sparse *, int64_t *, size_t, int, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_resymbol_noperm: recompute the symbolic pattern of L, no L->Perm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_resymbol_noperm: recompute the symbolic pattern of L, no L->Perm +//------------------------------------------------------------------------------ -/* Remove entries from L that are not in the factorization of A, A*A', - * or F*F' (depending on A->stype and whether fset is NULL or not). */ +// Remove entries from L that are not in the factorization of A, A*A', +// or F*F' (depending on A->stype and whether fset is NULL or not). int cholmod_resymbol_noperm ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int pack, /* if TRUE, pack the columns of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization, entries pruned on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int pack, // if TRUE, pack the columns of L + // input/output: + cholmod_factor *L, // factorization, entries pruned on output cholmod_common *Common ) ; - int cholmod_l_resymbol_noperm (cholmod_sparse *, int64_t *, size_t, int, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rcond: compute rough estimate of reciprocal of condition number */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rcond: compute rough estimate of reciprocal of condition number +//------------------------------------------------------------------------------ -double cholmod_rcond /* return min(diag(L)) / max(diag(L)) */ +double cholmod_rcond // return rcond estimate ( - /* ---- input ---- */ - cholmod_factor *L, - /* --------------- */ + // input: + cholmod_factor *L, // factorization to query; not modified cholmod_common *Common ) ; - double cholmod_l_rcond (cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_postorder: Compute the postorder of a tree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_postorder: Compute the postorder of a tree +//------------------------------------------------------------------------------ -int32_t cholmod_postorder /* return # of nodes postordered */ +int32_t cholmod_postorder // return # of nodes postordered ( - /* ---- input ---- */ - int32_t *Parent, /* size n. Parent [j] = p if p is the parent of j */ + // input: + int32_t *Parent, // size n. Parent [j] = p if p is the parent of j size_t n, - int32_t *Weight_p, /* size n, optional. Weight [j] is weight of node j */ - /* ---- output --- */ - int32_t *Post, /* size n. Post [k] = j is kth in postordered tree */ - /* --------------- */ + int32_t *Weight, // size n, optional. Weight [j] is weight of node j + // output: + int32_t *Post, // size n. Post [k] = j is kth in postordered tree cholmod_common *Common ) ; - int64_t cholmod_l_postorder (int64_t *, size_t, int64_t *, int64_t *, cholmod_common *) ; @@ -2916,217 +3073,227 @@ int64_t cholmod_l_postorder (int64_t *, size_t, int64_t *, int64_t *, #ifndef NMATRIXOPS -/* Basic operations on sparse and dense matrices. - * - * cholmod_drop A = entries in A with abs. value >= tol - * cholmod_norm_dense s = norm (X), 1-norm, inf-norm, or 2-norm - * cholmod_norm_sparse s = norm (A), 1-norm or inf-norm - * cholmod_horzcat C = [A,B] - * cholmod_scale A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) - * cholmod_sdmult Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y - * cholmod_ssmult C = A*B - * cholmod_submatrix C = A (i,j), where i and j are arbitrary vectors - * cholmod_vertcat C = [A ; B] - * - * A, B, C: sparse matrices (cholmod_sparse) - * X, Y: dense matrices (cholmod_dense) - * s: scalar or vector - * - * Requires the Utility module. Not required by any other CHOLMOD module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_drop: drop entries with small absolute value */ -/* -------------------------------------------------------------------------- */ +// Basic operations on sparse and dense matrices. +// +// cholmod_drop A = entries in A with abs. value >= tol +// cholmod_norm_dense s = norm (X), 1-norm, inf-norm, or 2-norm +// cholmod_norm_sparse s = norm (A), 1-norm or inf-norm +// cholmod_horzcat C = [A,B] +// cholmod_scale A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) +// cholmod_sdmult Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y +// cholmod_ssmult C = A*B +// cholmod_submatrix C = A (i,j), where i and j are arbitrary vectors +// cholmod_vertcat C = [A ; B] +// +// A, B, C: sparse matrices (cholmod_sparse) +// X, Y: dense matrices (cholmod_dense) +// s: scalar or vector +// +// Requires the Utility module. Not required by any other CHOLMOD module. + +//------------------------------------------------------------------------------ +// cholmod_drop: drop entries with small absolute value +//------------------------------------------------------------------------------ int cholmod_drop ( - /* ---- input ---- */ - double tol, /* keep entries with absolute value > tol */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to drop entries from */ - /* --------------- */ + // input: + double tol, // keep entries with absolute value > tol + // input/output: + cholmod_sparse *A, // matrix to drop entries from cholmod_common *Common ) ; - int cholmod_l_drop (double, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_norm_dense: s = norm (X), 1-norm, inf-norm, or 2-norm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_norm_dense: s = norm (X), 1-norm, inf-norm, or 2-norm +//------------------------------------------------------------------------------ -double cholmod_norm_dense +double cholmod_norm_dense // returns norm (X) ( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */ - /* --------------- */ + // input: + cholmod_dense *X, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm cholmod_common *Common ) ; - double cholmod_l_norm_dense (cholmod_dense *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_norm_sparse: s = norm (A), 1-norm or inf-norm */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_norm_sparse: s = norm (A), 1-norm or inf-norm +//------------------------------------------------------------------------------ -double cholmod_norm_sparse +double cholmod_norm_sparse // returns norm (A) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm cholmod_common *Common ) ; - double cholmod_l_norm_sparse (cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_horzcat: C = [A,B] */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_horzcat: C = [A,B] +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_horzcat +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_horzcat // returns C = [A B] ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to concatenate + cholmod_sparse *B, // right matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_horzcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_scale: A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_scale: A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) +//------------------------------------------------------------------------------ -/* scaling modes, selected by the scale input parameter: */ -#define CHOLMOD_SCALAR 0 /* A = s*A */ -#define CHOLMOD_ROW 1 /* A = diag(s)*A */ -#define CHOLMOD_COL 2 /* A = A*diag(s) */ -#define CHOLMOD_SYM 3 /* A = diag(s)*A*diag(s) */ +// scaling modes, selected by the scale input parameter: +#define CHOLMOD_SCALAR 0 /* A = s*A */ +#define CHOLMOD_ROW 1 /* A = diag(s)*A */ +#define CHOLMOD_COL 2 /* A = A*diag(s) */ +#define CHOLMOD_SYM 3 /* A = diag(s)*A*diag(s) */ int cholmod_scale ( - /* ---- input ---- */ - cholmod_dense *S, /* scale factors (scalar or vector) */ - int scale, /* type of scaling to compute */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to scale */ - /* --------------- */ + // input: + cholmod_dense *S, // scale factors (scalar or vector) + int scale, // type of scaling to compute + // input/output: + cholmod_sparse *A, // matrix to scale cholmod_common *Common ) ; - int cholmod_l_scale (cholmod_dense *, int, cholmod_sparse *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_sdmult: Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_sdmult: Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y +//------------------------------------------------------------------------------ -/* Sparse matrix times dense matrix */ +// Sparse matrix times dense matrix int cholmod_sdmult ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to multiply */ - int transpose, /* use A if 0, or A' otherwise */ - double alpha [2], /* scale factor for A */ - double beta [2], /* scale factor for Y */ - cholmod_dense *X, /* dense matrix to multiply */ - /* ---- in/out --- */ - cholmod_dense *Y, /* resulting dense matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to multiply + int transpose, // use A if 0, otherwise use A' + double alpha [2], // scale factor for A + double beta [2], // scale factor for Y + cholmod_dense *X, // dense matrix to multiply + // input/output: + cholmod_dense *Y, // resulting dense matrix cholmod_common *Common ) ; - int cholmod_l_sdmult (cholmod_sparse *, int, double *, double *, cholmod_dense *, cholmod_dense *Y, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_ssmult: C = A*B */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_ssmult: C = A*B +//------------------------------------------------------------------------------ -/* Sparse matrix times sparse matrix */ +// Sparse matrix times sparse matrix. -cholmod_sparse *cholmod_ssmult +// If A and/or B are symmetric, they are converted first to unsymmetric, and +// the conversion is governed by the mode input parameter. + +cholmod_sparse *cholmod_ssmult // return C=A*B ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to multiply */ - cholmod_sparse *B, /* right matrix to multiply */ - int stype, /* requested stype of C */ - int values, /* TRUE: do numerical values, FALSE: pattern only */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to multiply + cholmod_sparse *B, // right matrix to multiply + int stype, // requested stype of C + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_ssmult (cholmod_sparse *, cholmod_sparse *, int, int, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_submatrix: C = A (r,c), where i and j are arbitrary vectors */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_submatrix: C = A (r,c), where i and j are arbitrary vectors +//------------------------------------------------------------------------------ -/* rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1. - * In this case, r can be NULL. An rsize of zero, or r = NULL and rsize >= 0, - * denotes "[ ]" in MATLAB notation (the empty set). - * Similar rules hold for csize. - */ +// rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1. +// In this case, r can be NULL. An rsize of zero, or r = NULL and rsize >= 0, +// denotes "[ ]" in MATLAB notation (the empty set). +// Similar rules hold for csize. -cholmod_sparse *cholmod_submatrix +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_submatrix // return C = A (rset,cset) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to subreference */ - int32_t *rset, /* set of row indices, duplicates OK */ - int64_t rsize, /* size of r; rsize < 0 denotes ":" */ - int32_t *cset, /* set of column indices, duplicates OK */ - int64_t csize, /* size of c; csize < 0 denotes ":" */ - int values, /* if TRUE compute the numerical values of C */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to subreference + int32_t *rset, // set of row indices, duplicates OK + int64_t rsize, // size of rset, or -1 for ":" + int32_t *cset, // set of column indices, duplicates OK + int64_t csize, // size of cset, or -1 for ":" + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_submatrix (cholmod_sparse *, int64_t *, int64_t, int64_t *, int64_t, int, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_vertcat: C = [A ; B] */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_vertcat: C = [A ; B] +//------------------------------------------------------------------------------ -cholmod_sparse *cholmod_vertcat +// C is returned as an unsymmetric matrix with C->stype of zero. If A and/or +// B are symmetric, they are converted first to unsymmetric, and the conversion +// is governed by the mode input parameter. + +cholmod_sparse *cholmod_vertcat // returns C = [A ; B] ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // top matrix to concatenate + cholmod_sparse *B, // bottom matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric + // 0: pattern cholmod_common *Common ) ; - cholmod_sparse *cholmod_l_vertcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_symmetry: determine if a sparse matrix is symmetric */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_symmetry: determine if a sparse matrix is symmetric +//------------------------------------------------------------------------------ -int cholmod_symmetry +// return values of cholmod_symmetry and cholmod_write: +// #define CHOLMOD_MM_RECTANGULAR 1 +// #define CHOLMOD_MM_UNSYMMETRIC 2 +// #define CHOLMOD_MM_SYMMETRIC 3 +// #define CHOLMOD_MM_HERMITIAN 4 +// #define CHOLMOD_MM_SKEW_SYMMETRIC 5 +// #define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 +// #define CHOLMOD_MM_HERMITIAN_POSDIAG 7 + +int cholmod_symmetry // returns the matrix symmetry (see above) ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - int option, - /* ---- output ---- */ - int32_t *xmatched, - int32_t *pmatched, - int32_t *nzoffdiag, - int32_t *nzdiag, - /* --------------- */ + int option, // option 0, 1, or 2 + // output: + int32_t *xmatched, // # of matched numerical entries + int32_t *pmatched, // # of matched entries in pattern + int32_t *nzoffdiag, // # of off diagonal entries + int32_t *nzdiag, // # of diagonal entries cholmod_common *Common ) ; - int cholmod_l_symmetry (cholmod_sparse *, int, int64_t *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; @@ -3138,316 +3305,289 @@ int cholmod_l_symmetry (cholmod_sparse *, int, int64_t *, int64_t *, int64_t *, #ifndef NMODIFY -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_modify.h. - * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager - * http://www.suitesparse.com - * -------------------------------------------------------------------------- */ - -/* Sparse Cholesky modification routines: update / downdate / rowadd / rowdel. - * Can also modify a corresponding solution to Lx=b when L is modified. This - * module is most useful when applied on a Cholesky factorization computed by - * the Cholesky module, but it does not actually require the Cholesky module. - * The Utility module can create an identity Cholesky factorization (LDL' where - * L=D=I) that can then by modified by these routines. - * - * Primary routines: - * ----------------- - * - * cholmod_updown multiple rank update/downdate - * cholmod_rowadd add a row to an LDL' factorization - * cholmod_rowdel delete a row from an LDL' factorization - * - * Secondary routines: - * ------------------- - * - * cholmod_updown_solve update/downdate, and modify solution to Lx=b - * cholmod_updown_mark update/downdate, and modify solution to partial Lx=b - * cholmod_updown_mask update/downdate for LPDASA - * cholmod_updown_mask2 update/downdate for LPDASA - * cholmod_rowadd_solve add a row, and update solution to Lx=b - * cholmod_rowadd_mark add a row, and update solution to partial Lx=b - * cholmod_rowdel_solve delete a row, and downdate Lx=b - * cholmod_rowdel_mark delete a row, and downdate solution to partial Lx=b - * - * Requires the Utility module. Not required by any other CHOLMOD module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_updown: multiple rank update/downdate */ -/* -------------------------------------------------------------------------- */ - -/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' - * (a downdate). The factor object L need not be an LDL' factorization; it - * is converted to one if it isn't. */ +//------------------------------------------------------------------------------ +// CHOLMOD:Modify Module. Copyright (C) 2005-2023, Timothy A. Davis and William +// W. Hager. http://www.suitesparse.com +//------------------------------------------------------------------------------ + +// Sparse Cholesky modification routines: update / downdate / rowadd / rowdel. +// Can also modify a corresponding solution to Lx=b when L is modified. This +// module is most useful when applied on a Cholesky factorization computed by +// the Cholesky module, but it does not actually require the Cholesky module. +// The Utility module can create an identity Cholesky factorization (LDL' where +// L=D=I) that can then by modified by these routines. +// +// Primary routines: +// ----------------- +// +// cholmod_updown multiple rank update/downdate +// cholmod_rowadd add a row to an LDL' factorization +// cholmod_rowdel delete a row from an LDL' factorization +// +// Secondary routines: +// ------------------- +// +// cholmod_updown_solve update/downdate, and modify solution to Lx=b +// cholmod_updown_mark update/downdate, and modify solution to partial Lx=b +// cholmod_updown_mask update/downdate for LPDASA +// cholmod_updown_mask2 update/downdate for LPDASA +// cholmod_rowadd_solve add a row, and update solution to Lx=b +// cholmod_rowadd_mark add a row, and update solution to partial Lx=b +// cholmod_rowdel_solve delete a row, and downdate Lx=b +// cholmod_rowdel_mark delete a row, and downdate solution to partial Lx=b +// +// Requires the Utility module. Not required by any other CHOLMOD module. + +//------------------------------------------------------------------------------ +// cholmod_updown: multiple rank update/downdate +//------------------------------------------------------------------------------ + +// Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' +// (a downdate). The factor object L need not be an LDL' factorization; it +// is converted to one if it isn't. int cholmod_updown // update/downdate ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; -int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; - +int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *, + cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_solve: update/downdate, and modify solution to Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_solve: update/downdate, and modify solution to Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown, except that it also updates/downdates the - * solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not - * need as input to this routine, but a sparse change to b is (DeltaB). Only - * entries in DeltaB corresponding to columns modified in L are accessed; the - * rest must be zero. */ +// Does the same as cholmod_updown, except that it also updates/downdates the +// solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not +// need as input to this routine, but a sparse change to b is (DeltaB). Only +// entries in DeltaB corresponding to columns modified in L are accessed; the +// rest must be zero. int cholmod_updown_solve ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_updown_solve (int, cholmod_sparse *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_mark: update/downdate, and modify solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_mark: update/downdate, and modify solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. See cholmod_updown.c for - * a description of colmark. */ +// Does the same as cholmod_updown_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. See cholmod_updown.c for +// a description of colmark. int cholmod_updown_mark ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_updown_mark (int, cholmod_sparse *, int64_t *, cholmod_factor *, + cholmod_dense *, cholmod_dense *, cholmod_common *) ; -int cholmod_l_updown_mark (int, cholmod_sparse *, int64_t *, - cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_updown_mask: update/downdate, for LPDASA */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_updown_mask: update/downdate, for LPDASA +//------------------------------------------------------------------------------ -/* Does the same as cholmod_updown_mark, except has an additional "mask" - * argument. This routine is an "expert" routine. It is meant for use in - * LPDASA only. See cholmod_updown.c for a description of mask. */ +// Does the same as cholmod_updown_mark, except has an additional "mask" +// argument. This routine is an "expert" routine. It is meant for use in +// LPDASA only. See cholmod_updown.c for a description of mask. int cholmod_updown_mask ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - int32_t *mask, /* size n */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + int32_t *mask, // size n + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - -int cholmod_l_updown_mask (int, cholmod_sparse *, int64_t *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; +int cholmod_l_updown_mask (int, cholmod_sparse *, int64_t *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; int cholmod_updown_mask2 ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - int32_t *mask, /* size n */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + int32_t *colmark, // array of size n. See cholmod_updown.c for details + int32_t *mask, // size n int32_t maskmark, - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_updown_mask2 (int, cholmod_sparse *, int64_t *, int64_t *, + int64_t, cholmod_factor *, cholmod_dense *, cholmod_dense *, + cholmod_common *) ; -int cholmod_l_updown_mask2 (int, cholmod_sparse *, int64_t *, - int64_t *, int64_t, cholmod_factor *, cholmod_dense *, - cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd: add a row to an LDL' factorization (a rank-2 update) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd: add a row to an LDL' factorization (a rank-2 update) +//------------------------------------------------------------------------------ -/* cholmod_rowadd adds a row to the LDL' factorization. It computes the kth - * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) - * accordingly. The kth row and column of L must originally be equal to the - * kth row and column of the identity matrix. The kth row/column of L is - * computed as the factorization of the kth row/column of the matrix to - * factorize, which is provided as a single n-by-1 sparse matrix R. */ +// cholmod_rowadd adds a row to the LDL' factorization. It computes the kth +// row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) +// accordingly. The kth row and column of L must originally be equal to the +// kth row and column of the identity matrix. The kth row/column of L is +// computed as the factorization of the kth row/column of the matrix to +// factorize, which is provided as a single n-by-1 sparse matrix R. int cholmod_rowadd // add a row to an LDL' factorization ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; - int cholmod_l_rowadd (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd_solve: add a row, and update solution to Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd_solve: add a row, and update solution to Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b - * See cholmod_updown for a description of how Lx=b is updated. There is on - * additional parameter: bk specifies the new kth entry of b. */ +// Does the same as cholmod_rowadd, and also updates the solution to Lx=b +// See cholmod_updown for a description of how Lx=b is updated. There is on +// additional parameter: bk specifies the new kth entry of b. int cholmod_rowadd_solve ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right-hand-side b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right-hand-side b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_rowadd_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowadd_mark: add a row, and update solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowadd_mark: add a row, and update solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowadd_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. */ +// Does the same as cholmod_rowadd_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. int cholmod_rowadd_mark ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right hand side, b */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right hand side, b + int32_t *colmark, // int32_t array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; +int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel: delete a row from an LDL' factorization (a rank-2 update) */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel: delete a row from an LDL' factorization (a rank-2 update) +//------------------------------------------------------------------------------ -/* Sets the kth row and column of L to be the kth row and column of the identity - * matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, - * the caller can optionally provide the nonzero pattern (or an upper bound) of - * kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want - * CHOLMOD to determine this itself, which is easier for the caller, but takes - * a little more time. - */ +// Sets the kth row and column of L to be the kth row and column of the identity +// matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, +// the caller can optionally provide the nonzero pattern (or an upper bound) of +// kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want +// CHOLMOD to determine this itself, which is easier for the caller, but takes +// a little more time. int cholmod_rowdel // delete a rw from an LDL' factorization ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) ; - int cholmod_l_rowdel (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel_solve: delete a row, and downdate Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel_solve: delete a row, and downdate Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. - * When row/column k of A is "deleted" from the system A*y=b, this can induce - * a change to x, in addition to changes arising when L and b are modified. - * If this is the case, the kth entry of y is required as input (yk) */ +// Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. +// When row/column k of A is "deleted" from the system A*y=b, this can induce +// a change to x, in addition to changes arising when L and b are modified. +// If this is the case, the kth entry of y is required as input (yk). int cholmod_rowdel_solve ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - int cholmod_l_rowdel_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_rowdel_mark: delete a row, and downdate solution to partial Lx=b */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_rowdel_mark: delete a row, and downdate solution to partial Lx=b +//------------------------------------------------------------------------------ -/* Does the same as cholmod_rowdel_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. */ +// Does the same as cholmod_rowdel_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. int cholmod_rowdel_mark ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - int32_t *colmark, /* array of size n. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + int32_t *colmark, // int32_t array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) ; - -int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, - int64_t *, cholmod_factor *, cholmod_dense *, cholmod_dense *, - cholmod_common *) ; +int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, int64_t *, + cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; #endif @@ -3455,254 +3595,217 @@ int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, // CHOLMOD:Partition Module (CAMD, CCOLAMD, and CSYMAMD) //============================================================================== +//------------------------------------------------------------------------------ +// CHOLMOD/Partition: +// Copyright (C) 2005-2023, Univ. of Florida. Author: Timothy A. Davis +//------------------------------------------------------------------------------ + +// CHOLMOD Partition module, interface to CAMD, CCOLAMD, CSYMAMD, and METIS, +// and graph partitioning and graph-partition-based orderings. Includes an +// interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering +// methods which order a matrix following constraints determined via nested +// dissection. +// +// These functions do not require METIS. They are installed unless NCAMD +// is defined: +// cholmod_ccolamd interface to CCOLAMD ordering +// cholmod_csymamd interface to CSYMAMD ordering +// cholmod_camd interface to CAMD ordering +// +// These functions require METIS: +// cholmod_nested_dissection CHOLMOD nested dissection ordering +// cholmod_metis METIS nested dissection ordering (METIS_NodeND) +// cholmod_bisect graph partitioner (currently based on METIS) +// cholmod_metis_bisector direct interface to METIS_ComputeVertexSeparator +// +// Requires the Utility and Cholesky modules, and three packages: METIS, CAMD, +// and CCOLAMD. Optionally used by the Cholesky module. + #ifndef NCAMD -/* CHOLMOD Partition module, interface to CAMD, CCOLAMD, and CSYMAMD - * - * An interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering - * methods which order a matrix following constraints determined via nested - * dissection. - * - * These functions do not require METIS. They are installed unless NCAMD - * is defined: - * cholmod_ccolamd interface to CCOLAMD ordering - * cholmod_csymamd interface to CSYMAMD ordering - * cholmod_camd interface to CAMD ordering - * - * Requires the Utility and Cholesky modules, and two packages: CAMD, - * and CCOLAMD. Used by functions in the Partition Module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_ccolamd */ -/* -------------------------------------------------------------------------- */ - -/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */ +//------------------------------------------------------------------------------ +// cholmod_ccolamd +//------------------------------------------------------------------------------ + +// Order AA' or A(:,f)*A(:,f)' using CCOLAMD. int cholmod_ccolamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int32_t *Cmember, /* size A->nrow. Cmember [i] = c if row i is in the - * constraint set c. c must be >= 0. The # of - * constraint sets is max (Cmember) + 1. If Cmember is - * NULL, then it is interpretted as Cmember [i] = 0 for - * all i */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Cmember, // size A->nrow. Cmember [i] = c if row i is in the + // constraint set c. c must be >= 0. The # of + // constraint sets is max (Cmember) + 1. If Cmember is + // NULL, then it is interpretted as Cmember [i] = 0 for + // all i. + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_ccolamd (cholmod_sparse *, int64_t *, size_t, int64_t *, + int64_t *, cholmod_common *) ; -int cholmod_l_ccolamd (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_csymamd */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_csymamd +//------------------------------------------------------------------------------ -/* Order A using CSYMAMD. */ +// Order A using CSYMAMD. int cholmod_csymamd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - /* ---- output --- */ - int32_t *Cmember, /* size nrow. see cholmod_ccolamd above */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + // output: + int32_t *Cmember, // size nrow. see cholmod_ccolamd.c for description + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; +int cholmod_l_csymamd (cholmod_sparse *, int64_t *, int64_t *, + cholmod_common *) ; -int cholmod_l_csymamd (cholmod_sparse *, int64_t *, - int64_t *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_camd */ -/* -------------------------------------------------------------------------- */ - -/* Order A using CAMD. */ +//------------------------------------------------------------------------------ +// cholmod_camd: order A using CAMD +//------------------------------------------------------------------------------ int cholmod_camd ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Cmember, /* size nrow. see cholmod_ccolamd above */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int32_t *Cmember, // size nrow. see cholmod_ccolamd.c for description. + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; - -int cholmod_l_camd (cholmod_sparse *, int64_t *, size_t, - int64_t *, int64_t *, cholmod_common *) ; +int cholmod_l_camd (cholmod_sparse *, int64_t *, size_t, int64_t *, int64_t *, + cholmod_common *) ; #endif -//============================================================================== +//------------------------------------------------------------------------------ // CHOLMOD:Partition Module (graph partition methods) -//============================================================================== +//------------------------------------------------------------------------------ // These routines still exist if CHOLMOD is compiled with -DNPARTITION, // but they return Common->status = CHOLMOD_NOT_INSTALLED in that case. + #if 1 -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_partition.h. - * Copyright (C) 2005-2013, Univ. of Florida. Author: Timothy A. Davis - * -------------------------------------------------------------------------- */ - -/* CHOLMOD Partition module. - * - * Graph partitioning and graph-partition-based orderings. Includes an - * interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering - * methods which order a matrix following constraints determined via nested - * dissection. - * - * These functions require METIS: - * cholmod_nested_dissection CHOLMOD nested dissection ordering - * cholmod_metis METIS nested dissection ordering (METIS_NodeND) - * cholmod_bisect graph partitioner (currently based on METIS) - * cholmod_metis_bisector direct interface to METIS_ComputeVertexSeparator - * - * Requires the Utility and Cholesky modules, and three packages: METIS, CAMD, - * and CCOLAMD. Optionally used by the Cholesky module. - * - * Note that METIS does not have a version that uses int64_t integers. If you - * try to use cholmod_nested_dissection, cholmod_metis, cholmod_bisect, or - * cholmod_metis_bisector on a matrix that is too large, an error code will be - * returned. METIS does have an "idxtype", which could be redefined as - * int64_t, if you wish to edit METIS or use compile-time flags to redefine - * idxtype. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_nested_dissection */ -/* -------------------------------------------------------------------------- */ - -/* Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method - * (METIS's node bisector applied recursively to compute the separator tree - * and constraint sets, followed by CCOLAMD using the constraints). Usually - * finds better orderings than METIS_NodeND, but takes longer. - */ - -int64_t cholmod_nested_dissection /* returns # of components */ -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - int32_t *CParent, /* size A->nrow. On output, CParent [c] is the parent - * of component c, or EMPTY if c is a root, and where - * c is in the range 0 to # of components minus 1 */ - int32_t *Cmember, /* size A->nrow. Cmember [j] = c if node j of A is - * in component c */ - /* --------------- */ +//------------------------------------------------------------------------------ +// cholmod_nested_dissection +//------------------------------------------------------------------------------ + +// Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method +// (METIS's node bisector applied recursively to compute the separator tree +// and constraint sets, followed by CCOLAMD using the constraints). Usually +// finds better orderings than METIS_NodeND, but takes longer. + +int64_t cholmod_nested_dissection // returns # of components, or -1 if error +( + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + int32_t *Perm, // size A->nrow, output permutation + int32_t *CParent, // size A->nrow. On output, CParent [c] is the parent + // of component c, or EMPTY if c is a root, and where + // c is in the range 0 to # of components minus 1 + int32_t *Cmember, // size A->nrow. Cmember [j] = c if node j of A is + // in component c cholmod_common *Common ) ; - int64_t cholmod_l_nested_dissection (cholmod_sparse *, int64_t *, size_t, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_metis */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_metis +//------------------------------------------------------------------------------ -/* Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. */ +// Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. int cholmod_metis ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with etree or coletree postorder */ - /* ---- output --- */ - int32_t *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with etree or coletree postorder + // output: + int32_t *Perm, // size A->nrow, output permutation cholmod_common *Common ) ; - int cholmod_l_metis (cholmod_sparse *, int64_t *, size_t, int, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_bisect */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_bisect +//------------------------------------------------------------------------------ -/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. */ +// Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. -int64_t cholmod_bisect /* returns # of nodes in separator */ +int64_t cholmod_bisect // returns # of nodes in separator ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - int32_t *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int compress, /* if TRUE, compress the graph first */ - /* ---- output --- */ - int32_t *Partition, /* size A->nrow. Node i is in the left graph if - * Partition [i] = 0, the right graph if 1, and in the - * separator if 2. */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + int32_t *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int compress, // if TRUE, compress the graph first + // output: + int32_t *Partition, // size A->nrow. Node i is in the left graph if + // Partition [i] = 0, the right graph if 1, and in the + // separator if 2. cholmod_common *Common ) ; - int64_t cholmod_l_bisect (cholmod_sparse *, int64_t *, size_t, int, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_metis_bisector */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_metis_bisector +//------------------------------------------------------------------------------ -/* Find a set of nodes that bisects the graph of A or AA' (direct interface - * to METIS_ComputeVertexSeperator). */ +// Find a set of nodes that bisects the graph of A or AA' (direct interface +// to METIS_ComputeVertexSeperator). -int64_t cholmod_metis_bisector /* returns separator size */ +int64_t cholmod_metis_bisector // returns separator size ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - int32_t *Anw, /* size A->nrow, node weights, can be NULL, */ - /* which means the graph is unweighted. */ - int32_t *Aew, /* size nz, edge weights (silently ignored). */ - /* This option was available with METIS 4, but not */ - /* in METIS 5. This argument is now unused, but */ - /* it remains for backward compatibilty, so as not */ - /* to change the API for cholmod_metis_bisector. */ - /* ---- output --- */ - int32_t *Partition, /* size A->nrow */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + int32_t *Anw, // size A->nrow, node weights, can be NULL, + // which means the graph is unweighted. + int32_t *Aew, // size nz, edge weights (silently ignored). + // This option was available with METIS 4, but not + // in METIS 5. This argument is now unused, but + // it remains for backward compatibilty, so as not + // to change the API for cholmod_metis_bisector. + // output: + int32_t *Partition, // size A->nrow cholmod_common *Common ) ; - int64_t cholmod_l_metis_bisector (cholmod_sparse *, int64_t *, int64_t *, int64_t *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_collapse_septree */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_collapse_septree +//------------------------------------------------------------------------------ -/* Collapse nodes in a separator tree. */ +// Collapse nodes in a separator tree. int64_t cholmod_collapse_septree ( - /* ---- input ---- */ - size_t n, /* # of nodes in the graph */ - size_t ncomponents, /* # of nodes in the separator tree (must be <= n) */ - double nd_oksep, /* collapse if #sep >= nd_oksep * #nodes in subtree */ - size_t nd_small, /* collapse if #nodes in subtree < nd_small */ - /* ---- in/out --- */ - int32_t *CParent, /* size ncomponents; from cholmod_nested_dissection */ - int32_t *Cmember, /* size n; from cholmod_nested_dissection */ - /* --------------- */ + // input: + size_t n, // # of nodes in the graph + size_t ncomponents, // # of nodes in the separator tree (must be <= n) + double nd_oksep, // collapse if #sep >= nd_oksep * #nodes in subtree + size_t nd_small, // collapse if #nodes in subtree < nd_small + // output: + int32_t *CParent, // size ncomponents; from cholmod_nested_dissection + int32_t *Cmember, // size n; from cholmod_nested_dissection cholmod_common *Common ) ; - int64_t cholmod_l_collapse_septree (size_t, size_t, double, size_t, int64_t *, int64_t *, cholmod_common *) ; @@ -3714,154 +3817,147 @@ int64_t cholmod_l_collapse_septree (size_t, size_t, double, size_t, int64_t *, #ifndef NSUPERNODAL -/* Supernodal analysis, factorization, and solve. The simplest way to use - * these routines is via the Cholesky module. It does not provide any - * fill-reducing orderings, but does accept the orderings computed by the - * Cholesky module. It does not require the Cholesky module itself, however. - * - * Primary routines: - * ----------------- - * cholmod_super_symbolic supernodal symbolic analysis - * cholmod_super_numeric supernodal numeric factorization - * cholmod_super_lsolve supernodal Lx=b solve - * cholmod_super_ltsolve supernodal L'x=b solve - * - * Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed - * below, including how they are used in CHOLMOD. - * - * BLAS routines: - * -------------- - * dtrsv solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1 - * dtrsm solve LX=B or L'X=b, L non-unit diagonal - * dgemv y=y-A*x or y=y-A'*x (x and y stride-1) - * dgemm C=A*B', C=C-A*B, or C=C-A'*B - * dsyrk C=tril(A*A') - * - * LAPACK routines: - * ---------------- - * dpotrf LAPACK: A=chol(tril(A)) - * - * Requires the Utility module, and two external packages: LAPACK and the BLAS. - * Optionally used by the Cholesky module. - */ - -/* -------------------------------------------------------------------------- */ -/* cholmod_super_symbolic */ -/* -------------------------------------------------------------------------- */ - -/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric - * factorization. The user need not call this directly; cholmod_analyze is - * a "simple" wrapper for this routine. - */ - -int cholmod_super_symbolic -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - int32_t *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ +// Supernodal analysis, factorization, and solve. The simplest way to use +// these routines is via the Cholesky module. It does not provide any +// fill-reducing orderings, but does accept the orderings computed by the +// Cholesky module. It does not require the Cholesky module itself, however. +// +// Primary routines: +// ----------------- +// cholmod_super_symbolic supernodal symbolic analysis +// cholmod_super_numeric supernodal numeric factorization +// cholmod_super_lsolve supernodal Lx=b solve +// cholmod_super_ltsolve supernodal L'x=b solve +// +// Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed +// below, including how they are used in CHOLMOD. Only the double methods are +// listed, but CHOLMOD also uses the corresponding single, single complex, and +// double complex routines. +// +// BLAS routines: +// -------------- +// dtrsv solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1 +// dtrsm solve LX=B or L'X=b, L non-unit diagonal +// dgemv y=y-A*x or y=y-A'*x (x and y stride-1) +// dgemm C=A*B', C=C-A*B, or C=C-A'*B +// dsyrk C=tril(A*A'), zherk for the double complex case +// +// LAPACK routines: +// ---------------- +// dpotrf LAPACK: A=chol(tril(A)) +// +// Requires the Utility module, and two external packages: LAPACK and the BLAS. +// Optionally used by the Cholesky module. + +//------------------------------------------------------------------------------ +// cholmod_super_symbolic +//------------------------------------------------------------------------------ + +// Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric +// factorization. The user need not call this directly; cholmod_analyze is +// a "simple" wrapper for this routine. + +int cholmod_super_symbolic +( + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + int32_t *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) ; - int cholmod_l_super_symbolic (cholmod_sparse *, cholmod_sparse *, int64_t *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_symbolic2 */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_symbolic2 +//------------------------------------------------------------------------------ -/* Analyze for supernodal Cholesky or multifrontal QR */ +// Analyze for supernodal Cholesky or multifrontal QR + +#define CHOLMOD_ANALYZE_FOR_SPQR 0 +#define CHOLMOD_ANALYZE_FOR_CHOLESKY 1 +#define CHOLMOD_ANALYZE_FOR_SPQRGPU 2 int cholmod_super_symbolic2 ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - int32_t *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + int32_t *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) ; - int cholmod_l_super_symbolic2 (int, cholmod_sparse *, cholmod_sparse *, int64_t *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_numeric */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_numeric +//------------------------------------------------------------------------------ -/* Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using - * a BLAS-based supernodal method. The user need not call this directly; - * cholmod_factorize is a "simple" wrapper for this routine. - */ +// Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using +// a BLAS-based supernodal method. The user need not call this directly; +// cholmod_factorize is a "simple" wrapper for this routine. int cholmod_super_numeric ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - double beta [2], /* beta*I is added to diagonal of matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // F = A' or A(:,f)' + double beta [2], // beta*I is added to diagonal of matrix to factorize + // input/output: + cholmod_factor *L, // factorization cholmod_common *Common ) ; - int cholmod_l_super_numeric (cholmod_sparse *, cholmod_sparse *, double *, cholmod_factor *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_lsolve */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_lsolve +//------------------------------------------------------------------------------ -/* Solve Lx=b where L is from a supernodal numeric factorization. The user - * need not call this routine directly. cholmod_solve is a "simple" wrapper - * for this routine. */ +// Solve Lx=b where L is from a supernodal numeric factorization. The user +// need not call this routine directly. cholmod_solve is a "simple" wrapper +// for this routine. int cholmod_super_lsolve ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the forward solve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to Lx=b on output */ - /* ---- workspace */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the forward solve + // input/output: + cholmod_dense *X, // b on input, solution to Lx=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) ; - int cholmod_l_super_lsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; -/* -------------------------------------------------------------------------- */ -/* cholmod_super_ltsolve */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// cholmod_super_ltsolve +//------------------------------------------------------------------------------ -/* Solve L'x=b where L is from a supernodal numeric factorization. The user - * need not call this routine directly. cholmod_solve is a "simple" wrapper - * for this routine. */ +// Solve L'x=b where L is from a supernodal numeric factorization. The user +// need not call this routine directly. cholmod_solve is a "simple" wrapper +// for this routine. int cholmod_super_ltsolve ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the backsolve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to L'x=b on output */ - /* ---- workspace */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the backsolve + // input/output: + cholmod_dense *X, // b on input, solution to L'x=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) ; - int cholmod_l_super_ltsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; @@ -3912,18 +4008,16 @@ int cholmod_l_score_comp (struct cholmod_descendant_score_t *i, #include #endif -/* CHOLMOD_GPU_PRINTF: for printing GPU debug error messages */ -/* -#define CHOLMOD_GPU_PRINTF(args) printf args -*/ +// CHOLMOD_GPU_PRINTF: for printing GPU debug error messages +// #define CHOLMOD_GPU_PRINTF(args) printf args #define CHOLMOD_GPU_PRINTF(args) -/* define supernode requirements for processing on GPU */ -#define CHOLMOD_ND_ROW_LIMIT 256 /* required descendant rows */ -#define CHOLMOD_ND_COL_LIMIT 32 /* required descendnat cols */ +// define supernode requirements for processing on GPU +#define CHOLMOD_ND_ROW_LIMIT 256 /* required descendant rows */ +#define CHOLMOD_ND_COL_LIMIT 32 /* required descendnat cols */ #define CHOLMOD_POTRF_LIMIT 512 /* required cols for POTRF & TRSM on GPU */ -/* # of host supernodes to perform before checking for free pinned buffers */ +// # of host supernodes to perform before checking for free pinned buffers #define CHOLMOD_GPU_SKIP 3 #define CHOLMOD_HANDLE_CUDA_ERROR(e,s) {if (e) {ERROR(CHOLMOD_GPU_PROBLEM,s);}} @@ -3944,14 +4038,14 @@ typedef struct cholmod_gpu_pointers } cholmod_gpu_pointers ; -int cholmod_gpu_memorysize /* GPU memory size available, 1 if no GPU */ +int cholmod_gpu_memorysize // GPU memory size available, 1 if no GPU ( size_t *total_mem, size_t *available_mem, cholmod_common *Common ) ; -int cholmod_l_gpu_memorysize /* GPU memory size available, 1 if no GPU */ +int cholmod_l_gpu_memorysize // GPU memory size available, 1 if no GPU ( size_t *total_mem, size_t *available_mem, diff --git a/CHOLMOD/Include/cholmod_internal.h b/CHOLMOD/Include/cholmod_internal.h index 04ffcbbb00..54dee6be0d 100644 --- a/CHOLMOD/Include/cholmod_internal.h +++ b/CHOLMOD/Include/cholmod_internal.h @@ -2,30 +2,29 @@ // CHOLMOD/Include/cholmod_internal.h //------------------------------------------------------------------------------ -// CHOLMOD/Include/cholmod_internal.h. Copyright (C) 2005-2022, +// CHOLMOD/Include/cholmod_internal.h. Copyright (C) 2005-2023, // Timothy A. Davis. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 //------------------------------------------------------------------------------ -/* CHOLMOD internal include file. - * - * This file contains internal definitions for CHOLMOD, not meant to be included - * in user code. They define macros that are not prefixed with CHOLMOD_. This - * file can safely #include'd in user code if you want to make use of the - * macros defined here, and don't mind the possible name conflicts with your - * code, however. - * - * Required by all CHOLMOD routines. Not required by any user routine that - * uses CHOLMOMD. Unless debugging is enabled, this file does not require any - * CHOLMOD module (not even the Utility module). - * - * If debugging is enabled, all CHOLMOD modules require the Check module. - * Enabling debugging requires that this file be editted. Debugging cannot be - * enabled with a compiler flag. This is because CHOLMOD is exceedingly slow - * when debugging is enabled. Debugging is meant for development of CHOLMOD - * itself, not by users of CHOLMOD. - */ +// CHOLMOD internal include file. +// +// This file contains internal definitions for CHOLMOD, not meant to be +// included in user code. They define macros that are not prefixed with +// CHOLMOD_. This file can safely #include'd in user code if you want to make +// use of the macros defined here, and don't mind the possible name conflicts +// with your code, however. +// +// Required by all CHOLMOD routines. Not required by any user routine that +// uses CHOLMOMD. Unless debugging is enabled, this file does not require any +// CHOLMOD module (not even the Utility module). +// +// If debugging is enabled, all CHOLMOD modules require the Check module. +// Enabling debugging requires that this file be editted. Debugging cannot be +// enabled with a compiler flag. This is because CHOLMOD is exceedingly slow +// when debugging is enabled. Debugging is meant for development of CHOLMOD +// itself, not by users of CHOLMOD. #ifndef CHOLMOD_INTERNAL_H #define CHOLMOD_INTERNAL_H @@ -33,43 +32,55 @@ #define SUITESPARSE_BLAS_DEFINITIONS #include "cholmod.h" -/* ========================================================================== */ -/* === debugging and basic includes ========================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// debugging and basic includes +//------------------------------------------------------------------------------ -/* turn off debugging */ +// turn off debugging #ifndef NDEBUG #define NDEBUG #endif -/* Uncomment this line to enable debugging. CHOLMOD will be very slow. -#undef NDEBUG - */ +// Uncomment this line to enable debugging. CHOLMOD will be very slow. +// #undef NDEBUG + +// Uncomment this line to get a summary of the time spent in the BLAS, +// for development diagnostics only: +// #define BLAS_TIMER + +// Uncomment this line to get a long dump as a text file (blas_dump.txt), that +// records each call to the BLAS, for development diagnostics only: +// #define BLAS_DUMP + +// if BLAS_DUMP is enabled, the BLAS_TIMER must also be enabled. +#if defined ( BLAS_DUMP ) && ! defined ( BLAS_TIMER ) +#define BLAS_TIMER +#endif -/* ========================================================================== */ -/* === basic definitions ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// basic definitions +//------------------------------------------------------------------------------ -/* Some non-conforming compilers insist on defining TRUE and FALSE. */ +// Some non-conforming compilers insist on defining TRUE and FALSE. #undef TRUE #undef FALSE #define TRUE 1 #define FALSE 0 -/* NULL should already be defined, but ensure it is here. */ +// NULL should already be defined, but ensure it is here. #ifndef NULL #define NULL ((void *) 0) #endif -/* FLIP is a "negation about -1", and is used to mark an integer i that is - * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY - * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i - * for all integers i. UNFLIP (i) is >= EMPTY. */ +// FLIP is a "negation about -1", and is used to mark an integer i that is +// normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY +// is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i +// for all integers i. UNFLIP (i) is >= EMPTY. #define EMPTY (-1) #define FLIP(i) (-(i)-2) #define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i)) -/* MAX and MIN are not safe to use for NaN's */ +// MAX and MIN are not safe to use for NaN's #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c))) #define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d))) @@ -81,49 +92,49 @@ (((k) < (lo)) ? (lo) : \ (((k) > (hi)) ? (hi) : (k))) -/* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise. - * Not safe for NaN's */ +// find the sign: -1 if x < 0, 1 if x > 0, zero otherwise. +// Not safe for NaN's #define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0)) -/* round up an integer x to a multiple of s */ +// round up an integer x to a multiple of s #define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s))) #define ERROR(status,msg) \ CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common) -/* Check a pointer and return if null. Set status to invalid, unless the - * status is already "out of memory" */ -#define RETURN_IF_NULL(A,result) \ -{ \ - if ((A) == NULL) \ - { \ - if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ - { \ - ERROR (CHOLMOD_INVALID, "argument missing") ; \ - } \ - return (result) ; \ - } \ +// Check a pointer and return if null. Set status to invalid, unless the +// status is already "out of memory" +#define RETURN_IF_NULL(A,result) \ +{ \ + if ((A) == NULL) \ + { \ + if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ + { \ + ERROR (CHOLMOD_INVALID, "argument missing") ; \ + } \ + return (result) ; \ + } \ } -/* Return if Common is NULL or invalid */ -#define RETURN_IF_NULL_COMMON(result) \ -{ \ - if (Common == NULL) \ - { \ - return (result) ; \ - } \ - if (Common->itype != ITYPE) \ - { \ - Common->status = CHOLMOD_INVALID ; \ - return (result) ; \ - } \ +// Return if Common is NULL or invalid +#define RETURN_IF_NULL_COMMON(result) \ +{ \ + if (Common == NULL) \ + { \ + return (result) ; \ + } \ + if (Common->itype != ITYPE) \ + { \ + Common->status = CHOLMOD_INVALID ; \ + return (result) ; \ + } \ } -/* 1e308 is a huge number that doesn't take many characters to print in a - * file, in CHOLMOD/Check/cholmod_read and _write. Numbers larger than this - * are interpretted as Inf, since sscanf doesn't read in Inf's properly. - * This assumes IEEE double precision arithmetic. DBL_MAX would be a little - * better, except that it takes too many digits to print in a file. */ +// 1e308 is a huge number that doesn't take many characters to print in a +// file, in CHOLMOD/Check/cholmod_read and _write. Numbers larger than this +// are interpretted as Inf, since sscanf doesn't read in Inf's properly. +// This assumes IEEE double precision arithmetic. DBL_MAX would be a little +// better, except that it takes too many digits to print in a file. #define HUGE_DOUBLE 1e308 //============================================================================== @@ -181,54 +192,54 @@ void cholmod_l_set_empty void cholmod_to_simplicial_sym ( - cholmod_factor *L, // sparse factorization to modify + cholmod_factor *L, // sparse factorization to modify int to_ll, // change L to hold a LL' or LDL' factorization cholmod_common *Common ) ; void cholmod_l_to_simplicial_sym ( - cholmod_factor *L, // sparse factorization to modify + cholmod_factor *L, // sparse factorization to modify int to_ll, // change L to hold a LL' or LDL' factorization cholmod_common *Common ) ; -/* ========================================================================== */ -/* === Include/cholmod_complexity.h ========================================= */ -/* ========================================================================== */ - -/* Define operations on pattern, real, complex, and zomplex objects. - * - * The xtype of an object defines it numerical type. A qttern object has no - * numerical values (A->x and A->z are NULL). A real object has no imaginary - * qrt (A->x is used, A->z is NULL). A complex object has an imaginary qrt - * that is stored interleaved with its real qrt (A->x is of size 2*nz, A->z - * is NULL). A zomplex object has both real and imaginary qrts, which are - * stored seqrately, as in MATLAB (A->x and A->z are both used). - * - * XTYPE is CHOLMOD_PATTERN, _REAL, _COMPLEX or _ZOMPLEX, and is the xtype of - * the template routine under construction. XTYPE2 is equal to XTYPE, except - * if XTYPE is CHOLMOD_PATTERN, in which case XTYPE is CHOLMOD_REAL. - * XTYPE and XTYPE2 are defined in cholmod_template.h. - */ +//------------------------------------------------------------------------------ +// operations for pattern/real/complex/zomplex +//------------------------------------------------------------------------------ + +// Define operations on pattern, real, complex, and zomplex objects. +// +// The xtype of an object defines it numerical type. A qttern object has no +// numerical values (A->x and A->z are NULL). A real object has no imaginary +// qrt (A->x is used, A->z is NULL). A complex object has an imaginary qrt +// that is stored interleaved with its real qrt (A->x is of size 2*nz, A->z +// is NULL). A zomplex object has both real and imaginary qrts, which are +// stored seqrately, as in MATLAB (A->x and A->z are both used). +// +// XTYPE is CHOLMOD_PATTERN, _REAL, _COMPLEX or _ZOMPLEX, and is the xtype of +// the template routine under construction. XTYPE2 is equal to XTYPE, except +// if XTYPE is CHOLMOD_PATTERN, in which case XTYPE is CHOLMOD_REAL. +// XTYPE and XTYPE2 are defined in cholmod_template.h. //------------------------------------------------------------------------------ // pattern: single or double //------------------------------------------------------------------------------ -#define P_TEMPLATE(name) p_ ## name -#define P_S_TEMPLATE(name) p_s_ ## name +#define P_TEMPLATE(name) p_ ## name +#define PS_TEMPLATE(name) ps_ ## name -#define P_ASSIGN2(x,z,p,ax,az,q) x [p] = 1 -#define P_PRINT(k,x,z,p) PRK(k, ("1")) +#define P_ASSIGN2(x,z,p,ax,az,q) x [p] = 1 +#define P_PRINT(k,x,z,p) PRK(k, ("1")) //------------------------------------------------------------------------------ // real: single or double //------------------------------------------------------------------------------ -#define R_TEMPLATE(name) r_ ## name -#define R_S_TEMPLATE(name) r_s_ ## name +#define RD_TEMPLATE(name) rd_ ## name +#define RS_TEMPLATE(name) rs_ ## name +#define R_ABS(x,z,p) fabs ((double) (x [p])) #define R_ASSEMBLE(x,z,p,ax,az,q) x [p] += ax [q] #define R_ASSIGN(x,z,p,ax,az,q) x [p] = ax [q] #define R_ASSIGN_CONJ(x,z,p,ax,az,q) x [p] = ax [q] @@ -259,11 +270,14 @@ void cholmod_l_to_simplicial_sym // complex: single or double //------------------------------------------------------------------------------ -#define C_TEMPLATE(name) c_ ## name -#define CT_TEMPLATE(name) ct_ ## name +#define CD_TEMPLATE(name) cd_ ## name +#define CD_T_TEMPLATE(name) cd_t_ ## name + +#define CS_TEMPLATE(name) cs_ ## name +#define CS_T_TEMPLATE(name) cs_t_ ## name -#define C_S_TEMPLATE(name) c_s_ ## name -#define CT_S_TEMPLATE(name) ct_s_ ## name +#define C_ABS(x,z,p) SuiteSparse_config_hypot ((double) (x [2*(p)]), \ + (double) (x [2*(p)+1])) #define C_ASSEMBLE(x,z,p,ax,az,q) \ x [2*(p) ] += ax [2*(q) ] ; \ @@ -302,12 +316,12 @@ void cholmod_l_to_simplicial_sym x [2*(p) ] -= ax [2*(q) ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] -= ax [2*(q)+1] * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] -/* s += conj(a)*b */ +// s += conj(a)*b #define C_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] += ax [2*(q) ] * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ;\ x [2*(p)+1] += (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] -/* s -= conj(a)*b */ +// s -= conj(a)*b #define C_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] -= ax [2*(q) ] * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ;\ x [2*(p)+1] -= (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] @@ -345,7 +359,7 @@ void cholmod_l_to_simplicial_sym x [2*(p)+1] = (float) ci ; \ } -/* s -= conj(a)*a ; note that the result of conj(a)*a is real */ +// s -= conj(a)*a ; note that the result of conj(a)*a is real #define C_LLDOT(x,p, ax,az,q) \ x [2*(p)] -= ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1] @@ -359,7 +373,7 @@ void cholmod_l_to_simplicial_sym x [2*(p) ] = ax [2*(q) ] * bx [2*(r)] ; \ x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)] -/* s -= conj(a)*a/t */ +// s -= conj(a)*a/t #define C_LDLDOT(x,p, ax,az,q, bx,r) \ x [2*(p)] -= (ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]) / bx[r] @@ -367,11 +381,14 @@ void cholmod_l_to_simplicial_sym // zomplex: single or double //------------------------------------------------------------------------------ -#define Z_TEMPLATE(name) z_ ## name -#define ZT_TEMPLATE(name) zt_ ## name +#define ZD_TEMPLATE(name) zd_ ## name +#define ZD_T_TEMPLATE(name) zd_t_ ## name + +#define ZS_TEMPLATE(name) zs_ ## name +#define ZS_T_TEMPLATE(name) zs_t_ ## name -#define Z_S_TEMPLATE(name) z_s_ ## name -#define ZT_S_TEMPLATE(name) zt_s_ ## name +#define Z_ABS(x,z,p) SuiteSparse_config_hypot ((double) (x [p]), \ + (double) (z [p])) #define Z_ASSEMBLE(x,z,p,ax,az,q) \ x [p] += ax [q] ; \ @@ -448,7 +465,7 @@ void cholmod_l_to_simplicial_sym z [p] = (float) ci ; \ } -/* s -= conj(a)*a ; note that the result of conj(a)*a is real */ +// s -= conj(a)*a ; note that the result of conj(a)*a is real #define Z_LLDOT(x,p, ax,az,q) \ x [p] -= ax [q] * ax [q] + az [q] * az [q] @@ -462,7 +479,7 @@ void cholmod_l_to_simplicial_sym x [p] = ax [q] * bx [r] ; \ z [p] = az [q] * bx [r] -/* s -= conj(a)*a/t */ +// s -= conj(a)*a/t #define Z_LDLDOT(x,p, ax,az,q, bx,r) \ x [p] -= (ax [q] * ax [q] + az [q] * az [q]) / bx[r] @@ -506,9 +523,9 @@ void cholmod_l_to_simplicial_sym { \ if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ { \ - ERROR (CHOLMOD_INVALID, "dense matrix invalid") ; \ + ERROR (CHOLMOD_INVALID, "dense matrix invalid") ; \ } \ - return (result) ; \ + return (result) ; \ } #define RETURN_IF_SPARSE_MATRIX_INVALID(A,result) \ @@ -521,7 +538,7 @@ void cholmod_l_to_simplicial_sym { \ ERROR (CHOLMOD_INVALID, "sparse matrix invalid") ; \ } \ - return (result) ; \ + return (result) ; \ } #define RETURN_IF_TRIPLET_MATRIX_INVALID(T,result) \ @@ -535,74 +552,13 @@ void cholmod_l_to_simplicial_sym { \ ERROR (CHOLMOD_INVALID, "triplet matrix invalid") ; \ } \ - return (result) ; \ + return (result) ; \ } #define RETURN_IF_FACTOR_INVALID(L,result) \ RETURN_IF_NULL (L, result) ; \ RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, result) ; -//============================================================================== -// Architecture and BLAS -//============================================================================== - -#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2) - - #define CHOLMOD_SOL2 - #define CHOLMOD_ARCHITECTURE "Sun Solaris" - -#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI) - - #define CHOLMOD_SGI - #define CHOLMOD_ARCHITECTURE "SGI Irix" - -#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86) - - #define CHOLMOD_LINUX - #define CHOLMOD_ARCHITECTURE "Linux" - -#elif defined (__APPLE__) - - #define CHOLMOD_MAC - #define CHOLMOD_ARCHITECTURE "Mac" - -#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS) - - #define CHOLMOD_AIX - #define CHOLMOD_ARCHITECTURE "IBM AIX" - -#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA) - - #define CHOLMOD_ALPHA - #define CHOLMOD_ARCHITECTURE "Compaq Alpha" - -#elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) - - #if defined (__MINGW32__) || defined (__MINGW32__) - #define CHOLMOD_MINGW - #elif defined (__CYGWIN32__) || defined (__CYGWIN32__) - #define CHOLMOD_CYGWIN - #else - #define CHOLMOD_WINDOWS - #endif - #define CHOLMOD_ARCHITECTURE "Microsoft Windows" - -#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX) - - #define CHOLMOD_HP - #define CHOLMOD_ARCHITECTURE "HP Unix" - -#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700) - - #define CHOLMOD_HP - #define CHOLMOD_ARCHITECTURE "HP 700 Unix" - -#else - - #define CHOLMOD_ARCHITECTURE "unknown" - -#endif - //============================================================================== //=== openmp support =========================================================== //============================================================================== @@ -612,7 +568,7 @@ static inline int cholmod_nthreads // returns # of OpenMP threads to use double work, // total work to do cholmod_common *Common ) -{ +{ #ifdef _OPENMP double chunk = Common->chunk ; // give each thread at least this much work int nthreads_max = Common->nthreads_max ; // max # of threads to use @@ -631,25 +587,38 @@ static inline int cholmod_nthreads // returns # of OpenMP threads to use #endif } -/* ========================================================================== */ -/* === debugging definitions ================================================ */ -/* ========================================================================== */ +//============================================================================== +//==== debugging definitions =================================================== +//============================================================================== + +#if 0 +#if 0 +#define GOTCHA ; +#else +#define GOTCHA \ +{ \ + printf ("Gotcha! %d:%s\n", __LINE__, __FILE__) ; \ + fflush (stdout) ; \ + abort ( ) ; \ +} +#endif +#endif #ifndef NDEBUG #include -/* The cholmod_dump routines are in the Check module. No CHOLMOD routine - * calls the cholmod_check_* or cholmod_print_* routines in the Check module, - * since they use Common workspace that may already be in use. Instead, they - * use the cholmod_dump_* routines defined there, which allocate their own - * workspace if they need it. */ +// The cholmod_dump routines are in the Check module. No CHOLMOD routine +// calls the cholmod_check_* or cholmod_print_* routines in the Check module, +// since they use Common workspace that may already be in use. Instead, they +// use the cholmod_dump_* routines defined there, which allocate their own +// workspace if they need it. #ifndef EXTERN #define EXTERN extern #endif -/* double, int */ +// int32_t EXTERN int cholmod_dump ; EXTERN int cholmod_dump_malloc ; int64_t cholmod_dump_sparse (cholmod_sparse *, const char *, @@ -663,15 +632,15 @@ int cholmod_dump_perm (int *, size_t, size_t, const char *, cholmod_common *) ; int cholmod_dump_parent (int *, size_t, const char *, cholmod_common *) ; void cholmod_dump_init (const char *, cholmod_common *) ; int cholmod_dump_mem (const char *, int64_t, cholmod_common *) ; -void cholmod_dump_real (const char *, double *, int64_t, +void cholmod_dump_real (const char *, void *, int, int64_t, int64_t, int, int, cholmod_common *) ; -void cholmod_dump_super (int64_t, int *, int *, int *, int *, double *, +void cholmod_dump_super (int64_t, int *, int *, int *, int *, void *, int, int, cholmod_common *) ; int cholmod_dump_partition (int64_t, int *, int *, int *, int *, int64_t, cholmod_common *) ; -int cholmod_dump_work(int, int, int64_t, cholmod_common *) ; +int cholmod_dump_work(int, int, int64_t, int, cholmod_common *) ; -/* double, int64_t */ +// int64_t EXTERN int cholmod_l_dump ; EXTERN int cholmod_l_dump_malloc ; int64_t cholmod_l_dump_sparse (cholmod_sparse *, const char *, @@ -687,18 +656,22 @@ int cholmod_l_dump_parent (int64_t *, size_t, const char *, cholmod_common *) ; void cholmod_l_dump_init (const char *, cholmod_common *) ; int cholmod_l_dump_mem (const char *, int64_t, cholmod_common *) ; -void cholmod_l_dump_real (const char *, double *, int64_t, +void cholmod_l_dump_real (const char *, void *, int, int64_t, int64_t, int, int, cholmod_common *) ; void cholmod_l_dump_super (int64_t, int64_t *, int64_t *, int64_t *, int64_t *, - double *, int, cholmod_common *) ; + void *, int, int, cholmod_common *) ; int cholmod_l_dump_partition (int64_t, int64_t *, int64_t *, int64_t *, int64_t *, int64_t, cholmod_common *) ; -int cholmod_l_dump_work(int, int, int64_t, cholmod_common *) ; +int cholmod_l_dump_work(int, int, int64_t, int, cholmod_common *) ; #define DEBUG_INIT(s,Common) { CHOLMOD(dump_init)(s, Common) ; } +#ifdef MATLAB_MEX_FILE +#define ASSERT(expression) (mxAssert ((expression), "")) +#else #define ASSERT(expression) (assert (expression)) +#endif #define PRK(k,params) \ { \ @@ -726,30 +699,16 @@ size_t CM_memtable_size (void *p) ; bool CM_memtable_find (void *p) ; void CM_memtable_remove (void *p) ; -#define PRINTM(params) \ -{ \ - if (CHOLMOD(dump_malloc) > 0) \ - { \ - printf params ; \ - } \ +#define PRINTM(params) \ +{ \ + if (CHOLMOD(dump_malloc) > 0) \ + { \ + printf params ; \ + } \ } #define DEBUG(statement) statement -#else - -/* Debugging disabled (the normal case) */ -#define PRK(k,params) -#define DEBUG_INIT(s,Common) -#define PRINT0(params) -#define PRINT1(params) -#define PRINT2(params) -#define PRINT3(params) -#define PRINTM(params) -#define ASSERT(expression) -#define DEBUG(statement) -#endif - static bool check_flag (cholmod_common *Common) { int64_t mark = Common->mark ; @@ -774,4 +733,18 @@ static bool check_flag (cholmod_common *Common) return (true) ; } +#else + +// Debugging disabled (the normal case) +#define PRK(k,params) +#define DEBUG_INIT(s,Common) +#define PRINT0(params) +#define PRINT1(params) +#define PRINT2(params) +#define PRINT3(params) +#define PRINTM(params) +#define ASSERT(expression) +#define DEBUG(statement) +#endif + #endif diff --git a/CHOLMOD/Include/cholmod_template.h b/CHOLMOD/Include/cholmod_template.h index 8ec5283541..d6bae6c33c 100644 --- a/CHOLMOD/Include/cholmod_template.h +++ b/CHOLMOD/Include/cholmod_template.h @@ -2,7 +2,7 @@ // CHOLMOD/Include/cholmod_template.h: template definitions for CHOLMOD //------------------------------------------------------------------------------ -// CHOLMOD/Include/cholmod_internal.h. Copyright (C) 2005-2022, +// CHOLMOD/Include/cholmod_internal.h. Copyright (C) 2005-2023, // Timothy A. Davis. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 @@ -28,6 +28,7 @@ #undef TEMPLATE #undef TEMPLATE2 +#undef TEMPLATE_DTYPE #undef XTYPE #undef XTYPE2 #undef XTYPE_OK @@ -36,6 +37,7 @@ #undef ENTRY_IS_ONE #undef IMAG_IS_NONZERO +#undef ABS #undef ASSEMBLE #undef ASSIGN #undef ASSIGN_CONJ @@ -76,24 +78,31 @@ #ifdef SINGLE // single precision #define Real float + #define TEMPLATE_DTYPE(name) s_ ## name #else // double precision #ifndef DOUBLE #define DOUBLE #endif #define Real double + #define TEMPLATE_DTYPE(name) d_ ## name #endif //------------------------------------------------------------------------------ -// pattern: both double and single +// xtype: pattern/real/complex/zomplex //------------------------------------------------------------------------------ #ifdef PATTERN + //-------------------------------------------------------------------------- + // pattern: both double and single + //-------------------------------------------------------------------------- + #ifdef SINGLE - #define PREFIX p_s_ - #define TEMPLATE(name) P_S_TEMPLATE(name) - #define TEMPLATE2(name) P_S_TEMPLATE(name) + #define PREFIX ps_ + #define TEMPLATE(name) PS_TEMPLATE(name) + #define TEMPLATE2(name) PS_TEMPLATE(name) + #define TEMPLATE3(name) PS_TEMPLATE(name) #else #define PREFIX p_ #define TEMPLATE(name) P_TEMPLATE(name) @@ -109,6 +118,7 @@ #define IMAG_IS_NONZERO(ax,az,q) (FALSE) #define ENTRY_SIZE 0 + #define ABS(ax,az,p) ((double) 1) #define ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) @@ -136,20 +146,20 @@ #define XPRINT2(x,z,p) P_PRINT(2,x,z,p) #define XPRINT3(x,z,p) P_PRINT(3,x,z,p) -//------------------------------------------------------------------------------ -// real: double and single -//------------------------------------------------------------------------------ - #elif defined (REAL) + //-------------------------------------------------------------------------- + // real: double and single + //-------------------------------------------------------------------------- + #ifdef SINGLE - #define PREFIX r_s_ - #define TEMPLATE(name) R_S_TEMPLATE(name) - #define TEMPLATE2(name) R_S_TEMPLATE(name) + #define PREFIX rs_ + #define TEMPLATE(name) RS_TEMPLATE(name) + #define TEMPLATE2(name) RS_TEMPLATE(name) #else - #define PREFIX r_ - #define TEMPLATE(name) R_TEMPLATE(name) - #define TEMPLATE2(name) R_TEMPLATE(name) + #define PREFIX rd_ + #define TEMPLATE(name) RD_TEMPLATE(name) + #define TEMPLATE2(name) RD_TEMPLATE(name) #endif #define XTYPE CHOLMOD_REAL @@ -161,7 +171,8 @@ #define IMAG_IS_NONZERO(ax,az,q) (FALSE) #define ENTRY_SIZE 1 - #define ASSEMBLE(x,z,p,ax,az,q) R_ASSEMBLE(x,z,p,ax,az,q) + #define ABS(ax,az,p) R_ABS(ax,az,p) + #define ASSEMBLE(x,z,p,ax,az,q) R_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) @@ -178,8 +189,8 @@ #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ R_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) R_LLDOT(x,p,ax,az,q) - #define CLEAR(x,z,p) R_CLEAR(x,z,p) - #define CLEAR_IMAG(x,z,p) R_CLEAR_IMAG(x,z,p) + #define CLEAR(x,z,p) R_CLEAR(x,z,p) + #define CLEAR_IMAG(x,z,p) R_CLEAR_IMAG(x,z,p) #define DIV(x,z,p,ax,az,q) R_DIV(x,z,p,ax,az,q) @@ -192,37 +203,38 @@ #define XPRINT2(x,z,p) R_PRINT(2,x,z,p) #define XPRINT3(x,z,p) R_PRINT(3,x,z,p) -//------------------------------------------------------------------------------ -// complex: both double and single -//------------------------------------------------------------------------------ - #elif defined (COMPLEX) + //-------------------------------------------------------------------------- + // complex: both double and single + //-------------------------------------------------------------------------- + #ifdef SINGLE - #define PREFIX c_s_ + #define PREFIX cs_ #ifdef NCONJUGATE // non-conjugate - #define TEMPLATE(name) CT_S_TEMPLATE(name) - #define TEMPLATE2(name) CT_S_TEMPLATE(name) + #define TEMPLATE(name) CS_T_TEMPLATE(name) + #define TEMPLATE2(name) CS_T_TEMPLATE(name) #else // conjugate - #define TEMPLATE(name) C_S_TEMPLATE(name) - #define TEMPLATE2(name) C_S_TEMPLATE(name) + #define TEMPLATE(name) CS_TEMPLATE(name) + #define TEMPLATE2(name) CS_TEMPLATE(name) #endif #else - #define PREFIX c_ + #define PREFIX cd_ #ifdef NCONJUGATE // non-conjugate - #define TEMPLATE(name) CT_TEMPLATE(name) - #define TEMPLATE2(name) CT_TEMPLATE(name) + #define TEMPLATE(name) CD_T_TEMPLATE(name) + #define TEMPLATE2(name) CD_T_TEMPLATE(name) #else // conjugate - #define TEMPLATE(name) C_TEMPLATE(name) - #define TEMPLATE2(name) C_TEMPLATE(name) + #define TEMPLATE(name) CD_TEMPLATE(name) + #define TEMPLATE2(name) CD_TEMPLATE(name) #endif #endif - #define ASSEMBLE(x,z,p,ax,az,q) C_ASSEMBLE(x,z,p,ax,az,q) + #define ABS(ax,az,p) C_ABS(ax,az,p) + #define ASSEMBLE(x,z,p,ax,az,q) C_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) C_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) C_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) C_ASSIGN(x,z,p,ax,az,q) @@ -248,8 +260,8 @@ #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ C_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) C_LLDOT(x,p,ax,az,q) - #define CLEAR(x,z,p) C_CLEAR(x,z,p) - #define CLEAR_IMAG(x,z,p) C_CLEAR_IMAG(x,z,p) + #define CLEAR(x,z,p) C_CLEAR(x,z,p) + #define CLEAR_IMAG(x,z,p) C_CLEAR_IMAG(x,z,p) #ifdef SINGLE #define DIV(x,z,p,ax,az,q) C_S_DIV(x,z,p,ax,az,q) @@ -266,36 +278,37 @@ #define XPRINT2(x,z,p) C_PRINT(2,x,z,p) #define XPRINT3(x,z,p) C_PRINT(3,x,z,p) -//------------------------------------------------------------------------------ -// zomplex: both double and single -//------------------------------------------------------------------------------ - #elif defined (ZOMPLEX) + //-------------------------------------------------------------------------- + // zomplex: both double and single + //-------------------------------------------------------------------------- + #ifdef SINGLE - #define PREFIX z_s_ + #define PREFIX zs_ #ifdef NCONJUGATE // non-conjugate - #define TEMPLATE(name) ZT_S_TEMPLATE(name) - #define TEMPLATE2(name) CT_S_TEMPLATE(name) + #define TEMPLATE(name) ZS_T_TEMPLATE(name) + #define TEMPLATE2(name) CS_T_TEMPLATE(name) #else // conjugate - #define TEMPLATE(name) Z_S_TEMPLATE(name) - #define TEMPLATE2(name) C_S_TEMPLATE(name) + #define TEMPLATE(name) ZS_TEMPLATE(name) + #define TEMPLATE2(name) CS_TEMPLATE(name) #endif #else - #define PREFIX z_ + #define PREFIX zd_ #ifdef NCONJUGATE // non-conjugate - #define TEMPLATE(name) ZT_TEMPLATE(name) - #define TEMPLATE2(name) CT_TEMPLATE(name) + #define TEMPLATE(name) ZD_T_TEMPLATE(name) + #define TEMPLATE2(name) CD_T_TEMPLATE(name) #else - #define TEMPLATE(name) Z_TEMPLATE(name) - #define TEMPLATE2(name) C_TEMPLATE(name) + #define TEMPLATE(name) ZD_TEMPLATE(name) + #define TEMPLATE2(name) CD_TEMPLATE(name) #endif #endif - #define ASSEMBLE(x,z,p,ax,az,q) Z_ASSEMBLE(x,z,p,ax,az,q) + #define ABS(ax,az,p) Z_ABS(ax,az,p) + #define ASSEMBLE(x,z,p,ax,az,q) Z_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) Z_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) Z_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) Z_ASSIGN(x,z,p,ax,az,q) @@ -321,8 +334,8 @@ #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ Z_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) Z_LLDOT(x,p,ax,az,q) - #define CLEAR(x,z,p) Z_CLEAR(x,z,p) - #define CLEAR_IMAG(x,z,p) Z_CLEAR_IMAG(x,z,p) + #define CLEAR(x,z,p) Z_CLEAR(x,z,p) + #define CLEAR_IMAG(x,z,p) Z_CLEAR_IMAG(x,z,p) #ifdef SINGLE #define DIV(x,z,p,ax,az,q) Z_S_DIV(x,z,p,ax,az,q) @@ -341,6 +354,10 @@ #endif +//------------------------------------------------------------------------------ +// conjugate/non-conjugate assignment (for pattern/real/complex/zomplex) +//------------------------------------------------------------------------------ + #ifdef NCONJUGATE // non-conjugate assign #define ASSIGN_CONJ_OR_NCONJ(x,z,p,ax,az,q) ASSIGN(x,z,p,ax,az,q) @@ -349,3 +366,158 @@ #define ASSIGN_CONJ_OR_NCONJ(x,z,p,ax,az,q) ASSIGN_CONJ(x,z,p,ax,az,q) #endif +//------------------------------------------------------------------------------ +// macros for finding untested code (for developent only) +//------------------------------------------------------------------------------ + +// These macros are xtype and/or dtype-type specific versions of the GOTCHA +// macro #defined in cholmod_internal.h. + +#if 0 + + #undef PI_GOTCHA + #undef PL_GOTCHA + + #undef PDI_GOTCHA + #undef RDI_GOTCHA + #undef CDI_GOTCHA + #undef ZDI_GOTCHA + + #undef PDL_GOTCHA + #undef RDL_GOTCHA + #undef CDL_GOTCHA + #undef ZDL_GOTCHA + + #undef PSI_GOTCHA + #undef RSI_GOTCHA + #undef CSI_GOTCHA + #undef ZSI_GOTCHA + + #undef PSL_GOTCHA + #undef RSL_GOTCHA + #undef CSL_GOTCHA + #undef ZSL_GOTCHA + + #ifdef DOUBLE + + #ifdef CHOLMOD_INT64 + + #if defined ( PATTERN ) + #define PL_GOTCHA GOTCHA + #define PDL_GOTCHA GOTCHA + #elif defined ( REAL ) + #define RDL_GOTCHA GOTCHA + #elif defined ( COMPLEX ) + #define CDL_GOTCHA GOTCHA + #elif defined ( ZOMPLEX ) + #define ZDL_GOTCHA GOTCHA + #endif + + #else + + #if defined ( PATTERN ) + #define PI_GOTCHA GOTCHA + #define PDI_GOTCHA GOTCHA + #elif defined ( REAL ) + #define RDI_GOTCHA GOTCHA + #elif defined ( COMPLEX ) + #define CDI_GOTCHA GOTCHA + #elif defined ( ZOMPLEX ) + #define ZDI_GOTCHA GOTCHA + #endif + + #endif + + #else + + #ifdef CHOLMOD_INT64 + + #if defined ( PATTERN ) + #define PL_GOTCHA GOTCHA + #define PSL_GOTCHA GOTCHA + #elif defined ( REAL ) + #define RSL_GOTCHA GOTCHA + #elif defined ( COMPLEX ) + #define CSL_GOTCHA GOTCHA + #elif defined ( ZOMPLEX ) + #define ZSL_GOTCHA GOTCHA + #endif + + #else + + #if defined ( PATTERN ) + #define PI_GOTCHA GOTCHA + #define PSI_GOTCHA GOTCHA + #elif defined ( REAL ) + #define RSI_GOTCHA GOTCHA + #elif defined ( COMPLEX ) + #define CSI_GOTCHA GOTCHA + #elif defined ( ZOMPLEX ) + #define ZSI_GOTCHA GOTCHA + #endif + + #endif + #endif + + #ifndef PI_GOTCHA + #define PI_GOTCHA ; + #endif + + #ifndef PL_GOTCHA + #define PL_GOTCHA ; + #endif + + #ifndef PDI_GOTCHA + #define PDI_GOTCHA ; + #endif + #ifndef RDI_GOTCHA + #define RDI_GOTCHA ; + #endif + #ifndef CDI_GOTCHA + #define CDI_GOTCHA ; + #endif + #ifndef ZDI_GOTCHA + #define ZDI_GOTCHA ; + #endif + + #ifndef PDL_GOTCHA + #define PDL_GOTCHA ; + #endif + #ifndef RDL_GOTCHA + #define RDL_GOTCHA ; + #endif + #ifndef CDL_GOTCHA + #define CDL_GOTCHA ; + #endif + #ifndef ZDL_GOTCHA + #define ZDL_GOTCHA ; + #endif + + #ifndef PSI_GOTCHA + #define PSI_GOTCHA ; + #endif + #ifndef RSI_GOTCHA + #define RSI_GOTCHA ; + #endif + #ifndef CSI_GOTCHA + #define CSI_GOTCHA ; + #endif + #ifndef ZSI_GOTCHA + #define ZSI_GOTCHA ; + #endif + + #ifndef PSL_GOTCHA + #define PSL_GOTCHA ; + #endif + #ifndef RSL_GOTCHA + #define RSL_GOTCHA ; + #endif + #ifndef CSL_GOTCHA + #define CSL_GOTCHA ; + #endif + #ifndef ZSL_GOTCHA + #define ZSL_GOTCHA ; + #endif + +#endif + diff --git a/CHOLMOD/Include/cholmod_types.h b/CHOLMOD/Include/cholmod_types.h index ab6dde04f6..a3f49581d5 100644 --- a/CHOLMOD/Include/cholmod_types.h +++ b/CHOLMOD/Include/cholmod_types.h @@ -14,11 +14,11 @@ // CHOLMOD_INT64). CHOLMOD is designed for 2 types of integer variables: // int32_t or int64_t. // -// The complex types (ANSI-compatible complex, and MATLAB-compatable zomplex) +// The complex types (ANSI-compatible complex, and MATLAB-compatible zomplex) // are based on the double or float type, and are not selected here. They are // typically selected via template routines. -// ----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ #undef Int #undef UInt @@ -27,6 +27,8 @@ #undef ITYPE #undef ID #undef CLEAR_FLAG +// #undef I_GOTCHA +// #undef L_GOTCHA #if defined ( CHOLMOD_INT64 ) @@ -41,6 +43,9 @@ #define ITYPE CHOLMOD_LONG #define ID "%" PRId64 + // #define L_GOTCHA GOTCHA + // #define I_GOTCHA ; + #define CLEAR_FLAG(Common) \ { \ Common->mark++ ; \ @@ -68,6 +73,9 @@ #define ITYPE CHOLMOD_INT #define ID "%d" + // #define L_GOTCHA ; + // #define I_GOTCHA GOTCHA + #define CLEAR_FLAG(Common) \ { \ Common->mark++ ; \ @@ -80,3 +88,26 @@ #endif +//------------------------------------------------------------------------------ +// check for BLAS integer overflow +//------------------------------------------------------------------------------ + +// The conversion of a CHOLMOD integer (Int) to a BLAS/LAPACK integer (the +// SUITESPARSE_BLAS_INT can result in an integer overflow. This is detected by +// the SUITESPARSE_TO_BLAS_INT macro in SuiteSparse_config.h. If the error +// condition occurs, that macro sets Common->blas_ok to false, and that call +// and any subsequent calls to the BLAS/LAPACK will be skipped. From that +// point on, Common->blas_ok will remain false for that call to CHOLMOD. The +// following macro sets CHOLMOD status to CHOLMOD_TOO_LARGE if the BLAS +// conversion has failed. This is done only once for a particular call to any +// given CHOLMOD method. + +#define CHECK_FOR_BLAS_INTEGER_OVERFLOW \ +{ \ + if ((sizeof (SUITESPARSE_BLAS_INT) < sizeof (Int)) && \ + (Common->status == CHOLMOD_OK) && !(Common->blas_ok)) \ + { \ + ERROR (CHOLMOD_TOO_LARGE, "BLAS integer overflow") ; \ + } \ +} + diff --git a/CHOLMOD/MATLAB/Contents.m b/CHOLMOD/MATLAB/Contents.m index 0eba6f3b56..4ff7b02f68 100644 --- a/CHOLMOD/MATLAB/Contents.m +++ b/CHOLMOD/MATLAB/Contents.m @@ -4,29 +4,29 @@ % chol2 - sparse Cholesky factorization, A=R'R. % lchol - sparse A=L*L' factorization. % ldlchol - sparse A=LDL' factorization -% ldlupdate - multiple-rank update or downdate of a sparse LDL' factorization. -% ldlrowmod - add/delete row from a sparse LDL' factorization. -% resymbol - recomputes the symbolic Cholesky factorization of the matrix A. +% ldlupdate - multiple-rank update or downdate of a sparse LDL' factorization +% ldlrowmod - add/delete a row from a sparse LDL' factorization. +% resymbol - recomputes the symbolic Cholesky factorization of the matrix A % ldlsolve - solve LDL'x=b using a sparse LDL' factorization -% ldlsplit - split an LDL' factorization into L and D. -% metis - nested dissection ordering via METIS_NodeND. +% ldlsplit - split an LDL' factorization into L and D +% metis - nested dissection ordering via METIS_NodeND % nesdis - nested dissection ordering via CHOLMOD's nested dissection. -% septree - prune a separator tree. +% septree - prune a separator tree % bisect - computes a node separator based on METIS_ComputeVertexSeparator. % analyze - order and analyze a matrix using CHOLMOD's best-effort ordering. % etree2 - sparse elimination tree. -% sparse2 - replacement for SPARSE % symbfact2 - symbolic factorization % sdmult - sparse matrix times dense matrix -% mread - read a sparse matrix from a file in Matrix Market format. +% mread - read a sparse matrix from a file in Matrix Market format % mwrite - write a matrix to a file in Matrix Market form. -% spsym - determine if a sparse matrix is symmetric, Hermitian, or skew-symmetric. +% spsym - check if a matrix is symmetric, Hermitian, or skew-symmetric. % ldl_normest - estimate the 1-norm of A-L*D*L' without computing L*D*L' % cholmod_demo - a demo for CHOLMOD % cholmod_install - compile and install CHOLMOD, AMD, COLAMD, CCOLAMD, CAMD % cholmod_make - compiles the CHOLMOD mexFunctions % graph_demo - graph partitioning demo -% cholmod_updown_demo - a demo of update/downdate and row add/delete functions +% cholmod_updown_demo - a demo for CHOLMOD's update/downdate & row add/delete +% get_symmetry - same as spsym, just slower for testing only % % % Example: @@ -35,5 +35,5 @@ % Note: cholmod has been renamed cholmod2, so as not to conflict with itself % (the MATLAB built-in cholmod function). -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MATLAB/README.txt b/CHOLMOD/MATLAB/README.txt index 665c44dd20..6563416779 100644 --- a/CHOLMOD/MATLAB/README.txt +++ b/CHOLMOD/MATLAB/README.txt @@ -12,7 +12,7 @@ your MATLAB command window to test your newly compiling CHOLMOD functions. Test/cholmod_test.m runs the test suite for the MATLAB interface to CHOLMOD. It requires the "ssget" interface to the SuiteSparse matrix collection, but provides a more extensive test for CHOLMOD. To obtain a copy of ssget, see -http://sparse.tamu.edu. +http://sparse.tamu.edu, or see SuiteSparse/ssget. ---------------------------------------- Using AMD, CCOLAMD, and COLAMD in MATLAB @@ -20,8 +20,8 @@ Using AMD, CCOLAMD, and COLAMD in MATLAB The following steps are not required to use CHOLMOD in MATLAB. -To use AMD in MATLAB, go to the AMD/MATLAB directory and either type "amd_install" -in the MATLAB command window, or type "make" in the Unix shell. +To use AMD in MATLAB, go to the AMD/MATLAB directory and either type +"amd_install" in the MATLAB command window, or type "make" in the Unix shell. To use CCOLAMD in MATLAB, go to the CCOLAMD directory and type ccolamd_install. diff --git a/CHOLMOD/MATLAB/Test/Contents.m b/CHOLMOD/MATLAB/Test/Contents.m index 06f0b97ecd..08b751fd02 100644 --- a/CHOLMOD/MATLAB/Test/Contents.m +++ b/CHOLMOD/MATLAB/Test/Contents.m @@ -1,17 +1,12 @@ % CHOLMOD TEST functions % % cholmod_test - test the CHOLMOD mexFunctions -% dg - order and plot A*A', using CHOLMOD's nested dissection -% n2 - script to test CHOLMOD septree function -% nn - Compare nesdis with metis, in both quality and run time +% other1 - Compare nesdis with metis, in both quality and run time +% other2 - script to test CHOLMOD septree function % test0 - test most CHOLMOD functions -% test1 - test sparse2 -% test2 - test sparse2 % test3 - test sparse on int8, int16, and logical % test4 - test cholmod2 with multiple and sparse right-hand-sides -% test5 - test sparse2 % test6 - test sparse with large matrix, both real and complex -% test7 - test sparse2 % test8 - order a large range of sparse matrices, test symbfact2 % test9 - test metis, etree, bisect, nesdis % test10 - test cholmod2's backslash on real and complex matrices @@ -35,7 +30,8 @@ % test27 - test nesdis with one matrix (HB/west0479) % test28 - test nesdis % testmm - compare mread and mmread for entire Matrix Market collection -% testsolve - test CHOLMOD and compare with x=A\b +% testnd - order and plot A*A', using CHOLMOD's nested dissection +% testsolve - test CHOLMOD and compare with x=A\b % ltest - test lxbpattern % lxtest - test lsubsolve % ltest2 - test lsubsolve @@ -43,6 +39,6 @@ % Example: % cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MATLAB/Test/GB_spones_mex.c b/CHOLMOD/MATLAB/Test/GB_spones_mex.c index af3e4d16e2..1deb6915a8 100644 --- a/CHOLMOD/MATLAB/Test/GB_spones_mex.c +++ b/CHOLMOD/MATLAB/Test/GB_spones_mex.c @@ -2,7 +2,7 @@ // GB_spones_mex: like spones(A) in MATLAB but do not drop zeros on input //------------------------------------------------------------------------------ -// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved. +// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2023, All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // The MATLAB built-in function spones(A) has changed, as of MATLAB R2019b. diff --git a/CHOLMOD/MATLAB/Test/blas_dump_results.m b/CHOLMOD/MATLAB/Test/blas_dump_results.m new file mode 100644 index 0000000000..0194649b80 --- /dev/null +++ b/CHOLMOD/MATLAB/Test/blas_dump_results.m @@ -0,0 +1,421 @@ +%BLAS_DUMP_RESULTS analyze results from BLAS_DUMP +% use with 'make large' or go_nd12k + +% Used in supernodal factorization: +% +% 0 dsyrk ("L", "N", n k 0 lda ldc 0 +% 1 ssyrk ("L", "N", n k 0 lda ldc 0 +% 2 zherk ("L", "N", n k 0 lda ldc 0 +% 3 cherk ("L", "N", n k 0 lda ldc 0 +% +% 4 dgemm ("N", "C", m n k lda ldb ldc +% 5 sgemm ("N", "C", m n k lda ldb ldc +% 6 zgemm ("N", "C", m n k lda ldb ldc +% 7 cgemm ("N", "C", m n k lda ldb ldc +% +% 8 dpotrf ("L", n 0 0 lda 0 0 +% 9 spotrf ("L", n 0 0 lda 0 0 +% 10 zpotrf ("L", n 0 0 lda 0 0 +% 11 cpotrf ("L", n 0 0 lda 0 0 +% +% 12 dtrsm ("R", "L", "C", "N", m n 0 lda ldb 0 +% 13 strsm ("R", "L", "C", "N", m n 0 lda ldb 0 +% 14 ztrsm ("R", "L", "C", "N", m n 0 lda ldb 0 +% 15 ctrsm ("R", "L", "C", "N", m n 0 lda ldb 0 +% +% Used in supernodal forward/backsolve (not benchmarked): +% +% 16 dgemm ("N", "N", +% 17 sgemm ("N", "N", +% 18 zgemm ("N", "N", +% 19 cgemm ("N", "N", +% +% 20 dgemm ("C", "N", +% 21 sgemm ("C", "N", +% 22 zgemm ("C", "N", +% 23 cgemm ("C", "N", +% +% 24 dgemv ("N", +% 25 sgemv ("N", +% 26 zgemv ("N", +% 27 cgemv ("N", +% +% 28 dgemv ("C", +% 29 sgemv ("C", +% 30 zgemv ("C", +% 31 cgemv ("C", +% +% 32 dtrsm ("L", "L", "N", "N", +% 33 strsm ("L", "L", "N", "N", +% 34 ztrsm ("L", "L", "N", "N", +% 35 ctrsm ("L", "L", "N", "N", +% +% 36 dtrsm ("L", "L", "C", "N", +% 37 strsm ("L", "L", "C", "N", +% 38 ztrsm ("L", "L", "C", "N", +% 39 ctrsm ("L", "L", "C", "N", +% +% 40 dtrsv ("L", "N", "N", +% 41 strsv ("L", "N", "N", +% 42 ztrsv ("L", "N", "N", +% 43 ctrsv ("L", "N", "N", +% +% 44 dtrsv ("L", "C", "N", +% 45 strsv ("L", "C", "N", +% 46 ztrsv ("L", "C", "N", +% 47 ctrsv ("L", "C", "N", + +clear all + +% from 'make large', not in MATLAB +outside = load ('blas_dump.txt') ; + +% from 'go_nd12k' in MATLAB +inside = load ('MATLAB/blas_dump.txt') ; + +% Each line contains the 10 space-delimited values: +% +% 1 kernel see blas_legend.txt (0 to 15) +% 2 4 or 8 sizeof (blas integer), always 8 for MATLAB +% 3 4 or 8 size of the index in a sparse matrix, always 8 for MATLAB; +% cholmod_*i_simple will report 4. +% 4:6 m,n,k sizes of the matrices (0 if not used) +% 7:9 lda,ldb,ldc leading dimensions (0 if not used) +% 10 time time for this call to the BLAS / LAPACK + +%------------------------------------------------------------------------------- +% outside MATLAB, double results: +%------------------------------------------------------------------------------- + +% analyze time: 2.135 sec +% factorize time: 5.085 sec +% solve time: 0.106 sec +% total time: 7.326 sec +% CHOLMOD BLAS statistics: +% SYRK CPU calls 1783 time 1.3997e+00 +% GEMM CPU calls 1450 time 1.1142e+00 +% POTRF CPU calls 334 time 9.9486e-01 +% TRSM CPU calls 333 time 6.7501e-01 +% total time in the BLAS: 4.1838e+00 + +dsyrk_outside = outside (find (outside (:,1) == 0), :) ; +dgemm_outside = outside (find (outside (:,1) == 4), :) ; +dpotrf_outside = outside (find (outside (:,1) == 8), :) ; +dtrsm_outside = outside (find (outside (:,1) == 12), :) ; + +dsyrk_outside_time = dsyrk_outside (:,10) ; +dgemm_outside_time = dgemm_outside (:,10) ; +dpotrf_outside_time = dpotrf_outside (:,10) ; +dtrsm_outside_time = dtrsm_outside (:,10) ; + +fprintf ('\n') ; +fprintf ('total dsyrk time, outside: %g\n', sum (dsyrk_outside_time)) ; +fprintf ('total dgemm time, outside: %g\n', sum (dgemm_outside_time)) ; +fprintf ('total dpotrf time, outside: %g\n', sum (dpotrf_outside_time)) ; +fprintf ('total dtrsm time, outside: %g\n', sum (dtrsm_outside_time)) ; +fprintf ('total BLAS time, outside: %g\n', ... + sum (dsyrk_outside_time) + sum (dgemm_outside_time) + ... + sum (dpotrf_outside_time) + sum (dtrsm_outside_time)) ; + +% get work for dsyrk/ssyrk +n_syrk = dsyrk_outside (:,4) ; +k_syrk = dsyrk_outside (:,5) ; +syrk_work = n_syrk .* n_syrk .* (k_syrk+1) ; + +% get work for dgemm/sgemm +m_gemm = dgemm_outside (:,4) ; +n_gemm = dgemm_outside (:,5) ; +k_gemm = dgemm_outside (:,6) ; +gemm_work = (m_gemm .* n_gemm .* k_gemm) * 2 ; + +% get work for dpotrf/spotrf +n_potrf = dpotrf_outside (:,4) ; +potrf_work = (n_potrf .* n_potrf .* n_potrf) / 3 ; + +% get work for dtrsm/strsm +m_trsm = dtrsm_outside (:,4) ; +n_trsm = dtrsm_outside (:,5) ; +trsm_work = m_trsm .* n_trsm .* n_trsm ; + +%------------------------------------------------------------------------------- +% outside MATLAB, single results: +%------------------------------------------------------------------------------- + +% analyze time: 2.375 sec +% factorize time: 2.814 sec +% solve time: 0.046 sec +% total time: 5.236 sec +% CHOLMOD BLAS statistics: +% SYRK CPU calls 1783 time 7.9215e-01 +% GEMM CPU calls 1450 time 5.9799e-01 +% POTRF CPU calls 334 time 5.0774e-01 +% TRSM CPU calls 333 time 3.5276e-01 +% total time in the BLAS: 2.2506e+00 + +ssyrk_outside = outside (find (outside (:,1) == 1), :) ; +sgemm_outside = outside (find (outside (:,1) == 5), :) ; +spotrf_outside = outside (find (outside (:,1) == 9), :) ; +strsm_outside = outside (find (outside (:,1) == 13), :) ; + +ssyrk_outside_time = ssyrk_outside (:,10) ; +sgemm_outside_time = sgemm_outside (:,10) ; +spotrf_outside_time = spotrf_outside (:,10) ; +strsm_outside_time = strsm_outside (:,10) ; + +fprintf ('\n') ; +fprintf ('total ssyrk time, outside: %g\n', sum (ssyrk_outside_time)) ; +fprintf ('total sgemm time, outside: %g\n', sum (sgemm_outside_time)) ; +fprintf ('total spotrf time, outside: %g\n', sum (spotrf_outside_time)) ; +fprintf ('total strsm time, outside: %g\n', sum (strsm_outside_time)) ; +fprintf ('total BLAS time, outside: %g\n', ... + sum (ssyrk_outside_time) + sum (sgemm_outside_time) + ... + sum (spotrf_outside_time) + sum (strsm_outside_time)) ; + +%------------------------------------------------------------------------------- +% inside MATLAB, double results: +%------------------------------------------------------------------------------- + +% time for x=A\b (in double): 9.82203 sec +% analyze time: 2.62621 sec +% factorize time: 7.25898 sec +% solve time: 0.125075 sec +% CHOLMOD BLAS statistics: +% SYRK CPU calls 1783 time 1.9567e+00 +% GEMM CPU calls 1450 time 1.3923e+00 +% POTRF CPU calls 334 time 1.5183e+00 +% TRSM CPU calls 333 time 8.0667e-01 +% total time in the BLAS: 5.6740e+00 +% time for x=cholmod2(A,b) (double): 10.0717 sec + +dsyrk_inside = inside (find (inside (:,1) == 0), :) ; +dgemm_inside = inside (find (inside (:,1) == 4), :) ; +dpotrf_inside = inside (find (inside (:,1) == 8), :) ; +dtrsm_inside = inside (find (inside (:,1) == 12), :) ; + +dsyrk_inside_time = dsyrk_inside (:,10) ; +dgemm_inside_time = dgemm_inside (:,10) ; +dpotrf_inside_time = dpotrf_inside (:,10) ; +dtrsm_inside_time = dtrsm_inside (:,10) ; + +fprintf ('\n') ; +fprintf ('total dsyrk time, inside: %g\n', sum (dsyrk_inside_time)) ; +fprintf ('total dgemm time, inside: %g\n', sum (dgemm_inside_time)) ; +fprintf ('total dpotrf time, inside: %g\n', sum (dpotrf_inside_time)) ; +fprintf ('total dtrsm time, inside: %g\n', sum (dtrsm_inside_time)) ; +fprintf ('total BLAS time, inside: %g\n', ... + sum (dsyrk_inside_time) + sum (dgemm_inside_time) + ... + sum (dpotrf_inside_time) + sum (dtrsm_inside_time)) ; + +%------------------------------------------------------------------------------- +% inside MATLAB, single results: +%------------------------------------------------------------------------------- + +% analyze time: 2.63795 sec +% factorize time: 142.123 sec +% solve time: 0.0919384 sec +% CHOLMOD BLAS statistics: +% SYRK CPU calls 1783 time 5.9033e+01 +% GEMM CPU calls 1450 time 2.3369e+01 +% POTRF CPU calls 334 time 4.0921e+01 +% TRSM CPU calls 333 time 1.7772e+01 +% total time in the BLAS: 1.4109e+02 +% time for x=cholmod2(A,b) (single): 144.914 sec + +ssyrk_inside = inside (find (inside (:,1) == 1), :) ; +sgemm_inside = inside (find (inside (:,1) == 5), :) ; +spotrf_inside = inside (find (inside (:,1) == 9), :) ; +strsm_inside = inside (find (inside (:,1) == 13), :) ; + +ssyrk_inside_time = ssyrk_inside (:,10) ; +sgemm_inside_time = sgemm_inside (:,10) ; +spotrf_inside_time = spotrf_inside (:,10) ; +strsm_inside_time = strsm_inside (:,10) ; + +fprintf ('\n') ; +fprintf ('total ssyrk time, inside: %g\n', sum (ssyrk_inside_time)) ; +fprintf ('total sgemm time, inside: %g\n', sum (sgemm_inside_time)) ; +fprintf ('total spotrf time, inside: %g\n', sum (spotrf_inside_time)) ; +fprintf ('total strsm time, inside: %g\n', sum (strsm_inside_time)) ; +fprintf ('total BLAS time, inside: %g\n', ... + sum (ssyrk_inside_time) + sum (sgemm_inside_time) + ... + sum (spotrf_inside_time) + sum (strsm_inside_time)) ; + +whos + +%------------------------------------------------------------------------------- +% compare results: +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +% figure 1 +%------------------------------------------------------------------------------- + +% x axis is each call to the BLAS/LAPACK, in order. +% y axis is the cumulative sum of the run time in that BLAS/LAPACK method. + +figure (1) +clf + +subplot (2,2,1) +nsyrk = length (ssyrk_outside) +semilogy ((1:nsyrk), cumsum (ssyrk_inside_time), 'r') ; +hold on +semilogy ((1:nsyrk), cumsum (ssyrk_outside_time), 'g') ; +semilogy ((1:nsyrk), cumsum (dsyrk_inside_time), 'b') ; +semilogy ((1:nsyrk), cumsum (dsyrk_outside_time), 'k') ; +xlabel ('*syrk, in order of call') ; +ylabel ('cumulative syrk time (log10 scale)') ; +legend ('ssyrk inside', 'ssyrk outside', ... + 'dsyrk inside', 'dsyrk outside', ... + 'Location', 'SouthEast') ; + +subplot (2,2,2) +ngemm = length (sgemm_outside) +semilogy ((1:ngemm), cumsum (sgemm_inside_time), 'r') ; +hold on +semilogy ((1:ngemm), cumsum (sgemm_outside_time), 'g') ; +semilogy ((1:ngemm), cumsum (dgemm_inside_time), 'b') ; +semilogy ((1:ngemm), cumsum (dgemm_outside_time), 'k') ; +xlabel ('*gemm, in order of call') ; +ylabel ('cumulative gemm time (log10 scale)') ; +legend ('sgemm inside', 'sgemm outside', ... + 'dgemm inside', 'dgemm outside', ... + 'Location', 'SouthEast') ; + +subplot (2,2,3) +npotrf = length (spotrf_outside) +semilogy ((1:npotrf), cumsum (spotrf_inside_time), 'r') ; +hold on +semilogy ((1:npotrf), cumsum (spotrf_outside_time), 'g') ; +semilogy ((1:npotrf), cumsum (dpotrf_inside_time), 'b') ; +semilogy ((1:npotrf), cumsum (dpotrf_outside_time), 'k') ; +xlabel ('*potrf, in order of call') ; +ylabel ('cumulative potrf time (log10 scale)') ; +legend ('spotrf inside', 'spotrf outside', ... + 'dpotrf inside', 'dpotrf outside', ... + 'Location', 'SouthEast') ; + +subplot (2,2,4) +ntrsm = length (strsm_outside) +semilogy ((1:ntrsm), cumsum (strsm_inside_time), 'r') ; +hold on +semilogy ((1:ntrsm), cumsum (strsm_outside_time), 'g') ; +semilogy ((1:ntrsm), cumsum (dtrsm_inside_time), 'b') ; +semilogy ((1:ntrsm), cumsum (dtrsm_outside_time), 'k') ; +xlabel ('*trsm, in order of call') ; +ylabel ('cumulative *trsm time (log10 scale)') ; +legend ('strsm inside', 'strsm outside', ... + 'dtrsm inside', 'dtrsm outside', ... + 'Location', 'SouthEast') ; + +%------------------------------------------------------------------------------- +% figure 2 +%------------------------------------------------------------------------------- + +% x axis is amount of work in the BLAS/LAPACK call +% y axis is the run time of that call inside + +figure (2) +clf + +subplot (2,2,1) +loglog (syrk_work, ssyrk_inside_time, 'ro') ; +hold on +loglog (syrk_work, ssyrk_outside_time, 'go') ; +xlabel ('syrk work (log scale)') ; +ylabel ('ssyrk time (log scale)') ; +legend ('inside', 'outside', 'Location', 'SouthEast') ; + +subplot (2,2,2) +loglog (gemm_work, sgemm_inside_time, 'ro') ; +hold on +loglog (gemm_work, sgemm_outside_time, 'go') ; +xlabel ('gemm work (log scale)') ; +ylabel ('sgemm time (log scale)') ; +legend ('inside', 'outside', 'Location', 'SouthEast') ; + +subplot (2,2,3) +loglog (potrf_work, spotrf_inside_time, 'ro') ; +hold on +loglog (potrf_work, spotrf_outside_time, 'go') ; +xlabel ('potrf work (log scale)') ; +ylabel ('potrf time (log scale)') ; +legend ('inside', 'outside', 'Location', 'SouthEast') ; + +subplot (2,2,4) +loglog (trsm_work, strsm_inside_time, 'ro') ; +hold on +loglog (trsm_work, strsm_outside_time, 'go') ; +xlabel ('trsm work (log scale)') ; +ylabel ('strsm time (log scale)') ; +legend ('inside', 'outside', 'Location', 'SouthEast') ; + +%------------------------------------------------------------------------------- +% figure 3 +%------------------------------------------------------------------------------- + +% x axis is amount of work in the BLAS/LAPACK call +% y axis is the run time of that call inside divided by outside + +figure (3) +clf + +subplot (2,2,1) +loglog (syrk_work, ssyrk_inside_time ./ ssyrk_outside_time, 'bo') ; +xlabel ('syrk work (log scale)') ; +ylabel ('ssyrk time (inside/outside)') ; + +subplot (2,2,2) +loglog (gemm_work, sgemm_inside_time ./ sgemm_outside_time, 'bo') ; +xlabel ('gemm work (log scale)') ; +ylabel ('sgemm time (inside/outside)') ; + +subplot (2,2,3) +loglog (potrf_work, spotrf_inside_time ./ spotrf_outside_time, 'bo') ; +xlabel ('potrf work (log scale)') ; +ylabel ('spotrf time (inside/outside)') ; + +subplot (2,2,4) +loglog (trsm_work, strsm_inside_time ./ strsm_outside_time, 'bo') ; +xlabel ('trsm work (log scale)') ; +ylabel ('strsm time (inside/outside)') ; + +%------------------------------------------------------------------------------- +% worst cases +%------------------------------------------------------------------------------- + +ssyrk_rel = (ssyrk_inside_time ./ ssyrk_outside_time) ; +sgemm_rel = (sgemm_inside_time ./ sgemm_outside_time) ; +spotrf_rel = (spotrf_inside_time ./ spotrf_outside_time) ; +strsm_rel = (strsm_inside_time ./ strsm_outside_time) ; + +[bad, i1] = max (ssyrk_rel) ; +[bad, i2] = max (sgemm_rel) ; +[bad, i3] = max (spotrf_rel) ; +[bad, i4] = max (strsm_rel) ; + +fprintf ('\nWorst case ssyrk:\n') ; +fprintf (' n %4d k %4d inside: %12.6f sec outside: %12.6f sec\n', ... + n_syrk (i1), k_syrk (i1), ssyrk_inside_time (i1), ssyrk_outside_time (i1)) ; +fprintf (' same in dsyrk: inside %12.6f sec, outside %12.6f\n', ... + dsyrk_inside_time (i1), dsyrk_outside_time (i1)) ; + +fprintf ('\nWorst case sgemm:\n') ; +fprintf (' m %4d n %4d k %4d inside: %12.6f sec outside: %12.6f sec\n', ... + m_gemm (i2), n_gemm (i2), k_gemm (i2), sgemm_inside_time (i2), sgemm_outside_time (i2)) ; +fprintf (' same in dgemm: inside %12.6f sec, outside %12.6f\n', ... + dgemm_inside_time (i2), dgemm_outside_time (i2)) ; + +fprintf ('\nWorst case spotrf:\n') ; +fprintf (' n %4d inside: %12.6f sec outside: %12.6f sec\n', ... + n_potrf (i3), spotrf_inside_time (i3), spotrf_outside_time (i3)) ; +fprintf (' same in dpotrm: inside %12.6f sec, outside %12.6f\n', ... + dpotrf_inside_time (i3), dpotrf_outside_time (i3)) ; + +fprintf ('\nWorst case strsm:\n') ; +fprintf (' m %4d n %4d inside: %12.6f sec outside: %12.6f sec\n', ... + m_trsm (i4), n_trsm (i4), strsm_inside_time (i4), strsm_outside_time (i4)) ; +fprintf (' same in strrm: inside %12.6f sec, outside %12.6f\n', ... + dtrsm_inside_time (i4), dtrsm_outside_time (i4)) ; + + diff --git a/CHOLMOD/MATLAB/Test/blas_legend.txt b/CHOLMOD/MATLAB/Test/blas_legend.txt new file mode 100644 index 0000000000..ae40e16d0d --- /dev/null +++ b/CHOLMOD/MATLAB/Test/blas_legend.txt @@ -0,0 +1,64 @@ +Used in supernodal factorization: + + 0 dsyrk ("L", "N", n k 0 lda ldc 0 + 1 ssyrk ("L", "N", n k 0 lda ldc 0 + 2 zherk ("L", "N", n k 0 lda ldc 0 + 3 cherk ("L", "N", n k 0 lda ldc 0 + + 4 dgemm ("N", "C", m n k lda ldb ldc + 5 sgemm ("N", "C", m n k lda ldb ldc + 6 zgemm ("N", "C", m n k lda ldb ldc + 7 cgemm ("N", "C", m n k lda ldb ldc + + 8 dpotrf ("L", n 0 0 lda 0 0 + 9 spotrf ("L", n 0 0 lda 0 0 + 10 zpotrf ("L", n 0 0 lda 0 0 + 11 cpotrf ("L", n 0 0 lda 0 0 + + 12 dtrsm ("R", "L", "C", "N", m n 0 lda ldb 0 + 13 strsm ("R", "L", "C", "N", m n 0 lda ldb 0 + 14 ztrsm ("R", "L", "C", "N", m n 0 lda ldb 0 + 15 ctrsm ("R", "L", "C", "N", m n 0 lda ldb 0 + +Used in supernodal forward/backsolve (not benchmarked): + + 16 dgemm ("N", "N", + 17 sgemm ("N", "N", + 18 zgemm ("N", "N", + 19 cgemm ("N", "N", + + 20 dgemm ("C", "N", + 21 sgemm ("C", "N", + 22 zgemm ("C", "N", + 23 cgemm ("C", "N", + + 24 dgemv ("N", + 25 sgemv ("N", + 26 zgemv ("N", + 27 cgemv ("N", + + 28 dgemv ("C", + 29 sgemv ("C", + 30 zgemv ("C", + 31 cgemv ("C", + + 32 dtrsm ("L", "L", "N", "N", + 33 strsm ("L", "L", "N", "N", + 34 ztrsm ("L", "L", "N", "N", + 35 ctrsm ("L", "L", "N", "N", + + 36 dtrsm ("L", "L", "C", "N", + 37 strsm ("L", "L", "C", "N", + 38 ztrsm ("L", "L", "C", "N", + 39 ctrsm ("L", "L", "C", "N", + + 40 dtrsv ("L", "N", "N", + 41 strsv ("L", "N", "N", + 42 ztrsv ("L", "N", "N", + 43 ctrsv ("L", "N", "N", + + 44 dtrsv ("L", "C", "N", + 45 strsv ("L", "C", "N", + 46 ztrsv ("L", "C", "N", + 47 ctrsv ("L", "C", "N", + diff --git a/CHOLMOD/MATLAB/Test/cholmod_test.m b/CHOLMOD/MATLAB/Test/cholmod_test.m index 10c3a9507f..398481de58 100644 --- a/CHOLMOD/MATLAB/Test/cholmod_test.m +++ b/CHOLMOD/MATLAB/Test/cholmod_test.m @@ -16,13 +16,7 @@ function cholmod_test (nmat, do_diary) % cholmod_demo: run tests on a few random matrices % graph_demo: graph partitioning demo % test0: test most CHOLMOD functions -% test1: test sparse2 -% test2: test sparse2 -% test3: test sparse on int8, int16, and logical % test4: test cholmod2 with multiple and sparse right-hand-sides -% test5: test sparse2 -% test6: test sparse with large matrix, both real and complex, compare w/MATLAB -% test7: test sparse2 % test8: order many sparse matrices, test symbfact2, compare amd and metis % test9: test metis, etree, bisect, nesdis % test10: test cholmod2's backslash on real and complex matrices @@ -46,12 +40,12 @@ function cholmod_test (nmat, do_diary) % ltest: test lxbpattern % lxtest: test lsubsolve % -% See also test0, test1, ... test28. +% See also test0, ... test28. % This extensive test is not included: % test28: test nesdis -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ if (nargin < 2) @@ -121,13 +115,7 @@ function cholmod_test (nmat, do_diary) end waitbar ( 2/tt, h, 'CHOLMOD test0') ; test0 (nmat) ; waitbar ( 3/tt, h, 'CHOLMOD test1') ; - test1 ; waitbar ( 4/tt, h, 'CHOLMOD test2') ; - test2 ; waitbar ( 5/tt, h, 'CHOLMOD test3') ; - test3 ; waitbar ( 6/tt, h, 'CHOLMOD test4') ; test4 ; waitbar ( 7/tt, h, 'CHOLMOD test5') ; - test5 ; waitbar ( 8/tt, h, 'CHOLMOD test6') ; - test6 ; waitbar ( 9/tt, h, 'CHOLMOD test7') ; - test7 ; waitbar (10/tt, h, 'CHOLMOD test8') ; if (do_metis) % these tests require METIS diff --git a/CHOLMOD/MATLAB/Test/go_nd12k.m b/CHOLMOD/MATLAB/Test/go_nd12k.m new file mode 100644 index 0000000000..eec1016dd3 --- /dev/null +++ b/CHOLMOD/MATLAB/Test/go_nd12k.m @@ -0,0 +1,51 @@ + +% clear all +% clear mex +% format compact + +fprintf ('testing a small problem:\n') ; +Prob = ssget (1440) +A = Prob.A ; +n = size (A,1) ; +b = rand (n,1) ; +x1 = A\b ; +err1 = norm (A*x1-b) +x2 = cholmod2 (A,b) ; +err2 = norm (A*x2-b) +x3 = cholmod2 (A,b, 'single') ; +err3 = norm (A*double(x3)-b) +whos + +fprintf ('testing a large problem (nd12k):\n') ; + +Prob = ssget (938) +A = Prob.A ; +n = size (A,1) ; +b = rand (n,1) ; +I = speye (n) ; +% condest (A) is 2e7 so single precision has trouble; +% so add 100*I: +A = A + 100*I ; + +tic +x1 = A\b ; +t = toc ; +fprintf ('time for x=A\\b (in double): %g sec\n', t) ; + +tic +x2 = cholmod2 (A, b) ; +t = toc ; +fprintf ('time for x=cholmod2(A,b) (double): %g sec\n', t) ; + +fprintf ('... please wait ...\n') ; +b2 = single (b) ; +tic +x3 = cholmod2 (A, b2, 'single') ; +t = toc ; +fprintf ('time for x=cholmod2(A,b) (single): %g sec\n', t) ; + +anorm = norm (A,1) +norm (A*x1-b,1) / anorm +norm (A*x2-b,1) / anorm +norm (A*double (x3) - b, 1) / anorm + diff --git a/CHOLMOD/MATLAB/Test/ltest.m b/CHOLMOD/MATLAB/Test/ltest.m index 52c0331574..ea6cd4d72c 100644 --- a/CHOLMOD/MATLAB/Test/ltest.m +++ b/CHOLMOD/MATLAB/Test/ltest.m @@ -4,7 +4,7 @@ % ltest % See also cholmod_test, lxtest, ltest2 -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ rng ('default') diff --git a/CHOLMOD/MATLAB/Test/ltest2.m b/CHOLMOD/MATLAB/Test/ltest2.m index 7b1d43f322..d898a66058 100644 --- a/CHOLMOD/MATLAB/Test/ltest2.m +++ b/CHOLMOD/MATLAB/Test/ltest2.m @@ -5,7 +5,7 @@ % % See also cholmod_test, ltest, ltest2 -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ if (~isreal (L)) @@ -32,7 +32,7 @@ case 3 x1 = (L' \ (D \ ( ( b)))) ; % solve DL'x = b - + case 4 x1 = ( ( (L \ ( b)))) ; % solve Lx = b @@ -80,7 +80,7 @@ case 3 x1 = (L2' \ ( ( ( b)))) ; % solve L2'x = b - + case 4 x1 = ( ( (L2 \ ( b)))) ; % solve L2x = b diff --git a/CHOLMOD/MATLAB/Test/lxtest.m b/CHOLMOD/MATLAB/Test/lxtest.m index 4e992656a0..8379d27a0c 100644 --- a/CHOLMOD/MATLAB/Test/lxtest.m +++ b/CHOLMOD/MATLAB/Test/lxtest.m @@ -4,7 +4,7 @@ % lxtest % See also cholmod_test, ltest, ltest2 -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ rng ('default') diff --git a/CHOLMOD/MATLAB/Test/nn.m b/CHOLMOD/MATLAB/Test/other1.m similarity index 69% rename from CHOLMOD/MATLAB/Test/nn.m rename to CHOLMOD/MATLAB/Test/other1.m index 91cad02c95..e4ec9865bc 100644 --- a/CHOLMOD/MATLAB/Test/nn.m +++ b/CHOLMOD/MATLAB/Test/other1.m @@ -1,10 +1,10 @@ -%NN Compare nesdis with metis, in both quality and run time +%OTHER1 Compare nesdis with metis, in both quality and run time % % Example: -% nn +% other1 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ index = ssget ; @@ -31,23 +31,23 @@ [m n] = size (A) ; if (m ~= n) - continue ; + continue ; end fprintf ('%35s: ', Prob.name) ; if (m == n) - mode = 'sym' ; - A = A + A' ; - len = n ; + mode = 'sym' ; + A = A + A' ; + len = n ; elseif (m < n) - mode = 'row' ; - len = m ; + mode = 'row' ; + len = m ; else - mode = 'col' ; - len = n ; + mode = 'col' ; + len = n ; end - + fprintf (' %s ', mode) ; % try nesdis using camd, and splitting connected components @@ -70,27 +70,27 @@ tm = toc ; if (any (sort (p1) ~= 1:len)) - error ('p1!') ; + error ('p1!') ; end if (any (sort (p2) ~= 1:len)) - error ('p2!') ; + error ('p2!') ; end % compare ordering quality if (m == n) - c2 = symbfact2 (A (p2,p2), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; - c1 = symbfact2 (A (p1,p1), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; - cm = symbfact2 (A (pm,pm), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; + c2 = symbfact2 (A (p2,p2), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; + c1 = symbfact2 (A (p1,p1), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; + cm = symbfact2 (A (pm,pm), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; elseif (m < n) - c2 = symbfact2 (A (p2, :), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; - c1 = symbfact2 (A (p1, :), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; - cm = symbfact2 (A (pm, :), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; + c2 = symbfact2 (A (p2, :), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; + c1 = symbfact2 (A (p1, :), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; + cm = symbfact2 (A (pm, :), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; else - c2 = symbfact2 (A ( :,p2), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; - c1 = symbfact2 (A ( :,p1), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; - cm = symbfact2 (A ( :,pm), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; + c2 = symbfact2 (A ( :,p2), mode) ; fl2 = sum (c2.^2) ; c2 = sum (c2) ; + c1 = symbfact2 (A ( :,p1), mode) ; fl1 = sum (c1.^2) ; c1 = sum (c1) ; + cm = symbfact2 (A ( :,pm), mode) ; flm = sum (cm.^2) ; cm = sum (cm) ; end T1 (k) = t1 ; @@ -108,11 +108,11 @@ flmax =max ([max(Fl1 (1:k)) max(Fl2 (1:k)) max(FlM (1:k))]) ; fprintf (... - 'time %8.2f %8.2f %8.2f speedup %8.2f flop %8.2e %8.2e %8.2e ratio %8.2f\n', ... - t2, t1, tm, tm/t1, fl2, fl1, flm, flm/fl1) ; + 'time %8.2f %8.2f %8.2f speedup %8.2f flop %8.2e %8.2e %8.2e ratio %8.2f\n', ... + t2, t1, tm, tm/t1, fl2, fl1, flm, flm/fl1) ; if (mod (k, 20) ~= 0) - continue + continue end subplot (3,3,1) ; @@ -120,21 +120,21 @@ semilogy (1:k, x, 'o', [1 k], [1 1], 'r-') ; axis tight title (sprintf ('(nesdis default)/(with split) time, median: %g', ... - median (x))) ; + median (x))) ; subplot (3,3,2) ; x = (Lnz1 (1:k) ./ Lnz2 (1:k)) ; semilogy (1:k, x, 'o', [1 k], [1 1], 'r-') ; axis tight title (sprintf ('(nesdis default)/(with split) lnz, median: %g', ... - median (x))) ; + median (x))) ; subplot (3,3,3) ; x = (Fl1 (1:k) ./ Fl2 (1:k)) ; semilogy (1:k, x, 'o', [1 k], [1 1], 'r-') ; axis tight title (sprintf ('(nesdis default)/(with split) flops, median: %g', ... - median (x))) ; + median (x))) ; subplot (3,3,4) ; x = T1 (1:k) ./ TM (1:k) ; diff --git a/CHOLMOD/MATLAB/Test/n2.m b/CHOLMOD/MATLAB/Test/other2.m similarity index 57% rename from CHOLMOD/MATLAB/Test/n2.m rename to CHOLMOD/MATLAB/Test/other2.m index d884dc2a87..4cf3f5fc4d 100644 --- a/CHOLMOD/MATLAB/Test/n2.m +++ b/CHOLMOD/MATLAB/Test/other2.m @@ -1,9 +1,9 @@ -%N2 script to test CHOLMOD septree function +%OTHER2 script to test CHOLMOD septree function % Example: -% n2 +% other2 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ index = ssget ; @@ -13,7 +13,7 @@ nmat = length (f) ; for i = f - + Prob = ssget (i, index) ; disp (Prob) ; A = spones (Prob.A) ; @@ -22,15 +22,15 @@ clear Prob if (m == n) - mode = 'sym' ; - A = A + A' ; - len = n ; + mode = 'sym' ; + A = A + A' ; + len = n ; elseif (m < n) - mode = 'row' ; - len = m ; + mode = 'row' ; + len = m ; else - mode = 'col' ; - len = n ; + mode = 'col' ; + len = n ; end [p cp cmem] = nesdis (A, mode) ; @@ -38,15 +38,15 @@ subplot (2,4,1) ; treeplot (cp) ; - [cp2 cmem2] = septree (cp, cmem, 0.5, 200) ; %#ok + [cp2 cmem2] = septree (cp, cmem, 0.5, 200) ; %#ok subplot (2,4,2) ; treeplot (cp2) ; - [cp3 cmem3] = septree (cp, cmem, 0.2, 300) ; %#ok + [cp3 cmem3] = septree (cp, cmem, 0.2, 300) ; %#ok subplot (2,4,3) ; treeplot (cp3) ; - [cp4 cmem4] = septree (cp, cmem, 0.12, 500) ; %#ok + [cp4 cmem4] = septree (cp, cmem, 0.12, 500) ; %#ok subplot (2,4,4) ; treeplot (cp4) ; @@ -56,15 +56,15 @@ subplot (2,4,5) ; treeplot (cp) ; - [cp2 cmem2] = septree (cp, cmem, 0.5, 200) ; %#ok + [cp2 cmem2] = septree (cp, cmem, 0.5, 200) ; %#ok subplot (2,4,6) ; treeplot (cp2) ; - [cp3 cmem3] = septree (cp, cmem, 0.2, 300) ; %#ok + [cp3 cmem3] = septree (cp, cmem, 0.2, 300) ; %#ok subplot (2,4,7) ; treeplot (cp3) ; - [cp4 cmem4] = septree (cp, cmem, 0.12, 500) ; %#ok + [cp4 cmem4] = septree (cp, cmem, 0.12, 500) ; %#ok subplot (2,4,8) ; treeplot (cp4) ; diff --git a/CHOLMOD/MATLAB/Test/test0.m b/CHOLMOD/MATLAB/Test/test0.m index 4ce623308f..11820476d1 100644 --- a/CHOLMOD/MATLAB/Test/test0.m +++ b/CHOLMOD/MATLAB/Test/test0.m @@ -4,7 +4,7 @@ function test0 (nmat,f) % test0(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -42,15 +42,19 @@ function test0 (nmat,f) f = f (1:nmat) ; end -% f= 229 +% f = 1283 % err and err3 > 1e-6, in both CHOLMOD and MATLAB below +% f = 1278 % error at phase 4 + +% not positive definite, or errors in various phases +skip = [skip 1892 1278] ; fprintf ('test matrices sorted by dimension:\n') ; for i = f if (any (i == skip)) - continue + continue end fprintf ('%4d: %-20s %-20s %12d %d\n', i, ... - index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; + index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; end % pause @@ -58,18 +62,24 @@ function test0 (nmat,f) for i = f if (any (i == skip)) - continue + continue end % try - Problem = ssget (i) ; - A = Problem.A ; - fprintf ('\n================== Problem: %d: %s n: %d nnz: %d\n', ... - i, Problem.name, size (A,1), nnz (A)) ; - fprintf ('title: %s\n', Problem.title) ; - clear Problem - n = size (A,1) ; + Problem = ssget (i) ; + A = Problem.A ; + fprintf ('\n================== Problem: %d: %s n: %d nnz: %d\n', ... + i, Problem.name, size (A,1), nnz (A)) ; + fprintf ('title: %s\n', Problem.title) ; + clear Problem + n = size (A,1) ; + + [R,f,p] = chol (A) ; + if (f ~= 0) + fprintf ('not positive definite\n') ; + continue ; + end % use AMD from SuiteSparse tic @@ -77,215 +87,227 @@ function test0 (nmat,f) t0 = toc ; fprintf ('time: amd %10.4f\n', t0) ; - S = A (p,p) ; - - if (doplots) - subplot (3,2,1) ; spy (A) ; title ('A original') ; - subplot (3,2,2) ; spy (S) ; title ('A permuted') ; - drawnow ; - end - - % ensure chol, chol2, and lchol are loaded, for more accurate timing - R = chol2 (sparse (1)) ; %#ok - R = chol (sparse (1)) ; %#ok - R = lchol (sparse (1)) ; %#ok - R = ldlchol (sparse (1)) ; %#ok - R = ldlupdate (sparse (1), sparse (1)) ; %#ok - c = symbfact (sparse (1)) ; %#ok - - tic ; - L = lchol (S) ; - t3 = toc ; - if (doplots) - subplot (3,2,5) ; spy (L) ; title ('L=lchol') ; - drawnow ; - end - fprintf ('CHOLMOD time: L=lchol %10.4f nnz(L): %d\n', t3, nnz (L)) ; - lnorm = norm (L, 1) ; - - err = ldl_normest (S, L) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear L - - tic ; - R = chol2 (S) ; - t2 = toc ; - if (doplots) - subplot (3,2,3) ; spy (R) ; title ('R=chol2') ; - drawnow ; - end - fprintf ('CHOLMOD time: R=chol2 %10.4f nnz(R): %d\n', t2, nnz (R)) ; - - err = ldl_normest (S, R') / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear R - - tic ; - R = chol (S) ; - t1 = toc ; - fprintf ('MATLAB time: R=chol %10.4f nnz(R): %d\n', t1, nnz (R)) ; - if (doplots) - subplot (3,2,4) ; spy (R) ; title ('chol') ; - drawnow ; - end - - err = ldl_normest (S, R') / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear R - - tic ; - [count,h,parent,post,R] = symbfact (S) ; - t7 = toc ; - fprintf ('MATLAB [..,R]=symbfact %10.4f nnz(R): %d\n', t7, nnz (R)) ; - - fprintf ('\nCHOLMOD speedup vs MATLAB chol: R: %8.2f L: %8.2f\n\n', ... - t1/t2, t1/t3) ; - - fprintf ('\nCHOLMOD numeric lchol vs MATLAB symbfact: %8.2f\n', t7/t3) ; - - clear R S - - % use AMD or METIS, doing the ordering in CHOLMOD - tic - [L,p,q] = lchol (A) ; - t4 = toc ; - fprintf ('CHOLMOD time: [L,,q]=lchol %10.4f nnz(L): %d\n', ... - t4, nnz (L)) ; - if (doplots) - subplot (3,2,6) ; spy (L) ; title ('[L,p,q]=lchol') ; - drawnow ; - end - - err = ldl_normest (A (q,q), L) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear L - - % try an LDL' factorization, LD has LDL' factorization of S = A(q,q) - tic - [LD,p,q] = ldlchol (A) ; - t5 = toc ; - fprintf ('CHOLMOD time: [L,,q]=ldlchol %10.4f nnz(L): %d\n', ... - t5, nnz (LD)) ; - [L,D] = ldlsplit (LD) ; - S = A (q,q) ; - - err = ldl_normest (S, L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear L D A - - % update the LDL' factorization (rank 1 to 8). Pick a C that has - % the same pattern as a random set of columns of L, so no fill-in - % occurs. Then add one arbitrary entry, to add some fill-in to L. - k = 1 + floor (rand (1) * 8) ; - cols = randperm (n) ; - cols = cols (1:k) ; - C = sprandn (LD (:,cols)) ; - row = 1 + floor (rand (1) * n) ; - C (row,1) = 1 ; - - if (~isreal (C) | ~isreal (LD)) %#ok - fprintf ('skip update/downdate of complex matrix ...\n') ; - continue ; - end - - tic - LD2 = ldlupdate (LD, C) ; - t = toc ; - fprintf ('\nCHOLMOD time: rank-%d ldlupdate %10.4f nnz(L) %d', ... - k, t, nnz (LD2)) ; - - if (nnz (LD2) > nnz (LD)) - fprintf (' with fill-in\n') ; - else - fprintf (' no fill-in\n') ; - end - - % check the factorization, LD2 has LDL' factorization of S+C*C' - [L,D] = ldlsplit (LD2) ; - err = ldl_normest (S + C*C', L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - clear L D - - % downate the LDL' factorization, with just part of C - % no change to the pattern occurs. - k = max (1, floor (k/2)) ; - C1 = C (:, 1:k) ; - C2 = C (:, k+1:end) ; %#ok - tic - LD3 = ldlupdate (LD2, C1, '-') ; - t = toc ; - clear LD2 - fprintf ('CHOLMOD time: rank-%d ldldowndate %10.4f nnz(L) %d', ... - k, t, nnz (LD3)) ; - fprintf (' no fill-in\n') ; - - % check the factorization, LD3 has LDL' factorization of A(q,q)+C2*C2' - [L,D] = ldlsplit (LD3) ; - S2 = S + C*C' - C1*C1' ; - err = ldl_normest (S2, L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - - % now test resymbol - LD4 = resymbol (LD3, S2) ; - [L,D] = ldlsplit (LD4) ; - err = ldl_normest (S2, L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end - fprintf ('after resymbol: %d\n', nnz (LD4)) ; - - % compare resymbol with ldlchol - LD5 = ldlchol (S2) ; - if (nnz (LD5) ~= nnz (LD4)) - error ('!') ; - end + S = A (p,p) ; + + if (doplots) + subplot (3,2,1) ; spy (A) ; title ('A original') ; + subplot (3,2,2) ; spy (S) ; title ('A permuted') ; + drawnow ; + end + + % ensure chol, chol2, and lchol are loaded, for more accurate timing + R = chol2 (sparse (1)) ; %#ok + R = chol (sparse (1)) ; %#ok + R = lchol (sparse (1)) ; %#ok + R = ldlchol (sparse (1)) ; %#ok + R = ldlupdate (sparse (1), sparse (1)) ; %#ok + c = symbfact (sparse (1)) ; %#ok + + tic ; + L = lchol (S) ; + tL_cholmod = toc ; + if (doplots) + subplot (3,2,5) ; spy (L) ; title ('L=lchol') ; + drawnow ; + end + fprintf ('CHOLMOD time: L=lchol %10.4f nnz(L): %d\n', ... + tL_cholmod, nnz (L)) ; + lnorm = norm (L, 1) ; + + tic ; + L2 = chol (S, 'lower') ; + tL_matlab = toc ; + fprintf ('MATLAB time: L=chol %10.4f nnz(L): %d\n', ... + tL_matlab, nnz (L2)) ; + + err = ldl_normest (S, L) / lnorm ; + if (err > 1e-6) + err3 = ldl_normest (S, L2) / lnorm ; + err + err3 + condition_est = condest (S) + if (err > err3 * 1e3) + error ('1!') ; + else + % matrix 1283 triggers this condition + % both err and err3 are 2e-6 + clear L L2 + continue ; + end + end + clear L L2 + + tic ; + R = chol2 (S) ; + tR_cholmod = toc ; + if (doplots) + subplot (3,2,3) ; spy (R) ; title ('R=chol2') ; + drawnow ; + end + fprintf ('CHOLMOD time: R=chol2 %10.4f nnz(R): %d\n', ... + tR_cholmod, nnz (R)) ; + + err = ldl_normest (S, R') / lnorm ; + if (err > 1e-6) + error ('2!') ; + end + clear R + + tic ; + R = chol (S) ; + tR_matlab = toc ; + fprintf ('MATLAB time: R=chol %10.4f nnz(R): %d\n', ... + tR_matlab, nnz (R)) ; + if (doplots) + subplot (3,2,4) ; spy (R) ; title ('chol') ; + drawnow ; + end + + err = ldl_normest (S, R') / lnorm ; + if (err > 1e-6) + error ('3!') ; + end + clear R + + tic ; + [count,h,parent,post,R] = symbfact (S) ; + t7 = toc ; + fprintf ('MATLAB [..,R]=symbfact %10.4f nnz(R): %d\n', t7, nnz (R)) ; + + fprintf ('\nCHOLMOD speedup vs MATLAB chol: R: %8.2f L: %8.2f\n\n', ... + tR_matlab/tR_cholmod, tL_matlab/tL_cholmod) ; + + clear R S + + % use AMD or METIS, doing the ordering in CHOLMOD + tic + [L,p,q] = lchol (A) ; + t4 = toc ; + fprintf ('CHOLMOD time: [L,,q]=lchol %10.4f nnz(L): %d\n', ... + t4, nnz (L)) ; + if (doplots) + subplot (3,2,6) ; spy (L) ; title ('[L,p,q]=lchol') ; + drawnow ; + end + + err = ldl_normest (A (q,q), L) / lnorm ; + if (err > 1e-6) + % matrix 1278 triggers this error (1.4e-6) + err + error ('4!') ; + end + clear L + + % try an LDL' factorization, LD has LDL' factorization of S = A(q,q) + tic + [LD,p,q] = ldlchol (A) ; + t5 = toc ; + fprintf ('CHOLMOD time: [L,,q]=ldlchol %10.4f nnz(L): %d\n', ... + t5, nnz (LD)) ; + [L,D] = ldlsplit (LD) ; + S = A (q,q) ; + + err = ldl_normest (S, L, D) / lnorm ; + if (err > 1e-6) + error ('5!') ; + end + clear L D A + + % update the LDL' factorization (rank 1 to 8). Pick a C that has + % the same pattern as a random set of columns of L, so no fill-in + % occurs. Then add one arbitrary entry, to add some fill-in to L. + k = 1 + floor (rand (1) * 8) ; + cols = randperm (n) ; + cols = cols (1:k) ; + C = sprandn (LD (:,cols)) ; + row = 1 + floor (rand (1) * n) ; + C (row,1) = 1 ; + + if (~isreal (C) | ~isreal (LD)) %#ok + fprintf ('skip update/downdate of complex matrix ...\n') ; + continue ; + end + + tic + LD2 = ldlupdate (LD, C) ; + t = toc ; + fprintf ('\nCHOLMOD time: rank-%d ldlupdate %10.4f nnz(L) %d', ... + k, t, nnz (LD2)) ; + + if (nnz (LD2) > nnz (LD)) + fprintf (' with fill-in\n') ; + else + fprintf (' no fill-in\n') ; + end + + % check the factorization, LD2 has LDL' factorization of S+C*C' + [L,D] = ldlsplit (LD2) ; + err = ldl_normest (S + C*C', L, D) / lnorm ; + if (err > 1e-6) + error ('6!') ; + end + clear L D + + % downate the LDL' factorization, with just part of C + % no change to the pattern occurs. + k = max (1, floor (k/2)) ; + C1 = C (:, 1:k) ; + C2 = C (:, k+1:end) ; %#ok + tic + LD3 = ldlupdate (LD2, C1, '-') ; + t = toc ; + clear LD2 + fprintf ('CHOLMOD time: rank-%d ldldowndate %10.4f nnz(L) %d', ... + k, t, nnz (LD3)) ; + fprintf (' no fill-in\n') ; + + % check the factorization, LD3 has LDL' factorization of A(q,q)+C2*C2' + [L,D] = ldlsplit (LD3) ; + S2 = S + C*C' - C1*C1' ; + err = ldl_normest (S2, L, D) / lnorm ; + if (err > 1e-6) + error ('7!') ; + end + + % now test resymbol + LD4 = resymbol (LD3, S2) ; + [L,D] = ldlsplit (LD4) ; + err = ldl_normest (S2, L, D) / lnorm ; + if (err > 1e-6) + error ('8!') ; + end + fprintf ('after resymbol: %d\n', nnz (LD4)) ; + + % compare resymbol with ldlchol + LD5 = ldlchol (S2) ; + if (nnz (LD5) ~= nnz (LD4)) + error ('9!') ; + end % revised June 30, 2020 if (nnz (GB_spones_mex (LD5) - GB_spones_mex (LD4)) ~= 0) - error ('!') ; + error ('10!') ; end -% if (nnz (spones (LD5) - spones (LD4)) ~= 0) -% % TODO: fails on ssget (878) because MATLAB changed spones(...). -% LD5 (262,246) -% LD4 (262,246) -% spones (LD5) - spones (LD4) -% error ('!') ; -% end - - b = rand (n,2) ; - x = ldlsolve (LD4, b) ; - err1 = norm (S2*x-b,1) / norm (S,1) ; + b = rand (n,2) ; + x = ldlsolve (LD4, b) ; + err1 = norm (S2*x-b,1) / norm (S,1) ; - fprintf ('CHOLMOD residual: %6.1e\n', err1) ; + fprintf ('CHOLMOD residual: %6.1e\n', err1) ; - x = S2\b ; - err2 = norm (S2*x-b,1) / norm (S,1) ; - fprintf ('MATLAB residual: %6.1e\n', err2) ; + x = S2\b ; + err2 = norm (S2*x-b,1) / norm (S,1) ; + fprintf ('MATLAB residual: %6.1e\n', err2) ; - b = sprandn (n,3,0.4) ; - x = ldlsolve (LD4, b) ; - err1 = norm (S2*x-b,1) / norm (S,1) ; + b = sprandn (n,3,0.4) ; + x = ldlsolve (LD4, b) ; + err1 = norm (S2*x-b,1) / norm (S,1) ; - fprintf ('CHOLMOD residual: %6.1e (sparse b)\n', err1) ; + fprintf ('CHOLMOD residual: %6.1e (sparse b)\n', err1) ; - x = S2\b ; - err2 = norm (S2*x-b,1) / norm (S,1) ; - fprintf ('MATLAB residual: %6.1e (sparse b)\n', err2) ; + x = S2\b ; + err2 = norm (S2*x-b,1) / norm (S,1) ; + fprintf ('MATLAB residual: %6.1e (sparse b)\n', err2) ; % ---------------------------------------------------------------------- % test the row delete @@ -293,20 +315,20 @@ function test0 (nmat,f) tic LD6 = ldlrowmod (LD,k) ; t6 = toc ; - fprintf ('\nCHOLMOD time: ldlrowmod, delete %10.4f nnz(L) %d', ... - t6, nnz (LD6)) ; + fprintf ('\nCHOLMOD time: ldlrowmod, delete %10.4f nnz(L) %d', ... + t6, nnz (LD6)) ; I = speye (n) ; S2 = S ; S2 (k,:) = I (k,:) ; S2 (:,k) = I (:,k) ; - % check the factorization, LD6 has LDL' factorization of S2 - [L,D] = ldlsplit (LD6) ; - err = ldl_normest (S2, L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end + % check the factorization, LD6 has LDL' factorization of S2 + [L,D] = ldlsplit (LD6) ; + err = ldl_normest (S2, L, D) / lnorm ; + if (err > 1e-6) + error ('11!') ; + end % test the row add, by adding the row back in again Ck = S (:,k) ; @@ -316,20 +338,20 @@ function test0 (nmat,f) tic LD7 = ldlrowmod (LD6,k,Ck) ; t7 = toc ; - fprintf ('\nCHOLMOD time: ldlrowmod, add %10.4f nnz(L) %d', ... - t7, nnz (LD7)) ; - - % check the factorization, LD7 has LDL' factorization of S - [L,D] = ldlsplit (LD7) ; - err = ldl_normest (S, L, D) / lnorm ; - if (err > 1e-6) - error ('!') ; - end + fprintf ('\nCHOLMOD time: ldlrowmod, add %10.4f nnz(L) %d', ... + t7, nnz (LD7)) ; + + % check the factorization, LD7 has LDL' factorization of S + [L,D] = ldlsplit (LD7) ; + err = ldl_normest (S, L, D) / lnorm ; + if (err > 1e-6) + error ('12!') ; + end % ---------------------------------------------------------------------- % catch - % fprintf ('failed\n') ; + % fprintf ('failed\n') ; % end clear A S C L R LD LD2 LD3 D p q C1 C2 LD3 S2 LD4 b x LD5 I LDL6 LD7 Ck diff --git a/CHOLMOD/MATLAB/Test/test1.m b/CHOLMOD/MATLAB/Test/test1.m deleted file mode 100644 index f79edc6050..0000000000 --- a/CHOLMOD/MATLAB/Test/test1.m +++ /dev/null @@ -1,85 +0,0 @@ -function test1 (wait) -%TEST1 test sparse2 -% Example: -% test1 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test1: test sparse2\n') ; - -if (nargin == 0) - wait = 0 ; -end - -m = 3 ; -n = 4 ; - -ii = { 1, [2 3]', 2, [ ] } ; -jj = { 1, [2 3]', 3, [ ] } ; -ss = { 1, [2 3]', pi, [ ] } ; - -for ki = 1:length (ii) - for kj = 1:length (jj) - for ks = 1:length (ss) - - fprintf ('\n-----------------------------------------------\n') ; - i = ii {ki} %#ok - j = jj {kj} %#ok - s = ss {ks} %#ok - m %#ok - n %#ok - clear A1 A2 B1 B2 - - fprintf ('\nA1 = sparse (i,j,s,m,n)\n') ; - try % sparse, possibly with invalid inputs - A1 = sparse (i,j,s,m,n) %#ok - fprintf ('size A1: %d %d\n', size (A1)) ; - catch - A1 = 'A failed' ; - fprintf ('sparse failed\n') ; - end - - fprintf ('\nA2 = sparse2 (i,j,s,m,n)\n') ; - try % sparse2, possibly with invalid inputs - A2 = sparse2 (i,j,s,m,n) %#ok - fprintf ('size A2: %d %d\n', size (A2)) ; - catch - A2 = 'A failed' ; - fprintf ('sparse2 failed\n') ; - end - - fprintf ('\nB1 = sparse (i,j,s)\n') ; - try % sparse, possibly with invalid inputs - B1 = sparse (i,j,s) %#ok - fprintf ('size B1: %d %d\n', size (B1)) ; - catch - B1 = 'B failed' ; - fprintf ('sparse failed\n') ; - end - - fprintf ('\nB2 = sparse2 (i,j,s)\n') ; - try % sparse2, possibly with invalid inputs - B2 = sparse2 (i,j,s) %#ok - fprintf ('size B2: %d %d\n', size (B2)) ; - catch - B2 = 'B failed' ; - fprintf ('sparse2 failed\n') ; - end - - if (wait) - pause - end - - if (~isequal (A1,A2) | ~isequal (B1,B2)) %#ok - fprintf (... - '========================== SPARSE AND SPARSE2 DIFFER\n') ; - end - - end - end -end - -fprintf ('test1 passed (review the above results)\n') ; diff --git a/CHOLMOD/MATLAB/Test/test10.m b/CHOLMOD/MATLAB/Test/test10.m index 809e441fb6..c1998f1efc 100644 --- a/CHOLMOD/MATLAB/Test/test10.m +++ b/CHOLMOD/MATLAB/Test/test10.m @@ -4,7 +4,7 @@ function test10 (nmat) % test10(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -31,10 +31,10 @@ function test10 (nmat) fprintf ('test matrices sorted by dimension:\n') ; for i = f if (any (i == skip)) - continue + continue end fprintf ('%4d: %-20s %-20s %12d %d\n', i, ... - index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; + index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; end @@ -42,84 +42,84 @@ function test10 (nmat) % for nn = 23 if (any (nn == skip)) - continue + continue end % try - for complexity = 0:1 - - if nn < 0 - n = -nn ; - A = rand (n) + (complexity * rand(n) * 1i) ; - A=A*A' ; - full (A) - A = sparse (A) ; - - elseif (nn == 0) - - i = 1i ; - A = [ 11 4-i 1+i 2+2*i - 4+i 22 0 0 - 1-i 0 33 0 - 2-2*i 0 0 44 ] ; - A = sparse (A) ; - p = [4 3 2 1] ; %#ok - full (A) - A = sparse (A) ; - - else - - if (~complexity) - nn %#ok - Prob = ssget (nn) %#ok - end - A = Prob.A ; - if (complexity) - A = A / norm(A,1) ; - Z = .1 * sprandn (A) * 1i ; - Z = Z+Z' ; - A = A + Z ; - A = A + norm(A,1) * speye (size(A,1)) ; - end - n = size (A,1) ; - end - - for sparsity = 0:1 - - if (sparsity) - b = sprandn (n,4,0.1) ; - else - b = rand (n,4) ; - end - - b1 = b (:,1) ; - - [x1,x2,e1,e2] = testsolve (A,b1) ; %#ok - [x1,x2,e1,e2] = testsolve (A,b) ; %#ok - - if (sparsity) - b = sprandn (n,9,0.1) ; - else - b = rand (n,9) ; - end - - [x1,x2,e1,e2] = testsolve (A,b) ; %#ok - - if (sparsity) - b = sprandn (n,9,0.1) + sprandn (n,9,0.1)*1i ; - else - b = rand (n,9) + rand(n,9)*1i ; - end - - b1 = b (:,1) ; - - [x1,x2,e1,e2] = testsolve (A,b1) ; %#ok - [x1,x2,e1,e2] = testsolve (A,b) ; %#ok - - end - end + for complexity = 0:1 + + if nn < 0 + n = -nn ; + A = rand (n) + (complexity * rand(n) * 1i) ; + A=A*A' ; + full (A) + A = sparse (A) ; + + elseif (nn == 0) + + i = 1i ; + A = [ 11 4-i 1+i 2+2*i + 4+i 22 0 0 + 1-i 0 33 0 + 2-2*i 0 0 44 ] ; + A = sparse (A) ; + p = [4 3 2 1] ; %#ok + full (A) + A = sparse (A) ; + + else + + if (~complexity) + nn %#ok + Prob = ssget (nn) %#ok + end + A = Prob.A ; + if (complexity) + A = A / norm(A,1) ; + Z = .1 * sprandn (A) * 1i ; + Z = Z+Z' ; + A = A + Z ; + A = A + norm(A,1) * speye (size(A,1)) ; + end + n = size (A,1) ; + end + + for sparsity = 0:1 + + if (sparsity) + b = sprandn (n,4,0.1) ; + else + b = rand (n,4) ; + end + + b1 = b (:,1) ; + + [x1,x2,e1,e2] = testsolve (A,b1) ; %#ok + [x1,x2,e1,e2] = testsolve (A,b) ; %#ok + + if (sparsity) + b = sprandn (n,9,0.1) ; + else + b = rand (n,9) ; + end + + [x1,x2,e1,e2] = testsolve (A,b) ; %#ok + + if (sparsity) + b = sprandn (n,9,0.1) + sprandn (n,9,0.1)*1i ; + else + b = rand (n,9) + rand(n,9)*1i ; + end + + b1 = b (:,1) ; + + [x1,x2,e1,e2] = testsolve (A,b1) ; %#ok + [x1,x2,e1,e2] = testsolve (A,b) ; %#ok + + end + end % catch - % fprintf (' failed\n') ; + % fprintf (' failed\n') ; % end end diff --git a/CHOLMOD/MATLAB/Test/test11.m b/CHOLMOD/MATLAB/Test/test11.m index 4b659c940b..150d72adc7 100644 --- a/CHOLMOD/MATLAB/Test/test11.m +++ b/CHOLMOD/MATLAB/Test/test11.m @@ -5,7 +5,7 @@ function test11 (nmat) % test11(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -34,101 +34,101 @@ function test11 (nmat) fprintf ('test matrices sorted by dimension:\n') ; for i = f if (any (i == skip)) - continue + continue end fprintf ('%4d: %-20s %-20s %12d %d\n', i, ... - index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; + index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; end kk = 0 ; nmat = length (f) ; -T1 = zeros (1,nmat) ; % matlab time -T2 = zeros (1,nmat) ; % cholmod2 time -E1 = zeros (1,nmat) ; % matlab residual -E2 = zeros (1,nmat) ; % cholmod2 residual -FL = zeros (1,nmat) ; % cholmod2 flop count -LNZ = zeros (1,nmat) ; % cholmod2 lnz +T1 = zeros (1,nmat) ; % matlab time +T2 = zeros (1,nmat) ; % cholmod2 time +E1 = zeros (1,nmat) ; % matlab residual +E2 = zeros (1,nmat) ; % cholmod2 residual +FL = zeros (1,nmat) ; % cholmod2 flop count +LNZ = zeros (1,nmat) ; % cholmod2 lnz for kkk = 1:length(f) nn = f (kkk) ; if (any (nn == skip)) - continue + continue end % try - fprintf ('\n%3d: %s/%s\n', nn, index.Group {nn}, index.Name {nn}) ; - Prob = ssget (nn) ; - A = Prob.A ; - clear Prob - n = size (A,1) ; - b = rand (n,1) ; - - % analyze - [p count] = analyze (A) ; - % LDL' flop count - % fl = sum ((count-1).*(count-1) + 2*(count-1)) ; - % LL' flop count - fl = sum (count.^2) ; - lnz = sum (count) ; - fprintf ('n %d lnz %g fl %g\n', n, lnz, fl) ; - clear p count - - % try - k2 = 0 ; - t2 = 0 ; - while (t2 < 1) - tic - x = cholmod2 (A,b) ; - t = toc ; - t2 = t2 + t ; - k2 = k2 + 1 ; - end - t2 = t2 / k2 ; - e2 = norm (A*x-b,1) ; - % catch - % e2 = Inf ; - % k2 = Inf ; - % t2 = Inf ; - % end - fprintf ('cholmod2: t: %10.5f e: %6.1e mflop %6.0f\n', ... - t2, e2, 1e-6 * fl / t2) ; - - % try - k1 = 0 ; - t1 = 0 ; - while (t1 < 1) - tic - x = A\b ; - t = toc ; - t1 = t1 + t ; - k1 = k1 + 1 ; - end - t1 = t1 / k1 ; - e1 = norm (A*x-b,1) ; - % catch - % e1 = Inf ; - % k1 = Inf ; - % t1 = Inf ; - % end - fprintf ('matlab: t: %10.5f e: %6.1e mflop %6.0f', ... - t1, e1, 1e-6 * fl / t1) ; - - fprintf (' cholmod2 speedup: %5.1f\n', t1/t2) ; - - kk = kk + 1 ; - T1 (kk) = t1 ; - T2 (kk) = t2 ; - E1 (kk) = e1 ; - E2 (kk) = e2 ; - FL (kk) = fl ; - LNZ (kk) = lnz ; - %%% save Results T1 T2 E1 E2 FL LNZ f kkk + fprintf ('\n%3d: %s/%s\n', nn, index.Group {nn}, index.Name {nn}) ; + Prob = ssget (nn) ; + A = Prob.A ; + clear Prob + n = size (A,1) ; + b = rand (n,1) ; + + % analyze + [p count] = analyze (A) ; + % LDL' flop count + % fl = sum ((count-1).*(count-1) + 2*(count-1)) ; + % LL' flop count + fl = sum (count.^2) ; + lnz = sum (count) ; + fprintf ('n %d lnz %g fl %g\n', n, lnz, fl) ; + clear p count + + % try + k2 = 0 ; + t2 = 0 ; + while (t2 < 1) + tic + x = cholmod2 (A,b) ; + t = toc ; + t2 = t2 + t ; + k2 = k2 + 1 ; + end + t2 = t2 / k2 ; + e2 = norm (A*x-b,1) ; + % catch + % e2 = Inf ; + % k2 = Inf ; + % t2 = Inf ; + % end + fprintf ('cholmod2: t: %10.5f e: %6.1e gflop %6.1f\n', ... + t2, e2, 1e-9 * fl / t2) ; + + % try + k1 = 0 ; + t1 = 0 ; + while (t1 < 1) + tic + x = A\b ; + t = toc ; + t1 = t1 + t ; + k1 = k1 + 1 ; + end + t1 = t1 / k1 ; + e1 = norm (A*x-b,1) ; + % catch + % e1 = Inf ; + % k1 = Inf ; + % t1 = Inf ; + % end + fprintf ('matlab: t: %10.5f e: %6.1e gflop %6.1f', ... + t1, e1, 1e-9 * fl / t1) ; + + fprintf (' cholmod2 speedup: %5.1f\n', t1/t2) ; + + kk = kk + 1 ; + T1 (kk) = t1 ; + T2 (kk) = t2 ; + E1 (kk) = e1 ; + E2 (kk) = e2 ; + FL (kk) = fl ; + LNZ (kk) = lnz ; + %%% save Results T1 T2 E1 E2 FL LNZ f kkk % catch - % fprintf (' failed\n') ; + % fprintf (' failed\n') ; % end clear A x b diff --git a/CHOLMOD/MATLAB/Test/test11results.m b/CHOLMOD/MATLAB/Test/test11results.m index 08eb13e442..c54c13fd24 100644 --- a/CHOLMOD/MATLAB/Test/test11results.m +++ b/CHOLMOD/MATLAB/Test/test11results.m @@ -4,7 +4,7 @@ % test11results % See also test11, cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ load Results @@ -12,8 +12,8 @@ c = E1(1:kkk) < 1 & T1(1:kkk) > 0 ; m = E2(1:kkk) < 1 & T2(1:kkk) > 0 ; -cgood = find (c) ; %#ok -mgood = find (m) ; %#ok +cgood = find (c) ; %#ok +mgood = find (m) ; %#ok good = find (c | m) ; bad = find (~(c|m)) ; @@ -27,18 +27,18 @@ for k = good i = f (k) ; % fprintf ('%4d: t1 %10.2f t2 %10.2f fl %6.1e lnz %6.1e %s/%s\n', ... -% i, T1(k), T2(k), FL(k), LNZ(k), index.Group{i}, index.Name{i}) ; +% i, T1(k), T2(k), FL(k), LNZ(k), index.Group{i}, index.Name{i}) ; fprintf ('%10.4f %10.4f %6.1e %6.1e %5.2f %s/%s\n', ... - T1(k), T2(k), FL(k), LNZ(k), speedup(k), ... - index.Group{i}, index.Name{i}) ; + T1(k), T2(k), FL(k), LNZ(k), speedup(k), ... + index.Group{i}, index.Name{i}) ; end fprintf ('\nfailed in both:\n') ; for k = bad i = f (k) ; fprintf ('%10.4f %10.4f %6.1e %6.1e %5.2f %s/%s\n', ... - T1(k), T2(k), FL(k), LNZ(k), speedup(k), ... - index.Group{i}, index.Name{i}) ; + T1(k), T2(k), FL(k), LNZ(k), speedup(k), ... + index.Group{i}, index.Name{i}) ; end clf diff --git a/CHOLMOD/MATLAB/Test/test12.m b/CHOLMOD/MATLAB/Test/test12.m index fd7ebe858a..968d57392b 100644 --- a/CHOLMOD/MATLAB/Test/test12.m +++ b/CHOLMOD/MATLAB/Test/test12.m @@ -4,7 +4,7 @@ function test12 (nmat) % test12(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -29,9 +29,9 @@ function test12 (nmat) % MATLAB 7.0 (R14, sp2, linux) etree gives a segfault for these matrices: s_skip = [ 803 374 1287 1311 1308 957 958 1257 955 761 1282 1230 1256 ... - 924 1302 537 820 821 822 1258 ... - 844 845 1238 804 939 1270 1305 1208 1209 290 879 928 1307 1244 ... - 1275 1276 1296 885 1269 959 542 1290 ] ; + 924 1302 537 820 821 822 1258 ... + 844 845 1238 804 939 1270 1305 1208 1209 290 879 928 1307 1244 ... + 1275 1276 1296 885 1269 959 542 1290 ] ; sym_skip = s_skip ; @@ -41,12 +41,12 @@ function test12 (nmat) symt_skip= [ s_skip 592 593 809 ] ; rowcol_skip = [ 646 ... - 1224 803 588 589 374 1287 562 563 801 1311 1246 951 1308 950 ... - 957 958 800 1257 564 565 955 761 1282 590 591 1230 1256 952 566 ... - 567 924 1302 1293 1294 537 820 821 822 1306 849 1258 592 593 ... - 1225 844 845 1226 1238 1227 804 939 1270 752 753 1305 809 1228 ... - 1208 1209 1291 1292 1300 856 1229 290 879 928 1307 857 1244 ... - 1275 1276 1296 885 858 859 1269 1263 959 542 1290 ] ; + 1224 803 588 589 374 1287 562 563 801 1311 1246 951 1308 950 ... + 957 958 800 1257 564 565 955 761 1282 590 591 1230 1256 952 566 ... + 567 924 1302 1293 1294 537 820 821 822 1306 849 1258 592 593 ... + 1225 844 845 1226 1238 1227 804 939 1270 752 753 1305 809 1228 ... + 1208 1209 1291 1292 1300 856 1229 290 879 928 1307 857 1244 ... + 1275 1276 1296 885 858 859 1269 1263 959 542 1290 ] ; col_skip = [ rowcol_skip 647 612 610 648 799 651 652 750 751 640 ] ; @@ -61,154 +61,154 @@ function test12 (nmat) % try - Problem = ssget (i) ; - A = spones (Problem.A) ; - [m n] = size (A) ; - fprintf ('\n%4d: %-20s nrow: %6d ncol: %6d nnz: %10d\n', ... - i, Problem.name, m, n, nnz(A)) ; - - % if (max (m,n) < 500) - % A = full (A) ; - % end - - % warmup, for accurate timing - etree (sparse (1)) ; - etree2 (sparse (1)) ; - amd2 (sparse (1)) ; - - % test column etree - skip = any (i == col_skip) | m > 109000 ; %#ok - if (~skip) - tic ; - [parent post] = etree (A, 'col') ; - t1 = toc ; - else - t1 = Inf ; - end - - tic ; - [my_parent my_post] = etree2 (A, 'col') ; - t2 = toc ; - - if (~skip) - if (any (parent ~= my_parent)) - error ('parent invalid!') ; - end - end - fprintf ('etree(A,''col''): %8.4f %8.4f speedup %8.2f ',... - t1, t2, t1/t2); - if (~skip) - if (any (post ~= my_post)) - fprintf ('postorder differs') ; - end - end - fprintf ('\n') ; - - % test row etree - skip = any (i == row_skip) | m > 109000 ; %#ok - if (~skip) - tic ; - [parent post] = etree (A', 'col') ; - t1 = toc ; - else - t1 = Inf ; - end - - tic ; - [my_parent my_post] = etree2 (A, 'row') ; - t2 = toc ; - - if (~skip) - if (any (parent ~= my_parent)) - error ('parent invalid!') ; - end - end - fprintf ('etree(A,''row''): %8.4f %8.4f speedup %8.2f ',... - t1, t2, t1/t2); - if (~skip) - if (any (post ~= my_post)) - fprintf ('postorder differs') ; - end - end - fprintf ('\n') ; - - - - if (m == n) - - for trial = 1:2 - - if (trial == 1) - skip1 = any (i == sym_skip) | m > 109000 ; %#ok - skip2 = any (i == symt_skip) | m > 109000 ; %#ok - else - skip1 = any (i == p_sym_skip) | m > 109000 ; %#ok - skip2 = any (i == p_symt_skip) | m > 109000 ; %#ok - fprintf ('after amd:\n') ; - p = amd2 (A) ; % use AMD from SuiteSparse - A = A (p,p) ; - end - - % test symmetric etree, using triu(A) - if (~skip1) - tic ; - [parent post] = etree (A) ; - t1 = toc ; - else - t1 = Inf ; - end - - tic ; - [my_parent my_post] = etree2 (A) ; - t2 = toc ; - - if (~skip1) - if (any (parent ~= my_parent)) - error ('parent invalid!') ; - end - end - fprintf ('etree(A): %8.4f %8.4f speedup %8.2f ',... - t1, t2, t1/t2); - if (~skip1) - if (any (post ~= my_post)) - fprintf ('postorder differs') ; - end - end - fprintf ('\n') ; - - % test symmetric etree, using tril(A) - if (~skip2) - tic ; - [parent post] = etree (A') ; - t1 = toc ; - else - t1 = Inf ; - end - - tic ; - [my_parent my_post] = etree2 (A, 'lo') ; - t2 = toc ; - - if (~skip2) - if (any (parent ~= my_parent)) - error ('parent invalid!') ; - end - end - fprintf('etree(A''): %8.4f %8.4f speedup %8.2f ',... - t1, t2, t1/t2); - if (~skip2) - if (any (post ~= my_post)) - fprintf ('postorder differs') ; - end - end - fprintf ('\n') ; - - end - - end + Problem = ssget (i) ; + A = spones (Problem.A) ; + [m n] = size (A) ; + fprintf ('\n%4d: %-20s nrow: %6d ncol: %6d nnz: %10d\n', ... + i, Problem.name, m, n, nnz(A)) ; + + % if (max (m,n) < 500) + % A = full (A) ; + % end + + % warmup, for accurate timing + etree (sparse (1)) ; + etree2 (sparse (1)) ; + amd2 (sparse (1)) ; + + % test column etree + skip = any (i == col_skip) | m > 109000 ; %#ok + if (~skip) + tic ; + [parent post] = etree (A, 'col') ; + t1 = toc ; + else + t1 = Inf ; + end + + tic ; + [my_parent my_post] = etree2 (A, 'col') ; + t2 = toc ; + + if (~skip) + if (any (parent ~= my_parent)) + error ('parent invalid!') ; + end + end + fprintf ('etree(A,''col''): %8.4f %8.4f speedup %8.2f ',... + t1, t2, t1/t2); + if (~skip) + if (any (post ~= my_post)) + fprintf ('postorder differs') ; + end + end + fprintf ('\n') ; + + % test row etree + skip = any (i == row_skip) | m > 109000 ; %#ok + if (~skip) + tic ; + [parent post] = etree (A', 'col') ; + t1 = toc ; + else + t1 = Inf ; + end + + tic ; + [my_parent my_post] = etree2 (A, 'row') ; + t2 = toc ; + + if (~skip) + if (any (parent ~= my_parent)) + error ('parent invalid!') ; + end + end + fprintf ('etree(A,''row''): %8.4f %8.4f speedup %8.2f ',... + t1, t2, t1/t2); + if (~skip) + if (any (post ~= my_post)) + fprintf ('postorder differs') ; + end + end + fprintf ('\n') ; + + + + if (m == n) + + for trial = 1:2 + + if (trial == 1) + skip1 = any (i == sym_skip) | m > 109000 ; %#ok + skip2 = any (i == symt_skip) | m > 109000 ; %#ok + else + skip1 = any (i == p_sym_skip) | m > 109000 ; %#ok + skip2 = any (i == p_symt_skip) | m > 109000 ; %#ok + fprintf ('after amd:\n') ; + p = amd2 (A) ; % use AMD from SuiteSparse + A = A (p,p) ; + end + + % test symmetric etree, using triu(A) + if (~skip1) + tic ; + [parent post] = etree (A) ; + t1 = toc ; + else + t1 = Inf ; + end + + tic ; + [my_parent my_post] = etree2 (A) ; + t2 = toc ; + + if (~skip1) + if (any (parent ~= my_parent)) + error ('parent invalid!') ; + end + end + fprintf ('etree(A): %8.4f %8.4f speedup %8.2f ',... + t1, t2, t1/t2); + if (~skip1) + if (any (post ~= my_post)) + fprintf ('postorder differs') ; + end + end + fprintf ('\n') ; + + % test symmetric etree, using tril(A) + if (~skip2) + tic ; + [parent post] = etree (A') ; + t1 = toc ; + else + t1 = Inf ; + end + + tic ; + [my_parent my_post] = etree2 (A, 'lo') ; + t2 = toc ; + + if (~skip2) + if (any (parent ~= my_parent)) + error ('parent invalid!') ; + end + end + fprintf('etree(A''): %8.4f %8.4f speedup %8.2f ',... + t1, t2, t1/t2); + if (~skip2) + if (any (post ~= my_post)) + fprintf ('postorder differs') ; + end + end + fprintf ('\n') ; + + end + + end % catch - % fprintf ('%d: failed\n', i) ; + % fprintf ('%d: failed\n', i) ; % end end diff --git a/CHOLMOD/MATLAB/Test/test13.m b/CHOLMOD/MATLAB/Test/test13.m index 384521685a..aa1fff2a94 100644 --- a/CHOLMOD/MATLAB/Test/test13.m +++ b/CHOLMOD/MATLAB/Test/test13.m @@ -4,7 +4,7 @@ % test13 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); diff --git a/CHOLMOD/MATLAB/Test/test14.m b/CHOLMOD/MATLAB/Test/test14.m index 794ce70668..e760d7e02b 100644 --- a/CHOLMOD/MATLAB/Test/test14.m +++ b/CHOLMOD/MATLAB/Test/test14.m @@ -4,7 +4,7 @@ function test14 (nmat) % test14(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -20,9 +20,9 @@ function test14 (nmat) % These bugs show up when Common->metis_memory is set to zero: % skip = [ 1298 ] ; % runs out of memory in metis(A,'row') -skip = 1257 ; %#ok % GHS_psdef/crankseg_1: segfault in metis(A,'row') ; -skip = 850 ; %#ok % Chen/pkustk04: segfault in metis(A,'row') ; -skip = [ ] ; %#ok +skip = 1257 ; %#ok % GHS_psdef/crankseg_1: segfault in metis(A,'row') ; +skip = 850 ; %#ok % Chen/pkustk04: segfault in metis(A,'row') ; +skip = [ ] ; %#ok if (nargin > 0) nmat = max (0,nmat) ; @@ -34,93 +34,93 @@ function test14 (nmat) fprintf ('%d:\n', i) ; if (any (skip == i)) - fprintf ('skip %s / %s\n', index.Group {i}, index.Name {i}) ; - continue + fprintf ('skip %s / %s\n', index.Group {i}, index.Name {i}) ; + continue end % try - Prob = ssget (i) %#ok - A = Prob.A ; - [m n] = size (A) ; - - if (m == n) - S = spones (A) ; - else - n = min (m,n) ; - S = spones (A (1:n,1:n)) ; - end - - try % compute nnz(S*S') - nzaat = nnz (S*S') ; - catch - nzaat = -1 ; - end - try % compute nnz(S'*S) - nzata = nnz (S'*S) ; - catch - nzata = -1 ; - end - S = S | S' ; - - fprintf ('nnz(A) %d\n', nnz (A)) ; - fprintf ('nnz(S) %d\n', nnz (S)) ; - fprintf ('nnz(A*A'') %d\n', nzaat) ; - fprintf ('nnz(A''*A) %d\n', nzata) ; - - fprintf ('metis (S):\n') ; p1 = metis (S) ; - fprintf ('metis (A,row):\n') ; p2 = metis (A, 'row') ; - fprintf ('metis (A,col):\n') ; p3 = metis (A, 'col') ; - - fprintf ('turning off postorder:\n') ; - fprintf ('metis (S):\n') ; n1 = metis (S, 'sym', 'no postorder') ; - fprintf ('metis (A,row):\n') ; n2 = metis (A, 'row', 'no postorder') ; - fprintf ('metis (A,col):\n') ; n3 = metis (A, 'col', 'no postorder') ; - - fprintf ('analyzing results:\n') ; - - [pa1 po1] = etree2 (S (n1,n1)) ; - [pa2 po2] = etree2 (A (n2,:), 'row') ; - [pa3 po3] = etree2 (A (:,n3), 'col') ; - - q1 = n1 (po1) ; - q2 = n2 (po2) ; - q3 = n3 (po3) ; - - if (any (p1 ~= q1)) - error ('1!') ; - end - - if (any (p2 ~= q2)) - error ('2!') ; - end - - if (any (p3 ~= q3)) - error ('3!') ; - end - - s1 = symbfact2 (S (p1,p1)) ; - s2 = symbfact2 (A (p2,:), 'row') ; - s3 = symbfact2 (A (:,p3), 'col') ; - - t1 = symbfact2 (S (n1,n1)) ; - t2 = symbfact2 (A (n2,:), 'row') ; - t3 = symbfact2 (A (:,n3), 'col') ; - - if (any (s1 ~= t1 (po1))) - error ('s1!') ; - end - - if (any (s2 ~= t2 (po2))) - error ('s2!') ; - end - - if (any (s3 ~= t3 (po3))) - error ('s3!') ; - end + Prob = ssget (i) %#ok + A = Prob.A ; + [m n] = size (A) ; + + if (m == n) + S = spones (A) ; + else + n = min (m,n) ; + S = spones (A (1:n,1:n)) ; + end + + try % compute nnz(S*S') + nzaat = nnz (S*S') ; + catch + nzaat = -1 ; + end + try % compute nnz(S'*S) + nzata = nnz (S'*S) ; + catch + nzata = -1 ; + end + S = S | S' ; + + fprintf ('nnz(A) %d\n', nnz (A)) ; + fprintf ('nnz(S) %d\n', nnz (S)) ; + fprintf ('nnz(A*A'') %d\n', nzaat) ; + fprintf ('nnz(A''*A) %d\n', nzata) ; + + fprintf ('metis (S):\n') ; p1 = metis (S) ; + fprintf ('metis (A,row):\n') ; p2 = metis (A, 'row') ; + fprintf ('metis (A,col):\n') ; p3 = metis (A, 'col') ; + + fprintf ('turning off postorder:\n') ; + fprintf ('metis (S):\n') ; n1 = metis (S, 'sym', 'no postorder') ; + fprintf ('metis (A,row):\n') ; n2 = metis (A, 'row', 'no postorder') ; + fprintf ('metis (A,col):\n') ; n3 = metis (A, 'col', 'no postorder') ; + + fprintf ('analyzing results:\n') ; + + [pa1 po1] = etree2 (S (n1,n1)) ; + [pa2 po2] = etree2 (A (n2,:), 'row') ; + [pa3 po3] = etree2 (A (:,n3), 'col') ; + + q1 = n1 (po1) ; + q2 = n2 (po2) ; + q3 = n3 (po3) ; + + if (any (p1 ~= q1)) + error ('1!') ; + end + + if (any (p2 ~= q2)) + error ('2!') ; + end + + if (any (p3 ~= q3)) + error ('3!') ; + end + + s1 = symbfact2 (S (p1,p1)) ; + s2 = symbfact2 (A (p2,:), 'row') ; + s3 = symbfact2 (A (:,p3), 'col') ; + + t1 = symbfact2 (S (n1,n1)) ; + t2 = symbfact2 (A (n2,:), 'row') ; + t3 = symbfact2 (A (:,n3), 'col') ; + + if (any (s1 ~= t1 (po1))) + error ('s1!') ; + end + + if (any (s2 ~= t2 (po2))) + error ('s2!') ; + end + + if (any (s3 ~= t3 (po3))) + error ('s3!') ; + end % catch - % fprintf ('%d failed\n') ; + % fprintf ('%d failed\n') ; % end end diff --git a/CHOLMOD/MATLAB/Test/test15.m b/CHOLMOD/MATLAB/Test/test15.m index 359bf5e3c4..b4352a5cfc 100644 --- a/CHOLMOD/MATLAB/Test/test15.m +++ b/CHOLMOD/MATLAB/Test/test15.m @@ -4,7 +4,7 @@ function test15 (nmat) % test15(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -32,119 +32,119 @@ function test15 (nmat) % try - Problem = ssget (i) ; - A = spones (Problem.A) ; - [m n] = size (A) ; - fprintf ('\n%4d: %-20s nrow: %6d ncol: %6d nnz: %10d\n', ... - i, Problem.name, m, n, nnz(A)) ; - - % warmup, for accurate timing - etree (sparse (1)) ; - etree2 (sparse (1)) ; - amd2 (sparse (1)) ; - symbfact (sparse (1)) ; - symbfact2 (sparse (1)) ; - - % test symmetric case - if (m == n) - - % permute the matrix first - p = amd2 (A) ; - A = A (p,p) ; - - % test with triu(A) - tic - co = symbfact (A) ; - t1 = toc ; - tic - co2 = symbfact2 (A) ; - t2 = toc ; - - fprintf ('c=symbfact(A): %10.4f %10.4f speedup %8.2f lnz %d\n', ... - t1, t2, t1/t2, sum (co)) ; - - if (any (co ~= co2)) - error ('!') ; - end - - tic - [co h parent post R] = symbfact (A) ; - t1 = toc ; - tic - [co2 h2 parent2 post2 R2] = symbfact2 (A) ; - t2 = toc ; - - fprintf ('R=symbfact(A): %10.4f %10.4f speedup %8.2f\n',... - t1, t2, t1/t2) ; - - checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; - - % test with tril(A) - tic - co = symbfact (A') ; - t1 = toc ; - tic - co2 = symbfact2 (A,'lo') ; - t2 = toc ; - - fprintf (... - 'c=symbfact(A''): %10.4f %10.4f speedup %8.2f lnz %d\n',... - t1, t2, t1/t2, sum (co)) ; - - if (any (co ~= co2)) - error ('!') ; - end - - tic - [co h parent post R] = symbfact (A') ; - t1 = toc ; - tic - [co2 h2 parent2 post2 R2] = symbfact2 (A,'lo') ; - t2 = toc ; - - fprintf (... - 'R=symbfact(A''): %10.4f %10.4f speedup %8.2f\n',... - t1, t2, t1/t2) ; - - checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; - - end - - % permute the matrix first - p = colamd (A) ; - [parent post] = etree2 (A (:,p), 'col') ; - p = p (post) ; - A = A (:,p) ; - - % test column case - tic - co = symbfact (A,'col') ; - t1 = toc ; - tic - co2 = symbfact2 (A,'col') ; - t2 = toc ; - - fprintf ('c=symbfact(A,''col''): %10.4f %10.4f speedup %8.2f lnz %d\n', ... - t1, t2, t1/t2, sum (co)) ; - - if (any (co ~= co2)) - error ('!') ; - end - - tic - [co h parent post R] = symbfact (A,'col') ; - t1 = toc ; - tic - [co2 h2 parent2 post2 R2] = symbfact2 (A,'col') ; - t2 = toc ; - - fprintf ('R=symbfact(A,''col''): %10.4f %10.4f speedup %8.2f\n', ... - t1, t2, t1/t2) ; - - checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; + Problem = ssget (i) ; + A = spones (Problem.A) ; + [m n] = size (A) ; + fprintf ('\n%4d: %-20s nrow: %6d ncol: %6d nnz: %10d\n', ... + i, Problem.name, m, n, nnz(A)) ; + + % warmup, for accurate timing + etree (sparse (1)) ; + etree2 (sparse (1)) ; + amd2 (sparse (1)) ; + symbfact (sparse (1)) ; + symbfact2 (sparse (1)) ; + + % test symmetric case + if (m == n) + + % permute the matrix first + p = amd2 (A) ; + A = A (p,p) ; + + % test with triu(A) + tic + co = symbfact (A) ; + t1 = toc ; + tic + co2 = symbfact2 (A) ; + t2 = toc ; + + fprintf ('c=symbfact(A): %10.4f %10.4f speedup %8.2f lnz %d\n', ... + t1, t2, t1/t2, sum (co)) ; + + if (any (co ~= co2)) + error ('!') ; + end + + tic + [co h parent post R] = symbfact (A) ; + t1 = toc ; + tic + [co2 h2 parent2 post2 R2] = symbfact2 (A) ; + t2 = toc ; + + fprintf ('R=symbfact(A): %10.4f %10.4f speedup %8.2f\n',... + t1, t2, t1/t2) ; + + checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; + + % test with tril(A) + tic + co = symbfact (A') ; + t1 = toc ; + tic + co2 = symbfact2 (A,'lo') ; + t2 = toc ; + + fprintf (... + 'c=symbfact(A''): %10.4f %10.4f speedup %8.2f lnz %d\n',... + t1, t2, t1/t2, sum (co)) ; + + if (any (co ~= co2)) + error ('!') ; + end + + tic + [co h parent post R] = symbfact (A') ; + t1 = toc ; + tic + [co2 h2 parent2 post2 R2] = symbfact2 (A,'lo') ; + t2 = toc ; + + fprintf (... + 'R=symbfact(A''): %10.4f %10.4f speedup %8.2f\n',... + t1, t2, t1/t2) ; + + checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; + + end + + % permute the matrix first + p = colamd (A) ; + [parent post] = etree2 (A (:,p), 'col') ; + p = p (post) ; + A = A (:,p) ; + + % test column case + tic + co = symbfact (A,'col') ; + t1 = toc ; + tic + co2 = symbfact2 (A,'col') ; + t2 = toc ; + + fprintf ('c=symbfact(A,''col''): %10.4f %10.4f speedup %8.2f lnz %d\n', ... + t1, t2, t1/t2, sum (co)) ; + + if (any (co ~= co2)) + error ('!') ; + end + + tic + [co h parent post R] = symbfact (A,'col') ; + t1 = toc ; + tic + [co2 h2 parent2 post2 R2] = symbfact2 (A,'col') ; + t2 = toc ; + + fprintf ('R=symbfact(A,''col''): %10.4f %10.4f speedup %8.2f\n', ... + t1, t2, t1/t2) ; + + checkem(co,co2,parent,parent2,post,post2,R,R2,h,h2) ; % catch -% fprintf ('%d failed\n', i) ; +% fprintf ('%d failed\n', i) ; % end end diff --git a/CHOLMOD/MATLAB/Test/test16.m b/CHOLMOD/MATLAB/Test/test16.m index a9e559e869..337bb29e3b 100644 --- a/CHOLMOD/MATLAB/Test/test16.m +++ b/CHOLMOD/MATLAB/Test/test16.m @@ -4,7 +4,7 @@ % test16 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -13,7 +13,7 @@ rand ('state',1) ; randn ('state',1) ; -Prob = ssget (936) %#ok +Prob = ssget (936) %#ok A = Prob.A ; % tic % [L,s,p] = lchol (A) ; diff --git a/CHOLMOD/MATLAB/Test/test17.m b/CHOLMOD/MATLAB/Test/test17.m index 1af12fb2a3..882125965d 100644 --- a/CHOLMOD/MATLAB/Test/test17.m +++ b/CHOLMOD/MATLAB/Test/test17.m @@ -4,7 +4,7 @@ % test17 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -13,21 +13,21 @@ rand ('state',1) ; randn ('state',1) ; -Prob = ssget (887) %#ok +Prob = ssget (887) %#ok A = Prob.A ; -[L,s,p] = lchol (A) ; %#ok +[L,s,p] = lchol (A) ; %#ok norm (L,1) clear all -Prob = ssget (936) %#ok +Prob = ssget (936) %#ok A = Prob.A ; -[L,s,p] = lchol (A) ; %#ok -norm (L,1) %#ok +[L,s,p] = lchol (A) ; %#ok +norm (L,1) %#ok clear all -Prob = ssget (887) %#ok +Prob = ssget (887) %#ok A = Prob.A ; -[L,s,p] = lchol (A) ; %#ok -norm (L,1) %#ok +[L,s,p] = lchol (A) ; %#ok +norm (L,1) %#ok diff --git a/CHOLMOD/MATLAB/Test/test18.m b/CHOLMOD/MATLAB/Test/test18.m index 2982b04fe5..376783a1bb 100644 --- a/CHOLMOD/MATLAB/Test/test18.m +++ b/CHOLMOD/MATLAB/Test/test18.m @@ -4,7 +4,7 @@ % test18 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -13,7 +13,7 @@ rand ('state',1) ; randn ('state',1) ; -Prob = ssget (887) %#ok +Prob = ssget (887) %#ok A = Prob.A ; n = size (A,1) ; b = rand (n,1) ; @@ -22,7 +22,7 @@ clear all -Prob = ssget (936) %#ok +Prob = ssget (936) %#ok A = Prob.A ; n = size (A,1) ; b = rand (n,1) ; @@ -31,7 +31,7 @@ clear all -Prob = ssget (887) %#ok +Prob = ssget (887) %#ok A = Prob.A ; n = size (A,1) ; b = rand (n,1) ; diff --git a/CHOLMOD/MATLAB/Test/test19.m b/CHOLMOD/MATLAB/Test/test19.m index 0f736e7f5d..dda1dc679c 100644 --- a/CHOLMOD/MATLAB/Test/test19.m +++ b/CHOLMOD/MATLAB/Test/test19.m @@ -4,13 +4,13 @@ % test19 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); fprintf ('test19: look for NaN''s from lchol (caused by Intel MKL 7.x bug)\n') ; -Prob = ssget (936) %#ok +Prob = ssget (936) %#ok A = Prob.A ; [p count] = analyze (A) ; A = A (p,p) ; @@ -18,12 +18,12 @@ L = lchol (A) ; t = toc ; fl = sum (count.^2) ; -fprintf ('mflop rate: %8.2f\n', 1e-6*fl/t) ; +fprintf ('gflop rate: %8.2f\n', 1e-9*fl/t) ; n = size (L,1) ; for k = 1:n if (any (isnan (L (:,k)))) - k %#ok - error ('!') ; + k %#ok + error ('!') ; end end diff --git a/CHOLMOD/MATLAB/Test/test2.m b/CHOLMOD/MATLAB/Test/test2.m deleted file mode 100644 index 3b61a1330a..0000000000 --- a/CHOLMOD/MATLAB/Test/test2.m +++ /dev/null @@ -1,43 +0,0 @@ -function test2 -%TEST2 test sparse2 -% Example: -% test2 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test2: test sparse2\n') ; - -i = [ 2 3 ] %#ok -j = [ 3 4 ] %#ok -s = [11.4 9.2] + 1i * [3.4 1.2] %#ok -sparse (i,j,s) %#ok -sparse2 (i,j,s) %#ok - -n = 100 ; -nz = 4000 ; - -i = fix (n * rand (nz,1)) + 1 ; -j = fix (n * rand (nz,1)) + 1 ; -s = rand (nz,1) + 1i * rand (nz,1) ; -A = sparse (i,j,s,n,n) ; -B = sparse2 (i,j,s,n,n) ; -nnz(A) - -if (norm (A-B,1) > 1e-14) - A_minus_B = A-B %#ok - error ('!') ; -end - -C = sparse (A) ; -D = sparse2 (B) ; - -if (norm (C-D,1) > 1e-14) - C_minus_D = C-D %#ok - error ('!') ; -end -% spy(C) - -fprintf ('test2 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test20.m b/CHOLMOD/MATLAB/Test/test20.m index e6fb086920..c65a5ae579 100644 --- a/CHOLMOD/MATLAB/Test/test20.m +++ b/CHOLMOD/MATLAB/Test/test20.m @@ -4,54 +4,54 @@ % test20 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); fprintf ('test20: test symbfact2, cholmod2, and lu on a few large matrices\n') ; -unsym = [409 899 901 291 827] ; %#ok +unsym = [409 899 901 291 827] ; %#ok spd = [813 817] ; % f = [ unsym spd ] ; f = spd ; spparms ('spumoni',0) ; for i = f - Prob = ssget (i) %#ok + Prob = ssget (i) %#ok A = Prob.A ; clear Prob ; n = size (A,1) ; b = A*ones (n,1) ; if (any (i == spd)) - p = amd2 (A) ; - count = symbfact2 (A (p,p)) ; - count2 = symbfact (A (p,p)) ; - if (any (count ~= count2)) - error ('!') ; - end - fl = sum (count.^2) ; - lnz = sum (count) ; - unz = lnz ; - tic - x = cholmod2 (A,b) ; - t = toc ; + p = amd2 (A) ; + count = symbfact2 (A (p,p)) ; + count2 = symbfact (A (p,p)) ; + if (any (count ~= count2)) + error ('!') ; + end + fl = sum (count.^2) ; + lnz = sum (count) ; + unz = lnz ; + tic + x = cholmod2 (A,b) ; + t = toc ; else - % spparms ('spumoni',2) ; - [L, U, P, Q] = lu (A) ; %#ok - % fl = luflop (L,U) ; - Lnz = full (sum (spones (L))) - 1 ; - Unz = full (sum (spones (U')))' - 1 ; - fl = 2*Lnz*Unz + sum (Lnz) ; - lnz = nnz(L) ; - unz = nnz(U) ; - tic - x=A\b ; - t = toc ; + % spparms ('spumoni',2) ; + [L, U, P, Q] = lu (A) ; %#ok + % fl = luflop (L,U) ; + Lnz = full (sum (spones (L))) - 1 ; + Unz = full (sum (spones (U')))' - 1 ; + fl = 2*Lnz*Unz + sum (Lnz) ; + lnz = nnz(L) ; + unz = nnz(U) ; + tic + x=A\b ; + t = toc ; end err = norm (A*x-b,1) ; clear L U P Q A x b fprintf ('lnz %d unz %d nnz(L+U) %d fl %g gflop %g\n t %g err %e\n', ... - lnz, unz, lnz+unz-n, fl, 1e-9*fl/t, t, err) ; + lnz, unz, lnz+unz-n, fl, 1e-9*fl/t, t, err) ; % pause end diff --git a/CHOLMOD/MATLAB/Test/test21.m b/CHOLMOD/MATLAB/Test/test21.m index 0126d281b8..378d03b4b5 100644 --- a/CHOLMOD/MATLAB/Test/test21.m +++ b/CHOLMOD/MATLAB/Test/test21.m @@ -4,25 +4,25 @@ % test21 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); fprintf ('test21: test cholmod2 on diagonal or ill-conditioned matrices\n') ; f = [ - 72 % HB/bcsstm22 - 315 % Bai/mhdb416 - 64 % HB/bcsstm09 - 71 % HB/bcsstm21 - 1207 % Oberwolfach/t2dal_e - 354 % Boeing/crystm02 - 1211 % Oberwolfach/t3dl_e + 72 % HB/bcsstm22 + 315 % Bai/mhdb416 + 64 % HB/bcsstm09 + 71 % HB/bcsstm21 + 1207 % Oberwolfach/t2dal_e + 354 % Boeing/crystm02 + 1211 % Oberwolfach/t3dl_e ]' ; for i = f - Prob = ssget (i) %#ok + Prob = ssget (i) %#ok A = Prob.A ; n = size (A,1) ; x = ones (n,2) ; @@ -33,8 +33,8 @@ x2 = cholmod2 (A,b) ; s = norm (A,1) * norm (x,1) + norm (b,1) ; - resid1 = norm (A*x1-b,1) / s ; - resid2 = norm (A*x2-b,1) / s ; + resid1 = norm (A*x1-b,1) / s ; + resid2 = norm (A*x2-b,1) / s ; err1 = norm (x-x1,1) ; err2 = norm (x-x2,1) ; diff --git a/CHOLMOD/MATLAB/Test/test22.m b/CHOLMOD/MATLAB/Test/test22.m index f198997a53..fcca253470 100644 --- a/CHOLMOD/MATLAB/Test/test22.m +++ b/CHOLMOD/MATLAB/Test/test22.m @@ -6,7 +6,7 @@ function test22(nmat) % if nmat <= 0, just test problematic matrices % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -19,46 +19,46 @@ function test22(nmat) if (nargin > 0) problematic = (nmat <= 0) ; if (problematic) - % Matrices for which MATLAB and CHOLMOD differ, for which the error - % is high, or other issues arose during debugging - fprintf ('testing matrices for which MATLAB and CHOLMOD differ\n') ; - f = [ - 186 % HB/jgl011 - 109 % HB/curtis54 - 793 % Qaplib/lp_nug05 - 607 % LPnetlib/lp_brandy - 707 % LPnetlib/lp_bore3d - 231 % HB/plskz362 - 794 % Qaplib/lp_nug06 - 673 % LPnetlib/lp_scorpion - 1156 % Sandia/oscil_dcop_45 (also 1157:1168) - 795 % Qaplib/lp_nug07 - 796 % Qaplib/lp_nug08 - 260 % HB/well1033 - 261 % HB/well1850 - 230 % HB/plsk1919 - 649 % LPnetlib/lp_pds_02 - 660 % LPnetlib/lp_qap12 - 609 % LPnetlib/lp_cre_a - 619 % LPnetlib/lp_dfl001 - 661 % LPnetlib/lp_qap15 - 650 % LPnetlib/lp_pds_06 - 379 % Cote/vibrobox - 638 % LPnetlib/lp_ken_11 - 799 % Qaplib/lp_nug20 - ]' ; + % Matrices for which MATLAB and CHOLMOD differ, for which the error + % is high, or other issues arose during debugging + fprintf ('testing matrices for which MATLAB and CHOLMOD differ\n') ; + f = [ + 186 % HB/jgl011 + 109 % HB/curtis54 + 793 % Qaplib/lp_nug05 + 607 % LPnetlib/lp_brandy + 707 % LPnetlib/lp_bore3d + 231 % HB/plskz362 + 794 % Qaplib/lp_nug06 + 673 % LPnetlib/lp_scorpion + 1156 % Sandia/oscil_dcop_45 (also 1157:1168) + 795 % Qaplib/lp_nug07 + 796 % Qaplib/lp_nug08 + 260 % HB/well1033 + 261 % HB/well1850 + 230 % HB/plsk1919 + 649 % LPnetlib/lp_pds_02 + 660 % LPnetlib/lp_qap12 + 609 % LPnetlib/lp_cre_a + 619 % LPnetlib/lp_dfl001 + 661 % LPnetlib/lp_qap15 + 650 % LPnetlib/lp_pds_06 + 379 % Cote/vibrobox + 638 % LPnetlib/lp_ken_11 + 799 % Qaplib/lp_nug20 + ]' ; else - nmat = max (0,nmat) ; - nmat = min (nmat, length (f)) ; - f = f (1:nmat) ; + nmat = max (0,nmat) ; + nmat = min (nmat, length (f)) ; + f = f (1:nmat) ; end end skip = [ - 811, ... % Simon/appu, which is a random matrix - 937:939, ... % large ND/ problems - 1157:1168 ... % duplicates - 799 % rather large: Qaplib/lp_nug20 + 811, ... % Simon/appu, which is a random matrix + 937:939, ... % large ND/ problems + 1157:1168 ... % duplicates + 799 % rather large: Qaplib/lp_nug20 ] ; tlimit = 0.1 ; @@ -67,34 +67,34 @@ function test22(nmat) klimit = 1 ; % warmup, for more accurate timing -[R,p] = chol (sparse (1)) ; %#ok -[R,p] = chol2 (sparse (1)) ; %#ok +[R,p] = chol (sparse (1)) ; %#ok +[R,p] = chol2 (sparse (1)) ; %#ok clear R p for i = f if (any (i == skip)) - continue ; + continue ; end Problem = ssget (i) ; A = Problem.A ; [m n] = size (A) ; fprintf ('\n================== %4d: Problem: %s m: %d n: %d nnz: %d', ... - i, Problem.name, m, n, nnz (A)) ; + i, Problem.name, m, n, nnz (A)) ; clear Problem ; - try % create a symmetric version of the matrix - if (m == n) - if (nnz (A-A') > 0) - A = A+A' ; - end - else - A = A*A' ; - end + try % create a symmetric version of the matrix + if (m == n) + if (nnz (A-A') > 0) + A = A+A' ; + end + else + A = A*A' ; + end catch - fprintf ('skip\n') ; - continue + fprintf ('skip\n') ; + continue end fprintf (' %d\n', nnz (A)) ; @@ -108,98 +108,98 @@ function test22(nmat) % MATLAB k = 0 ; t1 = 0 ; - while (t1 < tlimit & k < klimit) %#ok - tic ; - [R1,p1] = chol (A) ; - t = toc ; - t1 = t1 + t ; - k = k + 1 ; + while (t1 < tlimit & k < klimit) %#ok + tic ; + [R1,p1] = chol (A) ; + t = toc ; + t1 = t1 + t ; + k = k + 1 ; end t1 = t1 / k ; % CHOLMOD k = 0 ; t2 = 0 ; - while (t2 < tlimit & k < klimit) %#ok - tic ; - [R2,p2] = chol2 (A) ; - t = toc ; - t2 = t2 + t ; - k = k + 1 ; + while (t2 < tlimit & k < klimit) %#ok + tic ; + [R2,p2] = chol2 (A) ; + t = toc ; + t2 = t2 + t ; + k = k + 1 ; end t2 = t2 / k ; if (klimit == 1) - rmin = full (min (abs (diag (R2)))) ; - rmax = full (max (abs (diag (R2)))) ; - if (p2 ~= 0 | isnan (rmin) | isnan (rmax) | rmax == 0) %#ok - rcond = 0 ; - else - rcond = rmin / rmax ; - end - fprintf ('rcond: %30.20e\n', rcond) ; + rmin = full (min (abs (diag (R2)))) ; + rmax = full (max (abs (diag (R2)))) ; + if (p2 ~= 0 | isnan (rmin) | isnan (rmax) | rmax == 0) %#ok + rcond = 0 ; + else + rcond = rmin / rmax ; + end + fprintf ('rcond: %30.20e\n', rcond) ; end if (p1 == 1) - % MATLAB does not follow its own definitions. If p is 1, then R is - % supposed to be 0-by-n, not 0-by-0. CHOLMOD fixes this bug. - % Here, A is m-by-m - R1 = sparse (0,m) ; + % MATLAB does not follow its own definitions. If p is 1, then R is + % supposed to be 0-by-n, not 0-by-0. CHOLMOD fixes this bug. + % Here, A is m-by-m + R1 = sparse (0,m) ; end kerr = 0 ; if (p1 ~= p2) - % MATLAB and CHOLMOD don't agree. See if both are correct, - % because differences in roundoff errors can make one go - % a little farther than the other. - - % if p1 is zero, it means MATLAB was fully successful - k1 = p1 ; - if (k1 == 0) - k1 = n ; - end - - % if p2 is zero, it means CHOLMOD was fully successful - k2 = p2 ; - if (k2 == 0) - k2 = n ; - end - - if (k1 > k2) - % MATLAB went further than CHOLMOD. This is OK if MATLAB found - % a small entry where CHOLMOD stopped. - k = k2 ; - kerr = R1 (k,k) ; - % now reduce R1 in size, to compare with R2 - R1 = R1 (1:k2-1,:) ; - else - % CHOLMOD went further than MATLAB. This is OK if CHOLMOD found - % a small entry where MATLAB stopped. - k = k1 ; - kerr = R2 (k,k) ; - % now reduce R2 in size, to compare with R1 - R2 = R2 (1:k1-1,:) ; - end + % MATLAB and CHOLMOD don't agree. See if both are correct, + % because differences in roundoff errors can make one go + % a little farther than the other. + + % if p1 is zero, it means MATLAB was fully successful + k1 = p1 ; + if (k1 == 0) + k1 = n ; + end + + % if p2 is zero, it means CHOLMOD was fully successful + k2 = p2 ; + if (k2 == 0) + k2 = n ; + end + + if (k1 > k2) + % MATLAB went further than CHOLMOD. This is OK if MATLAB found + % a small entry where CHOLMOD stopped. + k = k2 ; + kerr = R1 (k,k) ; + % now reduce R1 in size, to compare with R2 + R1 = R1 (1:k2-1,:) ; + else + % CHOLMOD went further than MATLAB. This is OK if CHOLMOD found + % a small entry where MATLAB stopped. + k = k1 ; + kerr = R2 (k,k) ; + % now reduce R2 in size, to compare with R1 + R2 = R2 (1:k1-1,:) ; + end end err = norm (R1-R2,1) / max (anorm,1) ; fprintf ('p: %6d %6d MATLAB: %10.4f CHOLMOD: %10.4f speedup %6.2f err:', ... - p1, p2, t1, t2, t1/t2) ; + p1, p2, t1, t2, t1/t2) ; if (err == 0) - fprintf (' 0') ; + fprintf (' 0') ; else - fprintf (' %6.0e', err) ; + fprintf (' %6.0e', err) ; end if (kerr == 0) - fprintf (' 0\n') ; + fprintf (' 0\n') ; else - fprintf (' %6.0e\n', kerr) ; + fprintf (' %6.0e\n', kerr) ; end % if (err > 1e-6) -% error ('!') ; +% error ('!') ; % end % pause diff --git a/CHOLMOD/MATLAB/Test/test23.m b/CHOLMOD/MATLAB/Test/test23.m index bacdd4bf6d..39010d9998 100644 --- a/CHOLMOD/MATLAB/Test/test23.m +++ b/CHOLMOD/MATLAB/Test/test23.m @@ -4,7 +4,7 @@ % test23 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -22,7 +22,7 @@ e1 = norm (A*x-b) ; tic ; -x = cholmod2 (A,b) ; +x = cholmod2 (A,b) ; t2 = toc ; e2 = norm (A*x-b) ; @@ -112,7 +112,7 @@ e1 = norm (A*x-b) ; tic ; -x = cholmod2 (A,b,0) ; +x = cholmod2 (A,b,0) ; t2 = toc ; e2 = norm (A*x-b) ; diff --git a/CHOLMOD/MATLAB/Test/test24.m b/CHOLMOD/MATLAB/Test/test24.m index 59ba77460c..f13e345f5c 100644 --- a/CHOLMOD/MATLAB/Test/test24.m +++ b/CHOLMOD/MATLAB/Test/test24.m @@ -4,7 +4,7 @@ % test24 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -21,40 +21,40 @@ fn = fix (20 * rand (1)) ; for complexity = 0:1 - for transpose = 0:1 - if (transpose) - fm = sm ; - else - fm = sn ; - end - S = sprand (sm,sn,0.5) ; - F = rand (fm,fn) ; - - if (complexity) - S = S + 1i * sprand (S) ; - F = F + 1i * rand (fm,fn) ; - end - - % MATLAB does not support empty complex matrices - if (isempty (S) | isempty (F)) %#ok - S = sparse (real (S)) ; - F = real (F) ; - end - - C = sdmult (S,F,transpose) ; - - if (transpose) - D = S'*F ; - else - D = S*F ; - end - - err = norm (C-D,1) ; - maxerr = max (err, maxerr) ; - if (err > 1e-13) - error ('!') ; - end - end + for transpose = 0:1 + if (transpose) + fm = sm ; + else + fm = sn ; + end + S = sprand (sm,sn,0.5) ; + F = rand (fm,fn) ; + + if (complexity) + S = S + 1i * sprand (S) ; + F = F + 1i * rand (fm,fn) ; + end + + % MATLAB does not support empty complex matrices + if (isempty (S) | isempty (F)) %#ok + S = sparse (real (S)) ; + F = real (F) ; + end + + C = sdmult (S,F,transpose) ; + + if (transpose) + D = S'*F ; + else + D = S*F ; + end + + err = norm (C-D,1) ; + maxerr = max (err, maxerr) ; + if (err > 1e-13) + error ('!') ; + end + end end end diff --git a/CHOLMOD/MATLAB/Test/test25.m b/CHOLMOD/MATLAB/Test/test25.m index 268c986e4c..d5c6993c8b 100644 --- a/CHOLMOD/MATLAB/Test/test25.m +++ b/CHOLMOD/MATLAB/Test/test25.m @@ -4,7 +4,7 @@ % test25 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -35,11 +35,11 @@ err = norm (C-D,1) ; fprintf (... - 'k: %3d time: MATLAB %8.2f CHOLMOD %8.2f speedup %8.2f err %6.0e',... - k, t1, t2, t1/t2, err) ; + 'k: %3d time: MATLAB %8.2f CHOLMOD %8.2f speedup %8.2f err %6.0e',... + k, t1, t2, t1/t2, err) ; fl = 2*nz*k ; - fprintf (' mflop: MATLAB %8.1f CHOLMOD %8.1f\n', 1e-6*fl/t1, 1e-6*fl/t2) ; - + fprintf (' gflop: MATLAB %8.2f CHOLMOD %8.2f\n', 1e-9*fl/t1, 1e-9*fl/t2) ; + clear C D X end diff --git a/CHOLMOD/MATLAB/Test/test26.m b/CHOLMOD/MATLAB/Test/test26.m index 1e50b8f611..8d7e5d8996 100644 --- a/CHOLMOD/MATLAB/Test/test26.m +++ b/CHOLMOD/MATLAB/Test/test26.m @@ -4,7 +4,7 @@ function test26 (do_metis) % test26 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -56,19 +56,19 @@ function test26b (A,C,do_metis) s1 = bisect (A) ; s2 = bisect (C) ; if (any (s1 ~= s2)) - error ('test 26 failed (bisect)!') ; + error ('test 26 failed (bisect)!') ; end p1 = metis (A) ; p2 = metis (C) ; if (any (p1 ~= p2)) - error ('test 26 failed (metis)!') ; + error ('test 26 failed (metis)!') ; end p1 = nesdis (A) ; p2 = nesdis (C) ; if (any (p1 ~= p2)) - error ('test 26 failed (nesdis)!') ; + error ('test 26 failed (nesdis)!') ; end end diff --git a/CHOLMOD/MATLAB/Test/test27.m b/CHOLMOD/MATLAB/Test/test27.m index 15fa5b9b0b..9c4306a86b 100644 --- a/CHOLMOD/MATLAB/Test/test27.m +++ b/CHOLMOD/MATLAB/Test/test27.m @@ -4,13 +4,13 @@ % test27 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); fprintf ('test27: test nesdis\n') ; Prob = ssget ('HB/west0479') ; -dg (Prob.A) ; +testnd (Prob.A) ; fprintf ('test27 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test28.m b/CHOLMOD/MATLAB/Test/test28.m index 8372a7be23..f3275521e6 100644 --- a/CHOLMOD/MATLAB/Test/test28.m +++ b/CHOLMOD/MATLAB/Test/test28.m @@ -4,7 +4,7 @@ % test28 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ index = ssget ; @@ -21,42 +21,42 @@ try - Prob = ssget (i, index) ; - A = spones (Prob.A) ; - [m n] = size (A) ; - - if (m < n) - A = A*A' ; - elseif (m > n) ; - A = A'*A ; - else - A = A+A' ; - end - - % default: do not split connected components - [p1 cp1 cmem1] = nesdis (A) ; %#ok - - % order connected components separately - [p2 cp2 cmem2] = nesdis (A, 'sym', [200 1]) ; %#ok - c1 = symbfact (A (p1,p1)) ; - c2 = symbfact (A (p2,p2)) ; - lnz1 = sum (c1) ; - lnz2 = sum (c2) ; - fprintf ('%35s %8d %8d ', Prob.name, lnz1, lnz2) - if (lnz1 == lnz2) - fprintf (' 1\n') ; - else - fprintf (' %8.3f\n', lnz1/lnz2) ; - end - - subplot (2,3,1) ; spy (A) ; - subplot (2,3,2) ; spy (A (p1,p1)) ; - subplot (2,3,3) ; treeplot (cp1) ; - subplot (2,3,5) ; spy (A (p2,p2)) ; - subplot (2,3,6) ; treeplot (cp2) ; - drawnow + Prob = ssget (i, index) ; + A = spones (Prob.A) ; + [m n] = size (A) ; + + if (m < n) + A = A*A' ; + elseif (m > n) ; + A = A'*A ; + else + A = A+A' ; + end + + % default: do not split connected components + [p1 cp1 cmem1] = nesdis (A) ; %#ok + + % order connected components separately + [p2 cp2 cmem2] = nesdis (A, 'sym', [200 1]) ; %#ok + c1 = symbfact (A (p1,p1)) ; + c2 = symbfact (A (p2,p2)) ; + lnz1 = sum (c1) ; + lnz2 = sum (c2) ; + fprintf ('%35s %8d %8d ', Prob.name, lnz1, lnz2) + if (lnz1 == lnz2) + fprintf (' 1\n') ; + else + fprintf (' %8.3f\n', lnz1/lnz2) ; + end + + subplot (2,3,1) ; spy (A) ; + subplot (2,3,2) ; spy (A (p1,p1)) ; + subplot (2,3,3) ; treeplot (cp1) ; + subplot (2,3,5) ; spy (A (p2,p2)) ; + subplot (2,3,6) ; treeplot (cp2) ; + drawnow catch - fprintf ('%4d failed\n', i) ; + fprintf ('%4d failed\n', i) ; end end diff --git a/CHOLMOD/MATLAB/Test/test29.m b/CHOLMOD/MATLAB/Test/test29.m index 18604a30d7..b429493e03 100644 --- a/CHOLMOD/MATLAB/Test/test29.m +++ b/CHOLMOD/MATLAB/Test/test29.m @@ -4,7 +4,7 @@ % spsym % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ rand ('state', 0) ; diff --git a/CHOLMOD/MATLAB/Test/test3.m b/CHOLMOD/MATLAB/Test/test3.m deleted file mode 100644 index 7135efc517..0000000000 --- a/CHOLMOD/MATLAB/Test/test3.m +++ /dev/null @@ -1,58 +0,0 @@ -function test3 -%TEST3 test sparse on int8, int16, and logical -% Example: -% test3 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test3: test sparse on int8, int16, and logical\n') ; - -clear all -c = ['a' 'b' 0 'd'] %#ok - -fprintf ('---- char:\n') ; -sparse2(c) -nzmax(ans) %#ok -whos - -fprintf ('---- char transposed:\n') ; -sparse2(c') -nzmax(ans) %#ok -whos - -fprintf ('---- int8:\n') ; -sparse2(int8(c)) -nzmax(ans) %#ok -whos - -fprintf ('---- int16:\n') ; -sparse2 (int16(c)) -nzmax(ans) %#ok -whos - -fprintf ('---- logical (using the MATLAB "sparse"):\n') ; -s = logical(rand(4) > .5) %#ok -sparse (s) -nzmax(ans) %#ok -whos - -fprintf ('---- logical (using sparse2):\n') ; -sparse2(s) -nzmax(ans) %#ok -whos - -fprintf ('---- double (using the MATLAB "sparse"):\n') ; -x = rand(4) %#ok -sparse (x > .5) %#ok -nzmax(ans) %#ok -whos - -fprintf ('---- double (using sparse2):\n') ; -sparse2 (x > .5) %#ok -nzmax(ans) %#ok -whos - -fprintf ('test3 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test4.m b/CHOLMOD/MATLAB/Test/test4.m index f7632ebabc..fd3bc3c968 100644 --- a/CHOLMOD/MATLAB/Test/test4.m +++ b/CHOLMOD/MATLAB/Test/test4.m @@ -4,7 +4,7 @@ % test4 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -16,7 +16,7 @@ b = rand (n,1) ; x = cholmod2 (A,b) ; m2 = norm (A*x-b,1) ; -b = sparse (b) ; +b = sparse (b) ; x = cholmod2 (A,b) ; m2 = max (m2, norm (A*x-b,1)) ; m1 = 0 ; @@ -28,7 +28,7 @@ x = cholmod2 (A,b) ; e2 = norm (A*x-b,1) ; if (e2 > 1e-11) - error ('!') ; + error ('!') ; end m1 = max (m1, e1) ; m2 = max (m2, e2) ; @@ -42,7 +42,7 @@ x = cholmod2 (A,b) ; e2 = norm (A*x-b,1) ; if (e2 > 1e-11) - error ('!') ; + error ('!') ; end m1 = max (m1, e1) ; m2 = max (m2, e2) ; @@ -50,7 +50,7 @@ fprintf ('maxerr %e %e\n', m1, m2) ; -if (m1 > 1e-11 | m2 > 1e-11) %#ok +if (m1 > 1e-11 | m2 > 1e-11) %#ok error ('!') ; end diff --git a/CHOLMOD/MATLAB/Test/test5.m b/CHOLMOD/MATLAB/Test/test5.m deleted file mode 100644 index 2d2a9e9186..0000000000 --- a/CHOLMOD/MATLAB/Test/test5.m +++ /dev/null @@ -1,96 +0,0 @@ -function test5 -%TEST5 test sparse2 -% Example: -% test5 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test5: test sparse2\n') ; - -randn ('state', 0) ; -rand ('state', 0) ; - -A = sprandn (10,20,0.2) ; -[m n ] = size (A) ; - -[i j x] = find (A) ; -% [i2 j2 x2] = cholmod_find (A) ; -% if (any (i ~= i2)) -% error ('i!') ; -%end -%if (any (j ~= j2)) -% error ('j!') ; -%end -%if (any (x ~= x2)) -% error ('x!') ; -%end - -% full (sum (spones (A'))) - -C = sparse (i,j,x,m,n) ; -B = sparse2 (i,j,x,m,n) ; -err = norm(A-B,1) ; -if (err > 0) - error ('dtri 1') ; -end -err = norm(C-B,1) ; -if (err > 0) - error ('dtri 1b') ; -end - -nz = length (x) ; -p = randperm (nz) ; - -i2 = i(p) ; -j2 = j(p) ; -x2 = x(p) ; %#ok - -B = sparse2 (i,j,x,m,n) ; -err = norm(A-B,1) ; -if (err > 0) - error ('dtri 2') ; -end - -ii = [i2 ; i2] ; -jj = [j2 ; j2] ; -xx = rand (2*nz,1) ; - -C = sparse (ii,jj,xx,m,n) ; -D = sparse2 (ii,jj,xx,m,n) ; -err = norm (C-D,1) ; -if (err > 0) - error ('dtri 3') ; -end - -% E = sparse2 (ii,jj,xx,n,n,+1) ; -E = sparse (min(ii,jj), max(ii,jj), xx, n, n) ; -F = sparse (min(ii,jj), max(ii,jj), xx, n, n) ; -err = norm (E-F,1) ; -if (err > 0) - error ('dtri 4') ; -end - -% E = sparse2 (ii,jj,xx,n,n,-1) ; -E = sparse (max(ii,jj), min(ii,jj), xx, n, n) ; -F = sparse (max(ii,jj), min(ii,jj), xx, n, n) ; -err = norm (E-F,1) ; -if (err > 0) - error ('dtri 5') ; -end - -[i1 j1 x1] = find (F) ; %#ok -% [i2 j2 x2] = cholmod_find (F) ; -% if (any (i1 ~= i2)) -% error ('i!') ; -% end -% if (any (j1 ~= j2)) -% error ('j!') ; -% end -% if (any (x1 ~= x2)) -% error ('x!') ; -% end - -fprintf ('test5 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test6.m b/CHOLMOD/MATLAB/Test/test6.m deleted file mode 100644 index 9f6a5436b3..0000000000 --- a/CHOLMOD/MATLAB/Test/test6.m +++ /dev/null @@ -1,168 +0,0 @@ -function test6 -%TEST6 test sparse with large matrix, both real and complex -% compare times with MATLAB -% Example: -% test6 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test6: test sparse with large matrix, both real and complex\n') ; - -for do_complex = 0:1 - - fprintf ('do_complex = %d\n', do_complex) ; - randn ('state', 0) ; - rand ('state', 0) ; - - % Prob = ssget (437) - Prob = ssget (749) %#ok - A = Prob.A ; - [m n] = size (A) ; %#ok - - if (do_complex) -% A = A + 1i*sprand(A) ; -% patch for MATLAB 7.2 - A = A + sparse(1:m,1:m,1i)*sprand(A) ; - end - - tic - [i j x] = find (A) ; - t = toc ; - fprintf ('find time %8.4f\n', t) ; - - % tic - % [i1 j1 x1] = cholmod_find (A) ; - % t = toc ; - % fprintf ('cholmod_find time %8.4f (for testing only, it should be slow)\n', t) ; - - % if (any (i ~= i1)) - % error ('i!') ; - % end - % if (any (j ~= j1)) - % error ('j!') ; - % end - % if (any (x ~= x1)) - % error ('x!') ; - % end - - [m n ] = size (A) ; - - tic ; - B = sparse2 (i,j,x,m,n) ; - t1 = toc ; - tic ; - C = sparse (i,j,x,m,n) ; - t2 = toc ; - - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f\n', t1, t2) ; - - err = norm(A-B,1) ; - if (err > 0) - error ('dtri2 1') ; - end - - err = norm(A-C,1) ; - if (err > 0) - error ('dtri2 1') ; - end - - nz = length (x) ; - p = randperm (nz) ; - - i2 = i(p) ; - j2 = j(p) ; - x2 = x(p) ; %#ok - - tic ; - B = sparse2 (i,j,x,m,n) ; - t1 = toc ; - tic ; - C = sparse (i,j,x,m,n) ; - t2 = toc ; - - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f (jumbled)\n', t1, t2) ; - - err = norm(A-B,1) ; - if (err > 0) - error ('dtri2 2') ; - end - - err = norm(A-C,1) ; - if (err > 0) - error ('dtri2 1') ; - end - - ii = [i2 ; i2] ; - jj = [j2 ; j2] ; - xx = rand (2*nz,1) ; - if (do_complex) - xx = xx + 1i* rand (2*nz,1) ; - end - - tic ; - D = sparse2 (ii,jj,xx,m,n) ; - t1 = toc ; - tic ; - C = sparse (ii,jj,xx,m,n) ; - t2 = toc ; - err = norm (C-D,1) ; - if (err > 0) - error ('dtri2 3') ; - end - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f (duplicates)\n', t1, t2) ; - - fprintf ('length %d nz %d\n', length (xx), nnz(D)) ; - - i2 = min (ii,jj) ; - j2 = max (ii,jj) ; - - tic ; - E = sparse2 (i2,j2,xx,n,n) ; - t1 = toc ; - tic ; - F = sparse (i2, j2, xx, n, n) ; - t2 = toc ; - err = norm (E-F,1) %#ok - if (err > 1e-13) - error ('dtri2 4') ; - end - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f (upper)\n', t1, t2) ; - - i2 = max (ii,jj) ; - j2 = min (ii,jj) ; - - tic ; - E = sparse2 (i2,j2,xx,n,n) ; - t1 = toc ; - tic ; - F = sparse (i2, j2, xx, n, n) ; - t2 = toc ; - err = norm (E-F,1) %#ok - if (err > 1e-13) - error ('dtri2 5') ; - end - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f (lower)\n', t1, t2) ; - - [ignore, i] = sort (ii) ; - ii = ii (i) ; - jj = jj (i) ; - xx = xx (i) ; - - tic ; - D = sparse2 (ii,jj,xx,m,n) ; - t1 = toc ; - tic ; - C = sparse (ii,jj,xx,m,n) ; - t2 = toc ; - err = norm (C-D,1) ; - if (err > 0) - error ('dtri2 6') ; - end - fprintf ('dtri time: cholmod2 %8.6f matlab %8.6f (sorted, dupl)\n', t1, t2) ; - -end - -fprintf ('test6 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test7.m b/CHOLMOD/MATLAB/Test/test7.m deleted file mode 100644 index c2a9c65f88..0000000000 --- a/CHOLMOD/MATLAB/Test/test7.m +++ /dev/null @@ -1,64 +0,0 @@ -function test7 -%TEST7 test sparse2 -% Example: -% test7 -% See also cholmod_test - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -fprintf ('=================================================================\n'); -fprintf ('test7: test sparse2\n') ; - -randn ('state', 0) ; -rand ('state', 0) ; - -% Prob = ssget (437) -Prob = ssget (750) %#ok -A = Prob.A ; -[m n] = size (A) ; - -tic -[i j x] = find (A) ; -t = toc ; -fprintf ('find time %8.4f\n', t) ; - -tic ; -B = sparse2 (i,j,x,m,n) ; %#ok -t1 = toc ; -fprintf ('tot: %8.6f\n', t1) - -tic ; -B = sparse2 (i,j,x,m,n) ; %#ok -t1 = toc ; -fprintf ('tot: %8.6f again \n', t1) ; - -tic ; -B1 = sparse2 (i,j,x) ; %#ok -t1 = toc ; -fprintf ('tot: %8.6f (i,j,x)\n', t1) ; - -nz = length (x) ; -p = randperm (nz) ; - -i2 = i(p) ; -j2 = j(p) ; -x2 = x(p) ; %#ok - -tic ; -B = sparse2 (i,j,x,m,n) ; %#ok -t1 = toc ; - -fprintf ('tot: %8.6f (jumbled)\n', t1) ; - -ii = [i2 ; i2] ; -jj = [j2 ; j2] ; -xx = rand (2*nz,1) ; - -tic ; -D = sparse2 (ii,jj,xx,m,n) ; %#ok -t1 = toc ; - -fprintf ('tot %8.6f (duplicates)\n', t1) ; - -fprintf ('test7 passed\n') ; diff --git a/CHOLMOD/MATLAB/Test/test8.m b/CHOLMOD/MATLAB/Test/test8.m index 63764892f9..efc7e8981f 100644 --- a/CHOLMOD/MATLAB/Test/test8.m +++ b/CHOLMOD/MATLAB/Test/test8.m @@ -5,7 +5,7 @@ function test8 (nmat) % test8(nmat) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); @@ -20,7 +20,7 @@ function test8 (nmat) ((index.numerical_symmetry == 1 & index.isBinary) | (index.posdef)) ... & (index.nnzdiag == index.nrows) ... & (index.nrows > 10000 | index.nrows == 9000) ... - & (index.nrows < 600000) & (index.nnz > index.nrows)) ; %#ok + & (index.nrows < 600000) & (index.nnz > index.nrows)) ; %#ok % include small matrices f = find (... @@ -28,8 +28,8 @@ function test8 (nmat) & (index.nnzdiag == index.nrows) ... & (index.nrows < 600000) & (index.nnz > index.nrows)) ; -for k = 1:length (f) - names {k} = index.Name {f(k)} ; %#ok +for k = 1:length (f) + names {k} = index.Name {f(k)} ; %#ok end [ignore i] = sort (names) ; @@ -39,7 +39,7 @@ function test8 (nmat) % fprintf ('test matrices sorted by name:\n') ; % for i = f % fprintf ('%4d: %-20s %-20s %12d %d\n', i, ... -% index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; +% index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; % end [ignore i] = sort (index.nrows (f)) ; @@ -54,7 +54,7 @@ function test8 (nmat) fprintf ('test matrices sorted by dimension:\n') ; for i = f fprintf ('%4d: %-20s %-20s %12d %d\n', i, ... - index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; + index.Group {i}, index.Name {i}, index.nrows (i), index.posdef (i)) ; end junk = sparse (1) ; @@ -64,18 +64,18 @@ function test8 (nmat) for k = 1:length (f) Problem = ssget (f(k)) ; - A = Problem.A ; + A = Problem.A ; fprintf ('\n================== Problem: %s n: %d nnz: %d\n', ... - Problem.name, size (A,1), nnz (A)) ; + Problem.name, size (A,1), nnz (A)) ; fprintf ('title: %s\n\n', Problem.title) ; clear Problem - n = size (A,1) ; %#ok + n = size (A,1) ; %#ok amd2 (junk) ; metis (junk) ; tic ; - [p1,info] = amd2 (A) ; %#ok + [p1,info] = amd2 (A) ; %#ok t1 = toc ; S1 = A (p1,p1) ; tic ; @@ -85,15 +85,15 @@ function test8 (nmat) d1 = symbfact (S1) ; ts2 = toc ; if (any (c1 ~= d1)) - error ('!') + error ('!') end fprintf ('symbfact time: MATLAB %9.4f CHOLMOD %9.4f speedup %8.2f\n', ... - ts1, ts2, ts1/ts2) ; + ts1, ts2, ts1/ts2) ; lnz1 = sum (c1) ; fl1 = sum (c1.^2) ; fprintf ('time: amd %10.4f mnnz(L) %8.1f mfl %8.0f fl/nnz(L) %8.1f\n', ... - t1, lnz1/1e6, fl1 /1e6, fl1/lnz1) ; + t1, lnz1/1e6, fl1 /1e6, fl1/lnz1) ; tic ; p2 = metis (A) ; @@ -104,18 +104,18 @@ function test8 (nmat) fl2 = sum (c2.^2) ; fprintf ('time: metis %10.4f mnnz(L) %8.1f mfl %8.0f fl/nnz(L) %8.1f\n', ... - t2, lnz2/1e6, fl2/1e6, fl2/lnz2) ; + t2, lnz2/1e6, fl2/1e6, fl2/lnz2) ; - r = lnz2 / lnz1 ; %#ok + r = lnz2 / lnz1 ; %#ok fprintf ('\nmetis/amd time: %8.4f nnz(L): %8.4f\n', t2/t1, lnz2/lnz1) ; % save results - lnz (k,1) = lnz1 ; %#ok - lnz (k,2) = lnz2 ; %#ok - fl1 (k,1) = fl1 ; %#ok - fl2 (k,2) = fl2 ; %#ok - t (k,1) = t1 ; %#ok - t (k,2) = t2 ; %#ok + lnz (k,1) = lnz1 ; %#ok + lnz (k,2) = lnz2 ; %#ok + fl1 (k,1) = fl1 ; %#ok + fl2 (k,2) = fl2 ; %#ok + t (k,1) = t1 ; %#ok + t (k,2) = t2 ; %#ok end diff --git a/CHOLMOD/MATLAB/Test/test9.m b/CHOLMOD/MATLAB/Test/test9.m index 5fb3b63277..00f512d6fb 100644 --- a/CHOLMOD/MATLAB/Test/test9.m +++ b/CHOLMOD/MATLAB/Test/test9.m @@ -4,75 +4,75 @@ % test9 % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('=================================================================\n'); fprintf ('test9: test metis, etree, bisect, nesdis\n') ; % Prob = ssget ('LPnetlib/lp_qap15') ; -Prob = ssget ('HB/bcsstk15') %#ok +Prob = ssget ('HB/bcsstk15') %#ok A = Prob.A ; C = A'*A ; R = A*A' ; fprintf ('\nmetis:\n') ; -tic ; p0 = metis (R) ; toc %#ok +tic ; p0 = metis (R) ; toc %#ok % [pa po] = etree2 (R (p0,p0)) ; sparse (po - (1:size(R,1))) -tic ; p1 = metis (C) ; toc %#ok +tic ; p1 = metis (C) ; toc %#ok % [pa po] = etree2 (C (p1,p1)) ; sparse (po - (1:size(C,1))) -tic ; p2 = metis (C, 'sym') ; toc %#ok +tic ; p2 = metis (C, 'sym') ; toc %#ok % [pa po] = etree2 (C (p1,p1)) ; sparse (po - (1:size(C,1))) -tic ; p3 = metis (A, 'row') ; toc %#ok +tic ; p3 = metis (A, 'row') ; toc %#ok % [pa po] = etree2 (A (p1,:), 'row') ; sparse (po - (1:size(A,1))) -tic ; p4 = metis (A, 'col') ; toc %#ok +tic ; p4 = metis (A, 'col') ; toc %#ok % [pa po] = etree2 (A (:,p1), 'col') ; sparse (po - (1:size(A,2))) fprintf ('\nmetis(A):\n') ; [m n] = size(A) ; if (m == n) if (nnz (A-A') == 0) - tic ; p5 = metis (A) ; toc - % spy (A (p5,p5)) ; - [ignore q] = etree (A(p5,p5)) ; - p5post = p5 (q) ; %#ok - % spy (A (p5post,p5post)) ; - lnz0 = sum (symbfact (A (p5,p5))) %#ok + tic ; p5 = metis (A) ; toc + % spy (A (p5,p5)) ; + [ignore q] = etree (A(p5,p5)) ; + p5post = p5 (q) ; %#ok + % spy (A (p5post,p5post)) ; + lnz0 = sum (symbfact (A (p5,p5))) %#ok end end fprintf ('\namd:\n') ; if (m == n) if (nnz (A-A') == 0) - tic ; z0 = amd2 (A) ; toc %#ok - lnz = sum (symbfact (A (z0,z0))) %#ok + tic ; z0 = amd2 (A) ; toc %#ok + lnz = sum (symbfact (A (z0,z0))) %#ok end end fprintf ('\nbisect:\n') ; -tic ; s0 = bisect (R) ; toc %#ok -tic ; s1 = bisect (C) ; toc %#ok -tic ; s2 = bisect (C, 'sym') ; toc %#ok -tic ; s3 = bisect (A, 'row') ; toc %#ok -tic ; s4 = bisect (A, 'col') ; toc %#ok +tic ; s0 = bisect (R) ; toc %#ok +tic ; s1 = bisect (C) ; toc %#ok +tic ; s2 = bisect (C, 'sym') ; toc %#ok +tic ; s3 = bisect (A, 'row') ; toc %#ok +tic ; s4 = bisect (A, 'col') ; toc %#ok fprintf ('\nnested dissection:\n') ; -tic ; [c0 cp0 cmem0] = nesdis (R) ; toc %#ok -tic ; [c1 cp1 cmem1] = nesdis (C) ; toc %#ok -tic ; [c2 cp2 cmem2] = nesdis (C, 'sym') ; toc %#ok -tic ; [c3 cp3 cmem3] = nesdis (A, 'row') ; toc %#ok -tic ; [c4 cp4 cmem4] = nesdis (A, 'col') ; toc %#ok +tic ; [c0 cp0 cmem0] = nesdis (R) ; toc %#ok +tic ; [c1 cp1 cmem1] = nesdis (C) ; toc %#ok +tic ; [c2 cp2 cmem2] = nesdis (C, 'sym') ; toc %#ok +tic ; [c3 cp3 cmem3] = nesdis (A, 'row') ; toc %#ok +tic ; [c4 cp4 cmem4] = nesdis (A, 'col') ; toc %#ok fprintf ('\nnested_dissection(A):\n') ; if (m == n) if (nnz (A-A') == 0) - tic ; c5 = nesdis (A) ; toc %#ok - lnz1 = sum (symbfact (A (c5,c5))) %#ok + tic ; c5 = nesdis (A) ; toc %#ok + lnz1 = sum (symbfact (A (c5,c5))) %#ok end end diff --git a/CHOLMOD/MATLAB/Test/testmm.m b/CHOLMOD/MATLAB/Test/testmm.m index 6f2ce9f3b7..9e3c10527a 100644 --- a/CHOLMOD/MATLAB/Test/testmm.m +++ b/CHOLMOD/MATLAB/Test/testmm.m @@ -4,7 +4,7 @@ % See also mread. % Requires the mmread MATLAB m-file from http://www.nist.gov -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ matrices = { @@ -520,31 +520,31 @@ [A,rows,cols,entries,rep,field,symm] = mmread(filename) ; t1 = toc ; fprintf (' %d by %d, nz %d %s %s %s\n', ... - rows, cols, entries, rep, field, symm) ; + rows, cols, entries, rep, field, symm) ; % try tic - B = mread (filename) ; + B = mread (filename) ; t2 = toc ; % catch -% B = [ ] ; +% B = [ ] ; % end fprintf ('speedup %6.2f nnz %d\n', t1/t2, nnz(A)) ; % mread add values to a pattern-only matrix. Remove them if (strcmp (field, 'pattern')) - B = spones (B) ; + B = spones (B) ; end if (isempty (B)) - fprintf ('============================ could not read with CHOLMOD\n') ; - error ('!') ; + fprintf ('============================ could not read with CHOLMOD\n') ; + error ('!') ; else - err = norm (A-B,1) ; - if (err ~= 0) - fprintf ('=================================== %8.1e\n', err) ; - error ('!') ; - end + err = norm (A-B,1) ; + if (err ~= 0) + fprintf ('=================================== %8.1e\n', err) ; + error ('!') ; + end end end diff --git a/CHOLMOD/MATLAB/Test/dg.m b/CHOLMOD/MATLAB/Test/testnd.m similarity index 90% rename from CHOLMOD/MATLAB/Test/dg.m rename to CHOLMOD/MATLAB/Test/testnd.m index 725c84a923..75bfe4eda6 100644 --- a/CHOLMOD/MATLAB/Test/dg.m +++ b/CHOLMOD/MATLAB/Test/testnd.m @@ -1,11 +1,11 @@ -function dg(A) +function testnd(A) %DG order and plot A*A', using CHOLMOD's nested dissection % used by test27.m % Example: -% dg(A) +% testnd(A) % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ A = GB_spones_mex (A) ; @@ -18,7 +18,7 @@ function dg(A) C = A (p,:) ; qmin = zeros (1,n) ; for j = 1:n - qmin (j) = min (find (C (:,j))) ; %#ok + qmin (j) = min (find (C (:,j))) ; %#ok end [ignore q] = sort (qmin) ; @@ -70,6 +70,6 @@ function dg(A) % hold on % for j = cboundaries % plot ([1 n], [j j], 'r', [j j], [1 n], 'r') ; -% end +% end diff --git a/CHOLMOD/MATLAB/Test/testsolve.m b/CHOLMOD/MATLAB/Test/testsolve.m index 1b8020e9f8..84f732fdc1 100644 --- a/CHOLMOD/MATLAB/Test/testsolve.m +++ b/CHOLMOD/MATLAB/Test/testsolve.m @@ -1,5 +1,5 @@ function [x1,x2,e1,e2] = testsolve (A,b) -%TESTSOLVE test CHOLMOD and compare with x=A\b +%TESTSOLVE test CHOLMOD and compare with x=A\b % [x1,x2,e1,e2] = testsolve (A,b) ; % Compare CHOLMOD and MATLAB's x=A\b % x1 = A\b, x2 = cholmod2(A,b), e1 = norm(A*x1-b), e2 = norm(A*x2-b) @@ -7,22 +7,30 @@ % [x1,x2,e1,e2] = testsolve (A,b) ; % See also cholmod_test -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('A: [n %6d real %d] B: [sp:%d nrhs %d real %d] ', ... size(A,1), isreal(A), issparse(b), size(b,2), isreal(b)) ; + +% fprintf ('\n') ; +% A +% b + tic x1 = A\b ; t1 = toc ; tic x2 = cholmod2(A,b) ; t2 = toc ; + +% x2 + tic e1 = norm (A*x1-b,1) ; t3 = toc ; e2 = norm (A*x2-b,1) ; -if (e2 == 0 | e1 == 0) %#ok +if (e2 == 0 | e1 == 0) %#ok e12 = 0 ; else e12 = log2 (e1/e2) ; @@ -33,12 +41,13 @@ t12 = t1 / t2 ; end if (t2 == 0) - t32 = 1 ; %#ok + t32 = 1 ; %#ok else - t32 = t3 / t2 ; %#ok + t32 = t3 / t2 ; %#ok end fprintf (' [e1: %5.0e : %5.1f] [t1: %8.2f t2 %8.2f : %5.1f]\n', ... e1, e12, t1, t2, t12) ; if (e2 > max (1e-8, 1e3*e1)) error ('!') ; end + diff --git a/CHOLMOD/MATLAB/analyze.c b/CHOLMOD/MATLAB/analyze.c index 641c1035bf..615c5fff1b 100644 --- a/CHOLMOD/MATLAB/analyze.c +++ b/CHOLMOD/MATLAB/analyze.c @@ -2,7 +2,7 @@ // CHOLMOD/MATLAB/analyze: MATLAB interface to CHOLMOD symbolic analysis //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ @@ -10,29 +10,28 @@ // MATLAB(tm) is a Trademark of The MathWorks, Inc. -/* Order a matrix and then analyze it, using CHOLMOD's best-effort ordering. - * Returns the count of the number of nonzeros in each column of L for the - * permuted matrix A. - * - * Usage: - * - * [p count] = analyze (A) orders A, using just tril(A) - * [p count] = analyze (A,'sym') orders A, using just tril(A) - * [p count] = analyze (A,'row') orders A*A' - * [p count] = analyze (A,'col') orders A'*A - * - * with an optional 3rd parameter: - * - * [p count] = analyze (A,'sym',k) orders A, using just tril(A) - * [p count] = analyze (A,'row',k) orders A*A' - * [p count] = analyze (A,'col',k) orders A'*A - * - * k=0 is the default. k != 0 selects the ordering strategy. - * - * See analyze.m for more details. - */ - -#include "cholmod_matlab.h" +// Order a matrix and then analyze it, using CHOLMOD's best-effort ordering. +// Returns the count of the number of nonzeros in each column of L for the +// permuted matrix A. +// +// Usage: +// +// [p count] = analyze (A) orders A, using just tril(A) +// [p count] = analyze (A,'sym') orders A, using just tril(A) +// [p count] = analyze (A,'row') orders A*A' +// [p count] = analyze (A,'col') orders A'*A +// +// with an optional 3rd parameter: +// +// [p count] = analyze (A,'sym',k) orders A, using just tril(A) +// [p count] = analyze (A,'row',k) orders A*A' +// [p count] = analyze (A,'col',k) orders A'*A +// +// k=0 is the default. k != 0 selects the ordering strategy. +// +// See analyze.m for more details. + +#include "sputil2.h" void mexFunction ( @@ -44,145 +43,135 @@ void mexFunction { double dummy = 0 ; cholmod_factor *L ; - cholmod_sparse *A, Amatrix, *C, *S ; + cholmod_sparse *A, Amatrix ; cholmod_common Common, *cm ; - int64_t n, transpose, c ; + int64_t transpose, c ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* only do the simplicial analysis (L->Perm and L->ColCount) */ + // only do the simplicial analysis (L->Perm and L->ColCount) cm->supernodal = CHOLMOD_SIMPLICIAL ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 2 || nargin < 1 || nargin > 3) { - mexErrMsgTxt ("Usage: [p count] = analyze (A, mode)") ; + mexErrMsgTxt ("Usage: [p count] = analyze (A, mode)") ; } if (nargin == 3) { - cm->nmethods = mxGetScalar (pargin [2]) ; - if (cm->nmethods == -1 || cm->nmethods == 1 || cm->nmethods == 2) - { - /* use AMD only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_AMD ; - cm->postorder = TRUE ; - } - else if (cm->nmethods == -2) - { - /* use METIS only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_METIS ; - cm->postorder = TRUE ; - } - else if (cm->nmethods == -3) - { - /* use NESDIS only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NESDIS ; - cm->postorder = TRUE ; - } + cm->nmethods = mxGetScalar (pargin [2]) ; + if (cm->nmethods == -1 || cm->nmethods == 1 || cm->nmethods == 2) + { + // use AMD only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_AMD ; + cm->postorder = TRUE ; + } + else if (cm->nmethods == -2) + { + // use METIS only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_METIS ; + cm->postorder = TRUE ; + } + else if (cm->nmethods == -3) + { + // use NESDIS only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NESDIS ; + cm->postorder = TRUE ; + } } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use tril(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use tril(A) + //-------------------------------------------------------------------------- A->stype = -1 ; transpose = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0] ; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - transpose = FALSE ; - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - transpose = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric case (A) if string starts with 's' */ - transpose = FALSE ; - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("analyze: unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0] ; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + transpose = FALSE ; + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + transpose = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric case (A) if string starts with 's' + transpose = FALSE ; + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("analyze: unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("analyze: A must be square") ; + mexErrMsgTxt ("analyze: A must be square") ; } - C = NULL ; + //-------------------------------------------------------------------------- + // analyze and order the matrix + //-------------------------------------------------------------------------- + if (transpose) { - /* C = A', and then order C*C' */ - C = cholmod_l_transpose (A, 0, cm) ; - if (C == NULL) - { - mexErrMsgTxt ("analyze failed") ; - } - A = C ; + // C = A', and then order C*C' + cholmod_sparse *C = cholmod_l_transpose (A, 0, cm) ; + L = cholmod_l_analyze (C, cm) ; + cholmod_l_free_sparse (&C, cm) ; + } + else + { + // order A or A*A' + L = cholmod_l_analyze (A, cm) ; } - n = A->nrow ; - - /* ---------------------------------------------------------------------- */ - /* analyze and order the matrix */ - /* ---------------------------------------------------------------------- */ - - L = cholmod_l_analyze (A, cm) ; - - /* ---------------------------------------------------------------------- */ - /* return Perm */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results and free workspace + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (L->Perm, n, 1) ; + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; + pargout [0] = sputil2_put_int (L->Perm, L->n, 1) ; if (nargout > 1) { - pargout [1] = sputil_put_int (L->ColCount, n, 0) ; + pargout [1] = sputil2_put_int (L->ColCount, L->n, 0) ; } - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ - cholmod_l_free_factor (&L, cm) ; - cholmod_l_free_sparse (&C, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/analyze.m b/CHOLMOD/MATLAB/analyze.m index 357ca0d44f..49e032a48f 100644 --- a/CHOLMOD/MATLAB/analyze.m +++ b/CHOLMOD/MATLAB/analyze.m @@ -1,4 +1,4 @@ -function [p, count] = analyze (A, mode, k) %#ok +function [p, count] = analyze (A, mode, k) %#ok %ANALYZE order and analyze a matrix using CHOLMOD's best-effort ordering. % % Example: @@ -13,19 +13,19 @@ % [p count] = analyze (A,'row',k) orders A*A' % [p count] = analyze (A,'col',k) orders A'*A % -% Returns a permutation and the count of the number of nonzeros in each -% column of L for the permuted matrix A. That is, count is returned as: +% Returns a permutation and the count of the number of nonzeros in each +% column of L for the permuted matrix A. That is, count is returned as: % % count = symbfact2 (A (p,p)) if ordering A % count = symbfact2 (A (p,:),'row') if ordering A*A' % count = symbfact2 (A (:,p),'col') if ordering A'*A % -% CHOLMOD uses the following ordering strategy: +% CHOLMOD uses the following ordering strategy: % -% k = 0: Try AMD. If that ordering gives a flop count >= 500 * nnz(L) -% and a fill-in of nnz(L) >= 5*nnz(C), then try METIS_NodeND (where -% C = A, A*A', or A'*A is the matrix being ordered. Selects the best -% ordering tried. This is the default. +% k = 0: Try AMD. If that ordering gives a flop count >= 500 * +% nnz(L) and a fill-in of nnz(L) >= 5*nnz(C), then try metis +% (where C=A, A*A', or A'*A is the matrix being ordered. +% Selects the best ordering tried. This is the default. % % if k > 0, then multiple orderings are attempted. % @@ -37,7 +37,7 @@ % k = 6: also try NESDIS with large leaves of the separator tree % k = 7: also try NESDIS with tiny leaves and no CCOLAMD ordering % k = 8: also try NESDIS with no dense-node removal -% k = 9: also try COLAMD if ordering A'*A or A*A', (AMD if ordering A). +% k = 9: also try COLAMD if ordering A'*A or A*A', AMD if ordering A % k > 9 is treated as k = 9 % % k = -1: just use AMD @@ -45,21 +45,22 @@ % k = -3: just use NESDIS % % The method returning the smallest nnz(L) is used for p and count. -% k = 4 takes much longer than (say) k = 0, but it can reduce nnz(L) by -% a typical 5% to 10%. k = 5 to 9 is getting extreme, but if you have -% lots of time and want to find the best ordering possible, set k = 9. +% k = 4 takes much longer than (say) k = 0, but it can reduce +% nnz(L) by a typical 5% to 10%. k = 5 to 9 is getting extreme, +% but if you have lots of time and want to find the best ordering +% possible, set k = 9. % -% If METIS is not installed for use in CHOLMOD, then the strategy is -% different: +% If METIS is not installed for use in CHOLMOD, then the strategy is +% different: % % k = 1 to 4: just try AMD % k = 5 to 8: also try the natural ordering (p = 1:n) -% k = 9: also try COLAMD if ordering A'*A or A*A', (AMD if ordering A). +% k = 9: also try COLAMD if ordering A'*A or A*A', AMD if ordering A % k > 9 is treated as k = 9 % -% See also METIS, NESDIS, BISECT, SYMBFACT, AMD +% See also metis, nesdis, bisect, symbfact, amd. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('analyze mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/bisect.c b/CHOLMOD/MATLAB/bisect.c index 278bbda7c6..38e8d7d3f9 100644 --- a/CHOLMOD/MATLAB/bisect.c +++ b/CHOLMOD/MATLAB/bisect.c @@ -2,7 +2,7 @@ // CHOLMOD/MATLAB/bisect: MATLAB interface to CHOLMOD graph bisection //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ @@ -11,23 +11,22 @@ // MATLAB(tm) is a Trademark of The MathWorks, Inc. // METIS is Copyrighted by G. Karypis -/* Find an node separator of an undirected graph, using - * METIS_ComputeVertexSeparator. - * - * Usage: - * - * s = bisect (A) bisects A, uses tril(A) - * s = bisect (A, 'sym') bisects A, uses tril(A) - * s = bisect (A, 'row') bisects A*A' - * s = bisect (A, 'col') bisects A'*A - * - * Node i of the graph is in the left graph if s(i)=0, the right graph if - * s(i)=1, and in the separator if s(i)=2. - * - * Requirse METIS and the CHOLMOD Partition Module. - */ - -#include "cholmod_matlab.h" +// Find an node separator of an undirected graph, using +// METIS_ComputeVertexSeparator. +// +// Usage: +// +// s = bisect (A) bisects A, uses tril(A) +// s = bisect (A, 'sym') bisects A, uses tril(A) +// s = bisect (A, 'row') bisects A*A' +// s = bisect (A, 'col') bisects A'*A +// +// Node i of the graph is in the left graph if s(i)=0, the right graph if +// s(i)=1, and in the separator if s(i)=2. +// +// Requirse METIS and the CHOLMOD Partition Module. + +#include "sputil2.h" void mexFunction ( @@ -42,126 +41,112 @@ void mexFunction double dummy = 0 ; int64_t *Partition ; - cholmod_sparse *A, Amatrix, *C, *S ; + cholmod_sparse *A, Amatrix, *C ; cholmod_common Common, *cm ; int64_t n, transpose, c ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin < 1 || nargin > 2) { - mexErrMsgTxt ("Usage: p = bisect (A, mode)") ; + mexErrMsgTxt ("Usage: p = bisect (A, mode)") ; } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use tril(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use tril(A) + //-------------------------------------------------------------------------- A->stype = -1 ; transpose = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0]; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - transpose = FALSE ; - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - transpose = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric case (A) if string starts with 's' */ - transpose = FALSE ; - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("bisect: p=bisect(A,mode) ; unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0]; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + transpose = FALSE ; + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + transpose = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric case (A) if string starts with 's' + transpose = FALSE ; + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("bisect: p=bisect(A,mode) ; unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("bisect: A must be square") ; + mexErrMsgTxt ("bisect: A must be square") ; } - C = NULL ; + //-------------------------------------------------------------------------- + // bisect with CHOLMOD's interface to METIS_ComputeVertexSeparator + //-------------------------------------------------------------------------- + + bool ok ; if (transpose) { - /* C = A', and then bisect C*C' */ - C = cholmod_l_transpose (A, 0, cm) ; - if (C == NULL) - { - mexErrMsgTxt ("bisect failed") ; - } - A = C ; + // C = A', and then bisect C*C' + cholmod_sparse *C = cholmod_l_transpose (A, 0, cm) ; + n = C->nrow ; + Partition = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ok = (cholmod_l_bisect (C, NULL, 0, TRUE, Partition, cm) >= 0) ; + cholmod_l_free_sparse (&C, cm) ; } - - n = A->nrow ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Partition = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - - /* ---------------------------------------------------------------------- */ - /* order the matrix with CHOLMOD's interface to METIS_NodeND */ - /* ---------------------------------------------------------------------- */ - - if (cholmod_l_bisect (A, NULL, 0, TRUE, Partition, cm) < 0) + else { - mexErrMsgTxt ("bisect failed") ; + // biset A or A*A' + n = A->nrow ; + Partition = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ok = (cholmod_l_bisect (A, NULL, 0, TRUE, Partition, cm) >= 0) ; } - /* ---------------------------------------------------------------------- */ - /* return Partition */ - /* ---------------------------------------------------------------------- */ - - pargout [0] = sputil_put_int (Partition, n, 0) ; - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results and free workspace + //-------------------------------------------------------------------------- + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; + if (!ok) mexErrMsgTxt ("bisect failed") ; + pargout [0] = sputil2_put_int (Partition, n, 0) ; cholmod_l_free (n, sizeof (int64_t), Partition, cm) ; - cholmod_l_free_sparse (&C, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; */ - + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; #else mexErrMsgTxt ("METIS and the CHOLMOD Partition Module not installed\n") ; #endif } + diff --git a/CHOLMOD/MATLAB/bisect.m b/CHOLMOD/MATLAB/bisect.m index 4989d4e41e..b1a66963df 100644 --- a/CHOLMOD/MATLAB/bisect.m +++ b/CHOLMOD/MATLAB/bisect.m @@ -1,25 +1,25 @@ -function p = bisect (A, mode) %#ok +function p = bisect (A, mode) %#ok %BISECT computes a node separator based on METIS_ComputeVertexSeparator. % % Example: -% s = bisect(A) bisects A. Uses tril(A) and assumes A is symmetric. -% s = bisect(A,'sym') the same as p=bisect(A). -% s = bisect(A,'col') bisects A'*A. -% s = bisect(A,'row') bisects A*A'. +% s = bisect(A) bisects A. Uses tril(A) and assumes A is symmetric +% s = bisect(A,'sym') the same as p=bisect(A) +% s = bisect(A,'col') bisects A'*A +% s = bisect(A,'row') bisects A*A' % -% A must be square for p=bisect(A) and bisect(A,'sym'). +% A must be square for p=bisect(A) and bisect(A,'sym'). % -% s is a vector of length equal to the dimension of A, A'*A, or A*A', -% depending on the matrix bisected. s(i)=0 if node i is in the left subgraph, -% s(i)=1 if it is in the right subgraph, and s(i)=2 if node i is in the node -% separator. +% s is a vector of length equal to the dimension of A, A'*A, or A*A', +% depending on the matrix bisected. s(i)=0 if node i is in the left +% subgraph, s(i)=1 if it is in the right subgraph, and s(i)=2 if node i +% is in the node separator. % -% Requires METIS, authored by George Karypis, Univ. of Minnesota. This -% MATLAB interface, via CHOLMOD, is by Tim Davis. +% Requires METIS, authored by George Karypis, Univ. of Minnesota. This +% MATLAB interface, via CHOLMOD, is by Tim Davis. % -% See also METIS, NESDIS +% See also metis, nesdis. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('bisect mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/chol2.c b/CHOLMOD/MATLAB/chol2.c index c6d90eca01..85035c3c58 100644 --- a/CHOLMOD/MATLAB/chol2.c +++ b/CHOLMOD/MATLAB/chol2.c @@ -2,36 +2,35 @@ // CHOLMOD/MATLAB/chol2: MATLAB interface to CHOLMOD Cholesky factorization //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Numeric R'R factorization. Note that LL' and LDL' are faster than R'R - * and use less memory. The R'R factorization methods use triu(A), just like - * MATLAB's built-in chol. - * - * R = chol2 (A) same as R = chol (A), just faster - * [R,p] = chol2 (A) save as [R,p] = chol(A), just faster - * [R,p,q] = chol2 (A) factorizes A(q,q) into R'*R - * - * A must be sparse. It can be complex or real. - * - * R is returned with no explicit zero entries. This means it might not be - * chordal, and R cannot be passed back to CHOLMOD for an update/downdate or - * for a fast simplicial solve. spones (R) will be equal to the R returned - * by symbfact2 if no numerically zero entries are dropped, or a subset - * otherwise. - */ - -#include "cholmod_matlab.h" +// Numeric R'R factorization. Note that LL' and LDL' are faster than R'R +// and use less memory. The R'R factorization methods use triu(A), just like +// MATLAB's built-in chol. +// +// R = chol2 (A) same as R = chol (A), just faster +// [R,p] = chol2 (A) save as [R,p] = chol(A), just faster +// [R,p,q] = chol2 (A) factorizes A(q,q) into R'*R +// +// A must be sparse. It can be complex or real. +// +// R is returned with no explicit zero entries. This means it might not be +// chordal, and R cannot be passed back to CHOLMOD for an update/downdate or +// for a fast simplicial solve. spones (R) will be equal to the R returned +// by symbfact2 if no numerically zero entries are dropped, or a subset +// otherwise. + +#include "sputil2.h" void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -41,121 +40,127 @@ void mexFunction cholmod_common Common, *cm ; int64_t n, minor ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* convert to packed LL' when done */ + // convert to packed LL' when done cm->final_asis = FALSE ; cm->final_super = FALSE ; cm->final_ll = TRUE ; cm->final_pack = TRUE ; cm->final_monotonic = TRUE ; - /* no need to prune entries due to relaxed supernodal amalgamation, since - * zeros are dropped with sputil_drop_zeros instead */ + // no need to prune entries due to relaxed supernodal amalgamation, since + // zeros are dropped with cholmod_l_drop instead cm->final_resymbol = FALSE ; cm->quick_return_if_not_posdef = (nargout < 2) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargin != 1 || nargout > 3) { - mexErrMsgTxt ("usage: [R,p,q] = chol2 (A)") ; + mexErrMsgTxt ("usage: [R,p,q] = chol2 (A)") ; } n = mxGetN (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("A must be square and sparse") ; + mexErrMsgTxt ("A must be square and sparse") ; } - /* get input sparse matrix A. Use triu(A) only */ - A = sputil_get_sparse (pargin [0], &Amatrix, &dummy, 1) ; + // get input sparse matrix A. Use triu(A) only + size_t A_xsize = 0 ; + A = sputil2_get_sparse (pargin [0], 1, CHOLMOD_DOUBLE, &Amatrix, + &A_xsize, cm) ; - /* use natural ordering if no q output parameter */ + // use natural ordering if no q output parameter if (nargout < 3) { - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = FALSE ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = FALSE ; } - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- L = cholmod_l_analyze (A, cm) ; cholmod_l_factorize (A, L, cm) ; if (nargout < 2 && cm->status != CHOLMOD_OK) { - mexErrMsgTxt ("matrix is not positive definite") ; + mexErrMsgTxt ("matrix is not positive definite") ; } - /* ---------------------------------------------------------------------- */ - /* convert L to a sparse matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert L to a sparse matrix + //-------------------------------------------------------------------------- - /* the conversion sets L->minor back to n, so get a copy of it first */ + // the conversion sets L->minor back to n, so get a copy of it first minor = L->minor ; Lsparse = cholmod_l_factor_to_sparse (L, cm) ; if (Lsparse->xtype == CHOLMOD_COMPLEX) { - /* convert Lsparse from complex to zomplex */ - cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; + // convert Lsparse from complex to zomplex + cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; } if (minor < n) { - /* remove columns minor to n-1 from Lsparse */ - sputil_trim (Lsparse, minor, cm) ; + // remove columns minor to n-1 from Lsparse + sputil2_trim (Lsparse, minor, cm) ; } - /* drop zeros from Lsparse */ - sputil_drop_zeros (Lsparse) ; + // drop zeros from Lsparse to save time computing R + cholmod_l_drop (0, Lsparse, cm) ; - /* Lsparse is lower triangular; conjugate transpose to get R */ + // Lsparse is lower triangular; conjugate transpose to get R R = cholmod_l_transpose (Lsparse, 2, cm) ; cholmod_l_free_sparse (&Lsparse, cm) ; - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results to MATLAB + //-------------------------------------------------------------------------- - /* return R */ - pargout [0] = sputil_put_sparse (&R, cm) ; + // R cannot be used by any update/downdate methods since its explicit zeros + // have been dropped. - /* return minor (translate to MATLAB convention) */ + // return R (zeros have already been dropped) + pargout [0] = sputil2_put_sparse (&R, mxDOUBLE_CLASS, + /* already dropped above: */ false, cm) ; + + // return minor (translate to MATLAB convention) if (nargout > 1) { - pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; - px = mxGetPr (pargout [1]) ; - px [0] = ((minor == n) ? 0 : (minor+1)) ; + pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + px = (double *) mxGetData (pargout [1]) ; + px [0] = ((minor == n) ? 0 : (minor+1)) ; } - /* return permutation */ + // return permutation if (nargout > 2) { - pargout [2] = sputil_put_int (L->Perm, n, 1) ; + pargout [2] = sputil2_put_int (L->Perm, n, 1) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- cholmod_l_free_factor (&L, cm) ; + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != (3 + mxIsComplex (pargout[0]))) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 1) cholmod_l_gpu_stats (cm) ; } + diff --git a/CHOLMOD/MATLAB/chol2.m b/CHOLMOD/MATLAB/chol2.m index 7ee0b484c2..7303ffb338 100644 --- a/CHOLMOD/MATLAB/chol2.m +++ b/CHOLMOD/MATLAB/chol2.m @@ -1,9 +1,9 @@ -function [R,p,q] = chol2 (A) %#ok +function [R,p,q] = chol2 (A) %#ok %CHOL2 sparse Cholesky factorization, A=R'R. -% Note that A=L*L' (LCHOL) and A=L*D*L' (LDLCHOL) factorizations are faster -% than R'*R (CHOL2 and CHOL) and use less memory. The LL' and LDL' -% factorization methods use tril(A). This method uses triu(A), just like -% the built-in CHOL. +% Note that A=L*L' (LCHOL) and A=L*D*L' (LDLCHOL) factorizations are +% faster than R'*R (CHOL2 and CHOL) and use less memory. The LL' and +% LDL' factorization methods use tril(A). This method uses triu(A), just +% like the built-in CHOL. % % Example: % R = chol2 (A) same as R = chol (A), just faster @@ -11,11 +11,11 @@ % [R,p,q] = chol2 (A) factorizes A(q,q) into R'*R, where q is % a fill-reducing ordering % -% A must be sparse. +% A must be sparse. % -% See also LCHOL, LDLCHOL, CHOL, LDLUPDATE. +% See also lchol, ldlchol, chol, ldlupdate. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('chol2 mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/cholmod2.c b/CHOLMOD/MATLAB/cholmod2.c index 39926534e6..0ec71bce24 100644 --- a/CHOLMOD/MATLAB/cholmod2.c +++ b/CHOLMOD/MATLAB/cholmod2.c @@ -2,55 +2,59 @@ // CHOLMOD/MATLAB/cholmod2: MATLAB interface to CHOLMOD x=A\b //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Supernodal sparse Cholesky backslash, x = A\b. Factorizes PAP' in LL' then - * solves a sparse linear system. Uses the diagonal and upper triangular part - * of A only. A must be sparse. b can be sparse or dense. - * - * Usage: - * - * x = cholmod2 (A, b) - * [x stats] = cholmod2 (A, b, ordering) % a scalar: 0,-1,-2, or -3 - * [x stats] = cholmod2 (A, b, p) % a permutation vector - * - * The 3rd argument select the ordering method to use. If not present or -1, - * the default ordering strategy is used (AMD, and then try METIS if AMD finds - * an ordering with high fill-in, and use the best method tried). - * - * Other options for the ordering parameter: - * - * 0 natural (no etree postordering) - * -1 use CHOLMOD's default ordering strategy (AMD, then try METIS) - * -2 AMD, and then try NESDIS (not METIS) if AMD has high fill-in - * -3 use AMD only - * -4 use METIS only - * -5 use NESDIS only - * -6 natural, but with etree postordering - * p user permutation (vector of size n, with a permutation of 1:n) - * - * stats(1) estimate of the reciprocal of the condition number - * stats(2) ordering used: - * 0: natural, 1: given, 2:amd, 3:metis, 4:nesdis, 5:colamd, - * 6: natural but postordered. - * stats(3) nnz(L) - * stats(4) flop count in Cholesky factorization. Excludes solution - * of upper/lower triangular systems, which can be easily - * computed from stats(3) (roughly 4*nnz(L)*size(b,2)). - * stats(5) memory usage in MB. - */ +// Supernodal sparse Cholesky backslash, x = A\b. Factorizes PAP' in LL' then +// solves a sparse linear system. Uses the diagonal and upper triangular part +// of A only. A must be sparse. b can be sparse or dense. +// +// Usage: +// +// x = cholmod2 (A, b) +// [x stats] = cholmod2 (A, b, ordering) % a scalar: 0,-1,-2, or -3 +// [x stats] = cholmod2 (A, b, p) % a permutation vector +// +// The 3rd argument select the ordering method to use. If not present or -1, +// the default ordering strategy is used (AMD, and then try METIS if AMD finds +// an ordering with high fill-in, and use the best method tried). +// +// A final string argument determines the precision to use: 'double' for +// double precision (real or complex) or 'single' for single precision +// (either real or complex). The default is 'double', even if all inputs +// are single. +// +// Other options for the ordering parameter: +// +// 0 natural (no etree postordering) +// -1 use CHOLMOD's default ordering strategy (AMD, then try METIS) +// -2 AMD, and then try NESDIS (not METIS) if AMD has high fill-in +// -3 use AMD only +// -4 use METIS only +// -5 use NESDIS only +// -6 natural, but with etree postordering +// p user permutation (vector of size n, with a permutation of 1:n) +// +// stats(1) estimate of the reciprocal of the condition number +// stats(2) ordering used: +// 0: natural, 1: given, 2:amd, 3:metis, 4:nesdis, 5:colamd, +// 6: natural but postordered. +// stats(3) nnz(L) +// stats(4) flop count in Cholesky factorization. Excludes solution +// of upper/lower triangular systems, which can be easily +// computed from stats(3) (roughly 4*nnz(L)*size(b,2)). +// stats(5) memory usage in MB. -#include "cholmod_matlab.h" +#include "sputil2.h" void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -61,69 +65,88 @@ void mexFunction cholmod_common Common, *cm ; int64_t n, B_is_sparse, ordering, k, *Perm ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* There is no supernodal LDL'. If cm->final_ll = FALSE (the default), then - * this mexFunction will use a simplicial LDL' when flops/lnz < 40, and a - * supernodal LL' otherwise. This may give suprising results to the MATLAB - * user, so always perform an LL' factorization by setting cm->final_ll - * to TRUE. */ + // There is no supernodal LDL'. If cm->final_ll = FALSE (the default), then + // this mexFunction will use a simplicial LDL' when flops/lnz < 40, and a + // supernodal LL' otherwise. This may give suprising results to the MATLAB + // user, so always perform an LL' factorization by setting cm->final_ll + // to TRUE. cm->final_ll = TRUE ; cm->quick_return_if_not_posdef = TRUE ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + // get the precision option + int dtype = CHOLMOD_DOUBLE ; + mxClassID mxdtype = mxDOUBLE_CLASS ; + if (nargin > 1 && mxIsChar (pargin [nargin-1])) + { + char str [LEN] ; + str [0] = '\0' ; + mxGetString (pargin [nargin-1], str, LEN) ; + if (str [0] == 's') ; + { + dtype = CHOLMOD_SINGLE ; + mxdtype = mxSINGLE_CLASS ; + } + nargin-- ; + } if (nargout > 2 || nargin < 2 || nargin > 3) { - mexErrMsgTxt ("usage: [x,rcond] = cholmod2 (A,b,ordering)") ; + mexErrMsgTxt ("usage: [x,rcond] = cholmod2 (A,b,ordering,prec)") ; } n = mxGetM (pargin [0]) ; if (!mxIsSparse (pargin [0]) || (n != mxGetN (pargin [0]))) { - mexErrMsgTxt ("A must be square and sparse") ; + mexErrMsgTxt ("A must be square and sparse") ; } if (n != mxGetM (pargin [1])) { - mexErrMsgTxt ("# of rows of A and B must match") ; + mexErrMsgTxt ("# of rows of A and B must match") ; } - /* get sparse matrix A. Use triu(A) only. */ - A = sputil_get_sparse (pargin [0], &Amatrix, &dummy, 1) ; + // get sparse matrix A. Use triu(A) only. + size_t A_xsize = 0 ; + A = sputil2_get_sparse (pargin [0], 1, dtype, &Amatrix, &A_xsize, cm) ; - /* get sparse or dense matrix B */ + // get sparse or dense matrix B B = NULL ; Bs = NULL ; B_is_sparse = mxIsSparse (pargin [1]) ; + size_t B_xsize = 0 ; if (B_is_sparse) { - /* get sparse matrix B (unsymmetric) */ - Bs = sputil_get_sparse (pargin [1], &Bspmatrix, &dummy, 0) ; + // get sparse matrix B (unsymmetric) + Bs = sputil2_get_sparse (pargin [1], 0, dtype, &Bspmatrix, &B_xsize, + cm) ; } else { - /* get dense matrix B */ - B = sputil_get_dense (pargin [1], &Bmatrix, &dummy) ; + // get dense matrix B + B = sputil2_get_dense (pargin [1], dtype, &Bmatrix, &B_xsize, cm) ; } - /* get the ordering option */ + // get the ordering option if (nargin < 3) { - /* use default ordering */ - ordering = -1 ; + // use default ordering + ordering = -1 ; } else { - /* use a non-default option */ - ordering = mxGetScalar (pargin [2]) ; + // use a non-default option + ordering = mxGetScalar (pargin [2]) ; } p = NULL ; @@ -131,140 +154,148 @@ void mexFunction if (ordering == 0) { - /* natural ordering */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = FALSE ; + // natural ordering + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = FALSE ; } else if (ordering == -1) { - /* default strategy ... nothing to change */ + // default strategy ... nothing to change } else if (ordering == -2) { - /* default strategy, but with NESDIS in place of METIS */ - cm->default_nesdis = TRUE ; + // default strategy, but with NESDIS in place of METIS + cm->default_nesdis = TRUE ; } else if (ordering == -3) { - /* use AMD only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_AMD ; - cm->postorder = TRUE ; + // use AMD only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_AMD ; + cm->postorder = TRUE ; } else if (ordering == -4) { - /* use METIS only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_METIS ; - cm->postorder = TRUE ; + // use METIS only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_METIS ; + cm->postorder = TRUE ; } else if (ordering == -5) { - /* use NESDIS only */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NESDIS ; - cm->postorder = TRUE ; + // use NESDIS only + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NESDIS ; + cm->postorder = TRUE ; } else if (ordering == -6) { - /* natural ordering, but with etree postordering */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = TRUE ; + // natural ordering, but with etree postordering + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = TRUE ; } else if (ordering == -7) { - /* always try both AMD and METIS, and pick the best */ - cm->nmethods = 2 ; - cm->method [0].ordering = CHOLMOD_AMD ; - cm->method [1].ordering = CHOLMOD_METIS ; - cm->postorder = TRUE ; + // always try both AMD and METIS, and pick the best + cm->nmethods = 2 ; + cm->method [0].ordering = CHOLMOD_AMD ; + cm->method [1].ordering = CHOLMOD_METIS ; + cm->postorder = TRUE ; } else if (ordering >= 1) { - /* assume the 3rd argument is a user-provided permutation of 1:n */ - if (mxGetNumberOfElements (pargin [2]) != n) - { - mexErrMsgTxt ("invalid input permutation") ; - } - /* copy from double to integer, and convert to 0-based */ - p = mxGetPr (pargin [2]) ; - Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - for (k = 0 ; k < n ; k++) - { - Perm [k] = p [k] - 1 ; - } - /* check the permutation */ - if (!cholmod_l_check_perm (Perm, n, n, cm)) - { - mexErrMsgTxt ("invalid input permutation") ; - } - /* use only the given permutation */ - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_GIVEN ; - cm->postorder = FALSE ; + // assume the 3rd argument is a user-provided permutation of 1:n + if (mxGetNumberOfElements (pargin [2]) != n) + { + mexErrMsgTxt ("invalid input permutation") ; + } + // copy from double to integer, and convert to 0-based + p = (double *) mxGetData (pargin [2]) ; + Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + for (k = 0 ; k < n ; k++) + { + Perm [k] = p [k] - 1 ; + } + // check the permutation + if (!cholmod_l_check_perm (Perm, n, n, cm)) + { + mexErrMsgTxt ("invalid input permutation") ; + } + // use only the given permutation + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_GIVEN ; + cm->postorder = FALSE ; } else { - mexErrMsgTxt ("invalid ordering option") ; + mexErrMsgTxt ("invalid ordering option") ; } - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- L = cholmod_l_analyze_p (A, Perm, NULL, 0, cm) ; cholmod_l_free (n, sizeof (int64_t), Perm, cm) ; cholmod_l_factorize (A, L, cm) ; rcond = cholmod_l_rcond (L, cm) ; - if (rcond == 0) { - mexWarnMsgTxt ("Matrix is indefinite or singular to working precision"); + mexWarnMsgTxt ("Matrix is indefinite or singular to working precision"); } else if (rcond < DBL_EPSILON) { - mexWarnMsgTxt ("Matrix is close to singular or badly scaled.") ; - mexPrintf (" Results may be inaccurate. RCOND = %g.\n", rcond) ; + mexWarnMsgTxt ("Matrix is close to singular or badly scaled.") ; + mexPrintf (" Results may be inaccurate. RCOND = %g.\n", rcond) ; } - /* ---------------------------------------------------------------------- */ - /* solve and return solution to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve and return solution to MATLAB + //-------------------------------------------------------------------------- if (B_is_sparse) { - /* solve AX=B with sparse X and B; return sparse X to MATLAB */ - Xs = cholmod_l_spsolve (CHOLMOD_A, L, Bs, cm) ; - pargout [0] = sputil_put_sparse (&Xs, cm) ; + // solve AX=B with sparse X and B; return sparse X to MATLAB. + // The sparse X must be returned to MATLAB as double since MATLAB + // does not (yet) support sparse single precision matrices. + // cholmod_l_spsolve returns Xs with no explicit zeros. + Xs = cholmod_l_spsolve (CHOLMOD_A, L, Bs, cm) ; + pargout [0] = sputil2_put_sparse (&Xs, mxDOUBLE_CLASS, + /* already done by cholmod_l_spsolve: */ false, cm) ; } else { - /* solve AX=B with dense X and B; return dense X to MATLAB */ - X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; - pargout [0] = sputil_put_dense (&X, cm) ; + // solve AX=B with dense X and B; return dense X to MATLAB + X = cholmod_l_solve (CHOLMOD_A, L, B, cm) ; + // the dense X can be returned in its current type + pargout [0] = sputil2_put_dense (&X, mxdtype, cm) ; } - /* return statistics, if requested */ + // return statistics, if requested if (nargout > 1) { - pargout [1] = mxCreateDoubleMatrix (1, 5, mxREAL) ; - p = mxGetPr (pargout [1]) ; - p [0] = rcond ; - p [1] = L->ordering ; - p [2] = cm->lnz ; - p [3] = cm->fl ; - p [4] = cm->memory_usage / 1048576. ; + pargout [1] = mxCreateDoubleMatrix (1, 5, mxREAL) ; + p = (double *) mxGetData (pargout [1]) ; + p [0] = rcond ; + p [1] = L->ordering ; + p [2] = cm->lnz ; + p [3] = cm->fl ; + p [4] = cm->memory_usage / 1048576. ; } + //-------------------------------------------------------------------------- + // free workspace and return result + //-------------------------------------------------------------------------- + + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; + sputil2_free_sparse (&Bs, &Bspmatrix, B_xsize, cm) ; + sputil2_free_dense (&B, &Bmatrix, B_xsize, cm) ; cholmod_l_free_factor (&L, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != - (mxIsComplex (pargout [0]) + (mxIsSparse (pargout[0]) ? 3:1))) - mexErrMsgTxt ("memory leak!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 1) cholmod_l_gpu_stats (cm) ; } + diff --git a/CHOLMOD/MATLAB/cholmod2.m b/CHOLMOD/MATLAB/cholmod2.m index ba4dcb2b4d..6a0813be51 100644 --- a/CHOLMOD/MATLAB/cholmod2.m +++ b/CHOLMOD/MATLAB/cholmod2.m @@ -1,27 +1,28 @@ -function [x,stats] = cholmod2 (A, b, ordering) %#ok +function [x,stats] = cholmod2 (A, b, ordering) %#ok %CHOLMOD2 supernodal sparse Cholesky backslash, x = A\b % % Example: % x = cholmod2 (A,b) % -% Computes the LL' factorization of A(p,p), where p is a fill-reducing -% ordering, then solves a sparse linear system Ax=b. A must be sparse, -% symmetric, and positive definite). Uses only the upper triangular part -% of A. A second output, [x,stats]=cholmod2(A,b), returns statistics: +% Computes the LL' factorization of A(p,p), where p is a fill-reducing +% ordering, then solves a sparse linear system Ax=b. A must be sparse, +% symmetric, and positive definite). Uses only the upper triangular part +% of A. A second output, [x,stats]=cholmod2(A,b), returns statistics: % -% stats(1) estimate of the reciprocal of the condition number -% stats(2) ordering used: +% stats(1) estimate of the reciprocal of the condition number +% stats(2) ordering used: % 0: natural, 1: given, 2:amd, 3:metis, 4:nesdis, % 5:colamd, 6: natural but postordered. -% stats(3) nnz(L) -% stats(4) flop count in Cholesky factorization. Excludes solution -% of upper/lower triangular systems, which can be easily -% computed from stats(3) (roughly 4*nnz(L)*size(b,2)). -% stats(5) memory usage in MB. +% stats(3) nnz(L) +% stats(4) flop count in Cholesky factorization. Excludes solution +% of upper/lower triangular systems, which can be easily +% computed from stats(3) (roughly 4*nnz(L)*size(b,2)). +% stats(5) memory usage in MB. % -% The 3rd argument select the ordering method to use. If not present or -1, -% the default ordering strategy is used (AMD, and then try METIS if AMD finds -% an ordering with high fill-in, and use the best method tried). +% The 3rd argument select the ordering method to use. If not present or +% -1, the default ordering strategy is used (AMD, and then try METIS if +% AMD finds an ordering with high fill-in, and use the best method +% tried). % % Other options for the ordering parameter: % @@ -34,9 +35,9 @@ % -6 natural, but with etree postordering % p user permutation (vector of size n, with a permutation of 1:n) % -% See also CHOL, MLDIVIDE. +% See also chol, mldivide. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('cholmod2 mexFunction not found\n') ; diff --git a/CHOLMOD/MATLAB/cholmod_demo.m b/CHOLMOD/MATLAB/cholmod_demo.m index 14bbbb8010..6202c7d05f 100644 --- a/CHOLMOD/MATLAB/cholmod_demo.m +++ b/CHOLMOD/MATLAB/cholmod_demo.m @@ -1,78 +1,32 @@ function cholmod_demo %CHOLMOD_DEMO a demo for CHOLMOD % -% Tests CHOLMOD with various randomly-generated matrices, and the west0479 -% matrix distributed with MATLAB. Random matrices are not good test cases, -% but they are easily generated. It also compares CHOLMOD and MATLAB on the -% sparse matrix problem used in the MATLAB BENCH command. +% Tests CHOLMOD with the sparse matrix problem used in the MATLAB bench +% program, with various sizes. Note that MATLAB uses CHOLMOD itself for +% x=A\b, chol, etc. so the timings should be comparable. % -% See CHOLMOD/MATLAB/Test/cholmod_test.m for a lengthy test using matrices from -% the SuiteSparse Matrix Collection. +% See CHOLMOD/MATLAB/Test/cholmod_test.m for a lengthy test using +% matrices from the SuiteSparse Matrix Collection. % % Example: % cholmod_demo % -% See also BENCH +% See also bench. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ help cholmod_demo -rand ('state', 0) ; -randn ('state', 0) ; - -load west0479 -A = west0479 ; -n = size (A,1) ; -A = A*A'+100*speye (n) ; -try_matrix (A) ; -clear A - -n = 2000 ; -A = sprandn (n, n, 0.002) ; -A = A+A'+100*speye (n) ; -try_matrix (A) ; -clear A - -for n = [100 2000] - A = rand (n) ; - A = A*A' + 10 * eye (n) ; + % matrix from bench (n = 600 is used in 'bench'): +for n = [600 1200] + A = delsq (numgrid ('L', n)) ; try_matrix (A) ; - clear A end -fprintf ('\n--------------------------------------------------------------\n') ; -fprintf ('\nWith the matrix used in the MATLAB 7.2 "bench" program.\n') ; - -n = 300 ; -A = delsq (numgrid ('L', n)) ; -b = sum (A)' ; - -tic ; -x = A\b ; -t1 = toc ; -e1 = norm (A*x-b) ; - -tic ; -x = cholmod2 (A,b) ; -t2 = toc ; -e2 = norm (A*x-b) ; - -fprintf ('MATLAB x=A\\b time: %8.4f resid: %8.0e\n', t1, e1) ; -fprintf ('CHOLMOD x=A\\b time: %8.4f resid: %8.0e\n', t2, e2) ; -fprintf ('CHOLMOD speedup: %8.2f\n', t1/t2) ; - -fprintf ('\ncholmod_demo finished: all tests passed\n') ; -fprintf ('\nFor more accurate timings, run this test again.\n') ; - - - - - - + %------------------------------------------------------------------------- function try_matrix (A) - % try_matrix: try a matrix with CHOLMOD + % try_matrix: try a matrix with CHOLMOD n = size (A,1) ; S = sparse (A) ; @@ -84,8 +38,8 @@ function try_matrix (A) fprintf ('cholmod_demo: dense matrix, n %d\n', n) ; end -X = rand (n,1) ; -C = sparse (X) ; +k = max (1,fix(n/2)) ; +C = A (:,k) * 0.1 ; try % use built-in AMD p = amd (S) ; @@ -104,16 +58,16 @@ function try_matrix (A) fl = sum (lnz.^2) ; tic -L = lchol (S) ; %#ok +L = lchol (S) ; %#ok t1 = toc ; -fprintf ('CHOLMOD lchol(sparse(A)) time: %6.2f mflop %8.1f\n', ... - t1, 1e-6 * fl / t1) ; +fprintf ('CHOLMOD lchol(sparse(A)) time: %6.2f gflop %8.2f\n', ... + t1, 1e-9 * fl / t1) ; tic -LD = ldlchol (S) ; %#ok +LD = ldlchol (S) ; t2 = toc ; -fprintf ('CHOLMOD ldlchol(sparse(A)) time: %6.2f mflop %8.1f\n', ... - t2, 1e-6 * fl / t2) ; +fprintf ('CHOLMOD ldlchol(sparse(A)) time: %6.2f gflop %8.2f\n', ... + t2, 1e-9 * fl / t2) ; tic LD2 = ldlupdate (LD,C) ; @@ -121,11 +75,10 @@ function try_matrix (A) fprintf ('CHOLMOD ldlupdate(sparse(A),C) time: %6.2f (rank-1, C dense)\n', t3) ; [L,D] = ldlsplit (LD2) ; -% L = full (L) ; -err = norm ((S+C*C') - L*D*L', 1) / norm (S,1) ; + % err = norm ((S+C*C') - L*D*L', 1) / norm (S,1) ; +err = ldl_normest ((S+C*C'), L, D) / norm (S,1) ; fprintf ('err: %g\n', err) ; -k = max (1,fix(n/2)) ; tic LD3 = ldlrowmod (LD, k) ; t4 = toc ; @@ -136,27 +89,54 @@ function try_matrix (A) I = speye (n) ; S2 (k,:) = I (k,:) ; S2 (:,k) = I (:,k) ; -err = norm (S2 - L*D*L', 1) / norm (S,1) ; + % err = norm (S2 - L*D*L', 1) / norm (S,1) ; +err = ldl_normest (S2, L, D) / norm (S,1) ; fprintf ('err: %g\n', err) ; LD4 = ldlchol (S2) ; [L,D] = ldlsplit (LD4) ; -% L = full (L) ; -err = norm (S2 - L*D*L', 1) / norm (S,1) ; + % err = norm (S2 - L*D*L', 1) / norm (S,1) ; +err = ldl_normest (S2, L, D) / norm (S,1) ; fprintf ('err: %g\n', err) ; tic -R = chol (S) ; %#ok +R = chol (S) ; %#ok s1 = toc ; -fprintf ('MATLAB chol(sparse(A)) time: %6.2f mflop %8.1f\n', ... - s1, 1e-6 * fl / s1) ; +fprintf ('MATLAB chol(sparse(A)) time: %6.2f gflop %8.2f\n', ... + s1, 1e-9 * fl / s1) ; + +fprintf ('CHOLMOD lchol(sparse(A)) speedup over chol(sparse(A)): %6.1f\n', ... + s1 / t1) ; + +b = sum (A)' ; + +tic ; +x = A\b ; +t1 = toc ; +e1 = norm (A*x-b, 1) ; + +tic ; +x = cholmod2 (A,b) ; +t2 = toc ; +e2 = norm (A*x-b) ; + +fprintf ('MATLAB x=A\\b time: %8.4f resid: %8.0e\n', t1, e1) ; +fprintf ('CHOLMOD x=A\\b time: %8.4f resid: %8.0e\n', t2, e2) ; +fprintf ('CHOLMOD speedup: %8.2f\n', t1/t2) ; + +if (n > 4000) + % problem is too large for full matrix tests + return ; +end + % tests with full matrices: +X = full (C) ; E = full (A) ; tic R = chol (E) ; s2 = toc ; -fprintf ('MATLAB chol(full(A)) time: %6.2f mflop %8.1f\n', ... - s2, 1e-6 * fl / s2) ; +fprintf ('MATLAB chol(full(A)) time: %6.2f gflop %8.2f\n', ... + s2, 1e-9 * fl / s2) ; Z = full (R) ; tic @@ -167,11 +147,6 @@ function try_matrix (A) err = norm ((E+X*X') - Z'*Z, 1) / norm (E,1) ; fprintf ('err: %g\n', err) ; -fprintf ('CHOLMOD lchol(sparse(A)) speedup over chol(sparse(A)): %6.1f\n', ... - s1 / t1) ; - fprintf ('CHOLMOD sparse update speedup vs MATLAB DENSE update: %6.1f\n', ... s3 / t3) ; -clear E S L R LD X C D Z -clear err s1 s2 s3 t1 t2 t3 n diff --git a/CHOLMOD/MATLAB/cholmod_install.m b/CHOLMOD/MATLAB/cholmod_install.m index 4700c32650..80a177eb14 100644 --- a/CHOLMOD/MATLAB/cholmod_install.m +++ b/CHOLMOD/MATLAB/cholmod_install.m @@ -5,19 +5,16 @@ % cholmod_install % compiles using METIS % % CHOLMOD relies on AMD and COLAMD, for its ordering options, and can -% optionally use CCOLAMD, CAMD, and METIS as well. By default, CCOLAMD, CAMD, -% and METIS are used. -% -% See http://www-users.cs.umn.edu/~karypis/metis for a copy of METIS 5.1.0. -% SuiteSparse uses a slightly-modified version of METIS 5.1.0. +% optionally use CCOLAMD, CAMD, and METIS as well. By default, CCOLAMD, +% CAMD, and METIS are used. % % You can only use cholmod_install while in the CHOLMOD/MATLAB directory. % -% See also analyze, bisect, chol2, cholmod2, etree2, lchol, ldlchol, ldlsolve, -% ldlupdate, metis, spsym, nesdis, septree, resymbol, sdmult, sparse2, -% symbfact2, mread, mwrite, amd2, colamd2, camd, ccolamd, ldlrowmod +% See also analyze, bisect, chol2, cholmod2, etree2, lchol, ldlchol, +% ldlsolve, ldlupdate, metis, spsym, nesdis, septree, resymbol, sdmult, +% symbfact2, mread, mwrite, amd2, colamd2, camd, ccolamd, ldlrowmod. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ % compile CHOLMOD and add to the path diff --git a/CHOLMOD/MATLAB/cholmod_make.m b/CHOLMOD/MATLAB/cholmod_make.m index a8c3a1e260..ad75ccf116 100644 --- a/CHOLMOD/MATLAB/cholmod_make.m +++ b/CHOLMOD/MATLAB/cholmod_make.m @@ -4,59 +4,45 @@ % Example: % cholmod_make % -% CHOLMOD relies on AMD and COLAMD, and optionally CCOLAMD, CAMD, and METIS. -% You must type the cholmod_make command while in the CHOLMOD/MATLAB directory. +% CHOLMOD relies on AMD and COLAMD, and optionally CCOLAMD, CAMD, and +% METIS. You must type the cholmod_make command while in the +% CHOLMOD/MATLAB directory. % -% See also analyze, bisect, chol2, cholmod2, etree2, lchol, ldlchol, ldlsolve, -% ldlupdate, metis, spsym, nesdis, septree, resymbol, sdmult, sparse2, -% symbfact2, mread, mwrite, ldlrowmod +% See also analyze, bisect, chol2, cholmod2, etree2, lchol, ldlchol, +% ldlsolve, ldlupdate, metis, spsym, nesdis, septree, resymbol, sdmult, +% symbfact2, mread, mwrite, ldlrowmod. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ -details = 0 ; % 1 if details of each command are to be printed +if verLessThan ('matlab', '9.4') + error ('MATLAB 9.4 (R2018a) or later is required') ; +end + +details = 0 ; % 1 if details of each command are to be printed v = version ; try % ispc does not appear in MATLAB 5.3 pc = ispc ; mac = ismac ; -catch %#ok +catch % if ispc fails, assume we are on a Windows PC if it's not unix pc = ~isunix ; mac = 0 ; end -flags = '' ; -is64 = ~isempty (strfind (computer, '64')) ; -if (is64) - % 64-bit MATLAB - flags = '-largeArrayDims' ; -else - error ('32-bit version no longer supported') ; -end - -% MATLAB 8.3.0 now has a -silent option to keep 'mex' from burbling too much -if (~verLessThan ('matlab', '8.3.0')) - flags = ['-silent ' flags] ; -end + % -R2018a: interleaved complex is required +flags = '-O -R2018a -silent ' ; include = '-I. -I.. -I../../AMD/Include -I../../COLAMD/Include -I../../CCOLAMD/Include -I../../CAMD/Include -I../Include -I../../SuiteSparse_config' ; -if (verLessThan ('matlab', '7.0')) - % do not attempt to compile CHOLMOD with large file support - include = [include ' -DNLARGEFILE'] ; -elseif (~pc) +if (~pc) % Linux/Unix require these flags for large file support include = [include ' -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE'] ; end -if (verLessThan ('matlab', '6.5')) - % logical class does not exist in MATLAB 6.1 or earlier - include = [include ' -DMATLAB6p1_OR_EARLIER'] ; -end - -% Determine if METIS is available + % Determine if METIS is available have_metis = exist ('../SuiteSparse_metis', 'dir') ; if (have_metis) @@ -79,9 +65,7 @@ if (pc) % BLAS/LAPACK functions have no underscore on Windows flags = [flags ' -DBLAS_NO_UNDERSCORE'] ; - if (verLessThan ('matlab', '7.5')) - lapack = 'libmwlapack.lib' ; - elseif (verLessThan ('matlab', '9.5')) + if (verLessThan ('matlab', '9.5')) lapack = 'libmwlapack.lib libmwblas.lib' ; else lapack = '-lmwlapack -lmwblas' ; @@ -89,25 +73,18 @@ else % BLAS/LAPACK functions have an underscore suffix flags = [flags ' -DBLAS_UNDERSCORE'] ; - if (verLessThan ('matlab', '7.5')) - lapack = '-lmwlapack' ; - else - lapack = '-lmwlapack -lmwblas' ; - end + lapack = '-lmwlapack -lmwblas' ; end -if (~verLessThan ('matlab', '7.8')) - % versions 7.8 and later on 64-bit platforms use a 64-bit BLAS - fprintf ('with 64-bit BLAS\n') ; - flags = [flags ' -DBLAS64'] ; -end + % using the 64-bit BLAS +flags = [flags ' -DBLAS64'] ; if (~(pc || mac)) % for POSIX timing routine lapack = [lapack ' -lrt'] ; end - %------------------------------------------------------------------------------- + %------------------------------------------------------------------------------ config_src = { '../../SuiteSparse_config/SuiteSparse_config' } ; @@ -138,7 +115,7 @@ '../../COLAMD/Source/colamd_l', ... '../../CCOLAMD/Source/ccolamd_l' } ; -cholmod_matlab = { 'cholmod_matlab' } ; +sputil2 = { 'sputil2' } ; cholmod_src = { '../Utility/cholmod_l_aat', ... @@ -265,7 +242,6 @@ 'septree', ... 'resymbol', ... 'sdmult', ... - 'sparse2', ... 'symbfact2', ... 'mread', ... 'mwrite', ... @@ -280,7 +256,7 @@ % compile each library source file obj = '' ; -source = [ordering_src config_src cholmod_src cholmod_matlab] ; +source = [sputil2 ordering_src config_src cholmod_src ] ; kk = 0 ; @@ -294,34 +270,35 @@ end o = ff (slash:end) ; % fprintf ('%s\n', o) ; - o = [o obj_extension] ; - obj = [obj ' ' o] ; %#ok - s = sprintf ('mex %s -O %s -c %s.c', flags, include, ff) ; - kk = do_cmd (s, kk, details) ; + o = [o obj_extension] ; %#ok + obj = [obj ' ' o] ; %#ok + s = sprintf ('mex %s %s -c %s.c', flags, include, ff) ; + kk = do_cmd (s, kk, details, '.') ; end % compile each mexFunction for f = cholmod_mex_src - s = sprintf ('mex %s -O %s %s.c', flags, include, f{1}) ; - s = [s obj ' ' lapack] ; %#ok - kk = do_cmd (s, kk, details) ; + s = sprintf ('mex %s %s %s.c', flags, include, f{1}) ; + s = [s obj ' ' lapack] ; %#ok + kk = do_cmd (s, kk, details, ':') ; end % clean up s = ['delete ' obj] ; -do_cmd (s, kk, details) ; +do_cmd (s, kk, details, '.') ; fprintf ('\nCHOLMOD successfully compiled\n') ; - %------------------------------------------------------------------------------ -function kk = do_cmd (s, kk, details) + %----------------------------------------------------------------------------- +function kk = do_cmd (s, kk, details, progress) %DO_CMD: evaluate a command, and either print it or print a "." if (details) fprintf ('%s\n', s) ; else if (mod (kk, 60) == 0) - fprintf ('\n') ; + fprintf ('\n') ; end kk = kk + 1 ; - fprintf ('.') ; + fprintf (progress) ; end eval (s) ; + diff --git a/CHOLMOD/MATLAB/cholmod_matlab.c b/CHOLMOD/MATLAB/cholmod_matlab.c deleted file mode 100644 index cb86ca5e7e..0000000000 --- a/CHOLMOD/MATLAB/cholmod_matlab.c +++ /dev/null @@ -1,2151 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/MATLAB/cholmod_matlab.c: utilities for CHOLMOD's MATLAB interface -//------------------------------------------------------------------------------ - -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Utility routines for the CHOLMOD MATLAB mexFunctions. - * - * If CHOLMOD runs out of memory, MATLAB will terminate the mexFunction - * immediately since it uses mxMalloc (see sputil_config, below). Likewise, - * if mxCreate* or mxMalloc (as called in this file) fails, MATLAB will also - * terminate the mexFunction. When this occurs, MATLAB frees all allocated - * memory, so we don't have to worry about memory leaks. If this were not the - * case, the routines in this file would suffer from memory leaks whenever an - * error occurred. - */ - -#include "cholmod_matlab.h" - -/* This file pointer is used for the mread and mwrite mexFunctions. It must - * be a global variable, because the file pointer is not passed to the - * sputil_error_handler function when an error occurs. */ -FILE *sputil_file = NULL ; - -/* ========================================================================== */ -/* === sputil_config ======================================================== */ -/* ========================================================================== */ - -/* Define function pointers and other parameters for a mexFunction */ - -void sputil_config (int64_t spumoni, cholmod_common *cm) -{ - /* cholmod_l_solve must return a real or zomplex X for MATLAB */ - cm->prefer_zomplex = TRUE ; - - /* printing and error handling */ - if (spumoni == 0) - { - /* do not print anything from within CHOLMOD */ - cm->print = -1 ; - SuiteSparse_config_printf_func_set (NULL) ; - } - else - { - /* spumoni = 1: print warning and error messages. cholmod_l_print_* - * routines will print a one-line summary of each object printed. - * spumoni = 2: also print a short summary of each object. - */ - cm->print = spumoni + 2 ; - /* SuiteSparse_config_printf_func_set ((void *) mexPrintf) ; */ - } - - /* error handler */ - cm->error_handler = sputil_error_handler ; - - /* Turn off METIS memory guard. It is not needed, because mxMalloc will - * safely terminate the mexFunction and free any workspace without killing - * all of MATLAB. This assumes cholmod_make was used to compile CHOLMOD - * for MATLAB. */ - cm->metis_memory = 0.0 ; -} - - -/* ========================================================================== */ -/* === sputil_error_handler ================================================= */ -/* ========================================================================== */ - -void sputil_error_handler (int status, const char *file, int line, - const char *message) -{ - if (status < CHOLMOD_OK) - { - /* - mexPrintf ("ERROR: file %s line %d, status %d\n", file, line, status) ; - */ - if (sputil_file != NULL) - { - fclose (sputil_file) ; - sputil_file = NULL ; - } - mexErrMsgTxt (message) ; - } - /* - else - { - mexPrintf ("Warning: file %s line %d, status %d\n", file, line, status); - } - */ -} - - -/* ========================================================================== */ -/* === sputil_get_sparse ==================================================== */ -/* ========================================================================== */ - -/* Create a shallow CHOLMOD copy of a MATLAB sparse matrix. No memory is - * allocated. The resulting matrix A must not be modified. - */ - -cholmod_sparse *sputil_get_sparse -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_sparse *A, /* CHOLMOD version of the matrix */ - double *dummy, /* a pointer to a valid scalar double */ - int64_t stype /* -1: lower, 0: unsymmetric, 1: upper */ -) -{ - int64_t *Ap ; - A->nrow = mxGetM (Amatlab) ; - A->ncol = mxGetN (Amatlab) ; - A->p = (int64_t *) mxGetJc (Amatlab) ; - A->i = (int64_t *) mxGetIr (Amatlab) ; - Ap = A->p ; - A->nzmax = Ap [A->ncol] ; - A->packed = TRUE ; - A->sorted = TRUE ; - A->nz = NULL ; - A->itype = CHOLMOD_LONG ; /* was CHOLMOD_INT in v1.6 and earlier */ - A->dtype = CHOLMOD_DOUBLE ; - A->stype = stype ; - -#ifndef MATLAB6p1_OR_EARLIER - - if (mxIsLogical (Amatlab)) - { - A->x = NULL ; - A->z = NULL ; - A->xtype = CHOLMOD_PATTERN ; - } - else if (mxIsEmpty (Amatlab)) - { - /* this is not dereferenced, but the existence (non-NULL) of these - * pointers is checked in CHOLMOD */ - A->x = dummy ; - A->z = dummy ; - A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; - } - else if (mxIsDouble (Amatlab)) - { - A->x = mxGetPr (Amatlab) ; - A->z = mxGetPi (Amatlab) ; - A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; - } - else - { - /* only logical and complex/real double matrices supported */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - -#else - - if (mxIsEmpty (Amatlab)) - { - /* this is not dereferenced, but the existence (non-NULL) of these - * pointers is checked in CHOLMOD */ - A->x = dummy ; - A->z = dummy ; - A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; - } - else - { - /* in MATLAB 6.1, the matrix is sparse, so it must be double */ - A->x = mxGetPr (Amatlab) ; - A->z = mxGetPi (Amatlab) ; - A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; - } - -#endif - - return (A) ; -} - - -/* ========================================================================== */ -/* === sputil_get_dense ===================================================== */ -/* ========================================================================== */ - -/* Create a shallow CHOLMOD copy of a MATLAB dense matrix. No memory is - * allocated. Only double (real and zomplex) matrices are supported. The - * resulting matrix B must not be modified. - */ - -cholmod_dense *sputil_get_dense -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_dense *A, /* CHOLMOD version of the matrix */ - double *dummy /* a pointer to a valid scalar double */ -) -{ - A->nrow = mxGetM (Amatlab) ; - A->ncol = mxGetN (Amatlab) ; - A->d = A->nrow ; - A->nzmax = A->nrow * A->ncol ; - A->dtype = CHOLMOD_DOUBLE ; - - if (mxIsEmpty (Amatlab)) - { - A->x = dummy ; - A->z = dummy ; - } - else if (mxIsDouble (Amatlab)) - { - A->x = mxGetPr (Amatlab) ; - A->z = mxGetPi (Amatlab) ; - } - else - { - /* only full double matrices supported by sputil_get_dense */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; - - return (A) ; -} - - -/* ========================================================================== */ -/* === sputil_get_sparse_pattern ============================================ */ -/* ========================================================================== */ - -/* Create a CHOLMOD_PATTERN sparse matrix for a MATLAB matrix, depending on the - * type: - * - * (1) MATLAB full real double: duplicate CHOLMOD_REAL sparse matrix. - * (2) MATLAB full complex double: duplicate CHOLMOD_ZOMPLEX sparse matrix. - * (3) MATLAB full logical: duplicate CHOLMOD_PATTERN sparse matrix. - * (4) MATLAB sparse real double: shallow CHOLMOD_REAL copy. - * (5) MATLAB sparse complex double: shallow CHOLMOD_ZOMPLEX copy. - * (6) MATLAB sparse logical: shallow CHOLMOD_PATTERN copy. - * - * A shallow copy or duplicate is returned; the shallow copy must not be freed. - * For a shallow copy, the return value A is the same as Ashallow. For a - * complete duplicate, A and Ashallow will differ. - */ - -cholmod_sparse *sputil_get_sparse_pattern -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_sparse *Ashallow, /* shallow CHOLMOD version of the matrix */ - double *dummy, /* a pointer to a valid scalar double */ - cholmod_common *cm -) -{ - cholmod_sparse *A = NULL ; - - if (!mxIsSparse (Amatlab)) - { - - /* ------------------------------------------------------------------ */ - /* A = sparse (X) where X is full */ - /* ------------------------------------------------------------------ */ - - if (mxIsDouble (Amatlab)) - { - - /* -------------------------------------------------------------- */ - /* convert full double X into sparse matrix A (pattern only) */ - /* -------------------------------------------------------------- */ - - cholmod_dense Xmatrix, *X ; - X = sputil_get_dense (Amatlab, &Xmatrix, dummy) ; - A = cholmod_l_dense_to_sparse (X, FALSE, cm) ; - - } - -#ifndef MATLAB6p1_OR_EARLIER - - else if (mxIsLogical (Amatlab)) - { - - /* -------------------------------------------------------------- */ - /* convert full logical MATLAB matrix into CHOLMOD_PATTERN */ - /* -------------------------------------------------------------- */ - - /* (this is copied and modified from t_cholmod_dense.c) */ - - char *x ; - int64_t *Ap, *Ai ; - int64_t nrow, ncol, i, j, nz, nzmax, p ; - - /* -------------------------------------------------------------- */ - /* count the number of nonzeros in the result */ - /* -------------------------------------------------------------- */ - - nrow = mxGetM (Amatlab) ; - ncol = mxGetN (Amatlab) ; - x = (char *) mxGetData (Amatlab) ; - nzmax = nrow * ncol ; - for (nz = 0, j = 0 ; j < nzmax ; j++) - { - if (x [j]) - { - nz++ ; - } - } - - /* -------------------------------------------------------------- */ - /* allocate the result A */ - /* -------------------------------------------------------------- */ - - A = cholmod_l_allocate_sparse (nrow, ncol, nz, TRUE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - - if (cm->status < CHOLMOD_OK) - { - return (NULL) ; /* out of memory */ - } - Ap = A->p ; - Ai = A->i ; - - /* -------------------------------------------------------------- */ - /* copy the full logical matrix into the sparse matrix A */ - /* -------------------------------------------------------------- */ - - p = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Ap [j] = p ; - for (i = 0 ; i < nrow ; i++) - { - if (x [i+j*nrow]) - { - Ai [p++] = i ; - } - } - } - /* ASSERT (p == nz) ; */ - Ap [ncol] = nz ; - } - -#endif - - else - { - /* only double and logical matrices supported */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - - } - else - { - - /* ------------------------------------------------------------------ */ - /* create a shallow copy of sparse matrix A (default stype is zero) */ - /* ------------------------------------------------------------------ */ - - A = sputil_get_sparse (Amatlab, Ashallow, dummy, 0) ; - A->x = NULL ; - A->z = NULL ; - A->xtype = CHOLMOD_PATTERN ; - } - - return (A) ; -} - - -/* ========================================================================== */ -/* === sputil_put_sparse ==================================================== */ -/* ========================================================================== */ - -/* Creates a true MATLAB version of a CHOLMOD sparse matrix. The CHOLMOD sparse - * matrix is destroyed. Both real and zomplex matrices are supported. - */ - -mxArray *sputil_put_sparse -( - cholmod_sparse **Ahandle, /* CHOLMOD version of the matrix */ - cholmod_common *cm -) -{ - mxArray *Amatlab ; - cholmod_sparse *A ; - A = *Ahandle ; - if (!A || A->x == NULL) mexErrMsgTxt ("invalid sparse matrix") ; - Amatlab = mxCreateSparse (0, 0, 0, - (A->xtype != CHOLMOD_REAL) ? mxCOMPLEX: mxREAL) ; - mxSetM (Amatlab, A->nrow) ; - mxSetN (Amatlab, A->ncol) ; - mxSetNzmax (Amatlab, A->nzmax) ; - MXFREE (mxGetJc (Amatlab)) ; - MXFREE (mxGetIr (Amatlab)) ; - MXFREE (mxGetPr (Amatlab)) ; - mxSetJc (Amatlab, A->p) ; - mxSetIr (Amatlab, A->i) ; - mxSetPr (Amatlab, A->x) ; - mexMakeMemoryPersistent (A->p) ; - mexMakeMemoryPersistent (A->i) ; - mexMakeMemoryPersistent (A->x) ; - if (A->xtype != CHOLMOD_REAL) - { - if (A->z == NULL) mexErrMsgTxt ("invalid complex sparse matrix") ; - MXFREE (mxGetPi (Amatlab)) ; - mxSetPi (Amatlab, A->z) ; - mexMakeMemoryPersistent (A->z) ; - } - A->p = NULL ; - A->i = NULL ; - A->x = NULL ; - A->z = NULL ; - cholmod_l_free_sparse (Ahandle, cm) ; - return (Amatlab) ; -} - - -/* ========================================================================== */ -/* === sputil_put_dense ===================================================== */ -/* ========================================================================== */ - -/* Creates a true MATLAB version of a CHOLMOD dense matrix. The CHOLMOD dense - * matrix is destroyed. Both real and zomplex matrices are supported. - */ - -mxArray *sputil_put_dense -( - cholmod_dense **Ahandle, /* CHOLMOD version of the matrix */ - cholmod_common *cm -) -{ - mxArray *Amatlab ; - cholmod_dense *A ; - A = *Ahandle ; - if (!A || A->x == NULL) mexErrMsgTxt ("invalid dense matrix") ; - Amatlab = mxCreateDoubleMatrix (0, 0, - (A->xtype != CHOLMOD_REAL) ? mxCOMPLEX: mxREAL) ; - mxSetM (Amatlab, A->nrow) ; - mxSetN (Amatlab, A->ncol) ; - MXFREE (mxGetPr (Amatlab)) ; - mxSetPr (Amatlab, A->x) ; - mexMakeMemoryPersistent (A->x) ; - if (A->xtype != CHOLMOD_REAL) - { - if (A->z == NULL) mexErrMsgTxt ("invalid complex dense matrix") ; - MXFREE (mxGetPi (Amatlab)) ; - mxSetPi (Amatlab, A->z) ; - mexMakeMemoryPersistent (A->z) ; - } - A->x = NULL ; - A->z = NULL ; - cholmod_l_free_dense (Ahandle, cm) ; - return (Amatlab) ; -} - - -/* ========================================================================== */ -/* === sputil_put_int ======================================================= */ -/* ========================================================================== */ - -/* Convert a int64_t vector into a double mxArray */ - -mxArray *sputil_put_int -( - int64_t *P, /* vector to convert */ - int64_t n, /* length of P */ - int64_t one_based /* 1 if convert from 0-based to 1-based, 0 otherwise */ -) -{ - double *p ; - mxArray *Q ; - int64_t i ; - Q = mxCreateDoubleMatrix (1, n, mxREAL) ; - p = mxGetPr (Q) ; - for (i = 0 ; i < n ; i++) - { - p [i] = (double) (P [i] + one_based) ; - } - return (Q) ; -} - - -/* ========================================================================== */ -/* === sputil_error ========================================================= */ -/* ========================================================================== */ - -/* An integer is out of range, or other error has occurred. */ - -void sputil_error -( - int64_t error, /* kind of error */ - int64_t is_index /* TRUE if a matrix index, FALSE if a matrix dimension */ -) -{ - if (error == ERROR_TOO_SMALL) - { - mexErrMsgTxt (is_index ? - "sparse: index into matrix must be positive" : - "sparse: sparse matrix sizes must be non-negative integers") ; - } - else if (error == ERROR_HUGE) - { - mexErrMsgTxt (is_index ? - "sparse: index into matrix is too large" : - "sparse: sparse matrix size is too large") ; - } - else if (error == ERROR_NOT_INTEGER) - { - mexErrMsgTxt (is_index ? - "sparse: index into matrix must be an integer" : - "sparse: sparse matrix size must be an integer") ; - } - else if (error == ERROR_TOO_LARGE) - { - mexErrMsgTxt ("sparse: index exceeds matrix dimensions") ; - } - else if (error == ERROR_USAGE) - { - mexErrMsgTxt ( - "Usage:\n" - "A = sparse (S)\n" - "A = sparse (i,j,s,m,n,nzmax)\n" - "A = sparse (i,j,s,m,n)\n" - "A = sparse (i,j,s)\n" - "A = sparse (m,n)\n") ; - } - else if (error == ERROR_LENGTH) - { - mexErrMsgTxt ("sparse: vectors must be the same lengths") ; - } - else if (error == ERROR_INVALID_TYPE) - { - mexErrMsgTxt ("matrix class not supported") ; - } -} - - -/* ========================================================================== */ -/* === sputil_double_to_int ================================================= */ -/* ========================================================================== */ - -/* convert a double into an integer */ - -int64_t sputil_double_to_int /* returns integer value of x */ -( - double x, /* double value to convert */ - int64_t is_index, /* TRUE if a matrix index, FALSE if a matrix dimension */ - int64_t n /* if a matrix index, x cannot exceed this dimension, - * except that -1 is treated as infinity */ -) -{ - int64_t i ; - if (x > INT64_MAX) - { - /* x is way too big for an integer */ - sputil_error (ERROR_HUGE, is_index) ; - } - else if (x < 0) - { - /* x must be non-negative */ - sputil_error (ERROR_TOO_SMALL, is_index) ; - } - i = (int64_t) x ; - if (x != (double) i) - { - /* x must be an integer */ - sputil_error (ERROR_NOT_INTEGER, is_index) ; - } - if (is_index) - { - if (i < 1) - { - sputil_error (ERROR_TOO_SMALL, is_index) ; - } - else if (i > n && n != EMPTY) - { - sputil_error (ERROR_TOO_LARGE, is_index) ; - } - } - return (i) ; -} - - -/* ========================================================================== */ -/* === sputil_nelements ===================================================== */ -/* ========================================================================== */ - -/* return the number of elements in an mxArray. Trigger an error on integer - * overflow (in case the argument is sparse) */ - -int64_t sputil_nelements (const mxArray *arg) -{ - double size ; - const int64_t *dims ; - int64_t k, ndims ; - ndims = mxGetNumberOfDimensions (arg) ; - dims = (int64_t *) mxGetDimensions (arg) ; - size = 1 ; - for (k = 0 ; k < ndims ; k++) - { - size *= dims [k] ; - } - return (sputil_double_to_int (size, FALSE, 0)) ; -} - - -/* ========================================================================== */ -/* === sputil_get_double ==================================================== */ -/* ========================================================================== */ - -double sputil_get_double (const mxArray *arg) -{ - if (sputil_nelements (arg) < 1) - { - /* [] is not a scalar, but its value is zero so that - * sparse ([],[],[]) is a 0-by-0 matrix */ - return (0) ; - } - return (mxGetScalar (arg)) ; -} - - -/* ========================================================================== */ -/* === sputil_get_integer =================================================== */ -/* ========================================================================== */ - -/* return an argument as a non-negative integer scalar, or -1 if error */ - -int64_t sputil_get_integer -( - const mxArray *arg, /* MATLAB argument to convert */ - int64_t is_index, /* TRUE if an index, FALSE if a matrix dimension */ - int64_t n /* maximum value, if an index */ -) -{ - double x = sputil_get_double (arg) ; - if (mxIsInf (x) || mxIsNaN (x)) - { - /* arg is Inf or NaN, return -1 */ - return (EMPTY) ; - } - return (sputil_double_to_int (x, is_index, n)) ; -} - - -/* ========================================================================== */ -/* === sputil_trim ========================================================== */ -/* ========================================================================== */ - -/* Remove columns k to n-1 from a sparse matrix S, leaving columns 0 to k-1. - * S must be packed (there can be no S->nz array). This condition is not - * checked, since only packed matrices are passed to this routine. */ - -void sputil_trim -( - cholmod_sparse *S, - int64_t k, - cholmod_common *cm -) -{ - int64_t *Sp ; - int64_t ncol ; - size_t n1, nznew ; - - if (S == NULL) - { - return ; - } - - ncol = S->ncol ; - if (k < 0 || k >= ncol) - { - /* do not modify S */ - return ; - } - - /* reduce S->p in size. This cannot fail. */ - n1 = ncol + 1 ; - S->p = cholmod_l_realloc (k+1, sizeof (int64_t), S->p, &n1, cm) ; - - /* get the new number of entries in S */ - Sp = S->p ; - nznew = Sp [k] ; - - /* reduce S->i, S->x, and S->z (if present) to size nznew */ - cholmod_l_reallocate_sparse (nznew, S, cm) ; - - /* S now has only k columns */ - S->ncol = k ; -} - - -/* ========================================================================== */ -/* === sputil_extract_zeros ================================================= */ -/* ========================================================================== */ - -/* Create a sparse binary (real double) matrix Z that contains the pattern - * of explicit zeros in the sparse real/zomplex double matrix A. */ - -cholmod_sparse *sputil_extract_zeros -( - cholmod_sparse *A, - cholmod_common *cm -) -{ - int64_t *Ap, *Ai, *Zp, *Zi ; - double *Ax, *Az, *Zx ; - int64_t j, p, nzeros = 0, is_complex, pz, nrow, ncol ; - cholmod_sparse *Z ; - - if (A == NULL || A->xtype == CHOLMOD_PATTERN || A->xtype == CHOLMOD_COMPLEX) - { - /* only sparse real/zomplex double matrices supported */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - ncol = A->ncol ; - nrow = A->nrow ; - is_complex = (A->xtype == CHOLMOD_ZOMPLEX) ; - - /* count the number of zeros in a sparse matrix A */ - for (j = 0 ; j < ncol ; j++) - { - for (p = Ap [j] ; p < Ap [j+1] ; p++) - { - if ((Ax [p] == 0) && - ((is_complex) ? (Az [p] == 0) : TRUE)) - { - nzeros++ ; - } - } - } - - /* allocate the Z matrix with space for all the zero entries */ - Z = cholmod_l_spzeros (nrow, ncol, nzeros, CHOLMOD_REAL, cm) ; - - /* extract the zeros from A and store them in Z as binary values */ - if (nzeros > 0) - { - Zp = Z->p ; - Zi = Z->i ; - Zx = Z->x ; - pz = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Zp [j] = pz ; - for (p = Ap [j] ; p < Ap [j+1] ; p++) - { - if ((Ax [p] == 0) && - ((is_complex) ? (Az [p] == 0) : TRUE)) - { - Zi [pz] = Ai [p] ; - Zx [pz] = 1 ; - pz++ ; - } - } - } - Zp [ncol] = pz ; - } - - return (Z) ; -} - - -/* ========================================================================== */ -/* === sputil_drop_zeros ==================================================== */ -/* ========================================================================== */ - -/* Drop zeros from a packed CHOLMOD sparse matrix (zomplex or real). This is - * very similar to CHOLMOD/MatrixOps/cholmod_drop, except that this routine has - * no tolerance parameter and it can handle zomplex matrices. NaN's are left - * in the matrix. If this is used on the sparse matrix version of the factor - * L, then the update/downdate methods cannot be applied to L (ldlupdate). - * Returns the number of entries dropped. - */ - -int64_t sputil_drop_zeros -( - cholmod_sparse *S -) -{ - double sik, zik ; - int64_t *Sp, *Si ; - double *Sx, *Sz ; - int64_t pdest, k, ncol, p, pend, nz ; - - if (S == NULL) - { - return (0) ; - } - - Sp = S->p ; - Si = S->i ; - Sx = S->x ; - Sz = S->z ; - pdest = 0 ; - ncol = S->ncol ; - nz = Sp [ncol] ; - - if (S->xtype == CHOLMOD_ZOMPLEX) - { - for (k = 0 ; k < ncol ; k++) - { - p = Sp [k] ; - pend = Sp [k+1] ; - Sp [k] = pdest ; - for ( ; p < pend ; p++) - { - sik = Sx [p] ; - zik = Sz [p] ; - if ((sik != 0) || (zik != 0)) - { - if (p != pdest) - { - Si [pdest] = Si [p] ; - Sx [pdest] = sik ; - Sz [pdest] = zik ; - } - pdest++ ; - } - } - } - } - else - { - for (k = 0 ; k < ncol ; k++) - { - p = Sp [k] ; - pend = Sp [k+1] ; - Sp [k] = pdest ; - for ( ; p < pend ; p++) - { - sik = Sx [p] ; - if ((sik != 0)) - { - if (p != pdest) - { - Si [pdest] = Si [p] ; - Sx [pdest] = sik ; - } - pdest++ ; - } - } - } - } - Sp [ncol] = pdest ; - return (nz - pdest) ; -} - - -/* ========================================================================== */ -/* === sputil_copy_ij ======================================================= */ -/* ========================================================================== */ - -/* copy i or j arguments into an int64_t vector. For small integer types, i and - * and j can be returned with negative entries; this error condition is caught - * later, in cholmod_triplet_to_sparse. - * - * Future work: if the mxClassID matches the default integer (INT32 for 32-bit - * MATLAB and INT64 for 64-bit), then it would save memory to patch in the - * vector with a pointer copy, rather than making a copy of the whole vector. - * This would require that the 1-based i and j vectors be converted on the fly - * to 0-based vectors in cholmod_triplet_to_sparse. - */ - -int64_t sputil_copy_ij /* returns the dimension, n */ -( - int64_t is_scalar, /* TRUE if argument is a scalar, FALSE otherwise */ - int64_t scalar, /* scalar value of the argument */ - void *vector, /* vector value of the argument */ - mxClassID category, /* type of vector */ - int64_t nz, /* length of output vector I */ - int64_t n, /* maximum dimension, EMPTY if not yet known */ - int64_t *I /* vector of length nz to copy into */ -) -{ - int64_t i, k, ok, ok2, ok3, n2 ; - - if (is_scalar) - { - n2 = scalar ; - if (n == EMPTY) - { - n = scalar ; - } - i = scalar - 1 ; - for (k = 0 ; k < nz ; k++) - { - I [k] = i ; - } - } - else - { - /* copy double input into int64_t vector (convert to 0-based) */ - ok = TRUE ; - ok2 = TRUE ; - ok3 = TRUE ; - n2 = 0 ; - - switch (category) - { - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - case mxLOGICAL_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((mxLogical *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - -#endif - - case mxCHAR_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((mxChar *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxINT8_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((INT8_T *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxUINT8_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((UINT8_T *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxINT16_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((INT16_T *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxUINT16_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((UINT16_T *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxINT32_CLASS: - - for (k = 0 ; k < nz ; k++) - { - i = (int64_t) (((INT32_T *) vector) [k]) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxUINT32_CLASS: - - for (k = 0 ; ok3 && k < nz ; k++) - { - double y = (((UINT32_T *) vector) [k]) ; - i = (int64_t) y ; - ok3 = (y < INT64_MAX) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxINT64_CLASS: - - for (k = 0 ; ok2 && ok3 && k < nz ; k++) - { - int64_t y = ((int64_t *) vector) [k] ; - i = (int64_t) y ; - ok2 = (y > 0) ; - ok3 = (y < INT64_MAX) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxUINT64_CLASS: - - for (k = 0 ; ok2 && ok3 && k < nz ; k++) - { - uint64_t y = ((uint64_t *) vector) [k] ; - i = (int64_t) y ; - ok2 = (y > 0) ; - ok3 = (y < INT64_MAX) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxSINGLE_CLASS: - - for (k = 0 ; ok && ok2 && ok3 && k < nz ; k++) - { - float y = ((float *) vector) [k] ; - i = (int64_t) y ; - ok = (y == (float) i) ; - ok2 = (y > 0) ; - ok3 = (y < INT64_MAX) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - break ; - - case mxDOUBLE_CLASS: - - for (k = 0 ; ok && ok2 && ok3 && k < nz ; k++) - { - double y = ((double *) vector) [k] ; - i = (int64_t) y ; - ok = (y == (double) i) ; - ok2 = (y > 0) ; - ok3 = (y < INT64_MAX) ; - I [k] = i - 1 ; - n2 = MAX (n2, i) ; - } - - break ; - - default: - - sputil_error (ERROR_INVALID_TYPE, FALSE) ; - break ; - } - - if (!ok) - { - sputil_error (ERROR_NOT_INTEGER, TRUE) ; - } - - if (!ok2) - { - sputil_error (ERROR_TOO_SMALL, TRUE) ; - } - - if (!ok3) - { - sputil_error (ERROR_HUGE, TRUE) ; - } - - } - return ((n == EMPTY) ? n2 : n) ; -} - - -/* ========================================================================== */ -/* === sputil_dense_to_sparse =============================================== */ -/* ========================================================================== */ - -/* Convert a dense matrix of any numeric type into a - * sparse double or sparse logical matrix. - */ - -#define COUNT_NZ \ -{ \ - for (j = 0 ; j < ncol ; j++) \ - { \ - for (i = 0 ; i < nrow ; i++) \ - { \ - xij = X [i + j*nrow] ; \ - if (xij != 0) \ - { \ - nz++ ; \ - } \ - } \ - } \ -} - -#define COPY_DENSE_TO_SPARSE(stype) \ -{ \ - stype *Sx ; \ - Sp = (int64_t *) mxGetJc (S) ; \ - Si = (int64_t *) mxGetIr (S) ; \ - Sx = (stype *) mxGetData (S) ; \ - nz = 0 ; \ - for (j = 0 ; j < ncol ; j++) \ - { \ - Sp [j] = nz ; \ - for (i = 0 ; i < nrow ; i++) \ - { \ - xij = X [i + j*nrow] ; \ - if (xij != 0) \ - { \ - Si [nz] = i ; \ - Sx [nz] = (stype) xij ; \ - nz++ ; \ - } \ - } \ - } \ - Sp [ncol] = nz ; \ -} - -#define DENSE_TO_SPARSE(type) \ -{ \ - type *X, xij ; \ - X = (type *) mxGetData (arg) ; \ - COUNT_NZ ; \ - S = mxCreateSparse (nrow, ncol, nz, mxREAL) ; \ - COPY_DENSE_TO_SPARSE (double) ; \ -} - -mxArray *sputil_dense_to_sparse (const mxArray *arg) -{ - mxArray *S = NULL ; - int64_t *Sp, *Si ; - int64_t nrow, ncol, nz, i, j ; - - nrow = mxGetM (arg) ; - ncol = mxGetN (arg) ; - nz = 0 ; - - if (mxIsComplex (arg)) - { - - /* ------------------------------------------------------------------ */ - /* convert a complex dense matrix into a complex sparse matrix */ - /* ------------------------------------------------------------------ */ - - double xij, zij ; - double *X, *Z, *Sx, *Sz ; - - if (mxGetClassID (arg) != mxDOUBLE_CLASS) - { - /* A complex matrix can have any class (int8, int16, single, etc), - * but this function only supports complex double. This condition - * is not checked in the caller. */ - sputil_error (ERROR_INVALID_TYPE, FALSE) ; - } - - X = mxGetPr (arg) ; - Z = mxGetPi (arg) ; - for (j = 0 ; j < ncol ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - xij = X [i + j*nrow] ; - zij = Z [i + j*nrow] ; - if ((xij != 0) || (zij != 0)) - { - nz++ ; - } - } - } - S = mxCreateSparse (nrow, ncol, nz, mxCOMPLEX) ; - Sp = (int64_t *) mxGetJc (S) ; - Si = (int64_t *) mxGetIr (S) ; - Sx = mxGetPr (S) ; - Sz = mxGetPi (S) ; - nz = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Sp [j] = nz ; - for (i = 0 ; i < nrow ; i++) - { - xij = X [i + j*nrow] ; - zij = Z [i + j*nrow] ; - if ((xij != 0) || (zij != 0)) - { - Si [nz] = i ; - Sx [nz] = xij ; - Sz [nz] = zij ; - nz++ ; - } - } - } - Sp [ncol] = nz ; - - } - else - { - - /* ------------------------------------------------------------------ */ - /* convert real matrix (any class) to sparse double or logical */ - /* ------------------------------------------------------------------ */ - - switch (mxGetClassID (arg)) - { - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - case mxLOGICAL_CLASS: - { - mxLogical *X, xij ; - X = (mxLogical *) mxGetData (arg) ; - COUNT_NZ ; - S = mxCreateSparseLogicalMatrix (nrow, ncol, nz) ; - COPY_DENSE_TO_SPARSE (mxLogical) ; - } - break ; -#endif - - case mxCHAR_CLASS: - - DENSE_TO_SPARSE (mxChar) ; - break ; - - case mxINT8_CLASS: - - DENSE_TO_SPARSE (char) ; - break ; - - case mxUINT8_CLASS: - - DENSE_TO_SPARSE (unsigned char) ; - break ; - - case mxINT16_CLASS: - - DENSE_TO_SPARSE (short) ; - break ; - - case mxUINT16_CLASS: - - DENSE_TO_SPARSE (unsigned short) ; - break ; - - case mxINT32_CLASS: - - DENSE_TO_SPARSE (INT32_T) ; - break ; - - case mxUINT32_CLASS: - - DENSE_TO_SPARSE (unsigned INT32_T) ; - break ; - - case mxINT64_CLASS: - - DENSE_TO_SPARSE (int64_t) ; - break ; - - case mxUINT64_CLASS: - - DENSE_TO_SPARSE (uint64_t) ; - break ; - - case mxSINGLE_CLASS: - - DENSE_TO_SPARSE (float) ; - break ; - - case mxDOUBLE_CLASS: - - DENSE_TO_SPARSE (double) ; - break ; - - default: - - sputil_error (ERROR_INVALID_TYPE, FALSE) ; - break ; - } - } - - return (S) ; -} - - -/* ========================================================================== */ -/* === sputil_triplet_to_sparse ============================================= */ -/* ========================================================================== */ - -/* Convert a triplet form into a sparse matrix. If complex, s must be double. - * If real, s can be of any class. - */ - -cholmod_sparse *sputil_triplet_to_sparse -( - int64_t nrow, int64_t ncol, int64_t nz, int64_t nzmax, - int64_t i_is_scalar, int64_t i, void *i_vector, mxClassID i_class, - int64_t j_is_scalar, int64_t j, void *j_vector, mxClassID j_class, - int64_t s_is_scalar, double x, double z, void *x_vector, double *z_vector, - mxClassID s_class, int64_t s_complex, - cholmod_common *cm -) -{ - double dummy = 0 ; - cholmod_triplet *T ; - cholmod_sparse *S ; - double *Tx, *Tz ; - int64_t *Ti, *Tj ; - int64_t k, x_patch ; - - /* ---------------------------------------------------------------------- */ - /* allocate the triplet form */ - /* ---------------------------------------------------------------------- */ - - /* Note that nrow and ncol may be EMPTY; this is not an error condition. - * Allocate the numerical part of T only if s is a scalar. */ - x_patch = (!s_is_scalar && (s_class == mxDOUBLE_CLASS || s_complex)) ; - - T = cholmod_l_allocate_triplet (MAX (0,nrow), MAX (0,ncol), nz, 0, - x_patch ? CHOLMOD_PATTERN : - (s_complex ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL), cm) ; - Ti = T->i ; - Tj = T->j ; - Tx = T->x ; - Tz = T->z ; - - /* ---------------------------------------------------------------------- */ - /* fill the triplet form */ - /* ---------------------------------------------------------------------- */ - - if (s_is_scalar) - { - - /* ------------------------------------------------------------------ */ - /* fill T->x and T->z with a scalar value */ - /* ------------------------------------------------------------------ */ - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = x ; - } - if (s_complex) - { - for (k = 0 ; k < nz ; k++) - { - Tz [k] = z ; - } - } - - } - else - { - - /* ------------------------------------------------------------------ */ - /* copy x/z_vector into T->x and T->z, and convert to double */ - /* ------------------------------------------------------------------ */ - - if (s_complex) - { - - /* Patch in s as the numerical values of the triplet matrix. - * Note that T->x and T->z must not be free'd when done. */ - T->x = (x_vector == NULL) ? &dummy : x_vector ; - T->z = (z_vector == NULL) ? &dummy : z_vector ; - T->xtype = CHOLMOD_ZOMPLEX ; - - } - else switch (s_class) - { - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - case mxLOGICAL_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((mxLogical *) x_vector) [k]) ; - } - break ; - -#endif - - case mxCHAR_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((mxChar *) x_vector) [k]) ; - } - break ; - - case mxINT8_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((INT8_T *) x_vector) [k]) ; - } - break ; - - case mxUINT8_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((UINT8_T *) x_vector) [k]) ; - } - break ; - - case mxINT16_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((INT16_T *) x_vector) [k]) ; - } - break ; - - case mxUINT16_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((UINT16_T *) x_vector) [k]) ; - } - break ; - - case mxINT32_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((INT32_T *) x_vector) [k]) ; - } - break ; - - case mxUINT32_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((UINT32_T *) x_vector) [k]) ; - } - break ; - - case mxINT64_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((int64_t *) x_vector) [k]) ; - } - break ; - - case mxUINT64_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((uint64_t *) x_vector) [k]) ; - } - break ; - - case mxSINGLE_CLASS: - - for (k = 0 ; k < nz ; k++) - { - Tx [k] = (double) (((float *) x_vector) [k]) ; - } - break ; - - case mxDOUBLE_CLASS: - - /* Patch in s as the numerical values of the triplet matrix. - * Note that T->x must not be free'd when done. */ - T->x = (x_vector == NULL) ? &dummy : x_vector ; - T->xtype = CHOLMOD_REAL ; - break ; - - default: - - sputil_error (ERROR_INVALID_TYPE, FALSE) ; - break ; - } - } - - /* copy i in to the integer vector T->i */ - nrow = sputil_copy_ij (i_is_scalar, i, i_vector, i_class, nz, nrow, Ti) ; - - /* copy j in to the integer vector T->j */ - ncol = sputil_copy_ij (j_is_scalar, j, j_vector, j_class, nz, ncol, Tj) ; - - /* nrow and ncol are known */ - T->nrow = nrow ; - T->ncol = ncol ; - T->nnz = nz ; - - /* ---------------------------------------------------------------------- */ - /* convert triplet to sparse matrix */ - /* ---------------------------------------------------------------------- */ - - /* If the triplet matrix T is invalid, or if CHOLMOD runs out of memory, - * then S is NULL. */ - S = cholmod_l_triplet_to_sparse (T, nzmax, cm) ; - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ - - /* do not free T->x or T->z if it points to input x_vector */ - if (x_patch) - { - T->x = NULL ; - T->z = NULL ; - T->xtype = CHOLMOD_PATTERN ; - } - cholmod_l_free_triplet (&T, cm) ; - return (S) ; -} - - -/* ========================================================================== */ -/* === sputil_copy_sparse =================================================== */ -/* ========================================================================== */ - -/* copy a sparse matrix, S = sparse(A), dropping any zero entries and ensuring - * the nzmax(S) == nnz(S). Explicit zero entries in A "cannot" occur, in - * the current version of MATLAB ... but a user mexFunction might generate a - * matrix with explicit zeros. This function ensures S=sparse(A) drops those - * explicit zeros. */ - -mxArray *sputil_copy_sparse (const mxArray *A) -{ - double aij, zij ; - mxArray *S ; - double *Ax, *Az, *Sx, *Sz ; - int64_t *Ap, *Ai, *Sp, *Si ; - int64_t anz, snz, p, j, nrow, ncol, pend ; - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier : all sparse matrices are OK */ - if (! (mxGetClassID (A) == mxLOGICAL_CLASS || - mxGetClassID (A) == mxDOUBLE_CLASS)) - { - /* Only sparse logical and real/complex double matrices supported. - * This condition is not checked in the caller. */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - -#endif - - nrow = mxGetM (A) ; - ncol = mxGetN (A) ; - Ap = (int64_t *) mxGetJc (A) ; - Ai = (int64_t *) mxGetIr (A) ; - anz = Ap [ncol] ; - - snz = 0 ; - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - if (mxIsLogical (A)) - { - - /* ------------------------------------------------------------------ */ - /* copy a sparse logical matrix */ - /* ------------------------------------------------------------------ */ - - /* count the number of nonzeros in A */ - mxLogical *Al, *Sl ; - Al = mxGetLogicals (A) ; - for (p = 0 ; p < anz ; p++) - { - if (Al [p]) - { - snz++ ; - } - } - - /* allocate S */ - S = mxCreateSparseLogicalMatrix (nrow, ncol, snz) ; - Sp = (int64_t *) mxGetJc (S) ; - Si = (int64_t *) mxGetIr (S) ; - Sl = mxGetLogicals (S) ; - - /* copy A into S, dropping zero entries */ - snz = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Sp [j] = snz ; - pend = Ap [j+1] ; - for (p = Ap [j] ; p < pend ; p++) - { - if (Al [p]) - { - Si [snz] = Ai [p] ; - Sl [snz] = 1 ; - snz++ ; - } - } - } - - } - else - -#endif - - if (mxIsComplex (A)) - { - - /* ------------------------------------------------------------------ */ - /* copy a sparse complex double matrix */ - /* ------------------------------------------------------------------ */ - - /* count the number of nonzeros in A */ - Ax = mxGetPr (A) ; - Az = mxGetPi (A) ; - for (p = 0 ; p < anz ; p++) - { - aij = Ax [p] ; - zij = Az [p] ; - if ((aij != 0) || (zij != 0)) - { - snz++ ; - } - } - - /* allocate S */ - S = mxCreateSparse (nrow, ncol, snz, mxCOMPLEX) ; - Sp = (int64_t *) mxGetJc (S) ; - Si = (int64_t *) mxGetIr (S) ; - Sx = mxGetPr (S) ; - Sz = mxGetPi (S) ; - - /* copy A into S, dropping zero entries */ - snz = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Sp [j] = snz ; - pend = Ap [j+1] ; - for (p = Ap [j] ; p < pend ; p++) - { - aij = Ax [p] ; - zij = Az [p] ; - if ((aij != 0) || (zij != 0)) - { - Si [snz] = Ai [p] ; - Sx [snz] = aij ; - Sz [snz] = zij ; - snz++ ; - } - } - } - - } - else - { - - /* ------------------------------------------------------------------ */ - /* copy a sparse real double matrix */ - /* ------------------------------------------------------------------ */ - - /* count the number of nonzeros in A */ - Ax = mxGetPr (A) ; - for (p = 0 ; p < anz ; p++) - { - aij = Ax [p] ; - if (aij != 0) - { - snz++ ; - } - } - - /* allocate S */ - S = mxCreateSparse (nrow, ncol, snz, mxREAL) ; - Sp = (int64_t *) mxGetJc (S) ; - Si = (int64_t *) mxGetIr (S) ; - Sx = mxGetPr (S) ; - - /* copy A into S, dropping zero entries */ - snz = 0 ; - for (j = 0 ; j < ncol ; j++) - { - Sp [j] = snz ; - pend = Ap [j+1] ; - for (p = Ap [j] ; p < pend ; p++) - { - aij = Ax [p] ; - if (aij != 0) - { - Si [snz] = Ai [p] ; - Sx [snz] = aij ; - snz++ ; - } - } - } - } - - Sp [ncol] = snz ; - return (S) ; -} - - -/* ========================================================================== */ -/* === sputil_sparse_to_dense =============================================== */ -/* ========================================================================== */ - -/* convert a sparse double or logical array to a dense double array */ - -mxArray *sputil_sparse_to_dense (const mxArray *S) -{ - mxArray *X ; - double *Sx, *Sz, *Xx, *Xz ; - int64_t *Sp, *Si ; - int64_t nrow, ncol, i, j, p, pend, j2 ; - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier : all sparse matrices are OK */ - if (! (mxGetClassID (S) == mxLOGICAL_CLASS || - mxGetClassID (S) == mxDOUBLE_CLASS)) - { - /* only sparse logical and real/complex double matrices supported */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - -#endif - - nrow = mxGetM (S) ; - ncol = mxGetN (S) ; - Sp = (int64_t *) mxGetJc (S) ; - Si = (int64_t *) mxGetIr (S) ; - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - if (mxIsLogical (S)) - { - /* logical */ - mxLogical *Sl ; - Sl = (mxLogical *) mxGetData (S) ; - X = mxCreateDoubleMatrix (nrow, ncol, mxREAL) ; - Xx = mxGetPr (X) ; - for (j = 0 ; j < ncol ; j++) - { - pend = Sp [j+1] ; - j2 = j*nrow ; - for (p = Sp [j] ; p < pend ; p++) - { - Xx [Si [p] + j2] = (double) (Sl [p]) ; - } - } - } - else - -#endif - - if (mxIsComplex (S)) - { - /* complex */ - Sx = mxGetPr (S) ; - Sz = mxGetPi (S) ; - X = mxCreateDoubleMatrix (nrow, ncol, mxCOMPLEX) ; - Xx = mxGetPr (X) ; - Xz = mxGetPi (X) ; - for (j = 0 ; j < ncol ; j++) - { - pend = Sp [j+1] ; - j2 = j*nrow ; - for (p = Sp [j] ; p < pend ; p++) - { - i = Si [p] ; - Xx [i + j2] = Sx [p] ; - Xz [i + j2] = Sz [p] ; - } - } - } - else - { - /* real */ - Sx = mxGetPr (S) ; - X = mxCreateDoubleMatrix (nrow, ncol, mxREAL) ; - Xx = mxGetPr (X) ; - for (j = 0 ; j < ncol ; j++) - { - pend = Sp [j+1] ; - j2 = j*nrow ; - for (p = Sp [j] ; p < pend ; p++) - { - Xx [Si [p] + j2] = Sx [p] ; - } - } - } - - return (X) ; -} - - -/* ========================================================================== */ -/* === sputil_check_ijvector ================================================ */ -/* ========================================================================== */ - -/* Check a sparse i or j input argument */ - -void sputil_check_ijvector (const mxArray *arg) -{ - if (mxIsComplex (arg)) - { - /* i and j cannot be complex */ - sputil_error (ERROR_NOT_INTEGER, TRUE) ; - } - if (mxIsSparse (arg)) - { - /* the i and j arguments for sparse(i,j,s,...) can be sparse, but if so - * they must have no zero entries. */ - double mn, m, nz ; - int64_t *p, n ; - m = (double) mxGetM (arg) ; - n = mxGetN (arg) ; - mn = m*n ; - p = (int64_t *) mxGetJc (arg) ; - nz = p [n] ; - if (mn != nz) - { - /* i or j contains at least one zero, which is invalid */ - sputil_error (ERROR_TOO_SMALL, TRUE) ; - } - } -} - - -/* ========================================================================== */ -/* === sputil_sparse ======================================================== */ -/* ========================================================================== */ - -/* Implements the sparse2 mexFunction */ - -void sputil_sparse -( - int nargout, - mxArray *pargout [ ], - int nargin, - const mxArray *pargin [ ] -) -{ - double x, z ; - double *z_vector ; - void *i_vector, *j_vector, *x_vector ; - mxArray *s_array ; - cholmod_sparse *S, *Z ; - cholmod_common Common, *cm ; - int64_t nrow, ncol, k, nz, i_is_scalar, j_is_scalar, s_is_sparse, - s_is_scalar, ilen, jlen, slen, nzmax, i, j, s_complex, ndropped ; - mxClassID i_class, j_class, s_class ; - - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ - - cm = &Common ; - cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - if (nargout > 2 || nargin > 6 || nargin == 4 || nargin == 0) - { - sputil_error (ERROR_USAGE, FALSE) ; - } - - /* ---------------------------------------------------------------------- */ - /* convert inputs into a sparse matrix S */ - /* ---------------------------------------------------------------------- */ - - S = NULL ; - Z = NULL ; - - if (nargin == 1) - { - - /* ------------------------------------------------------------------ */ - /* S = sparse (A) where A is sparse or full */ - /* ------------------------------------------------------------------ */ - - nrow = mxGetM (pargin [0]) ; - ncol = mxGetN (pargin [0]) ; - - if (mxIsSparse (pargin [0])) - { - - /* -------------------------------------------------------------- */ - /* S = sparse (A) where A is sparse (double, complex, or logical) */ - /* -------------------------------------------------------------- */ - - pargout [0] = sputil_copy_sparse (pargin [0]) ; - - } - else - { - - /* -------------------------------------------------------------- */ - /* S = sparse (A) where A is full (real or complex) */ - /* -------------------------------------------------------------- */ - - /* A can be of any numeric type (mxLogical, int8, ..., double), - * except that if A is complex, it must also be double. */ - pargout [0] = sputil_dense_to_sparse (pargin [0]) ; - } - - } - else if (nargin == 2) - { - - /* ------------------------------------------------------------------ */ - /* S = sparse (m,n) */ - /* ------------------------------------------------------------------ */ - - int64_t *Sp ; - nrow = sputil_get_integer (pargin [0], FALSE, 0) ; - ncol = sputil_get_integer (pargin [1], FALSE, 0) ; - pargout [0] = mxCreateSparse (nrow, ncol, 1, mxREAL) ; - Sp = (int64_t *) mxGetJc (pargout [0]) ; - Sp [0] = 0 ; - - } - else - { - - /* ------------------------------------------------------------------ */ - /* S = sparse (i,j,s), sparse (i,j,s,m,n) or sparse (i,j,s,m,n,nzmax) */ - /* ------------------------------------------------------------------ */ - - /* i, j, and s can be of any numeric type */ - - /* ensure i and j are valid (i and j cannot be complex) */ - sputil_check_ijvector (pargin [0]) ; - sputil_check_ijvector (pargin [1]) ; - - /* convert s from sparse to dense (double), if necessary */ - s_is_sparse = mxIsSparse (pargin [2]) ; - if (s_is_sparse) - { - /* s must be double (real/complex) or logical */ - s_array = sputil_sparse_to_dense (pargin [2]) ; - } - else - { - s_array = (mxArray *) pargin [2] ; - } - - /* s is now full. It can be any class, except if complex it must also - * be double */ - s_class = mxGetClassID (s_array) ; - s_complex = mxIsComplex (s_array) ; - if (s_complex && s_class != mxDOUBLE_CLASS) - { - /* for complex case, only double class is supported */ - sputil_error (ERROR_INVALID_TYPE, 0) ; - } - - /* get sizes of inputs */ - ilen = sputil_nelements (pargin [0]) ; - jlen = sputil_nelements (pargin [1]) ; - slen = sputil_nelements (s_array) ; - - /* if i, j, s are scalars, they "float" to sizes of non-scalar args */ - i_is_scalar = (ilen == 1) ; - j_is_scalar = (jlen == 1) ; - s_is_scalar = (slen == 1) ; - - /* find the length */ - if (!i_is_scalar) - { - /* if i is not a scalar, let it determine the length */ - nz = ilen ; - } - else if (!j_is_scalar) - { - /* otherwise, if j is not a scalar, let it determine the length */ - nz = jlen ; - } - else - { - /* finally, i and j are both scalars, so let s determine length */ - nz = slen ; - } - - /* make sure the sizes are compatible */ - if (!((i_is_scalar || ilen == nz) && - (j_is_scalar || jlen == nz) && - (s_is_scalar || slen == nz))) - { - sputil_error (ERROR_LENGTH, FALSE) ; - } - - if (nargin > 4) - { - nrow = sputil_get_integer (pargin [3], FALSE, 0) ; - ncol = sputil_get_integer (pargin [4], FALSE, 0) ; - } - else - { - /* nrow and ncol will be discovered by scanning i and j */ - nrow = EMPTY ; - ncol = EMPTY ; - } - - if (nargin > 5) - { - nzmax = sputil_get_integer (pargin [5], FALSE, 0) ; - nzmax = MAX (nzmax, nz) ; - } - else - { - nzmax = nz ; - } - - /* ------------------------------------------------------------------ */ - /* convert triplet form to sparse form */ - /* ------------------------------------------------------------------ */ - - i = i_is_scalar ? sputil_get_integer (pargin [0], TRUE, nrow) : 0 ; - i_vector = mxGetData (pargin [0]) ; - i_class = mxGetClassID (pargin [0]) ; - - j = j_is_scalar ? sputil_get_integer (pargin [1], TRUE, ncol) : 0 ; - j_vector = mxGetData (pargin [1]) ; - j_class = mxGetClassID (pargin [1]) ; - - x_vector = mxGetData (s_array) ; - z_vector = mxGetPi (s_array) ; - x = sputil_get_double (s_array) ; - z = (s_complex && z_vector != NULL) ? (z_vector [0]) : 0 ; - - S = sputil_triplet_to_sparse (nrow, ncol, nz, nzmax, - i_is_scalar, i, i_vector, i_class, - j_is_scalar, j, j_vector, j_class, - s_is_scalar, x, z, x_vector, z_vector, - s_class, s_complex, - cm) ; - - /* set nzmax(S) to nnz(S), unless nzmax is specified on input */ - if (nargin <= 5 && S != NULL) - { - cholmod_l_reallocate_sparse (cholmod_l_nnz (S, cm), S, cm) ; - } - - if (nargout > 1) - { - /* return a binary pattern of the explicit zero entries, for the - * [S Z] = sparse(i,j,x, ...) form. */ - Z = sputil_extract_zeros (S, cm) ; - } - - /* drop explicit zeros from S */ - ndropped = sputil_drop_zeros (S) ; - - /* if entries dropped, set nzmax(S) to nnz(S), unless nzmax specified */ - if (ndropped > 0 && nargin <= 5 && S != NULL) - { - cholmod_l_reallocate_sparse (cholmod_l_nnz (S, cm), S, cm) ; - } - - if (s_is_sparse) - { - mxDestroyArray (s_array) ; - } - } - - /* ---------------------------------------------------------------------- */ - /* convert S into a MATLAB sparse matrix */ - /* ---------------------------------------------------------------------- */ - - k = 0 ; - if (S != NULL) - { - -#ifndef MATLAB6p1_OR_EARLIER - - /* MATLAB 6.1 or earlier do not have mxLOGICAL_CLASS */ - if (mxIsLogical (pargin [2])) - { - /* copy S into a MATLAB sparse logical matrix */ - mxLogical *s_logical ; - pargout [0] = mxCreateSparseLogicalMatrix (0, 0, 0) ; - s_logical = cholmod_l_malloc (S->nzmax, sizeof (mxLogical), cm) ; - for (k = 0 ; k < (int64_t) (S->nzmax) ; k++) - { - s_logical [k] = 1 ; - } - MXFREE (mxGetData (pargout [0])) ; - mxSetData (pargout [0], s_logical) ; - mexMakeMemoryPersistent (s_logical) ; - k++ ; - } - else - -#endif - if (S->x == NULL) mexErrMsgTxt ("invalid sparse matrix") ; - - if (mxIsComplex (pargin [2])) - { - /* copy S into a MATLAB sparse complex double matrix */ - if (S->z == NULL) mexErrMsgTxt ("invalid complex sparse matrix") ; - pargout [0] = mxCreateSparse (0, 0, 0, mxCOMPLEX) ; - MXFREE (mxGetPr (pargout [0])) ; - MXFREE (mxGetPi (pargout [0])) ; - mxSetPr (pargout [0], S->x) ; - mxSetPi (pargout [0], S->z) ; - mexMakeMemoryPersistent (S->x) ; - mexMakeMemoryPersistent (S->z) ; - k += 2 ; - S->x = NULL ; - S->z = NULL ; - } - else - { - /* copy S into a MATLAB sparse real double matrix */ - pargout [0] = mxCreateSparse (0, 0, 0, mxREAL) ; - mxSetPr (pargout [0], S->x) ; - mexMakeMemoryPersistent (S->x) ; - k++ ; - S->x = NULL ; - } - - mxSetM (pargout [0], S->nrow) ; - mxSetN (pargout [0], S->ncol) ; - mxSetNzmax (pargout [0], S->nzmax) ; - MXFREE (mxGetJc (pargout [0])) ; - MXFREE (mxGetIr (pargout [0])) ; - mxSetJc (pargout [0], S->p) ; - mxSetIr (pargout [0], S->i) ; - mexMakeMemoryPersistent (S->p) ; - mexMakeMemoryPersistent (S->i) ; - k += 2 ; - - /* free cholmod_sparse S, except for what has been given to MATLAB */ - S->p = NULL ; - S->i = NULL ; - cholmod_l_free_sparse (&S, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* return Z to MATLAB, if requested */ - /* ---------------------------------------------------------------------- */ - - if (nargout > 1) - { - if (Z == NULL) - { - /* Z not computed; return an empty matrix */ - Z = cholmod_l_spzeros (nrow, ncol, 0, CHOLMOD_REAL, cm) ; - } - pargout [1] = sputil_put_sparse (&Z, cm) ; - } - - cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != k) mexErrMsgTxt ("!") ; - */ -} diff --git a/CHOLMOD/MATLAB/cholmod_matlab.h b/CHOLMOD/MATLAB/cholmod_matlab.h deleted file mode 100644 index 314caf662e..0000000000 --- a/CHOLMOD/MATLAB/cholmod_matlab.h +++ /dev/null @@ -1,173 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/MATLAB/cholmod_matlab.h: include file for CHOLMOD' MATLAB interface -//------------------------------------------------------------------------------ - -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Shared prototypes and definitions for CHOLMOD mexFunctions */ - -#include "SuiteSparse_config.h" - -#include "cholmod.h" -#include -#include "mex.h" -#define EMPTY (-1) -#define TRUE 1 -#define FALSE 0 -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define LEN 16 - -#define MXFREE(a) { \ - void *ptr ; \ - ptr = (void *) (a) ; \ - if (ptr != NULL) mxFree (ptr) ; \ -} - -#define ERROR_TOO_SMALL 0 -#define ERROR_HUGE 1 -#define ERROR_NOT_INTEGER 2 -#define ERROR_TOO_LARGE 3 -#define ERROR_USAGE 4 -#define ERROR_LENGTH 5 -#define ERROR_INVALID_TYPE 6 -#define ERROR_OUT_OF_MEMORY 7 - -/* getting spumoni at run-time takes way too much time */ -#ifndef SPUMONI -#define SPUMONI 0 -#endif - -/* closed by sputil_error_handler if not NULL */ -extern FILE *sputil_file ; - -void sputil_error /* reports an error */ -( - int64_t error, /* kind of error */ - int64_t is_index /* TRUE if a matrix index, FALSE if a matrix dimension */ -) ; - -int64_t sputil_double_to_int /* returns integer value of x */ -( - double x, /* double value to convert */ - int64_t is_index, /* TRUE if a matrix index, FALSE if a matrix dimension */ - int64_t n /* if a matrix index, x cannot exceed this dimension */ -) ; - -double sputil_get_double (const mxArray *arg) ; /* like mxGetScalar */ - -int64_t sputil_get_integer /* returns the integer value of a MATLAB argument */ -( - const mxArray *arg, /* MATLAB argument to convert */ - int64_t is_index, /* TRUE if an index, FALSE if a matrix dimension */ - int64_t n /* maximum value, if an index */ -) ; - - -int64_t sputil_copy_ij /* returns the dimension, n */ -( - int64_t is_scalar, /* TRUE if argument is a scalar, FALSE otherwise */ - int64_t scalar, /* scalar value of the argument */ - void *vector, /* vector value of the argument */ - mxClassID category, /* type of vector */ - int64_t nz, /* length of output vector I */ - int64_t n, /* maximum dimension, EMPTY if not yet known */ - int64_t *I /* vector of length nz to copy into */ -) ; - -/* converts a triplet matrix to a compressed-column matrix */ -cholmod_sparse *sputil_triplet_to_sparse -( - int64_t nrow, int64_t ncol, int64_t nz, int64_t nzmax, - int64_t i_is_scalar, int64_t i, void *i_vector, mxClassID i_class, - int64_t j_is_scalar, int64_t j, void *j_vector, mxClassID j_class, - int64_t s_is_scalar, double x, double z, void *x_vector, double *z_vector, - mxClassID s_class, int64_t s_complex, - cholmod_common *cm -) ; - -mxArray *sputil_copy_sparse (const mxArray *A) ; /* copy a sparse matrix */ - -int64_t sputil_nelements (const mxArray *arg) ; /* like mxGetNumberOfElements */ - -void sputil_sparse /* top-level wrapper for "sparse" function */ -( - int nargout, - mxArray *pargout [ ], - int nargin, - const mxArray *pargin [ ] -) ; - -void sputil_error_handler (int status, const char *file, int line, - const char *message) ; - -void sputil_config (int64_t spumoni, cholmod_common *cm) ; - -mxArray *sputil_sparse_to_dense (const mxArray *S) ; - -cholmod_sparse *sputil_get_sparse -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_sparse *A, /* CHOLMOD version of the matrix */ - double *dummy, /* a pointer to a valid scalar double */ - int64_t stype /* -1: lower, 0: unsymmetric, 1: upper */ -) ; - -cholmod_dense *sputil_get_dense -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_dense *A, /* CHOLMOD version of the matrix */ - double *dummy /* a pointer to a valid scalar double */ -) ; - -mxArray *sputil_put_dense /* returns the MATLAB version */ -( - cholmod_dense **Ahandle, /* CHOLMOD version of the matrix */ - cholmod_common *cm -) ; - -mxArray *sputil_put_sparse -( - cholmod_sparse **Ahandle, /* CHOLMOD version of the matrix */ - cholmod_common *cm -) ; - -int64_t sputil_drop_zeros /* drop numerical zeros from a CHOLMOD matrix */ -( - cholmod_sparse *S -) ; - -mxArray *sputil_put_int /* copy int64_t vector to mxArray */ -( - int64_t *P, /* vector to convert */ - int64_t n, /* length of P */ - int64_t one_based /* 1 if convert from 0-based to 1-based, else 0 */ -) ; - -mxArray *sputil_dense_to_sparse (const mxArray *arg) ; - -void sputil_check_ijvector (const mxArray *arg) ; - -void sputil_trim -( - cholmod_sparse *S, - int64_t k, - cholmod_common *cm -) ; - -cholmod_sparse *sputil_get_sparse_pattern -( - const mxArray *Amatlab, /* MATLAB version of the matrix */ - cholmod_sparse *Ashallow, /* shallow CHOLMOD version of the matrix */ - double *dummy, /* a pointer to a valid scalar double */ - cholmod_common *cm -) ; - -cholmod_sparse *sputil_extract_zeros -( - cholmod_sparse *A, - cholmod_common *cm -) ; diff --git a/CHOLMOD/MATLAB/cholmod_updown_demo.m b/CHOLMOD/MATLAB/cholmod_updown_demo.m index d2690587ac..e98c7e14a6 100644 --- a/CHOLMOD/MATLAB/cholmod_updown_demo.m +++ b/CHOLMOD/MATLAB/cholmod_updown_demo.m @@ -1,5 +1,5 @@ function cholmod_updown_demo -%CHOLMOD_UPDOWN_DEMO a demo for CHOLMOD's update/downdate and row add/delete +%CHOLMOD_UPDOWN_DEMO a demo for CHOLMOD's update/downdate & row add/delete % % Provides a short demo of CHOLMOD's update/downdate and row add/delete % functions. @@ -7,9 +7,9 @@ % Example: % cholmod_updown_demo % -% See also CHOLMOD_DEMO +% See also cholmod_demo -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ fprintf ('\n\n------------------------------------------------------------\n') ; @@ -23,7 +23,7 @@ b = rand (n,1) / n ; % L*D*L' = A(p,p). The 2nd argument is zero if A is positive definite. -[LD,ignore,p] = ldlchol (A) ; +[LD,ignore,p] = ldlchol (A) ; %#ok % solve Ax=b using the L*D*L' factorization of A(p,p) c = b (p) ; @@ -41,23 +41,23 @@ t1 = toc ; err = norm (A*x-b) ; fprintf ('norm (A*x-b) using backslash: %g\n', err) ; -fprintf ('time for x=A\\b: %g\n', t1) ; +fprintf ('time for x=A\\b: %g\n', t1) ; if (err > 1e-12) error ('!') end % check the norm of LDL'-S -[L,D] = ldlsplit (LD) ; +[L,D] = ldlsplit (LD) ; %#ok S = A (p,p) ; -err = norm (L*D*L' - S, 1) ; +% err = norm (L*D*L' - S, 1) ; fprintf ('nnz (L) for original matrix: %d\n', nnz (L)) ; % rank-1 update of the L*D*L' factorization % A becomes A2=A+W*W', and S becomes S2=S+C*C'. Some fillin occurs. fprintf ('\n\n------------------------------------------------------------\n') ; fprintf ('Update A to A+W*W'', and the permuted S=A(p,p) becomes S+C*C'':\n') ; -W = sparse ([1 2 3 152], [1 1 1 1], [5 -1 -1 -1], n, 1) -C = W (p,:) +W = sparse ([1 2 3 152], [1 1 1 1], [5 -1 -1 -1], n, 1) %#ok +C = W (p,:) %#ok tic LD2 = ldlupdate (LD, C, '+') ; t2 = toc ; @@ -82,7 +82,7 @@ if (err > 1e-12) error ('!') end -fprintf ('time to solve x=A\\b using update: %g\n', t2 + t3) ; +fprintf ('time to solve x=A\\b using update: %g\n', t2 + t3) ; % solve again, just using backslash tic @@ -93,7 +93,7 @@ if (err > 1e-12) error ('!') end -fprintf ('time for x=A\\b: %g\n', t1) ; +fprintf ('time for x=A\\b: %g\n', t1) ; fprintf ('speedup of update vs backslash: %g\n', t1 / (t2 + t3)) ; % invert the permutation @@ -143,7 +143,7 @@ err = norm (A3*x-b) ; fprintf ('norm (A3*x-b) with backslash: %g\n', err) ; fprintf ('time for x=A\\b with backslash %g\n', t1) ; -fprintf ('time for x=A\\b using rowdel: %g\n', t2 + t3) ; +fprintf ('time for x=A\\b using rowdel: %g\n', t2 + t3) ; fprintf ('speedup of rowdel vs backslash: %g\n', t1 / (t2 + t3)) ; % add row 3 back to A3 to get A4. This corresponds to row invp(3) in S and LDL @@ -193,6 +193,6 @@ end fprintf ('time for x=A\\b with backslash %g\n', t1) ; -fprintf ('time for x=A\\b using rowadd: %g\n', t2 + t3) ; +fprintf ('time for x=A\\b using rowadd: %g\n', t2 + t3) ; fprintf ('speedup of rowadd vs backslash: %g\n', t1 / (t2 + t3)) ; diff --git a/CHOLMOD/MATLAB/etree2.c b/CHOLMOD/MATLAB/etree2.c index 55801867cd..9a8902b7a7 100644 --- a/CHOLMOD/MATLAB/etree2.c +++ b/CHOLMOD/MATLAB/etree2.c @@ -2,28 +2,27 @@ // CHOLMOD/MATLAB/etree2: MATLAB interface to CHOLMOD etree //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Usage: - * - * parent = etree2 (A) returns etree of A, uses triu(A) - * parent = etree2 (A, 'col') returns etree of A'*A - * parent = etree2 (A, 'sym') same as etree2 (A) - * parent = etree2 (A, 'row') same as etree2 (A', 'col') - * parent = etree2 (A, 'lo') returns etree of A, uses tril(A) - * - * [parent post] = etree2(...) also returns a postorder of the tree - * - * etree2 (A, 'col') does not form A'*A and is thus faster than etree2 (A'*A) - * and takes less memory. Likewise, etree (A, 'row') does not - * form A*A', and is thus faster than etree2 (A*A') and takes less memory. - */ - -#include "cholmod_matlab.h" +// Usage: +// +// parent = etree2 (A) returns etree of A, uses triu(A) +// parent = etree2 (A, 'col') returns etree of A'*A +// parent = etree2 (A, 'sym') same as etree2 (A) +// parent = etree2 (A, 'row') same as etree2 (A', 'col') +// parent = etree2 (A, 'lo') returns etree of A, uses tril(A) +// +// [parent post] = etree2(...) also returns a postorder of the tree +// +// etree2 (A, 'col') does not form A'*A and is thus faster than etree2 (A'*A) +// and takes less memory. Likewise, etree (A, 'row') does not +// form A*A', and is thus faster than etree2 (A*A') and takes less memory. + +#include "sputil2.h" void mexFunction ( @@ -35,141 +34,140 @@ void mexFunction { double dummy = 0 ; int64_t *Parent ; - cholmod_sparse *A, Amatrix, *S ; + cholmod_sparse *A, Amatrix ; cholmod_common Common, *cm ; int64_t n, coletree, c ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 2 || nargin < 1 || nargin > 2) { - mexErrMsgTxt ("Usage: [parent post] = etree2 (A, mode)") ; + mexErrMsgTxt ("Usage: [parent post] = etree2 (A, mode)") ; } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use triu(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use triu(A) + //-------------------------------------------------------------------------- A->stype = 1 ; n = A->nrow ; coletree = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0] ; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - n = A->ncol ; - coletree = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric upper case (A) if string starts with 's' */ - A->stype = 1 ; - } - else if (tolower (c) == 'l') - { - /* symmetric lower case (A) if string starts with 'l' */ - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("etree2: unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0] ; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + n = A->ncol ; + coletree = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric upper case (A) if string starts with 's' + A->stype = 1 ; + } + else if (tolower (c) == 'l') + { + // symmetric lower case (A) if string starts with 'l' + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("etree2: unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("etree2: A must be square") ; + mexErrMsgTxt ("etree2: A must be square") ; } - /* ---------------------------------------------------------------------- */ - /* compute the etree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the etree + //-------------------------------------------------------------------------- Parent = cholmod_l_malloc (n, sizeof (int64_t), cm) ; if (A->stype == 1 || coletree) { - /* symmetric case: find etree of A, using triu(A) */ - /* column case: find column etree of A, which is etree of A'*A */ - cholmod_l_etree (A, Parent, cm) ; + // symmetric case: find etree of A, using triu(A) + // column case: find column etree of A, which is etree of A'*A + cholmod_l_etree (A, Parent, cm) ; } else { - /* symmetric case: find etree of A, using tril(A) */ - /* row case: find row etree of A, which is etree of A*A' */ - /* R = A' */ - cholmod_sparse *R ; - R = cholmod_l_transpose (A, 0, cm) ; - cholmod_l_etree (R, Parent, cm) ; - cholmod_l_free_sparse (&R, cm) ; + // symmetric case: find etree of A, using tril(A) + // row case: find row etree of A, which is etree of A*A' + // R = A' + cholmod_sparse *R ; + R = cholmod_l_transpose (A, 0, cm) ; + cholmod_l_etree (R, Parent, cm) ; + cholmod_l_free_sparse (&R, cm) ; } if (cm->status < CHOLMOD_OK) { - /* out of memory or matrix invalid */ - mexErrMsgTxt ("etree2 failed: matrix corrupted!") ; + // out of memory or matrix invalid + mexErrMsgTxt ("etree2 failed: matrix corrupted!") ; } - /* ---------------------------------------------------------------------- */ - /* return Parent to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return Parent to MATLAB + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (Parent, n, 1) ; + pargout [0] = sputil2_put_int (Parent, n, 1) ; - /* ---------------------------------------------------------------------- */ - /* postorder the tree and return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // postorder the tree and return results to MATLAB + //-------------------------------------------------------------------------- if (nargout > 1) { - int64_t *Post ; - Post = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - if (cholmod_l_postorder (Parent, n, NULL, Post, cm) != n) - { - /* out of memory or Parent invalid */ - mexErrMsgTxt ("etree2 postorder failed!") ; - } - pargout [1] = sputil_put_int (Post, n, 1) ; - cholmod_l_free (n, sizeof (int64_t), Post, cm) ; + int64_t *Post ; + Post = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + if (cholmod_l_postorder (Parent, n, NULL, Post, cm) != n) + { + // out of memory or Parent invalid + mexErrMsgTxt ("etree2 postorder failed!") ; + } + pargout [1] = sputil2_put_int (Post, n, 1) ; + cholmod_l_free (n, sizeof (int64_t), Post, cm) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- cholmod_l_free (n, sizeof (int64_t), Parent, cm) ; - cholmod_l_free_sparse (&S, cm) ; + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/etree2.m b/CHOLMOD/MATLAB/etree2.m index f875fee311..8409dfcb27 100644 --- a/CHOLMOD/MATLAB/etree2.m +++ b/CHOLMOD/MATLAB/etree2.m @@ -1,42 +1,43 @@ -function [parent, post] = etree2 (A, mode) %#ok +function [parent, post] = etree2 (A, mode) %#ok %ETREE2 sparse elimination tree. -% Finds the elimination tree of A, A'*A, or A*A', and optionaly postorders -% the tree. parent(j) is the parent of node j in the tree, or 0 if j is a -% root. The symmetric case uses only the upper or lower triangular part of -% A (etree2(A) uses the upper part, and etree2(A,'lo') uses the lower part). -% -% Example: -% parent = etree2 (A) finds the elimination tree of A, using triu(A) +% Finds the elimination tree of A, A'*A, or A*A', and optionaly +% postorders the tree. parent(j) is the parent of node j in the tree, or +% 0 if j is a root. The symmetric case uses only the upper or lower +% triangular part of A (etree2(A) uses the upper part, and etree2(A,'lo') +% uses the lower part). +% +% Example: +% parent = etree2 (A) finds the etree of A, using triu(A) % parent = etree2 (A,'sym') same as etree2(A) -% parent = etree2 (A,'col') finds the elimination tree of A'*A -% parent = etree2 (A,'row') finds the elimination tree of A*A' -% parent = etree2 (A,'lo') finds the elimination tree of A, using tril(A) +% parent = etree2 (A,'col') finds the etree of A'*A +% parent = etree2 (A,'row') finds the etree of A*A' +% parent = etree2 (A,'lo') finds the etree of A, using tril(A) % -% [parent,post] = etree2 (...) also returns a post-ordering of the tree. +% [parent,post] = etree2 (...) also returns a post-ordering of the tree. % -% If you have a fill-reducing permutation p, you can combine it with an -% elimination tree post-ordering using the following code. Post-ordering has -% no effect on fill-in (except for lu), but it does improve the performance -% of the subsequent factorization. +% If you have a fill-reducing permutation p, you can combine it with an +% elimination tree post-ordering using the following code. Post-ordering +% has no effect on fill-in (except for lu), but it does improve the +% performance of the subsequent factorization. % -% For the symmetric case, suitable for chol(A(p,p)): +% For the symmetric case, suitable for chol(A(p,p)): % % [parent post] = etree2 (A (p,p)) ; % p = p (post) ; % -% For the column case, suitable for qr(A(:,p)) or lu(A(:,p)): +% For the column case, suitable for qr(A(:,p)) or lu(A(:,p)): % % [parent post] = etree2 (A (:,p), 'col') ; % p = p (post) ; % -% For the row case, suitable for qr(A(p,:)') or chol(A(p,:)*A(p,:)'): +% For the row case, suitable for qr(A(p,:)') or chol(A(p,:)*A(p,:)'): % % [parent post] = etree2 (A (p,:), 'row') ; % p = p (post) ; % -% See also TREELAYOUT, TREEPLOT, ETREEPLOT, ETREE +% See also treelayout, treeplot, etreeplot, etree. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('etree2 mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/get_symmetry.m b/CHOLMOD/MATLAB/get_symmetry.m index 626bf02b8d..deda858d95 100644 --- a/CHOLMOD/MATLAB/get_symmetry.m +++ b/CHOLMOD/MATLAB/get_symmetry.m @@ -1,12 +1,14 @@ function result = get_symmetry (A,quick) -%GET_SYMMETRY: does the same thing as the spsym mexFunction. -% It's just a lot slower and uses much more memory. This function -% is meant for testing and documentation only. +%GET_SYMMETRY same as spsym, just slower for testing only +% Same as spsym, just a lot slower and uses much more memory. This +% function is meant for testing and documentation only. +% +% See also spsym. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. +% Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. % SPDX-License-Identifier: GPL-2.0+ -[m n] = size (A) ; +[m,n] = size (A) ; if (m ~= n) result = 1 ; % rectangular return @@ -16,9 +18,9 @@ end d = diag (A) ; posdiag = all (real (d) > 0) & all (imag (d) == 0) ; -if (quick & ~posdiag) +if (quick && ~posdiag) result = 2 ; % Not a candidate for sparse Cholesky. -elseif (~isreal (A) & nnz (A-A') == 0) +elseif (~isreal (A) && nnz (A-A') == 0) if (posdiag) result = 7 ; % complex Hermitian, with positive diagonal else @@ -36,3 +38,5 @@ result = 2 ; % unsymmetric end + + diff --git a/CHOLMOD/MATLAB/graph_demo.m b/CHOLMOD/MATLAB/graph_demo.m index 79e85bc9e2..41fc0a35a6 100644 --- a/CHOLMOD/MATLAB/graph_demo.m +++ b/CHOLMOD/MATLAB/graph_demo.m @@ -1,15 +1,15 @@ function graph_demo (n) %GRAPH_DEMO graph partitioning demo -% graph_demo(n) constructs an set of n-by-n 2D grids, partitions them, and -% plots them in one-second intervals. n is optional; it defaults to 60. +% graph_demo(n) constructs an set of n-by-n 2D grids, partitions them, and +% plots them in one-second intervals. n is optional; it defaults to 60. % -% Example: +% Example: % graph_demo % -% See also DELSQ, NUMGRID, GPLOT, TREEPLOT +% See also delsq, numgrid, gplot, treeplot. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ if (nargin < 1) % construct a 60-by-60 grid @@ -26,8 +26,8 @@ function graph_demo (n) x = repmat (0:n-1, n, 1) ; y = repmat (((n-1):-1:0)', 1, n) ; A = delsq (g) ; - x = x (find (g)) ; %#ok - y = y (find (g)) ; %#ok + x = x (find (g)) ; %#ok + y = y (find (g)) ; %#ok % plot the original grid clf @@ -39,7 +39,8 @@ function graph_demo (n) % bisect the graph s = bisect (A) ; - [i j] = find (A) ; + [i,j] = find (A) ; + subplot (2,2,2) my_gplot (sparse (i, j, s(i) == s(j)), x, y) ; title ('node bisection') ; @@ -52,9 +53,9 @@ function graph_demo (n) while (1) if (defaults) % use defaults - [p cp cmember] = nesdis (A) ; + [p, cp, cmember] = nesdis (A) ; %#ok else - [p cp cmember] = nesdis (A, 'sym', nsmall) ; + [p, cp, cmember] = nesdis (A, 'sym', nsmall) ; %#ok end % plot the components @@ -77,7 +78,6 @@ function graph_demo (n) drawnow pause (0.1) - if (defaults) break ; end @@ -90,13 +90,13 @@ function graph_demo (n) end end -function my_gplot (A, x, y) - % my_gplot : like gplot, just a lot faster +function my_gplot (A, x, y) % like gplot, just a lot faster [i, j] = find (A) ; -[ignore, p] = sort (max(i, j)) ; +[~, p] = sort (max(i, j)) ; i = i (p) ; j = j (p) ; -nans = repmat (NaN, size (i)) ; +nans = repmat (NaN, size (i)) ; %#ok x = [ x(i) x(j) nans ]' ; y = [ y(i) y(j) nans ]' ; plot (x (:), y (:)) ; + diff --git a/CHOLMOD/MATLAB/lchol.c b/CHOLMOD/MATLAB/lchol.c index e9db58e6ff..44b0194bcd 100644 --- a/CHOLMOD/MATLAB/lchol.c +++ b/CHOLMOD/MATLAB/lchol.c @@ -2,35 +2,34 @@ // CHOLMOD/MATLAB/lchol: MATLAB interface to CHOLMOD factorization //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Numeric LL' factorization. Note that LL' and LDL' are faster than R'R - * and use less memory. The LL' factorization methods use tril(A). - * - * L = lchol (A) same as L = chol (A)', just faster - * [L,p] = lchol (A) save as [R,p] = chol(A) ; L=R', just faster - * [L,p,q] = lchol (A) factorizes A(q,q) into L*L' - * - * A must be sparse. It can be complex or real. - * - * L is returned with no explicit zero entries. This means it might not be - * chordal, and L cannot be passed back to CHOLMOD for an update/downdate or - * for a fast simplicial solve. spones (L) will be equal to the L returned - * by symbfact2 if no numerically zero entries are dropped, or a subset - * otherwise. - */ - -#include "cholmod_matlab.h" +// Numeric LL' factorization. Note that LL' and LDL' are faster than R'R +// and use less memory. The LL' factorization methods use tril(A). +// +// L = lchol (A) same as L = chol (A)', just faster +// [L,p] = lchol (A) save as [R,p] = chol(A) ; L=R', just faster +// [L,p,q] = lchol (A) factorizes A(q,q) into L*L' +// +// A must be sparse. It can be complex or real. +// +// L is returned with no explicit zero entries. This means it might not be +// chordal, and L cannot be passed back to CHOLMOD for an update/downdate or +// for a fast simplicial solve. spones (L) will be equal to the L returned +// by symbfact2 if no numerically zero entries are dropped, or a subset +// otherwise. + +#include "sputil2.h" void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -40,117 +39,120 @@ void mexFunction cholmod_common Common, *cm ; int64_t n, minor ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* convert to packed LL' when done */ + // convert to packed LL' when done cm->final_asis = FALSE ; cm->final_super = FALSE ; cm->final_ll = TRUE ; cm->final_pack = TRUE ; cm->final_monotonic = TRUE ; - /* no need to prune entries due to relaxed supernodal amalgamation, since - * zeros are dropped with sputil_drop_zeros instead */ + // no need to prune entries due to relaxed supernodal amalgamation, since + // zeros are dropped with cholmod_l_drop instead cm->final_resymbol = FALSE ; cm->quick_return_if_not_posdef = (nargout < 2) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargin != 1 || nargout > 3) { - mexErrMsgTxt ("usage: [L,p,q] = lchol (A)") ; + mexErrMsgTxt ("usage: [L,p,q] = lchol (A)") ; } n = mxGetN (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("A must be square and sparse") ; + mexErrMsgTxt ("A must be square and sparse") ; } - /* get sparse matrix A, use tril(A) */ - A = sputil_get_sparse (pargin [0], &Amatrix, &dummy, -1) ; + // get sparse matrix A, use tril(A) + size_t A_xsize = 0 ; + A = sputil2_get_sparse (pargin [0], -1, CHOLMOD_DOUBLE, &Amatrix, &A_xsize, + cm) ; - /* use natural ordering if no q output parameter */ + // use natural ordering if no q output parameter if (nargout < 3) { - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = FALSE ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = FALSE ; } - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- L = cholmod_l_analyze (A, cm) ; cholmod_l_factorize (A, L, cm) ; if (nargout < 2 && cm->status != CHOLMOD_OK) { - mexErrMsgTxt ("matrix is not positive definite") ; + mexErrMsgTxt ("matrix is not positive definite") ; } - /* ---------------------------------------------------------------------- */ - /* convert L to a sparse matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert L to a sparse matrix + //-------------------------------------------------------------------------- - /* the conversion sets L->minor back to n, so get a copy of it first */ + // the conversion sets L->minor back to n, so get a copy of it first minor = L->minor ; Lsparse = cholmod_l_factor_to_sparse (L, cm) ; if (Lsparse->xtype == CHOLMOD_COMPLEX) { - /* convert Lsparse from complex to zomplex */ - cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; + // convert Lsparse from complex to zomplex + cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; } if (minor < n) { - /* remove columns minor to n-1 from Lsparse */ - sputil_trim (Lsparse, minor, cm) ; + // remove columns minor to n-1 from Lsparse + sputil2_trim (Lsparse, minor, cm) ; } - /* drop zeros from Lsparse */ - sputil_drop_zeros (Lsparse) ; + //-------------------------------------------------------------------------- + // return results to MATLAB + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + // L cannot be used by any update/downdate methods since its explicit zeros + // have been dropped. - /* return L as a sparse matrix */ - pargout [0] = sputil_put_sparse (&Lsparse, cm) ; + // return L as a sparse matrix (dropping explicit zeros) + pargout [0] = sputil2_put_sparse (&Lsparse, mxDOUBLE_CLASS, + /* drop explicit zeros */ true, cm) ; - /* return minor (translate to MATLAB convention) */ + // return minor (translate to MATLAB convention) if (nargout > 1) { - pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; - px = mxGetPr (pargout [1]) ; - px [0] = ((minor == n) ? 0 : (minor+1)) ; + pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + px = (double *) mxGetData (pargout [1]) ; + px [0] = ((minor == n) ? 0 : (minor+1)) ; } - /* return permutation */ + // return permutation if (nargout > 2) { - pargout [2] = sputil_put_int (L->Perm, n, 1) ; + pargout [2] = sputil2_put_int (L->Perm, n, 1) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- cholmod_l_free_factor (&L, cm) ; + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 3 + mxIsComplex (pargout[0])) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 1) cholmod_l_gpu_stats (cm) ; } + diff --git a/CHOLMOD/MATLAB/lchol.m b/CHOLMOD/MATLAB/lchol.m index 2886df485a..a029746640 100644 --- a/CHOLMOD/MATLAB/lchol.m +++ b/CHOLMOD/MATLAB/lchol.m @@ -1,18 +1,19 @@ -function [L,p,q] = lchol (A) %#ok +function [L,p,q] = lchol (A) %#ok %LCHOL sparse A=L*L' factorization. -% Note that L*L' (LCHOL) and L*D*L' (LDLCHOL) factorizations are faster than -% R'*R (CHOL2 and CHOL) and use less memory. The LL' and LDL' factorization -% methods use tril(A). A must be sparse. +% Note that L*L' (LCHOL) and L*D*L' (LDLCHOL) factorizations are faster +% than R'*R (CHOL2 and CHOL) and use less memory. The LL' and LDL' +% factorization methods use tril(A). A must be sparse. % -% Example: -% L = lchol (A) same as L = chol (A')', just faster -% [L,p] = lchol (A) same as [R,p] = chol(A') ; L=R', just faster -% [L,p,q] = lchol (A) factorizes A(q,q) into L*L', where q is a -% fill-reducing ordering +% Example: +% L = lchol (A) same as L = chol (A')', just faster +% [L,p] = lchol (A) same as [R,p] = chol(A') ; L=R', just faster +% [L,p,q] = lchol (A) factorizes A(q,q) into L*L', where q is a +% fill-reducing ordering % -% See also CHOL2, LDLCHOL, CHOL. +% See also chol2, ldlchol, chol. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('lchol mexFunction not found') ; + diff --git a/CHOLMOD/MATLAB/ldl_normest.m b/CHOLMOD/MATLAB/ldl_normest.m index 03542d36ac..51773c502c 100644 --- a/CHOLMOD/MATLAB/ldl_normest.m +++ b/CHOLMOD/MATLAB/ldl_normest.m @@ -3,19 +3,19 @@ % % Example: % -% rho = ldl_normest (A, L, D) +% rho = ldl_normest (A, L, D) % % which estimates the computation of the 1-norm: % -% rho = norm (A-L*D*L', 1) +% rho = norm (A-L*D*L', 1) % -% See also condest, normest +% See also condest, normest. -% Copyright 2006-2022, William W. Hager and Timothy A. Davis, -% All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, William W. Hager and Timothy A. Davis, + % All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ -[m n] = size (A) ; +[m,n] = size (A) ; if (m ~= n) error ('A must be square') ; @@ -57,7 +57,7 @@ z = (A*y) - L*(D*(L'*x)) ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - [zj, j] = max (abs (z .* notvisited)) ; + [~, j] = max (abs (z .* notvisited)) ; j = j (1) ; if (abs (z (j)) > z'*x) % { x = zeros (m, 1) ; diff --git a/CHOLMOD/MATLAB/ldlchol.c b/CHOLMOD/MATLAB/ldlchol.c index 31f68f095c..74e9b44be8 100644 --- a/CHOLMOD/MATLAB/ldlchol.c +++ b/CHOLMOD/MATLAB/ldlchol.c @@ -2,66 +2,65 @@ // CHOLMOD/MATLAB/ldlchol: MATLAB interface to CHOLMOD LDL' factorization //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Numeric LDL' factorization. Note that LL' and LDL' are faster than R'R - * and use less memory. The LDL' factorization methods use tril(A). - * The unit diagonal L can be obtained with tril(LD,-1)+speye(n) and the - * diagonal D can be obtained with D = diag(diag(LD)) ; - * - * LD = ldlchol (A) return the LDL' factorization of A - * [LD,p] = ldlchol (A) like [R,p] = chol(A), except LD is always square - * [LD,p,q] = ldlchol (A) factorizes A(q,q) into L*D*L' - * - * LD = ldlchol (A,beta) return the LDL' factorization of A*A'+beta*I - * [LD,p] = ldlchol (A,beta) like [R,p] = chol(A*A'+beta+I) - * [LD,p,q] = ldlchol (A,beta) factorizes A(q,:)*A(q,:)'+beta*I into L*D*L' - * - * Explicit zeros may appear in the LD matrix. The pattern of LD matches the - * pattern of L as computed by symbfact2, even if some entries in LD are - * explicitly zero. This is to ensure that ldlupdate works properly. You must - * NOT modify LD in MATLAB itself and then use ldlupdate if LD contains - * explicit zero entries; ldlupdate will fail catastrophically in this case. - * - * You MAY modify LD in MATLAB if you do not pass it back to ldlupdate. Just be - * aware that LD contains explicit zero entries, contrary to the standard - * practice in MATLAB of removing those entries from all sparse matrices. - * - * Note that CHOLMOD uses a supernodal LL' factorization and then converts it - * to LDL' for large matrices, and a simplicial LDL' factorization otherwise. - * Two-by-two block pivoting is not performed, in any case. Thus, ldlchol - * will not be able to perform an LDL' factorization of an arbitrary indefinite - * matrix. The matrix - * - * 0 1 - * 1 0 - * - * will fail, for example. You can tell CHOLMOD to always use its simplicial - * LDL' factorization by adding the statement - * - * cm->supernodal = CHOLMOD_SIMPLICIAL ; - * - * but ldlchol will be much slower for large matrices. It still will not be - * able to handle the above matrix, but it can then handle matrices such as - * - * -2 1 - * 1 -2 - * - * or any other symmetric matrix for which all leading minors are - * well-conditioned. - */ - -#include "cholmod_matlab.h" +// Numeric LDL' factorization. Note that LL' and LDL' are faster than R'R +// and use less memory. The LDL' factorization methods use tril(A). +// The unit diagonal L can be obtained with tril(LD,-1)+speye(n) and the +// diagonal D can be obtained with D = diag(diag(LD)) ; +// +// LD = ldlchol (A) return the LDL' factorization of A +// [LD,p] = ldlchol (A) like [R,p] = chol(A), except LD is always square +// [LD,p,q] = ldlchol (A) factorizes A(q,q) into L*D*L' +// +// LD = ldlchol (A,beta) return the LDL' factorization of A*A'+beta*I +// [LD,p] = ldlchol (A,beta) like [R,p] = chol(A*A'+beta+I) +// [LD,p,q] = ldlchol (A,beta) factorizes A(q,:)*A(q,:)'+beta*I into L*D*L' +// +// Explicit zeros may appear in the LD matrix. The pattern of LD matches the +// pattern of L as computed by symbfact2, even if some entries in LD are +// explicitly zero. This is to ensure that ldlupdate works properly. You must +// NOT modify LD in MATLAB itself and then use ldlupdate if LD contains +// explicit zero entries; ldlupdate will fail catastrophically in this case. +// +// You MAY modify LD in MATLAB if you do not pass it back to ldlupdate. Just be +// aware that LD contains explicit zero entries, contrary to the standard +// practice in MATLAB of removing those entries from all sparse matrices. +// +// Note that CHOLMOD uses a supernodal LL' factorization and then converts it +// to LDL' for large matrices, and a simplicial LDL' factorization otherwise. +// Two-by-two block pivoting is not performed, in any case. Thus, ldlchol +// will not be able to perform an LDL' factorization of an arbitrary indefinite +// matrix. The matrix +// +// 0 1 +// 1 0 +// +// will fail, for example. You can tell CHOLMOD to always use its simplicial +// LDL' factorization by adding the statement +// +// cm->supernodal = CHOLMOD_SIMPLICIAL ; +// +// but ldlchol will be much slower for large matrices. It still will not be +// able to handle the above matrix, but it can then handle matrices such as +// +// -2 1 +// 1 -2 +// +// or any other symmetric matrix for which all leading minors are +// well-conditioned. + +#include "sputil2.h" void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -71,129 +70,133 @@ void mexFunction cholmod_common Common, *cm ; int64_t n, minor ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* convert to packed LDL' when done */ + // convert to packed LDL' when done cm->final_asis = FALSE ; cm->final_super = FALSE ; cm->final_ll = FALSE ; cm->final_pack = TRUE ; cm->final_monotonic = TRUE ; - /* since numerically zero entries are NOT dropped from the symbolic - * pattern, we DO need to drop entries that result from supernodal - * amalgamation. */ + // since numerically zero entries are NOT dropped from the symbolic + // pattern, we DO need to drop entries that result from supernodal + // amalgamation. cm->final_resymbol = TRUE ; cm->quick_return_if_not_posdef = (nargout < 2) ; - /* This will disable the supernodal LL', which will be slow. */ - /* cm->supernodal = CHOLMOD_SIMPLICIAL ; */ + // This will disable the supernodal LL', which will be slow. + // cm->supernodal = CHOLMOD_SIMPLICIAL ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargin < 1 || nargin > 2 || nargout > 3) { - mexErrMsgTxt ("usage: [L,p,q] = ldlchol (A,beta)") ; + mexErrMsgTxt ("usage: [L,p,q] = ldlchol (A,beta)") ; } n = mxGetM (pargin [0]) ; if (!mxIsSparse (pargin [0])) { - mexErrMsgTxt ("A must be sparse") ; + mexErrMsgTxt ("A must be sparse") ; } if (nargin == 1 && n != mxGetN (pargin [0])) { - mexErrMsgTxt ("A must be square") ; + mexErrMsgTxt ("A must be square") ; } - /* get sparse matrix A, use tril(A) */ - A = sputil_get_sparse (pargin [0], &Amatrix, &dummy, -1) ; + // get sparse matrix A, use tril(A) + size_t A_xsize = 0 ; + A = sputil2_get_sparse (pargin [0], -1, CHOLMOD_DOUBLE, &Amatrix, + &A_xsize, cm) ; if (nargin == 1) { - A->stype = -1 ; /* use lower part of A */ - beta [0] = 0 ; - beta [1] = 0 ; + A->stype = -1 ; // use lower part of A + beta [0] = 0 ; + beta [1] = 0 ; } else { - A->stype = 0 ; /* use all of A, factorizing A*A' */ - beta [0] = mxGetScalar (pargin [1]) ; - beta [1] = 0 ; + A->stype = 0 ; // use all of A, factorizing A*A' + beta [0] = mxGetScalar (pargin [1]) ; + beta [1] = 0 ; } - /* use natural ordering if no q output parameter */ + // use natural ordering if no q output parameter if (nargout < 3) { - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = FALSE ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = FALSE ; } - /* ---------------------------------------------------------------------- */ - /* analyze and factorize */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // analyze and factorize + //-------------------------------------------------------------------------- L = cholmod_l_analyze (A, cm) ; cholmod_l_factorize_p (A, beta, NULL, 0, L, cm) ; if (nargout < 2 && cm->status != CHOLMOD_OK) { - mexErrMsgTxt ("matrix is not positive definite") ; + mexErrMsgTxt ("matrix is not positive definite") ; } - /* ---------------------------------------------------------------------- */ - /* convert L to a sparse matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert L to a sparse matrix + //-------------------------------------------------------------------------- - /* the conversion sets L->minor back to n, so get a copy of it first */ + // the conversion sets L->minor back to n, so get a copy of it first minor = L->minor ; Lsparse = cholmod_l_factor_to_sparse (L, cm) ; if (Lsparse->xtype == CHOLMOD_COMPLEX) { - /* convert Lsparse from complex to zomplex */ - cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; + // convert Lsparse from complex to zomplex + cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, Lsparse, cm) ; } - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results to MATLAB + //-------------------------------------------------------------------------- - /* return L as a sparse matrix (it may contain numerically zero entries) */ - pargout [0] = sputil_put_sparse (&Lsparse, cm) ; + // return L as a sparse matrix; it may contain numerically zero entries, + // which must be kept to allow update/downdate to work. + pargout [0] = sputil2_put_sparse (&Lsparse, mxDOUBLE_CLASS, + /* return L with explicit zeros kept */ false, cm) ; - /* return minor (translate to MATLAB convention) */ + // return minor (translate to MATLAB convention) if (nargout > 1) { - pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; - px = mxGetPr (pargout [1]) ; - px [0] = ((minor == n) ? 0 : (minor+1)) ; + pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + px = (double *) mxGetData (pargout [1]) ; + px [0] = ((minor == n) ? 0 : (minor+1)) ; } - /* return permutation */ + // return permutation if (nargout > 2) { - pargout [2] = sputil_put_int (L->Perm, n, 1) ; + pargout [2] = sputil2_put_int (L->Perm, n, 1) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- cholmod_l_free_factor (&L, cm) ; + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 3 + mxIsComplex (pargout[0])) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 1) cholmod_l_gpu_stats (cm) ; } + diff --git a/CHOLMOD/MATLAB/ldlchol.m b/CHOLMOD/MATLAB/ldlchol.m index 48ccbdc4c2..497124b81b 100644 --- a/CHOLMOD/MATLAB/ldlchol.m +++ b/CHOLMOD/MATLAB/ldlchol.m @@ -1,38 +1,40 @@ -function [LD,p,q] = ldlchol (A,beta) %#ok +function [LD,p,q] = ldlchol (A,beta) %#ok %LDLCHOL sparse A=LDL' factorization -% Note that L*L' (LCHOL) and L*D*L' (LDLCHOL) factorizations are faster than -% R'*R (CHOL2 and CHOL) and use less memory. The LL' and LDL' factorization -% methods use tril(A). A must be sparse. +% Note that L*L' (LCHOL) and L*D*L' (LDLCHOL) factorizations are faster +% than R'*R (CHOL2 and CHOL) and use less memory. The LL' and LDL' +% factorization methods use tril(A). A must be sparse. % -% Example: +% Example: % LD = ldlchol (A) return the LDL' factorization of A % [LD,p] = ldlchol (A) similar [R,p] = chol(A), but for L*D*L' -% [LD,p,q] = ldlchol (A) factorizes A(q,q) into L*D*L', where q is a -% fill-reducing ordering -% LD = ldlchol (A,beta) return the LDL' factorization of A*A'+beta*I +% [LD,p,q] = ldlchol (A) factorizes A(q,q) into L*D*L', where q is +% a fill-reducing ordering +% LD = ldlchol (A,beta) LDL' factorization of A*A'+beta*I % [LD,p] = ldlchol (A,beta) like [R,p] = chol(A*A'+beta+I) -% [LD,p,q] = ldlchol (A,beta) factorizes A(q,:)*A(q,:)'+beta*I into L*D*L' +% [LD,p,q] = ldlchol (A,beta) factorizes A(q,:)*A(q,:)'+beta*I = L*D*L' % -% The output matrix LD contains both L and D. D is on the diagonal of LD, and -% L is contained in the strictly lower triangular part of LD. The unit- -% diagonal of L is not stored. You can obtain the L and D matrices with -% [L,D] = ldlsplit (LD). LD is in the form needed by ldlupdate. +% The output matrix LD contains both L and D. D is on the diagonal of +% LD, and L is contained in the strictly lower triangular part of LD. +% The unit- diagonal of L is not stored. You can obtain the L and D +% matrices with [L,D] = ldlsplit (LD). LD is in the form needed by +% ldlupdate. % -% Explicit zeros may appear in the LD matrix. The pattern of LD matches the -% pattern of L as computed by symbfact2, even if some entries in LD are -% explicitly zero. This is to ensure that ldlupdate and ldlsolve work -% properly. You must NOT modify LD in MATLAB itself and then use ldlupdate -% or ldlsolve if LD contains explicit zero entries; ldlupdate and ldlsolve -% will fail catastrophically in this case. +% Explicit zeros may appear in the LD matrix. The pattern of LD matches +% the pattern of L as computed by symbfact2, even if some entries in LD +% are explicitly zero. This is to ensure that ldlupdate and ldlsolve +% work properly. You must NOT modify LD in MATLAB itself and then use +% ldlupdate or ldlsolve if LD contains explicit zero entries; ldlupdate +% and ldlsolve will fail catastrophically in this case. % -% You MAY modify LD in MATLAB if you do not pass it back to ldlupdate or -% ldlsolve. Just be aware that LD contains explicit zero entries, contrary -% to the standard practice in MATLAB of removing those entries from all -% sparse matrices. LD = sparse2 (LD) will remove any zero entries in LD. +% You MAY modify LD in MATLAB if you do not pass it back to ldlupdate or +% ldlsolve. Just be aware that LD contains explicit zero entries, +% contrary to the standard practice in MATLAB of removing those entries +% from all sparse matrices. LD = sparse (LD) will remove any zero +% entries in LD. % -% See also LDLUPDATE, LDLSOLVE, LDLSPLIT, CHOL2, LCHOL, CHOL, SPARSE2 +% See also ldlupdate, ldlsolve, ldlsplit, chol2, lchol, chol. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('ldlchol mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/ldlrowmod.c b/CHOLMOD/MATLAB/ldlrowmod.c index 6acb97a55f..4a4303b20a 100644 --- a/CHOLMOD/MATLAB/ldlrowmod.c +++ b/CHOLMOD/MATLAB/ldlrowmod.c @@ -2,41 +2,40 @@ // CHOLMOD/MATLAB/ldlrowmod: MATLAB interface to CHOLMOD rowmod method //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Rank-1 row add/delete of a sparse LDL' factorization. - * - * 'Adding' or 'deleting' a row does not change the dimension of L. - * Instead, deleting a row A(k,:) and the corresponding column A(:,k) means - * replacing the kth row and column of A with the kth row and column of the - * identity matrix. Adding a row is the opposite. This function then modifies - * the LDL' factorization of A to reflect this change. - * - * To add a row k, the kth row of A is assumed to already be the kth row of - * identity. This condition is not checked. - * - * On input, LD contains the LDL' factorization of A. See ldlchol for details. - * If A has been permuted, then C must reflect that permutation. In other - * words, the caller must have already permuted C according the the fill- - * reducing ordering found by ldlchol. - * - * Usage: - * - * LD = ldlrowmod (LD,k,C) add row k to an LDL' factorization - * LD = ldlrowmod (LD,k) delete row k from an LDL' factorization - * - * See ldlrowmod.m for details. LD and C must be real and sparse. - * C is a column vector that is the new column A(:,k). - * - * The bulk of the time is spent copying the input LD to the output LD. This - * mexFunction could be much faster if it could safely modify its input LD. - */ - -#include "cholmod_matlab.h" +// Rank-1 row add/delete of a sparse LDL' factorization. +// +// 'Adding' or 'deleting' a row does not change the dimension of L. +// Instead, deleting a row A(k,:) and the corresponding column A(:,k) means +// replacing the kth row and column of A with the kth row and column of the +// identity matrix. Adding a row is the opposite. This function then modifies +// the LDL' factorization of A to reflect this change. +// +// To add a row k, the kth row of A is assumed to already be the kth row of +// identity. This condition is not checked. +// +// On input, LD contains the LDL' factorization of A. See ldlchol for details. +// If A has been permuted, then C must reflect that permutation. In other +// words, the caller must have already permuted C according the the fill- +// reducing ordering found by ldlchol. +// +// Usage: +// +// LD = ldlrowmod (LD,k,C) add row k to an LDL' factorization +// LD = ldlrowmod (LD,k) delete row k from an LDL' factorization +// +// See ldlrowmod.m for details. LD and C must be real and sparse. +// C is a column vector that is the new column A(:,k). +// +// The bulk of the time is spent copying the input LD to the output LD. This +// mexFunction could be much faster if it could safely modify its input LD. + +#include "sputil2.h" void mexFunction ( @@ -55,37 +54,37 @@ void mexFunction int64_t j, k, s, rowadd, n, lnz ; int ok ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin < 2 || nargin > 3) { - mexErrMsgTxt ("Usage: LD = ldlrowmod (LD,k,C) or ldlrowmod (LD,k)") ; + mexErrMsgTxt ("Usage: LD = ldlrowmod (LD,k,C) or ldlrowmod (LD,k)") ; } n = mxGetN (pargin [0]) ; k = (int64_t) mxGetScalar (pargin [1]) ; - k = k - 1 ; /* change from 1-based to 0-based */ + k = k - 1 ; // change from 1-based to 0-based if (!mxIsSparse (pargin [0]) - || n != mxGetM (pargin [0]) - || mxIsComplex (pargin [0])) + || n != mxGetM (pargin [0]) + || mxIsComplex (pargin [0])) { - mexErrMsgTxt ("ldlrowmod: L must be real, square, and sparse") ; + mexErrMsgTxt ("ldlrowmod: L must be real, square, and sparse") ; } - /* ---------------------------------------------------------------------- */ - /* determine if we're doing an rowadd or rowdel */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine if we're doing an rowadd or rowdel + //-------------------------------------------------------------------------- rowadd = (nargin > 2) ; @@ -101,34 +100,36 @@ void mexFunction } } - /* ---------------------------------------------------------------------- */ - /* get C: sparse vector of incoming/outgoing column */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get C: sparse vector of incoming/outgoing column + //-------------------------------------------------------------------------- - C = (rowadd) ? sputil_get_sparse (pargin [2], &Cmatrix, &dummy, 0) : NULL ; + size_t C_xsize = 0 ; + C = (rowadd) ? sputil2_get_sparse (pargin [2], 0, CHOLMOD_DOUBLE, &Cmatrix, + &C_xsize, cm) : NULL ; - /* ---------------------------------------------------------------------- */ - /* construct a copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* get the MATLAB L */ + // get the MATLAB L Lp = (int64_t *) mxGetJc (pargin [0]) ; Li = (int64_t *) mxGetIr (pargin [0]) ; - Lx = mxGetPr (pargin [0]) ; + Lx = (double *) mxGetData (pargin [0]) ; - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; ColCount = L->ColCount ; for (j = 0 ; j < n ; j++) { - ColCount [j] = Lp [j+1] - Lp [j] ; + ColCount [j] = Lp [j+1] - Lp [j] ; } - /* allocate space for a CHOLMOD LDL' packed factor */ + // allocate space for a CHOLMOD LDL' packed factor cholmod_l_change_factor (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, L, cm) ; - /* copy MATLAB L into CHOLMOD L */ + // copy MATLAB L into CHOLMOD L Lp2 = L->p ; Li2 = L->i ; Lx2 = L->x ; @@ -136,24 +137,24 @@ void mexFunction lnz = L->nzmax ; for (j = 0 ; j <= n ; j++) { - Lp2 [j] = Lp [j] ; + Lp2 [j] = Lp [j] ; } for (j = 0 ; j < n ; j++) { - Lnz2 [j] = Lp [j+1] - Lp [j] ; + Lnz2 [j] = Lp [j+1] - Lp [j] ; } for (s = 0 ; s < lnz ; s++) { - Li2 [s] = Li [s] ; + Li2 [s] = Li [s] ; } for (s = 0 ; s < lnz ; s++) { - Lx2 [s] = Lx [s] ; + Lx2 [s] = Lx [s] ; } - /* ---------------------------------------------------------------------- */ - /* rowadd/rowdel the LDL' factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // rowadd/rowdel the LDL' factorization + //-------------------------------------------------------------------------- if (rowadd) { @@ -165,26 +166,27 @@ void mexFunction } if (!ok) mexErrMsgTxt ("ldlrowmod failed\n") ; - /* ---------------------------------------------------------------------- */ - /* copy the results back to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy the results back to MATLAB + //-------------------------------------------------------------------------- - /* change L back to packed LDL' (it may have become unpacked if the - * sparsity pattern changed). This change takes O(n) time if the pattern - * of L wasn't updated. */ + // change L back to packed LDL' (it may have become unpacked if the + // sparsity pattern changed). This change takes O(n) time if the pattern + // of L wasn't updated. Lsparse = cholmod_l_factor_to_sparse (L, cm) ; - /* return L as a sparse matrix */ - pargout [0] = sputil_put_sparse (&Lsparse, cm) ; + // return L as a sparse matrix; it may contain numerically zero entries, + // which must be kept to allow update/downdate to work. + pargout [0] = sputil2_put_sparse (&Lsparse, mxDOUBLE_CLASS, + /* return L with explicit zeros kept */ false, cm) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- cholmod_l_free_factor (&L, cm) ; + sputil2_free_sparse (&C, &Cmatrix, C_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 3 + mxIsComplex (pargout[0])) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/ldlrowmod.m b/CHOLMOD/MATLAB/ldlrowmod.m index b7e24dc516..c5de5abce5 100644 --- a/CHOLMOD/MATLAB/ldlrowmod.m +++ b/CHOLMOD/MATLAB/ldlrowmod.m @@ -1,56 +1,57 @@ -function LD = ldlrowmod (LD,k,C) %#ok +function LD = ldlrowmod (LD,k,C) %#ok %LDLROWMOD add/delete a row from a sparse LDL' factorization. % -% On input, LD contains the LDL' factorization of A (L*D*L'=A or A(q,q)). -% The unit-diagonal of L is not stored. In its place is the diagonal matrix -% D. LD can be computed using the CHOLMOD mexFunctions: -% -% LD = ldlchol (A) ; -% or -% [LD,p,q] = ldlchol (A) ; -% -% With this LD, either of the following MATLAB statements, -% -% Example: -% LD = ldlrowmod (LD,k,C) add row k to an LDL' factorization -% -% returns the LDL' factorization of S, where S = A except for S(:,k) = C -% and S (k,:) = C. The kth row of A is assumed to initially be equal to -% the kth row of identity. To delete a row: -% -% LD = ldlrowmod (LD,k) delete row k from an LDL' factorization -% -% returns the LDL' factorization of S, where S = A except that S(:,k) and -% S (k,:) become the kth column/row of speye(n), repespectively. -% -% LD and C must be sparse and real. LD must be square, and C must have the -% same number of rows as LD. You must not modify LD in MATLAB (see the -% WARNING below). -% -% Note that if C is sparse with few columns, most of the time spent in this -% routine is taken by copying the input LD to the output LD. If MATLAB -% allowed mexFunctions to safely modify its inputs, this mexFunction would -% be much faster, since not all of LD changes. -% -% See also LDLCHOL, LDLSPLIT, LDLSOLVE, CHOLUPDATE, LDLUPDATE -% -% =========================================================================== -% =============================== WARNING =================================== -% =========================================================================== -% MATLAB drops zero entries from its sparse matrices. LD can contain -% numerically zero entries that are symbolically present in the sparse matrix -% data structure. These are essential for ldlrowmod and ldlsolve to work -% properly, since they exploit the graph-theoretic structure of a sparse -% Cholesky factorization. If you modify LD in MATLAB, those zero entries may -% get dropped and the required graph property will be destroyed. In this -% case, ldlrowmod and ldlsolve will fail catastrophically (possibly with a -% segmentation fault, terminating MATLAB). It takes much more time to ensure -% this property holds than the time it takes to do the row add/delete or the -% solve, so ldlrowmod and ldlsolve simply assume the propertly holds. -% =========================================================================== +% On input, LD contains the LDL' factorization of A (L*D*L'=A or A(q,q)). +% The unit-diagonal of L is not stored. In its place is the diagonal +% matrix D. LD can be computed using the CHOLMOD mexFunctions: +% +% LD = ldlchol (A) ; +% or +% [LD,p,q] = ldlchol (A) ; +% +% With this LD, either of the following MATLAB statements, +% +% Example: +% LD = ldlrowmod (LD,k,C) add row k to an LDL' factorization +% +% returns the LDL' factorization of S, where S = A except for S(:,k) = +% C and S (k,:) = C. The kth row of A is assumed to initially be equal +% to the kth row of identity. To delete a row: +% +% LD = ldlrowmod (LD,k) delete row k from an LDL' factorization +% +% returns the LDL' factorization of S, where S = A except that S(:,k) +% and S (k,:) become the kth column/row of speye(n), repespectively. +% +% LD and C must be sparse and real. LD must be square, and C must have +% the same number of rows as LD. You must not modify LD in MATLAB (see +% the WARNING below). +% +% Note that if C is sparse with few columns, most of the time spent in +% this routine is taken by copying the input LD to the output LD. If +% MATLAB allowed mexFunctions to safely modify its inputs, this +% mexFunction would be much faster, since not all of LD changes. +% +% See also ldlchol, ldlsplit, ldlsolve, cholupdate, ldlupdate. +% +% ======================================================================== +% ============================ WARNING =================================== +% ======================================================================== +% +% MATLAB drops zero entries from its sparse matrices. LD can contain +% numerically zero entries that are symbolically present in the sparse +% matrix data structure. These are essential for ldlrowmod and ldlsolve +% to work properly, since they exploit the graph-theoretic structure of a +% sparse Cholesky factorization. If you modify LD in MATLAB, those zero +% entries may get dropped and the required graph property will be +% destroyed. In this case, ldlrowmod and ldlsolve will fail +% catastrophically (possibly with a segmentation fault, terminating +% MATLAB). It takes much more time to ensure this property holds than +% the time it takes to do the row add/delete or the solve, so ldlrowmod +% and ldlsolve simply assume the propertly holds. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('ldlrowmod mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/ldlsolve.c b/CHOLMOD/MATLAB/ldlsolve.c index 0f671c07a7..8d0a060e3f 100644 --- a/CHOLMOD/MATLAB/ldlsolve.c +++ b/CHOLMOD/MATLAB/ldlsolve.c @@ -2,22 +2,21 @@ // CHOLMOD/MATLAB/ldlsolve: MATLAB interface to CHOLMOD LDL' solve //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Solve LDL'x=b given an LDL' factorization computed by ldlchol. - * - * Usage: - * - * x = ldlsolve (LD,b) - * - * b can be dense or sparse. - */ +// Solve LDL'x=b given an LDL' factorization computed by ldlchol. +// +// Usage: +// +// x = ldlsolve (LD,b) +// +// b can be dense or sparse. -#include "cholmod_matlab.h" +#include "sputil2.h" void mexFunction ( @@ -35,21 +34,21 @@ void mexFunction cholmod_common Common, *cm ; int64_t j, k, n, B_is_sparse, head, tail ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin != 2) { - mexErrMsgTxt ("Usage: x = ldlsolve (LD, b)") ; + mexErrMsgTxt ("Usage: x = ldlsolve (LD, b)") ; } n = mxGetN (pargin [0]) ; @@ -57,55 +56,58 @@ void mexFunction if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("ldlsolve: LD must be sparse and square") ; + mexErrMsgTxt ("ldlsolve: LD must be sparse and square") ; } if (n != mxGetM (pargin [1])) { - mexErrMsgTxt ("ldlsolve: b wrong dimension") ; + mexErrMsgTxt ("ldlsolve: b wrong dimension") ; } - /* ---------------------------------------------------------------------- */ - /* get b */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get b + //-------------------------------------------------------------------------- - /* get sparse or dense matrix B */ + // get sparse or dense matrix B B = NULL ; Bs = NULL ; B_is_sparse = mxIsSparse (pargin [1]) ; + size_t B_xsize = 0 ; if (B_is_sparse) { - /* get sparse matrix B (unsymmetric) */ - Bs = sputil_get_sparse (pargin [1], &Bspmatrix, &dummy, 0) ; + // get sparse matrix B (unsymmetric) + Bs = sputil2_get_sparse (pargin [1], 0, CHOLMOD_DOUBLE, &Bspmatrix, + &B_xsize, cm) ; } else { - /* get dense matrix B */ - B = sputil_get_dense (pargin [1], &Bmatrix, &dummy) ; + // get dense matrix B + B = sputil2_get_dense (pargin [1], CHOLMOD_DOUBLE, &Bmatrix, + &B_xsize, cm) ; } - /* ---------------------------------------------------------------------- */ - /* construct a shallow copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a shallow copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* the construction of the CHOLMOD takes O(n) time and memory */ + // the construction of the CHOLMOD takes O(n) time and memory - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; - /* get the MATLAB L */ + // get the MATLAB L L->p = mxGetJc (pargin [0]) ; L->i = mxGetIr (pargin [0]) ; - L->x = mxGetPr (pargin [0]) ; - L->z = mxGetPi (pargin [0]) ; + L->x = mxGetData (pargin [0]) ; + L->z = NULL ; - /* allocate and initialize the rest of L */ + // allocate and initialize the rest of L L->nz = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Lp = L->p ; Lnz = L->nz ; for (j = 0 ; j < n ; j++) { - Lnz [j] = Lp [j+1] - Lp [j] ; + Lnz [j] = Lp [j+1] - Lp [j] ; } L->prev = cholmod_l_malloc (n+2, sizeof (int64_t), cm) ; L->next = cholmod_l_malloc (n+2, sizeof (int64_t), cm) ; @@ -120,56 +122,55 @@ void mexFunction Lprev [tail] = n-1 ; for (j = 0 ; j < n ; j++) { - Lnext [j] = j+1 ; - Lprev [j] = j-1 ; + Lnext [j] = j+1 ; + Lprev [j] = j-1 ; } Lprev [0] = head ; - L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; + L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; L->nzmax = Lp [n] ; - /* ---------------------------------------------------------------------- */ - /* solve and return solution to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve and return solution to MATLAB + //-------------------------------------------------------------------------- if (B_is_sparse) { - /* solve LDL'X=B with sparse X and B; return sparse X to MATLAB */ - Xs = cholmod_l_spsolve (CHOLMOD_LDLt, L, Bs, cm) ; - pargout [0] = sputil_put_sparse (&Xs, cm) ; + // solve LDL'X=B with sparse X and B; return sparse X to MATLAB. + // cholmod_l_spsolve returns Xs with no explicit zeros. + Xs = cholmod_l_spsolve (CHOLMOD_LDLt, L, Bs, cm) ; + pargout [0] = sputil2_put_sparse (&Xs, mxDOUBLE_CLASS, + /* already done by cholmod_l_spsolve: */ false, cm) ; } else { - /* solve AX=B with dense X and B; return dense X to MATLAB */ - X = cholmod_l_solve (CHOLMOD_LDLt, L, B, cm) ; - pargout [0] = sputil_put_dense (&X, cm) ; + // solve AX=B with dense X and B; return dense X to MATLAB + X = cholmod_l_solve (CHOLMOD_LDLt, L, B, cm) ; + pargout [0] = sputil2_put_dense (&X, mxDOUBLE_CLASS, cm) ; } rcond = cholmod_l_rcond (L, cm) ; if (rcond == 0) { - mexWarnMsgTxt ("Matrix is indefinite or singular to working precision"); + mexWarnMsgTxt ("Matrix is indefinite or singular to working precision"); } else if (rcond < DBL_EPSILON) { - mexWarnMsgTxt ("Matrix is close to singular or badly scaled.") ; - mexPrintf (" Results may be inaccurate. RCOND = %g.\n", rcond) ; + mexWarnMsgTxt ("Matrix is close to singular or badly scaled.") ; + mexPrintf (" Results may be inaccurate. RCOND = %g.\n", rcond) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- L->p = NULL ; L->i = NULL ; L->x = NULL ; - L->z = NULL ; + sputil2_free_sparse (&Bs, &Bspmatrix, B_xsize, cm) ; + sputil2_free_dense (&B, &Bmatrix, B_xsize, cm) ; cholmod_l_free_factor (&L, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != - (mxIsComplex (pargout [0]) + (mxIsSparse (pargout[0]) ? 3:1))) - mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/ldlsolve.m b/CHOLMOD/MATLAB/ldlsolve.m index bf70a81b8d..b5c8ad5d65 100644 --- a/CHOLMOD/MATLAB/ldlsolve.m +++ b/CHOLMOD/MATLAB/ldlsolve.m @@ -1,21 +1,21 @@ -function x = ldlsolve (LD,b) %#ok +function x = ldlsolve (LD,b) %#ok %LDLSOLVE solve LDL'x=b using a sparse LDL' factorization % -% Example: +% Example: % x = ldlsolve (LD,b) % -% solves the system L*D*L'*x=b for x. This is equivalent to +% solves the system L*D*L'*x=b for x. This is equivalent to % % [L,D] = ldlsplit (LD) ; % x = L' \ (D \ (L \ b)) ; % -% LD is from ldlchol, or as updated by ldlupdate or ldlrowmod. You must not -% modify LD as obtained from ldlchol, ldlupdate, or ldlrowmod prior to passing -% it to this function. See ldlupdate for more details. +% LD is from ldlchol, or as updated by ldlupdate or ldlrowmod. You must +% not modify LD as obtained from ldlchol, ldlupdate, or ldlrowmod prior +% to passing it to this function. See ldlupdate for more details. % -% See also LDLCHOL, LDLUPDATE, LDLSPLIT, LDLROWMOD +% See also ldlchol, ldlupdate, ldlsplit, ldlrowmod. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('ldlsolve mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/ldlsplit.m b/CHOLMOD/MATLAB/ldlsplit.m index f90699e834..20c62915a4 100644 --- a/CHOLMOD/MATLAB/ldlsplit.m +++ b/CHOLMOD/MATLAB/ldlsplit.m @@ -1,18 +1,18 @@ -function [L,D] = ldlsplit (LD) %#ok -%LDLSPLIT split an LDL' factorization into L and D. +function [L,D] = ldlsplit (LD) +%LDLSPLIT split an LDL' factorization into L and D % -% Example: +% Example: % [L,D] = ldlsplit (LD) % -% LD contains an LDL' factorization, computed with LD = ldlchol(A), -% for example. The diagonal of LD contains D, and the entries below -% the diagonal contain L (which has a unit diagonal). This function -% splits LD into its two components L and D so that L*D*L' = A. +% LD contains an LDL' factorization, computed with LD = ldlchol(A), for +% example. The diagonal of LD contains D, and the entries below the +% diagonal contain L (which has a unit diagonal). This function splits +% LD into its two components L and D so that L*D*L' = A. % -% See also LDLCHOL, LDLSOLVE, LDLUPDATE. +% See also ldlchol, ldlsolve, ldlupdate. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ n = size (LD,1) ; D = diag (diag (LD)) ; diff --git a/CHOLMOD/MATLAB/ldlupdate.c b/CHOLMOD/MATLAB/ldlupdate.c index 2d90ba82d1..e73ed17688 100644 --- a/CHOLMOD/MATLAB/ldlupdate.c +++ b/CHOLMOD/MATLAB/ldlupdate.c @@ -2,27 +2,26 @@ // CHOLMOD/MATLAB/ldlupdate: MATLAB interface to CHOLMOD update/downdate //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Multiple-rank update or downdate of a sparse LDL' factorization. - * - * Usage: - * - * LD = ldlupdate (LD,C) update an LDL' factorization - * LD = ldlupdate (LD,C,'+') update an LDL' factorization - * LD = ldlupdate (LD,C,'-') downdate an LDL' factorization - * - * See ldlupdate.m for details. LD and C must be real and sparse. - * - * The bulk of the time is spent copying the input LD to the output LD. This - * mexFunction could be much faster if it could safely modify its input LD. - */ - -#include "cholmod_matlab.h" +// Multiple-rank update or downdate of a sparse LDL' factorization. +// +// Usage: +// +// LD = ldlupdate (LD,C) update an LDL' factorization +// LD = ldlupdate (LD,C,'+') update an LDL' factorization +// LD = ldlupdate (LD,C,'-') downdate an LDL' factorization +// +// See ldlupdate.m for details. LD and C must be real and sparse. +// +// The bulk of the time is spent copying the input LD to the output LD. This +// mexFunction could be much faster if it could safely modify its input LD. + +#include "sputil2.h" void mexFunction ( @@ -41,80 +40,82 @@ void mexFunction int64_t j, k, s, update, n, lnz ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin < 2 || nargin > 3) { - mexErrMsgTxt ("Usage: L = ldlupdate (L, C, '+')") ; + mexErrMsgTxt ("Usage: L = ldlupdate (L, C, '+')") ; } n = mxGetN (pargin [0]) ; k = mxGetN (pargin [1]) ; if (!mxIsSparse (pargin [0]) || !mxIsSparse (pargin [1]) - || n != mxGetM (pargin [0]) || n != mxGetM (pargin [1]) - || mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) + || n != mxGetM (pargin [0]) || n != mxGetM (pargin [1]) + || mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { - mexErrMsgTxt ("ldlupdate: C and/or L not sparse, complex, or wrong" - " dimensions") ; + mexErrMsgTxt ("ldlupdate: C and/or L not sparse, complex, or wrong" + " dimensions") ; } - /* ---------------------------------------------------------------------- */ - /* determine if we're doing an update or downdate */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine if we're doing an update or downdate + //-------------------------------------------------------------------------- update = TRUE ; if (nargin > 2 && mxIsChar (pargin [2])) { - mxGetString (pargin [2], buf, LEN) ; - if (buf [0] == '-') - { - update = FALSE ; - } - else if (buf [0] != '+') - { - mexErrMsgTxt ("ldlupdate: update string must be '+' or '-'") ; - } + mxGetString (pargin [2], buf, LEN) ; + if (buf [0] == '-') + { + update = FALSE ; + } + else if (buf [0] != '+') + { + mexErrMsgTxt ("ldlupdate: update string must be '+' or '-'") ; + } } - /* ---------------------------------------------------------------------- */ - /* get C: sparse matrix of incoming/outgoing columns */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get C: sparse matrix of incoming/outgoing columns + //-------------------------------------------------------------------------- - C = sputil_get_sparse (pargin [1], &Cmatrix, &dummy, 0) ; + size_t C_xsize = 0 ; + C = sputil2_get_sparse (pargin [1], 0, CHOLMOD_DOUBLE, &Cmatrix, + &C_xsize, cm) ; - /* ---------------------------------------------------------------------- */ - /* construct a copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* get the MATLAB L */ + // get the MATLAB L Lp = (int64_t *) mxGetJc (pargin [0]) ; Li = (int64_t *) mxGetIr (pargin [0]) ; - Lx = mxGetPr (pargin [0]) ; + Lx = (double *) mxGetData (pargin [0]) ; - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; ColCount = L->ColCount ; for (j = 0 ; j < n ; j++) { - ColCount [j] = Lp [j+1] - Lp [j] ; + ColCount [j] = Lp [j+1] - Lp [j] ; } - /* allocate space for a CHOLMOD LDL' packed factor */ + // allocate space for a CHOLMOD LDL' packed factor cholmod_l_change_factor (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, L, cm) ; - /* copy MATLAB L into CHOLMOD L */ + // copy MATLAB L into CHOLMOD L Lp2 = L->p ; Li2 = L->i ; Lx2 = L->x ; @@ -122,50 +123,51 @@ void mexFunction lnz = L->nzmax ; for (j = 0 ; j <= n ; j++) { - Lp2 [j] = Lp [j] ; + Lp2 [j] = Lp [j] ; } for (j = 0 ; j < n ; j++) { - Lnz2 [j] = Lp [j+1] - Lp [j] ; + Lnz2 [j] = Lp [j+1] - Lp [j] ; } for (s = 0 ; s < lnz ; s++) { - Li2 [s] = Li [s] ; + Li2 [s] = Li [s] ; } for (s = 0 ; s < lnz ; s++) { - Lx2 [s] = Lx [s] ; + Lx2 [s] = Lx [s] ; } - /* ---------------------------------------------------------------------- */ - /* update/downdate the LDL' factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // update/downdate the LDL' factorization + //-------------------------------------------------------------------------- if (!cholmod_l_updown (update, C, L, cm)) { - mexErrMsgTxt ("ldlupdate failed\n") ; + mexErrMsgTxt ("ldlupdate failed\n") ; } - /* ---------------------------------------------------------------------- */ - /* copy the results back to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy the results back to MATLAB + //-------------------------------------------------------------------------- - /* change L back to packed LDL' (it may have become unpacked if the - * sparsity pattern changed). This change takes O(n) time if the pattern - * of L wasn't updated. */ + // change L back to packed LDL' (it may have become unpacked if the + // sparsity pattern changed). This change takes O(n) time if the pattern + // of L wasn't updated. Lsparse = cholmod_l_factor_to_sparse (L, cm) ; - /* return L as a sparse matrix */ - pargout [0] = sputil_put_sparse (&Lsparse, cm) ; + // return L as a sparse matrix; it may contain numerically zero entries, + // which must be kept to allow update/downdate to work. + pargout [0] = sputil2_put_sparse (&Lsparse, mxDOUBLE_CLASS, + /* return L with explicit zeros kept */ false, cm) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- + sputil2_free_sparse (&C, &Cmatrix, C_xsize, cm) ; cholmod_l_free_factor (&L, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 3 + mxIsComplex (pargout[0])) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/ldlupdate.m b/CHOLMOD/MATLAB/ldlupdate.m index ca0ffedf9b..9afba819f5 100644 --- a/CHOLMOD/MATLAB/ldlupdate.m +++ b/CHOLMOD/MATLAB/ldlupdate.m @@ -1,55 +1,56 @@ -function LD = ldlupdate (LD,C,updown) %#ok -%LDLUPDATE multiple-rank update or downdate of a sparse LDL' factorization. +function LD = ldlupdate (LD,C,updown) %#ok +%LDLUPDATE multiple-rank update or downdate of a sparse LDL' factorization % -% On input, LD contains the LDL' factorization of A (L*D*L'=A or A(q,q)). -% The unit-diagonal of L is not stored. In its place is the diagonal matrix -% D. LD can be computed using the CHOLMOD mexFunctions: +% On input, LD contains the LDL' factorization of A (L*D*L'=A or A(q,q)). +% The unit-diagonal of L is not stored. In its place is the diagonal +% matrix D. LD can be computed using the CHOLMOD mexFunctions: % -% LD = ldlchol (A) ; -% or -% [LD,p,q] = ldlchol (A) ; +% LD = ldlchol (A) ; +% or +% [LD,p,q] = ldlchol (A) ; % -% With this LD, either of the following MATLAB statements, +% With this LD, either of the following MATLAB statements: % -% Example: +% Example: % LD = ldlupdate (LD,C) % LD = ldlupdate (LD,C,'+') % -% return the LDL' factorization of A+C*C' or A(q,q)-C*C' if LD holds the LDL' -% factorization of A(q,q) on input. For a downdate: +% return the LDL' factorization of A+C*C' or A(q,q)-C*C' if LD holds the +% LDL' factorization of A(q,q) on input. For a downdate: % % LD = ldlupdate (LD,C,'-') % -% returns the LDL' factorization of A-C*C' or A(q,q)-C*C'. -% -% LD and C must be sparse and real. LD must be square, and C must have the -% same number of rows as LD. You must not modify LD in MATLAB (see the -% WARNING below). -% -% Note that if C is sparse with few columns, most of the time spent in this -% routine is taken by copying the input LD to the output LD. If MATLAB -% allowed mexFunctions to safely modify its inputs, this mexFunction would -% be much faster, since not all of LD changes. -% -% See also LDLCHOL, LDLSPLIT, LDLSOLVE, CHOLUPDATE -% -% =========================================================================== -% =============================== WARNING =================================== -% =========================================================================== -% MATLAB drops zero entries from its sparse matrices. LD can contain -% numerically zero entries that are symbolically present in the sparse matrix -% data structure. These are essential for ldlupdate and ldlsolve to work -% properly, since they exploit the graph-theoretic structure of a sparse -% Cholesky factorization. If you modify LD in MATLAB, those zero entries may -% get dropped and the required graph property will be destroyed. In this -% case, ldlupdate and ldlsolve will fail catastrophically (possibly with a -% segmentation fault, terminating MATLAB). It takes much more time to ensure -% this property holds than the time it takes to do the update/downdate or the -% solve, so ldlupdate and ldlsolve simply assume the propertly holds. -% =========================================================================== +% returns the LDL' factorization of A-C*C' or A(q,q)-C*C'. +% +% LD and C must be sparse and real. LD must be square, and C must have +% the same number of rows as LD. You must not modify LD in MATLAB (see +% the WARNING below). +% +% Note that if C is sparse with few columns, most of the time spent in +% this routine is taken by copying the input LD to the output LD. If +% MATLAB allowed mexFunctions to safely modify its inputs, this +% mexFunction would be much faster, since not all of LD changes. +% +% See also ldlchol, ldlsplit, ldlsolve, cholupdate. +% +% ======================================================================== +% ============================ WARNING =================================== +% ======================================================================== +% +% MATLAB drops zero entries from its sparse matrices. LD can contain +% numerically zero entries that are symbolically present in the sparse +% matrix data structure. These are essential for ldlupdate and ldlsolve +% to work properly, since they exploit the graph-theoretic structure of a +% sparse Cholesky factorization. If you modify LD in MATLAB, those zero +% entries may get dropped and the required graph property will be +% destroyed. In this case, ldlupdate and ldlsolve will fail +% catastrophically (possibly with a segmentation fault, terminating +% MATLAB). It takes much more time to ensure this property holds than +% the time it takes to do the update/downdate or the solve, so ldlupdate +% and ldlsolve simply assume the propertly holds. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('ldlupdate mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/lsubsolve.c b/CHOLMOD/MATLAB/lsubsolve.c index 856a86f7a7..c21bd594ff 100644 --- a/CHOLMOD/MATLAB/lsubsolve.c +++ b/CHOLMOD/MATLAB/lsubsolve.c @@ -2,48 +2,47 @@ // CHOLMOD/MATLAB/lsubsolve: MATLAB interface to CHOLMOD solver //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* [x xset] = lsubsolve (L,kind,P,b,system) - * - * L is a sparse lower triangular matrix, of size n-by-n. kind = 0 if - * L is from an LL' factorization, 1 if from LDL' (in which case L contains - * L in the lower part and D on the diagonal). P is a permutation vector, or - * empty (which means P is identity). b is a sparse column vector. - * system is a number between 0 and 8: - * - * Given L or LD, a permutation P, and a sparse right-hand size b, - * solve one of the following systems: - * - * Ax=b 0: CHOLMOD_A also applies the permutation L->Perm - * LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm - * LDx=b 2: CHOLMOD_LD - * DL'x=b 3: CHOLMOD_DLt - * Lx=b 4: CHOLMOD_L - * L'x=b 5: CHOLMOD_Lt - * Dx=b 6: CHOLMOD_D - * x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) - * x=P'b 8: CHOLMOD_Pt apply an inverse permutation - * - * The solution x is a dense vector, but it is a subset of the entire solution, - * x is zero except where xset is 1. xset is reach of b (or P*b) in the graph - * of L. If P is empty then it is treated as the identity permutation. - * - * No zeros can be dropped from the stucture of the Cholesky factorization - * because this function gets its elimination tree from L itself. See ldlchol - * for a method of constructing a sparse L with explicit zeros that are - * normally dropped by MATLAB. - * - * This function is only meant for testing the cholmod_solve2 function. The - * cholmod_solve2 function takes O(flops) time, but the setup time in this - * mexFunction wrapper can dominate that time. - */ - -#include "cholmod_matlab.h" +// [x xset] = lsubsolve (L,kind,P,b,system) +// +// L is a sparse lower triangular matrix, of size n-by-n. kind = 0 if +// L is from an LL' factorization, 1 if from LDL' (in which case L contains +// L in the lower part and D on the diagonal). P is a permutation vector, or +// empty (which means P is identity). b is a sparse column vector. +// system is a number between 0 and 8: +// +// Given L or LD, a permutation P, and a sparse right-hand size b, +// solve one of the following systems: +// +// Ax=b 0: CHOLMOD_A also applies the permutation L->Perm +// LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm +// LDx=b 2: CHOLMOD_LD +// DL'x=b 3: CHOLMOD_DLt +// Lx=b 4: CHOLMOD_L +// L'x=b 5: CHOLMOD_Lt +// Dx=b 6: CHOLMOD_D +// x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) +// x=P'b 8: CHOLMOD_Pt apply an inverse permutation +// +// The solution x is a dense vector, but it is a subset of the entire solution, +// x is zero except where xset is 1. xset is reach of b (or P*b) in the graph +// of L. If P is empty then it is treated as the identity permutation. +// +// No zeros can be dropped from the stucture of the Cholesky factorization +// because this function gets its elimination tree from L itself. See ldlchol +// for a method of constructing a sparse L with explicit zeros that are +// normally dropped by MATLAB. +// +// This function is only meant for testing the cholmod_solve2 function. The +// cholmod_solve2 function takes O(flops) time, but the setup time in this +// mexFunction wrapper can dominate that time. + +#include "sputil2.h" void mexFunction ( @@ -53,8 +52,8 @@ void mexFunction const mxArray *pargin [ ] ) { - double dummy = 0, *Px, *Xsetx ; - int64_t *Lp, *Lnz, *Xp, *Xi, xnz, *Perm, *Lprev, *Lnext, *Xsetp ; + double dummy = 0, *Px ; + int64_t *Lp, *Lnz, *Xp, *Xi, xnz, *Perm, *Lprev, *Lnext ; cholmod_sparse *Bset, Bmatrix, *Xset ; cholmod_dense *Bdense, *X, *Y, *E ; cholmod_factor *L ; @@ -62,96 +61,99 @@ void mexFunction int64_t k, j, n, head, tail, xsetlen ; int sys, kind ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargin != 5 || nargout > 2) { - mexErrMsgTxt ("usage: [x xset] = lsubsolve (L,kind,P,b,system)") ; + mexErrMsgTxt ("usage: [x xset] = lsubsolve (L,kind,P,b,system)") ; } n = mxGetN (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("lsubsolve: L must be sparse and square") ; + mexErrMsgTxt ("lsubsolve: L must be sparse and square") ; } if (mxGetNumberOfElements (pargin [1]) != 1) { - mexErrMsgTxt ("lsubsolve: kind must be a scalar") ; + mexErrMsgTxt ("lsubsolve: kind must be a scalar") ; } if (mxIsSparse (pargin [2]) || !(mxIsEmpty (pargin [2]) || mxGetNumberOfElements (pargin [2]) == n)) { - mexErrMsgTxt ("lsubsolve: P must be size n, or empty") ; + mexErrMsgTxt ("lsubsolve: P must be size n, or empty") ; } if (mxGetM (pargin [3]) != n || mxGetN (pargin [3]) != 1) { - mexErrMsgTxt ("lsubsolve: b wrong dimension") ; + mexErrMsgTxt ("lsubsolve: b wrong dimension") ; } if (!mxIsSparse (pargin [3])) { - mexErrMsgTxt ("lxbpattern: b must be sparse") ; + mexErrMsgTxt ("lxbpattern: b must be sparse") ; } if (mxGetNumberOfElements (pargin [4]) != 1) { - mexErrMsgTxt ("lsubsolve: system must be a scalar") ; + mexErrMsgTxt ("lsubsolve: system must be a scalar") ; } - /* ---------------------------------------------------------------------- */ - /* get the inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the inputs + //-------------------------------------------------------------------------- - kind = (int) sputil_get_integer (pargin [1], FALSE, 0) ; - sys = (int) sputil_get_integer (pargin [4], FALSE, 0) ; + kind = (int) mxGetScalar (pargin [1]) ; + sys = (int) mxGetScalar (pargin [4]) ; - /* ---------------------------------------------------------------------- */ - /* get the sparse b */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the sparse b + //-------------------------------------------------------------------------- + + // get sparse matrix B (unsymmetric) + size_t Bset_xsize = 0 ; + Bset = sputil2_get_sparse (pargin [3], 0, CHOLMOD_DOUBLE, &Bmatrix, + &Bset_xsize, cm) ; - /* get sparse matrix B (unsymmetric) */ - Bset = sputil_get_sparse (pargin [3], &Bmatrix, &dummy, 0) ; Bdense = cholmod_l_sparse_to_dense (Bset, cm) ; Bset->x = NULL ; Bset->z = NULL ; Bset->xtype = CHOLMOD_PATTERN ; - /* ---------------------------------------------------------------------- */ - /* construct a shallow copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a shallow copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* the construction of the CHOLMOD takes O(n) time and memory */ + // the construction of the CHOLMOD takes O(n) time and memory - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; - /* get the MATLAB L */ + // get the MATLAB L L->p = mxGetJc (pargin [0]) ; L->i = mxGetIr (pargin [0]) ; - L->x = mxGetPr (pargin [0]) ; - L->z = mxGetPi (pargin [0]) ; + L->x = mxGetData (pargin [0]) ; + L->z = NULL ; - /* allocate and initialize the rest of L */ + // allocate and initialize the rest of L L->nz = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Lp = L->p ; Lnz = L->nz ; for (j = 0 ; j < n ; j++) { - Lnz [j] = Lp [j+1] - Lp [j] ; + Lnz [j] = Lp [j+1] - Lp [j] ; } - /* these pointers are not accessed in cholmod_solve2 */ + // these pointers are not accessed in cholmod_solve2 L->prev = cholmod_l_malloc (n+2, sizeof (int64_t), cm) ; L->next = cholmod_l_malloc (n+2, sizeof (int64_t), cm) ; Lprev = L->prev ; @@ -165,15 +167,15 @@ void mexFunction Lprev [tail] = n-1 ; for (j = 0 ; j < n ; j++) { - Lnext [j] = j+1 ; - Lprev [j] = j-1 ; + Lnext [j] = j+1 ; + Lprev [j] = j-1 ; } Lprev [0] = head ; - L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; + L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; L->nzmax = Lp [n] ; - /* get the permutation */ + // get the permutation if (mxIsEmpty (pargin [2])) { L->Perm = NULL ; @@ -181,25 +183,23 @@ void mexFunction } else { + // convert from double to int64_t, and from 1-based to 0-based L->ordering = CHOLMOD_GIVEN ; L->Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Perm = L->Perm ; - Px = mxGetPr (pargin [2]) ; + Px = (double *) mxGetData (pargin [2]) ; for (k = 0 ; k < n ; k++) { Perm [k] = ((int64_t) Px [k]) - 1 ; } } - /* set the kind, LL' or LDL' */ + // set the kind, LL' or LDL' L->is_ll = (kind == 0) ; - /* - cholmod_l_print_factor (L, "L", cm) ; - */ - /* ---------------------------------------------------------------------- */ - /* solve the system */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve the system + //-------------------------------------------------------------------------- X = cholmod_l_zeros (n, 1, L->xtype, cm) ; Xset = NULL ; @@ -211,34 +211,56 @@ void mexFunction cholmod_l_free_dense (&Y, cm) ; cholmod_l_free_dense (&E, cm) ; - /* ---------------------------------------------------------------------- */ - /* return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_dense (&X, cm) ; + pargout [0] = sputil2_put_dense (&X, mxDOUBLE_CLASS, cm) ; - /* fill numerical values of Xset with one's */ - Xsetp = Xset->p ; - xsetlen = Xsetp [1] ; - Xset->x = cholmod_l_malloc (xsetlen, sizeof (double), cm) ; - Xsetx = Xset->x ; - for (k = 0 ; k < xsetlen ; k++) + // fill numerical values of Xset with one's + if (Xset == NULL) { - Xsetx [k] = 1 ; + // Px=b and P'x=b do not return Xset. Create Xset = 0:n-1 + Xset = cholmod_l_spzeros (n, 1, n, CHOLMOD_REAL, cm) ; + int64_t *Xsetp = Xset->p ; + int64_t *Xseti = Xset->i ; + double *Xsetx = Xset->x ; + Xsetp [0] = 0 ; + Xsetp [1] = n ; + for (k = 0 ; k < n ; k++) + { + Xseti [k] = k ; + Xsetx [k] = 1 ; + } + } + else + { + // Xset is returned, but needs to be converted from PATTERN to REAL + int64_t *Xsetp = Xset->p ; + xsetlen = Xsetp [1] ; + Xset->x = cholmod_l_malloc (xsetlen, sizeof (double), cm) ; + double *Xsetx = Xset->x ; + for (k = 0 ; k < xsetlen ; k++) + { + Xsetx [k] = 1 ; + } + Xset->xtype = CHOLMOD_REAL ; } - Xset->xtype = CHOLMOD_REAL ; - pargout [1] = sputil_put_sparse (&Xset, cm) ; + pargout [1] = sputil2_put_sparse (&Xset, mxDOUBLE_CLASS, + /* Xset is binary so it has no zeros to drop */ false, cm) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; cholmod_l_free_factor (&L, cm) ; + sputil2_free_sparse (&Bset, &Bmatrix, Bset_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/lxbpattern.c b/CHOLMOD/MATLAB/lxbpattern.c index e02eb968c0..0d94992012 100644 --- a/CHOLMOD/MATLAB/lxbpattern.c +++ b/CHOLMOD/MATLAB/lxbpattern.c @@ -2,27 +2,26 @@ // CHOLMOD/MATLAB/lxbpattern: MATLAB interface for CHOLMOD symbolic x=L\b solve //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Find the nonzero pattern of x=L\b for a sparse vector b. If numerical - * cancellation has caused entries to drop in L, then this function may - * give an incorrect result. - * - * xpattern = lxbpattern (L,b), same as xpattern = find (L\b), - * assuming no numerical cancellation, except that xpattern will not - * appear in sorted ordering (it appears in topological ordering). - * - * The core cholmod_lsolve_pattern function takes O(length (xpattern)) time, - * except that the initialzations in this mexFunction interface add O(n) time. - * - * This function is for testing cholmod_lsolve_pattern only. - */ - -#include "cholmod_matlab.h" +// Find the nonzero pattern of x=L\b for a sparse vector b. If numerical +// cancellation has caused entries to drop in L, then this function may +// give an incorrect result. +// +// xpattern = lxbpattern (L,b), same as xpattern = find (L\b), +// assuming no numerical cancellation, except that xpattern will not +// appear in sorted ordering (it appears in topological ordering). +// +// The core cholmod_lsolve_pattern function takes O(length (xpattern)) time, +// except that the initialzations in this mexFunction interface add O(n) time. +// +// This function is for testing cholmod_lsolve_pattern only. + +#include "sputil2.h" void mexFunction ( @@ -39,109 +38,113 @@ void mexFunction cholmod_common Common, *cm ; int64_t j, n ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargin != 2 || nargout > 1) { - mexErrMsgTxt ("usage: xpattern = lxbpattern (L,b)") ; + mexErrMsgTxt ("usage: xpattern = lxbpattern (L,b)") ; } n = mxGetN (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("lxbpattern: L must be sparse and square") ; + mexErrMsgTxt ("lxbpattern: L must be sparse and square") ; } if (n != mxGetM (pargin [1]) || mxGetN (pargin [1]) != 1) { - mexErrMsgTxt ("lxbpattern: b wrong dimension") ; + mexErrMsgTxt ("lxbpattern: b wrong dimension") ; } if (!mxIsSparse (pargin [1])) { - mexErrMsgTxt ("lxbpattern: b must be sparse") ; + mexErrMsgTxt ("lxbpattern: b must be sparse") ; } - /* ---------------------------------------------------------------------- */ - /* get the sparse b */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the sparse b + //-------------------------------------------------------------------------- - /* get sparse matrix B (unsymmetric) */ - B = sputil_get_sparse (pargin [1], &Bmatrix, &dummy, 0) ; + // get sparse matrix B (unsymmetric) + size_t B_xsize = 0 ; + B = sputil2_get_sparse (pargin [1], 0, CHOLMOD_DOUBLE, &Bmatrix, + &B_xsize, cm) ; - /* ---------------------------------------------------------------------- */ - /* construct a shallow copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct a shallow copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* the construction of the CHOLMOD takes O(n) time and memory */ + // the construction of the CHOLMOD takes O(n) time and memory - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; - /* get the MATLAB L */ + // get the MATLAB L L->p = mxGetJc (pargin [0]) ; L->i = mxGetIr (pargin [0]) ; - L->x = mxGetPr (pargin [0]) ; - L->z = mxGetPi (pargin [0]) ; + L->x = mxGetData (pargin [0]) ; + L->z = NULL ; - /* allocate and initialize the rest of L */ + // allocate and initialize the rest of L L->nz = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Lp = L->p ; Lnz = L->nz ; for (j = 0 ; j < n ; j++) { - Lnz [j] = Lp [j+1] - Lp [j] ; + Lnz [j] = Lp [j+1] - Lp [j] ; } - /* L is not truly a valid CHOLMOD sparse factor, since L->prev and next are - NULL. But these pointers are not accessed in cholmod_lsolve_pattern */ + // L is not truly a valid CHOLMOD sparse factor, since L->prev and next are + // NULL. But these pointers are not accessed in cholmod_lsolve_pattern L->prev = NULL ; L->next = NULL ; - L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL ; + L->xtype = (mxIsComplex (pargin [0])) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; L->nzmax = Lp [n] ; - /* ---------------------------------------------------------------------- */ - /* allocate size-n space for the result X */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate size-n space for the result X + //-------------------------------------------------------------------------- X = cholmod_l_allocate_sparse (n, 1, n, FALSE, TRUE, 0, 0, cm) ; - /* ---------------------------------------------------------------------- */ - /* find the pattern of X=L\B */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the pattern of X=L\B + //-------------------------------------------------------------------------- cholmod_l_lsolve_pattern (B, L, X, cm) ; - /* ---------------------------------------------------------------------- */ - /* return result, converting to 1-based */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return result, converting to 1-based + //-------------------------------------------------------------------------- Xp = (int64_t *) X->p ; Xi = (int64_t *) X->i ; xnz = Xp [1] ; - pargout [0] = sputil_put_int (Xi, xnz, 1) ; + pargout [0] = sputil2_put_int (Xi, xnz, 1) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; + sputil2_free_sparse (&B, &Bmatrix, B_xsize, cm) ; cholmod_l_free_factor (&L, cm) ; cholmod_l_free_sparse (&X, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/metis.c b/CHOLMOD/MATLAB/metis.c index 692b50c827..6640952330 100644 --- a/CHOLMOD/MATLAB/metis.c +++ b/CHOLMOD/MATLAB/metis.c @@ -2,29 +2,25 @@ // CHOLMOD/MATLAB/metis: MATLAB interface to CHOLMOD nested dissection via METIS //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ - -// MATLAB(tm) is a Trademark of The MathWorks, Inc. -// METIS is Copyrighted by G. Karypis - -/* Nested dissection using METIS_NodeND - * - * Usage: - * - * p = metis (A) orders A, using just tril(A) - * p = metis (A,'sym') orders A, using just tril(A) - * p = metis (A,'row') orders A*A' - * p = metis (A,'col') orders A'*A - * - * METIS_NodeND's ordering is followed by CHOLMOD's etree or column etree - * postordering. Requires METIS and the CHOLMOD Partition Module. - */ - -#include "cholmod_matlab.h" + +// Nested dissection using METIS_NodeND +// +// Usage: +// +// p = metis (A) orders A, using just tril(A) +// p = metis (A,'sym') orders A, using just tril(A) +// p = metis (A,'row') orders A*A' +// p = metis (A,'col') orders A'*A +// +// METIS_NodeND's ordering is followed by CHOLMOD's etree or column etree +// postordering. Requires METIS and the CHOLMOD Partition Module. + +#include "sputil2.h" void mexFunction ( @@ -37,129 +33,114 @@ void mexFunction #ifndef NPARTITION double dummy = 0 ; int64_t *Perm ; - cholmod_sparse *A, Amatrix, *C, *S ; + cholmod_sparse *A, Amatrix ; cholmod_common Common, *cm ; int64_t n, transpose, c, postorder ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin < 1 || nargin > 3) { - mexErrMsgTxt ("Usage: p = metis (A, mode)") ; + mexErrMsgTxt ("Usage: p = metis (A, mode)") ; } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use tril(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use tril(A) + //-------------------------------------------------------------------------- A->stype = -1 ; transpose = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0] ; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - transpose = FALSE ; - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - transpose = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric case (A) if string starts with 's' */ - transpose = FALSE ; - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("metis: p=metis(A,mode) ; unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0] ; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + transpose = FALSE ; + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + transpose = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric case (A) if string starts with 's' + transpose = FALSE ; + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("metis: p=metis(A,mode) ; unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("metis: A must be square") ; + mexErrMsgTxt ("metis: A must be square") ; } - C = NULL ; + //-------------------------------------------------------------------------- + // ordering A, AA', or A'A with METIS + //-------------------------------------------------------------------------- + + postorder = (nargin < 3) ; + int ok ; + if (transpose) { - /* C = A', and then order C*C' with METIS */ - C = cholmod_l_transpose (A, 0, cm) ; - if (C == NULL) - { - mexErrMsgTxt ("metis failed") ; - } - A = C ; + // C = A', and then order C*C' with METIS + cholmod_sparse *C = cholmod_l_transpose (A, 0, cm) ; + n = C->nrow ; + Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ok = cholmod_l_metis (C, NULL, 0, postorder, Perm, cm) ; + cholmod_l_free_sparse (&C, cm) ; } - - n = A->nrow ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - - /* ---------------------------------------------------------------------- */ - /* order the matrix with CHOLMOD's interface to METIS_NodeND */ - /* ---------------------------------------------------------------------- */ - - postorder = (nargin < 3) ; - if (!cholmod_l_metis (A, NULL, 0, postorder, Perm, cm)) + else { - mexErrMsgTxt ("metis failed") ; - return ; + // order A or A*A' with METIS + n = A->nrow ; + Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ok = cholmod_l_metis (A, NULL, 0, postorder, Perm, cm) ; } - /* ---------------------------------------------------------------------- */ - /* return Perm */ - /* ---------------------------------------------------------------------- */ - - pargout [0] = sputil_put_int (Perm, n, 1) ; - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and return results + //-------------------------------------------------------------------------- + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; + if (!ok) mexErrMsgTxt ("metis failed") ; + pargout [0] = sputil2_put_int (Perm, n, 1) ; cholmod_l_free (n, sizeof (int64_t), Perm, cm) ; - cholmod_l_free_sparse (&C, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; #else mexErrMsgTxt ("METIS and the CHOLMOD Partition Module not installed\n") ; #endif } + diff --git a/CHOLMOD/MATLAB/metis.m b/CHOLMOD/MATLAB/metis.m index 535994b068..2a16711bcb 100644 --- a/CHOLMOD/MATLAB/metis.m +++ b/CHOLMOD/MATLAB/metis.m @@ -1,23 +1,24 @@ -function p = metis (A, mode) %#ok -%METIS nested dissection ordering via METIS_NodeND. +function p = metis (A, mode) %#ok +%METIS nested dissection ordering via METIS_NodeND % -% Example: -% p = metis(A) returns p such chol(A(p,p)) is typically sparser than -% chol(A). Uses tril(A) and assumes A is symmetric. +% Example: +% p = metis(A) returns p such chol(A(p,p)) is typically sparser +% than chol(A). Uses tril(A) and assumes A is +% symmetric. % p = metis(A,'sym') the same as p=metis(A). -% p = metis(A,'col') returns p so that chol(A(:,p)'*A(:,p)) is typically -% sparser than chol(A'*A). -% p = metis(A,'row') returns p so that chol(A(p,:)*A(p,:)') is typically -% sparser than chol(A'*A). +% p = metis(A,'col') returns p so that chol(A(:,p)'*A(:,p)) is +% typically sparser than chol(A'*A). +% p = metis(A,'row') returns p so that chol(A(p,:)*A(p,:)') is +% typically sparser than chol(A'*A). % -% A must be square for p=metis(A) or metis(A,'sym') +% A must be square for p=metis(A) or metis(A,'sym') % -% Requires METIS, authored by George Karypis, Univ. of Minnesota. This -% MATLAB interface, via CHOLMOD, is by Tim Davis. +% Requires METIS, authored by George Karypis, Univ. of Minnesota. This +% MATLAB interface, via CHOLMOD, is by Tim Davis. % -% See also NESDIS, BISECT +% See also nesdis, bisect. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('metis mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/mread.c b/CHOLMOD/MATLAB/mread.c index e0cb677d59..271b0b99af 100644 --- a/CHOLMOD/MATLAB/mread.c +++ b/CHOLMOD/MATLAB/mread.c @@ -2,37 +2,36 @@ // CHOLMOD/MATLAB/mread: read a matrix in Matrix Market format //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* [A Z] = mread (filename, prefer_binary) - * - * Read a sparse or dense matrix from a file in Matrix Market format. - * - * All MatrixMarket formats are supported. - * The Matrix Market "integer" format is converted into real, but the values - * are preserved. The "pattern" format is converted into real. If a pattern - * matrix is unsymmetric, all of its values are equal to one. If a pattern is - * symmetric, the kth diagonal entry is set to one plus the number of - * off-diagonal nonzeros in row/column k, and off-diagonal entries are set to - * -1. - * - * Explicit zero entries are returned as the binary pattern of the matrix Z. - */ - -#include "cholmod_matlab.h" - -/* maximum file length */ +// [A Z] = mread (filename, prefer_binary) +// +// Read a sparse or dense matrix from a file in Matrix Market format. +// +// All MatrixMarket formats are supported. +// The Matrix Market "integer" format is converted into real, but the values +// are preserved. The "pattern" format is converted into real. If a pattern +// matrix is unsymmetric, all of its values are equal to one. If a pattern is +// symmetric, the kth diagonal entry is set to one plus the number of +// off-diagonal nonzeros in row/column k, and off-diagonal entries are set to +// -1. +// +// Explicit zero entries are returned as the binary pattern of the matrix Z. + +#include "sputil2.h" + +// maximum file length #define MAXLEN 1030 void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -43,174 +42,166 @@ void mexFunction int64_t *Ap = NULL, *Ai ; double *Ax, *Az = NULL ; char filename [MAXLEN] ; - int64_t nz, k, is_complex = FALSE, nrow = 0, ncol = 0, allzero ; + int64_t nz, k, is_complex = FALSE, nrow = 0, ncol = 0 ; int mtype ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargin < 1 || nargin > 2 || nargout > 2) { - mexErrMsgTxt ("usage: [A Z] = mread (filename, prefer_binary)") ; + mexErrMsgTxt ("usage: [A Z] = mread (filename, prefer_binary)") ; } if (!mxIsChar (pargin [0])) { - mexErrMsgTxt ("mread requires a filename") ; + mexErrMsgTxt ("mread requires a filename") ; } mxGetString (pargin [0], filename, MAXLEN) ; - sputil_file = fopen (filename, "r") ; - if (sputil_file == NULL) + sputil2_file = fopen (filename, "r") ; + if (sputil2_file == NULL) { - mexErrMsgTxt ("cannot open file") ; + mexErrMsgTxt ("cannot open file") ; } if (nargin > 1) { - cm->prefer_binary = (mxGetScalar (pargin [1]) != 0) ; + cm->prefer_binary = (mxGetScalar (pargin [1]) != 0) ; } - /* ---------------------------------------------------------------------- */ - /* read the matrix, as either a dense or sparse matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // read the matrix, as either a dense or sparse matrix + //-------------------------------------------------------------------------- - G = cholmod_l_read_matrix (sputil_file, 1, &mtype, cm) ; - fclose (sputil_file) ; - sputil_file = NULL ; + G = cholmod_l_read_matrix (sputil2_file, 1, &mtype, cm) ; + fclose (sputil2_file) ; + sputil2_file = NULL ; if (G == NULL) { - mexErrMsgTxt ("could not read file") ; + mexErrMsgTxt ("could not read file") ; } - /* get the specific matrix (A or X), and change to zomplex if needed */ + // get the specific matrix (A or X), and change to complex if needed if (mtype == CHOLMOD_SPARSE) { - A = (cholmod_sparse *) G ; - nrow = A->nrow ; - ncol = A->ncol ; - is_complex = (A->xtype == CHOLMOD_COMPLEX) ; - Ap = A->p ; - Ai = A->i ; - if (is_complex) - { - /* if complex, ensure A is zomplex */ - cholmod_l_sparse_xtype (CHOLMOD_ZOMPLEX, A, cm) ; - } - Ax = A->x ; - Az = A->z ; + A = (cholmod_sparse *) G ; + nrow = A->nrow ; + ncol = A->ncol ; + Ap = A->p ; + Ai = A->i ; + if (A->xtype == CHOLMOD_ZOMPLEX) + { + // if complex, ensure A is complex, not zomplex + cholmod_l_sparse_xtype (CHOLMOD_COMPLEX, A, cm) ; + } + is_complex = (A->xtype == CHOLMOD_COMPLEX) ; + Ax = A->x ; } else if (mtype == CHOLMOD_DENSE) { - X = (cholmod_dense *) G ; - nrow = X->nrow ; - ncol = X->ncol ; - is_complex = (X->xtype == CHOLMOD_COMPLEX) ; - if (is_complex) - { - /* if complex, ensure X is zomplex */ - cholmod_l_dense_xtype (CHOLMOD_ZOMPLEX, X, cm) ; - } - Ax = X->x ; - Az = X->z ; + X = (cholmod_dense *) G ; + nrow = X->nrow ; + ncol = X->ncol ; + if (X->xtype == CHOLMOD_ZOMPLEX) + { + // if complex, ensure X is complex, not zomplex + cholmod_l_dense_xtype (CHOLMOD_COMPLEX, X, cm) ; + } + is_complex = (X->xtype == CHOLMOD_COMPLEX) ; + Ax = X->x ; } else { - mexErrMsgTxt ("invalid file") ; + mexErrMsgTxt ("invalid file") ; } - /* ---------------------------------------------------------------------- */ - /* if requested, extract the zero entries and place them in Z */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // if requested, extract the zero entries and place them in Z + //-------------------------------------------------------------------------- if (nargout > 1) { - if (mtype == CHOLMOD_SPARSE) - { - /* A is a sparse real/zomplex double matrix */ - Z = sputil_extract_zeros (A, cm) ; - } - else - { - /* input is full; just return an empty Z matrix */ - Z = cholmod_l_spzeros (nrow, ncol, 0, CHOLMOD_REAL, cm) ; - } + if (mtype == CHOLMOD_SPARSE) + { + // A is a sparse real/zomplex double matrix + Z = sputil2_extract_zeros (A, cm) ; + } + else + { + // input is full; just return an empty Z matrix + Z = cholmod_l_spzeros (nrow, ncol, 0, CHOLMOD_REAL, cm) ; + } } - /* ---------------------------------------------------------------------- */ - /* prune the zero entries from A and set nzmax(A) to nnz(A) */ - /* ---------------------------------------------------------------------- */ - - if (mtype == CHOLMOD_SPARSE) - { - sputil_drop_zeros (A) ; - cholmod_l_reallocate_sparse (cholmod_l_nnz (A, cm), A, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* change a complex matrix to real if its imaginary part is all zero */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // change a complex matrix to real if its imaginary part is all zero + //-------------------------------------------------------------------------- if (is_complex) { - if (mtype == CHOLMOD_SPARSE) - { - nz = Ap [ncol] ; - } - else - { - nz = nrow * ncol ; - } - allzero = TRUE ; - for (k = 0 ; k < nz ; k++) - { - if (Az [k] != 0) - { - allzero = FALSE ; - break ; - } - } - if (allzero) - { - /* discard the all-zero imaginary part */ - if (mtype == CHOLMOD_SPARSE) - { - cholmod_l_sparse_xtype (CHOLMOD_REAL, A, cm) ; - } - else - { - cholmod_l_dense_xtype (CHOLMOD_REAL, X, cm) ; - } - } + if (mtype == CHOLMOD_SPARSE) + { + nz = Ap [ncol] ; + } + else + { + nz = nrow * ncol ; + } + bool allzero = true ; + for (k = 0 ; k < nz ; k++) + { + if (Ax [2*k+1] != 0) + { + allzero = false ; + break ; + } + } + if (allzero) + { + // discard the all-zero imaginary part + if (mtype == CHOLMOD_SPARSE) + { + cholmod_l_sparse_xtype (CHOLMOD_REAL, A, cm) ; + } + else + { + cholmod_l_dense_xtype (CHOLMOD_REAL, X, cm) ; + } + } } - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results to MATLAB + //-------------------------------------------------------------------------- if (mtype == CHOLMOD_SPARSE) { - pargout [0] = sputil_put_sparse (&A, cm) ; + // drop explicit zeros from A; their pattern is kept in Z + pargout [0] = sputil2_put_sparse (&A, mxDOUBLE_CLASS, + /* drop explicit zeros */ true, cm) ; } else { - pargout [0] = sputil_put_dense (&X, cm) ; + pargout [0] = sputil2_put_dense (&X, mxDOUBLE_CLASS, cm) ; } if (nargout > 1) { - pargout [1] = sputil_put_sparse (&Z, cm) ; + pargout [1] = sputil2_put_sparse (&Z, mxDOUBLE_CLASS, + /* Z is binary so it has no zeros to drop */ false, cm) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/mread.m b/CHOLMOD/MATLAB/mread.m index 6fe13b3346..6c4f3218ad 100644 --- a/CHOLMOD/MATLAB/mread.m +++ b/CHOLMOD/MATLAB/mread.m @@ -1,24 +1,26 @@ -function [A, Z] = mread (filename,prefer_binary) %#ok -%MREAD read a sparse matrix from a file in Matrix Market format. +function [A, Z] = mread (filename,prefer_binary) %#ok +%MREAD read a sparse matrix from a file in Matrix Market format % -% Example: +% Example: % A = mread (filename) % [A Z] = mread (filename, prefer_binary) % -% Unlike MMREAD, only the matrix is returned; the file format is not -% returned. Explicit zero entries can be present in the file; these are not -% included in A. They appear as the nonzero pattern of the binary matrix Z. +% Unlike MMREAD, only the matrix is returned; the file format is not +% returned. Explicit zero entries can be present in the file; these are +% not included in A. They appear as the nonzero pattern of the binary +% matrix Z. % -% If prefer_binary is not present, or zero, a symmetric pattern-only matrix -% is returned with A(i,i) = 1+length(find(A(:,i))) if it is present in the -% pattern, and A(i,j) = -1 for off-diagonal entries. If you want the original -% Matrix Market matrix in this case, simply use A = mread (filename,1). +% If prefer_binary is not present, or zero, a symmetric pattern-only +% matrix is returned with A(i,i) = 1+length(find(A(:,i))) if it is +% present in the pattern, and A(i,j) = -1 for off-diagonal entries. If +% you want the original Matrix Market matrix in this case, simply use +% A=mread(filename,1). % -% Compare with mmread.m at http://math.nist.gov/MatrixMarket +% Compare with mmread.m at http://math.nist.gov/MatrixMarket % -% See also load +% See also load. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('mread mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/mwrite.c b/CHOLMOD/MATLAB/mwrite.c index c8b52b3356..86256f26e8 100644 --- a/CHOLMOD/MATLAB/mwrite.c +++ b/CHOLMOD/MATLAB/mwrite.c @@ -2,37 +2,32 @@ // CHOLMOD/MATLAB/mwrite: write a matrix in Matrix Market format //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Write a matrix to a file in Matrix Market form. - * - * symmetry = mwrite (filename, A, Z, comments_filename) - * - * A can be sparse or full. - * - * If present and non-empty, A and Z must have the same dimension. Z contains - * the explicit zero entries in the matrix (which MATLAB drops). The entries - * of Z appear as explicit zeros in the output file. Z is optional. If it is - * an empty matrix it is ignored. Z must be sparse or empty, if present. - * It is ignored if A is full. - * - * filename is the name of the output file. comments_file is file whose - * contents are include after the Matrix Market header and before the first - * data line. Ignored if an empty string or not present. - */ - -#include "cholmod_matlab.h" +// Write a matrix to a file in Matrix Market form. +// +// symmetry = mwrite (filename, A, Z, comments_filename) +// +// A can be sparse or full. +// +// If present and non-empty, A and Z must have the same dimension. Z contains +// the explicit zero entries in the matrix (which MATLAB drops). The entries +// of Z appear as explicit zeros in the output file. Z is optional. If it is +// an empty matrix it is ignored. Z must be sparse or empty, if present. +// It is ignored if A is full. +// +// filename is the name of the output file. comments_file is file whose +// contents are include after the Matrix Market header and before the first +// data line. Ignored if an empty string or not present. + +#include "sputil2.h" #define MAXLEN 1030 -/* -------------------------------------------------------------------------- */ -/* mwrite mexFunction */ -/* -------------------------------------------------------------------------- */ - void mexFunction ( int nargout, @@ -48,142 +43,154 @@ void mexFunction int64_t arg_z, arg_comments, sym ; char filename [MAXLEN], comments [MAXLEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargin < 2 || nargin > 4 || nargout > 1) { - mexErrMsgTxt ("Usage: mwrite (filename, A, Z, comments_filename)") ; + mexErrMsgTxt ("Usage: mwrite (filename, A, Z, comments_filename)") ; } - /* ---------------------------------------------------------------------- */ - /* get the output filename */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the output filename + //-------------------------------------------------------------------------- if (!mxIsChar (pargin [0])) { - mexErrMsgTxt ("first parameter must be a filename") ; + mexErrMsgTxt ("first parameter must be a filename") ; } mxGetString (pargin [0], filename, MAXLEN) ; - /* ---------------------------------------------------------------------- */ - /* get the A matrix (sparse or dense) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the A matrix (sparse or dense) + //-------------------------------------------------------------------------- + + size_t A_xsize = 0 ; + size_t X_xsize = 0 ; if (mxIsSparse (pargin [1])) { - A = sputil_get_sparse (pargin [1], &Amatrix, &dummy, 0) ; - X = NULL ; + A = sputil2_get_sparse (pargin [1], 0, CHOLMOD_DOUBLE, &Amatrix, + &A_xsize, cm) ; + X = NULL ; } else { - X = sputil_get_dense (pargin [1], &Xmatrix, &dummy) ; - A = NULL ; + X = sputil2_get_dense (pargin [1], CHOLMOD_DOUBLE, &Xmatrix, + &X_xsize, cm) ; + A = NULL ; } - /* ---------------------------------------------------------------------- */ - /* determine if the Z matrix and comments_file are present */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine if the Z matrix and comments_file are present + //-------------------------------------------------------------------------- if (nargin == 3) { - if (mxIsChar (pargin [2])) - { - /* mwrite (file, A, comments) */ - arg_z = -1 ; - arg_comments = 2 ; - } - else - { - /* mwrite (file, A, Z). Ignore Z if A is full */ - arg_z = (A == NULL) ? -1 : 2 ; - arg_comments = -1 ; - } + if (mxIsChar (pargin [2])) + { + // mwrite (file, A, comments) + arg_z = -1 ; + arg_comments = 2 ; + } + else + { + // mwrite (file, A, Z). Ignore Z if A is full + arg_z = (A == NULL) ? -1 : 2 ; + arg_comments = -1 ; + } } else if (nargin == 4) { - /* mwrite (file, A, Z, comments). Ignore Z is A is full */ - arg_z = (A == NULL) ? -1 : 2 ; - arg_comments = 3 ; + // mwrite (file, A, Z, comments). Ignore Z is A is full + arg_z = (A == NULL) ? -1 : 2 ; + arg_comments = 3 ; } else { - arg_z = -1 ; - arg_comments = -1 ; + arg_z = -1 ; + arg_comments = -1 ; } - /* ---------------------------------------------------------------------- */ - /* get the Z matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the Z matrix + //-------------------------------------------------------------------------- + size_t Z_xsize = 0 ; if (arg_z == -1 || - mxGetM (pargin [arg_z]) == 0 || mxGetN (pargin [arg_z]) == 0) + mxGetM (pargin [arg_z]) == 0 || mxGetN (pargin [arg_z]) == 0) { - /* A is dense, Z is not present, or Z is empty. Ignore Z. */ - Z = NULL ; + // A is dense, Z is not present, or Z is empty. Ignore Z. + Z = NULL ; } else { - /* A is sparse and Z is present and not empty */ - if (!mxIsSparse (pargin [arg_z])) - { - mexErrMsgTxt ("Z must be sparse") ; - } - Z = sputil_get_sparse (pargin [arg_z], &Zmatrix, &dummy, 0) ; + // A is sparse and Z is present and not empty + if (!mxIsSparse (pargin [arg_z])) + { + mexErrMsgTxt ("Z must be sparse") ; + } + Z = sputil2_get_sparse (pargin [arg_z], 0, CHOLMOD_DOUBLE, &Zmatrix, + &Z_xsize, cm) ; } - /* ---------------------------------------------------------------------- */ - /* get the comments filename */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the comments filename + //-------------------------------------------------------------------------- comments [0] = '\0' ; if (arg_comments != -1) { - if (!mxIsChar (pargin [arg_comments])) - { - mexErrMsgTxt ("comments filename must be a string") ; - } - mxGetString (pargin [arg_comments], comments, MAXLEN) ; + if (!mxIsChar (pargin [arg_comments])) + { + mexErrMsgTxt ("comments filename must be a string") ; + } + mxGetString (pargin [arg_comments], comments, MAXLEN) ; } - /* ---------------------------------------------------------------------- */ - /* write the matrix to the file */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // write the matrix to the file + //-------------------------------------------------------------------------- - sputil_file = fopen (filename, "w") ; - if (sputil_file == NULL) + sputil2_file = fopen (filename, "w") ; + if (sputil2_file == NULL) { - mexErrMsgTxt ("error opening file") ; + mexErrMsgTxt ("error opening file") ; } if (A != NULL) { - sym = cholmod_l_write_sparse (sputil_file, A, Z, comments, cm) ; + sym = cholmod_l_write_sparse (sputil2_file, A, Z, comments, cm) ; } else { - sym = cholmod_l_write_dense (sputil_file, X, comments, cm) ; + sym = cholmod_l_write_dense (sputil2_file, X, comments, cm) ; } - fclose (sputil_file) ; - sputil_file = NULL ; + fclose (sputil2_file) ; + sputil2_file = NULL ; if (sym < 0) { - mexErrMsgTxt ("mwrite failed") ; + mexErrMsgTxt ("mwrite failed") ; } - /* ---------------------------------------------------------------------- */ - /* free workspace and return symmetry */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and return symmetry + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (&sym, 1, 0) ; + + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; + sputil2_free_sparse (&Z, &Zmatrix, Z_xsize, cm) ; + sputil2_free_dense (&X, &Xmatrix, X_xsize, cm) ; + pargout [0] = sputil2_put_int (&sym, 1, 0) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/mwrite.m b/CHOLMOD/MATLAB/mwrite.m index 27a0f04136..1ebe8f241d 100644 --- a/CHOLMOD/MATLAB/mwrite.m +++ b/CHOLMOD/MATLAB/mwrite.m @@ -1,24 +1,24 @@ -function mtype = mwrite (filename, A, Z, comments_filename) %#ok +function mtype = mwrite (filename, A, Z, comments_filename) %#ok %MWRITE write a matrix to a file in Matrix Market form. % -% Example: -% mtype = mwrite (filename, A, Z, comments_filename) +% Example: +% mtype = mwrite (filename, A, Z, comments_filename) % % A can be sparse or full. % -% If present and non-empty, A and Z must have the same dimension. Z contains -% the explicit zero entries in the matrix (which MATLAB drops). The entries -% of Z appear as explicit zeros in the output file. Z is optional. If it is -% an empty matrix it is ignored. Z must be sparse or empty, if present. -% It is ignored if A is full. +% If present and non-empty, A and Z must have the same dimension. Z +% contains the explicit zero entries in the matrix (which MATLAB drops). +% The entries of Z appear as explicit zeros in the output file. Z is +% optional. If it is an empty matrix it is ignored. Z must be sparse or +% empty, if present. It is ignored if A is full. % % filename is the name of the output file. comments_filename is the file -% whose contents are include after the Matrix Market header and before the -% first data line. Ignored if an empty string or not present. +% whose contents are include after the Matrix Market header and before +% the first data line. Ignored if an empty string or not present. % % See also mread. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('mwrite mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/nesdis.c b/CHOLMOD/MATLAB/nesdis.c index ceab769fcf..49c72e1754 100644 --- a/CHOLMOD/MATLAB/nesdis.c +++ b/CHOLMOD/MATLAB/nesdis.c @@ -2,7 +2,7 @@ // CHOLMOD/MATLAB/nesdis: MATLAB interface for CHOLMOD+METIS+CAMD+CCOLAMD //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ @@ -11,46 +11,45 @@ // MATLAB(tm) is a Trademark of The MathWorks, Inc. // METIS is Copyrighted by G. Karypis -/* CHOLMOD's nested dissection, based on METIS_ComputeVertexSeparator, CAMD, and - * CCOLAMD. - * - * Usage: - * - * [p, cp, cmember] = nesdis (A) orders A, using tril(A) - * [p, cp, cmember] = nesdis (A,'sym') orders A, using tril(A) - * [p, cp, cmember] = nesdis (A,'row') orders A*A' - * [p, cp, cmember] = nesdis (A,'col') orders A'*A - * - * Nested dissection ordering. Returns a permutation p such that the Cholesky - * factorization of A(p,p), A(p,:)*A(p,:)', or A(:,p)'*A(:,p) is sparser than - * the unpermuted system. 'mode' defaults to 'sym'. - * - * An optional 3rd input argument: - * - * nesdis (A,mode,opts) - * - * specifies control parameters. opts(1) is the smallest subgraph that should - * not be partitioned (default is 200), opts(2) is 1 if connected components are - * to be split independently (default is 0). opts(3) controls when a separator - * is kept; it is kept if nsep < opts(3)*n, where nsep is the number of nodes in - * the separator and n is the number of nodes in the graph being cut (default is - * 1). - * - * opts(4) is 0 if the smallest subgraphs are not to be ordered. For the 'sym' - * case, or if mode is not present: 1 if to be ordered by CAMD, or 2 if to be - * ordered with CSYMAMD (default is 1). For the other cases: 0 for natural - * ordering, 1 if to be ordered by CCOLAMD. - * - * cp and cmember are optional. cmember(i)=c means that node i is in component - * c, where c is in the range of 1 to the number of components. length(cp) is - * the number of components found. cp is the separator tree; cp(c) is the - * parent of component c, or 0 if c is a root. There can be anywhere from - * 1 to n components, where n is the number of rows of A, A*A', or A'*A. - * - * Requires METIS and the CHOLMOD Partition Module. - */ - -#include "cholmod_matlab.h" +// CHOLMOD's nested dissection, based on METIS_ComputeVertexSeparator, CAMD, and +// CCOLAMD. +// +// Usage: +// +// [p, cp, cmember] = nesdis (A) orders A, using tril(A) +// [p, cp, cmember] = nesdis (A,'sym') orders A, using tril(A) +// [p, cp, cmember] = nesdis (A,'row') orders A*A' +// [p, cp, cmember] = nesdis (A,'col') orders A'*A +// +// Nested dissection ordering. Returns a permutation p such that the Cholesky +// factorization of A(p,p), A(p,:)*A(p,:)', or A(:,p)'*A(:,p) is sparser than +// the unpermuted system. 'mode' defaults to 'sym'. +// +// An optional 3rd input argument: +// +// nesdis (A,mode,opts) +// +// specifies control parameters. opts(1) is the smallest subgraph that should +// not be partitioned (default is 200), opts(2) is 1 if connected components are +// to be split independently (default is 0). opts(3) controls when a separator +// is kept; it is kept if nsep < opts(3)*n, where nsep is the number of nodes in +// the separator and n is the number of nodes in the graph being cut (default is +// 1). +// +// opts(4) is 0 if the smallest subgraphs are not to be ordered. For the 'sym' +// case, or if mode is not present: 1 if to be ordered by CAMD, or 2 if to be +// ordered with CSYMAMD (default is 1). For the other cases: 0 for natural +// ordering, 1 if to be ordered by CCOLAMD. +// +// cp and cmember are optional. cmember(i)=c means that node i is in component +// c, where c is in the range of 1 to the number of components. length(cp) is +// the number of components found. cp is the separator tree; cp(c) is the +// parent of component c, or 0 if c is a root. There can be anywhere from +// 1 to n components, where n is the number of rows of A, A*A', or A'*A. +// +// Requires METIS and the CHOLMOD Partition Module. + +#include "sputil2.h" void mexFunction ( @@ -63,150 +62,136 @@ void mexFunction #ifndef NPARTITION double dummy = 0 ; int64_t *Perm, *Cmember, *CParent ; - cholmod_sparse *A, Amatrix, *C, *S ; + cholmod_sparse *A, Amatrix ; cholmod_common Common, *cm ; int64_t n, transpose, c, ncomp ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 3 || nargin < 1 || nargin > 3) { - mexErrMsgTxt ("Usage: [p cp cmember] = nesdis (A, mode, opts)") ; + mexErrMsgTxt ("Usage: [p cp cmember] = nesdis (A, mode, opts)") ; } if (nargin > 2) { - double *x = mxGetPr (pargin [2]) ; - n = mxGetNumberOfElements (pargin [2]) ; - if (n > 0) cm->method [0].nd_small = x [0] ; - if (n > 1) cm->method [0].nd_components = x [1] ; - if (n > 2) cm->method [0].nd_oksep = x [2] ; - if (n > 3) cm->method [0].nd_camd = x [3] ; + double *x = (double *) mxGetData (pargin [2]) ; + n = mxGetNumberOfElements (pargin [2]) ; + if (n > 0) cm->method [0].nd_small = x [0] ; + if (n > 1) cm->method [0].nd_components = x [1] ; + if (n > 2) cm->method [0].nd_oksep = x [2] ; + if (n > 3) cm->method [0].nd_camd = x [3] ; } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use tril(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use tril(A) + //-------------------------------------------------------------------------- A->stype = -1 ; transpose = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0] ; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - transpose = FALSE ; - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - transpose = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric case (A) if string starts with 's' */ - transpose = FALSE ; - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("nesdis: unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0] ; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + transpose = FALSE ; + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + transpose = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric case (A) if string starts with 's' + transpose = FALSE ; + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("nesdis: unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("nesdis: A must be square") ; + mexErrMsgTxt ("nesdis: A must be square") ; } - C = NULL ; + //-------------------------------------------------------------------------- + // order the matrix with CHOLMOD's nested dissection + //-------------------------------------------------------------------------- + if (transpose) { - /* C = A', and then order C*C' with cholmod_l_nested_dissection */ - C = cholmod_l_transpose (A, 0, cm) ; - if (C == NULL) - { - mexErrMsgTxt ("nesdis failed") ; - } - A = C ; + // C = A', and then order C*C' with cholmod_l_nested_dissection + cholmod_sparse *C = cholmod_l_transpose (A, 0, cm) ; + n = C->nrow ; + CParent = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + Cmember = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ncomp = cholmod_l_nested_dissection (C, NULL, 0, Perm, CParent, + Cmember, cm) ; + cholmod_l_free_sparse (&C, cm) ; } - - n = A->nrow ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - CParent = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - Cmember = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - - /* ---------------------------------------------------------------------- */ - /* order the matrix with CHOLMOD's nested dissection */ - /* ---------------------------------------------------------------------- */ - - ncomp = cholmod_l_nested_dissection (A, NULL, 0, Perm, CParent, Cmember,cm); - if (ncomp < 0) + else { - mexErrMsgTxt ("nesdis failed") ; - return ; + // order A or A*A' with cholmod_l_nested_dissection + n = A->nrow ; + CParent = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + Cmember = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + Perm = cholmod_l_malloc (n, sizeof (int64_t), cm) ; + ncomp = cholmod_l_nested_dissection (A, NULL, 0, Perm, CParent, + Cmember, cm) ; } - /* ---------------------------------------------------------------------- */ - /* return Perm, CParent, and Cmember */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and return results + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (Perm, n, 1) ; + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; + if (ncomp < 0) mexErrMsgTxt ("nesdis failed") ; + pargout [0] = sputil2_put_int (Perm, n, 1) ; if (nargout > 1) { - pargout [1] = sputil_put_int (CParent, ncomp, 1) ; + pargout [1] = sputil2_put_int (CParent, ncomp, 1) ; } if (nargout > 2) { - pargout [2] = sputil_put_int (Cmember, n, 1) ; + pargout [2] = sputil2_put_int (Cmember, n, 1) ; } - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ - cholmod_l_free (n, sizeof (int64_t), Perm, cm) ; cholmod_l_free (n, sizeof (int64_t), CParent, cm) ; cholmod_l_free (n, sizeof (int64_t), Cmember, cm) ; - cholmod_l_free_sparse (&C, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; #else mexErrMsgTxt ("METIS and the CHOLMOD Partition Module not installed\n") ; #endif } + diff --git a/CHOLMOD/MATLAB/nesdis.m b/CHOLMOD/MATLAB/nesdis.m index 229fc90163..f477a89032 100644 --- a/CHOLMOD/MATLAB/nesdis.m +++ b/CHOLMOD/MATLAB/nesdis.m @@ -1,54 +1,57 @@ -function [p, cparent, cmember] = nesdis (A, mode, opts) %#ok +function [p, cparent, cmember] = nesdis (A, mode, opts) %#ok %NESDIS nested dissection ordering via CHOLMOD's nested dissection. % % Example: -% p = nesdis(A) returns p such chol(A(p,p)) is typically sparser than -% chol(A). Uses tril(A) and assumes A is symmetric. +% p = nesdis(A) returns p such chol(A(p,p)) is typically +% sparser than chol(A). Uses tril(A) and assumes +% A is symmetric. % p = nesdis(A,'sym') the same as p=nesdis(A). -% p = nesdis(A,'col') returns p so that chol(A(:,p)'*A(:,p)) is typically -% sparser than chol(A'*A). -% p = nesdis(A,'row') returns p so that chol(A(p,:)*A(p,:)') is typically -% sparser than chol(A'*A). -% -% A must be square for p=nesdis(A) or nesdis(A,'sym'). -% -% With three output arguments, [p cp cmember] = nesdis(...), the separator -% tree and node-to-component mapping is returned. cmember(i)=c means that -% node i is in component c, where c is in the range of 1 to the number of -% components. length(cp) is the number of components found. cp is the -% separator tree; cp(c) is the parent of component c, or 0 if c is a root. -% There can be anywhere from 1 to n components, where n is dimension of A, -% A*A', or A'*A. cmember is a vector of length n. -% -% An optional 3rd input argument, nesdis (A,mode,opts), modifies the default -% parameters. opts(1) specifies the smallest subgraph that should not be -% partitioned (default is 200). opts(2) is 0 by default; if nonzero, -% connected components (formed after the node separator is removed) are -% partitioned independently. The default value tends to lead to a more -% balanced separator tree, cp. opts(3) defines when a separator is kept; it -% is kept if the separator size is < opts(3) times the number of nodes in the -% graph being cut (valid range is 0 to 1, default is 1). -% -% opts(4) specifies graph is to be ordered after it is dissected. For the -% 'sym' case: 0: natural ordering, 1: CAMD, 2: CSYMAMD. For other cases: -% 0: natural ordering, nonzero: CCOLAMD. The default is 1, to use CAMD for -% the symmetric case and CCOLAMD for the other cases. -% -% If opts is shorter than length 4, defaults are used for entries -% that are not present. -% -% NESDIS uses METIS' node separator algorithm to recursively partition the -% graph. This gives a set of constraints (cmember) that is then passed to -% CCOLAMD, CSYMAMD, or CAMD, constrained minimum degree ordering algorithms. -% NESDIS typically takes slightly more time than METIS (METIS_NodeND), but -% tends to produce better orderings. -% -% Requires METIS, authored by George Karypis, Univ. of Minnesota. This -% MATLAB interface, via CHOLMOD, is by Tim Davis. -% -% See also METIS, BISECT, AMD +% p = nesdis(A,'col') returns p so that chol(A(:,p)'*A(:,p)) is +% typically sparser than chol(A'*A). +% p = nesdis(A,'row') returns p so that chol(A(p,:)*A(p,:)') is +% typically sparser than chol(A'*A). +% +% A must be square for p=nesdis(A) or nesdis(A,'sym'). +% +% With three output arguments, [p cp cmember] = nesdis(...), the +% separator tree and node-to-component mapping is returned. cmember(i)=c +% means that node i is in component c, where c is in the range of 1 to +% the number of components. length(cp) is the number of components +% found. cp is the separator tree; cp(c) is the parent of component c, +% or 0 if c is a root. There can be anywhere from 1 to n components, +% where n is dimension of A, A*A', or A'*A. cmember is a vector of +% length n. +% +% An optional 3rd input argument, nesdis (A,mode,opts), modifies the +% default parameters. opts(1) specifies the smallest subgraph that +% should not be partitioned (default is 200). opts(2) is 0 by default; +% if nonzero, connected components (formed after the node separator is +% removed) are partitioned independently. The default value tends to +% lead to a more balanced separator tree, cp. opts(3) defines when a +% separator is kept; it is kept if the separator size is < opts(3) times +% the number of nodes in the graph being cut (valid range is 0 to 1, +% default is 1). +% +% opts(4) specifies graph is to be ordered after it is dissected. For +% the 'sym' case: 0: natural ordering, 1: CAMD, 2: CSYMAMD. For other +% cases: 0: natural ordering, nonzero: CCOLAMD. The default is 1, to use +% CAMD for the symmetric case and CCOLAMD for the other cases. +% +% If opts is shorter than length 4, defaults are used for entries that +% are not present. +% +% NESDIS uses METIS' node separator algorithm to recursively partition +% the graph. This gives a set of constraints (cmember) that is then +% passed to CCOLAMD, CSYMAMD, or CAMD, constrained minimum degree +% ordering algorithms. NESDIS typically takes slightly more time than +% METIS (METIS_NodeND), but tends to produce better orderings. +% +% Requires METIS, authored by George Karypis, Univ. of Minnesota. This +% MATLAB interface, via CHOLMOD, is by Tim Davis. +% +% See also metis, bisect, amd. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('nesdis mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/resymbol.c b/CHOLMOD/MATLAB/resymbol.c index 8fe2e1f95b..046e421ea7 100644 --- a/CHOLMOD/MATLAB/resymbol.c +++ b/CHOLMOD/MATLAB/resymbol.c @@ -2,25 +2,22 @@ // CHOLMOD/MATLAB/resymbol: MATLAB interface for CHOLMOD symbolic re-analysis //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Usage: - * L = resymbol (L, A) - * - * Recompute the symbolic Cholesky factorization of the matrix A. A must be - * symmetric. Only tril(A) is used. Entries in L that are not in the Cholesky - * factorization of A are removed from L. L can be from an LL' or LDL' - * factorization. The numerical values of A are ignored; only its nonzero - * pattern is used. - */ +// Usage: +// L = resymbol (L, A) +// +// Recompute the symbolic Cholesky factorization of the matrix A. A must be +// symmetric. Only tril(A) is used. Entries in L that are not in the Cholesky +// factorization of A are removed from L. L can be from an LL' or LDL' +// factorization. The numerical values of A are ignored; only its nonzero +// pattern is used. -/* ========================================================================== */ - -#include "cholmod_matlab.h" +#include "sputil2.h" void mexFunction ( @@ -31,131 +28,121 @@ void mexFunction ) { double dummy = 0 ; - double *Lx, *Lx2, *Lz, *Lz2 ; + double *Lx, *Lx2 ; int64_t *Li, *Lp, *Lnz2, *Li2, *Lp2, *ColCount ; - cholmod_sparse *A, Amatrix, *Lsparse, *S ; + cholmod_sparse *A, Amatrix, *Lsparse ; cholmod_factor *L ; cholmod_common Common, *cm ; int64_t j, s, n, lnz, is_complex ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin != 2) { - mexErrMsgTxt ("usage: L = resymbol (L, A)\n") ; + mexErrMsgTxt ("usage: L = resymbol (L, A)\n") ; } n = mxGetN (pargin [0]) ; if (!mxIsSparse (pargin [0]) || n != mxGetM (pargin [0])) { - mexErrMsgTxt ("resymbol: L must be sparse and square") ; + mexErrMsgTxt ("resymbol: L must be sparse and square") ; } if (n != mxGetM (pargin [1]) || n != mxGetN (pargin [1])) { - mexErrMsgTxt ("resymbol: A and L must have same dimensions") ; + mexErrMsgTxt ("resymbol: A and L must have same dimensions") ; } - /* ---------------------------------------------------------------------- */ - /* get the sparse matrix A */ - /* ---------------------------------------------------------------------- */ - - A = sputil_get_sparse_pattern (pargin [1], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + //-------------------------------------------------------------------------- + // get the sparse matrix A + //-------------------------------------------------------------------------- + A = sputil2_get_sparse_pattern (pargin [1], CHOLMOD_DOUBLE, &Amatrix, cm) ; A->stype = -1 ; - /* A = sputil_get_sparse (pargin [1], &Amatrix, &dummy, -1) ; */ + //-------------------------------------------------------------------------- + // construct a copy of the input sparse matrix L + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* construct a copy of the input sparse matrix L */ - /* ---------------------------------------------------------------------- */ - - /* get the MATLAB L */ + // get the MATLAB L Lp = (int64_t *) mxGetJc (pargin [0]) ; Li = (int64_t *) mxGetIr (pargin [0]) ; - Lx = mxGetPr (pargin [0]) ; - Lz = mxGetPi (pargin [0]) ; + Lx = mxGetData (pargin [0]) ; + is_complex = mxIsComplex (pargin [0]) ; - /* allocate the CHOLMOD symbolic L */ + // allocate the CHOLMOD symbolic L L = cholmod_l_allocate_factor (n, cm) ; L->ordering = CHOLMOD_NATURAL ; ColCount = L->ColCount ; for (j = 0 ; j < n ; j++) { - ColCount [j] = Lp [j+1] - Lp [j] ; + ColCount [j] = Lp [j+1] - Lp [j] ; } - /* allocate space for a CHOLMOD LDL' packed factor */ - /* (LL' and LDL' are treated identically) */ - cholmod_l_change_factor (is_complex ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL, - FALSE, FALSE, TRUE, TRUE, L, cm) ; + // allocate space for a CHOLMOD LDL' packed factor + // (LL' and LDL' are treated identically) + cholmod_l_change_factor (is_complex ? CHOLMOD_COMPLEX : CHOLMOD_REAL, + FALSE, FALSE, TRUE, TRUE, L, cm) ; - /* copy MATLAB L into CHOLMOD L */ + // copy MATLAB L into CHOLMOD L Lp2 = L->p ; Li2 = L->i ; Lx2 = L->x ; - Lz2 = L->z ; Lnz2 = L->nz ; lnz = L->nzmax ; for (j = 0 ; j <= n ; j++) { - Lp2 [j] = Lp [j] ; + Lp2 [j] = Lp [j] ; } for (j = 0 ; j < n ; j++) { - Lnz2 [j] = Lp [j+1] - Lp [j] ; + Lnz2 [j] = Lp [j+1] - Lp [j] ; } for (s = 0 ; s < lnz ; s++) { - Li2 [s] = Li [s] ; + Li2 [s] = Li [s] ; } - for (s = 0 ; s < lnz ; s++) - { - Lx2 [s] = Lx [s] ; - } - if (is_complex) + int64_t lnz2 = (is_complex) ? (2*lnz) : lnz ; + for (s = 0 ; s < lnz2 ; s++) { - for (s = 0 ; s < lnz ; s++) - { - Lz2 [s] = Lz [s] ; - } + Lx2 [s] = Lx [s] ; } - /* ---------------------------------------------------------------------- */ - /* resymbolic factorization */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // resymbolic factorization + //-------------------------------------------------------------------------- cholmod_l_resymbol (A, NULL, 0, TRUE, L, cm) ; - /* ---------------------------------------------------------------------- */ - /* copy the results back to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy the results back to MATLAB + //-------------------------------------------------------------------------- Lsparse = cholmod_l_factor_to_sparse (L, cm) ; - /* return L as a sparse matrix */ - pargout [0] = sputil_put_sparse (&Lsparse, cm) ; + // return L as a sparse matrix; it may contain numerically zero entries, + // which must be kept to allow update/downdate to work. + pargout [0] = sputil2_put_sparse (&Lsparse, mxDOUBLE_CLASS, + /* return L with explicit zeros kept */ false, cm) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; cholmod_l_free_factor (&L, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 3 + mxIsComplex (pargout[0])) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/resymbol.m b/CHOLMOD/MATLAB/resymbol.m index 0afcbfad0e..52299914dc 100644 --- a/CHOLMOD/MATLAB/resymbol.m +++ b/CHOLMOD/MATLAB/resymbol.m @@ -1,20 +1,20 @@ -function L = resymbol (L, A) %#ok -%RESYMBOL recomputes the symbolic Cholesky factorization of the matrix A. +function L = resymbol (L, A) %#ok +%RESYMBOL recomputes the symbolic Cholesky factorization of the matrix A % -% Example: +% Example: % L = resymbol (L, A) % -% Recompute the symbolic Cholesky factorization of the matrix A. A must be -% symmetric. Only tril(A) is used. Entries in L that are not in the Cholesky -% factorization of A are removed from L. L can be from an LL' or LDL' -% factorization (lchol or ldlchol). resymbol is useful after a series of -% downdates via ldlupdate or ldlrowmod, since downdates do not remove any -% entries in L. The numerical values of A are ignored; only its nonzero -% pattern is used. +% Recompute the symbolic Cholesky factorization of the matrix A. A must +% be symmetric. Only tril(A) is used. Entries in L that are not in the +% Cholesky factorization of A are removed from L. L can be from an LL' +% or LDL' factorization (lchol or ldlchol). resymbol is useful after a +% series of downdates via ldlupdate or ldlrowmod, since downdates do not +% remove any entries in L. The numerical values of A are ignored; only +% its nonzero pattern is used. % -% See also LCHOL, LDLUPDATE, LDLROWMOD +% See also lchol, ldlupdate, ldlrowmod. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('resymbol not found') ; diff --git a/CHOLMOD/MATLAB/sdmult.c b/CHOLMOD/MATLAB/sdmult.c index c10f0a522a..0b538134cf 100644 --- a/CHOLMOD/MATLAB/sdmult.c +++ b/CHOLMOD/MATLAB/sdmult.c @@ -2,23 +2,22 @@ // CHOLMOD/MATLAB/sdmult: sparse-times-full using CHOLMOD //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Compute C = S*F or S'*F where S is sparse and F is full (C is also sparse). - * S and F must both be real or both be complex. - * - * Usage: - * - * C = sdmult (S,F) ; C = S*F - * C = sdmult (S,F,0) ; C = S*F - * C = sdmult (S,F,1) ; C = S'*F - */ +// Compute C = S*F or S'*F where S is sparse and F is full (C is also sparse). +// S and F must both be real or both be complex. +// +// Usage: +// +// C = sdmult (S,F) ; C = S*F +// C = sdmult (S,F,0) ; C = S*F +// C = sdmult (S,F,1) ; C = S'*F -#include "cholmod_matlab.h" +#include "sputil2.h" void mexFunction ( @@ -32,23 +31,23 @@ void mexFunction cholmod_sparse *S, Smatrix ; cholmod_dense *F, Fmatrix, *C ; cholmod_common Common, *cm ; - int64_t srow, scol, frow, fcol, crow, transpose ; + int64_t srow, scol, frow, fcol, crow, transpose ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- if (nargout > 1 || nargin < 2 || nargin > 3) { - mexErrMsgTxt ("Usage: C = sdmult (S,F,transpose)") ; + mexErrMsgTxt ("Usage: C = sdmult (S,F,transpose)") ; } srow = mxGetM (pargin [0]) ; @@ -60,37 +59,41 @@ void mexFunction if (frow != (transpose ? srow : scol)) { - mexErrMsgTxt ("invalid inner dimensions") ; + mexErrMsgTxt ("invalid inner dimensions") ; } if (!mxIsSparse (pargin [0]) || mxIsSparse (pargin [1])) { - mexErrMsgTxt ("sdmult (S,F): S must be sparse, F must be full") ; + mexErrMsgTxt ("sdmult (S,F): S must be sparse, F must be full") ; } - /* ---------------------------------------------------------------------- */ - /* get S and F */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get S and F + //-------------------------------------------------------------------------- - S = sputil_get_sparse (pargin [0], &Smatrix, &dummy, 0) ; - F = sputil_get_dense (pargin [1], &Fmatrix, &dummy) ; + size_t S_xsize = 0 ; + S = sputil2_get_sparse (pargin [0], 0, CHOLMOD_DOUBLE, &Smatrix, + &S_xsize, cm) ; - /* ---------------------------------------------------------------------- */ - /* C = S*F or S'*F */ - /* ---------------------------------------------------------------------- */ + size_t F_xsize = 0 ; + F = sputil2_get_dense (pargin [1], CHOLMOD_DOUBLE, &Fmatrix, &F_xsize, cm) ; + + //-------------------------------------------------------------------------- + // C = S*F or S'*F + //-------------------------------------------------------------------------- crow = transpose ? scol : srow ; C = cholmod_l_allocate_dense (crow, fcol, crow, F->xtype, cm) ; cholmod_l_sdmult (S, transpose, one, zero, F, C, cm) ; - pargout [0] = sputil_put_dense (&C, cm) ; + pargout [0] = sputil2_put_dense (&C, mxDOUBLE_CLASS, cm) ; - /* ---------------------------------------------------------------------- */ - /* free workspace and the CHOLMOD L, except for what is copied to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and the CHOLMOD L, except for what is copied to MATLAB + //-------------------------------------------------------------------------- + sputil2_free_sparse (&S, &Smatrix, S_xsize, cm) ; + sputil2_free_dense (&F, &Fmatrix, F_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != (mxIsComplex (pargout [0]) + 1)) mexErrMsgTxt ("!"); - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/sdmult.m b/CHOLMOD/MATLAB/sdmult.m index bef01fb02e..4355694af3 100644 --- a/CHOLMOD/MATLAB/sdmult.m +++ b/CHOLMOD/MATLAB/sdmult.m @@ -1,19 +1,17 @@ -function C = sdmult (S,F,transpose) %#ok +function C = sdmult (S,F,transpose) %#ok %SDMULT sparse matrix times dense matrix -% Compute C = S*F or S'*F where S is sparse and F is full (C is also sparse). -% S and F must both be real or both be complex. This function is -% substantially faster than the MATLAB expression C=S*F when F has many -% columns. +% Compute C = S*F or S'*F where S is sparse and F is full (C is also +% sparse). S and F must both be real or both be complex. % % Example: % C = sdmult (S,F) ; C = S*F % C = sdmult (S,F,0) ; C = S*F % C = sdmult (S,F,1) ; C = S'*F % -% See also MTIMES +% See also mtimes. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('sdmult mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/septree.c b/CHOLMOD/MATLAB/septree.c index ad088f751e..4610c534ea 100644 --- a/CHOLMOD/MATLAB/septree.c +++ b/CHOLMOD/MATLAB/septree.c @@ -2,7 +2,7 @@ // CHOLMOD/MATLAB/septree: MATLAB interface to CHOLMOD prune of separator tree //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ @@ -11,29 +11,28 @@ // MATLAB(tm) is a Trademark of The MathWorks, Inc. // METIS is Copyrighted by G. Karypis -/* Prune a separator tree. - * - * Usage: - * - * [cp_new, cmember_new] = septree (cp, cmember, nd_oksep, nd_small) ; - * - * cp and cmember are outputs of the nesdis mexFunction. - * - * cmember(i)=c means that node i is in component - * c, where c is in the range of 1 to the number of components. length(cp) is - * the number of components found. cp is the separator tree; cp(c) is the - * parent of component c, or 0 if c is a root. There can be anywhere from - * 1 to n components, where n is the number of rows of A, A*A', or A'*A. - * - * On output, cp_new and cmember_new are the new tree and graph-to-tree mapping. - * A subtree is collapsed into a single node if the number of nodes in the - * separator is > nd_oksep times the total size of the subtree, or if the - * subtree has fewer than nd_small nodes. - * - * Requires the CHOLMOD Partition Module. - */ - -#include "cholmod_matlab.h" +// Prune a separator tree. +// +// Usage: +// +// [cp_new, cmember_new] = septree (cp, cmember, nd_oksep, nd_small) ; +// +// cp and cmember are outputs of the nesdis mexFunction. +// +// cmember(i)=c means that node i is in component +// c, where c is in the range of 1 to the number of components. length(cp) is +// the number of components found. cp is the separator tree; cp(c) is the +// parent of component c, or 0 if c is a root. There can be anywhere from +// 1 to n components, where n is the number of rows of A, A*A', or A'*A. +// +// On output, cp_new and cmember_new are the new tree and graph-to-tree mapping. +// A subtree is collapsed into a single node if the number of nodes in the +// separator is > nd_oksep times the total size of the subtree, or if the +// subtree has fewer than nd_small nodes. +// +// Requires the CHOLMOD Partition Module. + +#include "sputil2.h" void mexFunction ( @@ -50,22 +49,22 @@ void mexFunction double nd_oksep ; int64_t nd_small, nc, n, c, j, nc_new ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 2 || nargin != 4) { - mexErrMsgTxt ("Usage: [cp_new, cmember_new] = " - "septree (cp, cmember, nd_oksep, nd_small)") ; + mexErrMsgTxt ("Usage: [cp_new, cmember_new] = " + "septree (cp, cmember, nd_oksep, nd_small)") ; } nc = mxGetNumberOfElements (pargin [0]) ; @@ -75,66 +74,64 @@ void mexFunction if (n < nc) { - mexErrMsgTxt ("invalid inputs") ; + mexErrMsgTxt ("invalid inputs") ; } CParent = cholmod_l_malloc (nc, sizeof (int64_t), cm) ; Cmember = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - p = mxGetPr (pargin [0]) ; + p = (double *) mxGetData (pargin [0]) ; for (c = 0 ; c < nc ; c++) { - CParent [c] = p [c] - 1 ; - if (CParent [c] < EMPTY || CParent [c] > nc) - { - mexErrMsgTxt ("cp invalid") ; - } + CParent [c] = p [c] - 1 ; + if (CParent [c] < EMPTY || CParent [c] > nc) + { + mexErrMsgTxt ("cp invalid") ; + } } - p = mxGetPr (pargin [1]) ; + p = (double *) mxGetData (pargin [1]) ; for (j = 0 ; j < n ; j++) { - Cmember [j] = p [j] - 1 ; - if (Cmember [j] < 0 || Cmember [j] > nc) - { - mexErrMsgTxt ("cmember invalid") ; - } + Cmember [j] = p [j] - 1 ; + if (Cmember [j] < 0 || Cmember [j] > nc) + { + mexErrMsgTxt ("cmember invalid") ; + } } - /* ---------------------------------------------------------------------- */ - /* collapse the tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // collapse the tree + //-------------------------------------------------------------------------- nc_new = cholmod_l_collapse_septree (n, nc, nd_oksep, nd_small, CParent, - Cmember, cm) ; + Cmember, cm) ; if (nc_new < 0) { - mexErrMsgTxt ("septree failed") ; - return ; + mexErrMsgTxt ("septree failed") ; + return ; } - /* ---------------------------------------------------------------------- */ - /* return CParent and Cmember */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return CParent and Cmember + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (CParent, nc_new, 1) ; + pargout [0] = sputil2_put_int (CParent, nc_new, 1) ; if (nargout > 1) { - pargout [1] = sputil_put_int (Cmember, n, 1) ; + pargout [1] = sputil2_put_int (Cmember, n, 1) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- cholmod_l_free (nc, sizeof (int64_t), CParent, cm) ; cholmod_l_free (n, sizeof (int64_t), Cmember, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != 0) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; #else mexErrMsgTxt ("CHOLMOD Partition Module not installed\n") ; #endif } + diff --git a/CHOLMOD/MATLAB/septree.m b/CHOLMOD/MATLAB/septree.m index 6ea9d94989..a2b50d71d0 100644 --- a/CHOLMOD/MATLAB/septree.m +++ b/CHOLMOD/MATLAB/septree.m @@ -1,26 +1,26 @@ function [cp_new, cmember_new] = septree (cp, cmember, nd_oksep, nd_small) %#ok -%SEPTREE prune a separator tree. +%SEPTREE prune a separator tree % -% Example: +% Example: % [cp_new, cmember_new] = septree (cp, cmember, nd_oksep, nd_small) ; % -% cp and cmember are outputs of nesdis. cmember(i)=c means that node i is in -% component c, where c is in the range of 1 to the number of components. -% length(cp) is the number of components found. cp is the separator tree; -% cp(c) is the parent of component c, or 0 if c is a root. There can be -% anywhere from 1 to n components, where n is the number of rows of A, A*A', -% or A'*A. +% cp and cmember are outputs of nesdis. cmember(i)=c means that node i +% is in component c, where c is in the range of 1 to the number of +% components. length(cp) is the number of components found. cp is the +% separator tree; cp(c) is the parent of component c, or 0 if c is a +% root. There can be anywhere from 1 to n components, where n is the +% number of rows of A, A*A', or A'*A. % -% On output, cp_new and cmember_new are the new tree and graph-to-tree -% mapping. A subtree is collapsed into a single node if the number of nodes -% in the separator is > nd_oksep times the total size of the subtree, or if -% the subtree has fewer than nd_small nodes. +% On output, cp_new and cmember_new are the new tree and graph-to-tree +% mapping. A subtree is collapsed into a single node if the number of +% nodes in the separator is > nd_oksep times the total size of the +% subtree, or if the subtree has fewer than nd_small nodes. % -% Requires the CHOLMOD Partition Module. +% Requires the CHOLMOD Partition Module. % -% See also NESDIS. +% See also nesdis. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('septree mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/sparse2.c b/CHOLMOD/MATLAB/sparse2.c deleted file mode 100644 index e0caa41650..0000000000 --- a/CHOLMOD/MATLAB/sparse2.c +++ /dev/null @@ -1,24 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/MATLAB/sparse2: MATLAB interface to CHOLMOD triplet-to-sparse method -//------------------------------------------------------------------------------ - -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Identical to the "sparse" function in MATLAB, just faster. */ - -#include "cholmod_matlab.h" - -void mexFunction -( - int nargout, - mxArray *pargout [ ], - int nargin, - const mxArray *pargin [ ] -) -{ - sputil_sparse (nargout, pargout, nargin, pargin) ; -} diff --git a/CHOLMOD/MATLAB/sparse2.m b/CHOLMOD/MATLAB/sparse2.m deleted file mode 100644 index 19bc2a2c13..0000000000 --- a/CHOLMOD/MATLAB/sparse2.m +++ /dev/null @@ -1,28 +0,0 @@ -function S = sparse2 (i,j,s,m,n,nzmax) %#ok -%SPARSE2 replacement for SPARSE -% -% Example: -% S = sparse2 (i,j,s,m,n,nzmax) -% -% Identical to the MATLAB sparse function (just faster). -% An additional feature is added that is not part of the MATLAB sparse -% function, the Z matrix. With an extra output, -% -% [S Z] = sparse2 (i,j,s,m,n,nzmax) -% -% the matrix Z is a binary real matrix whose nonzero pattern contains the -% explicit zero entries that were dropped from S. Z only contains entries -% for the sparse2(i,j,s,...) usage. [S Z]=sparse2(X) where X is full always -% returns Z with nnz(Z) = 0, as does [S Z]=sparse2(m,n). More precisely, -% Z is the following matrix (where ... means the optional m, n, and nzmax -% parameters). -% -% S = sparse (i,j,s, ...) -% Z = spones (sparse (i,j,1, ...)) - spones (S) -% -% See also sparse. - -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ - -error ('sparse2 mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/spsym.c b/CHOLMOD/MATLAB/spsym.c index 3d5b8dd84d..ebab833881 100644 --- a/CHOLMOD/MATLAB/spsym.c +++ b/CHOLMOD/MATLAB/spsym.c @@ -2,23 +2,22 @@ // CHOLMOD/MATLAB/spsym: MATLAB interface to CHOLMOD sparse symmetry metrics //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* [result xmatched pmatched nzoffdiag nzdiag] = spsym (A, quick). - * See the spsym.m file for a description of what it computes. - */ +// [result xmatched pmatched nzoffdiag nzdiag] = spsym (A, quick). +// See the spsym.m file for a description of what it computes. -#include "cholmod_matlab.h" +#include "sputil2.h" void mexFunction ( - int nargout, + int nargout, mxArray *pargout [ ], - int nargin, + int nargin, const mxArray *pargin [ ] ) { @@ -27,49 +26,51 @@ void mexFunction cholmod_common Common, *cm ; int64_t result, quick, option, xmatched, pmatched, nzoffdiag, nzdiag ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set parameters */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set parameters + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargin > 2 || nargin < 1 || nargout > 5) { - mexErrMsgTxt ("usage: [s xmatch pmatch nzoff nzd] = spsym (A,quick)") ; + mexErrMsgTxt ("usage: [s xmatch pmatch nzoff nzd] = spsym (A,quick)") ; } if (!mxIsSparse (pargin [0])) { - mexErrMsgTxt ("A must be sparse and double") ; + mexErrMsgTxt ("A must be sparse and double") ; } - /* get sparse matrix A */ - A = sputil_get_sparse (pargin [0], &Amatrix, &dummy, 0) ; + // get sparse matrix A + size_t A_xsize = 0 ; + A = sputil2_get_sparse (pargin [0], 0, CHOLMOD_DOUBLE, &Amatrix, + &A_xsize, cm) ; - /* get the "quick" parameter */ + // get the "quick" parameter quick = (nargin > 1) ? (mxGetScalar (pargin [1]) != 0) : FALSE ; if (nargout > 1) { - option = 2 ; + option = 2 ; } else if (quick) { - option = 0 ; + option = 0 ; } else { - option = 1 ; + option = 1 ; } - /* ---------------------------------------------------------------------- */ - /* determine symmetry */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine symmetry + //-------------------------------------------------------------------------- xmatched = 0 ; pmatched = 0 ; @@ -77,23 +78,25 @@ void mexFunction nzdiag = 0 ; result = cholmod_l_symmetry (A, option, &xmatched, &pmatched, &nzoffdiag, - &nzdiag, cm) ; + &nzdiag, cm) ; - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results to MATLAB + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (&result, 1, 0) ; + pargout [0] = sputil2_put_int (&result, 1, 0) ; - if (nargout > 1) pargout [1] = sputil_put_int (&xmatched, 1, 0) ; - if (nargout > 2) pargout [2] = sputil_put_int (&pmatched, 1, 0) ; - if (nargout > 3) pargout [3] = sputil_put_int (&nzoffdiag, 1, 0) ; - if (nargout > 4) pargout [4] = sputil_put_int (&nzdiag, 1, 0) ; + if (nargout > 1) pargout [1] = sputil2_put_int (&xmatched, 1, 0) ; + if (nargout > 2) pargout [2] = sputil2_put_int (&pmatched, 1, 0) ; + if (nargout > 3) pargout [3] = sputil2_put_int (&nzoffdiag, 1, 0) ; + if (nargout > 4) pargout [4] = sputil2_put_int (&nzdiag, 1, 0) ; - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + sputil2_free_sparse (&A, &Amatrix, A_xsize, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/spsym.m b/CHOLMOD/MATLAB/spsym.m index 6b38cd117a..962772590a 100644 --- a/CHOLMOD/MATLAB/spsym.m +++ b/CHOLMOD/MATLAB/spsym.m @@ -1,98 +1,57 @@ -function result = spsym (A, quick) %#ok -%SPSYM determine if a sparse matrix is symmetric, Hermitian, or skew-symmetric. -% If so, also determine if its diagonal has all positive real entries. -% A must be sparse. +function result = spsym (A, quick) %#ok +%SPSYM check if a matrix is symmetric, Hermitian, or skew-symmetric. +% If so, also determine if its diagonal has all positive real entries. +% A must be sparse. % -% Example: +% Example: % result = spsym (A) ; % result = spsym (A,quick) ; % -% If quick = 0, or is not present, then this routine returns: +% If quick = 0, or is not present, then this routine returns: % % 1: if A is rectangular % 2: if A is unsymmetric % 3: if A is symmetric, but with one or more A(j,j) <= 0 % 4: if A is Hermitian, but with one or more A(j,j) <= 0 or with % nonzero imaginary part -% 5: if A is skew symmetric (and thus the diagonal is all zero as well) +% 5: if A is skew symmetric (and thus the diagonal is all zero) % 6: if A is symmetric with real positive diagonal % 7: if A is Hermitian with real positive diagonal % -% If quick is nonzero, then the function can return more quickly, as soon as -% it finds a diagonal entry that is <= 0 or with a nonzero imaginary part. -% In this case, it returns 2 for a square matrix, even if the matrix might -% otherwise be symmetric or Hermitian. -% -% Regardless of the value of "quick", this function returns 6 or 7 if A is -% a candidate for sparse Cholesky. -% -% For an MATLAB M-file function that computes the same thing as this -% mexFunction (but much slower), see the get_symmetry function by typing -% "type spsym". -% -% This spsym function does not compute the transpose of A, nor does it need -% to examine the entire matrix if it is unsymmetric. It uses very little -% memory as well (just size-n workspace, where n = size (A,1)). -% -% Examples: -% load west0479 -% A = west0479 ; -% spsym (A) -% spsym (A+A') -% spsym (A-A') -% spsym (A+A'+3*speye(size(A,1))) -% -% See also mldivide. - -% function result = get_symmetry (A,quick) -% %GET_SYMMETRY: does the same thing as the spsym mexFunction. -% % It's just a lot slower and uses much more memory. This function -% % is meant for testing and documentation only. -% [m n] = size (A) ; -% if (m ~= n) -% result = 1 ; % rectangular -% return -% end -% if (nargin < 2) -% quick = 0 ; -% end -% d = diag (A) ; -% posdiag = all (real (d) > 0) & all (imag (d) == 0) ; -% if (quick & ~posdiag) -% result = 2 ; % Not a candidate for sparse Cholesky. -% elseif (~isreal (A) & nnz (A-A') == 0) -% if (posdiag) -% result = 7 ; % complex Hermitian, with positive diagonal -% else -% result = 4 ; % complex Hermitian, nonpositive diagonal -% end -% elseif (nnz (A-A.') == 0) -% if (posdiag) -% result = 6 ; % symmetric with positive diagonal -% else -% result = 3 ; % symmetric, nonpositive diagonal -% end -% elseif (nnz (A+A.') == 0) -% result = 5 ; % skew symmetric -% else -% result = 2 ; % unsymmetric -% end - -% With additional outputs, spsym computes the following for square matrices: -% (in this case "quick" is ignored, and set to zero): +% If quick is nonzero, then the function can return more quickly, as soon +% as it finds a diagonal entry that is <= 0 or with a nonzero imaginary +% part. In this case, it returns 2 for a square matrix, even if the +% matrix might otherwise be symmetric or Hermitian. Regardless of the +% value of "quick", this function returns 6 or 7 if A is a candidate for +% sparse Cholesky. spsym does not compute the transpose of A, nor does +% it need to examine the entire matrix if it is unsymmetric. +% +% Examples: +% load west0479 +% A = west0479 ; +% spsym (A) +% spsym (A+A') +% spsym (A-A') +% spsym (A+A'+3*speye(size(A,1))) +% +% With additional outputs, spsym computes the following for square +% matrices (in this case "quick" is ignored, and treated as zero): % % [result xmatched pmatched nzoffdiag nnzdiag] = spsym(A) % -% xmatched is the number of nonzero entries for which A(i,j) = conj(A(j,i)). -% pmatched is the number of entries (i,j) for which A(i,j) and A(j,i) are -% both in the pattern of A (the value doesn't matter). nzoffdiag is the -% total number of off-diagonal entries in the pattern. nzdiag is the number -% of diagonal entries in the pattern. If the matrix is rectangular, -% xmatched, pmatched, nzoffdiag, and nzdiag are not computed (all of them are -% returned as zero). Note that a matched pair, A(i,j) and A(j,i) for i != j, -% is counted twice (once per entry). +% xmatched is the number of nonzero entries for which A(i,j) = +% conj(A(j,i)). pmatched is the number of entries (i,j) for which +% A(i,j) and A(j,i) are both in the pattern of A (the value doesn't +% matter). nzoffdiag is the total number of off-diagonal entries in +% the pattern. nzdiag is the number of diagonal entries in the +% pattern. If the matrix is rectangular, xmatched, pmatched, +% nzoffdiag, and nzdiag are not computed (all of them are returned as +% zero). Note that a matched pair, A(i,j) and A(j,i) for i != j, is +% counted twice (once per entry). +% +% See also mldivide. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('spsym mexFunction not found') ; diff --git a/CHOLMOD/MATLAB/sputil2.c b/CHOLMOD/MATLAB/sputil2.c new file mode 100644 index 0000000000..7a22bace38 --- /dev/null +++ b/CHOLMOD/MATLAB/sputil2.c @@ -0,0 +1,1132 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MATLAB/sputil2.c: utilities for CHOLMOD's MATLAB interface +//------------------------------------------------------------------------------ + +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Utility routines for the CHOLMOD MATLAB mexFunctions. +// +// If CHOLMOD runs out of memory, MATLAB will terminate the mexFunction +// immediately since it uses mxMalloc (see sputil2_config, below). Likewise, +// if mxCreate* or mxMalloc (as called in this file) fails, MATLAB will also +// terminate the mexFunction. When this occurs, MATLAB frees all allocated +// memory, so we don't have to worry about memory leaks. If this were not the +// case, the routines in this file would suffer from memory leaks whenever an +// error occurred. + +#include "sputil2.h" + +// This file pointer is used for the mread and mwrite mexFunctions. It must +// be a global variable, because the file pointer is not passed to the +// sputil2_error_handler function when an error occurs. +FILE *sputil2_file = NULL ; + +//------------------------------------------------------------------------------ +// sputil2_config +//------------------------------------------------------------------------------ + +// Define function pointers and other parameters for a mexFunction + +void sputil2_config (int64_t spumoni, cholmod_common *cm) +{ + // cholmod_l_solve must return a real or complex X for MATLAB + cm->prefer_zomplex = false ; + + // printing and error handling + if (spumoni == 0) + { + // do not print anything from within CHOLMOD + cm->print = -1 ; + SuiteSparse_config_printf_func_set (NULL) ; + } + else + { + // spumoni = 1: print warning and error messages. cholmod_l_print_* + // routines will print a one-line summary of each object printed. + // spumoni = 2: also print a short summary of each object. + cm->print = spumoni + 2 ; + // SuiteSparse_config_printf_func_set ((void *) mexPrintf) ; + } + + // error handler + cm->error_handler = sputil2_error_handler ; + + // Turn off METIS memory guard. It is not needed, because mxMalloc will + // safely terminate the mexFunction and free any workspace without killing + // all of MATLAB. This assumes cholmod_make was used to compile CHOLMOD + // for MATLAB. + cm->metis_memory = 0.0 ; +} + +//------------------------------------------------------------------------------ +// sputil2_error_handler +//------------------------------------------------------------------------------ + +void sputil2_error_handler +( + int status, + const char *file, + int line, + const char *message +) +{ + if (status < CHOLMOD_OK) + { + if (sputil2_file != NULL) + { + fclose (sputil2_file) ; + sputil2_file = NULL ; + } + mexErrMsgTxt (message) ; + } +} + +//------------------------------------------------------------------------------ +// sputil2_get_sparse +//------------------------------------------------------------------------------ + +// Create a shallow or deep CHOLMOD sparse copy of a MATLAB sparse or dense +// matrix. A is returned with A->xtype of CHOLMOD_PATTERN (if Amatlab is +// logical), CHOLMOD_REAL (if Amatlab is real), or CHOLMOD_COMPLEX (if Amatlab +// is complex). +// +// If the MATLAB matrix is dense, then A is a freshly allocated CHOLMOD sparse +// matrix. +// +// If the MATLAB matrix is sparse, then A == &Astatic, and it is fully or +// partially shallow. The A->p and A->i arrays are always shallow. The +// numerical array A->x can be shallow or deep. +// +// The output matrix must be freed by sputil2_free_sparse. The CHOLMOD matrix +// A must not be modified, except by sputil2_free_sparse. +// +// Example: +// +// mxArray M = pargin [0] ; +// cholmod_sparse *A, Astatic ; +// size_t xsize ; +// A = sputil2_get_sparse (M, -1, CHOLMOD_SINGLE, &Astatic, &xsize, cm) ; +// ... use A in CHOLMOD; do not change A or xsize. +// sputil2_free_sparse (&A, Astatic, xsize, cm) ; + +cholmod_sparse *sputil2_get_sparse // create a CHOLMOD copy of a MATLAB matrix +( + // input: + const mxArray *Amatlab, // MATLAB sparse or dense matrix + int stype, // assumed A->stype (-1: lower, 0: unsym, 1: upper) + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output, if the MATLAB input matrix is sparse. + // output: + size_t *xsize, // if > 0, A->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_sparse. + cholmod_common *cm +) +{ + + cholmod_sparse *A = NULL ; + + if (!mxIsSparse (Amatlab)) + { + // get a MATLAB dense matrix + cholmod_dense Xstatic ; + size_t X_xsize = 0 ; + cholmod_dense *X = sputil2_get_dense (Amatlab, dtype, &Xstatic, + &X_xsize, cm) ; + // convert it to sparse, with A->stype of 0 + A = cholmod_l_dense_to_sparse (X, 1, cm) ; + sputil2_free_dense (&X, &Xstatic, X_xsize, cm) ; + if (stype != 0) + { + // convert from 0 to the requested stype + cholmod_sparse *A2 = cholmod_l_copy (A, stype, 2, cm) ; + cholmod_l_free_sparse (&A, cm) ; + A = A2 ; + } + } + else + { + // get a MATLAB sparse matrix + A = sputil2_get_sparse_only (Amatlab, stype, dtype, Astatic, xsize, cm); + } + + return (A) ; +} + +//------------------------------------------------------------------------------ +// sputil2_get_sparse_only +//------------------------------------------------------------------------------ + +// Get a CHOLMOD shallow or deep copy of a MATLAB sparse matrix. + +cholmod_sparse *sputil2_get_sparse_only // returns A = Astatic +( + // input: + const mxArray *Amatlab, // MATLAB sparse matrix + int stype, // assumed A->stype (-1: lower, 0: unsym, 1: upper) + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output. + // output: + size_t *xsize, // if > 0, A->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_sparse. + cholmod_common *cm +) +{ + + //-------------------------------------------------------------------------- + // fill the static header of A + //-------------------------------------------------------------------------- + + if (!mxIsSparse (Amatlab)) + { + // the MATLAB matrix must be sparse + mexErrMsgTxt ("input matrix must be sparse") ; + } + + cholmod_sparse *A = Astatic ; + memset (A, 0, sizeof (cholmod_sparse)) ; + A->nrow = mxGetM (Amatlab) ; + A->ncol = mxGetN (Amatlab) ; + A->p = (int64_t *) mxGetJc (Amatlab) ; + A->i = (int64_t *) mxGetIr (Amatlab) ; + int64_t *Ap = A->p ; + int64_t anz = Ap [A->ncol] ; + A->nzmax = anz ; + A->packed = true ; + A->sorted = true ; + A->nz = NULL ; + A->itype = CHOLMOD_LONG ; + A->stype = (stype < 0) ? -1 : (stype == 0 ? 0 : 1) ; + A->dtype = (dtype == 0) ? CHOLMOD_DOUBLE : CHOLMOD_SINGLE ; + A->z = NULL ; + (*xsize) = 0 ; + + //-------------------------------------------------------------------------- + // get the numerical values + //-------------------------------------------------------------------------- + + int Amatlab_class = mxGetClassID (Amatlab) ; + if (Amatlab_class == mxLOGICAL_CLASS) + { + + //---------------------------------------------------------------------- + // logical MATLAB sparse matrix + //---------------------------------------------------------------------- + + A->xtype = CHOLMOD_PATTERN ; + A->x = NULL ; + + } + else + { + + //---------------------------------------------------------------------- + // numerical MATLAB sparse matrix + //---------------------------------------------------------------------- + + A->xtype = mxIsComplex (Amatlab) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; + size_t e = (A->xtype == CHOLMOD_REAL) ? 1 : 2 ; + int Amatlab_dtype ; + + if (Amatlab_class == mxSINGLE_CLASS) + { + // single or single complex MATLAB sparse matrix + Amatlab_dtype = CHOLMOD_SINGLE ; + } + else if (Amatlab_class == mxDOUBLE_CLASS) + { + // double or double complex MATLAB sparse matrix + Amatlab_dtype = CHOLMOD_DOUBLE ; + } + else + { + // matrix class is not supported + mexErrMsgTxt ("get_sparse: class not supported") ; + } + + //---------------------------------------------------------------------- + // get a deep or shallow copy of A->x + //---------------------------------------------------------------------- + + if (mxIsEmpty (Amatlab)) + { + + //------------------------------------------------------------------ + // the MATLAB matrix is empty + //------------------------------------------------------------------ + + // CHOLMOD requires a non-NULL A->x array, but doesn't access it + A->x = cholmod_l_calloc (2, sizeof (double), cm) ; + (*xsize) = 2 * sizeof (double) ; + + } + else if (A->dtype == Amatlab_dtype) + { + + //------------------------------------------------------------------ + // the MATLAB dtype matches the requested type + //------------------------------------------------------------------ + + A->x = mxGetData (Amatlab) ; + + } + else if (A->dtype == CHOLMOD_SINGLE) + { + + //------------------------------------------------------------------ + // convert a MATLAB double matrix into CHOLMOD single + //------------------------------------------------------------------ + + double *Ax_matlab = (double *) mxGetData (Amatlab) ; + int64_t anz2 = MAX (anz, 2) ; + A->x = cholmod_l_malloc (anz2, e * sizeof (float), cm) ; + (*xsize) = anz2 * e * sizeof (float) ; + float *Ax = A->x ; + for (int64_t k = 0 ; k < anz * e ; k++) + { + Ax [k] = (float) Ax_matlab [k] ; + } + + } + else // A->dtype == CHOLMOD_DOUBLE + { + + //------------------------------------------------------------------ + // convert a MATLAB single matrix into CHOLMOD double + //------------------------------------------------------------------ + + // NOTE: this does not exist yet in MATLAB. + float *Ax_matlab = (float *) mxGetData (Amatlab) ; + int64_t anz2 = MAX (anz, 2) ; + A->x = cholmod_l_malloc (anz2, e * sizeof (double), cm) ; + (*xsize) = anz2 * e * sizeof (double) ; + double *Ax = A->x ; + for (int64_t k = 0 ; k < anz * e ; k++) + { + Ax [k] = (float) Ax_matlab [k] ; + } + } + } + return (A) ; +} + +//------------------------------------------------------------------------------ +// sputil2_free_sparse +//------------------------------------------------------------------------------ + +// Frees any content of a CHOLMOD sparse matrix created by sputil2_get_sparse +// or sputil2_get_sparse_only. + +void sputil2_free_sparse // free a matrix created by sputil2_get_sparse +( + // input/output: + cholmod_sparse **Ahandle, // matrix created by sputil2_get_sparse + cholmod_sparse *Astatic, + // input: + size_t xsize, // from sputil2_get_sparse when A was created + cholmod_common *cm +) +{ + + if (Ahandle == NULL || *Ahandle == NULL) + { + // nothing to do + return ; + } + + cholmod_sparse *A = (*Ahandle) ; + + if (A == Astatic) + { + // A has a shallow header + if (xsize > 0) + { + cholmod_l_free (xsize, sizeof (uint8_t), A->x, cm) ; + } + memset (A, 0, sizeof (cholmod_sparse)) ; + (*Ahandle) = NULL ; + } + else + { + // A is a fully deep matrix + cholmod_l_free_sparse (Ahandle, cm) ; + } +} + +//------------------------------------------------------------------------------ +// sputil2_get_dense +//------------------------------------------------------------------------------ + +// Create a CHOLMOD dense matrix (single or double) from a MATLAB dense matrix +// (single, double, or logical). + +cholmod_dense *sputil2_get_dense // CHOLMOD copy of a MATLAB dense matrix +( + // input: + const mxArray *Xmatlab, // MATLAB dense matrix + int dtype, // requested X->dtype (0: double, nonzero: single) + // input/output: + cholmod_dense *Xstatic, // the header of X on input, contents not + // initialized. Contains the CHOLMOD dense X on + // output. + // output: + size_t *xsize, // if > 0, X->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_dense. + cholmod_common *cm +) +{ + + //-------------------------------------------------------------------------- + // fill the static header of X + //-------------------------------------------------------------------------- + + if (mxIsSparse (Xmatlab)) + { + // the MATLAB matrix must be dense + mexErrMsgTxt ("input matrix must be dense") ; + } + + cholmod_dense *X = Xstatic ; + memset (X, 0, sizeof (cholmod_dense)) ; + X->nrow = mxGetM (Xmatlab) ; + X->ncol = mxGetN (Xmatlab) ; + X->d = X->nrow ; + int64_t xnz = X->nrow * X->ncol ; + X->nzmax = xnz ; + X->dtype = (dtype == 0) ? CHOLMOD_DOUBLE : CHOLMOD_SINGLE ; + X->z = NULL ; + (*xsize) = 0 ; + + //-------------------------------------------------------------------------- + // get the numerical values + //-------------------------------------------------------------------------- + + X->xtype = mxIsComplex (Xmatlab) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; + size_t e = (X->xtype == CHOLMOD_REAL) ? 1 : 2 ; + int Xmatlab_dtype ; + + int Xmatlab_class = mxGetClassID (Xmatlab) ; + if (Xmatlab_class == mxSINGLE_CLASS) + { + // single or single complex MATLAB dense matrix + Xmatlab_dtype = CHOLMOD_SINGLE ; + } + else if (Xmatlab_class == mxDOUBLE_CLASS) + { + // double or double complex MATLAB dense matrix + Xmatlab_dtype = CHOLMOD_DOUBLE ; + } + else + { + // logical MATLAB dense matrix, converted to CHOLMOD_REAL + X->xtype = CHOLMOD_REAL ; + Xmatlab_dtype = -1 ; + } + + //-------------------------------------------------------------------------- + // get a deep or shallow copy of X->x + //-------------------------------------------------------------------------- + + if (mxIsEmpty (Xmatlab)) + { + + //---------------------------------------------------------------------- + // the MATLAB matrix is empty + //---------------------------------------------------------------------- + + // CHOLMOD requires a non-NULL X->x array, but doesn't access it + X->x = cholmod_l_calloc (2, sizeof (double), cm) ; + (*xsize) = 2 * sizeof (double) ; + + } + else if (X->dtype == Xmatlab_dtype) + { + + //---------------------------------------------------------------------- + // the MATLAB dtype matches the requested type + //---------------------------------------------------------------------- + + X->x = mxGetData (Xmatlab) ; + + } + else if (X->dtype == CHOLMOD_SINGLE) + { + + //---------------------------------------------------------------------- + // convert a MATLAB double or logical matrix into CHOLMOD single + //---------------------------------------------------------------------- + + int64_t xnz2 = MAX (xnz, 2) ; + X->x = cholmod_l_malloc (xnz2, e * sizeof (float), cm) ; + (*xsize) = xnz2 * e * sizeof (float) ; + float *Xx = X->x ; + if (Xmatlab_dtype == CHOLMOD_DOUBLE) + { + // convert MATLAB double to CHOLMOD single + double *Xx_matlab = (double *) mxGetData (Xmatlab) ; + for (int64_t k = 0 ; k < xnz * e ; k++) + { + Xx [k] = (float) Xx_matlab [k] ; + } + } + else + { + // convert MATLAB logical to CHOLMOD single + uint8_t *Xx_matlab = (uint8_t *) mxGetData (Xmatlab) ; + for (int64_t k = 0 ; k < xnz * e ; k++) + { + Xx [k] = (float) Xx_matlab [k] ; + } + } + + } + else // X->dtype == CHOLMOD_DOUBLE + { + + //---------------------------------------------------------------------- + // convert a MATLAB single or logical matrix into CHOLMOD double + //---------------------------------------------------------------------- + + int64_t xnz2 = MAX (xnz, 2) ; + X->x = cholmod_l_malloc (xnz2, e * sizeof (double), cm) ; + (*xsize) = xnz2 * e * sizeof (double) ; + double *Xx = X->x ; + if (Xmatlab_dtype == CHOLMOD_SINGLE) + { + // convert MATLAB single to CHOLMOD double + float *Xx_matlab = (float *) mxGetData (Xmatlab) ; + for (int64_t k = 0 ; k < xnz * e ; k++) + { + Xx [k] = (double) Xx_matlab [k] ; + } + } + else + { + // convert MATLAB logical to CHOLMOD double + uint8_t *Xx_matlab = (uint8_t *) mxGetData (Xmatlab) ; + for (int64_t k = 0 ; k < xnz * e ; k++) + { + Xx [k] = (double) Xx_matlab [k] ; + } + } + } + + return (X) ; +} + +//------------------------------------------------------------------------------ +// sputil2_free_dense +//------------------------------------------------------------------------------ + +// Frees any content of a CHOLMOD dense matrix created by sputil2_get_dense + +void sputil2_free_dense // free a matrix created by sputil2_get_dense +( + // input/output: + cholmod_dense **Xhandle, // matrix created by sputil2_get_dense + cholmod_dense *Xstatic, + // input: + size_t xsize, // from sputil2_get_dense when X was created + cholmod_common *cm +) +{ + + if (Xhandle == NULL || *Xhandle == NULL) + { + // nothing to do + return ; + } + + cholmod_dense *X = (*Xhandle) ; + + if (X == Xstatic) + { + // X has a shallow header + if (xsize > 0) + { + cholmod_l_free (xsize, sizeof (uint8_t), X->x, cm) ; + } + memset (X, 0, sizeof (cholmod_dense)) ; + (*Xhandle) = NULL ; + } + else + { + mexErrMsgTxt ("invalid dense matrix") ; + } +} + +//------------------------------------------------------------------------------ +// sputil2_get_sparse_pattern +//------------------------------------------------------------------------------ + +// Create a CHOLMOD_PATTERN sparse matrix for a MATLAB sparse or dense matrix. +// The stype is returned as zero. The resulting matrix should not be modified, +// except to be freed by sputil2_free_sparse. +// +// Example: +// +// mxArray M = pargin [0] ; +// cholmod_sparse *A, Astatic ; +// A = sputil2_get_sparse_pattern (M, CHOLMOD_SINGLE, &Astatic, cm) ; +// ... use A in CHOLMOD; do not change A +// sputil2_free_sparse (&A, Astatic, 0, cm) ; + +cholmod_sparse *sputil2_get_sparse_pattern +( + // input: + const mxArray *Amatlab, // MATLAB sparse or dense matrix + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output, if the MATLAB input matrix is sparse. + cholmod_common *cm +) +{ + + cholmod_sparse *A = NULL ; + + if (!mxIsSparse (Amatlab) && mxIsLogical (Amatlab)) + { + + //---------------------------------------------------------------------- + // convert full logical MATLAB matrix into CHOLMOD_PATTERN + //---------------------------------------------------------------------- + + int64_t nrow = mxGetM (Amatlab) ; + int64_t ncol = mxGetN (Amatlab) ; + uint8_t *x = (uint8_t *) mxGetData (Amatlab) ; + int64_t nzmax = nrow * ncol ; + + //---------------------------------------------------------------------- + // count the number of nonzeros in the result + //---------------------------------------------------------------------- + + int64_t nz = 0 ; + for (int64_t j = 0 ; j < nzmax ; j++) + { + if (x [j]) + { + nz++ ; + } + } + + //---------------------------------------------------------------------- + // allocate the result A + //---------------------------------------------------------------------- + + A = cholmod_l_spzeros (nrow, ncol, nz, CHOLMOD_PATTERN + dtype, cm) ; + int64_t *Ap = A->p ; + int64_t *Ai = A->i ; + + //---------------------------------------------------------------------- + // copy the full logical matrix into the sparse matrix A + //---------------------------------------------------------------------- + + int64_t p = 0 ; + for (int64_t j = 0 ; j < ncol ; j++) + { + Ap [j] = p ; + for (int64_t i = 0 ; i < nrow ; i++) + { + if (x [i+j*nrow]) + { + Ai [p++] = i ; + } + } + } + Ap [ncol] = nz ; + + } + else + { + + //---------------------------------------------------------------------- + // get the MATLAB matrix as a CHOLMOD sparse matrix + //---------------------------------------------------------------------- + + // use the existing dtype of the MATLAB matrix + int Amatlab_dtype = (mxGetClassID (Amatlab) == mxSINGLE_CLASS) ? + CHOLMOD_SINGLE : CHOLMOD_DOUBLE ; + + // get the sparse A + size_t A_xsize = 0 ; + A = sputil2_get_sparse (Amatlab, 0, Amatlab_dtype, Astatic, &A_xsize, + cm) ; + + //---------------------------------------------------------------------- + // convert A to CHOLMOD_PATTERN + //---------------------------------------------------------------------- + + if (A == Astatic) + { + // A has a shallow header so free A->x and set A to CHOLMOD_PATTERN + if (A_xsize > 0) + { + cholmod_l_free (A_xsize, sizeof (uint8_t), A->x, cm) ; + } + A->xtype = CHOLMOD_PATTERN ; + A->x = NULL ; + } + else + { + // A is a fully deep matrix + cholmod_l_sparse_xtype (CHOLMOD_PATTERN + dtype, A, cm) ; + } + } + + return (A) ; +} + +//------------------------------------------------------------------------------ +// sputil2_put_sparse +//------------------------------------------------------------------------------ + +// create a MATLAB version of a CHOLMOD sparse matrix. The CHOLMOD sparse +// matrix is destroyed. + +mxArray *sputil2_put_sparse // return MATLAB version of the matrix +( + cholmod_sparse **Ahandle, // CHOLMOD version of the matrix + mxClassID mxclass, // requested class of the MATLAB matrix: + // mxDOUBLE_CLASS, mxSINGLE_CLASS, or + // mxLOGICAL_CLASS + bool drop, // if true, drop explicit zeros + cholmod_common *cm +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + mxArray *Amatlab ; + if (Ahandle == NULL || (*Ahandle) == NULL) + { + mexErrMsgTxt ("A is null") ; + } + cholmod_sparse *A = (*Ahandle) ; + + //-------------------------------------------------------------------------- + // create the MATLAB sparse matrix + //-------------------------------------------------------------------------- + + mxComplexity mxcomplexity ; + + if (mxclass == mxLOGICAL_CLASS) + { + mxcomplexity = mxREAL ; + Amatlab = mxCreateSparseLogicalMatrix (0, 0, 1) ; + } + else + { + mxcomplexity = (A->xtype <= CHOLMOD_REAL) ? mxREAL : mxCOMPLEX ; + if (mxclass == mxDOUBLE_CLASS) + { + Amatlab = mxCreateSparse (0, 0, 1, mxcomplexity) ; + } + else if (mxclass == mxSINGLE_CLASS) + { + // not yet supported ... + // Amatlab = mxCreateSparseSingle? ... (0, 0, 1, mxcomplexity) ; + mexErrMsgTxt ("MATLAB sparse single matrices not yet supported") ; + } + else + { + mexErrMsgTxt ("put_sparse: class not supported") ; + } + } + + //-------------------------------------------------------------------------- + // convert the CHOLMOD A into the desired xtype and dtype + //-------------------------------------------------------------------------- + + int A_dtype = (mxclass == mxSINGLE_CLASS) ? CHOLMOD_SINGLE : CHOLMOD_DOUBLE; + int A_xtype = (mxclass == mxLOGICAL_CLASS) ? CHOLMOD_PATTERN : + ((mxcomplexity == mxREAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX) ; + + // does nothing if the matrix is already in the requested xtype and dtype. + cholmod_l_sparse_xtype (A_xtype + A_dtype, A, cm) ; + + //-------------------------------------------------------------------------- + // drop explicit zeros from A + //-------------------------------------------------------------------------- + + // This is optional, since dropping zeros from a LL' or LDL' factorization + // will break its chordal property and thus breaks ldlrowmod, ldlupdate, + // and lsubsolve. + + if (drop) + { + // drop zeros + cholmod_l_drop (0, A, cm) ; + // reduce the space taken by A->i and A->x + int64_t anz = cholmod_l_nnz (A, cm) ; + int64_t anzmax = A->nzmax ; + if (anz < anzmax && anzmax > 4) + { + cholmod_l_reallocate_sparse (anz, A, cm) ; + } + } + + //-------------------------------------------------------------------------- + // transplant the pattern from A into Amatlab + //-------------------------------------------------------------------------- + + int64_t *Ap = A->p ; + size_t anz = Ap [A->ncol] ; + mxSetM (Amatlab, A->nrow) ; + mxSetN (Amatlab, A->ncol) ; + mxSetNzmax (Amatlab, A->nzmax) ; + MXFREE (mxGetJc (Amatlab)) ; + MXFREE (mxGetIr (Amatlab)) ; + MXFREE (mxGetData (Amatlab)) ; + mxSetJc (Amatlab, (mwIndex *) A->p) ; + mxSetIr (Amatlab, (mwIndex *) A->i) ; + A->p = NULL ; + A->i = NULL ; + mexMakeMemoryPersistent (A->p) ; + mexMakeMemoryPersistent (A->i) ; + + //-------------------------------------------------------------------------- + // transplant the values from A into Amatlab + //-------------------------------------------------------------------------- + + if (A_xtype == CHOLMOD_PATTERN) + { + // give the MATLAB logical sparse matrix values all equal to 1 + uint8_t *Ax = cholmod_l_malloc (anz, sizeof (uint8_t), cm) ; + memset (Ax, 1, anz * sizeof (uint8_t)) ; + mxSetData (Amatlab, Ax) ; + mexMakeMemoryPersistent (Ax) ; + } + else + { + // transplant A->x as the values of the MATLAB sparse matrix + mxSetData (Amatlab, A->x) ; + mexMakeMemoryPersistent (A->x) ; + A->x = NULL ; + } + + //-------------------------------------------------------------------------- + // free the CHOLMOD sparse matrix and return the new MATLAB sparse matrix + //-------------------------------------------------------------------------- + + cholmod_l_free_sparse (Ahandle, cm) ; + return (Amatlab) ; +} + +//------------------------------------------------------------------------------ +// sputil2_put_dense +//------------------------------------------------------------------------------ + +// create a MATLAB version of a CHOLMOD dense matrix. The CHOLMOD dense +// matrix is destroyed. + +mxArray *sputil2_put_dense // return MATLAB version of the matrix +( + cholmod_dense **Xhandle, // CHOLMOD version of the matrix + mxClassID mxclass, // requested class of the MATLAB matrix: + // mxDOUBLE_CLASS, mxSINGLE_CLASS, or + // mxLOGICAL_CLASS + cholmod_common *cm +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + mxArray *Xmatlab ; + if (Xhandle == NULL || (*Xhandle) == NULL) + { + mexErrMsgTxt ("X is null") ; + } + cholmod_dense *X = (*Xhandle) ; + + //-------------------------------------------------------------------------- + // create the MATLAB dense matrix + //-------------------------------------------------------------------------- + + mxComplexity mxcomplexity ; + int dtype ; + + if (mxclass == mxLOGICAL_CLASS) + { + // logical case not yet supported + mexErrMsgTxt ("put_dense: logical class not supported") ; + } + else + { + mxcomplexity = (X->xtype <= CHOLMOD_REAL) ? mxREAL : mxCOMPLEX ; + if (mxclass == mxDOUBLE_CLASS || mxclass == mxSINGLE_CLASS) + { + Xmatlab = mxCreateNumericMatrix (0, 0, mxclass, mxcomplexity) ; + } + else + { + // other cases not yet supported + mexErrMsgTxt ("put_dense: class not supported") ; + } + } + + //-------------------------------------------------------------------------- + // convert the CHOLMOD X into the desired xtype and dtype + //-------------------------------------------------------------------------- + + int X_dtype = (mxclass == mxSINGLE_CLASS) ? CHOLMOD_SINGLE : CHOLMOD_DOUBLE; + int X_xtype = (mxcomplexity == mxREAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX ; + + // does nothing if the matrix is already in the requested xtype and dtype. + cholmod_l_dense_xtype (X_xtype + X_dtype, X, cm) ; + + //-------------------------------------------------------------------------- + // transplant the matrix from X into Xmatlab + //-------------------------------------------------------------------------- + + mxSetM (Xmatlab, X->nrow) ; + mxSetN (Xmatlab, X->ncol) ; + MXFREE (mxGetData (Xmatlab)) ; + mxSetData (Xmatlab, X->x) ; + mexMakeMemoryPersistent (X->x) ; + X->x = NULL ; + + //-------------------------------------------------------------------------- + // free the CHOLMOD dense matrix and return the new MATLAB dense matrix + //-------------------------------------------------------------------------- + + cholmod_l_free_dense (Xhandle, cm) ; + return (Xmatlab) ; +} + +//------------------------------------------------------------------------------ +// sputil2_put_int +//------------------------------------------------------------------------------ + +// Convert a int64_t vector into a double mxArray + +mxArray *sputil2_put_int +( + int64_t *P, // vector to convert + int64_t n, // length of P + int64_t one_based // 1 if convert from 0-based to 1-based, 0 otherwise +) +{ + mxArray *Q = mxCreateDoubleMatrix (1, n, mxREAL) ; + double *p = (double *) mxGetData (Q) ; + for (int64_t i = 0 ; i < n ; i++) + { + p [i] = (double) (P [i] + one_based) ; + } + return (Q) ; +} + +//------------------------------------------------------------------------------ +// sputil2_trim +//------------------------------------------------------------------------------ + +// Remove columns k to n-1 from a sparse matrix S, leaving columns 0 to k-1. +// S must be packed (there can be no S->nz array). + +void sputil2_trim +( + cholmod_sparse *S, + int64_t k, + cholmod_common *cm +) +{ + + if (S == NULL) + { + return ; + } + + if (!S->packed) + { + mexErrMsgTxt ("invalid matrix") ; + } + + int64_t ncol = S->ncol ; + if (k < 0 || k >= ncol) + { + // do not modify S + return ; + } + + // reduce S->p in size. This cannot fail. + size_t n1 = ncol + 1 ; + S->p = cholmod_l_realloc (k+1, sizeof (int64_t), S->p, &n1, cm) ; + + // get the new number of entries in S + int64_t *Sp = S->p ; + size_t nznew = Sp [k] ; + + // reduce S->i, S->x, and S->z (if present) to size nznew + cholmod_l_reallocate_sparse (nznew, S, cm) ; + + // S now has only k columns + S->ncol = k ; +} + +//------------------------------------------------------------------------------ +// sputil2_extract_zeros +//------------------------------------------------------------------------------ + +// Create a sparse binary (real) matrix Z that contains the pattern +// of explicit zeros in the sparse real/complex/zomplex double matrix A. +// A must be packed. + +cholmod_sparse *sputil2_extract_zeros +( + cholmod_sparse *A, + cholmod_common *cm +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + if (A == NULL) + { + mexErrMsgTxt ("A is null") ; + } + + if (!A->packed) + { + mexErrMsgTxt ("invalid matrix") ; + } + + int dtype = A->dtype ; + int64_t ncol = A->ncol ; + int64_t nrow = A->nrow ; + int64_t *Ap = A->p ; + int64_t *Ai = A->i ; + + //-------------------------------------------------------------------------- + // count the number of zeros in a sparse matrix A + //-------------------------------------------------------------------------- + + int64_t nzeros = 0 ; + bool is_complex = (A->xtype == CHOLMOD_COMPLEX) ; + bool is_zomplex = (A->xtype == CHOLMOD_ZOMPLEX) ; + + if (A->xtype == CHOLMOD_PATTERN) + { + // Z is empty + ; + } + else if (dtype == CHOLMOD_DOUBLE) + { + double *Ax = A->x ; + double *Az = A->z ; + for (int64_t j = 0 ; j < ncol ; j++) + { + for (int64_t p = Ap [j] ; p < Ap [j+1] ; p++) + { + if (is_complex ? (Ax [2*p] == 0 && Ax [2*p+1] == 0) : + (is_zomplex ? (Ax [p] == 0 && Az [p] == 0) : (Ax [p] == 0))) + { + nzeros++ ; + } + } + } + } + else + { + float *Ax = A->x ; + float *Az = A->z ; + for (int64_t j = 0 ; j < ncol ; j++) + { + for (int64_t p = Ap [j] ; p < Ap [j+1] ; p++) + { + if (is_complex ? (Ax [2*p] == 0 && Ax [2*p+1] == 0) : + (is_zomplex ? (Ax [p] == 0 && Az [p] == 0) : (Ax [p] == 0))) + { + nzeros++ ; + } + } + } + } + + //-------------------------------------------------------------------------- + // allocate the Z matrix with space for all the zero entries + //-------------------------------------------------------------------------- + + cholmod_sparse *Z = cholmod_l_spzeros (nrow, ncol, nzeros, + CHOLMOD_REAL + dtype, cm) ; + if (nzeros == 0) + { + // Z is empty + return (Z) ; + } + + //-------------------------------------------------------------------------- + // extract the zeros from A and store them in Z as binary values + //-------------------------------------------------------------------------- + + int64_t pz = 0 ; + int64_t *Zp = Z->p ; + int64_t *Zi = Z->i ; + + if (dtype == CHOLMOD_DOUBLE) + { + double *Ax = A->x ; + double *Az = A->z ; + double *Zx = Z->x ; + for (int64_t j = 0 ; j < ncol ; j++) + { + Zp [j] = pz ; + for (int64_t p = Ap [j] ; p < Ap [j+1] ; p++) + { + if (is_complex ? (Ax [2*p] == 0 && Ax [2*p+1] == 0) : + (is_zomplex ? (Ax [p] == 0 && Az [p] == 0) : (Ax [p] == 0))) + { + Zi [pz] = Ai [p] ; + Zx [pz] = 1 ; + pz++ ; + } + } + } + } + else + { + float *Ax = A->x ; + float *Az = A->z ; + float *Zx = Z->x ; + for (int64_t j = 0 ; j < ncol ; j++) + { + Zp [j] = pz ; + for (int64_t p = Ap [j] ; p < Ap [j+1] ; p++) + { + if (is_complex ? (Ax [2*p] == 0 && Ax [2*p+1] == 0) : + (is_zomplex ? (Ax [p] == 0 && Az [p] == 0) : (Ax [p] == 0))) + { + Zi [pz] = Ai [p] ; + Zx [pz] = 1 ; + pz++ ; + } + } + } + } + + //-------------------------------------------------------------------------- + // finalize the last column of Z and return result + //-------------------------------------------------------------------------- + + Zp [ncol] = pz ; + return (Z) ; +} + diff --git a/CHOLMOD/MATLAB/sputil2.h b/CHOLMOD/MATLAB/sputil2.h new file mode 100644 index 0000000000..e50dcf07c9 --- /dev/null +++ b/CHOLMOD/MATLAB/sputil2.h @@ -0,0 +1,175 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MATLAB/sputil2.h: include file for CHOLMOD' MATLAB interface +//------------------------------------------------------------------------------ + +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Shared prototypes and definitions for CHOLMOD mexFunctions + +#include "SuiteSparse_config.h" +#include "cholmod.h" +#include +#include "mex.h" + +#if MX_HAS_INTERLEAVED_COMPLEX +// -R2018a is required +#else +#error "CHOLMOD must be compiled with 'mex -R2018a'" +#endif + +#define EMPTY (-1) +#define TRUE 1 +#define FALSE 0 +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define LEN 16 + +#define MXFREE(a) \ +{ \ + void *ptr ; \ + ptr = (void *) (a) ; \ + if (ptr != NULL) mxFree (ptr) ; \ +} + +// getting spumoni at run-time takes way too much time +#ifndef SPUMONI +#define SPUMONI 0 +#endif + +// closed by sputil2_error_handler if not NULL +extern FILE *sputil2_file ; + +void sputil2_error_handler +( + int status, + const char *file, + int line, + const char *message +) ; + +void sputil2_config (int64_t spumoni, cholmod_common *cm) ; + +cholmod_sparse *sputil2_get_sparse // create a CHOLMOD copy of a MATLAB matrix +( + // input: + const mxArray *Amatlab, // MATLAB sparse or dense matrix + int stype, // assumed A->stype (-1: lower, 0: unsym, 1: upper) + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output, if the MATLAB input matrix is sparse. + // output: + size_t *xsize, // if > 0, A->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_sparse. + cholmod_common *cm +) ; + +cholmod_sparse *sputil2_get_sparse_only // returns A = Astatic +( + // input: + const mxArray *Amatlab, // MATLAB sparse matrix + int stype, // assumed A->stype (-1: lower, 0: unsym, 1: upper) + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output. + // output: + size_t *xsize, // if > 0, A->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_sparse. + cholmod_common *cm +) ; + +void sputil2_free_sparse // free a matrix created by sputil2_get_sparse +( + // input/output: + cholmod_sparse **A, // a CHOLMOD matrix created by sputil2_get_sparse + cholmod_sparse *Astatic, + // input: + size_t xsize, // from sputil2_get_sparse when A was created + cholmod_common *cm +) ; + +cholmod_dense *sputil2_get_dense // CHOLMOD copy of a MATLAB dense matrix +( + // input: + const mxArray *Xmatlab, // MATLAB dense matrix + int dtype, // requested X->dtype (0: double, nonzero: single) + // input/output: + cholmod_dense *Xstatic, // the header of X on input, contents not + // initialized. Contains the CHOLMOD dense X on + // output. + // output: + size_t *xsize, // if > 0, X->x has size xsize bytes, and it is a + // deep copy and must be freed by + // sputil2_free_dense. + cholmod_common *cm +) ; + +void sputil2_free_dense // free a matrix created by sputil2_get_dense +( + // input/output: + cholmod_dense **Xhandle, // matrix created by sputil2_get_dense + cholmod_dense *Xstatic, + // input: + size_t xsize, // from sputil2_get_dense when X was created + cholmod_common *cm +) ; + +mxArray *sputil2_put_dense // return MATLAB version of the matrix +( + cholmod_dense **Xhandle, // CHOLMOD version of the matrix + mxClassID mxclass, // requested class of the MATLAB matrix: + // mxDOUBLE_CLASS, mxSINGLE_CLASS, or + // mxLOGICAL_CLASS + cholmod_common *cm +) ; + +mxArray *sputil2_put_sparse // return MATLAB version of the matrix +( + cholmod_sparse **Ahandle, // CHOLMOD version of the matrix + mxClassID mxclass, // requested class of the MATLAB matrix: + // mxDOUBLE_CLASS, mxSINGLE_CLASS, or + // mxLOGICAL_CLASS + bool drop, // if true, drop explicit zeros + cholmod_common *cm +) ; + +mxArray *sputil2_put_int // copy int64_t vector to mxArray +( + int64_t *P, // vector to convert + int64_t n, // length of P + int64_t one_based // 1 if convert from 0-based to 1-based, else 0 +) ; + +void sputil2_trim +( + cholmod_sparse *S, + int64_t k, + cholmod_common *cm +) ; + +cholmod_sparse *sputil2_get_sparse_pattern +( + // input: + const mxArray *Amatlab, // MATLAB sparse or dense matrix + int dtype, // requested A->dtype (0: double, nonzero: single) + // input/output: + cholmod_sparse *Astatic, // a static header of A on input, contents not + // initialized. Contains the CHOLMOD sparse A on + // output, if the MATLAB input matrix is sparse. + cholmod_common *cm +) ; + +cholmod_sparse *sputil2_extract_zeros +( + cholmod_sparse *A, + cholmod_common *cm +) ; + diff --git a/CHOLMOD/MATLAB/symbfact2.c b/CHOLMOD/MATLAB/symbfact2.c index e01a84f001..1f6fa307d3 100644 --- a/CHOLMOD/MATLAB/symbfact2.c +++ b/CHOLMOD/MATLAB/symbfact2.c @@ -2,41 +2,40 @@ // CHOLMOD/MATLAB/symbfact2: MATLAB interface to CHOLMOD symbolic analysis //------------------------------------------------------------------------------ -// CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Usage: - * - * count = symbfact2 (A) returns row counts of R=chol(A) - * count = symbfact2 (A,'col') returns row counts of R=chol(A'*A) - * count = symbfact2 (A,'sym') same as symbfact2(A) - * count = symbfact2 (A,'lo') same as symbfact2(A'), uses tril(A) - * count = symbfact2 (A,'row') returns row counts of R=chol(A*A') - * - * [count, h, parent, post, R] = symbfact2 (...) - * - * h: height of the elimination tree - * parent: the elimination tree itself - * post: postordering of the elimination tree - * R: a 0-1 matrix whose structure is that of chol(A) or chol(A'*A) - * for the 'col' case - * - * symbfact2(A) and symbfact2(A,'sym') uses triu(A). - * symbfact2(A,'lo') uses tril(A). - * - * These forms return L = R' instead of R. They are faster and take less - * memory. They return the same count, h, parent, and post outputs. - * - * [count, h, parent, post, L] = symbfact2 (A,'col','L') - * [count, h, parent, post, L] = symbfact2 (A,'sym','L') - * [count, h, parent, post, L] = symbfact2 (A,'lo', 'L') - * [count, h, parent, post, L] = symbfact2 (A,'row','L') - */ - -#include "cholmod_matlab.h" +// Usage: +// +// count = symbfact2 (A) returns row counts of R=chol(A) +// count = symbfact2 (A,'col') returns row counts of R=chol(A'*A) +// count = symbfact2 (A,'sym') same as symbfact2(A) +// count = symbfact2 (A,'lo') same as symbfact2(A'), uses tril(A) +// count = symbfact2 (A,'row') returns row counts of R=chol(A*A') +// +// [count, h, parent, post, R] = symbfact2 (...) +// +// h: height of the elimination tree +// parent: the elimination tree itself +// post: postordering of the elimination tree +// R: a 0-1 matrix whose structure is that of chol(A) or chol(A'*A) +// for the 'col' case +// +// symbfact2(A) and symbfact2(A,'sym') uses triu(A). +// symbfact2(A,'lo') uses tril(A). +// +// These forms return L = R' instead of R. They are faster and take less +// memory. They return the same count, h, parent, and post outputs. +// +// [count, h, parent, post, L] = symbfact2 (A,'col','L') +// [count, h, parent, post, L] = symbfact2 (A,'sym','L') +// [count, h, parent, post, L] = symbfact2 (A,'lo', 'L') +// [count, h, parent, post, L] = symbfact2 (A,'row','L') + +#include "sputil2.h" void mexFunction ( @@ -49,87 +48,86 @@ void mexFunction double dummy = 0 ; double *Lx, *px ; int64_t *Parent, *Post, *ColCount, *First, *Level, *Rp, *Ri, *Lp, *Li, *W ; - cholmod_sparse *A, Amatrix, *F, *Aup, *Alo, *R, *A1, *A2, *L, *S ; + cholmod_sparse *A, Amatrix, *F, *Aup, *Alo, *R, *A1, *A2, *L ; cholmod_common Common, *cm ; int64_t n, i, coletree, j, lnz, p, k, height, c ; char buf [LEN] ; - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD and set defaults */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // start CHOLMOD and set defaults + //-------------------------------------------------------------------------- cm = &Common ; cholmod_l_start (cm) ; - sputil_config (SPUMONI, cm) ; + sputil2_config (SPUMONI, cm) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- if (nargout > 5 || nargin < 1 || nargin > 3) { - mexErrMsgTxt ( - "Usage: [count h parent post R] = symbfact2 (A, mode, Lmode)") ; + mexErrMsgTxt ( + "Usage: [count h parent post R] = symbfact2 (A, mode, Lmode)") ; } - /* ---------------------------------------------------------------------- */ - /* get input matrix A */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get input matrix A + //-------------------------------------------------------------------------- - A = sputil_get_sparse_pattern (pargin [0], &Amatrix, &dummy, cm) ; - S = (A == &Amatrix) ? NULL : A ; + A = sputil2_get_sparse_pattern (pargin [0], CHOLMOD_DOUBLE, &Amatrix, cm) ; - /* ---------------------------------------------------------------------- */ - /* get A->stype, default is to use triu(A) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get A->stype, default is to use triu(A) + //-------------------------------------------------------------------------- A->stype = 1 ; n = A->nrow ; coletree = FALSE ; if (nargin > 1) { - buf [0] = '\0' ; - if (mxIsChar (pargin [1])) - { - mxGetString (pargin [1], buf, LEN) ; - } - c = buf [0] ; - if (tolower (c) == 'r') - { - /* unsymmetric case (A*A') if string starts with 'r' */ - A->stype = 0 ; - } - else if (tolower (c) == 'c') - { - /* unsymmetric case (A'*A) if string starts with 'c' */ - n = A->ncol ; - coletree = TRUE ; - A->stype = 0 ; - } - else if (tolower (c) == 's') - { - /* symmetric upper case (A) if string starts with 's' */ - A->stype = 1 ; - } - else if (tolower (c) == 'l') - { - /* symmetric lower case (A) if string starts with 'l' */ - A->stype = -1 ; - } - else - { - mexErrMsgTxt ("symbfact2: unrecognized mode") ; - } + buf [0] = '\0' ; + if (mxIsChar (pargin [1])) + { + mxGetString (pargin [1], buf, LEN) ; + } + c = buf [0] ; + if (tolower (c) == 'r') + { + // unsymmetric case (A*A') if string starts with 'r' + A->stype = 0 ; + } + else if (tolower (c) == 'c') + { + // unsymmetric case (A'*A) if string starts with 'c' + n = A->ncol ; + coletree = TRUE ; + A->stype = 0 ; + } + else if (tolower (c) == 's') + { + // symmetric upper case (A) if string starts with 's' + A->stype = 1 ; + } + else if (tolower (c) == 'l') + { + // symmetric lower case (A) if string starts with 'l' + A->stype = -1 ; + } + else + { + mexErrMsgTxt ("symbfact2: unrecognized mode") ; + } } if (A->stype && A->nrow != A->ncol) { - mexErrMsgTxt ("symbfact2: A must be square") ; + mexErrMsgTxt ("symbfact2: A must be square") ; } - /* ---------------------------------------------------------------------- */ - /* compute the etree, its postorder, and the row/column counts */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the etree, its postorder, and the row/column counts + //-------------------------------------------------------------------------- Parent = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Post = cholmod_l_malloc (n, sizeof (int64_t), cm) ; @@ -137,197 +135,196 @@ void mexFunction First = cholmod_l_malloc (n, sizeof (int64_t), cm) ; Level = cholmod_l_malloc (n, sizeof (int64_t), cm) ; - /* F = A' */ + // F = A' F = cholmod_l_transpose (A, 0, cm) ; if (A->stype == 1 || coletree) { - /* symmetric upper case: find etree of A, using triu(A) */ - /* column case: find column etree of A, which is etree of A'*A */ - Aup = A ; - Alo = F ; + // symmetric upper case: find etree of A, using triu(A) + // column case: find column etree of A, which is etree of A'*A + Aup = A ; + Alo = F ; } else { - /* symmetric lower case: find etree of A, using tril(A) */ - /* row case: find row etree of A, which is etree of A*A' */ - Aup = F ; - Alo = A ; + // symmetric lower case: find etree of A, using tril(A) + // row case: find row etree of A, which is etree of A*A' + Aup = F ; + Alo = A ; } cholmod_l_etree (Aup, Parent, cm) ; if (cm->status < CHOLMOD_OK) { - /* out of memory or matrix invalid */ - mexErrMsgTxt ("symbfact2 failed: matrix corrupted!") ; + // out of memory or matrix invalid + mexErrMsgTxt ("symbfact2 failed: matrix corrupted!") ; } if (cholmod_l_postorder (Parent, n, NULL, Post, cm) != n) { - /* out of memory or Parent invalid */ - mexErrMsgTxt ("symbfact2 postorder failed!") ; + // out of memory or Parent invalid + mexErrMsgTxt ("symbfact2 postorder failed!") ; } - /* symmetric upper case: analyze tril(F), which is triu(A) */ - /* column case: analyze F*F', which is A'*A */ - /* symmetric lower case: analyze tril(A) */ - /* row case: analyze A*A' */ + // symmetric upper case: analyze tril(F), which is triu(A) + // column case: analyze F*F', which is A'*A + // symmetric lower case: analyze tril(A) + // row case: analyze A*A' cholmod_l_rowcolcounts (Alo, NULL, 0, Parent, Post, NULL, ColCount, - First, Level, cm) ; + First, Level, cm) ; if (cm->status < CHOLMOD_OK) { - /* out of memory or matrix invalid */ - mexErrMsgTxt ("symbfact2 failed: matrix corrupted!") ; + // out of memory or matrix invalid + mexErrMsgTxt ("symbfact2 failed: matrix corrupted!") ; } - /* ---------------------------------------------------------------------- */ - /* return results to MATLAB: count, h, parent, and post */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return results to MATLAB: count, h, parent, and post + //-------------------------------------------------------------------------- - pargout [0] = sputil_put_int (ColCount, n, 0) ; + pargout [0] = sputil2_put_int (ColCount, n, 0) ; if (nargout > 1) { - /* compute the elimination tree height */ - height = 0 ; - for (i = 0 ; i < n ; i++) - { - height = MAX (height, Level [i]) ; - } - height++ ; - pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; - px = mxGetPr (pargout [1]) ; - px [0] = height ; + // compute the elimination tree height + height = 0 ; + for (i = 0 ; i < n ; i++) + { + height = MAX (height, Level [i]) ; + } + height++ ; + pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + px = (double *) mxGetData (pargout [1]) ; + px [0] = height ; } if (nargout > 2) { - pargout [2] = sputil_put_int (Parent, n, 1) ; + pargout [2] = sputil2_put_int (Parent, n, 1) ; } if (nargout > 3) { - pargout [3] = sputil_put_int (Post, n, 1) ; + pargout [3] = sputil2_put_int (Post, n, 1) ; } - /* ---------------------------------------------------------------------- */ - /* construct L, if requested */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct L, if requested + //-------------------------------------------------------------------------- if (nargout > 4) { - if (A->stype == 1) - { - /* symmetric upper case: use triu(A) only, A2 not needed */ - A1 = A ; - A2 = NULL ; - } - else if (A->stype == -1) - { - /* symmetric lower case: use tril(A) only, A2 not needed */ - A1 = F ; - A2 = NULL ; - } - else if (coletree) - { - /* column case: analyze F*F' */ - A1 = F ; - A2 = A ; - } - else - { - /* row case: analyze A*A' */ - A1 = A ; - A2 = F ; - } - - /* count the total number of entries in L */ - lnz = 0 ; - for (j = 0 ; j < n ; j++) - { - lnz += ColCount [j] ; - } - - /* allocate the output matrix L (pattern-only) */ - L = cholmod_l_allocate_sparse (n, n, lnz, TRUE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - Lp = L->p ; - Li = L->i ; - - /* initialize column pointers */ - lnz = 0 ; - for (j = 0 ; j < n ; j++) - { - Lp [j] = lnz ; - lnz += ColCount [j] ; - } - Lp [j] = lnz ; - - /* create a copy of the column pointers */ - W = First ; - for (j = 0 ; j < n ; j++) - { - W [j] = Lp [j] ; - } - - /* get workspace for computing one row of L */ - R = cholmod_l_allocate_sparse (n, 1, n, FALSE, TRUE, 0, CHOLMOD_PATTERN, - cm) ; - Rp = R->p ; - Ri = R->i ; - - /* compute L one row at a time */ - for (k = 0 ; k < n ; k++) - { - /* get the kth row of L and store in the columns of L */ - cholmod_l_row_subtree (A1, A2, k, Parent, R, cm) ; - for (p = 0 ; p < Rp [1] ; p++) - { - Li [W [Ri [p]]++] = k ; - } - /* add the diagonal entry */ - Li [W [k]++] = k ; - } - - /* free workspace */ - cholmod_l_free_sparse (&R, cm) ; - - /* transpose L to get R, or leave as is */ - if (nargin < 3) - { - /* R = L' */ - R = cholmod_l_transpose (L, 0, cm) ; - cholmod_l_free_sparse (&L, cm) ; - L = R ; - } - - /* fill numerical values of L with one's (only MATLAB needs this...) */ - L->x = cholmod_l_malloc (lnz, sizeof (double), cm) ; - Lx = L->x ; - for (p = 0 ; p < lnz ; p++) - { - Lx [p] = 1 ; - } - L->xtype = CHOLMOD_REAL ; - - /* return L (or R) to MATLAB */ - pargout [4] = sputil_put_sparse (&L, cm) ; + if (A->stype == 1) + { + // symmetric upper case: use triu(A) only, A2 not needed + A1 = A ; + A2 = NULL ; + } + else if (A->stype == -1) + { + // symmetric lower case: use tril(A) only, A2 not needed + A1 = F ; + A2 = NULL ; + } + else if (coletree) + { + // column case: analyze F*F' + A1 = F ; + A2 = A ; + } + else + { + // row case: analyze A*A' + A1 = A ; + A2 = F ; + } + + // count the total number of entries in L + lnz = 0 ; + for (j = 0 ; j < n ; j++) + { + lnz += ColCount [j] ; + } + + // allocate the output matrix L (pattern-only) + L = cholmod_l_allocate_sparse (n, n, lnz, TRUE, TRUE, 0, + CHOLMOD_PATTERN, cm) ; + Lp = L->p ; + Li = L->i ; + + // initialize column pointers + lnz = 0 ; + for (j = 0 ; j < n ; j++) + { + Lp [j] = lnz ; + lnz += ColCount [j] ; + } + Lp [j] = lnz ; + + // create a copy of the column pointers + W = First ; + for (j = 0 ; j < n ; j++) + { + W [j] = Lp [j] ; + } + + // get workspace for computing one row of L + R = cholmod_l_allocate_sparse (n, 1, n, FALSE, TRUE, 0, CHOLMOD_PATTERN, + cm) ; + Rp = R->p ; + Ri = R->i ; + + // compute L one row at a time + for (k = 0 ; k < n ; k++) + { + // get the kth row of L and store in the columns of L + cholmod_l_row_subtree (A1, A2, k, Parent, R, cm) ; + for (p = 0 ; p < Rp [1] ; p++) + { + Li [W [Ri [p]]++] = k ; + } + // add the diagonal entry + Li [W [k]++] = k ; + } + + // free workspace + cholmod_l_free_sparse (&R, cm) ; + + // transpose L to get R, or leave as is + if (nargin < 3) + { + // R = L' + R = cholmod_l_transpose (L, 0, cm) ; + cholmod_l_free_sparse (&L, cm) ; + L = R ; + } + + // fill numerical values of L with one's (only MATLAB needs this...) + L->x = cholmod_l_malloc (lnz, sizeof (double), cm) ; + Lx = L->x ; + for (p = 0 ; p < lnz ; p++) + { + Lx [p] = 1 ; + } + L->xtype = CHOLMOD_REAL ; + + // return L (or R) to MATLAB + pargout [4] = sputil2_put_sparse (&L, mxDOUBLE_CLASS, + /* L or R is binary so it has no zeros to dro */ false, cm) ; } - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + sputil2_free_sparse (&A, &Amatrix, 0, cm) ; cholmod_l_free (n, sizeof (int64_t), Parent, cm) ; cholmod_l_free (n, sizeof (int64_t), Post, cm) ; cholmod_l_free (n, sizeof (int64_t), ColCount, cm) ; cholmod_l_free (n, sizeof (int64_t), First, cm) ; cholmod_l_free (n, sizeof (int64_t), Level, cm) ; cholmod_l_free_sparse (&F, cm) ; - cholmod_l_free_sparse (&S, cm) ; cholmod_l_finish (cm) ; - cholmod_l_print_common (" ", cm) ; - /* - if (cm->malloc_count != ((nargout == 5) ? 3:0)) mexErrMsgTxt ("!") ; - */ + if (SPUMONI > 0) cholmod_l_print_common (" ", cm) ; } + diff --git a/CHOLMOD/MATLAB/symbfact2.m b/CHOLMOD/MATLAB/symbfact2.m index d44f2211b7..702bb26f05 100644 --- a/CHOLMOD/MATLAB/symbfact2.m +++ b/CHOLMOD/MATLAB/symbfact2.m @@ -1,48 +1,49 @@ -function [count, h, parent, post, L] = symbfact2 (A, mode, Lmode) %#ok +function [count, h, parent, post, L] = symbfact2 (A, mode, Lmode) %#ok %SYMBFACT2 symbolic factorization % -% Analyzes the Cholesky factorization of A, A'*A, or A*A'. +% Analyzes the Cholesky factorization of A, A'*A, or A*A'. % % Example: -% count = symbfact2 (A) returns row counts of R=chol(A) -% count = symbfact2 (A,'col') returns row counts of R=chol(A'*A) -% count = symbfact2 (A,'sym') same as symbfact2(A) -% count = symbfact2 (A,'lo') same as symbfact2(A'), uses tril(A) -% count = symbfact2 (A,'row') returns row counts of R=chol(A*A') +% count = symbfact2 (A) returns row counts of R=chol(A) +% count = symbfact2 (A,'col') returns row counts of R=chol(A'*A) +% count = symbfact2 (A,'sym') same as symbfact2(A) +% count = symbfact2 (A,'lo') same as symbfact2(A'), uses tril(A) +% count = symbfact2 (A,'row') returns row counts of R=chol(A*A') % -% The flop count for a subsequent LL' factorization is sum(count.^2) +% The flop count for a subsequent LL' factorization is sum(count.^2) % -% [count, h, parent, post, R] = symbfact2 (...) returns: +% [count, h, parent, post, R] = symbfact2 (...) returns: % % h: height of the elimination tree % parent: the elimination tree itself % post: postordering of the elimination tree -% R: a 0-1 matrix whose structure is that of chol(A) for the symmetric -% case, chol(A'*A) for the 'col' case, or chol(A*A') for the -% 'row' case. +% R: a 0-1 matrix whose structure is that of chol(A) for the +% symmetric case, chol(A'*A) for the 'col' case, or chol(A*A') +% for the 'row' case. % -% symbfact2(A) and symbfact2(A,'sym') uses the upper triangular part of A -% (triu(A)) and assumes the lower triangular part is the transpose of -% the upper triangular part. symbfact2(A,'lo') uses tril(A) instead. +% symbfact2(A) and symbfact2(A,'sym') uses the upper triangular part of A +% (triu(A)) and assumes the lower triangular part is the transpose of the +% upper triangular part. symbfact2(A,'lo') uses tril(A) instead. % -% With one to four output arguments, symbfact2 takes time almost proportional -% to nnz(A)+n where n is the dimension of R, and memory proportional to -% nnz(A). Computing the 5th argument takes more time and memory, both -% O(nnz(L)). Internally, the pattern of L is computed and R=L' is returned. +% With one to four output arguments, symbfact2 takes time almost +% proportional to nnz(A)+n where n is the dimension of R, and memory +% proportional to nnz(A). Computing the 5th argument takes more time and +% memory, both O(nnz(L)). Internally, the pattern of L is computed and +% R=L' is returned. % -% The following forms return L = R' instead of R. They are faster and take -% less memory than the forms above. They return the same count, h, parent, -% and post outputs. +% The following forms return L = R' instead of R. They are faster and +% take less memory than the forms above. They return the same count, h, +% parent, and post outputs. % % [count, h, parent, post, L] = symbfact2 (A,'col','L') % [count, h, parent, post, L] = symbfact2 (A,'sym','L') % [count, h, parent, post, L] = symbfact2 (A,'lo', 'L') % [count, h, parent, post, L] = symbfact2 (A,'row','L') % -% See also CHOL, ETREE, TREELAYOUT, SYMBFACT +% See also chol, etree, treelayout, symbfact. -% Copyright 2006-2022, Timothy A. Davis, All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0+ + % Copyright 2006-2023, Timothy A. Davis, All Rights Reserved. + % SPDX-License-Identifier: GPL-2.0+ error ('symbfact2 mexFunction not found!') ; diff --git a/CHOLMOD/Makefile b/CHOLMOD/Makefile index eb4d0dda2e..ac1fe734c2 100644 --- a/CHOLMOD/Makefile +++ b/CHOLMOD/Makefile @@ -2,7 +2,7 @@ # SuiteSparse/CHOLOMD/Makefile #------------------------------------------------------------------------------- -# This CHOLMOD/Makefile: Copyright (c) 2005-2022, Timothy A. Davis. +# This CHOLMOD/Makefile: Copyright (c) 2005-2023, Timothy A. Davis. # CHOLMOD: Copyright and license varies by module. #------------------------------------------------------------------------------- @@ -64,17 +64,56 @@ all: library demos: library ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && cmake --build . --config Release -j${JOBS} ) - ./build/cholmod_demo < ./Demo/Matrix/bcsstk01.tri - ./build/cholmod_l_demo < ./Demo/Matrix/bcsstk01.tri - ./build/cholmod_demo < ./Demo/Matrix/lp_afiro.tri - ./build/cholmod_l_demo < ./Demo/Matrix/lp_afiro.tri - ./build/cholmod_demo < ./Demo/Matrix/can___24.mtx - ./build/cholmod_l_demo < ./Demo/Matrix/can___24.mtx - ./build/cholmod_demo < ./Demo/Matrix/c.tri - ./build/cholmod_l_demo < ./Demo/Matrix/c.tri - ./build/cholmod_simple < ./Demo/Matrix/c.tri - ./build/cholmod_simple < ./Demo/Matrix/can___24.mtx - ./build/cholmod_simple < ./Demo/Matrix/bcsstk01.tri + ./build/cholmod_di_demo ./Demo/Matrix/bcsstk01.tri > ./build/bcsstk01_out.txt + ./build/cholmod_dl_demo ./Demo/Matrix/bcsstk01.tri >> ./build/bcsstk01_out.txt + ./build/cholmod_si_demo ./Demo/Matrix/bcsstk01.tri >> ./build/bcsstk01_out.txt + ./build/cholmod_sl_demo ./Demo/Matrix/bcsstk01.tri >> ./build/bcsstk01_out.txt + # + ./build/cholmod_di_demo ./Demo/Matrix/lp_afiro.tri > ./build/lp_afiro_out.txt + ./build/cholmod_dl_demo ./Demo/Matrix/lp_afiro.tri >> ./build/lp_afiro_out.txt + ./build/cholmod_si_demo ./Demo/Matrix/lp_afiro.tri >> ./build/lp_afiro_out.txt + ./build/cholmod_sl_demo ./Demo/Matrix/lp_afiro.tri >> ./build/lp_afiro_out.txt + # + ./build/cholmod_di_demo ./Demo/Matrix/can___24.mtx > ./build/can24_out.txt + ./build/cholmod_dl_demo ./Demo/Matrix/can___24.mtx >> ./build/can24_out.txt + ./build/cholmod_si_demo ./Demo/Matrix/can___24.mtx >> ./build/can24_out.txt + ./build/cholmod_sl_demo ./Demo/Matrix/can___24.mtx >> ./build/can24_out.txt + # + ./build/cholmod_di_demo ./Demo/Matrix/c.tri > ./build/complex_out.txt + ./build/cholmod_dl_demo ./Demo/Matrix/c.tri >> ./build/complex_out.txt + ./build/cholmod_si_demo ./Demo/Matrix/c.tri >> ./build/complex_out.txt + ./build/cholmod_sl_demo ./Demo/Matrix/c.tri >> ./build/complex_out.txt + # + ./build/cholmod_di_simple < ./Demo/Matrix/bcsstk01.tri > ./build/di_simple.out.txt + ./build/cholmod_dl_simple < ./Demo/Matrix/bcsstk01.tri > ./build/dl_simple.out.txt + ./build/cholmod_si_simple < ./Demo/Matrix/bcsstk01.tri > ./build/si_simple.out.txt + ./build/cholmod_sl_simple < ./Demo/Matrix/bcsstk01.tri > ./build/sl_simple.out.txt + # + ./build/cholmod_di_simple < ./Demo/Matrix/lp_afiro.tri >> ./build/di_simple.out.txt + ./build/cholmod_dl_simple < ./Demo/Matrix/lp_afiro.tri >> ./build/dl_simple.out.txt + ./build/cholmod_si_simple < ./Demo/Matrix/lp_afiro.tri >> ./build/si_simple.out.txt + ./build/cholmod_sl_simple < ./Demo/Matrix/lp_afiro.tri >> ./build/sl_simple.out.txt + # + ./build/cholmod_di_simple < ./Demo/Matrix/can___24.mtx >> ./build/di_simple.out.txt + ./build/cholmod_dl_simple < ./Demo/Matrix/can___24.mtx >> ./build/dl_simple.out.txt + ./build/cholmod_si_simple < ./Demo/Matrix/can___24.mtx >> ./build/si_simple.out.txt + ./build/cholmod_sl_simple < ./Demo/Matrix/can___24.mtx >> ./build/sl_simple.out.txt + # + ./build/cholmod_di_simple < ./Demo/Matrix/c.tri >> ./build/di_simple.out.txt + ./build/cholmod_dl_simple < ./Demo/Matrix/c.tri >> ./build/dl_simple.out.txt + ./build/cholmod_si_simple < ./Demo/Matrix/c.tri >> ./build/si_simple.out.txt + ./build/cholmod_sl_simple < ./Demo/Matrix/c.tri >> ./build/sl_simple.out.txt + +large: library + ./build/cholmod_dl_simple < ~/nd12k.mtx > ./build/dl_nd12k.out.txt + ./build/cholmod_sl_simple < ~/nd12k.mtx > ./build/sl_nd12k.out.txt + +ilarge: library + ./build/cholmod_di_simple < ~/nd12k.mtx > ./build/di_nd12k.out.txt + ./build/cholmod_si_simple < ~/nd12k.mtx > ./build/si_nd12k.out.txt + +test: library + ( cd build && ctest . || ctest . --rerun-failed --output-on-failure ) cov: ( cd Tcov && $(MAKE) ) diff --git a/CHOLMOD/MatrixOps/cholmod_drop.c b/CHOLMOD/MatrixOps/cholmod_drop.c index eceb86a7ca..8d68af4e0e 100644 --- a/CHOLMOD/MatrixOps/cholmod_drop.c +++ b/CHOLMOD/MatrixOps/cholmod_drop.c @@ -2,180 +2,120 @@ // CHOLMOD/MatrixOps/cholmod_drop: drop small entries from a sparse matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Drop small entries from A, and entries in the ignored part of A if A - * is symmetric. None of the matrix operations drop small numerical entries - * from a matrix, except for this one. NaN's and Inf's are kept. - * - * workspace: none - * - * Supports pattern and real matrices, complex and zomplex not supported. - */ +// Drop small entries from A, and entries in the ignored part of A if A +// is symmetric. None of the matrix operations drop small numerical entries +// from a matrix, except for this one. NaN's and Inf's are kept. +// +// workspace: none +// +// Supports any xtype (pattern, real, complex, zomplex) and any dtype +// (single or double). #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === cholmod_drop ========================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_drop_worker +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_drop_worker.c" +#define COMPLEX +#include "t_cholmod_drop_worker.c" +#define ZOMPLEX +#include "t_cholmod_drop_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_drop_worker.c" +#define COMPLEX +#include "t_cholmod_drop_worker.c" +#define ZOMPLEX +#include "t_cholmod_drop_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_drop +//------------------------------------------------------------------------------ int CHOLMOD(drop) ( - /* ---- input ---- */ - double tol, /* keep entries with absolute value > tol */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to drop entries from */ - /* --------------- */ + // input: + double tol, // keep entries with absolute value > tol + // input/output: + cholmod_sparse *A, // matrix to drop entries from cholmod_common *Common ) { - double aij ; - double *Ax ; - Int *Ap, *Ai, *Anz ; - Int packed, i, j, nrow, ncol, p, pend, nz, values ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ; + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A predrop", Common) >= 0) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Anz = A->nz ; - packed = A->packed ; - ncol = A->ncol ; - nrow = A->nrow ; - values = (A->xtype != CHOLMOD_PATTERN) ; - nz = 0 ; - - if (values) - { - - /* ------------------------------------------------------------------ */ - /* drop small numerical entries from A, and entries in ignored part */ - /* ------------------------------------------------------------------ */ - - if (A->stype > 0) - { - - /* -------------------------------------------------------------- */ - /* A is symmetric, with just upper triangular part stored */ - /* -------------------------------------------------------------- */ - - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - Ap [j] = nz ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - aij = Ax [p] ; - if (i <= j && (fabs (aij) > tol || isnan (aij))) - { - Ai [nz] = i ; - Ax [nz] = aij ; - nz++ ; - } - } - } - - } - else if (A->stype < 0) - { - - /* -------------------------------------------------------------- */ - /* A is symmetric, with just lower triangular part stored */ - /* -------------------------------------------------------------- */ - - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - Ap [j] = nz ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - aij = Ax [p] ; - if (i >= j && (fabs (aij) > tol || isnan (aij))) - { - Ai [nz] = i ; - Ax [nz] = aij ; - nz++ ; - } - } - } - } - else - { - - /* -------------------------------------------------------------- */ - /* both parts of A present, just drop small entries */ - /* -------------------------------------------------------------- */ - - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - Ap [j] = nz ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - aij = Ax [p] ; - if (fabs (aij) > tol || isnan (aij)) - { - Ai [nz] = i ; - Ax [nz] = aij ; - nz++ ; - } - } - } - } - Ap [ncol] = nz ; - - /* reduce A->i and A->x in size */ - ASSERT (MAX (1,nz) <= A->nzmax) ; - CHOLMOD(reallocate_sparse) (nz, A, Common) ; - ASSERT (Common->status >= CHOLMOD_OK) ; + //-------------------------------------------------------------------------- + // drop small entries from A + //-------------------------------------------------------------------------- - } - else + switch ((A->xtype + A->dtype) % 8) { - /* ------------------------------------------------------------------ */ - /* consider only the pattern of A */ - /* ------------------------------------------------------------------ */ - - /* Note that cholmod_band_inplace calls cholmod_reallocate_sparse */ - if (A->stype > 0) - { - CHOLMOD(band_inplace) (0, ncol, 0, A, Common) ; - } - else if (A->stype < 0) - { - CHOLMOD(band_inplace) (-nrow, 0, 0, A, Common) ; - } + default: + // pattern only: just drop entries outside the lower/upper part, + // if A is symmetric + if (A->stype > 0) + { + CHOLMOD(band_inplace) (0, A->ncol, 0, A, Common) ; + } + else if (A->stype < 0) + { + CHOLMOD(band_inplace) (-(A->nrow), 0, 0, A, Common) ; + } + break ; + + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_drop_worker (tol, A, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_drop_worker (tol, A, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_drop_worker (tol, A, Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_drop_worker (tol, A, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_drop_worker (tol, A, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_drop_worker (tol, A, Common) ; + break ; } ASSERT (CHOLMOD(dump_sparse) (A, "A dropped", Common) >= 0) ; return (TRUE) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_horzcat.c b/CHOLMOD/MatrixOps/cholmod_horzcat.c index 741e0ed394..cd8c68a4ed 100644 --- a/CHOLMOD/MatrixOps/cholmod_horzcat.c +++ b/CHOLMOD/MatrixOps/cholmod_horzcat.c @@ -2,200 +2,210 @@ // CHOLMOD/MatrixOps/cholmod_horzcat: horizontal concatenation, C=[A B] //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Horizontal concatenation, C = [A , B] in MATLAB notation. - * - * A and B can be up/lo/unsym; C is unsymmetric and packed. - * A and B must have the same number of rows. - * C is sorted if both A and B are sorted. - * - * workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)). - * allocates temporary copies of A and B if they are symmetric. - * - * A and B must have the same numeric xtype, unless values is FALSE. - * A and B cannot be complex or zomplex, unless values is FALSE. - */ +// Horizontal concatenation, C = [A , B] in MATLAB notation. +// +// A and B can be up/lo/unsym; C is unsymmetric and packed. +// A and B must have the same number of rows. +// C is sorted if both A and B are sorted. +// +// workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)). +// allocates temporary copies of A and B if they are symmetric. +// +// A and B must have the same xtype and dtype, unless mode is 0. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === cholmod_horzcat ====================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_horzcat_worker template +//------------------------------------------------------------------------------ -cholmod_sparse *CHOLMOD(horzcat) +#define PATTERN +#include "t_cholmod_horzcat_worker.c" + +#define DOUBLE +#define REAL +#include "t_cholmod_horzcat_worker.c" +#define COMPLEX +#include "t_cholmod_horzcat_worker.c" +#define ZOMPLEX +#include "t_cholmod_horzcat_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_horzcat_worker.c" +#define COMPLEX +#include "t_cholmod_horzcat_worker.c" +#define ZOMPLEX +#include "t_cholmod_horzcat_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_horzcat +//------------------------------------------------------------------------------ + +cholmod_sparse *CHOLMOD(horzcat) // return C = [A B] ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to concatenate + cholmod_sparse *B, // right matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric + // 1: numerical (non-conj.) if A and/or B are symmetric + // 0: pattern cholmod_common *Common ) { - double *Ax, *Bx, *Cx ; - Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Cp, *Ci ; - cholmod_sparse *C, *A2, *B2 ; - Int apacked, bpacked, ancol, bncol, ncol, nrow, anz, bnz, nz, j, p, pend, - pdest ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + cholmod_sparse *C = NULL, *A2 = NULL, *B2 = NULL ; RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; - values = values && - (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; - RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; + + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN || B->xtype == CHOLMOD_PATTERN) + { + mode = 0 ; + } + bool values = (mode != 0) ; + + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; + RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->nrow != B->nrow) { - /* A and B must have the same number of rows */ - ERROR (CHOLMOD_INVALID, "A and B must have same # rows") ; - return (NULL) ; + // A and B must have the same number of rows + ERROR (CHOLMOD_INVALID, "A and B must have same # rows") ; + return (NULL) ; + } + if (mode != 0 && (A->xtype != B->xtype || A->dtype != A->dtype)) + { + // A and B must have the same xtype and dtype if mode is 0 + ERROR (CHOLMOD_INVALID, "A and B must have same xtype and dtype") ; + return (NULL) ; } - /* A and B must have the same numerical type if values is TRUE (both must - * be CHOLMOD_REAL, this is implicitly checked above) */ Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - ancol = A->ncol ; - bncol = B->ncol ; - nrow = A->nrow ; + Int ancol = A->ncol ; + Int bncol = B->ncol ; + Int nrow = A->nrow ; CHOLMOD(allocate_work) (0, MAX3 (nrow, ancol, bncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (NULL) ; + // out of memory + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert A and/or B if necessary + //-------------------------------------------------------------------------- - /* convert A to unsymmetric, if necessary */ - A2 = NULL ; + // convert A to unsymmetric, if necessary if (A->stype != 0) { - /* workspace: Iwork (max (A->nrow,A->ncol)) */ - A2 = CHOLMOD(copy) (A, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (NULL) ; - } - A = A2 ; + // workspace: Iwork (max (A->nrow,A->ncol)) + A2 = CHOLMOD(copy) (A, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + A = A2 ; } - /* convert B to unsymmetric, if necessary */ - B2 = NULL ; + // convert B to unsymmetric, if necessary if (B->stype != 0) { - /* workspace: Iwork (max (B->nrow,B->ncol)) */ - B2 = CHOLMOD(copy) (B, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - return (NULL) ; - } - B = B2 ; + // workspace: Iwork (max (B->nrow,B->ncol)) + B2 = CHOLMOD(copy) (B, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + return (NULL) ; + } + B = B2 ; } - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - apacked = A->packed ; + //-------------------------------------------------------------------------- + // allocate C + //-------------------------------------------------------------------------- - Bp = B->p ; - Bnz = B->nz ; - Bi = B->i ; - Bx = B->x ; - bpacked = B->packed ; - - /* ---------------------------------------------------------------------- */ - /* allocate C */ - /* ---------------------------------------------------------------------- */ - - anz = CHOLMOD(nnz) (A, Common) ; - bnz = CHOLMOD(nnz) (B, Common) ; - ncol = ancol + bncol ; - nz = anz + bnz ; + Int anz = CHOLMOD(nnz) (A, Common) ; + Int bnz = CHOLMOD(nnz) (B, Common) ; + Int ncol = ancol + bncol ; + Int nz = anz + bnz ; C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, A->sorted && B->sorted, TRUE, - 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; + 0, (values ? A->xtype : CHOLMOD_PATTERN) + A->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - return (NULL) ; + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + CHOLMOD(free_sparse) (&B2, Common) ; + return (NULL) ; } - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - - /* ---------------------------------------------------------------------- */ - /* C = [A , B] */ - /* ---------------------------------------------------------------------- */ - pdest = 0 ; + //-------------------------------------------------------------------------- + // C = [A , B] + //-------------------------------------------------------------------------- - /* copy A as the first A->ncol columns of C */ - for (j = 0 ; j < ancol ; j++) + switch ((C->xtype + C->dtype) % 8) { - /* A(:,j) is the jth column of C */ - p = Ap [j] ; - pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; - Cp [j] = pdest ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Ai [p] ; - if (values) Cx [pdest] = Ax [p] ; - pdest++ ; - } - } + default: + p_cholmod_horzcat_worker (C, A, B) ; + break ; - /* copy B as the next B->ncol columns of C */ - for (j = 0 ; j < bncol ; j++) - { - /* B(:,j) is the (ancol+j)th column of C */ - p = Bp [j] ; - pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ; - Cp [ancol + j] = pdest ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Bi [p] ; - if (values) Cx [pdest] = Bx [p] ; - pdest++ ; - } + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_horzcat_worker (C, A, B) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_horzcat_worker (C, A, B) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_horzcat_worker (C, A, B) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_horzcat_worker (C, A, B) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_horzcat_worker (C, A, B) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_horzcat_worker (C, A, B) ; + break ; } - Cp [ncol] = pdest ; - ASSERT (pdest == anz + bnz) ; - /* ---------------------------------------------------------------------- */ - /* free the unsymmetric copies of A and B, and return C */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the unsymmetric copies of A and B, and return C + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (C) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_l_drop.c b/CHOLMOD/MatrixOps/cholmod_l_drop.c index da5ab9e092..9a589733a7 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_drop.c +++ b/CHOLMOD/MatrixOps/cholmod_l_drop.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_drop.c: int64_t version of cholmod_drop //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_horzcat.c b/CHOLMOD/MatrixOps/cholmod_l_horzcat.c index a8f9cac9d5..bc5e9a0843 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_horzcat.c +++ b/CHOLMOD/MatrixOps/cholmod_l_horzcat.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_horzcat.c: int64_t version of cholmod_horzcat //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_norm.c b/CHOLMOD/MatrixOps/cholmod_l_norm.c index b3bb886ba6..1da65af91f 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_norm.c +++ b/CHOLMOD/MatrixOps/cholmod_l_norm.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_norm.c: int64_t version of cholmod_norm //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_scale.c b/CHOLMOD/MatrixOps/cholmod_l_scale.c index 8c56e00e18..fc1b331250 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_scale.c +++ b/CHOLMOD/MatrixOps/cholmod_l_scale.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_scale.c: int64_t version of cholmod_scale //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_sdmult.c b/CHOLMOD/MatrixOps/cholmod_l_sdmult.c index 94cce98918..56a4d88e35 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_sdmult.c +++ b/CHOLMOD/MatrixOps/cholmod_l_sdmult.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_sdmult.c: int64_t version of cholmod_sdmult //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_ssmult.c b/CHOLMOD/MatrixOps/cholmod_l_ssmult.c index 521771f2d9..fe26bb3271 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_ssmult.c +++ b/CHOLMOD/MatrixOps/cholmod_l_ssmult.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_ssmult.c: int64_t version of cholmod_ssmult //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_submatrix.c b/CHOLMOD/MatrixOps/cholmod_l_submatrix.c index 0ceb8037be..9311742aa3 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_submatrix.c +++ b/CHOLMOD/MatrixOps/cholmod_l_submatrix.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_submatrix.c: int64_t version of cholmod_submatrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_symmetry.c b/CHOLMOD/MatrixOps/cholmod_l_symmetry.c index b421762479..664797e350 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_symmetry.c +++ b/CHOLMOD/MatrixOps/cholmod_l_symmetry.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_symmetry.c: int64_t version of cholmod_symmetry //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_l_vertcat.c b/CHOLMOD/MatrixOps/cholmod_l_vertcat.c index c567f5c94b..dfc2a458ff 100644 --- a/CHOLMOD/MatrixOps/cholmod_l_vertcat.c +++ b/CHOLMOD/MatrixOps/cholmod_l_vertcat.c @@ -2,7 +2,7 @@ // CHOLMOD/MatrixOps/cholmod_l_vertcat.c: int64_t version of cholmod_vertcat //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/MatrixOps/cholmod_norm.c b/CHOLMOD/MatrixOps/cholmod_norm.c index e4a2b55b77..8f7de298cb 100644 --- a/CHOLMOD/MatrixOps/cholmod_norm.c +++ b/CHOLMOD/MatrixOps/cholmod_norm.c @@ -2,449 +2,219 @@ // CHOLMOD/MatrixOps/cholmod_norm: compute norm of a sparse matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* r = norm (A), compute the infinity-norm, 1-norm, or 2-norm of a sparse or - * dense matrix. Can compute the 2-norm only for a dense column vector. - * Returns -1 if an error occurs. - * - * Pattern, real, complex, and zomplex sparse matrices are supported. - */ +// r = norm (A), compute the infinity-norm, 1-norm, or 2-norm of a sparse or +// dense matrix. Can compute the 2-norm only for a dense column vector. +// Returns -1 if an error occurs. +// +// Pattern, real, complex, and zomplex sparse matrices, with any dtype, are +// supported. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === abs_value ============================================================ */ -/* ========================================================================== */ - -/* Compute the absolute value of a real, complex, or zomplex value */ - -static double abs_value -( - int xtype, - double *Ax, - double *Az, - Int p, - cholmod_common *Common -) -{ - double s = 0 ; - switch (xtype) - { - case CHOLMOD_PATTERN: - s = 1 ; - break ; - - case CHOLMOD_REAL: - s = fabs (Ax [p]) ; - break ; - - case CHOLMOD_COMPLEX: - s = SuiteSparse_config_hypot (Ax [2*p], Ax [2*p+1]) ; - break ; - - case CHOLMOD_ZOMPLEX: - s = SuiteSparse_config_hypot (Ax [p], Az [p]) ; - break ; - } - return (s) ; -} +//------------------------------------------------------------------------------ +// t_cholmod_norm_worker template +//------------------------------------------------------------------------------ +#define PATTERN +#include "t_cholmod_norm_worker.c" + +#define DOUBLE +#define REAL +#include "t_cholmod_norm_worker.c" +#define COMPLEX +#include "t_cholmod_norm_worker.c" +#define ZOMPLEX +#include "t_cholmod_norm_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_norm_worker.c" +#define COMPLEX +#include "t_cholmod_norm_worker.c" +#define ZOMPLEX +#include "t_cholmod_norm_worker.c" -/* ========================================================================== */ -/* === cholmod_norm_dense =================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_norm_dense +//------------------------------------------------------------------------------ -double CHOLMOD(norm_dense) +double CHOLMOD(norm_dense) // returns norm (X) ( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */ - /* --------------- */ + // input: + cholmod_dense *X, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm cholmod_common *Common ) { - double xnorm, s, x, z ; - double *Xx, *Xz, *W ; - Int nrow, ncol, d, i, j, use_workspace, xtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (X, EMPTY) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - ncol = X->ncol ; - if (norm < 0 || norm > 2 || (norm == 2 && ncol > 1)) + if (norm < 0 || norm > 2 || (norm == 2 && X->ncol > 1)) { - ERROR (CHOLMOD_INVALID, "invalid norm") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "invalid norm") ; + return (EMPTY) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - nrow = X->nrow ; - d = X->d ; - Xx = X->x ; - Xz = X->z ; - xtype = X->xtype ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace, if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace, if needed + //-------------------------------------------------------------------------- - W = NULL ; - use_workspace = (norm == 0 && ncol > 4) ; + double *W = NULL ; + bool use_workspace = (norm == 0 && X->ncol > 4) ; if (use_workspace) { - CHOLMOD(allocate_work) (0, 0, nrow, Common) ; - W = Common->Xwork ; - if (Common->status < CHOLMOD_OK) - { - /* oops, no workspace */ - use_workspace = FALSE ; - } + CHOLMOD(alloc_work) (0, 0, X->nrow, CHOLMOD_DOUBLE, Common) ; + W = (double *) (Common->Xwork) ; + if (Common->status < CHOLMOD_OK) + { + // oops, no workspace + use_workspace = FALSE ; + W = NULL ; + } } + //-------------------------------------------------------------------------- + // compute the norm + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* compute the norm */ - /* ---------------------------------------------------------------------- */ + double xnorm = 0 ; - xnorm = 0 ; - - if (use_workspace) + switch ((X->xtype + X->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + xnorm = rs_cholmod_norm_dense_worker (X, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* infinity-norm = max row sum, using stride-1 access of X */ - /* ------------------------------------------------------------------ */ - - DEBUG (for (i = 0 ; i < nrow ; i++) ASSERT (W [i] == 0)) ; - - /* this is faster than stride-d, but requires O(nrow) workspace */ - for (j = 0 ; j < ncol ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - W [i] += abs_value (xtype, Xx, Xz, i+j*d, Common) ; - } - } - for (i = 0 ; i < nrow ; i++) - { - s = W [i] ; - if ((isnan (s) || s > xnorm) && !isnan (xnorm)) - { - xnorm = s ; - } - W [i] = 0 ; - } + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + xnorm = cs_cholmod_norm_dense_worker (X, norm, W) ; + break ; - } - else if (norm == 0) - { + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + xnorm = zs_cholmod_norm_dense_worker (X, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* infinity-norm = max row sum, using stride-d access of X */ - /* ------------------------------------------------------------------ */ - - for (i = 0 ; i < nrow ; i++) - { - s = 0 ; - for (j = 0 ; j < ncol ; j++) - { - s += abs_value (xtype, Xx, Xz, i+j*d, Common) ; - } - if ((isnan (s) || s > xnorm) && !isnan (xnorm)) - { - xnorm = s ; - } - } + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + xnorm = rd_cholmod_norm_dense_worker (X, norm, W) ; + break ; - } - else if (norm == 1) - { + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + xnorm = cd_cholmod_norm_dense_worker (X, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* 1-norm = max column sum */ - /* ------------------------------------------------------------------ */ - - for (j = 0 ; j < ncol ; j++) - { - s = 0 ; - for (i = 0 ; i < nrow ; i++) - { - s += abs_value (xtype, Xx, Xz, i+j*d, Common) ; - } - if ((isnan (s) || s > xnorm) && !isnan (xnorm)) - { - xnorm = s ; - } - } - } - else - { - - /* ------------------------------------------------------------------ */ - /* 2-norm = sqrt (sum (X.^2)) */ - /* ------------------------------------------------------------------ */ - - switch (xtype) - { - - case CHOLMOD_REAL: - for (i = 0 ; i < nrow ; i++) - { - x = Xx [i] ; - xnorm += x*x ; - } - break ; - - case CHOLMOD_COMPLEX: - for (i = 0 ; i < nrow ; i++) - { - x = Xx [2*i ] ; - z = Xx [2*i+1] ; - xnorm += x*x + z*z ; - } - break ; - - case CHOLMOD_ZOMPLEX: - for (i = 0 ; i < nrow ; i++) - { - x = Xx [i] ; - z = Xz [i] ; - xnorm += x*x + z*z ; - } - break ; - } - - xnorm = sqrt (xnorm) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + xnorm = zd_cholmod_norm_dense_worker (X, norm, W) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* return result */ - /* ---------------------------------------------------------------------- */ - return (xnorm) ; } +//------------------------------------------------------------------------------ +// cholmod_norm_sparse +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_norm_sparse ================================================== */ -/* ========================================================================== */ - -double CHOLMOD(norm_sparse) +double CHOLMOD(norm_sparse) // returns norm (A) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to compute the norm of */ - int norm, /* type of norm: 0: inf. norm, 1: 1-norm */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm cholmod_common *Common ) { - double anorm, s ; - double *Ax, *Az, *W ; - Int *Ap, *Ai, *Anz ; - Int i, j, p, pend, nrow, ncol, packed, xtype ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - ncol = A->ncol ; - nrow = A->nrow ; if (norm < 0 || norm > 1) { - ERROR (CHOLMOD_INVALID, "invalid norm") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "invalid norm") ; + return (EMPTY) ; } - if (A->stype && nrow != ncol) + if (A->stype && A->nrow != A->ncol) { - ERROR (CHOLMOD_INVALID, "matrix invalid") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "matrix invalid") ; + return (EMPTY) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - Anz = A->nz ; - packed = A->packed ; - xtype = A->xtype ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace, if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace, if needed + //-------------------------------------------------------------------------- - W = NULL ; + double *W = NULL ; if (A->stype || norm == 0) { - CHOLMOD(allocate_work) (0, 0, nrow, Common) ; - W = Common->Xwork ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (EMPTY) ; - } - DEBUG (for (i = 0 ; i < nrow ; i++) ASSERT (W [i] == 0)) ; + CHOLMOD(alloc_work) (0, 0, A->nrow, CHOLMOD_DOUBLE, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (EMPTY) ; + } + W = (double *) (Common->Xwork) ; + DEBUG (for (Int i = 0 ; i < A->nrow ; i++) ASSERT (W [i] == 0)) ; } - /* ---------------------------------------------------------------------- */ - /* compute the norm */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compute the norm + //-------------------------------------------------------------------------- - anorm = 0 ; + double anorm = 0 ; - if (A->stype > 0) + switch ((A->xtype + A->dtype) % 8) { - /* ------------------------------------------------------------------ */ - /* A is symmetric with upper triangular part stored */ - /* ------------------------------------------------------------------ */ - - /* infinity-norm = 1-norm = max row/col sum */ - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - s = abs_value (xtype, Ax, Az, p, Common) ; - if (i == j) - { - W [i] += s ; - } - else if (i < j) - { - W [i] += s ; - W [j] += s ; - } - } - } + default: + anorm = p_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - } - else if (A->stype < 0) - { + case CHOLMOD_SINGLE + CHOLMOD_REAL: + anorm = rs_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* A is symmetric with lower triangular part stored */ - /* ------------------------------------------------------------------ */ - - /* infinity-norm = 1-norm = max row/col sum */ - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - s = abs_value (xtype, Ax, Az, p, Common) ; - if (i == j) - { - W [i] += s ; - } - else if (i > j) - { - W [i] += s ; - W [j] += s ; - } - } - } + case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: + anorm = cs_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - } - else if (norm == 0) - { + case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: + anorm = zs_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* A is unsymmetric, compute the infinity-norm */ - /* ------------------------------------------------------------------ */ - - /* infinity-norm = max row sum */ - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - W [Ai [p]] += abs_value (xtype, Ax, Az, p, Common) ; - } - } + case CHOLMOD_DOUBLE + CHOLMOD_REAL: + anorm = rd_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - } - else - { + case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: + anorm = cd_cholmod_norm_sparse_worker (A, norm, W) ; + break ; - /* ------------------------------------------------------------------ */ - /* A is unsymmetric, compute the 1-norm */ - /* ------------------------------------------------------------------ */ - - /* 1-norm = max column sum */ - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - if (xtype == CHOLMOD_PATTERN) - { - s = pend - p ; - } - else - { - s = 0 ; - for ( ; p < pend ; p++) - { - s += abs_value (xtype, Ax, Az, p, Common) ; - } - } - if ((isnan (s) || s > anorm) && !isnan (anorm)) - { - anorm = s ; - } - } + case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: + anorm = zd_cholmod_norm_sparse_worker (A, norm, W) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* compute the max row sum */ - /* ---------------------------------------------------------------------- */ - - if (A->stype || norm == 0) - { - for (i = 0 ; i < nrow ; i++) - { - s = W [i] ; - if ((isnan (s) || s > anorm) && !isnan (anorm)) - { - anorm = s ; - } - W [i] = 0 ; - } - } - - /* ---------------------------------------------------------------------- */ - /* return result */ - /* ---------------------------------------------------------------------- */ - return (anorm) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_scale.c b/CHOLMOD/MatrixOps/cholmod_scale.c index 50dc6e4e24..3b7f571cfa 100644 --- a/CHOLMOD/MatrixOps/cholmod_scale.c +++ b/CHOLMOD/MatrixOps/cholmod_scale.c @@ -2,214 +2,181 @@ // CHOLMOD/MatrixOps/cholmod_scale: scale a sparse matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* scale a matrix: A = diag(s)*A, A*diag(s), s*A, or diag(s)*A*diag(s) - * - * A can be of any type (packed/unpacked, upper/lower/unsymmetric). - * The symmetry of A is ignored; all entries in the matrix are modified. - * - * If A is m-by-n unsymmetric but scaled symmtrically, the result is - * A = diag (s (1:m)) * A * diag (s (1:n)). - * - * Note: diag(s) should be interpretted as spdiags(s,0,n,n) where n=length(s). - * - * Row or column scaling of a symmetric matrix still results in a symmetric - * matrix, since entries are still ignored by other routines. - * For example, when row-scaling a symmetric matrix where just the upper - * triangular part is stored (and lower triangular entries ignored) - * A = diag(s)*triu(A) is performed, where the result A is also - * symmetric-upper. This has the effect of modifying the implicit lower - * triangular part. In MATLAB notation: - * - * U = diag(s)*triu(A) ; - * L = tril (U',-1) - * A = L + U ; - * - * The scale parameter determines the kind of scaling to perform: - * - * CHOLMOD_SCALAR: s[0]*A - * CHOLMOD_ROW: diag(s)*A - * CHOLMOD_COL: A*diag(s) - * CHOLMOD_SYM: diag(s)*A*diag(s) - * - * The size of S depends on the scale parameter: - * - * CHOLMOD_SCALAR: size 1 - * CHOLMOD_ROW: size nrow-by-1 or 1-by-nrow - * CHOLMOD_COL: size ncol-by-1 or 1-by-ncol - * CHOLMOD_SYM: size max(nrow,ncol)-by-1, or 1-by-max(nrow,ncol) - * - * workspace: none - * - * Only real matrices are supported. - */ +// scale a matrix: A = diag(s)*A, A*diag(s), s*A, or diag(s)*A*diag(s) +// +// A can be of any type (packed/unpacked, upper/lower/unsymmetric). +// The symmetry of A is ignored; all entries in the matrix are modified. +// +// If A is m-by-n unsymmetric but scaled symmtrically, the result is +// A = diag (s (1:m)) * A * diag (s (1:n)). +// +// Note: diag(s) should be interpretted as spdiags(s,0,n,n) where n=length(s). +// +// Row or column scaling of a symmetric matrix still results in a symmetric +// matrix, since entries are still ignored by other routines. +// For example, when row-scaling a symmetric matrix where just the upper +// triangular part is stored (and lower triangular entries ignored) +// A = diag(s)*triu(A) is performed, where the result A is also +// symmetric-upper. This has the effect of modifying the implicit lower +// triangular part. In MATLAB notation: +// +// U = diag(s)*triu(A) ; +// L = tril (U',-1) +// A = L + U ; +// +// The scale parameter determines the kind of scaling to perform: +// +// CHOLMOD_SCALAR: s[0]*A +// CHOLMOD_ROW: diag(s)*A +// CHOLMOD_COL: A*diag(s) +// CHOLMOD_SYM: diag(s)*A*diag(s) +// +// The size of S depends on the scale parameter: +// +// CHOLMOD_SCALAR: size 1 +// CHOLMOD_ROW: size nrow-by-1 or 1-by-nrow +// CHOLMOD_COL: size ncol-by-1 or 1-by-ncol +// CHOLMOD_SYM: size max(nrow,ncol)-by-1, or 1-by-max(nrow,ncol) +// +// workspace: none +// +// Real, complex, and zomplex matrices are supported, of any dtype. +// The xtype and dtype of A and S must match. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === cholmod_scale ======================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_scale_worker +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_scale_worker.c" +#define COMPLEX +#include "t_cholmod_scale_worker.c" +#define ZOMPLEX +#include "t_cholmod_scale_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_scale_worker.c" +#define COMPLEX +#include "t_cholmod_scale_worker.c" +#define ZOMPLEX +#include "t_cholmod_scale_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_scale +//------------------------------------------------------------------------------ int CHOLMOD(scale) ( - /* ---- input ---- */ - cholmod_dense *S, /* scale factors (scalar or vector) */ - int scale, /* type of scaling to compute */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to scale */ - /* --------------- */ + // input: + cholmod_dense *S, // scale factors (scalar or vector) + int scale, // type of scaling to compute + // input/output: + cholmod_sparse *A, // matrix to scale cholmod_common *Common ) { - double t ; - double *Ax, *s ; - Int *Ap, *Anz, *Ai ; - Int packed, j, ncol, nrow, p, pend, sncol, snrow, nn, ok ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (S, FALSE) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - RETURN_IF_XTYPE_INVALID (S, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - ncol = A->ncol ; - nrow = A->nrow ; - sncol = S->ncol ; - snrow = S->nrow ; + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; + RETURN_IF_XTYPE_INVALID (S, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; + if (A->xtype != S->xtype || A->dtype != S->dtype) + { + ERROR (CHOLMOD_INVALID, "xtype and dtype of A and S must match") ; + return (FALSE) ; + } + + Int ncol = A->ncol ; + Int nrow = A->nrow ; + Int sncol = S->ncol ; + Int snrow = S->nrow ; + bool ok ; + if (scale == CHOLMOD_SCALAR) { - ok = (snrow == 1 && sncol == 1) ; + ok = (snrow == 1 && sncol == 1) ; } else if (scale == CHOLMOD_ROW) { - ok = (snrow == nrow && sncol == 1) || (snrow == 1 && sncol == nrow) ; + ok = (snrow == nrow && sncol == 1) || (snrow == 1 && sncol == nrow) ; } else if (scale == CHOLMOD_COL) { - ok = (snrow == ncol && sncol == 1) || (snrow == 1 && sncol == ncol) ; + ok = (snrow == ncol && sncol == 1) || (snrow == 1 && sncol == ncol) ; } else if (scale == CHOLMOD_SYM) { - nn = MAX (nrow, ncol) ; - ok = (snrow == nn && sncol == 1) || (snrow == 1 && sncol == nn) ; + Int nn = MAX (nrow, ncol) ; + ok = (snrow == nn && sncol == 1) || (snrow == 1 && sncol == nn) ; } else { - /* scale invalid */ - ERROR (CHOLMOD_INVALID, "invalid scaling option") ; - return (FALSE) ; + // scale invalid + ERROR (CHOLMOD_INVALID, "invalid scaling option") ; + return (FALSE) ; } if (!ok) { - /* S is wrong size */ - ERROR (CHOLMOD_INVALID, "invalid scale factors") ; - return (FALSE) ; + // S is wrong size + ERROR (CHOLMOD_INVALID, "invalid scale factors") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // scale the matrix + //-------------------------------------------------------------------------- - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - packed = A->packed ; - s = S->x ; - - /* ---------------------------------------------------------------------- */ - /* scale the matrix */ - /* ---------------------------------------------------------------------- */ - - if (scale == CHOLMOD_ROW) + switch ((A->xtype + A->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_scale_worker (S, scale, A) ; + break ; - /* ------------------------------------------------------------------ */ - /* A = diag(s)*A, row scaling */ - /* ------------------------------------------------------------------ */ + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_scale_worker (S, scale, A) ; + break ; - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - Ax [p] *= s [Ai [p]] ; - } - } + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_scale_worker (S, scale, A) ; + break ; - } - else if (scale == CHOLMOD_COL) - { - - /* ------------------------------------------------------------------ */ - /* A = A*diag(s), column scaling */ - /* ------------------------------------------------------------------ */ - - for (j = 0 ; j < ncol ; j++) - { - t = s [j] ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - Ax [p] *= t ; - } - } - - } - else if (scale == CHOLMOD_SYM) - { - - /* ------------------------------------------------------------------ */ - /* A = diag(s)*A*diag(s), symmetric scaling */ - /* ------------------------------------------------------------------ */ - - for (j = 0 ; j < ncol ; j++) - { - t = s [j] ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - Ax [p] *= t * s [Ai [p]] ; - } - } + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_scale_worker (S, scale, A) ; + break ; - } - else if (scale == CHOLMOD_SCALAR) - { + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_scale_worker (S, scale, A) ; + break ; - /* ------------------------------------------------------------------ */ - /* A = s[0] * A, scalar scaling */ - /* ------------------------------------------------------------------ */ - - t = s [0] ; - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - Ax [p] *= t ; - } - } + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_scale_worker (S, scale, A) ; + break ; } ASSERT (CHOLMOD(dump_sparse) (A, "A scaled", Common) >= 0) ; return (TRUE) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_sdmult.c b/CHOLMOD/MatrixOps/cholmod_sdmult.c index 6e66448fd6..708b48b268 100644 --- a/CHOLMOD/MatrixOps/cholmod_sdmult.c +++ b/CHOLMOD/MatrixOps/cholmod_sdmult.c @@ -2,75 +2,80 @@ // CHOLMOD/MatrixOps/cholmod_sdmult: sparse-times-dense matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Sparse matrix times dense matrix: - * Y = alpha*(A*X) + beta*Y or Y = alpha*(A'*X) + beta*Y, - * where A is sparse and X and Y are dense. - * - * when using A, X has A->ncol columns and Y has A->nrow rows - * when using A', X has A->nrow columns and Y has A->ncol rows - * - * workspace: none in Common. Temporary workspace of size 4*(X->nrow) is used - * if A is stored in symmetric form and X has four columns or more. If the - * workspace is not available, a slower method is used instead that requires - * no workspace. - * - * transpose = 0: use A - * otherwise, use A' (complex conjugate transpose) - * - * transpose is ignored if the matrix is symmetric or Hermitian. - * (the array transpose A.' is not supported). - * - * Supports real, complex, and zomplex matrices, but the xtypes of A, X, and Y - * must all match. - */ +// Sparse matrix times dense matrix: +// Y = alpha*(A*X) + beta*Y or Y = alpha*(A'*X) + beta*Y, +// where A is sparse and X and Y are dense. +// +// when using A, X has A->ncol columns and Y has A->nrow rows +// when using A', X has A->nrow columns and Y has A->ncol rows +// +// workspace: none in Common. Temporary workspace of size 4*(X->nrow) is used +// if A is stored in symmetric form and X has four columns or more. If the +// workspace is not available, a slower method is used instead that requires +// no workspace. +// +// transpose = 0: use A +// otherwise, use A' (complex conjugate transpose) +// +// transpose is ignored if the matrix is symmetric or Hermitian. +// (the array transpose A.' is not supported). +// +// Supports real, complex, and zomplex matrices, but the xtypes and dtypes of +// A, X, and Y must all match. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === TEMPLATE ============================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_sdmult_worker +//------------------------------------------------------------------------------ +#define DOUBLE #define REAL -#include "t_cholmod_sdmult.c" +#include "t_cholmod_sdmult_worker.c" #define COMPLEX -#include "t_cholmod_sdmult.c" +#include "t_cholmod_sdmult_worker.c" #define ZOMPLEX -#include "t_cholmod_sdmult.c" +#include "t_cholmod_sdmult_worker.c" -/* ========================================================================== */ -/* === cholmod_sdmult ======================================================= */ -/* ========================================================================== */ +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_sdmult_worker.c" +#define COMPLEX +#include "t_cholmod_sdmult_worker.c" +#define ZOMPLEX +#include "t_cholmod_sdmult_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_sdmult +//------------------------------------------------------------------------------ int CHOLMOD(sdmult) ( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to multiply */ - int transpose, /* use A if 0, otherwise use A' */ - double alpha [2], /* scale factor for A */ - double beta [2], /* scale factor for Y */ - cholmod_dense *X, /* dense matrix to multiply */ - /* ---- in/out --- */ - cholmod_dense *Y, /* resulting dense matrix */ - /* --------------- */ + // input: + cholmod_sparse *A, // sparse matrix to multiply + int transpose, // use A if 0, otherwise use A' + double alpha [2], // scale factor for A + double beta [2], // scale factor for Y + cholmod_dense *X, // dense matrix to multiply + // input/output: + cholmod_dense *Y, // resulting dense matrix cholmod_common *Common ) { - double *w ; - size_t nx, ny ; - Int e ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -79,69 +84,92 @@ int CHOLMOD(sdmult) RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (Y, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; - ny = transpose ? A->ncol : A->nrow ; /* required length of Y */ - nx = transpose ? A->nrow : A->ncol ; /* required length of X */ + size_t ny = transpose ? A->ncol : A->nrow ; // required length of Y + size_t nx = transpose ? A->nrow : A->ncol ; // required length of X if (X->nrow != nx || X->ncol != Y->ncol || Y->nrow != ny) { - /* X and/or Y have the wrong dimension */ - ERROR (CHOLMOD_INVALID, "X and/or Y have wrong dimensions") ; - return (FALSE) ; + // X and/or Y have the wrong dimension + ERROR (CHOLMOD_INVALID, "X and/or Y have wrong dimensions") ; + return (FALSE) ; } - if (A->xtype != X->xtype || A->xtype != Y->xtype) + if (A->xtype != X->xtype || A->xtype != Y->xtype || + A->dtype != X->dtype || A->dtype != Y->dtype) { - ERROR (CHOLMOD_INVALID, "A, X, and Y must have same xtype") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "A, X, and Y must have same xtype and dtype") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace, if required */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace, if required + //-------------------------------------------------------------------------- + + void *w = NULL ; + size_t e = (A->dtype == CHOLMOD_SINGLE) ? sizeof (float) : sizeof (double) ; + size_t ex = e * ((A->xtype == CHOLMOD_REAL) ? 1 : 2) ; - w = NULL ; - e = (A->xtype == CHOLMOD_REAL ? 1:2) ; if (A->stype && X->ncol >= 4) { - w = CHOLMOD(malloc) (nx, 4*e*sizeof (double), Common) ; + w = CHOLMOD(malloc) (4*nx, ex, Common) ; } if (Common->status < CHOLMOD_OK) { - return (FALSE) ; /* out of memory */ + return (FALSE) ; // out of memory } - /* ---------------------------------------------------------------------- */ - /* Y = alpha*op(A)*X + beta*Y via template routine */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // Y = alpha*op(A)*X + beta*Y via template routine + //-------------------------------------------------------------------------- ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ; DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ; DEBUG (if ((beta [0] != 0) - || ((beta [1] != 0) && A->xtype != CHOLMOD_REAL)) - CHOLMOD(dump_dense) (Y, "Y", Common)) ; + || ((beta [1] != 0) && A->xtype != CHOLMOD_REAL)) + CHOLMOD(dump_dense) (Y, "Y", Common)) ; - switch (A->xtype) + float s_alpha [2] ; + s_alpha [0] = (float) alpha [0] ; + s_alpha [1] = (float) alpha [1] ; + float s_beta [2] ; + s_beta [0] = (float) beta [0] ; + s_beta [1] = (float) beta [1] ; + + switch ((A->xtype + A->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_sdmult_worker (A, transpose, s_alpha, s_beta, X, Y, w) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_sdmult_worker (A, transpose, s_alpha, s_beta, X, Y, w) ; + break ; - case CHOLMOD_REAL: - r_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ; - break ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_sdmult_worker (A, transpose, s_alpha, s_beta, X, Y, w) ; + break ; - case CHOLMOD_COMPLEX: - c_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ; - break ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_sdmult_worker (A, transpose, alpha, beta, X, Y, w) ; + break ; - case CHOLMOD_ZOMPLEX: - z_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ; - break ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_sdmult_worker (A, transpose, alpha, beta, X, Y, w) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_sdmult_worker (A, transpose, alpha, beta, X, Y, w) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- - CHOLMOD(free) (4*nx, e*sizeof (double), w, Common) ; + CHOLMOD(free) (4*nx, ex, w, Common) ; DEBUG (CHOLMOD(dump_dense) (Y, "Y", Common)) ; return (TRUE) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_ssmult.c b/CHOLMOD/MatrixOps/cholmod_ssmult.c index 17a40a60ab..37ed563080 100644 --- a/CHOLMOD/MatrixOps/cholmod_ssmult.c +++ b/CHOLMOD/MatrixOps/cholmod_ssmult.c @@ -2,486 +2,343 @@ // CHOLMOD/MatrixOps/cholmod_ssmult: sparse-times-sparse matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* C = A*B. Multiply two sparse matrices. - * - * A and B can be packed or unpacked, sorted or unsorted, and of any stype. - * If A or B are symmetric, an internal unsymmetric copy is made first, however. - * C is computed as if A and B are unsymmetric, and then if the stype input - * parameter requests a symmetric form (upper or lower) the matrix is converted - * into that form. - * - * C is returned as packed, and either unsorted or sorted, depending on the - * "sorted" input parameter. If C is returned sorted, then either C = (B'*A')' - * or C = (A*B)'' is computed, depending on the number of nonzeros in A, B, and - * C. - * - * workspace: - * if C unsorted: Flag (A->nrow), W (A->nrow) if values - * if C sorted: Flag (B->ncol), W (B->ncol) if values - * Iwork (max (A->ncol, A->nrow, B->nrow, B->ncol)) - * allocates temporary copies for A, B, and C, if required. - * - * Only pattern and real matrices are supported. Complex and zomplex matrices - * are supported only when the numerical values are not computed ("values" - * is FALSE). - */ +// C = A*B. Multiply two sparse matrices. +// +// A and B can be packed or unpacked, sorted or unsorted, and of any stype. If +// A or B are symmetric, an internal unsymmetric copy is made first, however. +// For the complex case, if A and/or B are symmetric with just their lower or +// upper part stored, they are assumed to be Hermitian when converted. +// +// C is computed as if A and B are unsymmetric, and then if the stype input +// parameter requests a symmetric form (upper or lower) the matrix is converted +// into that form. +// +// C is returned as packed, and either unsorted or sorted, depending on the +// "sorted" input parameter. If C is returned sorted, then either C = (B'*A')' +// or C = (A*B)'' is computed, depending on the number of nonzeros in A, B, and +// C. +// +// workspace: +// if C unsorted: Flag (A->nrow), W (A->nrow) if values +// if C sorted: Flag (B->ncol), W (B->ncol) if values +// Iwork (max (A->ncol, A->nrow, B->nrow, B->ncol)) +// allocates temporary copies for A, B, and C, if required. +// +// Matrices of any xtype and dtype supported, but the xtype and dtype of +// A and B must match (unless mode is zero). #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === cholmod_ssmult ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_ssmult_worker template +//------------------------------------------------------------------------------ + +#define PATTERN +#include "t_cholmod_ssmult_worker.c" + +#define DOUBLE +#define REAL +#include "t_cholmod_ssmult_worker.c" +#define COMPLEX +#include "t_cholmod_ssmult_worker.c" +#define ZOMPLEX +#include "t_cholmod_ssmult_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_ssmult_worker.c" +#define COMPLEX +#include "t_cholmod_ssmult_worker.c" +#define ZOMPLEX +#include "t_cholmod_ssmult_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_ssmult +//------------------------------------------------------------------------------ -cholmod_sparse *CHOLMOD(ssmult) +cholmod_sparse *CHOLMOD(ssmult) // return C=A*B ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to multiply */ - cholmod_sparse *B, /* right matrix to multiply */ - int stype, /* requested stype of C */ - int values, /* TRUE: do numerical values, FALSE: pattern only */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // left matrix to multiply + cholmod_sparse *B, // right matrix to multiply + int stype, // requested stype of C + int mode, // 2: numerical (conj) if A and/or B are symmetric + // 1: numerical (non-conj.) if A and/or B are symmetric + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) { - double bjt ; - double *Ax, *Bx, *Cx, *W ; - Int *Ap, *Anz, *Ai, *Bp, *Bnz, *Bi, *Cp, *Ci, *Flag ; - cholmod_sparse *C, *A2, *B2, *A3, *B3, *C2 ; - Int apacked, bpacked, j, i, pa, paend, pb, pbend, ncol, mark, cnz, t, p, - nrow, anz, bnz, do_swap_and_transpose, n1, n2 ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + cholmod_sparse *C = NULL, *A2 = NULL, *B2 = NULL, *C2 = NULL ; RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; - values = values && - (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; - RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN || B->xtype == CHOLMOD_PATTERN) + { + mode = 0 ; + } + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; + RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->ncol != B->nrow) { - /* inner dimensions must agree */ - ERROR (CHOLMOD_INVALID, "A and B inner dimensions must match") ; - return (NULL) ; + // inner dimensions must agree + ERROR (CHOLMOD_INVALID, "A and B inner dimensions must match") ; + return (NULL) ; + } + + bool values = (mode != 0) ; + if (values && (A->xtype != B->xtype || A->dtype != B->dtype)) + { + // A and B must have the same numerical type if mode != 0 + ERROR (CHOLMOD_INVALID, "A and B must have the same xtype and dtype") ; + return (NULL) ; } - /* A and B must have the same numerical type if values is TRUE (both must - * be CHOLMOD_REAL, this is implicitly checked above) */ + Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- if (A->nrow <= 1) { - /* C will be implicitly sorted, so no need to sort it here */ - sorted = FALSE ; + // C will be implicitly sorted, so no need to sort it here + sorted = FALSE ; } + size_t n1 ; if (sorted) { - n1 = MAX (A->nrow, B->ncol) ; + n1 = MAX (A->nrow, B->ncol) ; } else { - n1 = A->nrow ; + n1 = A->nrow ; } - n2 = MAX4 (A->ncol, A->nrow, B->nrow, B->ncol) ; - CHOLMOD(allocate_work) (n1, n2, values ? n1 : 0, Common) ; + size_t n2 = (size_t) MAX4 (A->ncol, A->nrow, B->nrow, B->ncol) ; + size_t nw = ((A->xtype >= CHOLMOD_COMPLEX) ? 2 : 1) * (values ? n1 : 0) ; + CHOLMOD(alloc_work) (n1, n2, nw, A->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (NULL) ; + // out of memory + return (NULL) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1 : 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - /* convert A to unsymmetric, if necessary */ + // convert A to unsymmetric, if necessary A2 = NULL ; B2 = NULL ; if (A->stype) { - /* workspace: Iwork (max (A->nrow,A->ncol)) */ - A2 = CHOLMOD(copy) (A, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; - return (NULL) ; - } - A = A2 ; + // workspace: Iwork (max (A->nrow,A->ncol)) + A2 = CHOLMOD(copy) (A, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; + return (NULL) ; + } + A = A2 ; } - /* convert B to unsymmetric, if necessary */ + // convert B to unsymmetric, if necessary if (B->stype) { - /* workspace: Iwork (max (B->nrow,B->ncol)) */ - B2 = CHOLMOD(copy) (B, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; - return (NULL) ; - } - B = B2 ; + // workspace: Iwork (max (B->nrow,B->ncol)) + B2 = CHOLMOD(copy) (B, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; + return (NULL) ; + } + B = B2 ; } ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ; ASSERT (CHOLMOD(dump_sparse) (B, "B", Common) >= 0) ; - /* get the A matrix */ - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - apacked = A->packed ; - - /* get the B matrix */ - Bp = B->p ; - Bnz = B->nz ; - Bi = B->i ; - Bx = B->x ; - bpacked = B->packed ; - - /* get the size of C */ - nrow = A->nrow ; - ncol = B->ncol ; - - /* get workspace */ - W = Common->Xwork ; /* size nrow, unused if values is FALSE */ - Flag = Common->Flag ; /* size nrow, Flag [0..nrow-1] < mark on input*/ - - /* ---------------------------------------------------------------------- */ - /* count the number of entries in the result C */ - /* ---------------------------------------------------------------------- */ - - cnz = 0 ; - for (j = 0 ; j < ncol ; j++) + // get the A matrix + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + bool apacked = A->packed ; + + // get the B matrix + Int *Bp = B->p ; + Int *Bnz = B->nz ; + Int *Bi = B->i ; + bool bpacked = B->packed ; + + // get the size of C + Int nrow = A->nrow ; + Int ncol = B->ncol ; + + // get workspace + void *W = Common->Xwork ; // size nrow, unused if values is false + Int *Flag = Common->Flag ; // size nrow, Flag [0..nrow-1] < mark on input + + //-------------------------------------------------------------------------- + // count the number of entries in the result C + //-------------------------------------------------------------------------- + + int ok = TRUE ; + size_t cnz = 0 ; + size_t cnzmax = SIZE_MAX - A->nrow ; + for (Int j = 0 ; ok && (j < ncol) ; j++) { - /* clear the Flag array */ - /* mark = CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - - /* for each nonzero B(t,j) in column j, do: */ - pb = Bp [j] ; - pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; - for ( ; pb < pbend ; pb++) - { - /* B(t,j) is nonzero */ - t = Bi [pb] ; - - /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */ - pa = Ap [t] ; - paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ; - for ( ; pa < paend ; pa++) - { - i = Ai [pa] ; - if (Flag [i] != mark) - { - Flag [i] = mark ; - cnz++ ; - } - } - } - if (cnz < 0) - { - break ; /* integer overflow case */ - } + // clear the Flag array + CLEAR_FLAG (Common) ; + Int mark = Common->mark ; + + // for each nonzero B(k,j) in column j, do: + Int pb = Bp [j] ; + Int pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; + for ( ; pb < pbend ; pb++) + { + // B(k,j) is nonzero + Int k = Bi [pb] ; + + // add the nonzero pattern of A(:,k) to the pattern of C(:,j) + Int pa = Ap [k] ; + Int paend = (apacked) ? (Ap [k+1]) : (pa + Anz [k]) ; + for ( ; pa < paend ; pa++) + { + Int i = Ai [pa] ; + if (Flag [i] != mark) + { + Flag [i] = mark ; + cnz++ ; + } + } + } + ok = (cnz < cnzmax) ; } - /* mark = CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - mark = Common->mark ; - /* ---------------------------------------------------------------------- */ - /* check for integer overflow */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate C + //-------------------------------------------------------------------------- - if (cnz < 0) + C = CHOLMOD(allocate_sparse) (nrow, ncol, ok ? cnz : SIZE_MAX, FALSE, TRUE, + 0, (values ? A->xtype : CHOLMOD_PATTERN) + A->dtype, Common) ; + if (Common->status < CHOLMOD_OK) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; - return (NULL) ; + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + CHOLMOD(free_sparse) (&B2, Common) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* Determine how to return C sorted (if requested) */ - /* ---------------------------------------------------------------------- */ + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; - do_swap_and_transpose = FALSE ; + //-------------------------------------------------------------------------- + // C = A*B + //-------------------------------------------------------------------------- - if (sorted) + switch ((C->xtype + C->dtype) % 8) { - /* Determine the best way to return C with sorted columns. Computing - * C = (B'*A')' takes cnz + anz + bnz time (ignoring O(n) terms). - * Sorting C when done, C = (A*B)'', takes 2*cnz time. Pick the one - * with the least amount of work. */ - - anz = CHOLMOD(nnz) (A, Common) ; - bnz = CHOLMOD(nnz) (B, Common) ; - - do_swap_and_transpose = (anz + bnz < cnz) ; - - if (do_swap_and_transpose) - { - - /* -------------------------------------------------------------- */ - /* C = (B'*A')' */ - /* -------------------------------------------------------------- */ - - /* workspace: Iwork (A->nrow) */ - A3 = CHOLMOD(ptranspose) (A, values, NULL, NULL, 0, Common) ; - CHOLMOD(free_sparse) (&A2, Common) ; - A2 = A3 ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)); - return (NULL) ; - } - /* workspace: Iwork (B->nrow) */ - B3 = CHOLMOD(ptranspose) (B, values, NULL, NULL, 0, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - B2 = B3 ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)); - return (NULL) ; - } - A = B2 ; - B = A2 ; - - /* get the new A matrix */ - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - apacked = A->packed ; - - /* get the new B matrix */ - Bp = B->p ; - Bnz = B->nz ; - Bi = B->i ; - Bx = B->x ; - bpacked = B->packed ; - - /* get the size of C' */ - nrow = A->nrow ; - ncol = B->ncol ; - } - } - - /* ---------------------------------------------------------------------- */ - /* allocate C */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(allocate_sparse) (nrow, ncol, cnz, FALSE, TRUE, 0, - values ? A->xtype : CHOLMOD_PATTERN, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; - return (NULL) ; - } - - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; + default: + p_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - /* ---------------------------------------------------------------------- */ - /* C = A*B */ - /* ---------------------------------------------------------------------- */ + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - cnz = 0 ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - if (values) - { + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - /* pattern and values */ - for (j = 0 ; j < ncol ; j++) - { - /* clear the Flag array */ - /* mark = CHOLMOD(clear_flag (Common)) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - - /* start column j of C */ - Cp [j] = cnz ; - - /* for each nonzero B(t,j) in column j, do: */ - pb = Bp [j] ; - pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; - for ( ; pb < pbend ; pb++) - { - /* B(t,j) is nonzero */ - t = Bi [pb] ; - bjt = Bx [pb] ; - - /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) - * and scatter the values into W */ - pa = Ap [t] ; - paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ; - for ( ; pa < paend ; pa++) - { - i = Ai [pa] ; - if (Flag [i] != mark) - { - Flag [i] = mark ; - Ci [cnz++] = i ; - } - W [i] += Ax [pa] * bjt ; - } - } - - /* gather the values into C(:,j) */ - for (p = Cp [j] ; p < cnz ; p++) - { - i = Ci [p] ; - Cx [p] = W [i] ; - W [i] = 0 ; - } - } + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - } - else - { + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_ssmult_worker (C, A, B, Common) ; + break ; - /* pattern only */ - for (j = 0 ; j < ncol ; j++) - { - /* clear the Flag array */ - /* mark = CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - - /* start column j of C */ - Cp [j] = cnz ; - - /* for each nonzero B(t,j) in column j, do: */ - pb = Bp [j] ; - pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; - for ( ; pb < pbend ; pb++) - { - /* B(t,j) is nonzero */ - t = Bi [pb] ; - - /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */ - pa = Ap [t] ; - paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ; - for ( ; pa < paend ; pa++) - { - i = Ai [pa] ; - if (Flag [i] != mark) - { - Flag [i] = mark ; - Ci [cnz++] = i ; - } - } - } - } + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_ssmult_worker (C, A, B, Common) ; + break ; } - Cp [ncol] = cnz ; - ASSERT (MAX (1,cnz) == C->nzmax) ; - - /* ---------------------------------------------------------------------- */ - /* clear workspace and free temporary matrices */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear workspace and free temporary matrices + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; - /* CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; - /* ---------------------------------------------------------------------- */ - /* convert C to a symmetric upper/lower matrix if requested */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert C to a symmetric upper/lower matrix if requested + //-------------------------------------------------------------------------- - /* convert C in place, which cannot fail since no memory is allocated */ + // convert C in place, which cannot fail since no memory is allocated if (stype > 0) { - /* C = triu (C), in place */ - (void) CHOLMOD(band_inplace) (0, ncol, values, C, Common) ; - C->stype = 1 ; + // C = triu (C), in place + (void) CHOLMOD(band_inplace) (0, ncol, values, C, Common) ; + C->stype = 1 ; } else if (stype < 0) { - /* C = tril (C), in place */ - (void) CHOLMOD(band_inplace) (-nrow, 0, values, C, Common) ; - C->stype = -1 ; + // C = tril (C), in place + (void) CHOLMOD(band_inplace) (-nrow, 0, values, C, Common) ; + C->stype = -1 ; } ASSERT (Common->status >= CHOLMOD_OK) ; - /* ---------------------------------------------------------------------- */ - /* sort C, if requested */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // sort C, if requested + //-------------------------------------------------------------------------- if (sorted) { - if (do_swap_and_transpose) - { - /* workspace: Iwork (C->ncol), which is A->nrow since C=(B'*A') */ - C2 = CHOLMOD(ptranspose) (C, values, NULL, NULL, 0, Common) ; - CHOLMOD(free_sparse) (&C, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)); - return (NULL) ; - } - C = C2 ; - } - else - { - /* workspace: Iwork (max (C->nrow,C->ncol)) */ - if (!CHOLMOD(sort) (C, Common)) - { - /* out of memory */ - CHOLMOD(free_sparse) (&C, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)); - return (NULL) ; - } - } + // this cannot fail (no workspace; sort is done in-place) + CHOLMOD(sort) (C, Common) ; } - /* ---------------------------------------------------------------------- */ - /* return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- ASSERT (CHOLMOD(dump_sparse) (C, "ssmult", Common) >= 0) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, nw, A->dtype, Common)) ; return (C) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_submatrix.c b/CHOLMOD/MatrixOps/cholmod_submatrix.c index 9d0127c7bc..b699097b62 100644 --- a/CHOLMOD/MatrixOps/cholmod_submatrix.c +++ b/CHOLMOD/MatrixOps/cholmod_submatrix.c @@ -2,432 +2,439 @@ // CHOLMOD/MatrixOps/cholmod_submatrix: extract submatrix from a sparse matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* C = A (rset,cset), where C becomes length(rset)-by-length(cset) in dimension. - * rset and cset can have duplicate entries. A and C must be unsymmetric. C - * is packed. If the sorted flag is TRUE on input, or rset is sorted and A is - * sorted, then C is sorted; otherwise C is unsorted. - * - * A NULL rset or cset means "[ ]" in MATLAB notation. - * If the length of rset or cset is negative, it denotes ":" in MATLAB notation. - * - * For permuting a matrix, this routine is an alternative to cholmod_ptranspose - * (which permutes and transposes a matrix and can work on symmetric matrices). - * - * The time taken by this routine is O(A->nrow) if the Common workspace needs - * to be initialized, plus O(C->nrow + C->ncol + nnz (A (:,cset))). Thus, if C - * is small and the workspace is not initialized, the time can be dominated by - * the call to cholmod_allocate_work. However, once the workspace is - * allocated, subsequent calls take less time. - * - * workspace: Iwork (max (A->nrow + length (rset), length (cset))). - * allocates temporary copy of C if it is to be returned sorted. - * - * Future work: A common case occurs where A has sorted columns, and rset is in - * the form lo:hi in MATLAB notation. This routine could exploit that case - * to run even faster when the matrix is sorted, particularly when lo is small. - * - * Only pattern and real matrices are supported. Complex and zomplex matrices - * are supported only when "values" is FALSE. - */ +// C = A (rset,cset), where C becomes length(rset)-by-length(cset) in +// dimension. rset and cset can have duplicate entries. A can be symmetric; +// C is returned as unsymmetric. C is packed. If the sorted flag is TRUE on +// input, or rset is sorted and A is sorted, then C is sorted; otherwise C is +// unsorted. +// +// A NULL rset or cset means "[ ]" in MATLAB notation. +// If the length of rset or cset is negative, it denotes ":" in MATLAB notation. +// +// For permuting a matrix, this routine is an alternative to cholmod_ptranspose +// (which permutes and transposes a matrix and can work on symmetric matrices). +// +// The time taken by this routine is O(A->nrow) if the Common workspace needs +// to be initialized, plus O(C->nrow + C->ncol + nnz (A (:,cset))). Thus, if C +// is small and the workspace is not initialized, the time can be dominated by +// the call to cholmod_allocate_work. However, once the workspace is +// allocated, subsequent calls take less time. +// +// workspace: Iwork (max (A->nrow + length (rset), length (cset))). +// allocates temporary copy of C if it is to be returned sorted. +// +// Matrices of any xtype and dtype are supported. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === check_subset ========================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_submatrix_worker +//------------------------------------------------------------------------------ + +#define PATTERN +#include "t_cholmod_submatrix_worker.c" + +#define DOUBLE +#define REAL +#include "t_cholmod_submatrix_worker.c" +#define COMPLEX +#include "t_cholmod_submatrix_worker.c" +#define ZOMPLEX +#include "t_cholmod_submatrix_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_submatrix_worker.c" +#define COMPLEX +#include "t_cholmod_submatrix_worker.c" +#define ZOMPLEX +#include "t_cholmod_submatrix_worker.c" + +//------------------------------------------------------------------------------ +// check_subset +//------------------------------------------------------------------------------ -/* Check the rset or cset, and return TRUE if valid, FALSE if invalid */ +// Check the rset or cset, and return TRUE if valid, FALSE if invalid static int check_subset (Int *set, Int len, Int n) { Int k ; if (set == NULL) { - return (TRUE) ; + return (TRUE) ; } for (k = 0 ; k < len ; k++) { - if (set [k] < 0 || set [k] >= n) - { - return (FALSE) ; - } + if (set [k] < 0 || set [k] >= n) + { + return (FALSE) ; + } } return (TRUE) ; } +//------------------------------------------------------------------------------ +// cholmod_submatrix +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_submatrix ==================================================== */ -/* ========================================================================== */ - -cholmod_sparse *CHOLMOD(submatrix) +cholmod_sparse *CHOLMOD(submatrix) // return C = A (rset,cset) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to subreference */ - Int *rset, /* set of row indices, duplicates OK */ - int64_t rsize, /* size of rset, or -1 for ":" */ - Int *cset, /* set of column indices, duplicates OK */ - int64_t csize, /* size of cset, or -1 for ":" */ - int values, /* if TRUE compute the numerical values of C */ - int sorted, /* if TRUE then return C with sorted columns */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to subreference + Int *rset, // set of row indices, duplicates OK + int64_t rsize, // size of rset, or -1 for ":" + Int *cset, // set of column indices, duplicates OK + int64_t csize, // size of cset, or -1 for ":" + int mode, // 2: numerical (conj) if A is symmetric, + // 1: numerical (non-conj.) if A is symmetric + // 0: pattern + int sorted, // if TRUE then return C with sorted columns cholmod_common *Common ) { - double aij = 0 ; - double *Ax, *Cx ; - Int *Ap, *Ai, *Anz, *Ci, *Cp, *Head, *Rlen, *Rnext, *Iwork ; - cholmod_sparse *C ; - Int packed, ancol, anrow, cnrow, cncol, nnz, i, j, csorted, ilast, p, - pend, pdest, ci, cj, head, nr, nc ; - size_t s ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + cholmod_sparse *C = NULL, *A2 = NULL ; RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; - values = (values && (A->xtype != CHOLMOD_PATTERN)) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; - if (A->stype != 0) + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; + + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN) { - /* A must be unsymmetric */ - ERROR (CHOLMOD_INVALID, "symmetric upper or lower case not supported") ; - return (NULL) ; + mode = 0 ; } + bool values = (mode != 0) ; if (rsize > Int_max || csize > Int_max) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (NULL) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (NULL) ; } - Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get problem size + //-------------------------------------------------------------------------- - ancol = A->ncol ; - anrow = A->nrow ; - nr = (Int) rsize ; - nc = (Int) csize ; + Int ancol = A->ncol ; + Int anrow = A->nrow ; + Int nr = (Int) rsize ; + Int nc = (Int) csize ; if (rset == NULL) { - /* nr = 0 denotes rset = [ ], nr < 0 denotes rset = 0:anrow-1 */ - nr = (nr < 0) ? (-1) : 0 ; + // nr = 0 denotes rset = [ ], nr < 0 denotes rset = 0:anrow-1 + nr = (nr < 0) ? (-1) : 0 ; } if (cset == NULL) { - /* nr = 0 denotes cset = [ ], nr < 0 denotes cset = 0:ancol-1 */ - nc = (nc < 0) ? (-1) : 0 ; + // nr = 0 denotes cset = [ ], nr < 0 denotes cset = 0:ancol-1 + nc = (nc < 0) ? (-1) : 0 ; } - cnrow = (nr < 0) ? anrow : nr ; /* negative rset means rset = 0:anrow-1 */ - cncol = (nc < 0) ? ancol : nc ; /* negative cset means cset = 0:ancol-1 */ + Int cnrow = (nr < 0) ? anrow : nr ; // negative rset means rset = 0:anrow-1 + Int cncol = (nc < 0) ? ancol : nc ; // negative cset means cset = 0:ancol-1 + + //-------------------------------------------------------------------------- + // check for quick return + //-------------------------------------------------------------------------- if (nr < 0 && nc < 0) { - /* ------------------------------------------------------------------ */ - /* C = A (:,:), use cholmod_copy instead */ - /* ------------------------------------------------------------------ */ - - /* workspace: Iwork (max (C->nrow,C->ncol)) */ - PRINT1 (("submatrix C = A (:,:)\n")) ; - C = CHOLMOD(copy) (A, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (NULL) ; - } - return (C) ; + //---------------------------------------------------------------------- + // C = A (:,:), use cholmod_copy instead + //---------------------------------------------------------------------- + + // workspace: Iwork (max (C->nrow,C->ncol)) + PRINT1 (("submatrix C = A (:,:)\n")) ; + C = CHOLMOD(copy) (A, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + return (C) ; } + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- + PRINT1 (("submatrix nr "ID" nc "ID" Cnrow "ID" Cncol "ID"" - " Anrow "ID" Ancol "ID"\n", nr, nc, cnrow, cncol, anrow, ancol)) ; + " Anrow "ID" Ancol "ID"\n", nr, nc, cnrow, cncol, anrow, ancol)) ; - /* s = MAX3 (anrow+MAX(0,nr), cncol, cnrow) ; */ - s = CHOLMOD(add_size_t) (anrow, MAX (0,nr), &ok) ; + // s = MAX3 (anrow+MAX(0,nr), cncol, cnrow) ; + int ok = TRUE ; + size_t nr_size = (size_t) MAX (0, nr) ; + size_t s = CHOLMOD(add_size_t) (A->nrow, MAX (0, nr_size), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (NULL) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (NULL) ; } s = MAX3 (s, ((size_t) cncol), ((size_t) cnrow)) ; CHOLMOD(allocate_work) (anrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (NULL) ; + // out of memory + return (NULL) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - packed = A->packed ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Head = Common->Head ; /* size anrow */ - Iwork = Common->Iwork ; - Rlen = Iwork ; /* size anrow (i/i/l) */ - Rnext = Iwork + anrow ; /* size nr (i/i/l), not used if nr < 0 */ - - /* ---------------------------------------------------------------------- */ - /* construct inverse of rset and compute nnz (C) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check rset and cset + //-------------------------------------------------------------------------- PRINT1 (("nr "ID" nc "ID"\n", nr, nc)) ; PRINT1 (("anrow "ID" ancol "ID"\n", anrow, ancol)) ; PRINT1 (("cnrow "ID" cncol "ID"\n", cnrow, cncol)) ; - DEBUG (for (i = 0 ; i < nr ; i++) PRINT2 (("rset ["ID"] = "ID"\n", - i, rset [i]))); - DEBUG (for (i = 0 ; i < nc ; i++) PRINT2 (("cset ["ID"] = "ID"\n", - i, cset [i]))); - - /* C is sorted if A and rset are sorted, or if C has one row or less */ - csorted = A->sorted || (cnrow <= 1) ; + DEBUG (for (Int i = 0 ; i < nr ; i++) + PRINT2 (("rset ["ID"] = "ID"\n", i, rset [i]))); + DEBUG (for (Int i = 0 ; i < nc ; i++) + PRINT2 (("cset ["ID"] = "ID"\n", i, cset [i]))); if (!check_subset (rset, nr, anrow)) { - ERROR (CHOLMOD_INVALID, "invalid rset") ; - return (NULL) ; + ERROR (CHOLMOD_INVALID, "invalid rset") ; + return (NULL) ; } if (!check_subset (cset, nc, ancol)) { - ERROR (CHOLMOD_INVALID, "invalid cset") ; - return (NULL) ; + ERROR (CHOLMOD_INVALID, "invalid cset") ; + return (NULL) ; } - nnz = 0 ; + //-------------------------------------------------------------------------- + // convert A if necessary + //-------------------------------------------------------------------------- + + // convert A to unsymmetric, if necessary + if (A->stype != 0) + { + // workspace: Iwork (max (A->nrow,A->ncol)) + A2 = CHOLMOD(copy) (A, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + A = A2 ; + } + + ASSERT (A->stype == 0) ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + bool packed = A->packed ; + + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Int *Head = Common->Head ; // size anrow + Int *Iwork = Common->Iwork ; + Int *Rlen = Iwork ; // size anrow + Int *Rnext = Iwork + anrow ; // size nr, not used if nr < 0 + + //-------------------------------------------------------------------------- + // construct inverse of rset and compute nnz (C) + //-------------------------------------------------------------------------- + + // C is sorted if A and rset are sorted, or if C has one row or less + bool csorted = A->sorted || (cnrow <= 1) ; + + Int nnz = 0 ; if (nr < 0) { - /* C = A (:,cset) where cset = [ ] or cset is not empty */ - ASSERT (IMPLIES (cncol > 0, cset != NULL)) ; - for (cj = 0 ; cj < cncol ; cj++) - { - /* construct column cj of C, which is column j of A */ - j = cset [cj] ; - nnz += (packed) ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ; - } + // C = A (:,cset) where cset = [ ] or cset is not empty + ASSERT (IMPLIES (cncol > 0, cset != NULL)) ; + for (Int cj = 0 ; cj < cncol ; cj++) + { + // construct column cj of C, which is column j of A + Int j = cset [cj] ; + nnz += (packed) ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ; + } } else { - /* C = A (rset,cset), where rset is not empty but cset might be empty */ - /* create link lists in reverse order to preserve natural order */ - ilast = anrow ; - for (ci = nr-1 ; ci >= 0 ; ci--) - { - /* row i of A becomes row ci of C; add ci to ith link list */ - i = rset [ci] ; - head = Head [i] ; - Rlen [i] = (head == EMPTY) ? 1 : (Rlen [i] + 1) ; - Rnext [ci] = head ; - Head [i] = ci ; - if (i > ilast) - { - /* row indices in columns of C will not be sorted */ - csorted = FALSE ; - } - ilast = i ; - } - -#ifndef NDEBUG - for (i = 0 ; i < anrow ; i++) - { - Int k = 0 ; - Int rlen = (Head [i] != EMPTY) ? Rlen [i] : -1 ; - PRINT1 (("Row "ID" Rlen "ID": ", i, rlen)) ; - for (ci = Head [i] ; ci != EMPTY ; ci = Rnext [ci]) - { - k++ ; - PRINT2 ((""ID" ", ci)) ; - } - PRINT1 (("\n")) ; - ASSERT (IMPLIES (Head [i] != EMPTY, k == Rlen [i])) ; - } -#endif - - /* count nonzeros in C */ - for (cj = 0 ; cj < cncol ; cj++) - { - /* count rows in column cj of C, which is column j of A */ - j = (nc < 0) ? cj : (cset [cj]) ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - /* row i of A becomes multiple rows (ci) of C */ - i = Ai [p] ; - ASSERT (i >= 0 && i < anrow) ; - if (Head [i] != EMPTY) - { - nnz += Rlen [i] ; - } - } - } + // C = A (rset,cset), where rset is not empty but cset might be empty + // create link lists in reverse order to preserve natural order + Int ilast = anrow ; + for (Int ci = nr-1 ; ci >= 0 ; ci--) + { + // row i of A becomes row ci of C; add ci to ith link list + Int i = rset [ci] ; + Int head = Head [i] ; + Rlen [i] = (head == EMPTY) ? 1 : (Rlen [i] + 1) ; + Rnext [ci] = head ; + Head [i] = ci ; + if (i > ilast) + { + // row indices in columns of C will not be sorted + csorted = FALSE ; + } + ilast = i ; + } + + #ifndef NDEBUG + for (Int i = 0 ; i < anrow ; i++) + { + Int k = 0 ; + Int rlen = (Head [i] != EMPTY) ? Rlen [i] : -1 ; + PRINT1 (("Row "ID" Rlen "ID": ", i, rlen)) ; + for (Int ci = Head [i] ; ci != EMPTY ; ci = Rnext [ci]) + { + k++ ; + PRINT2 ((""ID" ", ci)) ; + } + PRINT1 (("\n")) ; + ASSERT (IMPLIES (Head [i] != EMPTY, k == Rlen [i])) ; + } + #endif + + // count entries in C + for (Int cj = 0 ; cj < cncol ; cj++) + { + // count rows in column cj of C, which is column j of A + Int j = (nc < 0) ? cj : (cset [cj]) ; + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // row i of A becomes multiple rows (ci) of C + Int i = Ai [p] ; + ASSERT (i >= 0 && i < anrow) ; + if (Head [i] != EMPTY) + { + nnz += Rlen [i] ; + } + } + } } PRINT1 (("nnz (C) "ID"\n", nnz)) ; - /* rset and cset are now valid */ + // rset and cset are now valid DEBUG (CHOLMOD(dump_subset) (rset, rsize, anrow, "rset", Common)) ; DEBUG (CHOLMOD(dump_subset) (cset, csize, ancol, "cset", Common)) ; - /* ---------------------------------------------------------------------- */ - /* allocate C */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate C + //-------------------------------------------------------------------------- C = CHOLMOD(allocate_sparse) (cnrow, cncol, nnz, csorted, TRUE, 0, - values ? A->xtype : CHOLMOD_PATTERN, Common) ; + (values ? A->xtype : CHOLMOD_PATTERN) + A->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - for (i = 0 ; i < anrow ; i++) - { - Head [i] = EMPTY ; - } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; - return (NULL) ; + // out of memory + for (Int i = 0 ; i < anrow ; i++) + { + Head [i] = EMPTY ; + } + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; + CHOLMOD(free_sparse) (&A2, Common) ; + return (NULL) ; } - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - - /* ---------------------------------------------------------------------- */ - /* C = A (rset,cset) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // C = A (rset,cset) + //-------------------------------------------------------------------------- - pdest = 0 ; if (nnz == 0) { - /* C has no nonzeros */ - for (cj = 0 ; cj <= cncol ; cj++) - { - Cp [cj] = 0 ; - } - } - else if (nr < 0) - { - /* C = A (:,cset), where cset is not empty */ - for (cj = 0 ; cj < cncol ; cj++) - { - /* construct column cj of C, which is column j of A */ - PRINT1 (("construct cj = j = "ID"\n", cj)) ; - j = cset [cj] ; - Cp [cj] = pdest ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Ai [p] ; - if (values) - { - Cx [pdest] = Ax [p] ; - } - pdest++ ; - ASSERT (pdest <= nnz) ; - } - } + // C has no entries + Int *Cp = C->p ; + for (Int cj = 0 ; cj <= cncol ; cj++) + { + Cp [cj] = 0 ; + } } else { - /* C = A (rset,cset), where rset is not empty but cset might be empty */ - for (cj = 0 ; cj < cncol ; cj++) - { - /* construct column cj of C, which is column j of A */ - PRINT1 (("construct cj = "ID"\n", cj)) ; - j = (nc < 0) ? cj : (cset [cj]) ; - PRINT1 (("cj = "ID"\n", j)) ; - Cp [cj] = pdest ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - /* row (Ai [p]) of A becomes multiple rows (ci) of C */ - PRINT2 (("i: "ID" becomes: ", Ai [p])) ; - if (values) - { - aij = Ax [p] ; - } - for (ci = Head [Ai [p]] ; ci != EMPTY ; ci = Rnext [ci]) - { - PRINT3 ((""ID" ", ci)) ; - Ci [pdest] = ci ; - if (values) - { - Cx [pdest] = aij ; - } - pdest++ ; - ASSERT (pdest <= nnz) ; - } - PRINT2 (("\n")) ; - } - } + switch ((C->xtype + C->dtype) % 8) + { + default: + p_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_submatrix_worker (C, A, nr, nc, cset, Head, Rnext) ; + break ; + } } - Cp [cncol] = pdest ; - ASSERT (nnz == pdest) ; - /* ---------------------------------------------------------------------- */ - /* clear workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear workspace + //-------------------------------------------------------------------------- - for (ci = 0 ; ci < nr ; ci++) + for (Int ci = 0 ; ci < nr ; ci++) { - Head [rset [ci]] = EMPTY ; + Head [rset [ci]] = EMPTY ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* sort C, if requested */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // sort C, if requested + //-------------------------------------------------------------------------- ASSERT (CHOLMOD(dump_sparse) (C , "C before sort", Common) >= 0) ; - if (sorted && !csorted) { - /* workspace: Iwork (max (C->nrow,C->ncol)) */ - if (!CHOLMOD(sort) (C, Common)) - { - /* out of memory */ - CHOLMOD(free_sparse) (&C, Common) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; - return (NULL) ; - } + CHOLMOD(sort) (C, Common) ; } - /* ---------------------------------------------------------------------- */ - /* return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + CHOLMOD(free_sparse) (&A2, Common) ; ASSERT (CHOLMOD(dump_sparse) (C , "Final C", Common) >= 0) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (C) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_symmetry.c b/CHOLMOD/MatrixOps/cholmod_symmetry.c index 5a1e573867..d745026123 100644 --- a/CHOLMOD/MatrixOps/cholmod_symmetry.c +++ b/CHOLMOD/MatrixOps/cholmod_symmetry.c @@ -2,198 +2,220 @@ // CHOLMOD/MatrixOps/cholmod_symmetry: determine symmetry status of a matrix //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Determines if a sparse matrix is rectangular, unsymmetric, symmetric, - * skew-symmetric, or Hermitian. It does so by looking at its numerical values - * of both upper and lower triangular parts of a CHOLMOD "unsymmetric" - * matrix, where A->stype == 0. The transpose of A is NOT constructed. - * - * If not unsymmetric, it also determines if the matrix has a diagonal whose - * entries are all real and positive (and thus a candidate for sparse Cholesky - * if A->stype is changed to a nonzero value). - * - * Note that a Matrix Market "general" matrix is either rectangular or - * unsymmetric. - * - * The row indices in the column of each matrix MUST be sorted for this function - * to work properly (A->sorted must be TRUE). This routine returns EMPTY if - * A->stype is not zero, or if A->sorted is FALSE. The exception to this rule - * is if A is rectangular. - * - * If option == 0, then this routine returns immediately when it finds a - * non-positive diagonal entry (or one with nonzero imaginary part). If the - * matrix is not a candidate for sparse Cholesky, it returns the value - * CHOLMOD_MM_UNSYMMETRIC, even if the matrix might in fact be symmetric or - * Hermitian. - * - * This routine is useful inside the MATLAB backslash, which must look at an - * arbitrary matrix (A->stype == 0) and determine if it is a candidate for - * sparse Cholesky. In that case, option should be 0. - * - * This routine is also useful when writing a MATLAB matrix to a file in - * Rutherford/Boeing or Matrix Market format. Those formats require a - * determination as to the symmetry of the matrix, and thus this routine should - * not return upon encountering the first non-positive diagonal. In this case, - * option should be 1. - * - * If option is 2, this function can be used to compute the numerical and - * pattern symmetry, where 0 is a completely unsymmetric matrix, and 1 is a - * perfectly symmetric matrix. This option is used when computing the following - * statistics for the matrices in the SuiteSparse Matrix Collection. - * - * numerical symmetry: number of matched offdiagonal nonzeros over - * the total number of offdiagonal entries. A real entry A(i,j), i ~= j, - * is matched if A (j,i) == A (i,j), but this is only counted if both - * A(j,i) and A(i,j) are nonzero. This does not depend on Z. - * (If A is complex, then the above test is modified; A (i,j) is matched - * if conj (A (j,i)) == A (i,j)). - * - * Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0. - * - * pattern symmetry: number of matched offdiagonal entries over the - * total number of offdiagonal entries. An entry A(i,j), i ~= j, is - * matched if A (j,i) is also an entry. - * - * Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0. - * - * The symmetry of a matrix with no offdiagonal entries is equal to 1. - * - * A workspace of size ncol integers is allocated; EMPTY is returned if this - * allocation fails. - * - * Summary of return values: - * - * EMPTY (-1) out of memory, stype not zero, A not sorted - * CHOLMOD_MM_RECTANGULAR 1 A is rectangular - * CHOLMOD_MM_UNSYMMETRIC 2 A is unsymmetric - * CHOLMOD_MM_SYMMETRIC 3 A is symmetric, but with non-pos. diagonal - * CHOLMOD_MM_HERMITIAN 4 A is Hermitian, but with non-pos. diagonal - * CHOLMOD_MM_SKEW_SYMMETRIC 5 A is skew symmetric - * CHOLMOD_MM_SYMMETRIC_POSDIAG 6 A is symmetric with positive diagonal - * CHOLMOD_MM_HERMITIAN_POSDIAG 7 A is Hermitian with positive diagonal - * - * See also the spsym mexFunction, which is a MATLAB interface for this code. - * - * If the matrix is a candidate for sparse Cholesky, it will return a result - * CHOLMOD_MM_SYMMETRIC_POSDIAG if real, or CHOLMOD_MM_HERMITIAN_POSDIAG if - * complex. Otherwise, it will return a value less than this. This is true - * regardless of the value of the option parameter. - */ +// Determines if a sparse matrix is rectangular, unsymmetric, symmetric, +// skew-symmetric, or Hermitian. It does so by looking at its numerical values +// of both upper and lower triangular parts of a CHOLMOD "unsymmetric" +// matrix, where A->stype == 0. The transpose of A is NOT constructed. +// +// If not unsymmetric, it also determines if the matrix has a diagonal whose +// entries are all real and positive (and thus a candidate for sparse Cholesky +// if A->stype is changed to a nonzero value). +// +// Note that a Matrix Market "general" matrix is either rectangular or +// unsymmetric. +// +// The row indices in the column of each matrix MUST be sorted for this function +// to work properly (A->sorted must be true). This routine returns EMPTY if +// A->stype is not zero, or if A->sorted is false. The exception to this rule +// is if A is rectangular. +// +// If option == 0, then this routine returns immediately when it finds a +// non-positive diagonal entry (or one with nonzero imaginary part). If the +// matrix is not a candidate for sparse Cholesky, it returns the value +// CHOLMOD_MM_UNSYMMETRIC, even if the matrix might in fact be symmetric or +// Hermitian. +// +// This routine is useful inside the MATLAB backslash, which must look at an +// arbitrary matrix (A->stype == 0) and determine if it is a candidate for +// sparse Cholesky. In that case, option should be 0. +// +// This routine is also useful when writing a MATLAB matrix to a file in +// Rutherford/Boeing or Matrix Market format. Those formats require a +// determination as to the symmetry of the matrix, and thus this routine should +// not return upon encountering the first non-positive diagonal. In this case, +// option should be 1. +// +// If option is 2, this function can be used to compute the numerical and +// pattern symmetry, where 0 is a completely unsymmetric matrix, and 1 is a +// perfectly symmetric matrix. This option is used when computing the following +// statistics for the matrices in the SuiteSparse Matrix Collection. +// +// numerical symmetry: number of matched offdiagonal nonzeros over +// the total number of offdiagonal entries. A real entry A(i,j), i ~= j, +// is matched if A (j,i) == A (i,j), but this is only counted if both +// A(j,i) and A(i,j) are nonzero. This does not depend on Z. +// (If A is complex, then the above test is modified; A (i,j) is matched +// if conj (A (j,i)) == A (i,j)). +// +// Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0. +// +// pattern symmetry: number of matched offdiagonal entries over the +// total number of offdiagonal entries. An entry A(i,j), i ~= j, is +// matched if A (j,i) is also an entry. +// +// Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0. +// +// The symmetry of a matrix with no offdiagonal entries is equal to 1. +// +// A workspace of size ncol integers is allocated; EMPTY is returned if this +// allocation fails. +// +// Summary of return values: +// +// EMPTY (-1) out of memory, stype not zero, A not sorted +// CHOLMOD_MM_RECTANGULAR 1 A is rectangular +// CHOLMOD_MM_UNSYMMETRIC 2 A is unsymmetric +// CHOLMOD_MM_SYMMETRIC 3 A is symmetric, but with non-pos. diagonal +// CHOLMOD_MM_HERMITIAN 4 A is Hermitian, but with non-pos. diagonal +// CHOLMOD_MM_SKEW_SYMMETRIC 5 A is skew symmetric +// CHOLMOD_MM_SYMMETRIC_POSDIAG 6 A is symmetric with positive diagonal +// CHOLMOD_MM_HERMITIAN_POSDIAG 7 A is Hermitian with positive diagonal +// +// See also the spsym mexFunction, which is a MATLAB interface for this code. +// +// If the matrix is a candidate for sparse Cholesky, it will return a result +// CHOLMOD_MM_SYMMETRIC_POSDIAG if real, or CHOLMOD_MM_HERMITIAN_POSDIAG if +// complex. Otherwise, it will return a value less than this. This is true +// regardless of the value of the option parameter. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === get_value ============================================================ */ -/* ========================================================================== */ - -/* Get the pth value in the matrix. */ +//------------------------------------------------------------------------------ +// get_value: get the pth value in the matrix +//------------------------------------------------------------------------------ static void get_value ( - double *Ax, /* real values, or real/imag. for CHOLMOD_COMPLEX type */ - double *Az, /* imaginary values for CHOLMOD_ZOMPLEX type */ - Int p, /* get the pth entry */ - Int xtype, /* A->xtype: pattern, real, complex, or zomplex */ - double *x, /* the real part */ - double *z /* the imaginary part */ + cholmod_sparse *A, // sparse matrix to query + Int p, // get the pth entry of A + int xtype, // A->xtype: pattern, real, complex, or zomplex + int dtype, // A->dtype: single or double + double *x, // the real part of A(i,j) + double *z // the imaginary part of A(i,j) ) { + switch (xtype) { - case CHOLMOD_PATTERN: - *x = 1 ; - *z = 0 ; - break ; - - case CHOLMOD_REAL: - *x = Ax [p] ; - *z = 0 ; - break ; - - case CHOLMOD_COMPLEX: - *x = Ax [2*p] ; - *z = Ax [2*p+1] ; - break ; - - case CHOLMOD_ZOMPLEX: - *x = Ax [p] ; - *z = Az [p] ; - break ; + case CHOLMOD_PATTERN: + (*x) = 1 ; + (*z) = 0 ; + break ; + + case CHOLMOD_REAL: + if (dtype == CHOLMOD_DOUBLE) + { + double *Ax = A->x ; + (*x) = Ax [p] ; + } + else + { + float *Ax = A->x ; + (*x) = (double) Ax [p] ; + } + (*z) = 0 ; + break ; + + case CHOLMOD_COMPLEX: + if (dtype == CHOLMOD_DOUBLE) + { + double *Ax = A->x ; + (*x) = Ax [2*p] ; + (*z) = Ax [2*p+1] ; + } + else + { + float *Ax = A->x ; + (*x) = (double) Ax [2*p] ; + (*z) = (double) Ax [2*p+1] ; + } + break ; + + case CHOLMOD_ZOMPLEX: + if (dtype == CHOLMOD_DOUBLE) + { + double *Ax = A->x ; + double *Az = A->z ; + (*x) = Ax [p] ; + (*z) = Az [p] ; + } + else + { + float *Ax = A->x ; + float *Az = A->z ; + (*x) = (double) Ax [p] ; + (*z) = (double) Az [p] ; + } + break ; } } +//------------------------------------------------------------------------------ +// cholmod_symmetry +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_symmetry ===================================================== */ -/* ========================================================================== */ - -/* Determine the symmetry of a matrix, and check its diagonal. - * - * option 0: Do not count # of matched pairs. Quick return if the - * the matrix has a zero, negative, or imaginary diagonal entry. - * - * option 1: Do not count # of matched pairs. Do not return quickly if - * the matrix has a zero, negative, or imaginary diagonal entry. - * The result 1 to 7 is accurately computed: - * - * EMPTY (-1) out of memory, stype not zero, A not sorted - * CHOLMOD_MM_RECTANGULAR 1 A is rectangular - * CHOLMOD_MM_UNSYMMETRIC 2 A is unsymmetric - * CHOLMOD_MM_SYMMETRIC 3 A is symmetric, with non-pos. diagonal - * CHOLMOD_MM_HERMITIAN 4 A is Hermitian, with non-pos. diagonal - * CHOLMOD_MM_SKEW_SYMMETRIC 5 A is skew symmetric - * CHOLMOD_MM_SYMMETRIC_POSDIAG 6 is symmetric with positive diagonal - * CHOLMOD_MM_HERMITIAN_POSDIAG 7 A is Hermitian with positive diagonal - * - * The routine returns as soon as the above is determined (that is, it - * can return as soon as it determines the matrix is unsymmetric). - * - * option 2: All of the above, but also compute the number of matched off- - * diagonal entries (of two types). xmatched is the number of - * nonzero entries for which A(i,j) = conj(A(j,i)). pmatched is - * the number of entries (i,j) for which A(i,j) and A(j,i) are both in - * the pattern of A (the value doesn't matter). nzoffdiag is the total - * number of off-diagonal entries in the pattern. nzdiag is the number of - * diagonal entries in the pattern. - * - * With option 0 or 1, or if the matrix is rectangular, xmatched, pmatched, - * nzoffdiag, and nzdiag are not computed. - * - * Note that a matched pair, A(i,j) and A(j,i) for i != j, is counted twice - * (once per entry). - */ +// Determine the symmetry of a matrix, and check its diagonal. +// +// option 0: Do not count # of matched pairs. Quick return if the +// the matrix has a zero, negative, or imaginary diagonal entry. +// +// option 1: Do not count # of matched pairs. Do not return quickly if +// the matrix has a zero, negative, or imaginary diagonal entry. +// The result 1 to 7 is accurately computed: +// +// EMPTY (-1): out of memory, stype not zero, +// A not sorted +// CHOLMOD_MM_RECTANGULAR 1 A is rectangular +// CHOLMOD_MM_UNSYMMETRIC 2 A is unsymmetric +// CHOLMOD_MM_SYMMETRIC 3 A is symmetric, with non-pos. diagonal +// CHOLMOD_MM_HERMITIAN 4 A is Hermitian, with non-pos. diagonal +// CHOLMOD_MM_SKEW_SYMMETRIC 5 A is skew symmetric +// CHOLMOD_MM_SYMMETRIC_POSDIAG 6 is symmetric with positive diagonal +// CHOLMOD_MM_HERMITIAN_POSDIAG 7 A is Hermitian with positive diagonal +// +// The routine returns as soon as the above is determined (that is, it +// can return as soon as it determines the matrix is unsymmetric). +// +// option 2: All of the above, but also compute the number of matched off- +// diagonal entries (of two types). xmatched is the number of nonzero +// entries for which A(i,j) = conj(A(j,i)). pmatched is the number of +// entries (i,j) for which A(i,j) and A(j,i) are both in the pattern of A +// (the value doesn't matter). nzoffdiag is the total number of +// off-diagonal entries in the pattern. nzdiag is the number of diagonal +// entries in the pattern. +// +// With option 0 or 1, or if the matrix is rectangular, xmatched, pmatched, +// nzoffdiag, and nzdiag are not computed. +// +// Note that a matched pair, A(i,j) and A(j,i) for i != j, is counted twice +// (once per entry). int CHOLMOD(symmetry) ( - /* ---- input ---- */ + // input: cholmod_sparse *A, - int option, /* option 0, 1, or 2 (see above) */ - /* ---- output --- */ /* outputs ignored if any are NULL */ - Int *p_xmatched, /* # of matched numerical entries */ - Int *p_pmatched, /* # of matched entries in pattern */ - Int *p_nzoffdiag, /* # of off diagonal entries */ - Int *p_nzdiag, /* # of diagonal entries */ - /* --------------- */ + int option, // option 0, 1, or 2 (see above) + // output: + Int *p_xmatched, // # of matched numerical entries + Int *p_pmatched, // # of matched entries in pattern + Int *p_nzoffdiag, // # of off diagonal entries + Int *p_nzdiag, // # of diagonal entries cholmod_common *Common ) { - double aij_real = 0, aij_imag = 0, aji_real = 0, aji_imag = 0 ; - double *Ax, *Az ; - Int *Ap, *Ai, *Anz, *munch ; - Int packed, nrow, ncol, xtype, is_symmetric, is_skew, is_hermitian, posdiag, - j, p, pend, i, piend, result, xmatched, pmatched, nzdiag, i2, found ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; @@ -202,285 +224,289 @@ int CHOLMOD(symmetry) ASSERT (CHOLMOD(dump_sparse) (A, "cholmod_symmetry", Common) >= 0) ; if (p_xmatched == NULL || p_pmatched == NULL - || p_nzoffdiag == NULL || p_nzdiag == NULL) + || p_nzoffdiag == NULL || p_nzdiag == NULL) { - /* option 2 is not performed if any output parameter is NULL */ - option = MAX (option, 1) ; + // option 2 is not performed if any output parameter is NULL + option = MAX (option, 1) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - Anz = A->nz ; - packed = A->packed ; - ncol = A->ncol ; - nrow = A->nrow ; - xtype = A->xtype ; + Int *Ap = A->p ; + Int *Ai = A->i ; + Int *Anz = A->nz ; + bool packed = A->packed ; + Int ncol = A->ncol ; + Int nrow = A->nrow ; + int xtype = A->xtype ; + int dtype = A->dtype ; - /* ---------------------------------------------------------------------- */ - /* check if rectangular, unsorted, or stype is not zero */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check if rectangular, unsorted, or stype is not zero + //-------------------------------------------------------------------------- if (nrow != ncol) { - /* matrix is rectangular */ - return (CHOLMOD_MM_RECTANGULAR) ; + // matrix is rectangular + return (CHOLMOD_MM_RECTANGULAR) ; } if (!(A->sorted) || A->stype != 0) { - /* this function cannot determine the type or symmetry */ - return (EMPTY) ; + // this function cannot determine the type or symmetry + return (EMPTY) ; } - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* this function requires uninitialized Int workspace of size ncol */ + // this function requires uninitialized Int workspace of size ncol CHOLMOD(allocate_work) (0, ncol, 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (EMPTY) ; + // out of memory + return (EMPTY) ; } - munch = Common->Iwork ; /* the munch array is size ncol */ + Int *munch = Common->Iwork ; // the munch array is size ncol - /* ---------------------------------------------------------------------- */ - /* determine symmetry of a square matrix */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine symmetry of a square matrix + //-------------------------------------------------------------------------- - /* a complex or zomplex matrix is Hermitian until proven otherwise */ - is_hermitian = (xtype >= CHOLMOD_COMPLEX) ; + // a complex or zomplex matrix is Hermitian until proven otherwise + bool is_hermitian = (xtype >= CHOLMOD_COMPLEX) ; - /* any matrix is symmetric until proven otherwise */ - is_symmetric = TRUE ; + // any matrix is symmetric until proven otherwise + bool is_symmetric = true ; - /* a non-pattern matrix is skew-symmetric until proven otherwise */ - is_skew = (xtype != CHOLMOD_PATTERN) ; + // a non-pattern matrix is skew-symmetric until proven otherwise + bool is_skew = (xtype != CHOLMOD_PATTERN) ; - /* a matrix has positive diagonal entries until proven otherwise */ - posdiag = TRUE ; + // a matrix has positive diagonal entries until proven otherwise + bool posdiag = true ; - /* munch pointers start at the top of each column */ - for (j = 0 ; j < ncol ; j++) + // munch pointers start at the top of each column + for (Int j = 0 ; j < ncol ; j++) { - munch [j] = Ap [j] ; + munch [j] = Ap [j] ; } - xmatched = 0 ; - pmatched = 0 ; - nzdiag = 0 ; + Int xmatched = 0 ; + Int pmatched = 0 ; + Int nzdiag = 0 ; - for (j = 0 ; j < ncol ; j++) /* examine each column of A */ + for (Int j = 0 ; j < ncol ; j++) // examine each column of A { - /* ------------------------------------------------------------------ */ - /* look at the entire munch column j */ - /* ------------------------------------------------------------------ */ - - /* start at the munch point of column j, and go to end of the column */ - p = munch [j] ; - pend = (packed) ? (Ap [j+1]) : (Ap [j] + Anz [j]) ; - - for ( ; p < pend ; p++) - { - /* get the row index of A(i,j) */ - i = Ai [p] ; - - if (i < j) - { - - /* ---------------------------------------------------------- */ - /* A(i,j) in triu(A), but matching A(j,i) not in tril(A) */ - /* ---------------------------------------------------------- */ - - /* entry A(i,j) is unmatched; it appears in the upper triangular - * part, but not the lower triangular part. The matrix is - * unsymmetric. */ - is_hermitian = FALSE ; - is_symmetric = FALSE ; - is_skew = FALSE ; - - } - else if (i == j) - { - - /* ---------------------------------------------------------- */ - /* the diagonal A(j,j) is present; check its value */ - /* ---------------------------------------------------------- */ - - get_value (Ax, Az, p, xtype, &aij_real, &aij_imag) ; - if (aij_real != 0. || aij_imag != 0.) - { - /* diagonal is nonzero; matrix is not skew-symmetric */ - nzdiag++ ; - is_skew = FALSE ; - } - if (aij_real <= 0. || aij_imag != 0.) - { - /* diagonal negative or imaginary; not chol candidate */ - posdiag = FALSE ; - } - if (aij_imag != 0.) - { - /* imaginary part is present; not Hermitian */ - is_hermitian = FALSE ; - } - - } - else /* i > j */ - { - - /* ---------------------------------------------------------- */ - /* consider column i, up to and including row j */ - /* ---------------------------------------------------------- */ - - /* munch the entry at top of column i up to and incl row j */ - piend = (packed) ? (Ap [i+1]) : (Ap [i] + Anz [i]) ; - - found = FALSE ; - - for ( ; munch [i] < piend ; munch [i]++) - { - - i2 = Ai [munch [i]] ; - - if (i2 < j) - { - - /* -------------------------------------------------- */ - /* A(i2,i) in triu(A) but A(i,i2) not in tril(A) */ - /* -------------------------------------------------- */ - - /* The matrix is unsymmetric. */ - is_hermitian = FALSE ; - is_symmetric = FALSE ; - is_skew = FALSE ; - - } - else if (i2 == j) - { - - /* -------------------------------------------------- */ - /* both A(i,j) and A(j,i) exist in the matrix */ - /* -------------------------------------------------- */ - - /* this is one more matching entry in the pattern */ - pmatched += 2 ; - found = TRUE ; - - /* get the value of A(i,j) */ - get_value (Ax, Az, p, xtype, &aij_real, &aij_imag) ; - - /* get the value of A(j,i) */ - get_value (Ax, Az, munch [i], - xtype, &aji_real, &aji_imag) ; - - /* compare A(i,j) with A(j,i) */ - if (aij_real != aji_real || aij_imag != aji_imag) - { - /* the matrix cannot be symmetric */ - is_symmetric = FALSE ; - } - if (aij_real != -aji_real || aij_imag != aji_imag) - { - /* the matrix cannot be skew-symmetric */ - is_skew = FALSE ; - } - if (aij_real != aji_real || aij_imag != -aji_imag) - { - /* the matrix cannot be Hermitian */ - is_hermitian = FALSE ; - } - else - { - /* A(i,j) and A(j,i) are numerically matched */ - xmatched += 2 ; - } - - } - else /* i2 > j */ - { - - /* -------------------------------------------------- */ - /* entry A(i2,i) is not munched; consider it later */ - /* -------------------------------------------------- */ - - break ; - } - } - - if (!found) - { - /* A(i,j) in tril(A) but A(j,i) not in triu(A). - * The matrix is unsymmetric. */ - is_hermitian = FALSE ; - is_symmetric = FALSE ; - is_skew = FALSE ; - } - } - - if (option < 2 && !(is_symmetric || is_skew || is_hermitian)) - { - /* matrix is unsymmetric; terminate the test */ - return (CHOLMOD_MM_UNSYMMETRIC) ; - } - } - - /* ------------------------------------------------------------------ */ - /* quick return if not Cholesky candidate */ - /* ------------------------------------------------------------------ */ - - if (option < 1 && (!posdiag || nzdiag <= j)) - { - /* Diagonal entry not present, or present but negative or with - * nonzero imaginary part. Quick return for option 0. */ - return (CHOLMOD_MM_UNSYMMETRIC) ; - } + //---------------------------------------------------------------------- + // look at the entire munch column j + //---------------------------------------------------------------------- + + // start at the munch point of column j, and go to end of the column + Int p = munch [j] ; + Int pend = (packed) ? (Ap [j+1]) : (Ap [j] + Anz [j]) ; + + for ( ; p < pend ; p++) + { + // get the row index of A(i,j) + Int i = Ai [p] ; + + if (i < j) + { + + //-------------------------------------------------------------- + // A(i,j) in triu(A), but matching A(j,i) not in tril(A) + //-------------------------------------------------------------- + + // entry A(i,j) is unmatched; it appears in the upper triangular + // part, but not the lower triangular part. The matrix is + // unsymmetric. + is_hermitian = false ; + is_symmetric = false ; + is_skew = false ; + + } + else if (i == j) + { + + //-------------------------------------------------------------- + // the diagonal A(j,j) is present; check its value + //-------------------------------------------------------------- + + double aij_real, aij_imag ; + get_value (A, p, xtype, dtype, &aij_real, &aij_imag) ; + if (aij_real != 0. || aij_imag != 0.) + { + // diagonal is nonzero; matrix is not skew-symmetric + nzdiag++ ; + is_skew = false ; + } + if (aij_real <= 0. || aij_imag != 0.) + { + // diagonal negative or imaginary; not chol candidate + posdiag = false ; + } + if (aij_imag != 0.) + { + // imaginary part is present; not Hermitian + is_hermitian = false ; + } + + } + else // i > j + { + + //-------------------------------------------------------------- + // consider column i, up to and including row j + //-------------------------------------------------------------- + + // munch the entry at top of column i up to and incl row j + Int piend = (packed) ? (Ap [i+1]) : (Ap [i] + Anz [i]) ; + + bool found = false ; + + for ( ; munch [i] < piend ; munch [i]++) + { + + Int i2 = Ai [munch [i]] ; + + if (i2 < j) + { + + //------------------------------------------------------ + // A(i2,i) in triu(A) but A(i,i2) not in tril(A) + //------------------------------------------------------ + + // the matrix is unsymmetric + is_hermitian = false ; + is_symmetric = false ; + is_skew = false ; + + } + else if (i2 == j) + { + + //------------------------------------------------------ + // both A(i,j) and A(j,i) exist in the matrix + //------------------------------------------------------ + + // this is one more matching entry in the pattern + pmatched += 2 ; + found = true ; + + // get the value of A(i,j) + double aij_real, aij_imag ; + get_value (A, p, xtype, dtype, &aij_real, &aij_imag) ; + + // get the value of A(j,i) at the munch [i] position + double aji_real, aji_imag ; + Int p2 = munch [i] ; + get_value (A, p2, xtype, dtype, &aji_real, &aji_imag) ; + + // compare A(i,j) with A(j,i) + if (aij_real != aji_real || aij_imag != aji_imag) + { + // the matrix cannot be symmetric + is_symmetric = false ; + } + if (aij_real != -aji_real || aij_imag != aji_imag) + { + // the matrix cannot be skew-symmetric + is_skew = false ; + } + if (aij_real != aji_real || aij_imag != -aji_imag) + { + // the matrix cannot be Hermitian + is_hermitian = false ; + } + else + { + // A(i,j) and A(j,i) are numerically matched + xmatched += 2 ; + } + + } + else // i2 > j + { + + //------------------------------------------------------ + // entry A(i2,i) is not munched; consider it later + //------------------------------------------------------ + + break ; + } + } + + if (!found) + { + // A(i,j) in tril(A) but A(j,i) not in triu(A). + // The matrix is unsymmetric. + is_hermitian = false ; + is_symmetric = false ; + is_skew = false ; + } + } + + if (option < 2 && !(is_symmetric || is_skew || is_hermitian)) + { + // matrix is unsymmetric; terminate the test + return (CHOLMOD_MM_UNSYMMETRIC) ; + } + } + + //---------------------------------------------------------------------- + // quick return if not Cholesky candidate + //---------------------------------------------------------------------- + + if (option < 1 && (!posdiag || nzdiag <= j)) + { + // Diagonal entry not present, or present but negative or with + // nonzero imaginary part. Quick return for option 0. + return (CHOLMOD_MM_UNSYMMETRIC) ; + } } - /* ---------------------------------------------------------------------- */ - /* return the results */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return the results + //-------------------------------------------------------------------------- if (nzdiag < ncol) { - /* not all diagonal entries are present */ - posdiag = FALSE ; + // not all diagonal entries are present + posdiag = false ; } if (option >= 2) { - *p_xmatched = xmatched ; - *p_pmatched = pmatched ; - *p_nzoffdiag = CHOLMOD(nnz) (A, Common) - nzdiag ; - *p_nzdiag = nzdiag ; + *p_xmatched = xmatched ; + *p_pmatched = pmatched ; + *p_nzoffdiag = CHOLMOD(nnz) (A, Common) - nzdiag ; + *p_nzdiag = nzdiag ; } - result = CHOLMOD_MM_UNSYMMETRIC ; + int result = CHOLMOD_MM_UNSYMMETRIC ; if (is_hermitian) { - /* complex Hermitian matrix, with either pos. or non-pos. diagonal */ - result = posdiag ? CHOLMOD_MM_HERMITIAN_POSDIAG : CHOLMOD_MM_HERMITIAN ; + // complex Hermitian matrix, with either pos. or non-pos. diagonal + result = posdiag ? CHOLMOD_MM_HERMITIAN_POSDIAG : CHOLMOD_MM_HERMITIAN ; } else if (is_symmetric) { - /* real or complex symmetric matrix, with pos. or non-pos. diagonal */ - result = posdiag ? CHOLMOD_MM_SYMMETRIC_POSDIAG : CHOLMOD_MM_SYMMETRIC ; + // real or complex symmetric matrix, with pos. or non-pos. diagonal + result = posdiag ? CHOLMOD_MM_SYMMETRIC_POSDIAG : CHOLMOD_MM_SYMMETRIC ; } else if (is_skew) { - /* real or complex skew-symmetric matrix */ - result = CHOLMOD_MM_SKEW_SYMMETRIC ; + // real or complex skew-symmetric matrix + result = CHOLMOD_MM_SKEW_SYMMETRIC ; } return (result) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/cholmod_vertcat.c b/CHOLMOD/MatrixOps/cholmod_vertcat.c index a121069f64..a99aaa522d 100644 --- a/CHOLMOD/MatrixOps/cholmod_vertcat.c +++ b/CHOLMOD/MatrixOps/cholmod_vertcat.c @@ -2,198 +2,212 @@ // CHOLMOD/MatrixOps/cholmod_vertcat: vertical concatenation: C=[A;B] //------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Vertical concatenation, C = [A ; B] in MATLAB notation. - * - * A and B can be up/lo/unsym; C is unsymmetric and packed. - * A and B must have the same number of columns. - * C is sorted if both A and B are sorted. - * - * workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)). - * allocates temporary copies of A and B if they are symmetric. - * - * Only pattern and real matrices are supported. Complex and zomplex matrices - * are supported only if "values" is FALSE. - */ +// Vertical concatenation, C = [A ; B] in MATLAB notation. +// +// A and B can be up/lo/unsym; C is unsymmetric and packed. +// A and B must have the same number of columns. +// C is sorted if both A and B are sorted. +// +// workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)). +// allocates temporary copies of A and B if they are symmetric. +// +// A and B must have the same xtype and dtype, unless mode is 0. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMATRIXOPS -/* ========================================================================== */ -/* === cholmod_vertcat ====================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_vertcat_worker template +//------------------------------------------------------------------------------ + +#define PATTERN +#include "t_cholmod_vertcat_worker.c" + +#define DOUBLE +#define REAL +#include "t_cholmod_vertcat_worker.c" +#define COMPLEX +#include "t_cholmod_vertcat_worker.c" +#define ZOMPLEX +#include "t_cholmod_vertcat_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_vertcat_worker.c" +#define COMPLEX +#include "t_cholmod_vertcat_worker.c" +#define ZOMPLEX +#include "t_cholmod_vertcat_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_vertcat +//------------------------------------------------------------------------------ cholmod_sparse *CHOLMOD(vertcat) ( - /* ---- input ---- */ - cholmod_sparse *A, /* left matrix to concatenate */ - cholmod_sparse *B, /* right matrix to concatenate */ - int values, /* if TRUE compute the numerical values of C */ - /* --------------- */ + // input: + cholmod_sparse *A, // top matrix to concatenate + cholmod_sparse *B, // bottom matrix to concatenate + int mode, // 2: numerical (conj) if A and/or B are symmetric + // 1: numerical (non-conj.) if A and/or B are symmetric + // 0: pattern cholmod_common *Common ) { - double *Ax, *Bx, *Cx ; - Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Cp, *Ci ; - cholmod_sparse *C, *A2, *B2 ; - Int apacked, bpacked, anrow, bnrow, ncol, nrow, anz, bnz, nz, j, p, pend, - pdest ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + cholmod_sparse *C = NULL, *A2 = NULL, *B2 = NULL ; RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; - values = values && - (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; - RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; - RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, - values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; + + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN || B->xtype == CHOLMOD_PATTERN) + { + mode = 0 ; + } + bool values = (mode != 0) ; + + RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; + RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->ncol != B->ncol) { - /* A and B must have the same number of columns */ - ERROR (CHOLMOD_INVALID, "A and B must have same # of columns") ; - return (NULL) ; + // A and B must have the same number of columns + ERROR (CHOLMOD_INVALID, "A and B must have same # of columns") ; + return (NULL) ; + } + if (mode != 0 && (A->xtype != B->xtype || A->dtype != A->dtype)) + { + // A and B must have the same xtype and dtype if mode is 0 + ERROR (CHOLMOD_INVALID, "A and B must have same xtype and dtype") ; + return (NULL) ; } - /* A and B must have the same numerical type if values is TRUE (both must - * be CHOLMOD_REAL, this is implicitly checked above) */ + Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - anrow = A->nrow ; - bnrow = B->nrow ; - ncol = A->ncol ; + Int anrow = A->nrow ; + Int bnrow = B->nrow ; + Int ncol = A->ncol ; CHOLMOD(allocate_work) (0, MAX3 (anrow, bnrow, ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (NULL) ; + // out of memory + return (NULL) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert A and/or B if necessary + //-------------------------------------------------------------------------- - /* convert A to unsymmetric, if necessary */ + // convert A to unsymmetric, if necessary A2 = NULL ; if (A->stype != 0) { - /* workspace: Iwork (max (A->nrow,A->ncol)) */ - A2 = CHOLMOD(copy) (A, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - return (NULL) ; - } - A = A2 ; + // workspace: Iwork (max (A->nrow,A->ncol)) + A2 = CHOLMOD(copy) (A, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + return (NULL) ; + } + A = A2 ; } - /* convert B to unsymmetric, if necessary */ + // convert B to unsymmetric, if necessary B2 = NULL ; if (B->stype != 0) { - /* workspace: Iwork (max (B->nrow,B->ncol)) */ - B2 = CHOLMOD(copy) (B, 0, values, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - return (NULL) ; - } - B = B2 ; + // workspace: Iwork (max (B->nrow,B->ncol)) + B2 = CHOLMOD(copy) (B, 0, mode, Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + return (NULL) ; + } + B = B2 ; } - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - apacked = A->packed ; - - Bp = B->p ; - Bnz = B->nz ; - Bi = B->i ; - Bx = B->x ; - bpacked = B->packed ; + //-------------------------------------------------------------------------- + // allocate C + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* allocate C */ - /* ---------------------------------------------------------------------- */ - - anz = CHOLMOD(nnz) (A, Common) ; - bnz = CHOLMOD(nnz) (B, Common) ; - nrow = anrow + bnrow ; - nz = anz + bnz ; + Int anz = CHOLMOD(nnz) (A, Common) ; + Int bnz = CHOLMOD(nnz) (B, Common) ; + Int nrow = anrow + bnrow ; + Int nz = anz + bnz ; C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, A->sorted && B->sorted, TRUE, - 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; + 0, (values ? A->xtype : CHOLMOD_PATTERN) + A->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - CHOLMOD(free_sparse) (&A2, Common) ; - CHOLMOD(free_sparse) (&B2, Common) ; - return (NULL) ; + // out of memory + CHOLMOD(free_sparse) (&A2, Common) ; + CHOLMOD(free_sparse) (&B2, Common) ; + return (NULL) ; } - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - /* ---------------------------------------------------------------------- */ - /* C = [A ; B] */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // C = [A ; B] + //-------------------------------------------------------------------------- - pdest = 0 ; - for (j = 0 ; j < ncol ; j++) + switch ((C->xtype + C->dtype) % 8) { - /* attach A(:,j) as the first part of C(:,j) */ - p = Ap [j] ; - pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; - Cp [j] = pdest ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Ai [p] ; - if (values) - { - Cx [pdest] = Ax [p] ; - } - pdest++ ; - } - - /* attach B(:,j) as the second part of C(:,j) */ - p = Bp [j] ; - pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Bi [p] + anrow ; - if (values) - { - Cx [pdest] = Bx [p] ; - } - pdest++ ; - } + default: + p_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_vertcat_worker (C, A, B) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_vertcat_worker (C, A, B) ; + break ; } - Cp [ncol] = pdest ; - ASSERT (pdest == nz) ; - /* ---------------------------------------------------------------------- */ - /* free the unsymmetric copies of A and B, and return C */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the unsymmetric copies of A and B, and return C + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (C) ; } + #endif #endif + diff --git a/CHOLMOD/MatrixOps/t_cholmod_drop_worker.c b/CHOLMOD/MatrixOps/t_cholmod_drop_worker.c new file mode 100644 index 0000000000..1332a4aa17 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_drop_worker.c @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_drop_worker: drop small entries +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// IF_DROP: macro to determine if A(i,j) is dropped +//------------------------------------------------------------------------------ + +#ifdef REAL + + #define IF_DROP(Ax,Az,p,tol) \ + double ax = (double) Ax [p] ; \ + if (tol_is_zero ? (ax == 0) : (fabs (ax) <= tol)) + +#elif defined ( COMPLEX ) + + #define IF_DROP(Ax,Az,p,tol) \ + double ax = (double) Ax [2*(p) ] ; \ + double az = (double) Ax [2*(p)+1] ; \ + if (tol_is_zero ? (ax == 0 && az == 0) : \ + (SuiteSparse_config_hypot (ax, az) <= tol)) + +#elif defined ( ZOMPLEX ) + + #define IF_DROP(Ax,Az,p,tol) \ + double ax = (double) Ax [p] ; \ + double az = (double) Az [p] ; \ + if (tol_is_zero ? (ax == 0 && az == 0) : \ + (SuiteSparse_config_hypot (ax, az) <= tol)) + +#endif + +//------------------------------------------------------------------------------ +// t_cholmod_drop_worker +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_drop_worker) +( + // input: + double tol, // keep entries with absolute value > tol + // input/output: + cholmod_sparse *A, // matrix to drop entries from + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + Int *Anz = A->nz ; + bool packed = A->packed ; + Int ncol = A->ncol ; + Int nz = 0 ; + bool tol_is_zero = (tol == 0.) ; + + //-------------------------------------------------------------------------- + // drop small numerical entries from A, and entries in ignored part + //-------------------------------------------------------------------------- + + if (A->stype > 0) + { + + //---------------------------------------------------------------------- + // A is symmetric, with just upper triangular part stored + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + Ap [j] = nz ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i > j) continue ; + IF_DROP (Ax, Az, p, tol) continue ; + // keep this entry + Ai [nz] = i ; + ASSIGN (Ax, Az, nz, Ax, Az, p) ; + nz++ ; + } + } + + } + else if (A->stype < 0) + { + + //---------------------------------------------------------------------- + // A is symmetric, with just lower triangular part stored + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + Ap [j] = nz ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i < j) continue ; + IF_DROP (Ax, Az, p, tol) continue ; + // keep this entry + Ai [nz] = i ; + ASSIGN (Ax, Az, nz, Ax, Az, p) ; + nz++ ; + } + } + + } + else + { + + //---------------------------------------------------------------------- + // both parts of A present, just drop small entries + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + Ap [j] = nz ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + IF_DROP (Ax, Az, p, tol) continue ; + // keep this entry + Ai [nz] = i ; + ASSIGN (Ax, Az, nz, Ax, Az, p) ; + nz++ ; + } + } + } + + // finalize the last column of A + Ap [ncol] = nz ; + + // reduce A->i and A->x in size + ASSERT (MAX (1,nz) <= A->nzmax) ; + CHOLMOD(reallocate_sparse) (nz, A, Common) ; + ASSERT (Common->status >= CHOLMOD_OK) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + +#undef IF_DROP + diff --git a/CHOLMOD/MatrixOps/t_cholmod_horzcat_worker.c b/CHOLMOD/MatrixOps/t_cholmod_horzcat_worker.c new file mode 100644 index 0000000000..d4a853ca1f --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_horzcat_worker.c @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_horzcat_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_horzcat_worker) +( + cholmod_sparse *C, // output matrix + cholmod_sparse *A, // left matrix to concatenate + cholmod_sparse *B // right matrix to concatenate +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool apacked = A->packed ; + Int ancol = A->ncol ; + + Int *Bp = B->p ; + Int *Bnz = B->nz ; + Int *Bi = B->i ; + Real *Bx = B->x ; + Real *Bz = B->z ; + bool bpacked = B->packed ; + Int bncol = B->ncol ; + + Int *Cp = C->p ; + Int *Ci = C->i ; + Real *Cx = C->x ; + Real *Cz = C->z ; + Int ncol = C->ncol ; + + //-------------------------------------------------------------------------- + // C = [A , B] + //-------------------------------------------------------------------------- + + Int pc = 0 ; + + // copy A as the first A->ncol columns of C + for (Int j = 0 ; j < ancol ; j++) + { + // A(:,j) is the jth column of C + Int p = Ap [j] ; + Int pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; + Cp [j] = pc ; + for ( ; p < pend ; p++) + { + Ci [pc] = Ai [p] ; + ASSIGN (Cx, Cz, pc, Ax, Az, p) ; + pc++ ; + } + } + + // copy B as the next B->ncol columns of C + for (Int j = 0 ; j < bncol ; j++) + { + // B(:,j) is the (ancol+j)th column of C + Int p = Bp [j] ; + Int pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ; + Cp [ancol + j] = pc ; + for ( ; p < pend ; p++) + { + Ci [pc] = Bi [p] ; + ASSIGN (Cx, Cz, pc, Bx, Bz, p) ; + pc++ ; + } + } + Cp [ncol] = pc ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/MatrixOps/t_cholmod_norm_worker.c b/CHOLMOD/MatrixOps/t_cholmod_norm_worker.c new file mode 100644 index 0000000000..8d8cecf697 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_norm_worker.c @@ -0,0 +1,307 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_norm_worker: compute norm of a sparse matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// The intermediate values and the final result are always computed in +// double, even if the matrix is single precision. + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// t_cholmod_norm_dense_worker +//------------------------------------------------------------------------------ + +#ifndef PATTERN + +static double TEMPLATE (cholmod_norm_dense_worker) // return norm +( + // input: + cholmod_dense *X, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm + double *W // optional size-ncol workspace, always double +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int ncol = X->ncol ; + Int nrow = X->nrow ; + Int d = X->d ; + Real *Xx = X->x ; + Real *Xz = X->z ; + + double xnorm = 0 ; + + //-------------------------------------------------------------------------- + // compute the norm + //-------------------------------------------------------------------------- + + if (W != NULL) + { + + //---------------------------------------------------------------------- + // infinity-norm = max row sum, using stride-1 access of X + //---------------------------------------------------------------------- + + DEBUG (for (Int i = 0 ; i < nrow ; i++) ASSERT (W [i] == 0)) ; + + // this is faster than stride-d, but requires O(nrow) workspace + for (Int j = 0 ; j < ncol ; j++) + { + for (Int i = 0 ; i < nrow ; i++) + { + W [i] += ABS (Xx, Xz, i+j*d) ; + } + } + for (Int i = 0 ; i < nrow ; i++) + { + double s = W [i] ; + if ((isnan (s) || s > xnorm) && !isnan (xnorm)) + { + xnorm = s ; + } + W [i] = 0 ; + } + + } + else if (norm == 0) + { + + //---------------------------------------------------------------------- + // infinity-norm = max row sum, using stride-d access of X + //---------------------------------------------------------------------- + + for (Int i = 0 ; i < nrow ; i++) + { + double s = 0 ; + for (Int j = 0 ; j < ncol ; j++) + { + s += ABS (Xx, Xz, i+j*d) ; + } + if ((isnan (s) || s > xnorm) && !isnan (xnorm)) + { + xnorm = s ; + } + } + + } + else if (norm == 1) + { + + //---------------------------------------------------------------------- + // 1-norm = max column sum + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + double s = 0 ; + for (Int i = 0 ; i < nrow ; i++) + { + s += ABS (Xx, Xz, i+j*d) ; + } + if ((isnan (s) || s > xnorm) && !isnan (xnorm)) + { + xnorm = s ; + } + } + + } + else + { + + //---------------------------------------------------------------------- + // 2-norm = sqrt (sum (X.^2)) + //---------------------------------------------------------------------- + + for (Int i = 0 ; i < nrow ; i++) + { + double s = ABS (Xx, Xz, i) ; + xnorm += s*s ; + } + xnorm = sqrt (xnorm) ; + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + return (xnorm) ; +} + +#endif + +//------------------------------------------------------------------------------ +// t_cholmod_norm_sparse_worker +//------------------------------------------------------------------------------ + +static double TEMPLATE (cholmod_norm_sparse_worker) // return norm +( + // input: + cholmod_sparse *A, // matrix to compute the norm of + int norm, // type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm + double *W // optional size-ncol workspace, always double +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Ai = A->i ; + Int *Anz = A->nz ; + Real *Ax = A->x ; + Real *Az = A->z ; + Int ncol = A->ncol ; + Int nrow = A->nrow ; + bool packed = A->packed ; + + double anorm = 0 ; + + if (A->stype > 0) + { + + //---------------------------------------------------------------------- + // A is symmetric with upper triangular part stored + //---------------------------------------------------------------------- + + // infinity-norm = 1-norm = max row/col sum + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + double s = ABS (Ax, Az, p) ; + if (i == j) + { + W [i] += s ; + } + else if (i < j) + { + W [i] += s ; + W [j] += s ; + } + } + } + + } + else if (A->stype < 0) + { + + //---------------------------------------------------------------------- + // A is symmetric with lower triangular part stored + //---------------------------------------------------------------------- + + // infinity-norm = 1-norm = max row/col sum + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + double s = ABS (Ax, Az, p) ; + if (i == j) + { + W [i] += s ; + } + else if (i > j) + { + W [i] += s ; + W [j] += s ; + } + } + } + + } + else if (norm == 0) + { + + //---------------------------------------------------------------------- + // A is unsymmetric, compute the infinity-norm + //---------------------------------------------------------------------- + + // infinity-norm = max row sum + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + W [Ai [p]] += ABS (Ax, Az, p) ; + } + } + + } + else + { + + //---------------------------------------------------------------------- + // A is unsymmetric, compute the 1-norm + //---------------------------------------------------------------------- + + // 1-norm = max column sum + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + double s ; + #ifdef PATTERN + { + s = pend - p ; + } + #else + { + s = 0 ; + for ( ; p < pend ; p++) + { + s += ABS (Ax, Az, p) ; + } + } + #endif + if ((isnan (s) || s > anorm) && !isnan (anorm)) + { + anorm = s ; + } + } + } + + //-------------------------------------------------------------------------- + // compute the max row sum + //-------------------------------------------------------------------------- + + if (A->stype || norm == 0) + { + for (Int i = 0 ; i < nrow ; i++) + { + double s = W [i] ; + if ((isnan (s) || s > anorm) && !isnan (anorm)) + { + anorm = s ; + } + W [i] = 0 ; + } + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + return (anorm) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/MatrixOps/t_cholmod_scale_worker.c b/CHOLMOD/MatrixOps/t_cholmod_scale_worker.c new file mode 100644 index 0000000000..fc9244fe26 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_scale_worker.c @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_scale_worker: scale a sparse matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_scale_worker) +( + // input: + cholmod_dense *S, // scale factors (scalar or vector) + int scale, // type of scaling to compute + // input/output: + cholmod_sparse *A // matrix to scale +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool packed = A->packed ; + Int ncol = A->ncol ; + + Real *Sx = S->x ; + Real *Sz = S->z ; + + //-------------------------------------------------------------------------- + // scale the matrix + //-------------------------------------------------------------------------- + + if (scale == CHOLMOD_ROW) + { + + //---------------------------------------------------------------------- + // A = diag(s)*A, row scaling + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // t = S (i) * A (i,j) + Real tx [2] ; + Real tz [1] ; + MULT (tx, tz, 0, Sx, Sz, i, Ax, Az, p) ; + // A (i,j) = t + ASSIGN (Ax, Az, p, tx, tz, 0) ; + } + } + + } + else if (scale == CHOLMOD_COL) + { + + //---------------------------------------------------------------------- + // A = A*diag(s), column scaling + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + // s = S (j) + Real sx [2] ; + Real sz [1] ; + ASSIGN (sx, sz, 0, Sx, Sz, j) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // t = A (i,j) * s + Real tx [2] ; + Real tz [1] ; + MULT (tx, tz, 0, Ax, Az, p, sx, sz, 0) ; + // A (i,j) = t + ASSIGN (Ax, Az, p, tx, tz, 0) ; + } + } + + } + else if (scale == CHOLMOD_SYM) + { + + //---------------------------------------------------------------------- + // A = diag(s)*A*diag(s), symmetric scaling + //---------------------------------------------------------------------- + + for (Int j = 0 ; j < ncol ; j++) + { + // s = S (j) + Real sx [2] ; + Real sz [1] ; + ASSIGN (sx, sz, 0, Sx, Sz, j) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // t = A (i,j) * S (i) + Real tx [2] ; + Real tz [1] ; + MULT (tx, tz, 0, Ax, Az, p, Sx, Sz, i) ; + // A (i,j) = s * t + MULT (Ax, Az, p, sx, sz, 0, tx, tz, 0) ; + } + } + + } + else if (scale == CHOLMOD_SCALAR) + { + + //---------------------------------------------------------------------- + // A = s[0] * A, scalar scaling + //---------------------------------------------------------------------- + + // s = S (0) + Real sx [2] ; + Real sz [1] ; + ASSIGN (sx, sz, 0, Sx, Sz, 0) ; + + for (Int j = 0 ; j < ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // t = s * A (i,j) + Real tx [2] ; + Real tz [1] ; + MULT (tx, tz, 0, sx, sz, 0, Ax, Az, p) ; + // A (i,j) = t + ASSIGN (Ax, Az, p, tx, tz, 0) ; + } + } + } +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/MatrixOps/t_cholmod_sdmult.c b/CHOLMOD/MatrixOps/t_cholmod_sdmult.c deleted file mode 100644 index 5f8158cc23..0000000000 --- a/CHOLMOD/MatrixOps/t_cholmod_sdmult.c +++ /dev/null @@ -1,724 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/MatrixOps/t_cholmod_sdmult: template for cholmod_sdmult -//------------------------------------------------------------------------------ - -// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Template routine for cholmod_sdmult */ - -#include "cholmod_template.h" - -#undef ADVANCE - -#ifdef REAL -#define ADVANCE(x,z,d) x += d -#elif defined (COMPLEX) -#define ADVANCE(x,z,d) x += 2*d -#else -#define ADVANCE(x,z,d) x += d ; z += d -#endif - -/* ========================================================================== */ -/* === t_cholmod_sdmult ===================================================== */ -/* ========================================================================== */ - -static void TEMPLATE (cholmod_sdmult) -( - /* ---- input ---- */ - cholmod_sparse *A, /* sparse matrix to multiply */ - int transpose, /* use A if 0, or A' otherwise */ - double alpha [2], /* scale factor for A */ - double beta [2], /* scale factor for Y */ - cholmod_dense *X, /* dense matrix to multiply */ - /* ---- in/out --- */ - cholmod_dense *Y, /* resulting dense matrix */ - /* -- workspace -- */ - double *W /* size 4*nx if needed, twice that for c/zomplex case */ -) -{ - - double yx [8], xx [8], ax [2] ; -#ifdef ZOMPLEX - double yz [4], xz [4], az [1] ; - double betaz [1], alphaz [1] ; -#endif - - double *Ax, *Az, *Xx, *Xz, *Yx, *Yz, *w, *Wz ; - Int *Ap, *Ai, *Anz ; - size_t nx, ny, dx, dy ; - Int packed, nrow, ncol, j, k, p, pend, kcol, i ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - -#ifdef ZOMPLEX - betaz [0] = beta [1] ; - alphaz [0] = alpha [1] ; -#endif - - ny = transpose ? A->ncol : A->nrow ; /* required length of Y */ - nx = transpose ? A->nrow : A->ncol ; /* required length of X */ - - nrow = A->nrow ; - ncol = A->ncol ; - - Ap = A->p ; - Anz = A->nz ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - packed = A->packed ; - Xx = X->x ; - Xz = X->z ; - Yx = Y->x ; - Yz = Y->z ; - kcol = X->ncol ; - dy = Y->d ; - dx = X->d ; - w = W ; - Wz = W + 4*nx ; - - /* ---------------------------------------------------------------------- */ - /* Y = beta * Y */ - /* ---------------------------------------------------------------------- */ - - if (ENTRY_IS_ZERO (beta, betaz, 0)) - { - for (k = 0 ; k < kcol ; k++) - { - for (i = 0 ; i < ((Int) ny) ; i++) - { - /* y [i] = 0. ; */ - CLEAR (Yx, Yz, i) ; - } - /* y += dy ; */ - ADVANCE (Yx,Yz,dy) ; - } - } - else if (!ENTRY_IS_ONE (beta, betaz, 0)) - { - for (k = 0 ; k < kcol ; k++) - { - for (i = 0 ; i < ((Int) ny) ; i++) - { - /* y [i] *= beta [0] ; */ - MULT (Yx,Yz,i, Yx,Yz,i, beta,betaz, 0) ; - } - /* y += dy ; */ - ADVANCE (Yx,Yz,dy) ; - } - } - - if (ENTRY_IS_ZERO (alpha, alphaz, 0)) - { - /* nothing else to do */ - return ; - } - - /* ---------------------------------------------------------------------- */ - /* Y += alpha * op(A) * X, where op(A)=A or A' */ - /* ---------------------------------------------------------------------- */ - - Yx = Y->x ; - Yz = Y->z ; - - k = 0 ; - - if (A->stype == 0) - { - - if (transpose) - { - - /* -------------------------------------------------------------- */ - /* Y += alpha * A' * x, unsymmetric case */ - /* -------------------------------------------------------------- */ - - if (kcol % 4 == 1) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj = 0. ; */ - CLEAR (yx, yz, 0) ; - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - /* yj += conj(Ax [p]) * x [Ai [p]] ; */ - i = Ai [p] ; - ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; - MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; - } - /* y [j] += alpha [0] * yj ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - } - /* y += dy ; */ - /* x += dx ; */ - ADVANCE (Yx,Yz,dy) ; - ADVANCE (Xx,Xz,dx) ; - k++ ; - - } - else if (kcol % 4 == 2) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = conj (Ax [p]) ; */ - ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; - - /* yj0 += aij * x [i ] ; */ - /* yj1 += aij * x [i+dx] ; */ - MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; - MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+dy] += alpha [0] * yj1 ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; - } - /* y += 2*dy ; */ - /* x += 2*dx ; */ - ADVANCE (Yx,Yz,2*dy) ; - ADVANCE (Xx,Xz,2*dx) ; - k += 2 ; - - } - else if (kcol % 4 == 3) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - /* yj2 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - CLEAR (yx,yz,2) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = conj (Ax [p]) ; */ - ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; - - /* yj0 += aij * x [i ] ; */ - /* yj1 += aij * x [i+ dx] ; */ - /* yj2 += aij * x [i+2*dx] ; */ - MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; - MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; - MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+ dy] += alpha [0] * yj1 ; */ - /* y [j+2*dy] += alpha [0] * yj2 ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; - MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; - } - /* y += 3*dy ; */ - /* x += 3*dx ; */ - ADVANCE (Yx,Yz,3*dy) ; - ADVANCE (Xx,Xz,3*dx) ; - k += 3 ; - } - - for ( ; k < kcol ; k += 4) - { - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - /* yj2 = 0. ; */ - /* yj3 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - CLEAR (yx,yz,2) ; - CLEAR (yx,yz,3) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = conj(Ax [p]) ; */ - ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; - - /* yj0 += aij * x [i ] ; */ - /* yj1 += aij * x [i+ dx] ; */ - /* yj2 += aij * x [i+2*dx] ; */ - /* yj3 += aij * x [i+3*dx] ; */ - MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; - MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; - MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; - MULTADD (yx,yz,3, ax,az,0, Xx,Xz,i+3*dx) ; - - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+ dy] += alpha [0] * yj1 ; */ - /* y [j+2*dy] += alpha [0] * yj2 ; */ - /* y [j+3*dy] += alpha [0] * yj3 ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; - MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; - MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ; - } - /* y += 4*dy ; */ - /* x += 4*dx ; */ - ADVANCE (Yx,Yz,4*dy) ; - ADVANCE (Xx,Xz,4*dx) ; - } - - } - else - { - - /* -------------------------------------------------------------- */ - /* Y += alpha * A * x, unsymmetric case */ - /* -------------------------------------------------------------- */ - - if (kcol % 4 == 1) - { - - for (j = 0 ; j < ncol ; j++) - { - /* xj = alpha [0] * x [j] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - /* y [Ai [p]] += Ax [p] * xj ; */ - i = Ai [p] ; - MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ; - } - } - /* y += dy ; */ - /* x += dx ; */ - ADVANCE (Yx,Yz,dy) ; - ADVANCE (Xx,Xz,dx) ; - k++ ; - - } - else if (kcol % 4 == 2) - { - - for (j = 0 ; j < ncol ; j++) - { - /* xj0 = alpha [0] * x [j ] ; */ - /* xj1 = alpha [0] * x [j+dx] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+dy] += aij * xj1 ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - } - } - /* y += 2*dy ; */ - /* x += 2*dx ; */ - ADVANCE (Yx,Yz,2*dy) ; - ADVANCE (Xx,Xz,2*dx) ; - k += 2 ; - - } - else if (kcol % 4 == 3) - { - - for (j = 0 ; j < ncol ; j++) - { - /* xj0 = alpha [0] * x [j ] ; */ - /* xj1 = alpha [0] * x [j+ dx] ; */ - /* xj2 = alpha [0] * x [j+2*dx] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; - MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - } - } - /* y += 3*dy ; */ - /* x += 3*dx ; */ - ADVANCE (Yx,Yz,3*dy) ; - ADVANCE (Xx,Xz,3*dx) ; - k += 3 ; - } - - for ( ; k < kcol ; k += 4) - { - for (j = 0 ; j < ncol ; j++) - { - /* xj0 = alpha [0] * x [j ] ; */ - /* xj1 = alpha [0] * x [j+ dx] ; */ - /* xj2 = alpha [0] * x [j+2*dx] ; */ - /* xj3 = alpha [0] * x [j+3*dx] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; - MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; - MULT (xx,xz,3, alpha,alphaz,0, Xx,Xz,j+3*dx) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - /* y [i+3*dy] += aij * xj3 ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; - } - } - /* y += 4*dy ; */ - /* x += 4*dx ; */ - ADVANCE (Yx,Yz,4*dy) ; - ADVANCE (Xx,Xz,4*dx) ; - } - } - - } - else - { - - /* ------------------------------------------------------------------ */ - /* Y += alpha * (A or A') * x, symmetric case (upper/lower) */ - /* ------------------------------------------------------------------ */ - - /* Only the upper/lower triangular part and the diagonal of A is used. - * Since both x and y are written to in the innermost loop, this - * code can experience cache bank conflicts if x is used directly. - * Thus, a copy is made of x, four columns at a time, if x has - * four or more columns. - */ - - if (kcol % 4 == 1) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj = 0. ; */ - CLEAR (yx,yz,0) ; - - /* xj = alpha [0] * x [j] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i == j) - { - /* y [i] += Ax [p] * xj ; */ - MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ; - } - else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) - { - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i] += aij * xj ; */ - /* yj += aij * x [i] ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; - - - } - } - /* y [j] += alpha [0] * yj ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - - } - /* y += dy ; */ - /* x += dx ; */ - ADVANCE (Yx,Yz,dy) ; - ADVANCE (Xx,Xz,dx) ; - k++ ; - - } - else if (kcol % 4 == 2) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - - /* xj0 = alpha [0] * x [j ] ; */ - /* xj1 = alpha [0] * x [j+dx] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i == j) - { - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+dy] += aij * xj1 ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - - } - else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) - { - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+dy] += aij * xj1 ; */ - /* yj0 += aij * x [i ] ; */ - /* yj1 += aij * x [i+dx] ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; - MULTADDCONJ (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; - - } - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+dy] += alpha [0] * yj1 ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; - - } - /* y += 2*dy ; */ - /* x += 2*dx ; */ - ADVANCE (Yx,Yz,2*dy) ; - ADVANCE (Xx,Xz,2*dx) ; - k += 2 ; - - } - else if (kcol % 4 == 3) - { - - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - /* yj2 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - CLEAR (yx,yz,2) ; - - /* xj0 = alpha [0] * x [j ] ; */ - /* xj1 = alpha [0] * x [j+ dx] ; */ - /* xj2 = alpha [0] * x [j+2*dx] ; */ - MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; - MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; - MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i == j) - { - - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - - } - else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) - { - - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - /* yj0 += aij * x [i ] ; */ - /* yj1 += aij * x [i+ dx] ; */ - /* yj2 += aij * x [i+2*dx] ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; - MULTADDCONJ (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; - MULTADDCONJ (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; - - } - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+ dy] += alpha [0] * yj1 ; */ - /* y [j+2*dy] += alpha [0] * yj2 ; */ - MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; - MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; - - } - /* y += 3*dy ; */ - /* x += 3*dx ; */ - ADVANCE (Yx,Yz,3*dy) ; - ADVANCE (Xx,Xz,3*dx) ; - - k += 3 ; - } - - /* copy four columns of X into W, and put in row form */ - for ( ; k < kcol ; k += 4) - { - - for (j = 0 ; j < ncol ; j++) - { - /* w [4*j ] = x [j ] ; */ - /* w [4*j+1] = x [j+ dx] ; */ - /* w [4*j+2] = x [j+2*dx] ; */ - /* w [4*j+3] = x [j+3*dx] ; */ - ASSIGN (w,Wz,4*j , Xx,Xz,j ) ; - ASSIGN (w,Wz,4*j+1, Xx,Xz,j+dx ) ; - ASSIGN (w,Wz,4*j+2, Xx,Xz,j+2*dx) ; - ASSIGN (w,Wz,4*j+3, Xx,Xz,j+3*dx) ; - } - - for (j = 0 ; j < ncol ; j++) - { - /* yj0 = 0. ; */ - /* yj1 = 0. ; */ - /* yj2 = 0. ; */ - /* yj3 = 0. ; */ - CLEAR (yx,yz,0) ; - CLEAR (yx,yz,1) ; - CLEAR (yx,yz,2) ; - CLEAR (yx,yz,3) ; - - /* xj0 = alpha [0] * w [4*j ] ; */ - /* xj1 = alpha [0] * w [4*j+1] ; */ - /* xj2 = alpha [0] * w [4*j+2] ; */ - /* xj3 = alpha [0] * w [4*j+3] ; */ - MULT (xx,xz,0, alpha,alphaz,0, w,Wz,4*j) ; - MULT (xx,xz,1, alpha,alphaz,0, w,Wz,4*j+1) ; - MULT (xx,xz,2, alpha,alphaz,0, w,Wz,4*j+2) ; - MULT (xx,xz,3, alpha,alphaz,0, w,Wz,4*j+3) ; - - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i == j) - { - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - /* y [i+3*dy] += aij * xj3 ; */ - MULTADD (Yx,Yz,i , ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy , ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; - - } - else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) - { - /* aij = Ax [p] ; */ - ASSIGN (ax,az,0, Ax,Az,p) ; - - /* y [i ] += aij * xj0 ; */ - /* y [i+ dy] += aij * xj1 ; */ - /* y [i+2*dy] += aij * xj2 ; */ - /* y [i+3*dy] += aij * xj3 ; */ - /* yj0 += aij * w [4*i ] ; */ - /* yj1 += aij * w [4*i+1] ; */ - /* yj2 += aij * w [4*i+2] ; */ - /* yj3 += aij * w [4*i+3] ; */ - MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; - MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; - MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; - MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; - MULTADDCONJ (yx,yz,0, ax,az,0, w,Wz,4*i) ; - MULTADDCONJ (yx,yz,1, ax,az,0, w,Wz,4*i+1) ; - MULTADDCONJ (yx,yz,2, ax,az,0, w,Wz,4*i+2) ; - MULTADDCONJ (yx,yz,3, ax,az,0, w,Wz,4*i+3) ; - - } - } - /* y [j ] += alpha [0] * yj0 ; */ - /* y [j+ dy] += alpha [0] * yj1 ; */ - /* y [j+2*dy] += alpha [0] * yj2 ; */ - /* y [j+3*dy] += alpha [0] * yj3 ; */ - MULTADD (Yx,Yz,j , alpha,alphaz,0, yx,yz,0) ; - MULTADD (Yx,Yz,j+dy , alpha,alphaz,0, yx,yz,1) ; - MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; - MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ; - - } - /* y += 4*dy ; */ - /* x += 4*dx ; */ - ADVANCE (Yx,Yz,4*dy) ; - ADVANCE (Xx,Xz,4*dx) ; - - } - } -} - - -#undef PATTERN -#undef REAL -#undef COMPLEX -#undef ZOMPLEX diff --git a/CHOLMOD/MatrixOps/t_cholmod_sdmult_worker.c b/CHOLMOD/MatrixOps/t_cholmod_sdmult_worker.c new file mode 100644 index 0000000000..d7ad2f01f6 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_sdmult_worker.c @@ -0,0 +1,718 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_sdmult_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// ADVANCE macro +//------------------------------------------------------------------------------ + +#ifdef REAL +#define ADVANCE(x,z,d) x += d +#elif defined (COMPLEX) +#define ADVANCE(x,z,d) x += 2*d +#else +#define ADVANCE(x,z,d) x += d ; z += d +#endif + +//------------------------------------------------------------------------------ +// t_cholmod_sdmult_worker +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_sdmult_worker) +( + // input: + cholmod_sparse *A, // sparse matrix to multiply + int transpose, // use A if 0, or A' otherwise + Real alpha [2], // scale factor for A + Real beta [2], // scale factor for Y + cholmod_dense *X, // dense matrix to multiply + // input/output: + cholmod_dense *Y, // resulting dense matrix + // workspace + Real *W // size 4*nx if needed, twice that for c/zomplex case +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real yx [8], xx [8], ax [2] ; + + #ifdef ZOMPLEX + Real yz [4], xz [4], az [1] ; + Real betaz [1], alphaz [1] ; + betaz [0] = beta [1] ; + alphaz [0] = alpha [1] ; + #endif + + size_t ny = transpose ? A->ncol : A->nrow ; // required length of Y + size_t nx = transpose ? A->nrow : A->ncol ; // required length of X + + Int nrow = A->nrow ; + Int ncol = A->ncol ; + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool packed = A->packed ; + + Real *Xx = X->x ; + Real *Xz = X->z ; + Real *Yx = Y->x ; + Real *Yz = Y->z ; + + Int kcol = X->ncol ; + size_t dy = Y->d ; + size_t dx = X->d ; + Real *w = W ; + Real *Wz = W + 4*nx ; + + //-------------------------------------------------------------------------- + // Y = beta * Y + //-------------------------------------------------------------------------- + + if (ENTRY_IS_ZERO (beta, betaz, 0)) + { + for (Int k = 0 ; k < kcol ; k++) + { + for (Int i = 0 ; i < ((Int) ny) ; i++) + { + // y [i] = 0 + CLEAR (Yx, Yz, i) ; + } + // y += dy + ADVANCE (Yx,Yz,dy) ; + } + } + else if (!ENTRY_IS_ONE (beta, betaz, 0)) + { + for (Int k = 0 ; k < kcol ; k++) + { + for (Int i = 0 ; i < ((Int) ny) ; i++) + { + // y [i] *= beta [0] + MULT (Yx,Yz,i, Yx,Yz,i, beta,betaz, 0) ; + } + // y += dy + ADVANCE (Yx,Yz,dy) ; + } + } + + if (ENTRY_IS_ZERO (alpha, alphaz, 0)) + { + // nothing else to do + return ; + } + + //-------------------------------------------------------------------------- + // Y += alpha * op(A) * X, where op(A)=A or A' + //-------------------------------------------------------------------------- + + Yx = Y->x ; + Yz = Y->z ; + Int k = 0 ; + + if (A->stype == 0) + { + + if (transpose) + { + + //------------------------------------------------------------------ + // Y += alpha * A' * x, unsymmetric case + //------------------------------------------------------------------ + + if (kcol % 4 == 1) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj = 0 + CLEAR (yx, yz, 0) ; + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // yj += conj(Ax [p]) * x [Ai [p]] + Int i = Ai [p] ; + ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; + MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; + } + // y [j] += alpha [0] * yj + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + } + // y += dy + // x += dx + ADVANCE (Yx,Yz,dy) ; + ADVANCE (Xx,Xz,dx) ; + k++ ; + + } + else if (kcol % 4 == 2) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = conj (Ax [p]) + ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; + + // yj0 += aij * x [i ] + // yj1 += aij * x [i+dx] + MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; + MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; + } + // y [j ] += alpha [0] * yj0 + // y [j+dy] += alpha [0] * yj1 + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; + } + // y += 2*dy + // x += 2*dx + ADVANCE (Yx,Yz,2*dy) ; + ADVANCE (Xx,Xz,2*dx) ; + k += 2 ; + + } + else if (kcol % 4 == 3) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + // yj2 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + CLEAR (yx,yz,2) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = conj (Ax [p]) + ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; + + // yj0 += aij * x [i ] + // yj1 += aij * x [i+ dx] + // yj2 += aij * x [i+2*dx] + MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; + MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; + MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; + } + // y [j ] += alpha [0] * yj0 + // y [j+ dy] += alpha [0] * yj1 + // y [j+2*dy] += alpha [0] * yj2 + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; + MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; + } + // y += 3*dy + // x += 3*dx + ADVANCE (Yx,Yz,3*dy) ; + ADVANCE (Xx,Xz,3*dx) ; + k += 3 ; + } + + for ( ; k < kcol ; k += 4) + { + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + // yj2 = 0 + // yj3 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + CLEAR (yx,yz,2) ; + CLEAR (yx,yz,3) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = conj(Ax [p]) + ASSIGN_CONJ (ax,az,0, Ax,Az,p) ; + + // yj0 += aij * x [i ] + // yj1 += aij * x [i+ dx] + // yj2 += aij * x [i+2*dx] + // yj3 += aij * x [i+3*dx] + MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ; + MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; + MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; + MULTADD (yx,yz,3, ax,az,0, Xx,Xz,i+3*dx) ; + + } + // y [j ] += alpha [0] * yj0 + // y [j+ dy] += alpha [0] * yj1 + // y [j+2*dy] += alpha [0] * yj2 + // y [j+3*dy] += alpha [0] * yj3 + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; + MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; + MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ; + } + // y += 4*dy + // x += 4*dx + ADVANCE (Yx,Yz,4*dy) ; + ADVANCE (Xx,Xz,4*dx) ; + } + + } + else + { + + //------------------------------------------------------------------ + // Y += alpha * A * x, unsymmetric case + //------------------------------------------------------------------ + + if (kcol % 4 == 1) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // xj = alpha [0] * x [j] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // y [Ai [p]] += Ax [p] * xj + Int i = Ai [p] ; + MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ; + } + } + // y += dy + // x += dx + ADVANCE (Yx,Yz,dy) ; + ADVANCE (Xx,Xz,dx) ; + k++ ; + + } + else if (kcol % 4 == 2) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // xj0 = alpha [0] * x [j ] + // xj1 = alpha [0] * x [j+dx] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+dy] += aij * xj1 + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + } + } + // y += 2*dy + // x += 2*dx + ADVANCE (Yx,Yz,2*dy) ; + ADVANCE (Xx,Xz,2*dx) ; + k += 2 ; + + } + else if (kcol % 4 == 3) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // xj0 = alpha [0] * x [j ] + // xj1 = alpha [0] * x [j+ dx] + // xj2 = alpha [0] * x [j+2*dx] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; + MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + } + } + // y += 3*dy + // x += 3*dx + ADVANCE (Yx,Yz,3*dy) ; + ADVANCE (Xx,Xz,3*dx) ; + k += 3 ; + } + + for ( ; k < kcol ; k += 4) + { + for (Int j = 0 ; j < ncol ; j++) + { + // xj0 = alpha [0] * x [j ] + // xj1 = alpha [0] * x [j+ dx] + // xj2 = alpha [0] * x [j+2*dx] + // xj3 = alpha [0] * x [j+3*dx] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; + MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; + MULT (xx,xz,3, alpha,alphaz,0, Xx,Xz,j+3*dx) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + // y [i+3*dy] += aij * xj3 + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; + } + } + // y += 4*dy + // x += 4*dx + ADVANCE (Yx,Yz,4*dy) ; + ADVANCE (Xx,Xz,4*dx) ; + } + } + + } + else + { + + //---------------------------------------------------------------------- + // Y += alpha * A * x, symmetric case (upper/lower) + //---------------------------------------------------------------------- + + // Only the upper/lower triangular part and the diagonal of A is used. + // Since both x and y are written to in the innermost loop, this code + // can experience cache bank conflicts if x is used directly. Thus, a + // copy is made of x, four columns at a time, if x has four or more + // columns. + + if (kcol % 4 == 1) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj = 0 + CLEAR (yx,yz,0) ; + + // xj = alpha [0] * x [j] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i == j) + { + // y [i] += Ax [p] * xj + MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ; + } + else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) + { + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i] += aij * xj + // yj += aij * x [i] + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; + + + } + } + // y [j] += alpha [0] * yj + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + + } + // y += dy + // x += dx + ADVANCE (Yx,Yz,dy) ; + ADVANCE (Xx,Xz,dx) ; + k++ ; + + } + else if (kcol % 4 == 2) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + + // xj0 = alpha [0] * x [j ] + // xj1 = alpha [0] * x [j+dx] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i == j) + { + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+dy] += aij * xj1 + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + + } + else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) + { + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+dy] += aij * xj1 + // yj0 += aij * x [i ] + // yj1 += aij * x [i+dx] + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; + MULTADDCONJ (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; + + } + } + // y [j ] += alpha [0] * yj0 + // y [j+dy] += alpha [0] * yj1 + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; + + } + // y += 2*dy + // x += 2*dx + ADVANCE (Yx,Yz,2*dy) ; + ADVANCE (Xx,Xz,2*dx) ; + k += 2 ; + + } + else if (kcol % 4 == 3) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + // yj2 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + CLEAR (yx,yz,2) ; + + // xj0 = alpha [0] * x [j ] + // xj1 = alpha [0] * x [j+ dx] + // xj2 = alpha [0] * x [j+2*dx] + MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ; + MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ; + MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i == j) + { + + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + + } + else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) + { + + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + // yj0 += aij * x [i ] + // yj1 += aij * x [i+ dx] + // yj2 += aij * x [i+2*dx] + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ; + MULTADDCONJ (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ; + MULTADDCONJ (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ; + + } + } + // y [j ] += alpha [0] * yj0 + // y [j+ dy] += alpha [0] * yj1 + // y [j+2*dy] += alpha [0] * yj2 + MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ; + MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; + + } + // y += 3*dy + // x += 3*dx + ADVANCE (Yx,Yz,3*dy) ; + ADVANCE (Xx,Xz,3*dx) ; + + k += 3 ; + } + + // copy four columns of X into W, and put in row form + for ( ; k < kcol ; k += 4) + { + + for (Int j = 0 ; j < ncol ; j++) + { + // w [4*j ] = x [j ] + // w [4*j+1] = x [j+ dx] + // w [4*j+2] = x [j+2*dx] + // w [4*j+3] = x [j+3*dx] + ASSIGN (w,Wz,4*j , Xx,Xz,j ) ; + ASSIGN (w,Wz,4*j+1, Xx,Xz,j+dx ) ; + ASSIGN (w,Wz,4*j+2, Xx,Xz,j+2*dx) ; + ASSIGN (w,Wz,4*j+3, Xx,Xz,j+3*dx) ; + } + + for (Int j = 0 ; j < ncol ; j++) + { + // yj0 = 0 + // yj1 = 0 + // yj2 = 0 + // yj3 = 0 + CLEAR (yx,yz,0) ; + CLEAR (yx,yz,1) ; + CLEAR (yx,yz,2) ; + CLEAR (yx,yz,3) ; + + // xj0 = alpha [0] * w [4*j ] + // xj1 = alpha [0] * w [4*j+1] + // xj2 = alpha [0] * w [4*j+2] + // xj3 = alpha [0] * w [4*j+3] + MULT (xx,xz,0, alpha,alphaz,0, w,Wz,4*j) ; + MULT (xx,xz,1, alpha,alphaz,0, w,Wz,4*j+1) ; + MULT (xx,xz,2, alpha,alphaz,0, w,Wz,4*j+2) ; + MULT (xx,xz,3, alpha,alphaz,0, w,Wz,4*j+3) ; + + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (i == j) + { + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + // y [i+3*dy] += aij * xj3 + MULTADD (Yx,Yz,i , ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy , ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; + + } + else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j)) + { + // aij = Ax [p] + ASSIGN (ax,az,0, Ax,Az,p) ; + + // y [i ] += aij * xj0 + // y [i+ dy] += aij * xj1 + // y [i+2*dy] += aij * xj2 + // y [i+3*dy] += aij * xj3 + // yj0 += aij * w [4*i ] + // yj1 += aij * w [4*i+1] + // yj2 += aij * w [4*i+2] + // yj3 += aij * w [4*i+3] + MULTADD (Yx,Yz,i, ax,az,0, xx,xz,0) ; + MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ; + MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ; + MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ; + MULTADDCONJ (yx,yz,0, ax,az,0, w,Wz,4*i) ; + MULTADDCONJ (yx,yz,1, ax,az,0, w,Wz,4*i+1) ; + MULTADDCONJ (yx,yz,2, ax,az,0, w,Wz,4*i+2) ; + MULTADDCONJ (yx,yz,3, ax,az,0, w,Wz,4*i+3) ; + + } + } + // y [j ] += alpha [0] * yj0 + // y [j+ dy] += alpha [0] * yj1 + // y [j+2*dy] += alpha [0] * yj2 + // y [j+3*dy] += alpha [0] * yj3 + MULTADD (Yx,Yz,j , alpha,alphaz,0, yx,yz,0) ; + MULTADD (Yx,Yz,j+dy , alpha,alphaz,0, yx,yz,1) ; + MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ; + MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ; + + } + // y += 4*dy + // x += 4*dx + ADVANCE (Yx,Yz,4*dy) ; + ADVANCE (Xx,Xz,4*dx) ; + } + } +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + +#undef ADVANCE + diff --git a/CHOLMOD/MatrixOps/t_cholmod_ssmult_worker.c b/CHOLMOD/MatrixOps/t_cholmod_ssmult_worker.c new file mode 100644 index 0000000000..b9b8221a5e --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_ssmult_worker.c @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_ssmult_worker: sparse-times-sparse matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_ssmult_worker) +( + cholmod_sparse *C, + cholmod_sparse *A, + cholmod_sparse *B, + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *W = Common->Xwork ; + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool apacked = A->packed ; + + Int *Bp = B->p ; + Int *Bnz = B->nz ; + Int *Bi = B->i ; + Real *Bx = B->x ; + Real *Bz = B->z ; + bool bpacked = B->packed ; + + // get the size of C + Int nrow = A->nrow ; + Int ncol = B->ncol ; + + // get workspace + Real *Wx = Common->Xwork ; // size nrow, unused if C is pattern + Real *Wz = Wx + nrow ; // only used for the zomplex case + Int *Flag = Common->Flag ; // size nrow, Flag [0..nrow-1] < mark on input + + Int *Cp = C->p ; + Int *Ci = C->i ; + Real *Cx = C->x ; + Real *Cz = C->z ; + + //-------------------------------------------------------------------------- + // C = A*B + //-------------------------------------------------------------------------- + + Int pc = 0 ; + + for (Int j = 0 ; j < ncol ; j++) + { + // clear the Flag array + CLEAR_FLAG (Common) ; + Int mark = Common->mark ; + + // start column j of C + Cp [j] = pc ; + + // for each nonzero B(k,j) in column j, do: + Int pb = Bp [j] ; + Int pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; + for ( ; pb < pbend ; pb++) + { + // B(k,j) is nonzero + Int k = Bi [pb] ; + + // b = Bx [pb] ; + Real bx [2] ; + Real bz [1] ; + ASSIGN (bx, bz, 0, Bx, Bz, pb) ; + + // add the nonzero pattern of A(:,k) to the pattern of C(:,j) + // and scatter the values into W + Int pa = Ap [k] ; + Int paend = (apacked) ? (Ap [k+1]) : (pa + Anz [k]) ; + for ( ; pa < paend ; pa++) + { + Int i = Ai [pa] ; + if (Flag [i] != mark) + { + Flag [i] = mark ; + Ci [pc++] = i ; + } + // W (i) += Ax [pa] * b ; + MULTADD (Wx, Wz, i, Ax, Az, pa, bx, bz, 0) ; + } + } + + // gather the values into C(:,j) + #ifndef PATTERN + for (Int p = Cp [j] ; p < pc ; p++) + { + Int i = Ci [p] ; + // Cx [p] = W (i) ; + ASSIGN (Cx, Cz, p, Wx, Wz, i) ; + // W (i) = 0 ; + CLEAR (Wx, Wz, i) ; + } + #endif + } + + Cp [ncol] = pc ; + ASSERT (MAX (1,pc) == C->nzmax) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/MatrixOps/t_cholmod_submatrix_worker.c b/CHOLMOD/MatrixOps/t_cholmod_submatrix_worker.c new file mode 100644 index 0000000000..40192ae480 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_submatrix_worker.c @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_submatrix_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_submatrix_worker) +( + cholmod_sparse *C, + cholmod_sparse *A, + Int nr, + Int nc, + Int *cset, // set of column indices, duplicates OK + Int *Head, + Int *Rnext +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Ai = A->i ; + Int *Anz = A->nz ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool packed = A->packed ; + + Int *Cp = C->p ; + Int *Ci = C->i ; + Real *Cx = C->x ; + Real *Cz = C->z ; + Int cncol = C->ncol ; + + //-------------------------------------------------------------------------- + // C = A (rset, cset) + //-------------------------------------------------------------------------- + + Int pc = 0 ; + + if (nr < 0) + { + + //---------------------------------------------------------------------- + // C = A (:,cset), where cset is not empty + //---------------------------------------------------------------------- + + for (Int cj = 0 ; cj < cncol ; cj++) + { + // construct column cj of C, which is column j of A + PRINT1 (("construct cj = j = "ID"\n", cj)) ; + Int j = cset [cj] ; + Cp [cj] = pc ; + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Ci [pc] = Ai [p] ; + ASSIGN (Cx, Cz, pc, Ax, Az, p) ; + pc++ ; + ASSERT (pc <= C->nzmax) ; + } + } + + } + else + { + + //---------------------------------------------------------------------- + // C = A (rset,cset), where rset is not empty but cset might be empty + //---------------------------------------------------------------------- + + for (Int cj = 0 ; cj < cncol ; cj++) + { + // construct column cj of C, which is column j of A + PRINT1 (("construct cj = "ID"\n", cj)) ; + Int j = (nc < 0) ? cj : (cset [cj]) ; + PRINT1 (("cj = "ID"\n", j)) ; + Cp [cj] = pc ; + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + // row (Ai [p]) of A becomes multiple rows (ci) of C + PRINT2 (("i: "ID" becomes: ", Ai [p])) ; + for (Int ci = Head [Ai [p]] ; ci != EMPTY ; ci = Rnext [ci]) + { + PRINT3 ((""ID" ", ci)) ; + Ci [pc] = ci ; + ASSIGN (Cx, Cz, pc, Ax, Az, p) ; + pc++ ; + ASSERT (pc <= C->nzmax) ; + } + PRINT2 (("\n")) ; + } + } + } + + // finalize the last column of C + Cp [cncol] = pc ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/MatrixOps/t_cholmod_vertcat_worker.c b/CHOLMOD/MatrixOps/t_cholmod_vertcat_worker.c new file mode 100644 index 0000000000..8570626a08 --- /dev/null +++ b/CHOLMOD/MatrixOps/t_cholmod_vertcat_worker.c @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/MatrixOps/t_cholmod_vertcat_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static void TEMPLATE (cholmod_vertcat_worker) +( + cholmod_sparse *C, // output matrix + cholmod_sparse *A, // top matrix to concatenate + cholmod_sparse *B // bottom matrix to concatenate +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Ap = A->p ; + Int *Anz = A->nz ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + bool apacked = A->packed ; + Int anrow = A->nrow ; + + Int *Bp = B->p ; + Int *Bnz = B->nz ; + Int *Bi = B->i ; + Real *Bx = B->x ; + Real *Bz = B->z ; + bool bpacked = B->packed ; + + Int *Cp = C->p ; + Int *Ci = C->i ; + Real *Cx = C->x ; + Real *Cz = C->z ; + Int ncol = C->ncol ; + + //-------------------------------------------------------------------------- + // C = [A ; B] + //-------------------------------------------------------------------------- + + Int pc = 0 ; + + for (Int j = 0 ; j < ncol ; j++) + { + // append A(:,j) as the first part of C(:,j) + Int p = Ap [j] ; + Int pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; + Cp [j] = pc ; + for ( ; p < pend ; p++) + { + Ci [pc] = Ai [p] ; + ASSIGN (Cx, Cz, pc, Ax, Az, p) ; + pc++ ; + } + + // append B(:,j) as the second part of C(:,j) + p = Bp [j] ; + pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ; + for ( ; p < pend ; p++) + { + Ci [pc] = Bi [p] + anrow ; + ASSIGN (Cx, Cz, pc, Bx, Bz, p) ; + pc++ ; + } + } + Cp [ncol] = pc ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Modify/cholmod_l_rowadd.c b/CHOLMOD/Modify/cholmod_l_rowadd.c index 86bcd9cf41..dab33443c3 100644 --- a/CHOLMOD/Modify/cholmod_l_rowadd.c +++ b/CHOLMOD/Modify/cholmod_l_rowadd.c @@ -2,7 +2,7 @@ // CHOLMOD/Modify/cholmod_l_rowadd.c: int64_t version of cholmod_rowadd //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Modify/cholmod_l_rowdel.c b/CHOLMOD/Modify/cholmod_l_rowdel.c index c8839bc116..a774be28df 100644 --- a/CHOLMOD/Modify/cholmod_l_rowdel.c +++ b/CHOLMOD/Modify/cholmod_l_rowdel.c @@ -2,7 +2,7 @@ // CHOLMOD/Modify/cholmod_l_rowdel.c: int64_t version of cholmod_rowdel //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Modify/cholmod_l_updown.c b/CHOLMOD/Modify/cholmod_l_updown.c index a37713cb71..25a4bc131c 100644 --- a/CHOLMOD/Modify/cholmod_l_updown.c +++ b/CHOLMOD/Modify/cholmod_l_updown.c @@ -2,7 +2,7 @@ // CHOLMOD/Modify/cholmod_l_updown.c: int64_t version of cholmod_updown //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Modify/cholmod_rowadd.c b/CHOLMOD/Modify/cholmod_rowadd.c index 32811db1be..0b83e9dbcc 100644 --- a/CHOLMOD/Modify/cholmod_rowadd.c +++ b/CHOLMOD/Modify/cholmod_rowadd.c @@ -2,47 +2,75 @@ // CHOLMOD/Modify/cholmod_rowadd: add row/column to an LDL' factorization //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // and William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Adds a row and column to an LDL' factorization, and optionally updates the - * solution to Lx=b. - * - * workspace: Flag (nrow), Head (nrow+1), W (2*nrow), Iwork (2*nrow) - * - * Only real matrices are supported. A symbolic L is converted into a - * numeric identity matrix before the row is added. - */ +// Adds a row and column to an LDL' factorization, and optionally updates the +// solution to Lx=b. +// +// workspace: Flag (nrow), Head (nrow+1), W (2*nrow), Iwork (2*nrow) +// +// Only real matrices are supported (single or double). A symbolic L is +// converted into a numeric identity matrix before the row is added. +// The dtypes of all matrices must match, except when L is symbolic (in which +// case it is converted to the dtype of R). #include "cholmod_internal.h" #ifndef NGPL #ifndef NMODIFY -/* ========================================================================== */ -/* === cholmod_rowadd ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// icomp: for sorting by qsort +//------------------------------------------------------------------------------ + +static int icomp (Int *i, Int *j) +{ + if (*i < *j) + { + return (-1) ; + } + else + { + return (1) ; + } +} + +//------------------------------------------------------------------------------ +// t_cholmod_rowadd_worker +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_rowadd_worker.c" -/* cholmod_rowadd adds a row to the LDL' factorization. It computes the kth - * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) - * accordingly. The kth row and column of L should originally be equal to the - * kth row and column of the identity matrix (they are treated as such, if they - * are not). The kth row/column of L is computed as the factorization of the - * kth row/column of the matrix to factorize, which is provided as a single - * n-by-1 sparse matrix R. The sparse vector R need not be sorted. - */ +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_rowadd_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_rowadd +//------------------------------------------------------------------------------ + +// cholmod_rowadd adds a row to the LDL' factorization. It computes the kth +// row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) +// accordingly. The kth row and column of L should originally be equal to the +// kth row and column of the identity matrix (they are treated as such, if they +// are not). The kth row/column of L is computed as the factorization of the +// kth row/column of the matrix to factorize, which is provided as a single +// n-by-1 sparse matrix R. The sparse vector R need not be sorted. int CHOLMOD(rowadd) ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) { @@ -52,625 +80,169 @@ int CHOLMOD(rowadd) return (CHOLMOD(rowadd_mark) (k, R, bk, NULL, L, NULL, NULL, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_rowadd_solve +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_rowadd_solve ================================================= */ -/* ========================================================================== */ - -/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b - * See cholmod_updown for a description of how Lx=b is updated. There is on - * additional parameter: bk specifies the new kth entry of b. - */ +// Does the same as cholmod_rowadd, and also updates the solution to Lx=b +// See cholmod_updown for a description of how Lx=b is updated. There is on +// additional parameter: bk specifies the new kth entry of b. int CHOLMOD(rowadd_solve) ( - /* ---- input ---- */ - size_t k, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right-hand-side b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right-hand-side b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { return (CHOLMOD(rowadd_mark) (k, R, bk, NULL, L, X, DeltaB, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_rowadd_mark +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === icomp ================================================================ */ -/* ========================================================================== */ - -/* for sorting by qsort */ -static int icomp (Int *i, Int *j) -{ - if (*i < *j) - { - return (-1) ; - } - else - { - return (1) ; - } -} - - -/* ========================================================================== */ -/* === cholmod_rowadd_mark ================================================== */ -/* ========================================================================== */ - -/* Does the same as cholmod_rowadd_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. */ +// Does the same as cholmod_rowadd_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. int CHOLMOD(rowadd_mark) ( - /* ---- input ---- */ - size_t kadd, /* row/column index to add */ - cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ - double bk [2], /* kth entry of the right hand side, b */ - Int *colmark, /* Int array of size 1. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t kadd, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + double bk [2], // kth entry of the right hand side, b + Int *colmark, // Int array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - double dk, yj, l_kj, lx, l_ij, sqrt_dk, dj, xk, rnz, fl ; - double *Lx, *W, *Cx, *Rx, *Xx, *Nx ; - Int *Li, *Lp, *Lnz, *Flag, *Stack, *Ci, *Rj, *Rp, *Lnext, *Iwork, *Rnz ; - cholmod_sparse *C, Cmatrix ; - Int i, j, p, pend, top, len, kk, li, lnz, mark, k, n, parent, Cp [2], - do_solve, do_update ; - size_t s ; - int ok = TRUE ; - DEBUG (Int lastrow) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (R, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ; RETURN_IF_XTYPE_INVALID (R, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - n = L->n ; - k = kadd ; + Int n = L->n ; + Int k = kadd ; if (kadd >= L->n || k < 0) { - ERROR (CHOLMOD_INVALID, "k invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "k invalid") ; + return (FALSE) ; } if (R->ncol != 1 || R->nrow != L->n) { - ERROR (CHOLMOD_INVALID, "R invalid") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "R invalid") ; + return (FALSE) ; } - Rj = R->i ; - Rx = R->x ; - Rp = R->p ; - Rnz = R->nz ; - rnz = (R->packed) ? (Rp [1]) : (Rnz [0]) ; - do_solve = (X != NULL) && (DeltaB != NULL) ; - if (do_solve) + if (L->xtype != CHOLMOD_PATTERN && L->dtype != R->dtype) { - RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - Xx = X->x ; - Nx = DeltaB->x ; - if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n || - DeltaB->ncol != 1 || Xx == NULL || Nx == NULL) - { - ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; - return (FALSE) ; - } + ERROR (CHOLMOD_INVALID, "R and L must have the same dtype") ; + return (FALSE) ; } - else + + if ((X != NULL) && (DeltaB != NULL)) { - Xx = NULL ; - Nx = NULL ; + // also update the solution to Lx=b + RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + if (X->nrow != L->n || X->ncol != 1 || + DeltaB->nrow != L->n || DeltaB->ncol != 1 || + X->dtype != R->dtype || DeltaB->dtype != R->dtype) + { + ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; + return (FALSE) ; + } } + Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 2*n */ - s = CHOLMOD(mult_size_t) (n, 2, &ok) ; + // s = 2*n + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (L->n, 2, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, s, s, Common) ; + CHOLMOD(alloc_work) (L->n, s, s, R->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; - } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, s, Common)) ; - - /* ---------------------------------------------------------------------- */ - /* convert to simplicial numeric LDL' factor, if not already */ - /* ---------------------------------------------------------------------- */ - - if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) - { - /* can only update/downdate a simplicial LDL' factorization */ - CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, - Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory, L is returned unchanged */ - return (FALSE) ; - } - } - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - /* inputs, not modified on output: */ - Lp = L->p ; /* size n+1. input, not modified on output */ - - /* outputs, contents defined on input for incremental case only: */ - Lnz = L->nz ; /* size n */ - Li = L->i ; /* size L->nzmax. Can change in size. */ - Lx = L->x ; /* size L->nzmax. Can change in size. */ - Lnext = L->next ; /* size n+2 */ - - ASSERT (L->nz != NULL) ; - - PRINT1 (("rowadd:\n")) ; - fl = 0 ; - -#if 0 -#ifndef NDEBUG - /* column k of L should be zero, except for the diagonal. This test is - * overly cautious. */ - for (p = Lp [k] + 1 ; p < Lp [k] + Lnz [k] ; p++) ASSERT (Lx [p] == 0) ; -#endif -#endif - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Flag = Common->Flag ; /* size n */ - W = Common->Xwork ; /* size n */ - Cx = W + n ; /* size n (use 2nd column of Xwork for C) */ - Iwork = Common->Iwork ; - Stack = Iwork ; /* size n (i/i/l), also in cholmod_updown */ - Ci = Iwork + n ; /* size n (i/i/l) */ - /* NOTE: cholmod_updown uses Iwork [0..n-1] (i/i/l) as Stack as well */ - - mark = Common->mark ; - - /* copy Rj/Rx into W/Ci */ - for (p = 0 ; p < rnz ; p++) - { - i = Rj [p] ; - ASSERT (i >= 0 && i < n) ; - W [i] = Rx [p] ; - Ci [p] = i ; - } - - /* At this point, W [Ci [0..rnz-1]] holds the sparse vector to add */ - /* The nonzero pattern of column W is held in Ci (it may be unsorted). */ - - /* ---------------------------------------------------------------------- */ - /* symbolic factorization to get pattern of kth row of L */ - /* ---------------------------------------------------------------------- */ - - DEBUG (for (p = 0 ; p < rnz ; p++) - PRINT1 (("C ("ID",%g)\n", Ci [p], W [Ci [p]]))) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; - - /* flag the diagonal */ - Flag [k] = mark ; - - /* find the union of all the paths */ - top = n ; - lnz = 0 ; /* # of nonzeros in column k of L, excluding diagonal */ - for (p = 0 ; p < rnz ; p++) - { - i = Ci [p] ; - - if (i < k) - { - - /* walk from i = entry in Ci to root (and stop if i marked)*/ - PRINT2 (("\nwalk from i = "ID" towards k = "ID"\n", i, k)) ; - len = 0 ; - - /* walk up tree, but stop if we go below the diagonal */ - while (i < k && i != EMPTY && Flag [i] < mark) - { - PRINT2 ((" Add "ID" to path\n", i)) ; - ASSERT (i >= 0 && i < k) ; - Stack [len++] = i ; /* place i on the stack */ - Flag [i] = mark ; /* mark i as visited */ - /* parent is the first entry in the column after the diagonal */ - ASSERT (Lnz [i] > 0) ; - parent = (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY ; - PRINT2 ((" parent: "ID"\n", parent)) ; - i = parent ; /* go up the tree */ - } - ASSERT (len <= top) ; - - /* move the path down to the bottom of the stack */ - /* this shifts Stack [0..len-1] down to [ ... oldtop-1] */ - while (len > 0) - { - Stack [--top] = Stack [--len] ; - } - } - else if (i > k) - { - /* prune the diagonal and upper triangular entries from Ci */ - Ci [lnz++] = i ; - Flag [i] = mark ; - } - } - -#ifndef NDEBUG - PRINT1 (("length of S after prune: "ID"\n", lnz)) ; - for (p = 0 ; p < lnz ; p++) - { - PRINT1 (("After prune Ci ["ID"] = "ID"\n", p, Ci [p])) ; - ASSERT (Ci [p] > k) ; + return (FALSE) ; } -#endif + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, s, R->dtype, Common)) ; - /* ---------------------------------------------------------------------- */ - /* ensure each column of L has enough space to grow */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert to simplicial numeric LDL' factor, if not already + //-------------------------------------------------------------------------- - for (kk = top ; kk < n ; kk++) + if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) { - /* could skip this if we knew column j already included row k */ - j = Stack [kk] ; - if (Lp [j] + Lnz [j] >= Lp [Lnext [j]]) - { - PRINT1 (("Col "ID" realloc, old Lnz "ID"\n", j, Lnz [j])) ; - if (!CHOLMOD(reallocate_column) (j, Lnz [j] + 1, L, Common)) - { - /* out of memory, L is now simplicial symbolic */ - /* CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - ASSERT (check_flag (Common)) ; - for (i = 0 ; i < n ; i++) - { - W [i] = 0 ; - } - return (FALSE) ; - } - /* L->i and L->x may have moved */ - Li = L->i ; - Lx = L->x ; - } - ASSERT (Lp [j] + Lnz [j] < Lp [Lnext [j]] - || (Lp [Lnext [j]] - Lp [j] == n-j)) ; + // can only update/downdate a simplicial LDL' factorization + if (L->xtype == CHOLMOD_PATTERN) + { + // L is symbolic; convert it to R->dtype + L->dtype = R->dtype ; + } + CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory, L is returned unchanged + return (FALSE) ; + } } - /* ---------------------------------------------------------------------- */ - /* compute kth row of L and store in column form */ - /* ---------------------------------------------------------------------- */ - - /* solve L (1:k-1, 1:k-1) * y (1:k-1) = b (1:k-1) */ - /* where b (1:k) is in W and Ci */ - - /* L (k, 1:k-1) = y (1:k-1) ./ D (1:k-1) */ - /* D (k) = B (k,k) - L (k, 1:k-1) * y (1:k-1) */ - - PRINT2 (("\nForward solve: "ID" to "ID"\n", top, n)) ; - ASSERT (Lnz [k] >= 1 && Li [Lp [k]] == k) ; - DEBUG (for (i = top ; i < n ; i++) PRINT2 ((" Path: "ID"\n", Stack [i]))) ; - - dk = W [k] ; - W [k] = 0.0 ; + ASSERT (L->dtype == R->dtype) ; - /* if do_solve: compute x (k) = b (k) - L (k, 1:k-1) * x (1:k-1) */ - xk = bk [0] ; - PRINT2 (("B [k] = %g\n", xk)) ; + //-------------------------------------------------------------------------- + // update L and X + //-------------------------------------------------------------------------- - for (kk = top ; kk < n ; kk++) - { - j = Stack [kk] ; - i = j ; - PRINT2 (("Forward solve col j = "ID":\n", j)) ; - ASSERT (j >= 0 && j < k) ; - - /* forward solve using L (j+1:k-1,j) */ - yj = W [j] ; - W [j] = 0.0 ; - p = Lp [j] ; - pend = p + Lnz [j] ; - ASSERT (Lnz [j] > 0) ; - dj = Lx [p++] ; - for ( ; p < pend ; p++) - { - i = Li [p] ; - PRINT2 ((" row "ID"\n", i)) ; - ASSERT (i > j) ; - ASSERT (i < n) ; - /* stop at row k */ - if (i >= k) - { - break ; - } - W [i] -= Lx [p] * yj ; - } - - /* each iteration of the above for loop did 2 flops, and 3 flops - * are done below. so: fl += 2 * (Lp [j] - p - 1) + 3 becomes: */ - fl += 2 * (Lp [j] - p) + 1 ; - - /* scale L (k,1:k-1) and compute dot product for D (k,k) */ - l_kj = yj / dj ; - dk -= l_kj * yj ; - - /* compute dot product for X(k) */ - if (do_solve) - { - xk -= l_kj * Xx [j] ; - } - - /* store l_kj in the jth column of L */ - /* and shift the rest of the column down */ - - li = k ; - lx = l_kj ; - - if (i == k) - { - /* no need to modify the nonzero pattern of L, since it already - * contains row index k. */ - ASSERT (Li [p] == k) ; - Lx [p] = l_kj ; - - for (p++ ; p < pend ; p++) - { - i = Li [p] ; - l_ij = Lx [p] ; - ASSERT (i > k && i < n) ; - PRINT2 ((" apply to row "ID" of column k of L\n", i)) ; - - /* add to the pattern of the kth column of L */ - if (Flag [i] < mark) - { - PRINT2 ((" add Ci["ID"] = "ID"\n", lnz, i)) ; - ASSERT (i > k) ; - Ci [lnz++] = i ; - Flag [i] = mark ; - } - - /* apply the update to the kth column of L */ - /* yj is equal to l_kj * d_j */ - - W [i] -= l_ij * yj ; - } - - } - else - { - - PRINT2 (("Shift col j = "ID", apply saxpy to col k of L\n", j)) ; - for ( ; p < pend ; p++) - { - /* swap (Li [p],Lx [p]) with (li,lx) */ - i = Li [p] ; - l_ij = Lx [p] ; - Li [p] = li ; - Lx [p] = lx ; - li = i ; - lx = l_ij ; - ASSERT (i > k && i < n) ; - PRINT2 ((" apply to row "ID" of column k of L\n", i)) ; - - /* add to the pattern of the kth column of L */ - if (Flag [i] < mark) - { - PRINT2 ((" add Ci["ID"] = "ID"\n", lnz, i)) ; - ASSERT (i > k) ; - Ci [lnz++] = i ; - Flag [i] = mark ; - } - - /* apply the update to the kth column of L */ - /* yj is equal to l_kj * d_j */ - - W [i] -= l_ij * yj ; - } - - /* store the last value in the jth column of L */ - Li [p] = li ; - Lx [p] = lx ; - Lnz [j]++ ; - - } - } + float s_bk [2] ; + s_bk [0] = (float) bk [0] ; + s_bk [1] = (float) bk [1] ; - /* ---------------------------------------------------------------------- */ - /* merge C with the pattern of the existing column of L */ - /* ---------------------------------------------------------------------- */ - - /* This column should be zero, but it may contain explicit zero entries. - * These entries should be kept, not dropped. */ - p = Lp [k] ; - pend = p + Lnz [k] ; - for (p++ ; p < pend ; p++) + switch (L->dtype & 4) { - i = Li [p] ; - /* add to the pattern of the kth column of L */ - if (Flag [i] < mark) - { - PRINT2 ((" add Ci["ID"] = "ID" from existing col k\n", lnz, i)) ; - ASSERT (i > k) ; - Ci [lnz++] = i ; - Flag [i] = mark ; - } - } + case CHOLMOD_SINGLE: + ok = rs_cholmod_rowadd_worker (k, R, s_bk, colmark, L, X, DeltaB, + Common) ; + break ; - /* ---------------------------------------------------------------------- */ - - if (do_solve) - { - Xx [k] = xk ; - PRINT2 (("Xx [k] = %g\n", Xx [k])) ; + case CHOLMOD_DOUBLE: + ok = rd_cholmod_rowadd_worker (k, R, bk, colmark, L, X, DeltaB, + Common) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* ensure abs (dk) >= dbound, if dbound is given */ - /* ---------------------------------------------------------------------- */ - - dk = (Common->dbound > 0) ? (CHOLMOD(dbound) (dk, Common)) : dk ; - - PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ; - - /* ---------------------------------------------------------------------- */ - /* store the kth column of L */ - /* ---------------------------------------------------------------------- */ - - /* ensure the new column of L has enough space */ - if (Lp [k] + lnz + 1 > Lp [Lnext [k]]) - { - PRINT1 (("New Col "ID" realloc, old Lnz "ID"\n", k, Lnz [k])) ; - if (!CHOLMOD(reallocate_column) (k, lnz + 1, L, Common)) - { - /* out of memory, L is now simplicial symbolic */ - CHOLMOD(clear_flag) (Common) ; - for (i = 0 ; i < n ; i++) - { - W [i] = 0 ; - } - return (FALSE) ; - } - /* L->i and L->x may have moved */ - Li = L->i ; - Lx = L->x ; - } - ASSERT (Lp [k] + lnz + 1 <= Lp [Lnext [k]]) ; - -#ifndef NDEBUG - PRINT2 (("\nPrior to sort: lnz "ID" (excluding diagonal)\n", lnz)) ; - for (kk = 0 ; kk < lnz ; kk++) - { - i = Ci [kk] ; - PRINT2 (("L ["ID"] kept: "ID" %e\n", kk, i, W [i] / dk)) ; - } -#endif - - /* sort Ci */ - qsort (Ci, lnz, sizeof (Int), (int (*) (const void *, const void *)) icomp); - - /* store the kth column of L */ - DEBUG (lastrow = k) ; - p = Lp [k] ; - Lx [p++] = dk ; - Lnz [k] = lnz + 1 ; - fl += lnz ; - for (kk = 0 ; kk < lnz ; kk++, p++) - { - i = Ci [kk] ; - PRINT2 (("L ["ID"] after sort: "ID", %e\n", kk, i, W [i] / dk)) ; - ASSERT (i > lastrow) ; - Li [p] = i ; - Lx [p] = W [i] / dk ; - W [i] = 0.0 ; - DEBUG (lastrow = i) ; - } - - /* compute DeltaB for updown (in DeltaB) */ - if (do_solve) - { - p = Lp [k] ; - pend = p + Lnz [k] ; - for (p++ ; p < pend ; p++) - { - ASSERT (Li [p] > k) ; - Nx [Li [p]] -= Lx [p] * xk ; - } - } - - /* clear the flag for the update */ - mark = CHOLMOD(clear_flag) (Common) ; - - /* workspaces are now cleared */ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ; - - /* ---------------------------------------------------------------------- */ - /* update/downdate */ - /* ---------------------------------------------------------------------- */ - - /* update or downdate L (k+1:n, k+1:n) with the vector - * C = L (:,k) * sqrt (abs (D [k])). - * Do a numeric update if D[k] < 0, numeric downdate otherwise. - */ - - ok = TRUE ; - Common->modfl = 0 ; - - PRINT1 (("rowadd update lnz = "ID"\n", lnz)) ; - if (lnz > 0) - { - do_update = (dk < 0) ; - if (do_update) - { - dk = -dk ; - } - sqrt_dk = sqrt (dk) ; - p = Lp [k] + 1 ; - for (kk = 0 ; kk < lnz ; kk++, p++) - { - Cx [kk] = Lx [p] * sqrt_dk ; - } - fl += lnz + 1 ; - - /* create a n-by-1 sparse matrix to hold the single column */ - C = &Cmatrix ; - C->nrow = n ; - C->ncol = 1 ; - C->nzmax = lnz ; - C->sorted = TRUE ; - C->packed = TRUE ; - C->p = Cp ; - C->i = Ci ; - C->x = Cx ; - C->nz = NULL ; - C->itype = L->itype ; - C->xtype = L->xtype ; - C->dtype = L->dtype ; - C->z = NULL ; - C->stype = 0 ; - - Cp [0] = 0 ; - Cp [1] = lnz ; - - /* numeric downdate if dk > 0, and optional Lx=b change */ - /* workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) */ - ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark, - L, X, DeltaB, Common) ; - - /* clear workspace */ - for (kk = 0 ; kk < lnz ; kk++) - { - Cx [kk] = 0 ; - } - } - - Common->modfl += fl ; + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- DEBUG (CHOLMOD(dump_factor) (L, "LDL factorization, L:", Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, s, R->dtype, Common)) ; return (ok) ; } + #endif #endif + diff --git a/CHOLMOD/Modify/cholmod_rowdel.c b/CHOLMOD/Modify/cholmod_rowdel.c index d33af94a1b..ce10ac1ff3 100644 --- a/CHOLMOD/Modify/cholmod_rowdel.c +++ b/CHOLMOD/Modify/cholmod_rowdel.c @@ -1,48 +1,58 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Modify/cholmod_del: delete row/column from an LDL' factorization +// CHOLMOD/Modify/cholmod_rowdel: delete row/column from an LDL' factorization //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // and William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Deletes a row and column from an LDL' factorization. The row and column k - * is set to the kth row and column of the identity matrix. Optionally - * downdates the solution to Lx=b. - * - * workspace: Flag (nrow), Head (nrow+1), W (nrow*2), Iwork (2*nrow) - * - * Only real matrices are supported (exception: since only the pattern of R - * is used, it can have any valid xtype). - */ +// Deletes a row and column from an LDL' factorization. The row and column k +// is set to the kth row and column of the identity matrix. Optionally +// downdates the solution to Lx=b. +// +// workspace: Flag (nrow), Head (nrow+1), W (nrow*2), Iwork (2*nrow) +// +// Only real matrices (single or double) are supported (exception: since only +// the pattern of R is used, it can have any valid xtype). #include "cholmod_internal.h" #ifndef NGPL #ifndef NMODIFY -/* ========================================================================== */ -/* === cholmod_rowdel ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_rowdel_worker +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_rowdel_worker.c" + +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_rowdel_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_rowdel +//------------------------------------------------------------------------------ -/* Sets the kth row and column of L to be the kth row and column of the identity - * matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, - * the caller can optionally provide the nonzero pattern (or an upper bound) of - * kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want - * CHOLMOD to determine this itself, which is easier for the caller, but takes - * a little more time. - */ +// Sets the kth row and column of L to be the kth row and column of the identity +// matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, +// the caller can optionally provide the nonzero pattern (or an upper bound) of +// kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want +// CHOLMOD to determine this itself, which is easier for the caller, but takes +// a little more time. int CHOLMOD(rowdel) ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) { @@ -52,407 +62,164 @@ int CHOLMOD(rowdel) return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, NULL, NULL, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_rowdel_solve +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_rowdel_solve ================================================= */ -/* ========================================================================== */ - -/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. - * When row/column k of A is "deleted" from the system A*y=b, this can induce - * a change to x, in addition to changes arising when L and b are modified. - * If this is the case, the kth entry of y is required as input (yk) */ +// Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. +// When row/column k of A is "deleted" from the system A*y=b, this can induce +// a change to x, in addition to changes arising when L and b are modified. +// If this is the case, the kth entry of y is required as input (yk). int CHOLMOD(rowdel_solve) ( - /* ---- input ---- */ - size_t k, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, X, DeltaB, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_rowdel_mark +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_rowdel_mark ================================================== */ -/* ========================================================================== */ - -/* Does the same as cholmod_rowdel_solve, except only part of L is used in - * the update/downdate of the solution to Lx=b. This routine is an "expert" - * routine. It is meant for use in LPDASA only. - * - * if R == NULL then columns 0:k-1 of L are searched for row k. Otherwise, it - * searches columns in the set defined by the pattern of the first column of R. - * This is meant to be the pattern of row k of L (a superset of that pattern is - * OK too). R must be a permutation of a subset of 0:k-1. - */ +// Does the same as cholmod_rowdel_solve, except only part of L is used in +// the update/downdate of the solution to Lx=b. This routine is an "expert" +// routine. It is meant for use in LPDASA only. +// +// if R == NULL then columns 0:k-1 of L are searched for row k. Otherwise, it +// searches columns in the set defined by the pattern of the first column of R. +// This is meant to be the pattern of row k of L (a superset of that pattern is +// OK too). R must be a permutation of a subset of 0:k-1. int CHOLMOD(rowdel_mark) ( - /* ---- input ---- */ - size_t kdel, /* row/column index to delete */ - cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ - double yk [2], /* kth entry in the solution to A*y=b */ - Int *colmark, /* Int array of size 1. See cholmod_updown.c */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + size_t kdel, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + double yk [2], // kth entry in the solution to A*y=b + Int *colmark, // Int array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - double dk, sqrt_dk, xk, dj, fl ; - double *Lx, *Cx, *W, *Xx, *Nx ; - Int *Li, *Lp, *Lnz, *Ci, *Rj, *Rp, *Iwork ; - cholmod_sparse *C, Cmatrix ; - Int j, p, pend, kk, lnz, n, Cp [2], do_solve, do_update, left, k, - right, middle, i, klast, given_row, rnz ; - size_t s ; - int ok = TRUE ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ; - n = L->n ; - k = kdel ; + Int n = L->n ; + Int k = kdel ; if (kdel >= L->n || k < 0) { - ERROR (CHOLMOD_INVALID, "k invalid") ; - return (FALSE) ; - } - if (R == NULL) - { - Rj = NULL ; - rnz = EMPTY ; - } - else - { - RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; - if (R->ncol != 1 || R->nrow != L->n) - { - ERROR (CHOLMOD_INVALID, "R invalid") ; - return (FALSE) ; - } - Rj = R->i ; - Rp = R->p ; - rnz = Rp [1] ; + ERROR (CHOLMOD_INVALID, "k invalid") ; + return (FALSE) ; } - do_solve = (X != NULL) && (DeltaB != NULL) ; - if (do_solve) + if (R != NULL) { - RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - Xx = X->x ; - Nx = DeltaB->x ; - if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n || - DeltaB->ncol != 1 || Xx == NULL || Nx == NULL) - { - ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; - return (FALSE) ; - } + RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; + if (R->ncol != 1 || R->nrow != L->n) + { + ERROR (CHOLMOD_INVALID, "R invalid") ; + return (FALSE) ; + } } - else + + if ((X != NULL) && (DeltaB != NULL)) { - Xx = NULL ; - Nx = NULL ; + RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + if (X->nrow != L->n || X->ncol != 1 || + DeltaB->nrow != L->n || DeltaB->ncol != 1 || + X->dtype != L->dtype || DeltaB->dtype != L->dtype) + { + ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; + return (FALSE) ; + } } + Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 2*n */ - s = CHOLMOD(mult_size_t) (n, 2, &ok) ; + // s = 2*n + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (L->n, 2, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, s, s, Common) ; + CHOLMOD(alloc_work) (L->n, s, s, L->dtype, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, L->dtype, Common)) ; - /* ---------------------------------------------------------------------- */ - /* convert to simplicial numeric LDL' factor, if not already */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert to simplicial numeric LDL' factor, if not already + //-------------------------------------------------------------------------- - if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) + if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) { - /* can only update/downdate a simplicial LDL' factorization */ - CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, - Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory, L is returned unchanged */ - return (FALSE) ; - } + // can only update/downdate a simplicial LDL' factorization + CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory, L is returned unchanged + return (FALSE) ; + } } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - /* inputs, not modified on output: */ - Lp = L->p ; /* size n+1 */ - - /* outputs, contents defined on input for incremental case only: */ - Lnz = L->nz ; /* size n */ - Li = L->i ; /* size L->nzmax. Can change in size. */ - Lx = L->x ; /* size L->nzmax. Can change in size. */ - - ASSERT (L->nz != NULL) ; + //-------------------------------------------------------------------------- + // update L and X + //-------------------------------------------------------------------------- - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + float s_yk [2] ; + s_yk [0] = (float) yk [0] ; + s_yk [1] = (float) yk [1] ; - W = Common->Xwork ; /* size n, used only in cholmod_updown */ - Cx = W + n ; /* use 2nd column of Xwork for C (size n) */ - Iwork = Common->Iwork ; - Ci = Iwork + n ; /* size n (i/i/l) */ - /* NOTE: cholmod_updown uses Iwork [0..n-1] (i/i/l) as Stack */ - - /* ---------------------------------------------------------------------- */ - /* prune row k from all columns of L */ - /* ---------------------------------------------------------------------- */ - - given_row = (rnz >= 0) ; - klast = given_row ? rnz : k ; - PRINT2 (("given_row "ID"\n", given_row)) ; - - for (kk = 0 ; kk < klast ; kk++) - { - /* either search j = 0:k-1 or j = Rj [0:rnz-1] */ - j = given_row ? (Rj [kk]) : (kk) ; - - if (j < 0 || j >= k) - { - ERROR (CHOLMOD_INVALID, "R invalid") ; - return (FALSE) ; - } - - PRINT2 (("Prune col j = "ID":\n", j)) ; - - lnz = Lnz [j] ; - dj = Lx [Lp [j]] ; - ASSERT (Lnz [j] > 0 && Li [Lp [j]] == j) ; - - if (lnz > 1) - { - left = Lp [j] ; - pend = left + lnz ; - right = pend - 1 ; - - i = Li [right] ; - - if (i < k) - { - /* row k is not in column j */ - continue ; - } - else if (i == k) - { - /* k is the last row index in this column (quick delete) */ - if (do_solve) - { - Xx [j] -= yk [0] * dj * Lx [right] ; - } - Lx [right] = 0 ; - } - else - { - /* binary search for row k in column j */ - PRINT2 (("\nBinary search: lnz "ID" k = "ID"\n", lnz, k)) ; - while (left < right) - { - middle = (left + right) / 2 ; - PRINT2 (("left "ID" right "ID" middle "ID": ["ID" "ID"" - ""ID"]\n", left, right, middle, - Li [left], Li [middle], Li [right])) ; - if (k > Li [middle]) - { - left = middle + 1 ; - } - else - { - right = middle ; - } - } - ASSERT (left >= Lp [j] && left < pend) ; - -#ifndef NDEBUG - /* brute force, linear-time search */ - { - Int p3 = Lp [j] ; - i = EMPTY ; - PRINT2 (("Brute force:\n")) ; - for ( ; p3 < pend ; p3++) - { - i = Li [p3] ; - PRINT2 (("p "ID" ["ID"]\n", p3, i)) ; - if (i >= k) - { - break ; - } - } - if (i == k) - { - ASSERT (k == Li [p3]) ; - ASSERT (p3 == left) ; - } - } -#endif - - if (k == Li [left]) - { - if (do_solve) - { - Xx [j] -= yk [0] * dj * Lx [left] ; - } - /* found row k in column j. Prune it from the column.*/ - Lx [left] = 0 ; - } - } - } - } - -#ifndef NDEBUG - /* ensure that row k has been deleted from the matrix L */ - for (j = 0 ; j < k ; j++) + switch (L->dtype & 4) { - Int lasti ; - lasti = EMPTY ; - p = Lp [j] ; - pend = p + Lnz [j] ; - /* look for row k in column j */ - PRINT1 (("Pruned column "ID"\n", j)) ; - for ( ; p < pend ; p++) - { - i = Li [p] ; - PRINT2 ((" "ID"", i)) ; - PRINT2 ((" %g\n", Lx [p])) ; - ASSERT (IMPLIES (i == k, Lx [p] == 0)) ; - ASSERT (i > lasti) ; - lasti = i ; - } - PRINT1 (("\n")) ; + case CHOLMOD_SINGLE: + ok = rs_cholmod_rowdel_worker (k, R, s_yk, colmark, L, X, DeltaB, + Common) ; + break ; + + case CHOLMOD_DOUBLE: + ok = rd_cholmod_rowdel_worker (k, R, yk, colmark, L, X, DeltaB, + Common) ; + break ; } -#endif - - /* ---------------------------------------------------------------------- */ - /* set diagonal and clear column k of L */ - /* ---------------------------------------------------------------------- */ - - lnz = Lnz [k] - 1 ; - ASSERT (Lnz [k] > 0) ; - - /* ---------------------------------------------------------------------- */ - /* update/downdate */ - /* ---------------------------------------------------------------------- */ - /* update or downdate L (k+1:n, k+1:n) with the vector - * C = L (:,k) * sqrt (abs (D [k])) - * Do a numeric update if D[k] > 0, numeric downdate otherwise. - */ - - PRINT1 (("rowdel downdate lnz = "ID"\n", lnz)) ; - - /* store the new unit diagonal */ - p = Lp [k] ; - pend = p + lnz + 1 ; - dk = Lx [p] ; - Lx [p++] = 1 ; - PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ; - ok = TRUE ; - fl = 0 ; - - if (lnz > 0) - { - /* compute DeltaB for updown (in DeltaB) */ - if (do_solve) - { - xk = Xx [k] - yk [0] * dk ; - for ( ; p < pend ; p++) - { - Nx [Li [p]] += Lx [p] * xk ; - } - } - - do_update = (dk > 0) ; - if (!do_update) - { - dk = -dk ; - } - sqrt_dk = sqrt (dk) ; - p = Lp [k] + 1 ; - for (kk = 0 ; kk < lnz ; kk++, p++) - { - Ci [kk] = Li [p] ; - Cx [kk] = Lx [p] * sqrt_dk ; - Lx [p] = 0 ; /* clear column k */ - } - fl = lnz + 1 ; - - /* create a n-by-1 sparse matrix to hold the single column */ - C = &Cmatrix ; - C->nrow = n ; - C->ncol = 1 ; - C->nzmax = lnz ; - C->sorted = TRUE ; - C->packed = TRUE ; - C->p = Cp ; - C->i = Ci ; - C->x = Cx ; - C->nz = NULL ; - C->itype = L->itype ; - C->xtype = L->xtype ; - C->dtype = L->dtype ; - C->z = NULL ; - C->stype = 0 ; - - Cp [0] = 0 ; - Cp [1] = lnz ; - - /* numeric update if dk > 0, and with Lx=b change */ - /* workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) */ - ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark, - L, X, DeltaB, Common) ; - - /* clear workspace */ - for (kk = 0 ; kk < lnz ; kk++) - { - Cx [kk] = 0 ; - } - } - - Common->modfl += fl ; - - if (do_solve) - { - /* kth equation becomes identity, so X(k) is now Y(k) */ - Xx [k] = yk [0] ; - } + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- DEBUG (CHOLMOD(dump_factor) (L, "LDL factorization, L:", Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, s, L->dtype, Common)) ; return (ok) ; } + #endif #endif + diff --git a/CHOLMOD/Modify/cholmod_updown.c b/CHOLMOD/Modify/cholmod_updown.c index ce1a1141d2..d2efea1633 100644 --- a/CHOLMOD/Modify/cholmod_updown.c +++ b/CHOLMOD/Modify/cholmod_updown.c @@ -2,147 +2,143 @@ // CHOLMOD/Modify/cholmod_updown: sparse Cholesky update/downdate //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // and William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Updates/downdates the LDL' factorization (symbolic, then numeric), by - * computing a new factorization of - * - * Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C' - * - * C must be sorted. It can be either packed or unpacked. As in all CHOLMOD - * routines, the columns of L are sorted on input, and also on output. - * - * If the factor is not an unpacked LDL' or dynamic LDL', it is converted - * to an LDL' dynamic factor. An unpacked LDL' factor may be updated, but if - * any one column runs out of space, the factor is converted to an LDL' - * dynamic one. If the initial conversion fails, the factor is returned - * unchanged. - * - * If memory runs out during the update, the factor is returned as a simplicial - * symbolic factor. That is, everything is freed except for the fill-reducing - * ordering and its corresponding column counts (typically computed by - * cholmod_analyze). - * - * Note that the fill-reducing permutation L->Perm is NOT used. The row - * indices of C refer to the rows of L, not A. If your original system is - * LDL' = PAP' (where P = L->Perm), and you want to compute the LDL' - * factorization of A+CC', then you must permute C first. That is: - * - * PAP' = LDL' - * P(A+CC')P' = PAP'+PCC'P' = LDL' + (PC)(PC)' = LDL' + Cnew*Cnew' - * where Cnew = P*C. - * - * You can use the cholmod_submatrix routine in the MatrixOps module - * to permute C, with: - * - * Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ; - * - * Note that the sorted input parameter to cholmod_submatrix must be TRUE, - * because cholmod_updown requires C with sorted columns. - * - * The system Lx=b can also be updated/downdated. The old system was Lold*x=b. - * The new system is Lnew*xnew = b + deltab. The old solution x is overwritten - * with xnew. Note that as in the update/downdate of L itself, the fill- - * reducing permutation L->Perm is not used. x and b are in the permuted - * ordering, not your original ordering. x and b are n-by-1; this routine - * does not handle multiple right-hand-sides. - * - * workspace: Flag (nrow), Head (nrow+1), W (maxrank*nrow), Iwork (nrow), - * where maxrank is 2, 4, or 8. - * - * Only real matrices are supported. A symbolic L is converted into a - * numeric identity matrix. - */ +// Updates/downdates the LDL' factorization (symbolic, then numeric), by +// computing a new factorization of +// +// Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C' +// +// C must be sorted. It can be either packed or unpacked. As in all CHOLMOD +// routines, the columns of L are sorted on input, and also on output. +// +// If the factor is not an unpacked LDL' or dynamic LDL', it is converted +// to an LDL' dynamic factor. An unpacked LDL' factor may be updated, but if +// any one column runs out of space, the factor is converted to an LDL' +// dynamic one. If the initial conversion fails, the factor is returned +// unchanged. +// +// If memory runs out during the update, the factor is returned as a simplicial +// symbolic factor. That is, everything is freed except for the fill-reducing +// ordering and its corresponding column counts (typically computed by +// cholmod_analyze). +// +// Note that the fill-reducing permutation L->Perm is NOT used. The row +// indices of C refer to the rows of L, not A. If your original system is +// LDL' = PAP' (where P = L->Perm), and you want to compute the LDL' +// factorization of A+CC', then you must permute C first. That is: +// +// PAP' = LDL' +// P(A+CC')P' = PAP'+PCC'P' = LDL' + (PC)(PC)' = LDL' + Cnew*Cnew' +// where Cnew = P*C. +// +// You can use the cholmod_submatrix routine in the MatrixOps module +// to permute C, with: +// +// Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ; +// +// Note that the sorted input parameter to cholmod_submatrix must be TRUE, +// because cholmod_updown requires C with sorted columns. +// +// The system Lx=b can also be updated/downdated. The old system was Lold*x=b. +// The new system is Lnew*xnew = b + deltab. The old solution x is overwritten +// with xnew. Note that as in the update/downdate of L itself, the fill- +// reducing permutation L->Perm is not used. x and b are in the permuted +// ordering, not your original ordering. x and b are n-by-1; this routine +// does not handle multiple right-hand-sides. +// +// workspace: Flag (nrow), Head (nrow+1), W (maxrank*nrow), Iwork (nrow), +// where maxrank is 2, 4, or 8. +// +// Only real matrices are supported (single and double). A symbolic L is +// converted into a numeric identity matrix. #include "cholmod_internal.h" #ifndef NGPL #ifndef NMODIFY -/* ========================================================================== */ -/* === cholmod_updown ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_updown +//------------------------------------------------------------------------------ -/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' - * (a downdate). The factor object L need not be an LDL' factorization; it - * is converted to one if it isn't. */ +// Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' +// (a downdate). The factor object L need not be an LDL' factorization; it +// is converted to one if it isn't. int CHOLMOD(updown) ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify cholmod_common *Common ) { - return (CHOLMOD(updown_mask2) (update, C, NULL, NULL, 0, L, NULL, NULL, - Common)) ; + return (CHOLMOD(updown_mask2) (update, C, /* colmark: */ NULL, + /* mask: */ NULL, /* maskmark: */ 0, + L, /* X: */ NULL, /* DeltaB: */ NULL, Common)) ; } +//------------------------------------------------------------------------------ +// cholmod_updown_solve +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_updown_solve ================================================= */ -/* ========================================================================== */ - -/* Does the same as cholmod_updown, except that it also updates/downdates the - * solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not - * need as input to this routine, but a sparse change to b is (DeltaB). Only - * entries in DeltaB corresponding to columns modified in L are accessed; the - * rest are ignored. - */ +// Does the same as cholmod_updown, except that it also updates/downdates the +// solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not +// need as input to this routine, but a sparse change to b is (DeltaB). Only +// entries in DeltaB corresponding to columns modified in L are accessed; the +// rest are ignored. int CHOLMOD(updown_solve) ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - return (CHOLMOD(updown_mask2) (update, C, NULL, NULL, 0, L, X, DeltaB, - Common)) ; + return (CHOLMOD(updown_mask2) (update, C, /* colmark: */ NULL, + /* mask: */ NULL, /* maskmark: */ 0, + L, X, DeltaB, Common)) ; } +//------------------------------------------------------------------------------ +// Power2 +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === Power2 =============================================================== */ -/* ========================================================================== */ - -/* Power2 [i] is smallest power of 2 that is >= i (for i in range 0 to 8) */ +// Power2 [i] is smallest power of 2 that is >= i (for i in range 0 to 8) -static Int Power2 [ ] = +static size_t Power2 [ ] = { -/* 0 1 2 3 4 5 6 7 8 */ +// 0 1 2 3 4 5 6 7 8 0, 1, 2, 4, 4, 8, 8, 8, 8 } ; -/* ========================================================================== */ -/* === debug routines ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// debug routines +//------------------------------------------------------------------------------ #ifndef NDEBUG static void dump_set (Int s, Int **Set_ps1, Int **Set_ps2, Int j, Int n, - cholmod_common *Common) + cholmod_common *Common) { Int *p, len, i, ilast ; if (CHOLMOD(dump) < -1) { - /* no checks if debug level is -2 or less */ - return ; + // no checks if debug level is -2 or less + return ; } len = Set_ps2 [s] - Set_ps1 [s] ; @@ -151,1443 +147,391 @@ static void dump_set (Int s, Int **Set_ps1, Int **Set_ps2, Int j, Int n, ilast = j ; for (p = Set_ps1 [s] ; p < Set_ps2 [s] ; p++) { - i = *p ; - PRINT3 ((" "ID"", i)) ; - ASSERT (i > ilast && i < n) ; - ilast = i ; + i = *p ; + PRINT3 ((" "ID"", i)) ; + ASSERT (i > ilast && i < n) ; + ilast = i ; } PRINT3 (("\n")) ; } -static void dump_col -( - char *w, Int j, Int p1, Int p2, Int *Li, double *Lx, Int n, - cholmod_common *Common -) -{ - Int p, row, lastrow ; - - if (CHOLMOD(dump) < -1) - { - /* no checks if debug level is -2 or less */ - return ; - } - - PRINT3 (("\n\nDUMP COL==== j = "ID" %s: p1="ID" p2="ID" \n", j, w, p1,p2)); - lastrow = -1 ; - for (p = p1 ; p < p2 ; p++) - { - PRINT3 ((" "ID": ", p)) ; - row = Li [p] ; - PRINT3 ((""ID" ", Li [p])) ; - PRINT3 (("%g ", Lx [p])) ; - PRINT3 (("\n")) ; - ASSERT (row > lastrow && row < n) ; - lastrow = row ; - } - ASSERT (p1 < p2) ; - ASSERT (Li [p1] == j) ; - PRINT3 (("\n")) ; -} #endif +//------------------------------------------------------------------------------ +// Path_type +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === a path =============================================================== */ -/* ========================================================================== */ - -/* A path is a set of nodes of the etree which are all affected by the same - * columns of C. */ +// A path is a set of nodes of the etree which are all affected by the same +// columns of C. typedef struct Path_struct { - Int start ; /* column at which to start, or EMPTY if initial */ - Int end ; /* column at which to end, or EMPTY if initial */ - Int ccol ; /* column of C to which path refers */ - Int parent ; /* parent path */ - Int c ; /* child of j along this path */ - Int next ; /* next path in link list */ - Int rank ; /* number of rank-1 paths merged onto this path */ - Int order ; /* dfs order of this path */ - Int wfirst ; /* first column of W to affect this path */ - Int pending ; /* column at which the path is pending */ - Int botrow ; /* for partial update/downdate of solution to Lx=b */ + Int start ; // column at which to start, or EMPTY if initial + Int end ; // column at which to end, or EMPTY if initial + Int ccol ; // column of C to which path refers + Int parent ; // parent path + Int c ; // child of j along this path + Int next ; // next path in link list + Int rank ; // number of rank-1 paths merged onto this path + Int order ; // dfs order of this path + Int wfirst ; // first column of W to affect this path + Int pending ; // column at which the path is pending + Int botrow ; // for partial update/downdate of solution to Lx=b } Path_type ; -/* ========================================================================== */ -/* === dfs ================================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// dfs +//------------------------------------------------------------------------------ -/* Compute the DFS order of the set of paths. This can be recursive because - * there are at most 23 paths to sort: one for each column of C (8 at most), - * and one for each node in a balanced binary tree with 8 leaves (15). - * Stack overflow is thus not a problem. */ +// Compute the DFS order of the set of paths. This can be recursive because +// there are at most 23 paths to sort: one for each column of C (8 at most), +// and one for each node in a balanced binary tree with 8 leaves (15). +// Stack overflow is thus not a problem. static void dfs ( - Path_type *Path, /* the set of Paths */ - Int k, /* the rank of the update/downdate */ - Int path, /* which path to work on */ - Int *path_order, /* the current path order */ - Int *w_order, /* the current order of the columns of W */ + Path_type *Path, // the set of Paths + Int k, // the rank of the update/downdate + Int path, // which path to work on + Int *path_order, // the current path order + Int *w_order, // the current order of the columns of W Int depth, - Int npaths /* total number of paths */ + Int npaths // total number of paths ) { - Int c ; /* child path */ + Int c ; // child path ASSERT (path >= 0 && path < npaths) ; if (path < k) { - /* this is a leaf node, corresponding to column W (:,path) */ - /* and column C (:, Path [path].ccol) */ - ASSERT (Path [path].ccol >= 0) ; - Path [path].wfirst = *w_order ; - Path [path].order = *w_order ; - (*w_order)++ ; + // this is a leaf node, corresponding to column W (:,path) + // and column C (:, Path [path].ccol) + ASSERT (Path [path].ccol >= 0) ; + Path [path].wfirst = *w_order ; + Path [path].order = *w_order ; + (*w_order)++ ; } else { - /* this is a non-leaf path, within the tree */ - ASSERT (Path [path].c != EMPTY) ; - ASSERT (Path [path].ccol == EMPTY) ; - /* order each child path */ - for (c = Path [path].c ; c != EMPTY ; c = Path [c].next) - { - dfs (Path, k, c, path_order, w_order, depth+1, npaths) ; - if (Path [path].wfirst == EMPTY) - { - Path [path].wfirst = Path [c].wfirst ; - } - } - /* order this path next */ - Path [path].order = (*path_order)++ ; + // this is a non-leaf path, within the tree + ASSERT (Path [path].c != EMPTY) ; + ASSERT (Path [path].ccol == EMPTY) ; + // order each child path + for (c = Path [path].c ; c != EMPTY ; c = Path [c].next) + { + dfs (Path, k, c, path_order, w_order, depth+1, npaths) ; + if (Path [path].wfirst == EMPTY) + { + Path [path].wfirst = Path [c].wfirst ; + } + } + // order this path next + Path [path].order = (*path_order)++ ; } } +//------------------------------------------------------------------------------ +// numeric update/downdate routines +//------------------------------------------------------------------------------ + +// naming scheme for the update/downdate worker methods: +// +// single case: s_updown_k_rank +// double case: d_updown_k_rank +// +// where k is 1, 2, 4, or 8, and rank is r for the t_cholmod_updown_wdim +// method, or 1 to 8 for the lowest level kernels. See t_cholmod_updown_wdim.c +// for details. -/* ========================================================================== */ -/* === numeric update/downdate routines ===================================== */ -/* ========================================================================== */ +#define UPDOWN_METHOD(prefix,k,rank) prefix ## updown_ ## k ## _ ## rank -#define WDIM 1 -#include "t_cholmod_updown.c" -#define WDIM 2 -#include "t_cholmod_updown.c" -#define WDIM 4 -#include "t_cholmod_updown.c" -#define WDIM 8 -#include "t_cholmod_updown.c" +#define DOUBLE +#define REAL +#include "t_cholmod_updown_worker.c" +#undef DOUBLE +#define SINGLE +#define REAL +#include "t_cholmod_updown_worker.c" -/* ========================================================================== */ -/* === cholmod_updown_mark ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_updown_mark +//------------------------------------------------------------------------------ -/* Update/downdate LDL' +/- C*C', and update/downdate selected portions of the - * solution to Lx=b. - * - * The original system is L*x = b. The new system is Lnew*xnew = b + deltab. - * deltab(i) can be nonzero only if column i of L is modified by the update/ - * downdate. If column i is not modified, the deltab(i) is not accessed. - * - * The solution to Lx=b is not modified if either X or DeltaB are NULL. - * - * Rowmark and colmark: - * -------------------- - * - * rowmark and colmark affect which portions of L take part in the update/ - * downdate of the solution to Lx=b. They do not affect how L itself is - * updated/downdated. They are both ignored if X or DeltaB are NULL. - * - * If not NULL, rowmark is an integer array of size n where L is n-by-n. - * rowmark [j] defines the part of column j of L that takes part in the update/ - * downdate of the forward solve, Lx=b. Specifically, if i = rowmark [j], - * then L(j:i-1,j) is used, and L(i:end,j) is ignored. - * - * If not NULL, colmark is an integer array of size C->ncol. colmark [ccol] - * for a column C(:,ccol) redefines those parts of L that take part in the - * update/downdate of Lx=b. Each column of C affects a set of columns of L. - * If column ccol of C affects column j of L, then the new rowmark [j] of - * column j of L is defined as colmark [ccol]. In a multiple-rank update/ - * downdate, if two or more columns of C affect column j, its new rowmark [j] - * is the colmark of the least-numbered column of C. colmark is ignored if - * it is NULL, in which case rowmark is not modified. If colmark [ccol] is - * EMPTY (-1), then rowmark is not modified for that particular column of C. - * colmark is ignored if it is NULL, or rowmark, X, or DeltaB are NULL. - * - * The algorithm for modifying the solution to Lx=b when rowmark and colmark - * are NULL is as follows: - * - * for each column j of L that is modified: - * deltab (j:end) += L (j:end,j) * x(j) - * modify L - * for each column j of L that is modified: - * x (j) = deltab (j) - * deltab (j) = 0 - * deltab (j+1:end) -= L (j+1:end,j) * x(j) - * - * If rowmark is non-NULL but colmark is NULL: - * - * for each column j of L that is modified: - * deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j) - * modify L - * for each column j of L that is modified: - * x (j) = deltab (j) - * deltab (j) = 0 - * deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j) - * - * If both rowmark and colmark are non-NULL: - * - * for each column j of L that is modified: - * deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j) - * modify L - * for each column j of L that is modified: - * modify rowmark (j) according to colmark - * for each column j of L that is modified: - * x (j) = deltab (j) - * deltab (j) = 0 - * deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j) - * - * Note that if the rank of C exceeds k = Common->maxrank (which is 2, 4, or 8), - * then the update/downdate is done as a series of rank-k updates. In this - * case, the above algorithm is repeated for each block of k columns of C. - * - * Unless it leads to no changes in rowmark, colmark should be used only if - * C->ncol <= Common->maxrank, because the update/downdate is done with maxrank - * columns at a time. Otherwise, the results are undefined. - * - * This routine is an "expert" routine. It is meant for use in LPDASA only. - */ +// Update/downdate LDL' +/- C*C', and update/downdate selected portions of the +// solution to Lx=b. +// +// The original system is L*x = b. The new system is Lnew*xnew = b + deltab. +// deltab(i) can be nonzero only if column i of L is modified by the update/ +// downdate. If column i is not modified, the deltab(i) is not accessed. +// +// The solution to Lx=b is not modified if either X or DeltaB are NULL. +// +// Rowmark and colmark: +// -------------------- +// +// rowmark and colmark affect which portions of L take part in the update/ +// downdate of the solution to Lx=b. They do not affect how L itself is +// updated/downdated. They are both ignored if X or DeltaB are NULL. +// +// If not NULL, rowmark is an integer array of size n where L is n-by-n. +// rowmark [j] defines the part of column j of L that takes part in the update/ +// downdate of the forward solve, Lx=b. Specifically, if i = rowmark [j], +// then L(j:i-1,j) is used, and L(i:end,j) is ignored. +// +// If not NULL, colmark is an integer array of size C->ncol. colmark [ccol] +// for a column C(:,ccol) redefines those parts of L that take part in the +// update/downdate of Lx=b. Each column of C affects a set of columns of L. +// If column ccol of C affects column j of L, then the new rowmark [j] of +// column j of L is defined as colmark [ccol]. In a multiple-rank update/ +// downdate, if two or more columns of C affect column j, its new rowmark [j] +// is the colmark of the least-numbered column of C. colmark is ignored if +// it is NULL, in which case rowmark is not modified. If colmark [ccol] is +// EMPTY (-1), then rowmark is not modified for that particular column of C. +// colmark is ignored if it is NULL, or rowmark, X, or DeltaB are NULL. +// +// The algorithm for modifying the solution to Lx=b when rowmark and colmark +// are NULL is as follows: +// +// for each column j of L that is modified: +// deltab (j:end) += L (j:end,j) * x(j) +// modify L +// for each column j of L that is modified: +// x (j) = deltab (j) +// deltab (j) = 0 +// deltab (j+1:end) -= L (j+1:end,j) * x(j) +// +// If rowmark is non-NULL but colmark is NULL: +// +// for each column j of L that is modified: +// deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j) +// modify L +// for each column j of L that is modified: +// x (j) = deltab (j) +// deltab (j) = 0 +// deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j) +// +// If both rowmark and colmark are non-NULL: +// +// for each column j of L that is modified: +// deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j) +// modify L +// for each column j of L that is modified: +// modify rowmark (j) according to colmark +// for each column j of L that is modified: +// x (j) = deltab (j) +// deltab (j) = 0 +// deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j) +// +// Note that if the rank of C exceeds k = Common->maxrank (which is 2, 4, or 8), +// then the update/downdate is done as a series of rank-k updates. In this +// case, the above algorithm is repeated for each block of k columns of C. +// +// Unless it leads to no changes in rowmark, colmark should be used only if +// C->ncol <= Common->maxrank, because the update/downdate is done with maxrank +// columns at a time. Otherwise, the results are undefined. +// +// This routine is an "expert" routine. It is meant for use in LPDASA only. int CHOLMOD(updown_mark) ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - Int *colmark, /* Int array of size n. */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + Int *colmark, // array of size n. See cholmod_updown.c for details + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - return (CHOLMOD(updown_mask2) (update, C, colmark, NULL, 0, L, X, DeltaB, - Common)) ; + return (CHOLMOD(updown_mask2) (update, C, colmark, + /* mask: */ NULL, /* maskmark: */ 0, + L, X, DeltaB, Common)) ; } - -/* ========================================================================== */ -/* === cholmod_updown_mask ================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_updown_mask +//------------------------------------------------------------------------------ int CHOLMOD(updown_mask) ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - Int *colmark, /* Int array of size n. See cholmod_updown.c */ - Int *mask, /* size n */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + Int *colmark, // array of size n. See cholmod_updown.c for details + Int *mask, // size n + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - Int maskmark = 0 ; - return (CHOLMOD(updown_mask2) (update, C, colmark, mask, maskmark, + return (CHOLMOD(updown_mask2) (update, C, colmark, + mask, /* maskmark: */ 0, L, X, DeltaB, Common)) ; } -/* ========================================================================== */ -/* === cholmod_updown_mask2 ================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_updown_mask2 +//------------------------------------------------------------------------------ int CHOLMOD(updown_mask2) ( - /* ---- input ---- */ - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* the incoming sparse update */ - Int *colmark, /* Int array of size n. See cholmod_updown.c */ - Int *mask, /* size n */ + // input: + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + Int *colmark, // array of size n. See cholmod_updown.c for details + Int *mask, // size n Int maskmark, - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ - cholmod_dense *DeltaB, /* change in b, zero on output */ - /* --------------- */ + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output cholmod_common *Common ) { - double xj, fl ; - double *Lx, *W, *Xx, *Nx ; - Int *Li, *Lp, *Lnz, *Cp, *Ci, *Cnz, *Head, *Flag, *Stack, *Lnext, *Iwork, - *Set_ps1 [32], *Set_ps2 [32], *ps1, *ps2 ; - size_t maxrank ; - Path_type OrderedPath [32], Path [32] ; - Int n, wdim, k1, k2, npaths, i, j, row, packed, ccol, p, cncol, do_solve, - mark, jj, j2, kk, nextj, p1, p2, c, use_colmark, newlnz, - k, newpath, path_order, w_order, scattered, path, newparent, pp1, pp2, - smax, maxrow, row1, nsets, s, p3, newlnz1, Set [32], top, len, lnz, m, - botrow ; - size_t w ; - int ok = TRUE ; - DEBUG (Int oldparent) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (C, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ; RETURN_IF_XTYPE_INVALID (C, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - n = L->n ; - cncol = C->ncol ; + Int n = L->n ; + Int cncol = C->ncol ; if (!(C->sorted)) { - ERROR (CHOLMOD_INVALID, "C must have sorted columns") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "C must have sorted columns") ; + return (FALSE) ; } - if (n != (Int) (C->nrow)) + if (L->n != C->nrow) { - ERROR (CHOLMOD_INVALID, "C and L dimensions do not match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "C and L dimensions do not match") ; + return (FALSE) ; } - do_solve = (X != NULL) && (DeltaB != NULL) ; - if (do_solve) + if (L->dtype != C->dtype) { - RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; - Xx = X->x ; - Nx = DeltaB->x ; - if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n || - DeltaB->ncol != 1 || Xx == NULL || Nx == NULL) - { - ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; - return (FALSE) ; - } + ERROR (CHOLMOD_INVALID, "C and L must have the same dtype") ; + return (FALSE) ; } - else + + if ((X != NULL) && (DeltaB != NULL)) { - Xx = NULL ; - Nx = NULL ; + RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ; + if (X->nrow != L->n || X->ncol != 1 || + DeltaB->nrow != L->n || DeltaB->ncol != 1 || + X->dtype != L->dtype || DeltaB->dtype != L->dtype) + { + ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ; + return (FALSE) ; + } } + Common->status = CHOLMOD_OK ; Common->modfl = 0 ; - fl = 0 ; - use_colmark = (colmark != NULL) ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ - - /* Note: cholmod_rowadd and cholmod_rowdel use the second n doubles in - * Common->Xwork for Cx, and then perform a rank-1 update here, which uses - * the first n doubles in Common->Xwork. Both the rowadd and rowdel - * routines allocate enough workspace so that Common->Xwork isn't destroyed - * below. Also, both cholmod_rowadd and cholmod_rowdel use the second n - * ints in Common->Iwork for Ci. - */ - - /* make sure maxrank is in the proper range */ - maxrank = CHOLMOD(maxrank) (n, Common) ; - k = MIN (cncol, (Int) maxrank) ; /* maximum k is wdim */ - wdim = Power2 [k] ; /* number of columns needed in W */ - ASSERT (wdim <= (Int) maxrank) ; - PRINT1 (("updown wdim final "ID" k "ID"\n", wdim, k)) ; - - /* w = wdim * n */ - w = CHOLMOD(mult_size_t) (n, wdim, &ok) ; + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- + + // Note: cholmod_rowadd and cholmod_rowdel use the second n doubles in + // Common->Xwork for Cx, and then perform a rank-1 update here, which uses + // the first n doubles in Common->Xwork. Both the rowadd and rowdel + // routines allocate enough workspace so that Common->Xwork isn't destroyed + // below. Also, both cholmod_rowadd and cholmod_rowdel use the second n + // ints in Common->Iwork for C->i. + + // make sure maxrank is in the proper range + size_t maxrank = CHOLMOD(maxrank) (n, Common) ; + Int k = MIN (cncol, (Int) maxrank) ; // maximum k is wdim + size_t wdim = Power2 [k] ; // number of columns needed in W + ASSERT (wdim <= maxrank) ; + PRINT1 (("updown wdim final "ID" k "ID"\n", (Int) wdim, k)) ; + + // w = wdim * n + int ok = TRUE ; + size_t w = CHOLMOD(mult_size_t) (L->n, wdim, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, n, w, Common) ; + CHOLMOD(alloc_work) (L->n, L->n, w, L->dtype, Common) ; if (Common->status < CHOLMOD_OK || maxrank == 0) { - /* out of memory, L is returned unchanged */ - return (FALSE) ; + // out of memory, L is returned unchanged + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* convert to simplicial numeric LDL' factor, if not already */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert to simplicial numeric LDL' factor, if not already + //-------------------------------------------------------------------------- - if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) + if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) { - /* can only update/downdate a simplicial LDL' factorization */ - CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, - Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory, L is returned unchanged */ - return (FALSE) ; - } + // can only update/downdate a simplicial LDL' factorization + CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L, + Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory, L is returned unchanged + return (FALSE) ; + } } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - /* mark = CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - mark = Common->mark ; PRINT1 (("updown, rank %g update %d\n", (double) C->ncol, update)) ; DEBUG (CHOLMOD(dump_factor) (L, "input L for updown", Common)) ; ASSERT (CHOLMOD(dump_sparse) (C, "input C for updown", Common) >= 0) ; - Ci = C->i ; - Cp = C->p ; - Cnz = C->nz ; - packed = C->packed ; - ASSERT (IMPLIES (!packed, Cnz != NULL)) ; - - /* ---------------------------------------------------------------------- */ - /* quick return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return + //-------------------------------------------------------------------------- if (cncol <= 0 || n == 0) { - /* nothing to do */ - return (TRUE) ; + // nothing to do + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* get L */ - /* ---------------------------------------------------------------------- */ - - Li = L->i ; - Lx = L->x ; - Lp = L->p ; - Lnz = L->nz ; - Lnext = L->next ; - ASSERT (Lnz != NULL) ; - - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ - - Flag = Common->Flag ; /* size n, Flag [i] <= mark must hold */ - Head = Common->Head ; /* size n, Head [i] == EMPTY must hold */ - W = Common->Xwork ; /* size n-by-wdim, zero on input and output*/ + //-------------------------------------------------------------------------- + // update/downdate + //-------------------------------------------------------------------------- - /* note that Iwork [n .. 2*n-1] (i/i/l) may be in use in rowadd/rowdel: */ - Iwork = Common->Iwork ; - Stack = Iwork ; /* size n, uninitialized (i/i/l) */ - - /* ---------------------------------------------------------------------- */ - /* entire rank-cncol update, done as a sequence of rank-k updates */ - /* ---------------------------------------------------------------------- */ - - ps1 = NULL ; - ps2 = NULL ; - - for (k1 = 0 ; k1 < cncol ; k1 += k) + switch (L->dtype & 4) { - - /* ------------------------------------------------------------------ */ - /* get the next k columns of C for the update/downdate */ - /* ------------------------------------------------------------------ */ - - /* the last update/downdate might be less than rank-k */ - if (k > cncol - k1) - { - k = cncol - k1 ; - wdim = Power2 [k] ; - } - k2 = k1 + k - 1 ; - - /* workspaces are in the following state, on input and output */ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ; - - /* ------------------------------------------------------------------ */ - /* create a zero-length path for each column of W */ - /* ------------------------------------------------------------------ */ - - nextj = n ; - path = 0 ; - for (ccol = k1 ; ccol <= k2 ; ccol++) - { - PRINT1 (("Column ["ID"]: "ID"\n", path, ccol)) ; - ASSERT (ccol >= 0 && ccol <= cncol) ; - pp1 = Cp [ccol] ; - pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; - /* get the row index j of the first entry in C (:,ccol) */ - if (pp2 > pp1) - { - /* Column ccol of C has at least one entry. */ - j = Ci [pp1] ; - } - else - { - /* Column ccol of C is empty. Pretend it has one entry in - * the last column with numerical value of zero. */ - j = n-1 ; - } - ASSERT (j >= 0 && j < n) ; - - /* find first column to work on */ - nextj = MIN (nextj, j) ; - - Path [path].ccol = ccol ; /* which column of C this path is for */ - Path [path].start = EMPTY ; /* paths for C have zero length */ - Path [path].end = EMPTY ; - Path [path].parent = EMPTY ; /* no parent yet */ - Path [path].rank = 1 ; /* one column of W */ - Path [path].c = EMPTY ; /* no child of this path (case A) */ - Path [path].next = Head [j] ; /* this path is pending at col j */ - Path [path].pending = j ; /* this path is pending at col j */ - Head [j] = path ; /* this path is pending at col j */ - PRINT1(("Path "ID" starts: start "ID" end "ID" parent "ID" c "ID"" - "j "ID" ccol "ID"\n", path, Path [path].start, - Path [path].end, Path [path].parent, - Path [path].c, j, ccol)) ; - - /* initialize botrow for this path */ - Path [path].botrow = (use_colmark) ? colmark [ccol] : n ; - - path++ ; - } - - /* we start with paths 0 to k-1. Next one (now unused) is npaths */ - npaths = k ; - - j = nextj ; - ASSERT (j < n) ; - scattered = FALSE ; - - /* ------------------------------------------------------------------ */ - /* symbolic update of columns of L */ - /* ------------------------------------------------------------------ */ - - while (j < n) - { - ASSERT (j >= 0 && j < n && Lnz [j] > 0) ; - - /* the old column, Li [p1..p2-1]. D (j,j) is stored in Lx [p1] */ - p1 = Lp [j] ; - newlnz = Lnz [j] ; - p2 = p1 + newlnz ; - -#ifndef NDEBUG - PRINT1 (("\n=========Column j="ID" p1 "ID" p2 "ID" lnz "ID" \n", - j, p1, p2, newlnz)) ; - dump_col ("Old", j, p1, p2, Li, Lx, n, Common) ; - oldparent = (Lnz [j] > 1) ? (Li [p1 + 1]) : EMPTY ; - ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ; - ASSERT (!scattered) ; - PRINT1 (("Col "ID": Checking paths, npaths: "ID"\n", j, npaths)) ; - for (kk = 0 ; kk < npaths ; kk++) - { - Int kk2, found, j3 = Path [kk].pending ; - PRINT2 (("Path "ID" pending at "ID".\n", kk, j3)) ; - if (j3 != EMPTY) - { - /* Path kk must be somewhere in link list for column j3 */ - ASSERT (Head [j3] != EMPTY) ; - PRINT3 ((" List at "ID": ", j3)) ; - found = FALSE ; - for (kk2 = Head [j3] ; kk2 != EMPTY ; kk2 = Path [kk2].next) - { - PRINT3 ((""ID" ", kk2)) ; - ASSERT (Path [kk2].pending == j3) ; - found = found || (kk2 == kk) ; - } - PRINT3 (("\n")) ; - ASSERT (found) ; - } - } - PRINT1 (("\nCol "ID": Paths at this column, head "ID"\n", - j, Head [j])); - ASSERT (Head [j] != EMPTY) ; - for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next) - { - PRINT1 (("path "ID": (c="ID" j="ID") npaths "ID"\n", - kk, Path[kk].c, j, npaths)) ; - ASSERT (kk >= 0 && kk < npaths) ; - ASSERT (Path [kk].pending == j) ; - } -#endif - - /* -------------------------------------------------------------- */ - /* determine the path we're on */ - /* -------------------------------------------------------------- */ - - /* get the first old path at column j */ - path = Head [j] ; - - /* -------------------------------------------------------------- */ - /* update/downdate of forward solve, Lx=b */ - /* -------------------------------------------------------------- */ - - if (do_solve) - { - xj = Xx [j] ; - if (xj != 0) - { - xj = Xx [j] ; - /* This is first time column j has been seen for entire */ - /* rank-k update/downdate. */ - - /* DeltaB += Lold (j:botrow-1,j) * X (j) */ - Nx [j] += xj ; /* diagonal of L */ - - /* find the botrow for this column */ - botrow = (use_colmark) ? Path [path].botrow : n ; - - for (p = p1 + 1 ; p < p2 ; p++) - { - i = Li [p] ; - if (i >= botrow) - { - break ; - } - Nx [i] += Lx [p] * xj ; - } - - /* clear X[j] to flag col j of Lold as having been seen. If - * X (j) was initially zero, then the above code is never - * executed for column j. This is safe, since if xj=0 the - * code above does not do anything anyway. */ - Xx [j] = 0.0 ; - } - } - - /* -------------------------------------------------------------- */ - /* start a new path at this column if two or more paths merge */ - /* -------------------------------------------------------------- */ - - newpath = - /* start a new path if paths have merged */ - (Path [path].next != EMPTY) - /* or if j is the first node on a path (case A). */ - || (Path [path].c == EMPTY) ; - - if (newpath) - { - /* get the botrow of the first path at column j */ - botrow = (use_colmark) ? Path [path].botrow : n ; - - path = npaths++ ; - ASSERT (npaths <= 3*k) ; - Path [path].ccol = EMPTY ; /* no single col of C for this path*/ - Path [path].start = j ; /* path starts at this column j */ - Path [path].end = EMPTY ; /* don't know yet where it ends */ - Path [path].parent = EMPTY ;/* don't know parent path yet */ - Path [path].rank = 0 ; /* rank is sum of child path ranks */ - PRINT1 (("Path "ID" starts: start "ID" end "ID" parent "ID"\n", - path, Path [path].start, Path [path].end, Path [path].parent)) ; - - /* set the botrow of the new path */ - Path [path].botrow = (use_colmark) ? botrow : n ; - } - - /* -------------------------------------------------------------- */ - /* for each path kk pending at column j */ - /* -------------------------------------------------------------- */ - - /* make a list of the sets that need to be merged into column j */ - nsets = 0 ; - - for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next) - { - - /* ---------------------------------------------------------- */ - /* path kk is at (c,j) */ - /* ---------------------------------------------------------- */ - - c = Path [kk].c ; - ASSERT (c < j) ; - PRINT1 (("TUPLE on path "ID" (c="ID" j="ID")\n", kk, c, j)) ; - ASSERT (Path [kk].pending == j) ; - - if (newpath) - { - /* finalize path kk and find rank of this path */ - Path [kk].end = c ; /* end of old path is previous node c */ - Path [kk].parent = path ; /* parent is this path */ - Path [path].rank += Path [kk].rank ; /* sum up ranks */ - Path [kk].pending = EMPTY ; - PRINT1 (("Path "ID" done:start "ID" end "ID" parent "ID"\n", - kk, Path [kk].start, Path [kk].end, Path [kk].parent)) ; - } - - if (c == EMPTY) - { - - /* ------------------------------------------------------ */ - /* CASE A: first node in path */ - /* ------------------------------------------------------ */ - - /* update: add pattern of incoming column */ - - /* Column ccol of C is in Ci [pp1 ... pp2-1] */ - ccol = Path [kk].ccol ; - pp1 = Cp [ccol] ; - pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; - PRINT1 (("Case A, ccol = "ID" len "ID"\n", ccol, pp2-pp1)) ; - ASSERT (IMPLIES (pp2 > pp1, Ci [pp1] == j)) ; - - if (!scattered) - { - /* scatter the original pattern of column j of L */ - for (p = p1 ; p < p2 ; p++) - { - Flag [Li [p]] = mark ; - } - scattered = TRUE ; - } - - /* scatter column ccol of C (skip first entry, j) */ - newlnz1 = newlnz ; - for (p = pp1 + 1 ; p < pp2 ; p++) - { - row = Ci [p] ; - if (Flag [row] < mark) - { - /* this is a new entry in Lj' */ - Flag [row] = mark ; - newlnz++ ; - } - } - if (newlnz1 != newlnz) - { - /* column ccol of C adds something to column j of L */ - Set [nsets++] = FLIP (ccol) ; - } - - } - else if (Head [c] == 1) - { - - /* ------------------------------------------------------ */ - /* CASE B: c is old, but changed, child of j */ - /* CASE C: new child of j */ - /* ------------------------------------------------------ */ - - /* Head [c] is 1 if col c of L has new entries, - * EMPTY otherwise */ - Flag [c] = 0 ; - Head [c] = EMPTY ; - - /* update: add Lc' */ - - /* column c of L is in Li [pp1 .. pp2-1] */ - pp1 = Lp [c] ; - pp2 = pp1 + Lnz [c] ; - PRINT1 (("Case B/C: c = "ID"\n", c)) ; - DEBUG (dump_col ("Child", c, pp1, pp2, Li, Lx, n, Common)) ; - ASSERT (j == Li [pp1 + 1]) ; /* j is new parent of c */ - - if (!scattered) - { - /* scatter the original pattern of column j of L */ - for (p = p1 ; p < p2 ; p++) - { - Flag [Li [p]] = mark ; - } - scattered = TRUE ; - } - - /* scatter column c of L (skip first two entries, c and j)*/ - newlnz1 = newlnz ; - for (p = pp1 + 2 ; p < pp2 ; p++) - { - row = Li [p] ; - if (Flag [row] < mark) - { - /* this is a new entry in Lj' */ - Flag [row] = mark ; - newlnz++ ; - } - } - PRINT2 (("\n")) ; - - if (newlnz1 != newlnz) - { - /* column c of L adds something to column j of L */ - Set [nsets++] = c ; - } - } - } - - /* -------------------------------------------------------------- */ - /* update the pattern of column j of L */ - /* -------------------------------------------------------------- */ - - /* Column j of L will be in Li/Lx [p1 .. p3-1] */ - p3 = p1 + newlnz ; - ASSERT (IMPLIES (nsets == 0, newlnz == Lnz [j])) ; - PRINT1 (("p1 "ID" p2 "ID" p3 "ID" nsets "ID"\n", p1, p2, p3,nsets)); - - /* -------------------------------------------------------------- */ - /* ensure we have enough space for the longer column */ - /* -------------------------------------------------------------- */ - - if (nsets > 0 && p3 > Lp [Lnext [j]]) - { - PRINT1 (("Col realloc: j "ID" newlnz "ID"\n", j, newlnz)) ; - if (!CHOLMOD(reallocate_column) (j, newlnz, L, Common)) - { - /* out of memory, L is now simplicial symbolic */ - CHOLMOD(clear_flag) (Common) ; - for (j = 0 ; j <= n ; j++) - { - Head [j] = EMPTY ; - } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ; - return (FALSE) ; - } - /* L->i and L->x may have moved. Column j has moved too */ - Li = L->i ; - Lx = L->x ; - p1 = Lp [j] ; - p2 = p1 + Lnz [j] ; - p3 = p1 + newlnz ; - } - - /* -------------------------------------------------------------- */ - /* create set pointers */ - /* -------------------------------------------------------------- */ - - for (s = 0 ; s < nsets ; s++) - { - /* Pattern of Set s is *(Set_ps1 [s] ... Set_ps2 [s]-1) */ - c = Set [s] ; - if (c < EMPTY) - { - /* column ccol of C, skip first entry (j) */ - ccol = FLIP (c) ; - pp1 = Cp [ccol] ; - pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; - ASSERT (pp2 - pp1 > 1) ; - Set_ps1 [s] = &(Ci [pp1 + 1]) ; - Set_ps2 [s] = &(Ci [pp2]) ; - PRINT1 (("set "ID" is ccol "ID"\n", s, ccol)) ; - } - else - { - /* column c of L, skip first two entries (c and j) */ - pp1 = Lp [c] ; - pp2 = pp1 + Lnz [c] ; - ASSERT (Lnz [c] > 2) ; - Set_ps1 [s] = &(Li [pp1 + 2]) ; - Set_ps2 [s] = &(Li [pp2]) ; - PRINT1 (("set "ID" is L "ID"\n", s, c)) ; - } - DEBUG (dump_set (s, Set_ps1, Set_ps2, j, n, Common)) ; - } - - /* -------------------------------------------------------------- */ - /* multiset merge */ - /* -------------------------------------------------------------- */ - - /* Merge the sets into a single sorted set, Lj'. Before the merge - * starts, column j is located in Li/Lx [p1 ... p2-1] and the - * space Li/Lx [p2 ... p3-1] is empty. p1 is Lp [j], p2 is - * Lp [j] + Lnz [j] (the old length of the column), and p3 is - * Lp [j] + newlnz (the new and longer length of the column). - * - * The sets 0 to nsets-1 are defined by the Set_ps1 and Set_ps2 - * pointers. Set s is located in *(Set_ps1 [s] ... Set_ps2 [s]-1). - * It may be a column of C, or a column of L. All row indices i in - * the sets are in the range i > j and i < n. All sets are sorted. - * - * The merge into column j of L is done in place. - * - * During the merge, p2 and p3 are updated. Li/Lx [p1..p2-1] - * reflects the indices of the old column j of L that are yet to - * be merged into the new column. Entries in their proper place in - * the new column j of L are located in Li/Lx [p3 ... p1+newlnz-1]. - * The merge finishes when p2 == p3. - * - * During the merge, set s consumed as it is merged into column j of - * L. Its unconsumed contents are *(Set_ps1 [s] ... Set_ps2 [s]-1). - * When a set is completely consumed, it is removed from the set of - * sets, and nsets is decremented. - * - * The multiset merge and 2-set merge finishes when p2 == p3. - */ - - PRINT1 (("Multiset merge p3 "ID" p2 "ID" nsets "ID"\n", - p3, p2, nsets)) ; - - while (p3 > p2 && nsets > 1) - { - -#ifndef NDEBUG - PRINT2 (("\nMultiset merge. nsets = "ID"\n", nsets)) ; - PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n", - p1, p2, p3)) ; - for (p = p1 + 1 ; p < p2 ; p++) - { - PRINT2 ((" p: "ID" source row "ID" %g\n", - p, Li[p], Lx[p])) ; - ASSERT (Li [p] > j && Li [p] < n) ; - } - PRINT2 (("---\n")) ; - for (p = p3 ; p < p1 + newlnz ; p++) - { - PRINT2 ((" p: "ID" target row "ID" %g\n", - p, Li[p], Lx[p])) ; - ASSERT (Li [p] > j && Li [p] < n) ; - } - for (s = 0 ; s < nsets ; s++) - { - dump_set (s, Set_ps1, Set_ps2, j, n, Common) ; - } -#endif - - /* get the entry at the tail end of source column Lj */ - row1 = Li [p2 - 1] ; - ASSERT (row1 >= j && p2 >= p1) ; - - /* find the largest row in all the sets */ - maxrow = row1 ; - smax = EMPTY ; - for (s = nsets-1 ; s >= 0 ; s--) - { - ASSERT (Set_ps1 [s] < Set_ps2 [s]) ; - row = *(Set_ps2 [s] - 1) ; - if (row == maxrow) - { - /* skip past this entry in set s (it is a duplicate) */ - Set_ps2 [s]-- ; - if (Set_ps1 [s] == Set_ps2 [s]) - { - /* nothing more in this set */ - nsets-- ; - Set_ps1 [s] = Set_ps1 [nsets] ; - Set_ps2 [s] = Set_ps2 [nsets] ; - if (smax == nsets) - { - /* Set smax redefined; it is now this set */ - smax = s ; - } - } - } - else if (row > maxrow) - { - maxrow = row ; - smax = s ; - } - } - ASSERT (maxrow > j) ; - - /* move the row onto the stack of the target column */ - if (maxrow == row1) - { - /* next entry is in Lj, move to the bottom of Lj' */ - ASSERT (smax == EMPTY) ; - p2-- ; - p3-- ; - Li [p3] = maxrow ; - Lx [p3] = Lx [p2] ; - } - else - { - /* new entry in Lj' */ - ASSERT (smax >= 0 && smax < nsets) ; - Set_ps2 [smax]-- ; - p3-- ; - Li [p3] = maxrow ; - Lx [p3] = 0.0 ; - if (Set_ps1 [smax] == Set_ps2 [smax]) - { - /* nothing more in this set */ - nsets-- ; - Set_ps1 [smax] = Set_ps1 [nsets] ; - Set_ps2 [smax] = Set_ps2 [nsets] ; - PRINT1 (("Set "ID" now empty\n", smax)) ; - } - } - } - - /* -------------------------------------------------------------- */ - /* 2-set merge: */ - /* -------------------------------------------------------------- */ - - /* This the same as the multi-set merge, except there is only one - * set s = 0 left. The source column j and the set 0 are being - * merged into the target column j. */ - - if (nsets > 0) - { - ps1 = Set_ps1 [0] ; - ps2 = Set_ps2 [0] ; - } - - while (p3 > p2) - { - -#ifndef NDEBUG - PRINT2 (("\n2-set merge.\n")) ; - ASSERT (nsets == 1) ; - PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n", - p1, p2, p3)) ; - for (p = p1 + 1 ; p < p2 ; p++) - { - PRINT2 ((" p: "ID" source row "ID" %g\n", - p, Li[p], Lx[p])) ; - ASSERT (Li [p] > j && Li [p] < n) ; - } - PRINT2 (("---\n")) ; - for (p = p3 ; p < p1 + newlnz ; p++) - { - PRINT2 ((" p: "ID" target row "ID" %g\n", - p, Li[p], Lx[p])) ; - ASSERT (Li [p] > j && Li [p] < n) ; - } - dump_set (0, Set_ps1, Set_ps2, j, n, Common) ; -#endif - - if (p2 == p1 + 1) - { - /* the top of Lj is empty; copy the set and quit */ - while (p3 > p2) - { - /* new entry in Lj' */ - row = *(--ps2) ; - p3-- ; - Li [p3] = row ; - Lx [p3] = 0.0 ; - } - } - else - { - /* get the entry at the tail end of Lj */ - row1 = Li [p2 - 1] ; - ASSERT (row1 > j && row1 < n) ; - /* get the entry at the tail end of the incoming set */ - ASSERT (ps1 < ps2) ; - row = *(ps2-1) ; - ASSERT (row > j && row1 < n) ; - /* move the larger of the two entries to the target set */ - if (row1 >= row) - { - /* next entry is in Lj, move to the bottom */ - if (row1 == row) - { - /* skip past this entry in the set */ - ps2-- ; - } - p2-- ; - p3-- ; - Li [p3] = row1 ; - Lx [p3] = Lx [p2] ; - } - else - { - /* new entry in Lj' */ - ps2-- ; - p3-- ; - Li [p3] = row ; - Lx [p3] = 0.0 ; - } - } - } - - /* -------------------------------------------------------------- */ - /* The new column j of L is now in Li/Lx [p1 ... p2-1] */ - /* -------------------------------------------------------------- */ - - p2 = p1 + newlnz ; - DEBUG (dump_col ("After merge: ", j, p1, p2, Li, Lx, n, Common)) ; - - fl += Path [path].rank * (6 + 4 * (double) newlnz) ; - - /* -------------------------------------------------------------- */ - /* clear Flag; original pattern of column j L no longer marked */ - /* -------------------------------------------------------------- */ - - mark = CHOLMOD(clear_flag) (Common) ; - scattered = FALSE ; - - /* -------------------------------------------------------------- */ - /* find the new parent */ - /* -------------------------------------------------------------- */ - - newparent = (newlnz > 1) ? (Li [p1 + 1]) : EMPTY ; - PRINT1 (("\nNew parent, Lnz: "ID": "ID" "ID"\n", - j, newparent,newlnz)); - ASSERT (oldparent == EMPTY || newparent <= oldparent) ; - - /* -------------------------------------------------------------- */ - /* go to the next node in the path */ - /* -------------------------------------------------------------- */ - - /* path moves to (j,nextj) unless j is a root */ - nextj = (newparent == EMPTY) ? n : newparent ; - - /* place path at head of list for nextj, or terminate the path */ - PRINT1 (("\n j = "ID" nextj = "ID"\n\n", j, nextj)) ; - Path [path].c = j ; - if (nextj < n) - { - /* put path on link list of pending paths at column nextj */ - Path [path].next = Head [nextj] ; - Path [path].pending = nextj ; - Head [nextj] = path ; - PRINT1 (("Path "ID" continues to ("ID","ID"). Rank "ID"\n", - path, Path [path].c, nextj, Path [path].rank)) ; - } - else - { - /* path has ended here, at a root */ - Path [path].next = EMPTY ; - Path [path].pending = EMPTY ; - Path [path].end = j ; - PRINT1 (("Path "ID" ends at root ("ID"). Rank "ID"\n", - path, Path [path].end, Path [path].rank)) ; - } - - /* The link list Head [j] can now be emptied. Set Head [j] to 1 - * if column j has changed (it is no longer used as a link list). */ - PRINT1 (("column "ID", oldlnz = "ID"\n", j, Lnz [j])) ; - Head [j] = (Lnz [j] != newlnz) ? 1 : EMPTY ; - Lnz [j] = newlnz ; - PRINT1 (("column "ID", newlnz = "ID"\n", j, newlnz)) ; - DEBUG (dump_col ("New", j, p1, p2, Li, Lx, n, Common)) ; - - /* move to the next column */ - if (k == Path [path].rank) - { - /* only one path left */ - j = nextj ; - } - else - { - /* The current path is moving from column j to column nextj - * (nextj is n if the path has ended). However, there may be - * other paths pending in columns j+1 to nextj-1. There are - * two methods for looking for the next column with a pending - * update. The first one looks at all columns j+1 to nextj-1 - * for a non-empty link list. This can be costly if j and - * nextj differ by a large amount (it can be O(n), but this - * entire routine may take Omega(1) time). The second method - * looks at all paths and finds the smallest column at which any - * path is pending. It takes O(# of paths), which is bounded - * by 23: one for each column of C (up to 8), and then 15 for a - * balanced binary tree with 8 leaves. However, if j and - * nextj differ by a tiny amount (nextj is often j+1 near - * the end of the matrix), looking at columns j+1 to nextj - * would be faster. Both methods give the same answer. */ - - if (nextj - j < npaths) - { - /* there are fewer columns to search than paths */ - PRINT1 (("check j="ID" to nextj="ID"\n", j, nextj)) ; - for (j2 = j + 1 ; j2 < nextj ; j2++) - { - PRINT1 (("check j="ID" "ID"\n", j2, Head [j2])) ; - if (Head [j2] != EMPTY) - { - PRINT1 (("found, j="ID"\n", j2)) ; - ASSERT (Path [Head [j2]].pending == j2) ; - break ; - } - } - } - else - { - /* there are fewer paths than columns to search */ - j2 = nextj ; - for (kk = 0 ; kk < npaths ; kk++) - { - jj = Path [kk].pending ; - PRINT2 (("Path "ID" pending at "ID"\n", kk, jj)) ; - if (jj != EMPTY) j2 = MIN (j2, jj) ; - } - } - j = j2 ; - } - } - - /* ensure workspaces are back to the values required on input */ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, TRUE, Common)) ; - - /* ------------------------------------------------------------------ */ - /* depth-first-search of tree to order the paths */ - /* ------------------------------------------------------------------ */ - - /* create lists of child paths */ - PRINT1 (("\n\nDFS search:\n\n")) ; - for (path = 0 ; path < npaths ; path++) - { - Path [path].c = EMPTY ; /* first child of path */ - Path [path].next = EMPTY ; /* next sibling of path */ - Path [path].order = EMPTY ; /* path is not ordered yet */ - Path [path].wfirst = EMPTY ; /* 1st column of W not found yet */ - -#ifndef NDEBUG - j = Path [path].start ; - PRINT1 (("Path "ID" : start "ID" end "ID" parent "ID" ccol "ID"\n", - path, j, Path [path].end, Path [path].parent, Path [path].ccol)) ; - for ( ; ; ) - { - PRINT1 ((" column "ID"\n", j)) ; - ASSERT (j == EMPTY || (j >= 0 && j < n)) ; - if (j == Path [path].end) - { - break ; - } - ASSERT (j >= 0 && j < n) ; - j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ; - } -#endif - } - - for (path = 0 ; path < npaths ; path++) - { - p = Path [path].parent ; /* add path to child list of parent */ - if (p != EMPTY) - { - ASSERT (p < npaths) ; - Path [path].next = Path [p].c ; - Path [p].c = path ; - } - } - - path_order = k ; - w_order = 0 ; - for (path = npaths-1 ; path >= 0 ; path--) - { - if (Path [path].order == EMPTY) - { - /* this path is the root of a subtree of Tbar */ - PRINT1 (("Root path "ID"\n", path)) ; - ASSERT (path >= k) ; - dfs (Path, k, path, &path_order, &w_order, 0, npaths) ; - } - } - ASSERT (path_order == npaths) ; - ASSERT (w_order == k) ; - - /* reorder the paths */ - for (path = 0 ; path < npaths ; path++) - { - /* old order is path, new order is Path [path].order */ - OrderedPath [Path [path].order] = Path [path] ; - } - -#ifndef NDEBUG - for (path = 0 ; path < npaths ; path++) - { - PRINT1 (("Ordered Path "ID": start "ID" end "ID" wfirst "ID" rank " - ""ID" ccol "ID"\n", path, OrderedPath [path].start, - OrderedPath [path].end, OrderedPath [path].wfirst, - OrderedPath [path].rank, OrderedPath [path].ccol)) ; - if (path < k) - { - ASSERT (OrderedPath [path].ccol >= 0) ; - } - else - { - ASSERT (OrderedPath [path].ccol == EMPTY) ; - } - } -#endif - - /* ------------------------------------------------------------------ */ - /* numeric update/downdate for all paths */ - /* ------------------------------------------------------------------ */ - - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ; - - switch (wdim) - { - case 1: - updown_1_r (update, C, k, L, W, OrderedPath, npaths, mask, - maskmark, Common) ; - break ; - case 2: - updown_2_r (update, C, k, L, W, OrderedPath, npaths, mask, - maskmark, Common) ; - break ; - case 4: - updown_4_r (update, C, k, L, W, OrderedPath, npaths, mask, - maskmark, Common) ; - break ; - case 8: - updown_8_r (update, C, k, L, W, OrderedPath, npaths, mask, - maskmark, Common) ; - break ; - } - - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ; + case CHOLMOD_SINGLE: + ok = rs_cholmod_updown_worker (k, update, C, colmark, mask, + maskmark, L, X, DeltaB, Common) ; + break ; + + case CHOLMOD_DOUBLE: + ok = rd_cholmod_updown_worker (k, update, C, colmark, mask, + maskmark, L, X, DeltaB, Common) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* update/downdate the forward solve */ - /* ---------------------------------------------------------------------- */ - - if (do_solve) - { - /* We now have DeltaB += Lold (:,j) * X (j) for all columns j in union - * of all paths seen during the entire rank-cncol update/downdate. For - * each j in path, do DeltaB -= Lnew (:,j)*DeltaB(j) - * in topological order. */ - -#ifndef NDEBUG - PRINT1 (("\ndo_solve, DeltaB + Lold(:,Path)*X(Path):\n")) ; - for (i = 0 ; i < n ; i++) - { - PRINT1 (("do_solve: "ID" %30.20e\n", i, Nx [i])) ; - } -#endif - - /* Note that the downdate, if it deleted entries, would need to compute - * the Stack prior to doing any downdates. */ + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- - /* find the union of all the paths in the new L */ - top = n ; /* "top" is stack pointer, not a row or column index */ - for (ccol = 0 ; ccol < cncol ; ccol++) - { - - /* -------------------------------------------------------------- */ - /* j = first row index of C (:,ccol) */ - /* -------------------------------------------------------------- */ - - pp1 = Cp [ccol] ; - pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; - if (pp2 > pp1) - { - /* Column ccol of C has at least one entry. */ - j = Ci [pp1] ; - } - else - { - /* Column ccol of C is empty */ - j = n-1 ; - } - PRINT1 (("\ndo_solve: ccol= "ID"\n", ccol)) ; - ASSERT (j >= 0 && j < n) ; - len = 0 ; - - /* -------------------------------------------------------------- */ - /* find the new rowmark */ - /* -------------------------------------------------------------- */ - - /* Each column of C can redefine the region of L that takes part in - * the update/downdate of the triangular solve Lx=b. If - * i = colmark [ccol] for column C(:,ccol), then i = rowmark [j] is - * redefined for all columns along the path modified by C(:,ccol). - * If more than one column modifies any given column j of L, then - * the rowmark of j is determined by the colmark of the least- - * numbered column that affects column j. That is, if both - * C(:,ccol1) and C(:,ccol2) affect column j of L, then - * rowmark [j] = colmark [MIN (ccol1, ccol2)]. - * - * rowmark [j] is not modified if rowmark or colmark are NULL, - * or if colmark [ccol] is EMPTY. - */ - - botrow = (use_colmark) ? (colmark [ccol]) : EMPTY ; - - /* -------------------------------------------------------------- */ - /* traverse from j towards root, stopping if node already visited */ - /* -------------------------------------------------------------- */ - - while (j != EMPTY && Flag [j] < mark) - { - PRINT1 (("do_solve: subpath j= "ID"\n", j)) ; - ASSERT (j >= 0 && j < n) ; - Stack [len++] = j ; /* place j on the stack */ - Flag [j] = mark ; /* flag j as visited */ - - /* if using colmark, mark column j with botrow */ - ASSERT (Li [Lp [j]] == j) ; /* diagonal is always present */ - if (use_colmark) - { - Li [Lp [j]] = botrow ; /* use the space for botrow */ - } - - /* go up the tree, to the parent of j */ - j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ; - } - - /* -------------------------------------------------------------- */ - /* move the path down to the bottom of the stack */ - /* -------------------------------------------------------------- */ - - ASSERT (len <= top) ; - while (len > 0) - { - Stack [--top] = Stack [--len] ; - } - } - -#ifndef NDEBUG - /* Union of paths now in Stack [top..n-1] in topological order */ - PRINT1 (("\nTopological order:\n")) ; - for (i = top ; i < n ; i++) - { - PRINT1 (("column "ID" in full path\n", Stack [i])) ; - } -#endif - - /* Do the forward solve for the full path part of L */ - for (m = top ; m < n ; m++) - { - j = Stack [m] ; - ASSERT (j >= 0 && j < n) ; - PRINT1 (("do_solve: path j= "ID"\n", j)) ; - p1 = Lp [j] ; - lnz = Lnz [j] ; - p2 = p1 + lnz ; - xj = Nx [j] ; - - /* copy new solution onto old one, for all cols in full path */ - Xx [j] = xj ; - Nx [j] = 0. ; - - /* DeltaB -= Lnew (j+1:botrow-1,j) * deltab(j) */ - if (use_colmark) - { - botrow = Li [p1] ; /* get botrow */ - Li [p1] = j ; /* restore diagonal entry */ - for (p = p1 + 1 ; p < p2 ; p++) - { - i = Li [p] ; - if (i >= botrow) break ; - Nx [i] -= Lx [p] * xj ; - } - } - else - { - for (p = p1 + 1 ; p < p2 ; p++) - { - Nx [Li [p]] -= Lx [p] * xj ; - } - } - } - - /* clear the Flag */ - mark = CHOLMOD(clear_flag) (Common) ; - } - - /* ---------------------------------------------------------------------- */ - /* successful update/downdate */ - /* ---------------------------------------------------------------------- */ - - Common->modfl = fl ; - DEBUG (for (j = 0 ; j < n ; j++) ASSERT (IMPLIES (do_solve, Nx[j] == 0.))) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, TRUE, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; DEBUG (CHOLMOD(dump_factor) (L, "output L for updown", Common)) ; - return (TRUE) ; + return (ok) ; } + #endif #endif + diff --git a/CHOLMOD/Modify/t_cholmod_rowadd_worker.c b/CHOLMOD/Modify/t_cholmod_rowadd_worker.c new file mode 100644 index 0000000000..b0486cb549 --- /dev/null +++ b/CHOLMOD/Modify/t_cholmod_rowadd_worker.c @@ -0,0 +1,505 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Modify/t_cholmod_rowadd_worker: add row/col to an LDL' factorization +//------------------------------------------------------------------------------ + +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, +// and William W. Hager. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static int TEMPLATE (cholmod_rowadd_worker) +( + // input: + Int k, // row/column index to add + cholmod_sparse *R, // row/column of matrix to factorize (n-by-1) + Real bk [2], // kth entry of the right hand side, b + Int *colmark, // Int array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int n = L->n ; + Int *Rj = R->i ; + Int *Rp = R->p ; + Int *Rnz = R->nz ; + Real *Rx = R->x ; + Int rnz = (R->packed) ? (Rp [1]) : (Rnz [0]) ; + bool do_solve = (X != NULL) && (DeltaB != NULL) ; + Real *Xx = NULL ; + Real *Nx = NULL ; + if (do_solve) + { + Xx = X->x ; + Nx = DeltaB->x ; + } + else + { + Xx = NULL ; + Nx = NULL ; + } + + // inputs, not modified on output: + Int *Lp = L->p ; // size n+1. input, not modified on output + + // outputs, contents defined on input for incremental case only: + Int *Lnz = L->nz ; // size n + Int *Li = L->i ; // size L->nzmax. Can change in size. + Real *Lx = L->x ; // size L->nzmax. Can change in size. + Int *Lnext = L->next ; // size n+2 + + ASSERT (L->nz != NULL) ; + + PRINT1 (("rowadd:\n")) ; + double fl = 0 ; + + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Int *Flag = Common->Flag ; // size n + Real *W = Common->Xwork ; // size n + Real *Cx = W + n ; // size n (use 2nd column of Xwork for C) + Int *Stack = Common->Iwork ; // size n, also in cholmod_updown + Int *Ci = Stack + n ; // size n + // NOTE: cholmod_updown uses Iwork [0..n-1] as Stack as well + + Int mark = Common->mark ; + + // copy Rj/Rx into W/Ci + for (Int p = 0 ; p < rnz ; p++) + { + Int i = Rj [p] ; + ASSERT (i >= 0 && i < n) ; + W [i] = Rx [p] ; + Ci [p] = i ; + } + + // At this point, W [Ci [0..rnz-1]] holds the sparse vector to add + // The nonzero pattern of column W is held in Ci (it may be unsorted). + + //-------------------------------------------------------------------------- + // symbolic factorization to get pattern of kth row of L + //-------------------------------------------------------------------------- + + DEBUG (for (Int p = 0 ; p < rnz ; p++) + PRINT1 (("C ("ID",%g)\n", Ci [p], W [Ci [p]]))) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; + + // flag the diagonal + Flag [k] = mark ; + + // find the union of all the paths + Int top = n ; + Int lnz = 0 ; // # of nonzeros in column k of L, excluding diagonal + for (Int p = 0 ; p < rnz ; p++) + { + Int i = Ci [p] ; + + if (i < k) + { + + // walk from i = entry in Ci to root (and stop if i marked) + PRINT2 (("\nwalk from i = "ID" towards k = "ID"\n", i, k)) ; + Int len = 0 ; + + // walk up tree, but stop if we go below the diagonal + while (i < k && i != EMPTY && Flag [i] < mark) + { + PRINT2 ((" Add "ID" to path\n", i)) ; + ASSERT (i >= 0 && i < k) ; + Stack [len++] = i ; // place i on the stack + Flag [i] = mark ; // mark i as visited + // parent is the first entry in the column after the diagonal + ASSERT (Lnz [i] > 0) ; + Int parent = (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY ; + PRINT2 ((" parent: "ID"\n", parent)) ; + i = parent ; // go up the tree + } + ASSERT (len <= top) ; + + // move the path down to the bottom of the stack + // this shifts Stack [0..len-1] down to [ ... oldtop-1] + while (len > 0) + { + Stack [--top] = Stack [--len] ; + } + } + else if (i > k) + { + // prune the diagonal and upper triangular entries from Ci + Ci [lnz++] = i ; + Flag [i] = mark ; + } + } + + #ifndef NDEBUG + PRINT1 (("length of S after prune: "ID"\n", lnz)) ; + for (Int p = 0 ; p < lnz ; p++) + { + PRINT1 (("After prune Ci ["ID"] = "ID"\n", p, Ci [p])) ; + ASSERT (Ci [p] > k) ; + } + #endif + + //-------------------------------------------------------------------------- + // ensure each column of L has enough space to grow + //-------------------------------------------------------------------------- + + for (Int kk = top ; kk < n ; kk++) + { + // could skip this if we knew column j already included row k + Int j = Stack [kk] ; + if (Lp [j] + Lnz [j] >= Lp [Lnext [j]]) + { + PRINT1 (("Col "ID" realloc, old Lnz "ID"\n", j, Lnz [j])) ; + if (!CHOLMOD(reallocate_column) (j, Lnz [j] + 1, L, Common)) + { + // out of memory, L is now simplicial symbolic + CLEAR_FLAG (Common) ; + ASSERT (check_flag (Common)) ; + for (Int i = 0 ; i < n ; i++) + { + W [i] = 0 ; + } + return (FALSE) ; + } + // L->i and L->x may have moved + Li = L->i ; + Lx = L->x ; + } + ASSERT (Lp [j] + Lnz [j] < Lp [Lnext [j]] + || (Lp [Lnext [j]] - Lp [j] == n-j)) ; + } + + //-------------------------------------------------------------------------- + // compute kth row of L and store in column form + //-------------------------------------------------------------------------- + + // solve L (1:k-1, 1:k-1) * y (1:k-1) = b (1:k-1) + // where b (1:k) is in W and Ci + + // L (k, 1:k-1) = y (1:k-1) ./ D (1:k-1) + // D (k) = B (k,k) - L (k, 1:k-1) * y (1:k-1) + + PRINT2 (("\nForward solve: "ID" to "ID"\n", top, n)) ; + ASSERT (Lnz [k] >= 1 && Li [Lp [k]] == k) ; + DEBUG (for (Int i = top ; i < n ; i++) + PRINT2 ((" Path: "ID"\n", Stack [i]))) ; + + Real dk = W [k] ; + W [k] = 0.0 ; + + // if do_solve: compute x (k) = b (k) - L (k, 1:k-1) * x (1:k-1) + Real xk = bk [0] ; + PRINT2 (("B [k] = %g\n", xk)) ; + + for (Int kk = top ; kk < n ; kk++) + { + Int j = Stack [kk] ; + Int i = j ; + PRINT2 (("Forward solve col j = "ID":\n", j)) ; + ASSERT (j >= 0 && j < k) ; + + // forward solve using L (j+1:k-1,j) + Real yj = W [j] ; + W [j] = 0.0 ; + Int p = Lp [j] ; + Int pend = p + Lnz [j] ; + ASSERT (Lnz [j] > 0) ; + Real dj = Lx [p++] ; + for ( ; p < pend ; p++) + { + i = Li [p] ; + PRINT2 ((" row "ID"\n", i)) ; + ASSERT (i > j) ; + ASSERT (i < n) ; + // stop at row k + if (i >= k) + { + break ; + } + W [i] -= Lx [p] * yj ; + } + + // each iteration of the above for loop did 2 flops, and 3 flops + // are done below. so: fl += 2 * (Lp [j] - p - 1) + 3 becomes: + fl += 2 * (Lp [j] - p) + 1 ; + + // scale L (k,1:k-1) and compute dot product for D (k,k) + Real l_kj = yj / dj ; + dk -= l_kj * yj ; + + // compute dot product for X(k) + if (do_solve) + { + xk -= l_kj * Xx [j] ; + } + + // store l_kj in the jth column of L + // and shift the rest of the column down + + Int li = k ; + Real lx = l_kj ; + + if (i == k) + { + // no need to modify the nonzero pattern of L, since it already + // contains row index k. + ASSERT (Li [p] == k) ; + Lx [p] = l_kj ; + + for (p++ ; p < pend ; p++) + { + i = Li [p] ; + Real l_ij = Lx [p] ; + ASSERT (i > k && i < n) ; + PRINT2 ((" apply to row "ID" of column k of L\n", i)) ; + + // add to the pattern of the kth column of L + if (Flag [i] < mark) + { + PRINT2 ((" add Ci["ID"] = "ID"\n", lnz, i)) ; + ASSERT (i > k) ; + Ci [lnz++] = i ; + Flag [i] = mark ; + } + + // apply the update to the kth column of L + // yj is equal to l_kj * d_j + W [i] -= l_ij * yj ; + } + + } + else + { + + PRINT2 (("Shift col j = "ID", apply saxpy to col k of L\n", j)) ; + for ( ; p < pend ; p++) + { + // swap (Li [p],Lx [p]) with (li,lx) + i = Li [p] ; + Real l_ij = Lx [p] ; + Li [p] = li ; + Lx [p] = lx ; + li = i ; + lx = l_ij ; + ASSERT (i > k && i < n) ; + PRINT2 ((" apply to row "ID" of column k of L\n", i)) ; + + // add to the pattern of the kth column of L + if (Flag [i] < mark) + { + PRINT2 ((" add Ci["ID"] = "ID"\n", lnz, i)) ; + ASSERT (i > k) ; + Ci [lnz++] = i ; + Flag [i] = mark ; + } + + // apply the update to the kth column of L + // yj is equal to l_kj * d_j + + W [i] -= l_ij * yj ; + } + + // store the last value in the jth column of L + Li [p] = li ; + Lx [p] = lx ; + Lnz [j]++ ; + } + } + + //-------------------------------------------------------------------------- + // merge C with the pattern of the existing column of L + //-------------------------------------------------------------------------- + + // This column should be zero, but it may contain explicit zero entries. + // These entries should be kept, not dropped. + Int p = Lp [k] ; + Int pend = p + Lnz [k] ; + for (p++ ; p < pend ; p++) + { + Int i = Li [p] ; + // add to the pattern of the kth column of L + if (Flag [i] < mark) + { + PRINT2 ((" add Ci["ID"] = "ID" from existing col k\n", lnz, i)) ; + ASSERT (i > k) ; + Ci [lnz++] = i ; + Flag [i] = mark ; + } + } + + //-------------------------------------------------------------------------- + // update X(k) + //-------------------------------------------------------------------------- + + if (do_solve) + { + Xx [k] = xk ; + PRINT2 (("Xx [k] = %g\n", Xx [k])) ; + } + + //-------------------------------------------------------------------------- + // ensure abs (dk) >= dbound/sbound, if given + //-------------------------------------------------------------------------- + + #ifdef DOUBLE + dk = (Common->dbound > 0) ? (CHOLMOD(dbound) (dk, Common)) : dk ; + #else + dk = (Common->sbound > 0) ? (CHOLMOD(sbound) (dk, Common)) : dk ; + #endif + + PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ; + + //-------------------------------------------------------------------------- + // store the kth column of L + //-------------------------------------------------------------------------- + + // ensure the new column of L has enough space + if (Lp [k] + lnz + 1 > Lp [Lnext [k]]) + { + PRINT1 (("New Col "ID" realloc, old Lnz "ID"\n", k, Lnz [k])) ; + if (!CHOLMOD(reallocate_column) (k, lnz + 1, L, Common)) + { + // out of memory, L is now simplicial symbolic + CHOLMOD(clear_flag) (Common) ; + for (Int i = 0 ; i < n ; i++) + { + W [i] = 0 ; + } + return (FALSE) ; + } + // L->i and L->x may have moved + Li = L->i ; + Lx = L->x ; + } + ASSERT (Lp [k] + lnz + 1 <= Lp [Lnext [k]]) ; + + #ifndef NDEBUG + PRINT2 (("\nPrior to sort: lnz "ID" (excluding diagonal)\n", lnz)) ; + for (Int kk = 0 ; kk < lnz ; kk++) + { + Int i = Ci [kk] ; + PRINT2 (("L ["ID"] kept: "ID" %e\n", kk, i, W [i] / dk)) ; + } + #endif + + // sort Ci + qsort (Ci, lnz, sizeof (Int), (int (*) (const void *, const void *)) icomp); + + // store the kth column of L + DEBUG (Int lastrow = k) ; + p = Lp [k] ; + Lx [p++] = dk ; + Lnz [k] = lnz + 1 ; + fl += lnz ; + for (Int kk = 0 ; kk < lnz ; kk++, p++) + { + Int i = Ci [kk] ; + PRINT2 (("L ["ID"] after sort: "ID", %e\n", kk, i, W [i] / dk)) ; + ASSERT (i > lastrow) ; + Li [p] = i ; + Lx [p] = W [i] / dk ; + W [i] = 0.0 ; + DEBUG (lastrow = i) ; + } + + // compute DeltaB for updown (in DeltaB) + if (do_solve) + { + Int p = Lp [k] ; + Int pend = p + Lnz [k] ; + for (p++ ; p < pend ; p++) + { + ASSERT (Li [p] > k) ; + Nx [Li [p]] -= Lx [p] * xk ; + } + } + + // clear the flag for the update + mark = CHOLMOD(clear_flag) (Common) ; + + // workspaces are now cleared + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, R->dtype, Common)) ; + + //-------------------------------------------------------------------------- + // update/downdate + //-------------------------------------------------------------------------- + + // update or downdate L (k+1:n, k+1:n) with the vector + // C = L (:,k) * sqrt (abs (D [k])). + // Do a numeric update if D[k] < 0, numeric downdate otherwise. + + int ok = TRUE ; + Common->modfl = 0 ; + + PRINT1 (("rowadd update lnz = "ID"\n", lnz)) ; + if (lnz > 0) + { + bool do_update = (dk < 0) ; + if (do_update) + { + dk = -dk ; + } + Real sqrt_dk = sqrt (dk) ; + Int p = Lp [k] + 1 ; + for (Int kk = 0 ; kk < lnz ; kk++, p++) + { + Cx [kk] = Lx [p] * sqrt_dk ; + } + fl += lnz + 1 ; + + // create a n-by-1 sparse matrix to hold the single column + cholmod_sparse *C, Cmatrix ; + Int Cp [2] ; + C = &Cmatrix ; + C->nrow = n ; + C->ncol = 1 ; + C->nzmax = lnz ; + C->sorted = TRUE ; + C->packed = TRUE ; + C->p = Cp ; + C->i = Ci ; + C->x = Cx ; + C->nz = NULL ; + C->itype = L->itype ; + C->xtype = L->xtype ; + C->dtype = L->dtype ; + C->z = NULL ; + C->stype = 0 ; + + Cp [0] = 0 ; + Cp [1] = lnz ; + + // numeric downdate if dk > 0, and optional Lx=b change + // workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) + ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark, + L, X, DeltaB, Common) ; + + // clear workspace + for (Int kk = 0 ; kk < lnz ; kk++) + { + Cx [kk] = 0 ; + } + } + + Common->modfl += fl ; + return (ok) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Modify/t_cholmod_rowdel_worker.c b/CHOLMOD/Modify/t_cholmod_rowdel_worker.c new file mode 100644 index 0000000000..a30453e897 --- /dev/null +++ b/CHOLMOD/Modify/t_cholmod_rowdel_worker.c @@ -0,0 +1,311 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Modify/t_cholmod_rowdel_worker: delete row/col from LDL' +//------------------------------------------------------------------------------ + +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, +// and William W. Hager. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +static int TEMPLATE (cholmod_rowdel_worker) +( + // input: + Int k, // row/column index to delete + cholmod_sparse *R, // NULL, or the nonzero pattern of kth row of L + Real yk [2], // kth entry in the solution to A*y=b + Int *colmark, // Int array of size 1. See cholmod_updown.c + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int n = L->n ; + Real dk, xk, dj ; + Real *Xx, *Nx ; + Int *Rj, *Rp ; + Int j, p, pend, kk, lnz, left, right, middle, i, klast, given_row, rnz ; + + if (R == NULL) + { + Rj = NULL ; + rnz = EMPTY ; + } + else + { + Rj = R->i ; + Rp = R->p ; + rnz = Rp [1] ; + } + + bool do_solve = (X != NULL) && (DeltaB != NULL) ; + if (do_solve) + { + Xx = X->x ; + Nx = DeltaB->x ; + } + else + { + Xx = NULL ; + Nx = NULL ; + } + + // inputs, not modified on output: + Int *Lp = L->p ; // size n+1 + + // outputs, contents defined on input for incremental case only: + Int *Lnz = L->nz ; // size n + Int *Li = L->i ; // size L->nzmax. Can change in size. + Real *Lx = L->x ; // size L->nzmax. Can change in size. + + ASSERT (L->nz != NULL) ; + + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Real *W = Common->Xwork ; // size n, used only in cholmod_updown + Real *Cx = W + n ; // use 2nd column of Xwork for C (size n) + Int *Iwork = Common->Iwork ; + Int *Ci = Iwork + n ; // size n + // NOTE: cholmod_updown uses Iwork [0..n-1] as Stack + + //-------------------------------------------------------------------------- + // prune row k from all columns of L + //-------------------------------------------------------------------------- + + given_row = (rnz >= 0) ; + klast = given_row ? rnz : k ; + PRINT2 (("given_row "ID"\n", given_row)) ; + + for (kk = 0 ; kk < klast ; kk++) + { + // either search j = 0:k-1 or j = Rj [0:rnz-1] + j = given_row ? (Rj [kk]) : (kk) ; + + if (j < 0 || j >= k) + { + ERROR (CHOLMOD_INVALID, "R invalid") ; + return (FALSE) ; + } + + PRINT2 (("Prune col j = "ID":\n", j)) ; + + lnz = Lnz [j] ; + dj = Lx [Lp [j]] ; + ASSERT (Lnz [j] > 0 && Li [Lp [j]] == j) ; + + if (lnz > 1) + { + left = Lp [j] ; + pend = left + lnz ; + right = pend - 1 ; + + i = Li [right] ; + + if (i < k) + { + // row k is not in column j + continue ; + } + else if (i == k) + { + // k is the last row index in this column (quick delete) + if (do_solve) + { + Xx [j] -= yk [0] * dj * Lx [right] ; + } + Lx [right] = 0 ; + } + else + { + // binary search for row k in column j + PRINT2 (("\nBinary search: lnz "ID" k = "ID"\n", lnz, k)) ; + while (left < right) + { + middle = (left + right) / 2 ; + PRINT2 (("left "ID" right "ID" middle "ID": ["ID" "ID"" + ""ID"]\n", left, right, middle, + Li [left], Li [middle], Li [right])) ; + if (k > Li [middle]) + { + left = middle + 1 ; + } + else + { + right = middle ; + } + } + ASSERT (left >= Lp [j] && left < pend) ; + + #ifndef NDEBUG + // brute force, linear-time search + { + Int p3 = Lp [j] ; + i = EMPTY ; + PRINT2 (("Brute force:\n")) ; + for ( ; p3 < pend ; p3++) + { + i = Li [p3] ; + PRINT2 (("p "ID" ["ID"]\n", p3, i)) ; + if (i >= k) + { + break ; + } + } + if (i == k) + { + ASSERT (k == Li [p3]) ; + ASSERT (p3 == left) ; + } + } + #endif + + if (k == Li [left]) + { + if (do_solve) + { + Xx [j] -= yk [0] * dj * Lx [left] ; + } + // found row k in column j. Prune it from the column. + Lx [left] = 0 ; + } + } + } + } + + #ifndef NDEBUG + // ensure that row k has been deleted from the matrix L + for (j = 0 ; j < k ; j++) + { + Int lasti ; + lasti = EMPTY ; + p = Lp [j] ; + pend = p + Lnz [j] ; + // look for row k in column j + PRINT1 (("Pruned column "ID"\n", j)) ; + for ( ; p < pend ; p++) + { + i = Li [p] ; + PRINT2 ((" "ID"", i)) ; + PRINT2 ((" %g\n", Lx [p])) ; + ASSERT (IMPLIES (i == k, Lx [p] == 0)) ; + ASSERT (i > lasti) ; + lasti = i ; + } + PRINT1 (("\n")) ; + } + #endif + + //-------------------------------------------------------------------------- + // set diagonal and clear column k of L + //-------------------------------------------------------------------------- + + lnz = Lnz [k] - 1 ; + ASSERT (Lnz [k] > 0) ; + + //-------------------------------------------------------------------------- + // update/downdate + //-------------------------------------------------------------------------- + + // update or downdate L (k+1:n, k+1:n) with the vector + // C = L (:,k) * sqrt (abs (D [k])) + // Do a numeric update if D[k] > 0, numeric downdate otherwise. + + PRINT1 (("rowdel downdate lnz = "ID"\n", lnz)) ; + + // store the new unit diagonal + p = Lp [k] ; + pend = p + lnz + 1 ; + dk = Lx [p] ; + Lx [p++] = 1 ; + PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ; + int ok = TRUE ; + double fl = 0 ; + + if (lnz > 0) + { + // compute DeltaB for updown (in DeltaB) + if (do_solve) + { + xk = Xx [k] - yk [0] * dk ; + for ( ; p < pend ; p++) + { + Nx [Li [p]] += Lx [p] * xk ; + } + } + + bool do_update = (dk > 0) ; + if (!do_update) + { + dk = -dk ; + } + Real sqrt_dk = sqrt (dk) ; + p = Lp [k] + 1 ; + for (kk = 0 ; kk < lnz ; kk++, p++) + { + Ci [kk] = Li [p] ; + Cx [kk] = Lx [p] * sqrt_dk ; + Lx [p] = 0 ; // clear column k + } + fl = lnz + 1 ; + + // create a n-by-1 sparse matrix to hold the single column + cholmod_sparse *C, Cmatrix ; + Int Cp [2] ; + C = &Cmatrix ; + C->nrow = n ; + C->ncol = 1 ; + C->nzmax = lnz ; + C->sorted = TRUE ; + C->packed = TRUE ; + C->p = Cp ; + C->i = Ci ; + C->x = Cx ; + C->nz = NULL ; + C->itype = L->itype ; + C->xtype = L->xtype ; + C->dtype = L->dtype ; + C->z = NULL ; + C->stype = 0 ; + + Cp [0] = 0 ; + Cp [1] = lnz ; + + // numeric update if dk > 0, and with Lx=b change + // workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) + ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark, + L, X, DeltaB, Common) ; + + // clear workspace + for (kk = 0 ; kk < lnz ; kk++) + { + Cx [kk] = 0 ; + } + } + + Common->modfl += fl ; + + if (do_solve) + { + // kth equation becomes identity, so X(k) is now Y(k) + Xx [k] = yk [0] ; + } + + return (ok) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Modify/t_cholmod_updown.c b/CHOLMOD/Modify/t_cholmod_updown.c deleted file mode 100644 index 40328ba957..0000000000 --- a/CHOLMOD/Modify/t_cholmod_updown.c +++ /dev/null @@ -1,212 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Modify/t_cholmod_updown: template for cholmod_updown -//------------------------------------------------------------------------------ - -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, -// and William W. Hager. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Updates/downdates the LDL' factorization, by computing a new factorization of - * - * Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C' - * - * This file is not compiled separately. It is included into - * cholmod_updown.c. There are no user-callable routines in this file. - * - * The next include statements, below, create the numerical update/downdate - * kernels from t_cholmod_updown_numkr.c. There are 4 compiled versions of this - * file, one for each value of WDIM in the set 1, 2, 4, and 8. Each calls - * multiple versions of t_cholmod_updown_numkr; the number of versions of each - * is equal to WDIM. Each t_cholmod_updown_numkr version is included as a - * static function within its t_cholmod_updown.c caller routine. Thus: - * - * t*_updown.c creates these versions of t_cholmod_updown_numkr.c: - * --------- --------------------------------------------------- - * - * updown_1_r updown_1_1 - * - * updown_2_r updown_2_1 updown_2_2 - * - * updown_4_r updown_4_1 updown_4_2 updown_4_3 updown_4_4 - * - * updown_8_r updown_8_1 updown_8_2 updown_8_3 updown_8_4 - * updown_8_5 updown_8_6 updown_8_7 updown_8_8 - * - * workspace: Xwork (nrow*wdim) - */ - -/* ========================================================================== */ -/* === routines for numeric update/downdate along one path ================== */ -/* ========================================================================== */ - -#undef FORM_NAME -#undef NUMERIC - -#define FORM_NAME(k,rank) updown_ ## k ## _ ## rank -#define NUMERIC(k,rank) FORM_NAME(k,rank) - -#define RANK 1 -#include "t_cholmod_updown_numkr.c" - -#if WDIM >= 2 -#define RANK 2 -#include "t_cholmod_updown_numkr.c" -#endif - -#if WDIM >= 4 -#define RANK 3 -#include "t_cholmod_updown_numkr.c" -#define RANK 4 -#include "t_cholmod_updown_numkr.c" -#endif - -#if WDIM == 8 -#define RANK 5 -#include "t_cholmod_updown_numkr.c" -#define RANK 6 -#include "t_cholmod_updown_numkr.c" -#define RANK 7 -#include "t_cholmod_updown_numkr.c" -#define RANK 8 -#include "t_cholmod_updown_numkr.c" -#endif - - -/* ========================================================================== */ -/* === numeric update/downdate for all paths ================================ */ -/* ========================================================================== */ - -static void NUMERIC (WDIM, r) -( - int update, /* TRUE for update, FALSE for downdate */ - cholmod_sparse *C, /* in packed or unpacked, and sorted form */ - /* no empty columns */ - Int rank, /* rank of the update/downdate */ - cholmod_factor *L, /* with unit diagonal (diagonal not stored) */ - /* temporary workspaces: */ - double W [ ], /* n-by-WDIM dense matrix, initially zero */ - Path_type Path [ ], - Int npaths, - Int mask [ ], /* size n */ - Int maskmark, - cholmod_common *Common -) -{ - double Alpha [8] ; - double *Cx, *Wpath, *W1, *a ; - Int i, j, p, ccol, pend, wfirst, e, path, packed ; - Int *Ci, *Cp, *Cnz ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - Ci = C->i ; - Cx = C->x ; - Cp = C->p ; - Cnz = C->nz ; - packed = C->packed ; - ASSERT (IMPLIES (!packed, Cnz != NULL)) ; - ASSERT (L->n == C->nrow) ; - DEBUG (CHOLMOD(dump_real) ("num_d: in W:", W, WDIM, L->n, FALSE, 1,Common)); - - /* ---------------------------------------------------------------------- */ - /* scatter C into W */ - /* ---------------------------------------------------------------------- */ - - for (path = 0 ; path < rank ; path++) - { - /* W (:, path) = C (:, Path [path].col) */ - ccol = Path [path].ccol ; - Wpath = W + path ; - PRINT1 (("Ordered Columns [path = "ID"] = "ID"\n", path, ccol)) ; - p = Cp [ccol] ; - pend = (packed) ? (Cp [ccol+1]) : (p + Cnz [ccol]) ; - /* column C can be empty */ - for ( ; p < pend ; p++) - { - i = Ci [p] ; - ASSERT (i >= 0 && i < (Int) (C->nrow)) ; - if (mask == NULL || mask [i] < maskmark) - { - Wpath [WDIM * i] = Cx [p] ; - } - PRINT1 ((" row "ID" : %g mask "ID"\n", i, Cx [p], - (mask) ? mask [i] : 0)) ; - } - Alpha [path] = 1.0 ; - } - DEBUG (CHOLMOD(dump_real) ("num_d: W:", W, WDIM, L->n, FALSE, 1,Common)) ; - - /* ---------------------------------------------------------------------- */ - /* numeric update/downdate of the paths */ - /* ---------------------------------------------------------------------- */ - - /* for each disjoint subpath in Tbar in DFS order do */ - for (path = rank ; path < npaths ; path++) - { - - /* determine which columns of W to use */ - wfirst = Path [path].wfirst ; - e = Path [path].end ; - j = Path [path].start ; - ASSERT (e >= 0 && e < (Int) (L->n)) ; - ASSERT (j >= 0 && j < (Int) (L->n)) ; - - W1 = W + wfirst ; /* pointer to row 0, column wfirst of W */ - a = Alpha + wfirst ; /* pointer to Alpha [wfirst] */ - - PRINT1 (("Numerical update/downdate of path "ID"\n", path)) ; - PRINT1 (("start "ID" end "ID" wfirst "ID" rank "ID" ccol "ID"\n", j, e, - wfirst, Path [path].rank, Path [path].ccol)) ; - -#if WDIM == 1 - NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ; -#else - - switch (Path [path].rank) - { - case 1: - NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ; - break ; - -#if WDIM >= 2 - case 2: - NUMERIC (WDIM,2) (update, j, e, a, W1, L, Common) ; - break ; -#endif - -#if WDIM >= 4 - case 3: - NUMERIC (WDIM,3) (update, j, e, a, W1, L, Common) ; - break ; - case 4: - NUMERIC (WDIM,4) (update, j, e, a, W1, L, Common) ; - break ; -#endif - -#if WDIM == 8 - case 5: - NUMERIC (WDIM,5) (update, j, e, a, W1, L, Common) ; - break ; - case 6: - NUMERIC (WDIM,6) (update, j, e, a, W1, L, Common) ; - break ; - case 7: - NUMERIC (WDIM,7) (update, j, e, a, W1, L, Common) ; - break ; - case 8: - NUMERIC (WDIM,8) (update, j, e, a, W1, L, Common) ; - break ; -#endif - - } -#endif - - } -} - -/* prepare for the next inclusion of this file in cholmod_updown.c */ -#undef WDIM diff --git a/CHOLMOD/Modify/t_cholmod_updown_numkr.c b/CHOLMOD/Modify/t_cholmod_updown_numkr.c index 62c9b75c20..e0f40d3a27 100644 --- a/CHOLMOD/Modify/t_cholmod_updown_numkr.c +++ b/CHOLMOD/Modify/t_cholmod_updown_numkr.c @@ -2,220 +2,202 @@ // CHOLMOD/Modify/t_cholmod_updown_numkr: template for update/downdate //------------------------------------------------------------------------------ -// CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis, +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, // and William W. Hager. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Supernodal numerical update/downdate of rank K = RANK, along a single path. - * This routine operates on a simplicial factor, but operates on adjacent - * columns of L that would fit within a single supernode. "Adjacent" means - * along a single path in the elimination tree; they may or may not be - * adjacent in the matrix L. - * - * external defines: NUMERIC, WDIM, RANK. - * - * WDIM is 1, 2, 4, or 8. RANK can be 1 to WDIM. - * - * A simple method is included (#define SIMPLE). The code works, but is slow. - * It is meant only to illustrate what this routine is doing. - * - * A rank-K update proceeds along a single path, using single-column, dual- - * column, or quad-column updates of L. If a column j and the next column - * in the path (its parent) do not have the same nonzero pattern, a single- - * column update is used. If they do, but the 3rd and 4th column from j do - * not have the same pattern, a dual-column update is used, in which the two - * columns are treated as if they were a single supernode of two columns. If - * there are 4 columns in the path that all have the same nonzero pattern, then - * a quad-column update is used. All three kinds of updates can be used along - * a single path, in a single call to this function. - * - * Single-column update: - * - * When updating a single column of L, each iteration of the for loop, - * below, processes four rows of W (all columns involved) and one column - * of L. Suppose we have a rank-5 update, and columns 2 through 6 of W - * are involved. In this case, W in this routine is a pointer to column - * 2 of the matrix W in the caller. W (in the caller, shown as 'W') is - * held in row-major order, and is 8-by-n (a dense matrix storage format), - * but shown below in column form to match the column of L. Suppose there - * are 13 nonzero entries in column 27 of L, with row indices 27 (the - * diagonal, D), 28, 30, 31, 42, 43, 44, 50, 51, 67, 81, 83, and 84. This - * pattern is held in Li [Lp [27] ... Lp [27 + Lnz [27] - 1], where - * Lnz [27] = 13. The modification of the current column j of L is done - * in the following order. A dot (.) means the entry of W is not accessed. - * - * W0 points to row 27 of W, and G is a 1-by-8 temporary vector. - * - * G[0] G[4] - * G x x x x x . . . - * - * W0 - * | - * v - * 27 . . x x x x x . W0 points to W (27,2) - * - * - * row 'W' W column j = 27 - * | | | of L - * v v v | - * first iteration of for loop: v - * - * 28 . . 1 5 9 13 17 . x - * 30 . . 2 6 10 14 18 . x - * 31 . . 3 7 11 15 19 . x - * 42 . . 4 8 12 16 20 . x - * - * second iteration of for loop: - * - * 43 . . 1 5 9 13 17 . x - * 44 . . 2 6 10 14 18 . x - * 50 . . 3 7 11 15 19 . x - * 51 . . 4 8 12 16 20 . x - * - * third iteration of for loop: - * - * 67 . . 1 5 9 13 17 . x - * 81 . . 2 6 10 14 18 . x - * 83 . . 3 7 11 15 19 . x - * 84 . . 4 8 12 16 20 . x - * - * If the number of offdiagonal nonzeros in column j of L is not divisible - * by 4, then the switch-statement does the work for the first nz % 4 rows. - * - * Dual-column update: - * - * In this case, two columns of L that are adjacent in the path are being - * updated, by 1 to 8 columns of W. Suppose columns j=27 and j=28 are - * adjacent columns in the path (they need not be j and j+1). Two rows - * of G and W are used as coefficients during the update: (G0, G1) and - * (W0, W1). - * - * G0 x x x x x . . . - * G1 x x x x x . . . - * - * 27 . . x x x x x . W0 points to W (27,2) - * 28 . . x x x x x . W1 points to W (28,2) - * - * - * row 'W' W0,W1 column j = 27 - * | | | of L - * v v v | - * | |-- column j = 28 of L - * v v - * update L (j1,j): - * - * 28 . . 1 2 3 4 5 . x - ("-" is not stored in L) - * - * cleanup iteration since length is odd: - * - * 30 . . 1 2 3 4 5 . x x - * - * then each iteration does two rows of both columns of L: - * - * 31 . . 1 3 5 7 9 . x x - * 42 . . 2 4 6 8 10 . x x - * - * 43 . . 1 3 5 7 9 . x x - * 44 . . 2 4 6 8 10 . x x - * - * 50 . . 1 3 5 7 9 . x x - * 51 . . 2 4 6 8 10 . x x - * - * 67 . . 1 3 5 7 9 . x x - * 81 . . 2 4 6 8 10 . x x - * - * 83 . . 1 3 5 7 9 . x x - * 84 . . 2 4 6 8 10 . x x - * - * If the number of offdiagonal nonzeros in column j of L is not even, - * then the cleanup iteration does the work for the first row. - * - * Quad-column update: - * - * In this case, four columns of L that are adjacent in the path are being - * updated, by 1 to 8 columns of W. Suppose columns j=27, 28, 30, and 31 - * are adjacent columns in the path (they need not be j, j+1, ...). Four - * rows of G and W are used as coefficients during the update: (G0 through - * G3) and (W0 through W3). j=27, j1=28, j2=30, and j3=31. - * - * G0 x x x x x . . . - * G1 x x x x x . . . - * G3 x x x x x . . . - * G4 x x x x x . . . - * - * 27 . . x x x x x . W0 points to W (27,2) - * 28 . . x x x x x . W1 points to W (28,2) - * 30 . . x x x x x . W2 points to W (30,2) - * 31 . . x x x x x . W3 points to W (31,2) - * - * - * row 'W' W0,W1,.. column j = 27 - * | | | of L - * v v v | - * | |-- column j = 28 of L - * | | |-- column j = 30 of L - * | | | |-- column j = 31 of L - * v v v v - * update L (j1,j): - * 28 . . 1 2 3 4 5 . x - - - - * - * update L (j2,j): - * 30 . . 1 2 3 4 5 . # x - - (# denotes modified) - * - * update L (j2,j1) - * 30 . . 1 2 3 4 5 . x # - - - * - * update L (j3,j) - * 31 . . 1 2 3 4 5 . # x x - - * - * update L (j3,j1) - * 31 . . 1 2 3 4 5 . x # x - - * - * update L (j3,j2) - * 31 . . 1 2 3 4 5 . x x # - - * - * cleanup iteration since length is odd: - * 42 . . 1 2 3 4 5 . x x x x - * - * - * ----- CHOLMOD v1.1.1 did the following -------------------------------------- - * then each iteration does two rows of all four colummns of L: - * - * 43 . . 1 3 5 7 9 . x x x x - * 44 . . 2 4 6 8 10 . x x x x - * - * 50 . . 1 3 5 7 9 . x x x x - * 51 . . 2 4 6 8 10 . x x x x - * - * 67 . . 1 3 5 7 9 . x x x x - * 81 . . 2 4 6 8 10 . x x x x - * - * 83 . . 1 3 5 7 9 . x x x x - * 84 . . 2 4 6 8 10 . x x x x - * - * ----- CHOLMOD v1.2.0 does the following ------------------------------------- - * then each iteration does one rows of all four colummns of L: - * - * 43 . . 1 2 3 4 5 . x x x x - * 44 . . 1 2 3 4 5 . x x x x - * 50 . . 1 3 5 4 5 . x x x x - * 51 . . 1 2 3 4 5 . x x x x - * 67 . . 1 3 5 4 5 . x x x x - * 81 . . 1 2 3 4 5 . x x x x - * 83 . . 1 3 5 4 5 . x x x x - * 84 . . 1 2 3 4 5 . x x x x - * - * This file is included in t_cholmod_updown.c, only. - * It is not compiled separately. It contains no user-callable routines. - * - * workspace: Xwork (WDIM*nrow) - */ - -/* ========================================================================== */ -/* === loop unrolling macros ================================================ */ -/* ========================================================================== */ +// Supernodal numerical update/downdate of rank K = RANK, along a single path. +// This routine operates on a simplicial factor, but operates on adjacent +// columns of L that would fit within a single supernode. "Adjacent" means +// along a single path in the elimination tree; they may or may not be +// adjacent in the matrix L. +// +// external defines: UPDOWN, WDIM, RANK, and DOUBLE / SINGLE. +// +// WDIM is 1, 2, 4, or 8. RANK can be 1 to WDIM. +// +// A simple method is included (#define SIMPLE). The code works, but is slow. +// It is meant only to illustrate what this routine is doing. +// +// A rank-K update proceeds along a single path, using single-column, dual- +// column, or quad-column updates of L. If a column j and the next column +// in the path (its parent) do not have the same nonzero pattern, a single- +// column update is used. If they do, but the 3rd and 4th column from j do +// not have the same pattern, a dual-column update is used, in which the two +// columns are treated as if they were a single supernode of two columns. If +// there are 4 columns in the path that all have the same nonzero pattern, then +// a quad-column update is used. All three kinds of updates can be used along +// a single path, in a single call to this function. +// +// Single-column update: +// +// When updating a single column of L, each iteration of the for loop, +// below, processes four rows of W (all columns involved) and one column +// of L. Suppose we have a rank-5 update, and columns 2 through 6 of W +// are involved. In this case, W in this routine is a pointer to column +// 2 of the matrix W in the caller. W (in the caller, shown as 'W') is +// held in row-major order, and is 8-by-n (a dense matrix storage format), +// but shown below in column form to match the column of L. Suppose there +// are 13 nonzero entries in column 27 of L, with row indices 27 (the +// diagonal, D), 28, 30, 31, 42, 43, 44, 50, 51, 67, 81, 83, and 84. This +// pattern is held in Li [Lp [27] ... Lp [27 + Lnz [27] - 1], where +// Lnz [27] = 13. The modification of the current column j of L is done +// in the following order. A dot (.) means the entry of W is not accessed. +// +// W0 points to row 27 of W, and G is a 1-by-8 temporary vector. +// +// G[0] G[4] +// G x x x x x . . . +// +// W0 +// | +// v +// 27 . . x x x x x . W0 points to W (27,2) +// +// +// row 'W' W column j = 27 +// | | | of L +// v v v | +// first iteration of for loop: v +// +// 28 . . 1 5 9 13 17 . x +// 30 . . 2 6 10 14 18 . x +// 31 . . 3 7 11 15 19 . x +// 42 . . 4 8 12 16 20 . x +// +// second iteration of for loop: +// +// 43 . . 1 5 9 13 17 . x +// 44 . . 2 6 10 14 18 . x +// 50 . . 3 7 11 15 19 . x +// 51 . . 4 8 12 16 20 . x +// +// third iteration of for loop: +// +// 67 . . 1 5 9 13 17 . x +// 81 . . 2 6 10 14 18 . x +// 83 . . 3 7 11 15 19 . x +// 84 . . 4 8 12 16 20 . x +// +// If the number of offdiagonal nonzeros in column j of L is not divisible +// by 4, then the switch-statement does the work for the first nz % 4 rows. +// +// Dual-column update: +// +// In this case, two columns of L that are adjacent in the path are being +// updated, by 1 to 8 columns of W. Suppose columns j=27 and j=28 are +// adjacent columns in the path (they need not be j and j+1). Two rows +// of G and W are used as coefficients during the update: (G0, G1) and +// (W0, W1). +// +// G0 x x x x x . . . +// G1 x x x x x . . . +// +// 27 . . x x x x x . W0 points to W (27,2) +// 28 . . x x x x x . W1 points to W (28,2) +// +// +// row 'W' W0,W1 column j = 27 +// | | | of L +// v v v | +// | |-- column j = 28 of L +// v v +// update L (j1,j): +// +// 28 . . 1 2 3 4 5 . x - ("-" is not stored in L) +// +// cleanup iteration since length is odd: +// +// 30 . . 1 2 3 4 5 . x x +// +// then each iteration does two rows of both columns of L: +// +// 31 . . 1 3 5 7 9 . x x +// 42 . . 2 4 6 8 10 . x x +// +// 43 . . 1 3 5 7 9 . x x +// 44 . . 2 4 6 8 10 . x x +// +// 50 . . 1 3 5 7 9 . x x +// 51 . . 2 4 6 8 10 . x x +// +// 67 . . 1 3 5 7 9 . x x +// 81 . . 2 4 6 8 10 . x x +// +// 83 . . 1 3 5 7 9 . x x +// 84 . . 2 4 6 8 10 . x x +// +// If the number of offdiagonal nonzeros in column j of L is not even, +// then the cleanup iteration does the work for the first row. +// +// Quad-column update: +// +// In this case, four columns of L that are adjacent in the path are being +// updated, by 1 to 8 columns of W. Suppose columns j=27, 28, 30, and 31 +// are adjacent columns in the path (they need not be j, j+1, ...). Four +// rows of G and W are used as coefficients during the update: (G0 through +// G3) and (W0 through W3). j=27, j1=28, j2=30, and j3=31. +// +// G0 x x x x x . . . +// G1 x x x x x . . . +// G3 x x x x x . . . +// G4 x x x x x . . . +// +// 27 . . x x x x x . W0 points to W (27,2) +// 28 . . x x x x x . W1 points to W (28,2) +// 30 . . x x x x x . W2 points to W (30,2) +// 31 . . x x x x x . W3 points to W (31,2) +// +// +// row 'W' W0,W1,.. column j = 27 +// | | | of L +// v v v | +// | |-- column j = 28 of L +// | | |-- column j = 30 of L +// | | | |-- column j = 31 of L +// v v v v +// update L (j1,j): +// 28 . . 1 2 3 4 5 . x - - - +// +// update L (j2,j): +// 30 . . 1 2 3 4 5 . # x - - (# denotes modified) +// +// update L (j2,j1) +// 30 . . 1 2 3 4 5 . x # - - +// +// update L (j3,j) +// 31 . . 1 2 3 4 5 . # x x - +// +// update L (j3,j1) +// 31 . . 1 2 3 4 5 . x # x - +// +// update L (j3,j2) +// 31 . . 1 2 3 4 5 . x x # - +// +// cleanup iteration since length is odd: +// 42 . . 1 2 3 4 5 . x x x x +// +// then each iteration does one row of all four colummns of L: +// +// 43 . . 1 2 3 4 5 . x x x x +// 44 . . 1 2 3 4 5 . x x x x +// 50 . . 1 3 5 4 5 . x x x x +// 51 . . 1 2 3 4 5 . x x x x +// 67 . . 1 3 5 4 5 . x x x x +// 81 . . 1 2 3 4 5 . x x x x +// 83 . . 1 3 5 4 5 . x x x x +// 84 . . 1 2 3 4 5 . x x x x +// +// This file is included in t_cholmod_updown_wdim.c, only. +// It is not compiled separately. It contains no user-callable routines. +// +// workspace: Xwork (WDIM*nrow) + +//------------------------------------------------------------------------------ +// loop unrolling macros +//------------------------------------------------------------------------------ #undef RANK1 #undef RANK2 @@ -270,7 +252,7 @@ #define RANK8(statement) statement #endif -#define FOR_ALL_K \ +#define FOR_ALL_K \ RANK1 (DO (0)) \ RANK2 (DO (1)) \ RANK3 (DO (2)) \ @@ -280,464 +262,485 @@ RANK7 (DO (6)) \ RANK8 (DO (7)) -/* ========================================================================== */ -/* === alpha/gamma ========================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// dbound/sbound +//------------------------------------------------------------------------------ + +#undef USE_DBOUND +#undef BOUND_DJ + +#ifdef DOUBLE + + // double case + #define USE_DBOUND bool use_dbound = (Common->dbound > 0) ; + #define BOUND_DJ(Dj,dj) \ + Dj = ((use_dbound) ? (CHOLMOD(dbound) (dj, Common)) : (dj)) ; + +#else + + // single case + #define USE_DBOUND bool use_sbound = (Common->sbound > 0) ; + #define BOUND_DJ(Dj,dj) \ + Dj = ((use_sbound) ? (CHOLMOD(sbound) (dj, Common)) : (dj)) ; + +#endif + +//------------------------------------------------------------------------------ +// alpha/gamma +//------------------------------------------------------------------------------ #undef ALPHA_GAMMA -#define ALPHA_GAMMA(Dj,Alpha,Gamma,W) \ -{ \ - double dj = Dj ; \ - if (update) \ - { \ - for (k = 0 ; k < RANK ; k++) \ - { \ - double w = W [k] ; \ - double alpha = Alpha [k] ; \ - double a = alpha + (w * w) / dj ; \ - dj *= a ; \ - Alpha [k] = a ; \ - Gamma [k] = (- w / dj) ; \ - dj /= alpha ; \ - } \ - } \ - else \ - { \ - for (k = 0 ; k < RANK ; k++) \ - { \ - double w = W [k] ; \ - double alpha = Alpha [k] ; \ - double a = alpha - (w * w) / dj ; \ - dj *= a ; \ - Alpha [k] = a ; \ - Gamma [k] = w / dj ; \ - dj /= alpha ; \ - } \ - } \ - Dj = ((use_dbound) ? (CHOLMOD(dbound) (dj, Common)) : (dj)) ; \ +#define ALPHA_GAMMA(Dj,Alpha,Gamma,W) \ +{ \ + Real dj = Dj ; \ + if (update) \ + { \ + for (k = 0 ; k < RANK ; k++) \ + { \ + Real w = W [k] ; \ + Real alpha = Alpha [k] ; \ + Real a = alpha + (w * w) / dj ; \ + dj *= a ; \ + Alpha [k] = a ; \ + Gamma [k] = (- w / dj) ; \ + dj /= alpha ; \ + } \ + } \ + else \ + { \ + for (k = 0 ; k < RANK ; k++) \ + { \ + Real w = W [k] ; \ + Real alpha = Alpha [k] ; \ + Real a = alpha - (w * w) / dj ; \ + dj *= a ; \ + Alpha [k] = a ; \ + Gamma [k] = w / dj ; \ + dj /= alpha ; \ + } \ + } \ + BOUND_DJ (Dj, dj) ; \ } -/* ========================================================================== */ -/* === numeric update/downdate along one path =============================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// numeric update/downdate along one path +//------------------------------------------------------------------------------ -static void NUMERIC (WDIM, RANK) +static void UPDOWN (WDIM, RANK) ( - int update, /* TRUE for update, FALSE for downdate */ - Int j, /* first column in the path */ - Int e, /* last column in the path */ - double Alpha [ ], /* alpha, for each column of W */ - double W [ ], /* W is an n-by-WDIM array, stored in row-major order */ - cholmod_factor *L, /* with unit diagonal (diagonal not stored) */ + int update, // TRUE for update, FALSE for downdate + Int j, // first column in the path + Int e, // last column in the path + Real Alpha [ ], // alpha, for each column of W + Real W [ ], // W is an n-by-WDIM array, stored in row-major order + cholmod_factor *L, // with unit diagonal (diagonal not stored) cholmod_common *Common ) { + USE_DBOUND ; + #ifdef SIMPLE #define w(row,col) W [WDIM*(row) + (col)] - /* ---------------------------------------------------------------------- */ - /* concise but slow version for illustration only */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // concise but slow version for illustration only + //-------------------------------------------------------------------------- - double Gamma [WDIM] ; - double *Lx ; - Int *Li, *Lp, *Lnz ; - Int p, k ; - Int use_dbound = (Common->dbound > 0) ; + Real Gamma [WDIM] ; + Int *Li = L->i ; + Real *Lx = L->x ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; - Li = L->i ; - Lx = L->x ; - Lp = L->p ; - Lnz = L->nz ; - - /* walk up the etree from node j to its ancestor e */ + // walk up the etree from node j to its ancestor e for ( ; j <= e ; j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : Int_max) { - /* update the diagonal entry D (j,j) with each column of W */ - ALPHA_GAMMA (Lx [Lp [j]], Alpha, Gamma, (&(w (j,0)))) ; - /* update column j of L */ - for (p = Lp [j] + 1 ; p < Lp [j] + Lnz [j] ; p++) - { - /* update row Li [p] of column j of L with each column of W */ - Int i = Li [p] ; - for (k = 0 ; k < RANK ; k++) - { - w (i,k) -= w (j,k) * Lx [p] ; - Lx [p] -= Gamma [k] * w (i,k) ; - } - } - /* clear workspace W */ - for (k = 0 ; k < RANK ; k++) - { - w (j,k) = 0 ; - } + // update the diagonal entry D (j,j) with each column of W + ALPHA_GAMMA (Lx [Lp [j]], Alpha, Gamma, (&(w (j,0)))) ; + // update column j of L + for (Int p = Lp [j] + 1 ; p < Lp [j] + Lnz [j] ; p++) + { + // update row Li [p] of column j of L with each column of W + Int i = Li [p] ; + for (Int k = 0 ; k < RANK ; k++) + { + w (i,k) -= w (j,k) * Lx [p] ; + Lx [p] -= Gamma [k] * w (i,k) ; + } + } + // clear workspace W + for (Int k = 0 ; k < RANK ; k++) + { + w (j,k) = 0 ; + } } #else - /* ---------------------------------------------------------------------- */ - /* dynamic supernodal version: supernodes detected dynamically */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // dynamic supernodal version: supernodes detected dynamically + //-------------------------------------------------------------------------- - double G0 [RANK], G1 [RANK], G2 [RANK], G3 [RANK] ; - double Z0 [RANK], Z1 [RANK], Z2 [RANK], Z3 [RANK] ; - double *W0, *W1, *W2, *W3, *Lx ; + Real G0 [RANK], G1 [RANK], G2 [RANK], G3 [RANK] ; + Real Z0 [RANK], Z1 [RANK], Z2 [RANK], Z3 [RANK] ; + Real *W0, *W1, *W2, *W3, *Lx ; Int *Li, *Lp, *Lnz ; Int j1, j2, j3, p0, p1, p2, p3, parent, lnz, pend, k ; - Int use_dbound = (Common->dbound > 0) ; Li = L->i ; Lx = L->x ; Lp = L->p ; Lnz = L->nz ; - /* walk up the etree from node j to its ancestor e */ + // walk up the etree from node j to its ancestor e for ( ; j <= e ; j = parent) { - p0 = Lp [j] ; /* col j is Li,Lx [p0 ... p0+lnz-1] */ - lnz = Lnz [j] ; - - W0 = W + WDIM * j ; /* pointer to row j of W */ - pend = p0 + lnz ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) Z0 [k] = W0 [k] ; - FOR_ALL_K - #undef DO - - /* for k = 0 to RANK-1 do: */ - #define DO(k) W0 [k] = 0 ; - FOR_ALL_K - #undef DO - - /* update D (j,j) */ - ALPHA_GAMMA (Lx [p0], Alpha, G0, Z0) ; - p0++ ; - - /* determine how many columns of L to update at the same time */ - parent = (lnz > 1) ? (Li [p0]) : Int_max ; - if (parent <= e && lnz == Lnz [parent] + 1) - { - - /* -------------------------------------------------------------- */ - /* node j and its parent j1 can be updated at the same time */ - /* -------------------------------------------------------------- */ - - j1 = parent ; - j2 = (lnz > 2) ? (Li [p0+1]) : Int_max ; - j3 = (lnz > 3) ? (Li [p0+2]) : Int_max ; - W1 = W + WDIM * j1 ; /* pointer to row j1 of W */ - p1 = Lp [j1] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) Z1 [k] = W1 [k] ; - FOR_ALL_K - #undef DO - - /* for k = 0 to RANK-1 do: */ - #define DO(k) W1 [k] = 0 ; - FOR_ALL_K - #undef DO - - /* update L (j1,j) */ - { - double lx = Lx [p0] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - Z1 [k] -= Z0 [k] * lx ; \ - lx -= G0 [k] * Z1 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx ; - } - - /* update D (j1,j1) */ - ALPHA_GAMMA (Lx [p1], Alpha, G1, Z1) ; - p1++ ; - - /* -------------------------------------------------------------- */ - /* update 2 or 4 columns of L */ - /* -------------------------------------------------------------- */ - - if ((j2 <= e) && /* j2 in the current path */ - (j3 <= e) && /* j3 in the current path */ - (lnz == Lnz [j2] + 2) && /* column j2 matches */ - (lnz == Lnz [j3] + 3)) /* column j3 matches */ - { - - /* ---------------------------------------------------------- */ - /* update 4 columns of L */ - /* ---------------------------------------------------------- */ - - /* p0 and p1 currently point to row j2 in cols j and j1 of L */ - - parent = (lnz > 4) ? (Li [p0+2]) : Int_max ; - W2 = W + WDIM * j2 ; /* pointer to row j2 of W */ - W3 = W + WDIM * j3 ; /* pointer to row j3 of W */ - p2 = Lp [j2] ; - p3 = Lp [j3] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) Z2 [k] = W2 [k] ; - FOR_ALL_K - #undef DO - - /* for k = 0 to RANK-1 do: */ - #define DO(k) Z3 [k] = W3 [k] ; - FOR_ALL_K - #undef DO - - /* for k = 0 to RANK-1 do: */ - #define DO(k) W2 [k] = 0 ; - FOR_ALL_K - #undef DO - - /* for k = 0 to RANK-1 do: */ - #define DO(k) W3 [k] = 0 ; - FOR_ALL_K - #undef DO - - /* update L (j2,j) and update L (j2,j1) */ - { - double lx [2] ; - lx [0] = Lx [p0] ; - lx [1] = Lx [p1] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - Z2 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z2 [k] ; \ - Z2 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z2 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx [0] ; - Lx [p1++] = lx [1] ; - } - - /* update D (j2,j2) */ - ALPHA_GAMMA (Lx [p2], Alpha, G2, Z2) ; - p2++ ; - - /* update L (j3,j), L (j3,j1), and L (j3,j2) */ - { - double lx [3] ; - lx [0] = Lx [p0] ; - lx [1] = Lx [p1] ; - lx [2] = Lx [p2] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - Z3 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z3 [k] ; \ - Z3 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z3 [k] ; \ - Z3 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * Z3 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx [0] ; - Lx [p1++] = lx [1] ; - Lx [p2++] = lx [2] ; - } - - /* update D (j3,j3) */ - ALPHA_GAMMA (Lx [p3], Alpha, G3, Z3) ; - p3++ ; - - /* each iteration updates L (i, [j j1 j2 j3]) */ - for ( ; p0 < pend ; p0++, p1++, p2++, p3++) - { - double lx [4], *w0 ; - lx [0] = Lx [p0] ; - lx [1] = Lx [p1] ; - lx [2] = Lx [p2] ; - lx [3] = Lx [p3] ; - w0 = W + WDIM * Li [p0] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \ - w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ; \ - w0 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * w0 [k] ; \ - w0 [k] -= Z3 [k] * lx [3] ; lx [3] -= G3 [k] * w0 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0] = lx [0] ; - Lx [p1] = lx [1] ; - Lx [p2] = lx [2] ; - Lx [p3] = lx [3] ; - } - } - else - { - - /* ---------------------------------------------------------- */ - /* update 2 columns of L */ - /* ---------------------------------------------------------- */ - - parent = j2 ; - - /* cleanup iteration if length is odd */ - if ((lnz - 2) % 2) - { - double lx [2] , *w0 ; - lx [0] = Lx [p0] ; - lx [1] = Lx [p1] ; - w0 = W + WDIM * Li [p0] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \ - w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx [0] ; - Lx [p1++] = lx [1] ; - } - - for ( ; p0 < pend ; p0 += 2, p1 += 2) - { - double lx [2][2], w [2], *w0, *w1 ; - lx [0][0] = Lx [p0 ] ; - lx [1][0] = Lx [p0+1] ; - lx [0][1] = Lx [p1 ] ; - lx [1][1] = Lx [p1+1] ; - w0 = W + WDIM * Li [p0 ] ; - w1 = W + WDIM * Li [p0+1] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w [0] = w0 [k] - Z0 [k] * lx [0][0] ; \ - w [1] = w1 [k] - Z0 [k] * lx [1][0] ; \ - lx [0][0] -= G0 [k] * w [0] ; \ - lx [1][0] -= G0 [k] * w [1] ; \ - w0 [k] = w [0] -= Z1 [k] * lx [0][1] ; \ - w1 [k] = w [1] -= Z1 [k] * lx [1][1] ; \ - lx [0][1] -= G1 [k] * w [0] ; \ - lx [1][1] -= G1 [k] * w [1] ; - FOR_ALL_K - #undef DO - - Lx [p0 ] = lx [0][0] ; - Lx [p0+1] = lx [1][0] ; - Lx [p1 ] = lx [0][1] ; - Lx [p1+1] = lx [1][1] ; - } - } - } - else - { - - /* -------------------------------------------------------------- */ - /* update one column of L */ - /* -------------------------------------------------------------- */ - - /* cleanup iteration if length is not a multiple of 4 */ - switch ((lnz - 1) % 4) - { - case 1: - { - double lx , *w0 ; - lx = Lx [p0] ; - w0 = W + WDIM * Li [p0] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx ; lx -= G0 [k] * w0 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx ; - } - break ; - - case 2: - { - double lx [2], *w0, *w1 ; - lx [0] = Lx [p0 ] ; - lx [1] = Lx [p0+1] ; - w0 = W + WDIM * Li [p0 ] ; - w1 = W + WDIM * Li [p0+1] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx [0] ; \ - w1 [k] -= Z0 [k] * lx [1] ; \ - lx [0] -= G0 [k] * w0 [k] ; \ - lx [1] -= G0 [k] * w1 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx [0] ; - Lx [p0++] = lx [1] ; - } - break ; - - case 3: - { - double lx [3], *w0, *w1, *w2 ; - lx [0] = Lx [p0 ] ; - lx [1] = Lx [p0+1] ; - lx [2] = Lx [p0+2] ; - w0 = W + WDIM * Li [p0 ] ; - w1 = W + WDIM * Li [p0+1] ; - w2 = W + WDIM * Li [p0+2] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx [0] ; \ - w1 [k] -= Z0 [k] * lx [1] ; \ - w2 [k] -= Z0 [k] * lx [2] ; \ - lx [0] -= G0 [k] * w0 [k] ; \ - lx [1] -= G0 [k] * w1 [k] ; \ - lx [2] -= G0 [k] * w2 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0++] = lx [0] ; - Lx [p0++] = lx [1] ; - Lx [p0++] = lx [2] ; - } - } - - for ( ; p0 < pend ; p0 += 4) - { - double lx [4], *w0, *w1, *w2, *w3 ; - lx [0] = Lx [p0 ] ; - lx [1] = Lx [p0+1] ; - lx [2] = Lx [p0+2] ; - lx [3] = Lx [p0+3] ; - w0 = W + WDIM * Li [p0 ] ; - w1 = W + WDIM * Li [p0+1] ; - w2 = W + WDIM * Li [p0+2] ; - w3 = W + WDIM * Li [p0+3] ; - - /* for k = 0 to RANK-1 do: */ - #define DO(k) \ - w0 [k] -= Z0 [k] * lx [0] ; \ - w1 [k] -= Z0 [k] * lx [1] ; \ - w2 [k] -= Z0 [k] * lx [2] ; \ - w3 [k] -= Z0 [k] * lx [3] ; \ - lx [0] -= G0 [k] * w0 [k] ; \ - lx [1] -= G0 [k] * w1 [k] ; \ - lx [2] -= G0 [k] * w2 [k] ; \ - lx [3] -= G0 [k] * w3 [k] ; - FOR_ALL_K - #undef DO - - Lx [p0 ] = lx [0] ; - Lx [p0+1] = lx [1] ; - Lx [p0+2] = lx [2] ; - Lx [p0+3] = lx [3] ; - } - } + p0 = Lp [j] ; // col j is Li,Lx [p0 ... p0+lnz-1] + lnz = Lnz [j] ; + + W0 = W + WDIM * j ; // pointer to row j of W + pend = p0 + lnz ; + + // for k = 0 to RANK-1 do: + #define DO(k) Z0 [k] = W0 [k] ; + FOR_ALL_K + #undef DO + + // for k = 0 to RANK-1 do: + #define DO(k) W0 [k] = 0 ; + FOR_ALL_K + #undef DO + + // update D (j,j) + ALPHA_GAMMA (Lx [p0], Alpha, G0, Z0) ; + p0++ ; + + // determine how many columns of L to update at the same time + parent = (lnz > 1) ? (Li [p0]) : Int_max ; + if (parent <= e && lnz == Lnz [parent] + 1) + { + + //------------------------------------------------------------------ + // node j and its parent j1 can be updated at the same time + //------------------------------------------------------------------ + + j1 = parent ; + j2 = (lnz > 2) ? (Li [p0+1]) : Int_max ; + j3 = (lnz > 3) ? (Li [p0+2]) : Int_max ; + W1 = W + WDIM * j1 ; // pointer to row j1 of W + p1 = Lp [j1] ; + + // for k = 0 to RANK-1 do: + #define DO(k) Z1 [k] = W1 [k] ; + FOR_ALL_K + #undef DO + + // for k = 0 to RANK-1 do: + #define DO(k) W1 [k] = 0 ; + FOR_ALL_K + #undef DO + + // update L (j1,j) + { + Real lx = Lx [p0] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + Z1 [k] -= Z0 [k] * lx ; \ + lx -= G0 [k] * Z1 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx ; + } + + // update D (j1,j1) + ALPHA_GAMMA (Lx [p1], Alpha, G1, Z1) ; + p1++ ; + + //------------------------------------------------------------------ + // update 2 or 4 columns of L + //------------------------------------------------------------------ + + if ((j2 <= e) && // j2 in the current path + (j3 <= e) && // j3 in the current path + (lnz == Lnz [j2] + 2) && // column j2 matches + (lnz == Lnz [j3] + 3)) // column j3 matches + { + + //-------------------------------------------------------------- + // update 4 columns of L + //-------------------------------------------------------------- + + // p0 and p1 currently point to row j2 in cols j and j1 of L + + parent = (lnz > 4) ? (Li [p0+2]) : Int_max ; + W2 = W + WDIM * j2 ; // pointer to row j2 of W + W3 = W + WDIM * j3 ; // pointer to row j3 of W + p2 = Lp [j2] ; + p3 = Lp [j3] ; + + // for k = 0 to RANK-1 do: + #define DO(k) Z2 [k] = W2 [k] ; + FOR_ALL_K + #undef DO + + // for k = 0 to RANK-1 do: + #define DO(k) Z3 [k] = W3 [k] ; + FOR_ALL_K + #undef DO + + // for k = 0 to RANK-1 do: + #define DO(k) W2 [k] = 0 ; + FOR_ALL_K + #undef DO + + // for k = 0 to RANK-1 do: + #define DO(k) W3 [k] = 0 ; + FOR_ALL_K + #undef DO + + // update L (j2,j) and update L (j2,j1) + { + Real lx [2] ; + lx [0] = Lx [p0] ; + lx [1] = Lx [p1] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + Z2 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z2 [k] ; \ + Z2 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z2 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx [0] ; + Lx [p1++] = lx [1] ; + } + + // update D (j2,j2) + ALPHA_GAMMA (Lx [p2], Alpha, G2, Z2) ; + p2++ ; + + // update L (j3,j), L (j3,j1), and L (j3,j2) + { + Real lx [3] ; + lx [0] = Lx [p0] ; + lx [1] = Lx [p1] ; + lx [2] = Lx [p2] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + Z3 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z3 [k] ; \ + Z3 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z3 [k] ; \ + Z3 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * Z3 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx [0] ; + Lx [p1++] = lx [1] ; + Lx [p2++] = lx [2] ; + } + + // update D (j3,j3) + ALPHA_GAMMA (Lx [p3], Alpha, G3, Z3) ; + p3++ ; + + // each iteration updates L (i, [j j1 j2 j3]) + for ( ; p0 < pend ; p0++, p1++, p2++, p3++) + { + Real lx [4], *w0 ; + lx [0] = Lx [p0] ; + lx [1] = Lx [p1] ; + lx [2] = Lx [p2] ; + lx [3] = Lx [p3] ; + w0 = W + WDIM * Li [p0] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \ + w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ; \ + w0 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * w0 [k] ; \ + w0 [k] -= Z3 [k] * lx [3] ; lx [3] -= G3 [k] * w0 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0] = lx [0] ; + Lx [p1] = lx [1] ; + Lx [p2] = lx [2] ; + Lx [p3] = lx [3] ; + } + } + else + { + + //-------------------------------------------------------------- + // update 2 columns of L + //-------------------------------------------------------------- + + parent = j2 ; + + // cleanup iteration if length is odd + if ((lnz - 2) % 2) + { + Real lx [2] , *w0 ; + lx [0] = Lx [p0] ; + lx [1] = Lx [p1] ; + w0 = W + WDIM * Li [p0] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \ + w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx [0] ; + Lx [p1++] = lx [1] ; + } + + for ( ; p0 < pend ; p0 += 2, p1 += 2) + { + Real lx [2][2], w [2], *w0, *w1 ; + lx [0][0] = Lx [p0 ] ; + lx [1][0] = Lx [p0+1] ; + lx [0][1] = Lx [p1 ] ; + lx [1][1] = Lx [p1+1] ; + w0 = W + WDIM * Li [p0 ] ; + w1 = W + WDIM * Li [p0+1] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w [0] = w0 [k] - Z0 [k] * lx [0][0] ; \ + w [1] = w1 [k] - Z0 [k] * lx [1][0] ; \ + lx [0][0] -= G0 [k] * w [0] ; \ + lx [1][0] -= G0 [k] * w [1] ; \ + w0 [k] = w [0] -= Z1 [k] * lx [0][1] ; \ + w1 [k] = w [1] -= Z1 [k] * lx [1][1] ; \ + lx [0][1] -= G1 [k] * w [0] ; \ + lx [1][1] -= G1 [k] * w [1] ; + FOR_ALL_K + #undef DO + + Lx [p0 ] = lx [0][0] ; + Lx [p0+1] = lx [1][0] ; + Lx [p1 ] = lx [0][1] ; + Lx [p1+1] = lx [1][1] ; + } + } + } + else + { + + //------------------------------------------------------------------ + // update one column of L + //------------------------------------------------------------------ + + // cleanup iteration if length is not a multiple of 4 + switch ((lnz - 1) % 4) + { + case 1: + { + Real lx , *w0 ; + lx = Lx [p0] ; + w0 = W + WDIM * Li [p0] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx ; lx -= G0 [k] * w0 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx ; + } + break ; + + case 2: + { + Real lx [2], *w0, *w1 ; + lx [0] = Lx [p0 ] ; + lx [1] = Lx [p0+1] ; + w0 = W + WDIM * Li [p0 ] ; + w1 = W + WDIM * Li [p0+1] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx [0] ; \ + w1 [k] -= Z0 [k] * lx [1] ; \ + lx [0] -= G0 [k] * w0 [k] ; \ + lx [1] -= G0 [k] * w1 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx [0] ; + Lx [p0++] = lx [1] ; + } + break ; + + case 3: + { + Real lx [3], *w0, *w1, *w2 ; + lx [0] = Lx [p0 ] ; + lx [1] = Lx [p0+1] ; + lx [2] = Lx [p0+2] ; + w0 = W + WDIM * Li [p0 ] ; + w1 = W + WDIM * Li [p0+1] ; + w2 = W + WDIM * Li [p0+2] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx [0] ; \ + w1 [k] -= Z0 [k] * lx [1] ; \ + w2 [k] -= Z0 [k] * lx [2] ; \ + lx [0] -= G0 [k] * w0 [k] ; \ + lx [1] -= G0 [k] * w1 [k] ; \ + lx [2] -= G0 [k] * w2 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0++] = lx [0] ; + Lx [p0++] = lx [1] ; + Lx [p0++] = lx [2] ; + } + } + + for ( ; p0 < pend ; p0 += 4) + { + Real lx [4], *w0, *w1, *w2, *w3 ; + lx [0] = Lx [p0 ] ; + lx [1] = Lx [p0+1] ; + lx [2] = Lx [p0+2] ; + lx [3] = Lx [p0+3] ; + w0 = W + WDIM * Li [p0 ] ; + w1 = W + WDIM * Li [p0+1] ; + w2 = W + WDIM * Li [p0+2] ; + w3 = W + WDIM * Li [p0+3] ; + + // for k = 0 to RANK-1 do: + #define DO(k) \ + w0 [k] -= Z0 [k] * lx [0] ; \ + w1 [k] -= Z0 [k] * lx [1] ; \ + w2 [k] -= Z0 [k] * lx [2] ; \ + w3 [k] -= Z0 [k] * lx [3] ; \ + lx [0] -= G0 [k] * w0 [k] ; \ + lx [1] -= G0 [k] * w1 [k] ; \ + lx [2] -= G0 [k] * w2 [k] ; \ + lx [3] -= G0 [k] * w3 [k] ; + FOR_ALL_K + #undef DO + + Lx [p0 ] = lx [0] ; + Lx [p0+1] = lx [1] ; + Lx [p0+2] = lx [2] ; + Lx [p0+3] = lx [3] ; + } + } } #endif } -/* prepare this file for another inclusion in t_cholmod_updown.c: */ + +// prepare this file for another inclusion in t_cholmod_updown_wdim.c: #undef RANK + diff --git a/CHOLMOD/Modify/t_cholmod_updown_wdim.c b/CHOLMOD/Modify/t_cholmod_updown_wdim.c new file mode 100644 index 0000000000..9652b484f0 --- /dev/null +++ b/CHOLMOD/Modify/t_cholmod_updown_wdim.c @@ -0,0 +1,213 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Modify/t_cholmod_updown_wdim: template for t_cholmod_updown_worker +//------------------------------------------------------------------------------ + +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, +// and William W. Hager. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Updates/downdates the LDL' factorization, by computing a new factorization of +// +// Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C' +// +// This file is not compiled separately. It is #included twice into +// t_cholmod_updown_worker.c, to create all the kernels for double and single +// precision update/downdate. There are no user-callable routines in this +// file. +// +// The next #include statements, below, create the numerical update/downdate +// kernels from t_cholmod_updown_numkr.c. For the double case, there are 4 +// compiled versions of this file, one for each value of WDIM in the set 1, 2, +// 4, and 8. Each calls multiple versions of t_cholmod_updown_numkr; the +// number of versions of each is equal to WDIM. Each t_cholmod_updown_numkr +// version is #included as a static function within its t_cholmod_updown_wdim.c +// caller routine. Thus, for the double case: +// +// t*_updown_wdim.c creates these versions of t_cholmod_updown_numkr.c: +// ---------------- --------------------------------------------------- +// +// d_updown_1_r d_updown_1_1 +// +// d_updown_2_r d_updown_2_1 d_updown_2_2 +// +// d_updown_4_r d_updown_4_1 d_updown_4_2 d_updown_4_3 d_updown_4_4 +// +// d_updown_8_r d_updown_8_1 d_updown_8_2 d_updown_8_3 d_updown_8_4 +// d_updown_8_5 d_updown_8_6 d_updown_8_7 d_updown_8_8 +// +// For the single (float) case, all the functions are named s_updown_*_*. +// +// workspace: Xwork (nrow*wdim) + +//------------------------------------------------------------------------------ +// routines for numeric update/downdate along one path +//------------------------------------------------------------------------------ + +#define RANK 1 +#include "t_cholmod_updown_numkr.c" + +#if WDIM >= 2 +#define RANK 2 +#include "t_cholmod_updown_numkr.c" +#endif + +#if WDIM >= 4 +#define RANK 3 +#include "t_cholmod_updown_numkr.c" +#define RANK 4 +#include "t_cholmod_updown_numkr.c" +#endif + +#if WDIM == 8 +#define RANK 5 +#include "t_cholmod_updown_numkr.c" +#define RANK 6 +#include "t_cholmod_updown_numkr.c" +#define RANK 7 +#include "t_cholmod_updown_numkr.c" +#define RANK 8 +#include "t_cholmod_updown_numkr.c" +#endif + +//------------------------------------------------------------------------------ +// numeric update/downdate for all paths +//------------------------------------------------------------------------------ + +static void UPDOWN (WDIM, r) // WDIM is a compile-time constant (1,2,4, or 8) +( + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // in packed or unpacked, and sorted form + // no empty columns + Int rank, // rank of the update/downdate + cholmod_factor *L, // with unit diagonal (diagonal not stored) + // temporary workspaces: + Real W [ ], // n-by-WDIM dense matrix, initially zero + Path_type Path [ ], + Int npaths, + Int mask [ ], // size n + Int maskmark, + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real Alpha [8] ; + Real *Cx, *Wpath, *W1, *a ; + Int i, j, p, ccol, pend, wfirst, e, path, packed ; + Int *Ci, *Cp, *Cnz ; + + Ci = C->i ; + Cx = C->x ; + Cp = C->p ; + Cnz = C->nz ; + packed = C->packed ; + ASSERT (IMPLIES (!packed, Cnz != NULL)) ; + ASSERT (L->n == C->nrow) ; + DEBUG (CHOLMOD(dump_real) ("num_d: in W:", W, L->dtype, + WDIM, L->n, FALSE, 1, Common)) ; + + //-------------------------------------------------------------------------- + // scatter C into W + //-------------------------------------------------------------------------- + + for (path = 0 ; path < rank ; path++) + { + // W (:, path) = C (:, Path [path].col) + ccol = Path [path].ccol ; + Wpath = W + path ; + PRINT1 (("Ordered Columns [path = "ID"] = "ID"\n", path, ccol)) ; + p = Cp [ccol] ; + pend = (packed) ? (Cp [ccol+1]) : (p + Cnz [ccol]) ; + // column C can be empty + for ( ; p < pend ; p++) + { + i = Ci [p] ; + ASSERT (i >= 0 && i < (Int) (C->nrow)) ; + if (mask == NULL || mask [i] < maskmark) + { + Wpath [WDIM * i] = Cx [p] ; + } + PRINT1 ((" row "ID" : %g mask "ID"\n", i, Cx [p], + (mask) ? mask [i] : 0)) ; + } + Alpha [path] = 1.0 ; + } + DEBUG (CHOLMOD(dump_real) ("num_d: W:", W, L->dtype, + WDIM, L->n, FALSE, 1,Common)) ; + + //-------------------------------------------------------------------------- + // numeric update/downdate of the paths + //-------------------------------------------------------------------------- + + // for each disjoint subpath in Tbar in DFS order do + for (path = rank ; path < npaths ; path++) + { + + // determine which columns of W to use + wfirst = Path [path].wfirst ; + e = Path [path].end ; + j = Path [path].start ; + ASSERT (e >= 0 && e < (Int) (L->n)) ; + ASSERT (j >= 0 && j < (Int) (L->n)) ; + + W1 = W + wfirst ; // pointer to row 0, column wfirst of W + a = Alpha + wfirst ; // pointer to Alpha [wfirst] + + PRINT1 (("Numerical update/downdate of path "ID"\n", path)) ; + PRINT1 (("start "ID" end "ID" wfirst "ID" rank "ID" ccol "ID"\n", j, e, + wfirst, Path [path].rank, Path [path].ccol)) ; + + #if WDIM == 1 + + UPDOWN (WDIM,1) (update, j, e, a, W1, L, Common) ; + + #else + + switch (Path [path].rank) + { + case 1: + UPDOWN (WDIM,1) (update, j, e, a, W1, L, Common) ; + break ; + + #if WDIM >= 2 + case 2: + UPDOWN (WDIM,2) (update, j, e, a, W1, L, Common) ; + break ; + #endif + + #if WDIM >= 4 + case 3: + UPDOWN (WDIM,3) (update, j, e, a, W1, L, Common) ; + break ; + case 4: + UPDOWN (WDIM,4) (update, j, e, a, W1, L, Common) ; + break ; + #endif + + #if WDIM == 8 + case 5: + UPDOWN (WDIM,5) (update, j, e, a, W1, L, Common) ; + break ; + case 6: + UPDOWN (WDIM,6) (update, j, e, a, W1, L, Common) ; + break ; + case 7: + UPDOWN (WDIM,7) (update, j, e, a, W1, L, Common) ; + break ; + case 8: + UPDOWN (WDIM,8) (update, j, e, a, W1, L, Common) ; + break ; + #endif + } + #endif + } +} + +// prepare for the next inclusion of this file in t_cholmod_updown_worker.c +#undef WDIM + diff --git a/CHOLMOD/Modify/t_cholmod_updown_worker.c b/CHOLMOD/Modify/t_cholmod_updown_worker.c new file mode 100644 index 0000000000..1e147529e0 --- /dev/null +++ b/CHOLMOD/Modify/t_cholmod_updown_worker.c @@ -0,0 +1,1168 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Modify/t_cholmod_updown_worker: sparse Cholesky update/downdate +//------------------------------------------------------------------------------ + +// CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis, +// and William W. Hager. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// This method, TEMPLATE (cholmod_updown_worker), is #included twice in +// cholmod_updown.c, to create rs_cholmod_updown_worker for the single case, +// and r_cholmod_updown_worker for the double case. + +// t_cholmod_update_wdim.c is #included four times below, to create the set of +// update/downdate methods for each value of WDIM (1, 2, 4, and 8). Then each +// of the four t_cholmod_update_wdim.c methods in turn #includes +// t_cholmod_updown_numkr.c WDIM times. + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// templates for each size of W +//------------------------------------------------------------------------------ + +#undef UPDOWN +#ifdef DOUBLE +// double: d_updown_k_rank +#define UPDOWN(k,rank) UPDOWN_METHOD(d_,k,rank) +#else +// single: s_updown_k_rank +#define UPDOWN(k,rank) UPDOWN_METHOD(s_,k,rank) +#endif + +#define WDIM 1 +#include "t_cholmod_updown_wdim.c" +#define WDIM 2 +#include "t_cholmod_updown_wdim.c" +#define WDIM 4 +#include "t_cholmod_updown_wdim.c" +#define WDIM 8 +#include "t_cholmod_updown_wdim.c" + +//------------------------------------------------------------------------------ +// debug routine +//------------------------------------------------------------------------------ + +#ifndef NDEBUG + +static void TEMPLATE (dump_col) +( + char *w, Int j, Int p1, Int p2, Int *Li, Real *Lx, Int n, + cholmod_common *Common +) +{ + Int p, row, lastrow ; + if (CHOLMOD(dump) < -1) + { + // no checks if debug level is -2 or less + return ; + } + PRINT3 (("\n\nDUMP COL==== j = "ID" %s: p1="ID" p2="ID" \n", j, w, p1,p2)); + lastrow = -1 ; + for (p = p1 ; p < p2 ; p++) + { + PRINT3 ((" "ID": ", p)) ; + row = Li [p] ; + PRINT3 ((""ID" ", Li [p])) ; + PRINT3 (("%g ", Lx [p])) ; + PRINT3 (("\n")) ; + ASSERT (row > lastrow && row < n) ; + lastrow = row ; + } + ASSERT (p1 < p2) ; + ASSERT (Li [p1] == j) ; + PRINT3 (("\n")) ; +} + +#endif + +//------------------------------------------------------------------------------ +// t_cholmod_updown_worker: for the single and double cases +//------------------------------------------------------------------------------ + +static int TEMPLATE (cholmod_updown_worker) +( + // input: + Int k, // maximum rank for each update/downdate + int update, // TRUE for update, FALSE for downdate + cholmod_sparse *C, // the incoming sparse update + Int *colmark, // array of size n. See cholmod_updown.c for details + Int *mask, // size n + Int maskmark, + // input/output: + cholmod_factor *L, // factor to modify + cholmod_dense *X, // solution to Lx=b (size n-by-1) + cholmod_dense *DeltaB, // change in b, zero on output + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Int *Set_ps1 [32], *Set_ps2 [32] ; + Path_type OrderedPath [32], Path [32] ; + + Int npaths, i, j, row, packed, ccol, p, + jj, j2, kk, nextj, p1, p2, c, newlnz, + newpath, path_order, w_order, scattered, path, pp1, pp2, + smax, maxrow, row1, nsets, s, p3, newlnz1, Set [32], top, len, lnz, m, + botrow ; + DEBUG (Int oldparent) ; + + Int mark = Common->mark ; + + Int *Ci = C->i ; + Int *Cp = C->p ; + Int *Cnz = C->nz ; + packed = C->packed ; + Int cncol = C->ncol ; + ASSERT (IMPLIES (!packed, Cnz != NULL)) ; + + Real *Xx, *Nx ; + bool do_solve = (X != NULL) && (DeltaB != NULL) ; + if (do_solve) + { + Xx = X->x ; + Nx = DeltaB->x ; + } + else + { + Xx = NULL ; + Nx = NULL ; + } + + Int n = L->n ; + Int *Li = L->i ; + Real *Lx = L->x ; + Int *Lp = L->p ; + Int *Lnz = L->nz ; + Int *Lnext = L->next ; + ASSERT (Lnz != NULL) ; + + Int wdim = Power2 [k] ; // number of columns in W + + double fl = 0 ; + bool use_colmark = (colmark != NULL) ; + + Int *ps1 = NULL ; + Int *ps2 = NULL ; + + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- + + Int *Flag = Common->Flag ; // size n, Flag [i] <= mark must hold + Int *Head = Common->Head ; // size n, Head [i] == EMPTY must hold + Real *W = Common->Xwork ; // size n-by-wdim, zero on input and output + + // note that Iwork [n .. 2*n-1] (i/i/l) may be in use in rowadd/rowdel: + Int *Iwork = Common->Iwork ; + Int *Stack = Iwork ; // size n, uninitialized + + //-------------------------------------------------------------------------- + // entire rank-cncol update, done as a sequence of rank-k updates + //-------------------------------------------------------------------------- + + for (Int k1 = 0 ; k1 < cncol ; k1 += k) + { + + //---------------------------------------------------------------------- + // get the next k columns of C for the update/downdate + //---------------------------------------------------------------------- + + // the last update/downdate might be less than rank-k + if (k > cncol - k1) + { + k = cncol - k1 ; + wdim = Power2 [k] ; + } + Int k2 = k1 + k - 1 ; + + // workspaces are in the following state, on input and output + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, L->dtype, Common)) ; + + //---------------------------------------------------------------------- + // create a zero-length path for each column of W + //---------------------------------------------------------------------- + + nextj = n ; + path = 0 ; + for (ccol = k1 ; ccol <= k2 ; ccol++) + { + PRINT1 (("Column ["ID"]: "ID"\n", path, ccol)) ; + ASSERT (ccol >= 0 && ccol <= cncol) ; + pp1 = Cp [ccol] ; + pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; + // get the row index j of the first entry in C (:,ccol) + if (pp2 > pp1) + { + // Column ccol of C has at least one entry. + j = Ci [pp1] ; + } + else + { + // Column ccol of C is empty. Pretend it has one entry in + // the last column with numerical value of zero. + j = n-1 ; + } + ASSERT (j >= 0 && j < n) ; + + // find first column to work on + nextj = MIN (nextj, j) ; + + Path [path].ccol = ccol ; // which column of C this path is for + Path [path].start = EMPTY ; // paths for C have zero length + Path [path].end = EMPTY ; + Path [path].parent = EMPTY ; // no parent yet + Path [path].rank = 1 ; // one column of W + Path [path].c = EMPTY ; // no child of this path (case A) + Path [path].next = Head [j] ; // this path is pending at col j + Path [path].pending = j ; // this path is pending at col j + Head [j] = path ; // this path is pending at col j + PRINT1(("Path "ID" starts: start "ID" end "ID" parent "ID" c "ID"" + "j "ID" ccol "ID"\n", path, Path [path].start, + Path [path].end, Path [path].parent, + Path [path].c, j, ccol)) ; + + // initialize botrow for this path + Path [path].botrow = (use_colmark) ? colmark [ccol] : n ; + + path++ ; + } + + // we start with paths 0 to k-1. Next one (now unused) is npaths + npaths = k ; + + j = nextj ; + ASSERT (j < n) ; + scattered = FALSE ; + + //---------------------------------------------------------------------- + // symbolic update of columns of L + //---------------------------------------------------------------------- + + while (j < n) + { + ASSERT (j >= 0 && j < n && Lnz [j] > 0) ; + + // the old column, Li [p1..p2-1]. D (j,j) is stored in Lx [p1] + p1 = Lp [j] ; + newlnz = Lnz [j] ; + p2 = p1 + newlnz ; + + #ifndef NDEBUG + PRINT1 (("\n=========Column j="ID" p1 "ID" p2 "ID" lnz "ID" \n", + j, p1, p2, newlnz)) ; + TEMPLATE (dump_col) ("Old", j, p1, p2, Li, Lx, n, Common) ; + oldparent = (Lnz [j] > 1) ? (Li [p1 + 1]) : EMPTY ; + ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, 0, Common)) ; + ASSERT (!scattered) ; + PRINT1 (("Col "ID": Checking paths, npaths: "ID"\n", j, npaths)) ; + for (kk = 0 ; kk < npaths ; kk++) + { + Int kk2, found, j3 = Path [kk].pending ; + PRINT2 (("Path "ID" pending at "ID".\n", kk, j3)) ; + if (j3 != EMPTY) + { + // Path kk must be somewhere in link list for column j3 + ASSERT (Head [j3] != EMPTY) ; + PRINT3 ((" List at "ID": ", j3)) ; + found = FALSE ; + for (kk2 = Head [j3] ; kk2 != EMPTY ; kk2 = Path [kk2].next) + { + PRINT3 ((""ID" ", kk2)) ; + ASSERT (Path [kk2].pending == j3) ; + found = found || (kk2 == kk) ; + } + PRINT3 (("\n")) ; + ASSERT (found) ; + } + } + PRINT1 (("\nCol "ID": Paths at this column, head "ID"\n", + j, Head [j])); + ASSERT (Head [j] != EMPTY) ; + for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next) + { + PRINT1 (("path "ID": (c="ID" j="ID") npaths "ID"\n", + kk, Path[kk].c, j, npaths)) ; + ASSERT (kk >= 0 && kk < npaths) ; + ASSERT (Path [kk].pending == j) ; + } + #endif + + //------------------------------------------------------------------ + // determine the path we're on + //------------------------------------------------------------------ + + // get the first old path at column j + path = Head [j] ; + + //------------------------------------------------------------------ + // update/downdate of forward solve, Lx=b + //------------------------------------------------------------------ + + if (do_solve) + { + Real xj = Xx [j] ; + if (xj != 0) + { + xj = Xx [j] ; + // This is first time column j has been seen for entire + // rank-k update/downdate. + + // DeltaB += Lold (j:botrow-1,j) * X (j) + Nx [j] += xj ; // diagonal of L + + // find the botrow for this column + botrow = (use_colmark) ? Path [path].botrow : n ; + + for (p = p1 + 1 ; p < p2 ; p++) + { + i = Li [p] ; + if (i >= botrow) + { + break ; + } + Nx [i] += Lx [p] * xj ; + } + + // clear X[j] to flag col j of Lold as having been seen. If + // X (j) was initially zero, then the above code is never + // executed for column j. This is safe, since if xj=0 the + // code above does not do anything anyway. + Xx [j] = 0.0 ; + } + } + + //------------------------------------------------------------------ + // start a new path at this column if two or more paths merge + //------------------------------------------------------------------ + + newpath = + // start a new path if paths have merged + (Path [path].next != EMPTY) + // or if j is the first node on a path (case A). + || (Path [path].c == EMPTY) ; + + if (newpath) + { + // get the botrow of the first path at column j + botrow = (use_colmark) ? Path [path].botrow : n ; + + path = npaths++ ; + ASSERT (npaths <= 3*k) ; + Path [path].ccol = EMPTY ; // no single col of C for this path + Path [path].start = j ; // path starts at this column j + Path [path].end = EMPTY ; // don't know yet where it ends + Path [path].parent = EMPTY ;// don't know parent path yet + Path [path].rank = 0 ; // rank is sum of child path ranks + PRINT1 (("Path "ID" starts: start "ID" end "ID" parent "ID"\n", + path, Path [path].start, Path [path].end, Path [path].parent)) ; + + // set the botrow of the new path + Path [path].botrow = (use_colmark) ? botrow : n ; + } + + //------------------------------------------------------------------ + // for each path kk pending at column j + //------------------------------------------------------------------ + + // make a list of the sets that need to be merged into column j + nsets = 0 ; + + for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next) + { + + //-------------------------------------------------------------- + // path kk is at (c,j) + //-------------------------------------------------------------- + + c = Path [kk].c ; + ASSERT (c < j) ; + PRINT1 (("TUPLE on path "ID" (c="ID" j="ID")\n", kk, c, j)) ; + ASSERT (Path [kk].pending == j) ; + + if (newpath) + { + // finalize path kk and find rank of this path + Path [kk].end = c ; // end of old path is previous node c + Path [kk].parent = path ; // parent is this path + Path [path].rank += Path [kk].rank ; // sum up ranks + Path [kk].pending = EMPTY ; + PRINT1 (("Path "ID" done:start "ID" end "ID" parent "ID"\n", + kk, Path [kk].start, Path [kk].end, Path [kk].parent)) ; + } + + if (c == EMPTY) + { + + //---------------------------------------------------------- + // CASE A: first node in path + //---------------------------------------------------------- + + // update: add pattern of incoming column + + // Column ccol of C is in Ci [pp1 ... pp2-1] + ccol = Path [kk].ccol ; + pp1 = Cp [ccol] ; + pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; + PRINT1 (("Case A, ccol = "ID" len "ID"\n", ccol, pp2-pp1)) ; + ASSERT (IMPLIES (pp2 > pp1, Ci [pp1] == j)) ; + + if (!scattered) + { + // scatter the original pattern of column j of L + for (p = p1 ; p < p2 ; p++) + { + Flag [Li [p]] = mark ; + } + scattered = TRUE ; + } + + // scatter column ccol of C (skip first entry, j) + newlnz1 = newlnz ; + for (p = pp1 + 1 ; p < pp2 ; p++) + { + row = Ci [p] ; + if (Flag [row] < mark) + { + // this is a new entry in Lj' + Flag [row] = mark ; + newlnz++ ; + } + } + if (newlnz1 != newlnz) + { + // column ccol of C adds something to column j of L + Set [nsets++] = FLIP (ccol) ; + } + + } + else if (Head [c] == 1) + { + + //---------------------------------------------------------- + // CASE B: c is old, but changed, child of j + // CASE C: new child of j + //---------------------------------------------------------- + + // Head [c] is 1 if col c of L has new entries, + // EMPTY otherwise + Flag [c] = 0 ; + Head [c] = EMPTY ; + + // update: add Lc' + + // column c of L is in Li [pp1 .. pp2-1] + pp1 = Lp [c] ; + pp2 = pp1 + Lnz [c] ; + PRINT1 (("Case B/C: c = "ID"\n", c)) ; + DEBUG (TEMPLATE (dump_col) ("Child", c, pp1, pp2, Li, Lx, + n, Common)) ; + ASSERT (j == Li [pp1 + 1]) ; // j is new parent of c + + if (!scattered) + { + // scatter the original pattern of column j of L + for (p = p1 ; p < p2 ; p++) + { + Flag [Li [p]] = mark ; + } + scattered = TRUE ; + } + + // scatter column c of L (skip first two entries, c and j) + newlnz1 = newlnz ; + for (p = pp1 + 2 ; p < pp2 ; p++) + { + row = Li [p] ; + if (Flag [row] < mark) + { + // this is a new entry in Lj' + Flag [row] = mark ; + newlnz++ ; + } + } + PRINT2 (("\n")) ; + + if (newlnz1 != newlnz) + { + // column c of L adds something to column j of L + Set [nsets++] = c ; + } + } + } + + //------------------------------------------------------------------ + // update the pattern of column j of L + //------------------------------------------------------------------ + + // Column j of L will be in Li/Lx [p1 .. p3-1] + p3 = p1 + newlnz ; + ASSERT (IMPLIES (nsets == 0, newlnz == Lnz [j])) ; + PRINT1 (("p1 "ID" p2 "ID" p3 "ID" nsets "ID"\n", p1, p2, p3,nsets)); + + //------------------------------------------------------------------ + // ensure we have enough space for the longer column + //------------------------------------------------------------------ + + if (nsets > 0 && p3 > Lp [Lnext [j]]) + { + PRINT1 (("Col realloc: j "ID" newlnz "ID"\n", j, newlnz)) ; + if (!CHOLMOD(reallocate_column) (j, newlnz, L, Common)) + { + // out of memory, L is now simplicial symbolic + CHOLMOD(clear_flag) (Common) ; + for (j = 0 ; j <= n ; j++) + { + Head [j] = EMPTY ; + } + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, L->dtype, + Common)) ; + return (FALSE) ; + } + // L->i and L->x may have moved. Column j has moved too + Li = L->i ; + Lx = L->x ; + p1 = Lp [j] ; + p2 = p1 + Lnz [j] ; + p3 = p1 + newlnz ; + } + + //------------------------------------------------------------------ + // create set pointers + //------------------------------------------------------------------ + + for (s = 0 ; s < nsets ; s++) + { + // Pattern of Set s is *(Set_ps1 [s] ... Set_ps2 [s]-1) + c = Set [s] ; + if (c < EMPTY) + { + // column ccol of C, skip first entry (j) + ccol = FLIP (c) ; + pp1 = Cp [ccol] ; + pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; + ASSERT (pp2 - pp1 > 1) ; + Set_ps1 [s] = &(Ci [pp1 + 1]) ; + Set_ps2 [s] = &(Ci [pp2]) ; + PRINT1 (("set "ID" is ccol "ID"\n", s, ccol)) ; + } + else + { + // column c of L, skip first two entries (c and j) + pp1 = Lp [c] ; + pp2 = pp1 + Lnz [c] ; + ASSERT (Lnz [c] > 2) ; + Set_ps1 [s] = &(Li [pp1 + 2]) ; + Set_ps2 [s] = &(Li [pp2]) ; + PRINT1 (("set "ID" is L "ID"\n", s, c)) ; + } + DEBUG (dump_set (s, Set_ps1, Set_ps2, j, n, Common)) ; + } + + //------------------------------------------------------------------ + // multiset merge + //------------------------------------------------------------------ + + // Merge the sets into a single sorted set, Lj'. Before the merge + // starts, column j is located in Li/Lx [p1 ... p2-1] and the + // space Li/Lx [p2 ... p3-1] is empty. p1 is Lp [j], p2 is + // Lp [j] + Lnz [j] (the old length of the column), and p3 is + // Lp [j] + newlnz (the new and longer length of the column). + // + // The sets 0 to nsets-1 are defined by the Set_ps1 and Set_ps2 + // pointers. Set s is located in *(Set_ps1 [s] ... Set_ps2 [s]-1). + // It may be a column of C, or a column of L. All row indices i in + // the sets are in the range i > j and i < n. All sets are sorted. + // + // The merge into column j of L is done in place. + // + // During the merge, p2 and p3 are updated. Li/Lx [p1..p2-1] + // reflects the indices of the old column j of L that are yet to + // be merged into the new column. Entries in their proper place in + // the new column j of L are located in Li/Lx [p3 ... p1+newlnz-1]. + // The merge finishes when p2 == p3. + // + // During the merge, set s consumed as it is merged into column j of + // L. Its unconsumed contents are *(Set_ps1 [s] ... Set_ps2 [s]-1). + // When a set is completely consumed, it is removed from the set of + // sets, and nsets is decremented. + // + // The multiset merge and 2-set merge finishes when p2 == p3. + + PRINT1 (("Multiset merge p3 "ID" p2 "ID" nsets "ID"\n", + p3, p2, nsets)) ; + + while (p3 > p2 && nsets > 1) + { + + #ifndef NDEBUG + PRINT2 (("\nMultiset merge. nsets = "ID"\n", nsets)) ; + PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n", + p1, p2, p3)) ; + for (p = p1 + 1 ; p < p2 ; p++) + { + PRINT2 ((" p: "ID" source row "ID" %g\n", + p, Li[p], Lx[p])) ; + ASSERT (Li [p] > j && Li [p] < n) ; + } + PRINT2 (("---\n")) ; + for (p = p3 ; p < p1 + newlnz ; p++) + { + PRINT2 ((" p: "ID" target row "ID" %g\n", + p, Li[p], Lx[p])) ; + ASSERT (Li [p] > j && Li [p] < n) ; + } + for (s = 0 ; s < nsets ; s++) + { + dump_set (s, Set_ps1, Set_ps2, j, n, Common) ; + } + #endif + + // get the entry at the tail end of source column Lj + row1 = Li [p2 - 1] ; + ASSERT (row1 >= j && p2 >= p1) ; + + // find the largest row in all the sets + maxrow = row1 ; + smax = EMPTY ; + for (s = nsets-1 ; s >= 0 ; s--) + { + ASSERT (Set_ps1 [s] < Set_ps2 [s]) ; + row = *(Set_ps2 [s] - 1) ; + if (row == maxrow) + { + // skip past this entry in set s (it is a duplicate) + Set_ps2 [s]-- ; + if (Set_ps1 [s] == Set_ps2 [s]) + { + // nothing more in this set + nsets-- ; + Set_ps1 [s] = Set_ps1 [nsets] ; + Set_ps2 [s] = Set_ps2 [nsets] ; + if (smax == nsets) + { + // Set smax redefined; it is now this set + smax = s ; + } + } + } + else if (row > maxrow) + { + maxrow = row ; + smax = s ; + } + } + ASSERT (maxrow > j) ; + + // move the row onto the stack of the target column + if (maxrow == row1) + { + // next entry is in Lj, move to the bottom of Lj' + ASSERT (smax == EMPTY) ; + p2-- ; + p3-- ; + Li [p3] = maxrow ; + Lx [p3] = Lx [p2] ; + } + else + { + // new entry in Lj' + ASSERT (smax >= 0 && smax < nsets) ; + Set_ps2 [smax]-- ; + p3-- ; + Li [p3] = maxrow ; + Lx [p3] = 0.0 ; + if (Set_ps1 [smax] == Set_ps2 [smax]) + { + // nothing more in this set + nsets-- ; + Set_ps1 [smax] = Set_ps1 [nsets] ; + Set_ps2 [smax] = Set_ps2 [nsets] ; + PRINT1 (("Set "ID" now empty\n", smax)) ; + } + } + } + + //------------------------------------------------------------------ + // 2-set merge: + //------------------------------------------------------------------ + + // This the same as the multi-set merge, except there is only one + // set s = 0 left. The source column j and the set 0 are being + // merged into the target column j. + + if (nsets > 0) + { + ps1 = Set_ps1 [0] ; + ps2 = Set_ps2 [0] ; + } + + while (p3 > p2) + { + + #ifndef NDEBUG + PRINT2 (("\n2-set merge.\n")) ; + ASSERT (nsets == 1) ; + PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n", + p1, p2, p3)) ; + for (p = p1 + 1 ; p < p2 ; p++) + { + PRINT2 ((" p: "ID" source row "ID" %g\n", + p, Li[p], Lx[p])) ; + ASSERT (Li [p] > j && Li [p] < n) ; + } + PRINT2 (("---\n")) ; + for (p = p3 ; p < p1 + newlnz ; p++) + { + PRINT2 ((" p: "ID" target row "ID" %g\n", + p, Li[p], Lx[p])) ; + ASSERT (Li [p] > j && Li [p] < n) ; + } + dump_set (0, Set_ps1, Set_ps2, j, n, Common) ; + #endif + + if (p2 == p1 + 1) + { + // the top of Lj is empty; copy the set and quit + while (p3 > p2) + { + // new entry in Lj' + row = *(--ps2) ; + p3-- ; + Li [p3] = row ; + Lx [p3] = 0.0 ; + } + } + else + { + // get the entry at the tail end of Lj + row1 = Li [p2 - 1] ; + ASSERT (row1 > j && row1 < n) ; + // get the entry at the tail end of the incoming set + ASSERT (ps1 < ps2) ; + row = *(ps2-1) ; + ASSERT (row > j && row1 < n) ; + // move the larger of the two entries to the target set + if (row1 >= row) + { + // next entry is in Lj, move to the bottom + if (row1 == row) + { + // skip past this entry in the set + ps2-- ; + } + p2-- ; + p3-- ; + Li [p3] = row1 ; + Lx [p3] = Lx [p2] ; + } + else + { + // new entry in Lj' + ps2-- ; + p3-- ; + Li [p3] = row ; + Lx [p3] = 0.0 ; + } + } + } + + //------------------------------------------------------------------ + // The new column j of L is now in Li/Lx [p1 ... p2-1] + //------------------------------------------------------------------ + + p2 = p1 + newlnz ; + DEBUG (TEMPLATE (dump_col) ("After merge: ", j, p1, p2, Li, Lx, n, + Common)) ; + + fl += Path [path].rank * (6 + 4 * (double) newlnz) ; + + //------------------------------------------------------------------ + // clear Flag; original pattern of column j L no longer marked + //------------------------------------------------------------------ + + mark = CHOLMOD(clear_flag) (Common) ; + scattered = FALSE ; + + //------------------------------------------------------------------ + // find the new parent + //------------------------------------------------------------------ + + Int newparent = (newlnz > 1) ? (Li [p1 + 1]) : EMPTY ; + PRINT1 (("\nNew parent, Lnz: "ID": "ID" "ID"\n", + j, newparent,newlnz)); + ASSERT (oldparent == EMPTY || newparent <= oldparent) ; + + //------------------------------------------------------------------ + // go to the next node in the path + //------------------------------------------------------------------ + + // path moves to (j,nextj) unless j is a root + nextj = (newparent == EMPTY) ? n : newparent ; + + // place path at head of list for nextj, or terminate the path + PRINT1 (("\n j = "ID" nextj = "ID"\n\n", j, nextj)) ; + Path [path].c = j ; + if (nextj < n) + { + // put path on link list of pending paths at column nextj + Path [path].next = Head [nextj] ; + Path [path].pending = nextj ; + Head [nextj] = path ; + PRINT1 (("Path "ID" continues to ("ID","ID"). Rank "ID"\n", + path, Path [path].c, nextj, Path [path].rank)) ; + } + else + { + // path has ended here, at a root + Path [path].next = EMPTY ; + Path [path].pending = EMPTY ; + Path [path].end = j ; + PRINT1 (("Path "ID" ends at root ("ID"). Rank "ID"\n", + path, Path [path].end, Path [path].rank)) ; + } + + // The link list Head [j] can now be emptied. Set Head [j] to 1 + // if column j has changed (it is no longer used as a link list). + PRINT1 (("column "ID", oldlnz = "ID"\n", j, Lnz [j])) ; + Head [j] = (Lnz [j] != newlnz) ? 1 : EMPTY ; + Lnz [j] = newlnz ; + PRINT1 (("column "ID", newlnz = "ID"\n", j, newlnz)) ; + DEBUG (TEMPLATE (dump_col) ("New", j, p1, p2, Li, Lx, n, Common)) ; + + // move to the next column + if (k == Path [path].rank) + { + // only one path left + j = nextj ; + } + else + { + // The current path is moving from column j to column nextj + // (nextj is n if the path has ended). However, there may be + // other paths pending in columns j+1 to nextj-1. There are + // two methods for looking for the next column with a pending + // update. The first one looks at all columns j+1 to nextj-1 + // for a non-empty link list. This can be costly if j and + // nextj differ by a large amount (it can be O(n), but this + // entire routine may take Omega(1) time). The second method + // looks at all paths and finds the smallest column at which any + // path is pending. It takes O(# of paths), which is bounded + // by 23: one for each column of C (up to 8), and then 15 for a + // balanced binary tree with 8 leaves. However, if j and + // nextj differ by a tiny amount (nextj is often j+1 near + // the end of the matrix), looking at columns j+1 to nextj + // would be faster. Both methods give the same answer. + + if (nextj - j < npaths) + { + // there are fewer columns to search than paths + PRINT1 (("check j="ID" to nextj="ID"\n", j, nextj)) ; + for (j2 = j + 1 ; j2 < nextj ; j2++) + { + PRINT1 (("check j="ID" "ID"\n", j2, Head [j2])) ; + if (Head [j2] != EMPTY) + { + PRINT1 (("found, j="ID"\n", j2)) ; + ASSERT (Path [Head [j2]].pending == j2) ; + break ; + } + } + } + else + { + // there are fewer paths than columns to search + j2 = nextj ; + for (kk = 0 ; kk < npaths ; kk++) + { + jj = Path [kk].pending ; + PRINT2 (("Path "ID" pending at "ID"\n", kk, jj)) ; + if (jj != EMPTY) j2 = MIN (j2, jj) ; + } + } + j = j2 ; + } + } + + // ensure workspaces are back to the values required on input + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; + + //---------------------------------------------------------------------- + // depth-first-search of tree to order the paths + //---------------------------------------------------------------------- + + // create lists of child paths + PRINT1 (("\n\nDFS search:\n\n")) ; + for (path = 0 ; path < npaths ; path++) + { + Path [path].c = EMPTY ; // first child of path + Path [path].next = EMPTY ; // next sibling of path + Path [path].order = EMPTY ; // path is not ordered yet + Path [path].wfirst = EMPTY ; // 1st column of W not found yet + + #ifndef NDEBUG + j = Path [path].start ; + PRINT1 (("Path "ID" : start "ID" end "ID" parent "ID" ccol "ID"\n", + path, j, Path [path].end, Path [path].parent, Path [path].ccol)) ; + for ( ; ; ) + { + PRINT1 ((" column "ID"\n", j)) ; + ASSERT (j == EMPTY || (j >= 0 && j < n)) ; + if (j == Path [path].end) + { + break ; + } + ASSERT (j >= 0 && j < n) ; + j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ; + } + #endif + } + + for (path = 0 ; path < npaths ; path++) + { + p = Path [path].parent ; // add path to child list of parent + if (p != EMPTY) + { + ASSERT (p < npaths) ; + Path [path].next = Path [p].c ; + Path [p].c = path ; + } + } + + path_order = k ; + w_order = 0 ; + for (path = npaths-1 ; path >= 0 ; path--) + { + if (Path [path].order == EMPTY) + { + // this path is the root of a subtree of Tbar + PRINT1 (("Root path "ID"\n", path)) ; + ASSERT (path >= k) ; + dfs (Path, k, path, &path_order, &w_order, 0, npaths) ; + } + } + ASSERT (path_order == npaths) ; + ASSERT (w_order == k) ; + + // reorder the paths + for (path = 0 ; path < npaths ; path++) + { + // old order is path, new order is Path [path].order + OrderedPath [Path [path].order] = Path [path] ; + } + + #ifndef NDEBUG + for (path = 0 ; path < npaths ; path++) + { + PRINT1 (("Ordered Path "ID": start "ID" end "ID" wfirst "ID" rank " + ""ID" ccol "ID"\n", path, OrderedPath [path].start, + OrderedPath [path].end, OrderedPath [path].wfirst, + OrderedPath [path].rank, OrderedPath [path].ccol)) ; + if (path < k) + { + ASSERT (OrderedPath [path].ccol >= 0) ; + } + else + { + ASSERT (OrderedPath [path].ccol == EMPTY) ; + } + } + #endif + + //---------------------------------------------------------------------- + // numeric update/downdate for all paths + //---------------------------------------------------------------------- + + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, L->dtype, Common)) ; + + switch (wdim) + { + case 1: + UPDOWN (1,r) (update, C, k, L, W, OrderedPath, npaths, mask, + maskmark, Common) ; + break ; + case 2: + UPDOWN (2,r) (update, C, k, L, W, OrderedPath, npaths, mask, + maskmark, Common) ; + break ; + case 4: + UPDOWN (4,r) (update, C, k, L, W, OrderedPath, npaths, mask, + maskmark, Common) ; + break ; + case 8: + UPDOWN (8,r) (update, C, k, L, W, OrderedPath, npaths, mask, + maskmark, Common) ; + break ; + } + + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, L->dtype, Common)) ; + } + + //-------------------------------------------------------------------------- + // update/downdate the forward solve + //-------------------------------------------------------------------------- + + if (do_solve) + { + // We now have DeltaB += Lold (:,j) * X (j) for all columns j in union + // of all paths seen during the entire rank-cncol update/downdate. For + // each j in path, do DeltaB -= Lnew (:,j)*DeltaB(j) + // in topological order. + + #ifndef NDEBUG + PRINT1 (("\ndo_solve, DeltaB + Lold(:,Path)*X(Path):\n")) ; + for (i = 0 ; i < n ; i++) + { + PRINT1 (("do_solve: "ID" %30.20e\n", i, Nx [i])) ; + } + #endif + + // Note that the downdate, if it deleted entries, would need to compute + // the Stack prior to doing any downdates. + + // find the union of all the paths in the new L + top = n ; // "top" is stack pointer, not a row or column index + for (ccol = 0 ; ccol < cncol ; ccol++) + { + + //------------------------------------------------------------------ + // j = first row index of C (:,ccol) + //------------------------------------------------------------------ + + pp1 = Cp [ccol] ; + pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ; + if (pp2 > pp1) + { + // Column ccol of C has at least one entry. + j = Ci [pp1] ; + } + else + { + // Column ccol of C is empty + j = n-1 ; + } + PRINT1 (("\ndo_solve: ccol= "ID"\n", ccol)) ; + ASSERT (j >= 0 && j < n) ; + len = 0 ; + + //------------------------------------------------------------------ + // find the new rowmark + //------------------------------------------------------------------ + + // Each column of C can redefine the region of L that takes part in + // the update/downdate of the triangular solve Lx=b. If + // i = colmark [ccol] for column C(:,ccol), then i = rowmark [j] is + // redefined for all columns along the path modified by C(:,ccol). + // If more than one column modifies any given column j of L, then + // the rowmark of j is determined by the colmark of the least- + // numbered column that affects column j. That is, if both + // C(:,ccol1) and C(:,ccol2) affect column j of L, then + // rowmark [j] = colmark [MIN (ccol1, ccol2)]. + // + // rowmark [j] is not modified if rowmark or colmark are NULL, + // or if colmark [ccol] is EMPTY. + + botrow = (use_colmark) ? (colmark [ccol]) : EMPTY ; + + //------------------------------------------------------------------ + // traverse from j towards root, stopping if node already visited + //------------------------------------------------------------------ + + while (j != EMPTY && Flag [j] < mark) + { + PRINT1 (("do_solve: subpath j= "ID"\n", j)) ; + ASSERT (j >= 0 && j < n) ; + Stack [len++] = j ; // place j on the stack + Flag [j] = mark ; // flag j as visited + + // if using colmark, mark column j with botrow + ASSERT (Li [Lp [j]] == j) ; // diagonal is always present + if (use_colmark) + { + Li [Lp [j]] = botrow ; // use the space for botrow + } + + // go up the tree, to the parent of j + j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ; + } + + //------------------------------------------------------------------ + // move the path down to the bottom of the stack + //------------------------------------------------------------------ + + ASSERT (len <= top) ; + while (len > 0) + { + Stack [--top] = Stack [--len] ; + } + } + + #ifndef NDEBUG + // Union of paths now in Stack [top..n-1] in topological order + PRINT1 (("\nTopological order:\n")) ; + for (i = top ; i < n ; i++) + { + PRINT1 (("column "ID" in full path\n", Stack [i])) ; + } + #endif + + // Do the forward solve for the full path part of L + for (m = top ; m < n ; m++) + { + j = Stack [m] ; + ASSERT (j >= 0 && j < n) ; + PRINT1 (("do_solve: path j= "ID"\n", j)) ; + p1 = Lp [j] ; + lnz = Lnz [j] ; + p2 = p1 + lnz ; + Real xj = Nx [j] ; + + // copy new solution onto old one, for all cols in full path + Xx [j] = xj ; + Nx [j] = 0. ; + + // DeltaB -= Lnew (j+1:botrow-1,j) * deltab(j) + if (use_colmark) + { + botrow = Li [p1] ; // get botrow + Li [p1] = j ; // restore diagonal entry + for (p = p1 + 1 ; p < p2 ; p++) + { + i = Li [p] ; + if (i >= botrow) break ; + Nx [i] -= Lx [p] * xj ; + } + } + else + { + for (p = p1 + 1 ; p < p2 ; p++) + { + Nx [Li [p]] -= Lx [p] * xj ; + } + } + } + + // clear the Flag + mark = CHOLMOD(clear_flag) (Common) ; + } + + //-------------------------------------------------------------------------- + // successful update/downdate + //-------------------------------------------------------------------------- + + Common->modfl = fl ; + DEBUG (for (j = 0 ; j < n ; j++) ASSERT (IMPLIES (do_solve, Nx[j] == 0.))) ; + return (TRUE) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Partition/cholmod_camd.c b/CHOLMOD/Partition/cholmod_camd.c index 716410df7f..a53aeab1c0 100644 --- a/CHOLMOD/Partition/cholmod_camd.c +++ b/CHOLMOD/Partition/cholmod_camd.c @@ -2,82 +2,80 @@ // CHOLMOD/Partition/cholmod_camd: CHOLMOD interface to CAMD //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the CAMD ordering routine. Orders A if the matrix is - * symmetric. On output, Perm [k] = i if row/column i of A is the kth - * row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation. - * - * If A is unsymmetric, cholmod_camd orders A*A'. On output, Perm [k] = i if - * row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to - * A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is - * ordered. - * - * Computes the flop count for a subsequent LL' factorization, the number - * of nonzeros in L, and the number of nonzeros in the matrix ordered (A, - * A*A' or A(:,f)*A(:,f)'). - * - * workspace: Iwork (4*nrow). Head (nrow). - * - * Allocates a temporary copy of A+A' or A*A' (with - * both upper and lower triangular parts) as input to CAMD. - * Also allocates 3*(n+1) additional integer workspace (not in Common). - * - * Supports any xtype (pattern, real, complex, or zomplex) - */ +// CHOLMOD interface to the CAMD ordering routine. Orders A if the matrix is +// symmetric. On output, Perm [k] = i if row/column i of A is the kth +// row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation. +// +// If A is unsymmetric, cholmod_camd orders A*A'. On output, Perm [k] = i if +// row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to +// A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is +// ordered. +// +// Computes the flop count for a subsequent LL' factorization, the number +// of nonzeros in L, and the number of nonzeros in the matrix ordered (A, +// A*A' or A(:,f)*A(:,f)'). +// +// workspace: Iwork (4*nrow). Head (nrow). +// +// Allocates a temporary copy of A+A' or A*A' (with +// both upper and lower triangular parts) as input to CAMD. +// Also allocates 3*(n+1) additional integer workspace (not in Common). +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCAMD #include "camd.h" -#if (CAMD_VERSION < CAMD_VERSION_CODE (2,0)) -#error "CAMD v2.0 or later is required" +#if (CAMD_VERSION < CAMD_VERSION_CODE (3,0)) +#error "CAMD v3.0 or later is required" #endif -/* ========================================================================== */ -/* === cholmod_camd ========================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_camd +//------------------------------------------------------------------------------ int CHOLMOD(camd) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - Int *Cmember, /* size nrow. see cholmod_ccolamd.c for description.*/ - /* ---- output ---- */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + Int *Cmember, // size nrow. see cholmod_ccolamd.c for description. + // output: + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + double Info [CAMD_INFO], Control2 [CAMD_CONTROL], *Control ; Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Next, *BucketSet, - *Work3n, *p ; + *Work3n, *p ; cholmod_sparse *C ; Int j, n, cnz ; - size_t s ; - int ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; n = A->nrow ; - /* s = 4*n */ - s = CHOLMOD(mult_size_t) (n, 4, &ok) ; + // s = 4*nrow + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 4, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } RETURN_IF_NULL (Perm, FALSE) ; @@ -85,129 +83,131 @@ int CHOLMOD(camd) Common->status = CHOLMOD_OK ; if (n == 0) { - /* nothing to do */ - Common->fl = 0 ; - Common->lnz = 0 ; - Common->anz = 0 ; - return (TRUE) ; + // nothing to do + Common->fl = 0 ; + Common->lnz = 0 ; + Common->anz = 0 ; + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - /* cholmod_analyze has allocated Cmember at Common->Iwork + 5*n+uncol, and - * CParent at Common->Iwork + 4*n+uncol, where uncol is 0 if A is symmetric - * or A->ncol otherwise. Thus, only the first 4n integers in Common->Iwork - * can be used here. */ + // cholmod_analyze has allocated Cmember at Common->Iwork + 5*n+uncol, and + // CParent at Common->Iwork + 4*n+uncol, where uncol is 0 if A is symmetric + // or A->ncol otherwise. Thus, only the first 4n integers in Common->Iwork + // can be used here. - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } p = Common->Iwork ; - Degree = p ; p += n ; /* size n */ - Elen = p ; p += n ; /* size n */ - Len = p ; p += n ; /* size n */ - Nv = p ; p += n ; /* size n */ + Degree = p ; p += n ; // size n + Elen = p ; p += n ; // size n + Len = p ; p += n ; // size n + Nv = p ; p += n ; // size n Work3n = CHOLMOD(malloc) (n+1, 3*sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } p = Work3n ; - Next = p ; p += n ; /* size n */ - Wi = p ; p += (n+1) ; /* size n+1 */ - BucketSet = p ; /* size n */ + Next = p ; p += n ; // size n + Wi = p ; p += (n+1) ; // size n+1 + BucketSet = p ; // size n - Head = Common->Head ; /* size n+1 */ + Head = Common->Head ; // size n+1 - /* ---------------------------------------------------------------------- */ - /* construct the input matrix for CAMD */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct the input matrix for CAMD + //-------------------------------------------------------------------------- if (A->stype == 0) { - /* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */ - C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ; + // C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C + C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ; } else { - /* C = A+A', but use only the upper triangular part of A if A->stype = 1 - * and only the lower part of A if A->stype = -1. Add extra space of - * nnz(C)/2+n to C. */ - C = CHOLMOD(copy) (A, 0, -2, Common) ; + // C = A+A', but use only the upper triangular part of A if A->stype = 1 + // and only the lower part of A if A->stype = -1. Add extra space of + // nnz(C)/2+n to C. + C = CHOLMOD(copy) (A, 0, -2, Common) ; } if (Common->status < CHOLMOD_OK) { - /* out of memory, fset invalid, or other error */ - CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ; - return (FALSE) ; + // out of memory, fset invalid, or other error + CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ; + return (FALSE) ; } Cp = C->p ; for (j = 0 ; j < n ; j++) { - Len [j] = Cp [j+1] - Cp [j] ; + Len [j] = Cp [j+1] - Cp [j] ; } - /* C does not include the diagonal, and both upper and lower parts. - * Common->anz includes the diagonal, and just the lower part of C */ + // C does not include the diagonal, and both upper and lower parts. + // Common->anz includes the diagonal, and just the lower part of C cnz = Cp [n] ; Common->anz = cnz / 2 + n ; - /* ---------------------------------------------------------------------- */ - /* order C using CAMD */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order C using CAMD + //-------------------------------------------------------------------------- - /* get parameters */ + // get parameters if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { - /* use CAMD defaults */ - Control = NULL ; + // use CAMD defaults + Control = NULL ; } else { - Control = Control2 ; - Control [CAMD_DENSE] = Common->method [Common->current].prune_dense ; - Control [CAMD_AGGRESSIVE] = Common->method [Common->current].aggressive; + Control = Control2 ; + Control [CAMD_DENSE] = Common->method [Common->current].prune_dense ; + Control [CAMD_AGGRESSIVE] = Common->method [Common->current].aggressive; } -#if defined ( CHOLMOD_INT64 ) - /* DEBUG (camd_l_debug_init ("cholmod_l_camd")) ; */ + #if defined ( CHOLMOD_INT64 ) + // DEBUG (camd_l_debug_init ("cholmod_l_camd")) ; camd_l2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, - Degree, Wi, Control, Info, Cmember, BucketSet) ; -#else - /* DEBUG (camd_debug_init ("cholmod_camd")) ; */ + Degree, Wi, Control, Info, Cmember, BucketSet) ; + #else + // DEBUG (camd_debug_init ("cholmod_camd")) ; camd_2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, - Degree, Wi, Control, Info, Cmember, BucketSet) ; -#endif + Degree, Wi, Control, Info, Cmember, BucketSet) ; + #endif - /* LL' flop count. Need to subtract n for LL' flop count. Note that this - * is a slight upper bound which is often exact (see CAMD/Source/camd_2.c - * for details). cholmod_analyze computes an exact flop count and - * fill-in. */ + // LL' flop count. Need to subtract n for LL' flop count. Note that this + // is a slight upper bound which is often exact (see CAMD/Source/camd_2.c + // for details). cholmod_analyze computes an exact flop count and + // fill-in. Common->fl = Info [CAMD_NDIV] + 2 * Info [CAMD_NMULTSUBS_LDL] + n ; - /* Info [CAMD_LNZ] excludes the diagonal */ + // Info [CAMD_LNZ] excludes the diagonal Common->lnz = n + Info [CAMD_LNZ] ; - /* ---------------------------------------------------------------------- */ - /* free the CAMD workspace and clear the persistent workspace in Common */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the CAMD workspace and clear the persistent workspace in Common + //-------------------------------------------------------------------------- ASSERT (IMPLIES (Common->status == CHOLMOD_OK, - CHOLMOD(dump_perm) (Perm, n, n, "CAMD2 perm", Common))) ; + CHOLMOD(dump_perm) (Perm, n, n, "CAMD2 perm", Common))) ; CHOLMOD(free_sparse) (&C, Common) ; for (j = 0 ; j <= n ; j++) { - Head [j] = EMPTY ; + Head [j] = EMPTY ; } CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ; return (TRUE) ; } + #endif + diff --git a/CHOLMOD/Partition/cholmod_ccolamd.c b/CHOLMOD/Partition/cholmod_ccolamd.c index 7251abd7df..ac195d861d 100644 --- a/CHOLMOD/Partition/cholmod_ccolamd.c +++ b/CHOLMOD/Partition/cholmod_ccolamd.c @@ -2,38 +2,37 @@ // CHOLMOD/Partition/cholmod_ccolamd: CHOLMOD interface to CCOLAMD //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the CCOLAMD ordering routine. Finds a permutation - * p such that the Cholesky factorization of PAA'P' is sparser than AA'. - * The column etree is found and postordered, and the ccolamd ordering is then - * combined with its postordering. A must be unsymmetric. - * - * workspace: Iwork (MAX (nrow,ncol)) - * Allocates a copy of its input matrix, which is - * then used as CCOLAMD's workspace. - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// CHOLMOD interface to the CCOLAMD ordering routine. Finds a permutation +// p such that the Cholesky factorization of PAA'P' is sparser than AA'. +// The column etree is found and postordered, and the ccolamd ordering is then +// combined with its postordering. A must be unsymmetric. +// +// workspace: Iwork (MAX (nrow,ncol)) +// Allocates a copy of its input matrix, which is +// then used as CCOLAMD's workspace. +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCAMD #include "ccolamd.h" -#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (2,5)) -#error "CCOLAMD v2.0 or later is required" +#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (3,0)) +#error "CCOLAMD v3.0 or later is required" #endif -/* ========================================================================== */ -/* === ccolamd_interface ==================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// ccolamd_interface +//------------------------------------------------------------------------------ -/* Order with ccolamd */ +// Order with ccolamd static int ccolamd_interface ( @@ -54,148 +53,149 @@ static int ccolamd_interface nrow = A->nrow ; ncol = A->ncol ; - /* ---------------------------------------------------------------------- */ - /* copy (and transpose) the input matrix A into the ccolamd workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy (and transpose) the input matrix A into the ccolamd workspace + //-------------------------------------------------------------------------- - /* C = A (:,f)', which also packs A if needed. */ - /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset non-NULL) */ + // C = A (:,f)', which also packs A if needed. + // workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset non-NULL) ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ; - /* ---------------------------------------------------------------------- */ - /* order the matrix (destroys the contents of C->i and C->p) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order the matrix (destroys the contents of C->i and C->p) + //-------------------------------------------------------------------------- - /* get parameters */ -#if defined ( CHOLMOD_INT64 ) + // get parameters + #if defined ( CHOLMOD_INT64 ) ccolamd_l_set_defaults (knobs) ; -#else + #else ccolamd_set_defaults (knobs) ; -#endif + #endif if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { - /* this is the CHOLMOD default, not the CCOLAMD default */ - knobs [CCOLAMD_DENSE_ROW] = -1 ; + // this is the CHOLMOD default, not the CCOLAMD default + knobs [CCOLAMD_DENSE_ROW] = -1 ; } else { - /* get the knobs from the Common parameters */ - knobs [CCOLAMD_DENSE_COL] =Common->method[Common->current].prune_dense ; - knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense2; - knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; - knobs [CCOLAMD_LU] =Common->method[Common->current].order_for_lu; + // get the knobs from the Common parameters + knobs [CCOLAMD_DENSE_COL] =Common->method[Common->current].prune_dense ; + knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense2; + knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; + knobs [CCOLAMD_LU] =Common->method[Common->current].order_for_lu; } if (ok) { -#if defined ( CHOLMOD_INT64 ) - ccolamd_l (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; -#else - ccolamd (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; -#endif - - ok = stats [CCOLAMD_STATUS] ; - - ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; - /* permutation returned in C->p, if the ordering succeeded */ - Cp = C->p ; - for (k = 0 ; k < nrow ; k++) - { - Perm [k] = Cp [k] ; - } + #if defined ( CHOLMOD_INT64 ) + ccolamd_l (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; + #else + ccolamd (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ; + #endif + + ok = stats [CCOLAMD_STATUS] ; + + ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; + // permutation returned in C->p, if the ordering succeeded + Cp = C->p ; + for (k = 0 ; k < nrow ; k++) + { + Perm [k] = Cp [k] ; + } } return (ok) ; } +//------------------------------------------------------------------------------ +// cholmod_ccolamd +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_ccolamd ====================================================== */ -/* ========================================================================== */ - -/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */ +// Order AA' or A(:,f)*A(:,f)' using CCOLAMD. int CHOLMOD(ccolamd) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - Int *Cmember, /* size A->nrow. Cmember [i] = c if row i is in the - * constraint set c. c must be >= 0. The # of - * constraint sets is max (Cmember) + 1. If Cmember is - * NULL, then it is interpretted as Cmember [i] = 0 for - * all i */ - /* ---- output --- */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + Int *Cmember, // size A->nrow. Cmember [i] = c if row i is in the + // constraint set c. c must be >= 0. The # of + // constraint sets is max (Cmember) + 1. If Cmember is + // NULL, then it is interpretted as Cmember [i] = 0 for + // all i. + // output: + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + cholmod_sparse *C ; Int ok, nrow, ncol ; size_t alen ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ - RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Perm, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->stype != 0) { - ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- nrow = A->nrow ; ncol = A->ncol ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- -#if defined ( CHOLMOD_INT64 ) + #if defined ( CHOLMOD_INT64 ) alen = ccolamd_l_recommended (A->nzmax, ncol, nrow) ; -#else + #else alen = ccolamd_recommended (A->nzmax, ncol, nrow) ; -#endif + #endif if (alen == 0) { - ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; + return (FALSE) ; } CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, - CHOLMOD_PATTERN, Common) ; + CHOLMOD_PATTERN + A->dtype, Common) ; - /* ---------------------------------------------------------------------- */ - /* order with ccolamd */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order with ccolamd + //-------------------------------------------------------------------------- ok = ccolamd_interface (A, alen, Perm, Cmember, fset, fsize, C, Common) ; - /* ---------------------------------------------------------------------- */ - /* free the workspace and return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the workspace and return result + //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&C, Common) ; return (ok) ; } + #endif + diff --git a/CHOLMOD/Partition/cholmod_csymamd.c b/CHOLMOD/Partition/cholmod_csymamd.c index 6990d34991..af682c827e 100644 --- a/CHOLMOD/Partition/cholmod_csymamd.c +++ b/CHOLMOD/Partition/cholmod_csymamd.c @@ -2,55 +2,54 @@ // CHOLMOD/Partition/cholmod_csymamd: CHOLMOD interface to CSYMAMD //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the CSYMAMD ordering routine. Finds a permutation - * p such that the Cholesky factorization of PAP' is sparser than A. - * The column etree is found and postordered, and the CSYMAMD - * ordering is then combined with its postordering. If A is unsymmetric, - * A+A' is ordered (A must be square). - * - * workspace: Head (nrow+1) - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// CHOLMOD interface to the CSYMAMD ordering routine. Finds a permutation +// p such that the Cholesky factorization of PAP' is sparser than A. +// The column etree is found and postordered, and the CSYMAMD +// ordering is then combined with its postordering. If A is unsymmetric, +// A+A' is ordered (A must be square). +// +// workspace: Head (nrow+1) +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NCAMD #include "ccolamd.h" -#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (2,5)) -#error "CCOLAMD v2.0 or later is required" +#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (3,0)) +#error "CCOLAMD v3.0 or later is required" #endif -/* ========================================================================== */ -/* === cholmod_csymamd ====================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_csymamd +//------------------------------------------------------------------------------ int CHOLMOD(csymamd) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - /* ---- output --- */ - Int *Cmember, /* size nrow. see cholmod_ccolamd.c for description */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + // output: + Int *Cmember, // size nrow. see cholmod_ccolamd.c for description + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + double knobs [CCOLAMD_KNOBS] ; Int *perm, *Head ; Int ok, i, nrow, stats [CCOLAMD_STATS] ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ - RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Perm, FALSE) ; @@ -59,33 +58,33 @@ int CHOLMOD(csymamd) if (A->nrow != A->ncol || !(A->packed)) { - ERROR (CHOLMOD_INVALID, "matrix must be square and packed") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "matrix must be square and packed") ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- nrow = A->nrow ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* order the matrix (does not affect A->p or A->i) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // order the matrix (does not affect A->p or A->i) + //-------------------------------------------------------------------------- - perm = Common->Head ; /* size nrow+1 (i/l/l) */ + perm = Common->Head ; // size nrow+1 - /* get parameters */ + // get parameters #if defined ( CHOLMOD_INT64 ) ccolamd_l_set_defaults (knobs) ; #else @@ -93,9 +92,9 @@ int CHOLMOD(csymamd) #endif if (Common->current >= 0 && Common->current < CHOLMOD_MAXMETHODS) { - /* get the knobs from the Common parameters */ - knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense ; - knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; + // get the knobs from the Common parameters + knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense ; + knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ; } { void * (*calloc_func) (size_t, size_t) ; @@ -104,42 +103,44 @@ int CHOLMOD(csymamd) free_func = SuiteSparse_config_free_func_get ( ) ; #if defined ( CHOLMOD_INT64 ) - csymamd_l (nrow, A->i, A->p, perm, knobs, stats, + csymamd_l (nrow, A->i, A->p, perm, knobs, stats, calloc_func, free_func, Cmember, A->stype) ; #else - csymamd (nrow, A->i, A->p, perm, knobs, stats, + csymamd (nrow, A->i, A->p, perm, knobs, stats, calloc_func, free_func, Cmember, A->stype) ; #endif - ok = stats [CCOLAMD_STATUS] ; + ok = stats [CCOLAMD_STATUS] ; } if (ok == CCOLAMD_ERROR_out_of_memory) { - ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; + ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; - /* ---------------------------------------------------------------------- */ - /* free the workspace and return result */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free the workspace and return result + //-------------------------------------------------------------------------- - /* permutation returned in perm [0..n-1] */ + // permutation returned in perm [0..n-1] for (i = 0 ; i < nrow ; i++) { - Perm [i] = perm [i] ; + Perm [i] = perm [i] ; } - /* clear Head workspace (used for perm, in csymamd): */ + // clear Head workspace (used for perm, in csymamd): Head = Common->Head ; for (i = 0 ; i <= nrow ; i++) { - Head [i] = EMPTY ; + Head [i] = EMPTY ; } return (ok) ; } + #endif + diff --git a/CHOLMOD/Partition/cholmod_l_camd.c b/CHOLMOD/Partition/cholmod_l_camd.c index d4c3809802..d5e2d02dff 100644 --- a/CHOLMOD/Partition/cholmod_l_camd.c +++ b/CHOLMOD/Partition/cholmod_l_camd.c @@ -2,7 +2,7 @@ // CHOLMOD/Partition/cholmod_l_camd.c: int64_t version of cholmod_camd //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Partition/cholmod_l_ccolamd.c b/CHOLMOD/Partition/cholmod_l_ccolamd.c index 56faa504de..dee953b526 100644 --- a/CHOLMOD/Partition/cholmod_l_ccolamd.c +++ b/CHOLMOD/Partition/cholmod_l_ccolamd.c @@ -2,7 +2,7 @@ // CHOLMOD/Partition/cholmod_l_ccolamd.c: int64_t version of cholmod_ccolamd //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Partition/cholmod_l_csymamd.c b/CHOLMOD/Partition/cholmod_l_csymamd.c index 2ffd4dd501..e75d293793 100644 --- a/CHOLMOD/Partition/cholmod_l_csymamd.c +++ b/CHOLMOD/Partition/cholmod_l_csymamd.c @@ -2,7 +2,7 @@ // CHOLMOD/Partition/cholmod_l_csymamd.c: int64_t version of cholmod_csymamd //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Partition/cholmod_l_metis.c b/CHOLMOD/Partition/cholmod_l_metis.c index f529e47ccd..ae857fe399 100644 --- a/CHOLMOD/Partition/cholmod_l_metis.c +++ b/CHOLMOD/Partition/cholmod_l_metis.c @@ -2,7 +2,7 @@ // CHOLMOD/Partition/cholmod_l_metis.c: int64_t version of cholmod_metis //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Partition/cholmod_l_nesdis.c b/CHOLMOD/Partition/cholmod_l_nesdis.c index 60572c9cb6..6f0eefff58 100644 --- a/CHOLMOD/Partition/cholmod_l_nesdis.c +++ b/CHOLMOD/Partition/cholmod_l_nesdis.c @@ -2,7 +2,7 @@ // CHOLMOD/Partition/cholmod_l_nesdis.c: int64_t version of cholmod_nesdis //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/CHOLMOD/Partition/cholmod_metis.c b/CHOLMOD/Partition/cholmod_metis.c index eb1ff4a63e..8c8a3943a2 100644 --- a/CHOLMOD/Partition/cholmod_metis.c +++ b/CHOLMOD/Partition/cholmod_metis.c @@ -2,53 +2,52 @@ // CHOLMOD/Partition/cholmod_metis: CHOLMOD interface to METIS //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD interface to the METIS package (Version 5.1.0): - * - * cholmod_metis_bisector: - * - * Wrapper for the METIS node separator function, - * METIS_ComputeVertexSeparator (METIS 5.1). - * - * Finds a set of nodes that partitions the graph into two parts. METIS - * 4.0 (the function METIS_ComputeVertexSeparator) allowed for edge - * weights to be passed to the bisector. This feature is removed in METIS - * 5.1. CHOLMOD itself does not rely on this feature (it calls the METIS - * bisector with edge weights of all 1s). However, user code can call - * cholmod_metis_bisector directly, and pass in edge weights. If you use - * METIS 5.1, these edge weights are now ignored; if you pass a non-NULL - * entry for edge weights, an error will be returned. - * - * cholmod_metis: - * - * Wrapper for METIS_NodeND, METIS's own nested dissection algorithm. - * Typically faster than cholmod_nested_dissection, mostly because it - * uses minimum degree on just the leaves of the separator tree, rather - * than the whole matrix. - * - * Note that METIS does not return an error if it runs out of memory. Instead, - * it terminates the program. This interface attempts to avoid that problem - * by preallocating space that should be large enough for any memory allocations - * within METIS, and then freeing that space, just before the call to METIS. - * While this is not guaranteed to work, it is very unlikely to fail. If you - * encounter this problem, increase Common->metis_memory. If you don't mind - * having your program terminated, set Common->metis_memory to zero (a value of - * 2.0 is usually safe). Several other METIS workarounds are made in the - * routines in this file. See the description of metis_memory_ok, just below, - * for more details. - * - * FUTURE WORK: interfaces to other partitioners (CHACO, SCOTCH, JOSTLE, ... ) - * - * workspace: several size-nz and size-n temporary arrays. Uses no workspace - * in Common. - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// CHOLMOD interface to the METIS package (Version 5.1.0): +// +// cholmod_metis_bisector: +// +// Wrapper for the METIS node separator function, +// METIS_ComputeVertexSeparator (METIS 5.1). +// +// Finds a set of nodes that partitions the graph into two parts. METIS +// 4.0 (the function METIS_ComputeVertexSeparator) allowed for edge +// weights to be passed to the bisector. This feature is removed in METIS +// 5.1. CHOLMOD itself does not rely on this feature (it calls the METIS +// bisector with edge weights of all 1s). However, user code can call +// cholmod_metis_bisector directly, and pass in edge weights. If you use +// METIS 5.1, these edge weights are now ignored; if you pass a non-NULL +// entry for edge weights, an error will be returned. +// +// cholmod_metis: +// +// Wrapper for METIS_NodeND, METIS's own nested dissection algorithm. +// Typically faster than cholmod_nested_dissection, mostly because it +// uses minimum degree on just the leaves of the separator tree, rather +// than the whole matrix. +// +// Note that METIS does not return an error if it runs out of memory. Instead, +// it terminates the program. This interface attempts to avoid that problem +// by preallocating space that should be large enough for any memory allocations +// within METIS, and then freeing that space, just before the call to METIS. +// While this is not guaranteed to work, it is very unlikely to fail. If you +// encounter this problem, increase Common->metis_memory. If you don't mind +// having your program terminated, set Common->metis_memory to zero (a value of +// 2.0 is usually safe). Several other METIS workarounds are made in the +// routines in this file. See the description of metis_memory_ok, just below, +// for more details. +// +// FUTURE WORK: interfaces to other partitioners (CHACO, SCOTCH, JOSTLE, ... ) +// +// workspace: several size-nz and size-n temporary arrays. Uses no workspace +// in Common. +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" @@ -123,67 +122,79 @@ #endif -/* ========================================================================== */ -/* === dumpgraph ============================================================ */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// dumpgraph +//------------------------------------------------------------------------------ -/* For dumping the input graph to METIS_NodeND, to check with METIS's onmetis - * and graphchk programs. For debugging only. To use, uncomment this #define: -#define DUMP_GRAPH - */ +// For dumping the input graph to METIS_NodeND, to check with METIS's onmetis +// and graphchk programs. For debugging only. To use, uncomment this #define: +// #define DUMP_GRAPH #ifdef DUMP_GRAPH -/* After dumping the graph with this routine, run "onmetis metisgraph" */ +// After dumping the graph with this routine, run "onmetis metisgraph" static void dumpgraph (idx_t *Mp, idx_t *Mi, int64_t n, cholmod_common *Common) { int64_t i, j, p, nz ; FILE *f ; nz = Mp [n] ; - printf ("Dumping METIS graph n %ld nz %ld\n", n, nz) ; /* DUMP_GRAPH */ + printf ("Dumping METIS graph n %ld nz %ld\n", n, nz) ; // DUMP_GRAPH f = fopen ("metisgraph", "w") ; if (f == NULL) { - ERROR (-99, "cannot open metisgraph") ; - return ; + ERROR (-99, "cannot open metisgraph") ; + return ; } - fprintf (f, "%ld %ld\n", n, nz/2) ; /* DUMP_GRAPH */ + fprintf (f, "%ld %ld\n", n, nz/2) ; // DUMP_GRAPH for (j = 0 ; j < n ; j++) { - for (p = Mp [j] ; p < Mp [j+1] ; p++) - { - i = Mi [p] ; - fprintf (f, " %ld", i+1) ; /* DUMP_GRAPH */ - } - fprintf (f, "\n") ; /* DUMP_GRAPH */ + for (p = Mp [j] ; p < Mp [j+1] ; p++) + { + i = Mi [p] ; + fprintf (f, " %ld", i+1) ; // DUMP_GRAPH + } + fprintf (f, "\n") ; // DUMP_GRAPH } fclose (f) ; } #endif +//------------------------------------------------------------------------------ +// error handling +//------------------------------------------------------------------------------ + +#define RETURN_IF_METIS_FAILED(metis_result, error) \ +{ \ + if (metis_result != METIS_OK) \ + { \ + int status = (metis_result == METIS_ERROR_MEMORY) ? \ + CHOLMOD_OUT_OF_MEMORY : CHOLMOD_INVALID ; \ + ERROR (status, "METIS failed") ; \ + return (error) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// metis_memory_ok +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === metis_memory_ok ====================================================== */ -/* ========================================================================== */ - -/* METIS will terminate your program if - * they run out of memory. In an attempt to workaround METIS' behavior, this - * routine allocates a single block of memory of size equal to an observed - * upper bound on METIS' memory usage. It then immediately deallocates the - * block. If the allocation fails, METIS is not called. - * - * Median memory usage for a graph with n nodes and nz edges (counting each - * edge twice, or both upper and lower triangular parts of a matrix) is - * 4*nz + 40*n + 4096 integers. A "typical" upper bound is 10*nz + 50*n + 4096 - * integers. Nearly all matrices tested fit within that upper bound, with the - * exception two in the UF sparse matrix collection: Schenk_IBMNA/c-64 and - * Gupta/gupta2. The latter exceeds the "upper bound" by a factor of just less - * than 2. - * - * If you do not mind having your program terminated if it runs out of memory, - * set Common->metis_memory to zero. Its default value is 2, which allows for - * some memory fragmentation, and also accounts for the Gupta/gupta2 matrix. - */ +// METIS will terminate your program if it runs out of memory. In an attempt +// to workaround METIS' behavior, this routine allocates a single block of +// memory of size equal to an observed upper bound on METIS' memory usage. It +// then immediately deallocates the block. If the allocation fails, METIS is +// not called. +// +// Median memory usage for a graph with n nodes and nz edges (counting each +// edge twice, or both upper and lower triangular parts of a matrix) is 4*nz + +// 40*n + 4096 integers. A "typical" upper bound is 10*nz + 50*n + 4096 +// integers. Nearly all matrices tested fit within that upper bound, with the +// exception two in the SuiteSparse matrix collection: Schenk_IBMNA/c-64 and +// Gupta/gupta2. The latter exceeds the "upper bound" by a factor of just less +// than 2. +// +// If you do not mind having your program terminated if it runs out of memory, +// set Common->metis_memory to zero. Its default value is 2, which allows for +// some memory fragmentation, and also accounts for the Gupta/gupta2 matrix. #define GUESS(nz,n) (10 * (nz) + 50 * (n) + 4096) @@ -200,116 +211,110 @@ static int metis_memory_ok if (Common->metis_memory <= 0) { - /* do not prevent METIS from running out of memory */ - return (TRUE) ; + // do not prevent METIS from running out of memory + return (TRUE) ; } n = MAX (1, n) ; nz = MAX (0, nz) ; - /* compute in double, to avoid integer overflow */ + // compute in double, to avoid integer overflow s = GUESS ((double) nz, (double) n) ; s *= Common->metis_memory ; if (s * sizeof (idx_t) >= ((double) SIZE_MAX)) { - /* don't even attempt to malloc such a large block */ - return (FALSE) ; + // don't even attempt to malloc such a large block + return (FALSE) ; } - /* recompute in size_t */ + // recompute in size_t metis_guard = GUESS ((size_t) nz, (size_t) n) ; metis_guard *= Common->metis_memory ; - /* attempt to malloc the block */ + // attempt to malloc the block p = CHOLMOD(malloc) (metis_guard, sizeof (idx_t), Common) ; if (p == NULL) { - /* failure - return out-of-memory condition */ - return (FALSE) ; + // failure - return out-of-memory condition + return (FALSE) ; } - /* success - free the block */ + // success - free the block CHOLMOD(free) (metis_guard, sizeof (idx_t), p, Common) ; return (TRUE) ; } #endif -/* ========================================================================== */ -/* === cholmod_metis_bisector =============================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_metis_bisector +//------------------------------------------------------------------------------ -/* Finds a set of nodes that bisects the graph of A or AA' (direct interface - * to METIS_ComputeVertexSeparator. - * - * The input matrix A must be square, symmetric (with both upper and lower - * parts present) and with no diagonal entries. These conditions are NOT - * checked. - */ +// Finds a set of nodes that bisects the graph of A or AA' (direct interface +// to METIS_ComputeVertexSeparator. +// +// The input matrix A must be square, symmetric (with both upper and lower +// parts present) and with no diagonal entries. These conditions are NOT +// checked. -int64_t CHOLMOD(metis_bisector) /* returns separator size */ +int64_t CHOLMOD(metis_bisector) // returns separator size ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - Int *Anw, /* size A->nrow, node weights, can be NULL, */ - /* which means the graph is unweighted. */ - Int *Aew, /* size nz, edge weights (silently ignored). */ - /* This option was available with METIS 4, but not */ - /* in METIS 5. This argument is now unused, but */ - /* it remains for backward compatibilty, so as not */ - /* to change the API for cholmod_metis_bisector. */ - /* ---- output --- */ - Int *Partition, /* size A->nrow */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + Int *Anw, // size A->nrow, node weights, can be NULL, + // which means the graph is unweighted. + Int *Aew, // size nz, edge weights (silently ignored). + // This option was available with METIS 4, but not + // in METIS 5. This argument is now unused, but + // it remains for backward compatibilty, so as not + // to change the API for cholmod_metis_bisector. + // output: + Int *Partition, // size A->nrow cholmod_common *Common ) { + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + #ifndef NPARTITION Int *Ap, *Ai ; idx_t *Mp, *Mi, *Mnw, *Mpart ; Int n, nleft, nright, j, p, csep, total_weight, lightest, nz ; idx_t nn, csp ; - size_t n1 ; - int ok ; DEBUG (Int nsep) ; - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ - RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; - /* RETURN_IF_NULL (Anw, EMPTY) ; */ - /* RETURN_IF_NULL (Aew, EMPTY) ; */ RETURN_IF_NULL (Partition, EMPTY) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (A->stype || A->nrow != A->ncol) { - /* A must be square, with both upper and lower parts present */ - ERROR (CHOLMOD_INVALID, "matrix must be square, symmetric," - " and with both upper/lower parts present") ; - return (EMPTY) ; + // A must be square, with both upper and lower parts present + ERROR (CHOLMOD_INVALID, "matrix must be square, symmetric," + " and with both upper/lower parts present") ; + return (EMPTY) ; } Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A for bisector", Common) >= 0) ; - /* ---------------------------------------------------------------------- */ - /* quick return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return + //-------------------------------------------------------------------------- n = A->nrow ; if (n == 0) { - return (0) ; + return (0) ; } - n1 = ((size_t) n) + 1 ; + size_t n1 = A->nrow + 1 ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- Ap = A->p ; Ai = A->i ; @@ -317,171 +322,152 @@ int64_t CHOLMOD(metis_bisector) /* returns separator size */ if (Anw != NULL) DEBUG (for (j = 0 ; j < n ; j++) ASSERT (Anw [j] > 0)) ; - /* ---------------------------------------------------------------------- */ - /* copy Int to METIS idx_t, if necessary */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy Int to METIS idx_t, if necessary + //-------------------------------------------------------------------------- if (sizeof (Int) == sizeof (idx_t)) { - /* this is the typical case */ - Mi = (idx_t *) Ai ; - Mp = (idx_t *) Ap ; - Mnw = (idx_t *) Anw ; - Mpart = (idx_t *) Partition ; + // this is the typical case + Mi = (idx_t *) Ai ; + Mp = (idx_t *) Ap ; + Mnw = (idx_t *) Anw ; + Mpart = (idx_t *) Partition ; } else { - /* idx_t and Int differ; copy the graph into the METIS idx_t */ - Mi = CHOLMOD(malloc) (nz, sizeof (idx_t), Common) ; - Mp = CHOLMOD(malloc) (n1, sizeof (idx_t), Common) ; - Mnw = Anw ? (CHOLMOD(malloc) (n, sizeof (idx_t), Common)) : NULL ; - Mpart = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; - if (Common->status < CHOLMOD_OK) - { - CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; - CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; - return (EMPTY) ; - } - for (p = 0 ; p < nz ; p++) - { - Mi [p] = Ai [p] ; - } - for (j = 0 ; j <= n ; j++) - { - Mp [j] = Ap [j] ; - } + // idx_t and Int differ; copy the graph into the METIS idx_t + Mi = CHOLMOD(malloc) (nz, sizeof (idx_t), Common) ; + Mp = CHOLMOD(malloc) (n1, sizeof (idx_t), Common) ; + Mnw = Anw ? (CHOLMOD(malloc) (n, sizeof (idx_t), Common)) : NULL ; + Mpart = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; + if (Common->status < CHOLMOD_OK) + { + CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; + CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; + return (EMPTY) ; + } + for (p = 0 ; p < nz ; p++) + { + Mi [p] = (idx_t) Ai [p] ; + } + for (j = 0 ; j <= n ; j++) + { + Mp [j] = (idx_t) Ap [j] ; + } if (Anw != NULL) { for (j = 0 ; j < n ; j++) { - Mnw [j] = Anw [j] ; + Mnw [j] = (idx_t) Anw [j] ; } } } - /* ---------------------------------------------------------------------- */ - /* METIS workaround: try to ensure METIS doesn't run out of memory */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // METIS workaround: try to ensure METIS doesn't run out of memory + //-------------------------------------------------------------------------- if (!metis_memory_ok (n, nz, Common)) { - /* METIS might ask for too much memory and thus terminate the program */ - if (sizeof (Int) != sizeof (idx_t)) - { - CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; - CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; - } - return (EMPTY) ; + // METIS might ask for too much memory and thus terminate the program + if (sizeof (Int) != sizeof (idx_t)) + { + CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; + CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; + } + return (EMPTY) ; } - /* ---------------------------------------------------------------------- */ - /* partition the graph */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // partition the graph + //-------------------------------------------------------------------------- -#ifndef NDEBUG + #ifndef NDEBUG PRINT1 (("Metis graph, n = "ID"\n", n)) ; for (j = 0 ; j < n ; j++) { - Int ppp, nodeweight = (Mnw ? Mnw [j] : 1) ; - PRINT2 (("M(:,"ID") node weight "ID"\n", j, nodeweight)) ; - ASSERT (nodeweight > 0) ; - for (ppp = Mp [j] ; ppp < Mp [j+1] ; ppp++) - { - PRINT3 ((" "ID "\n", (Int) Mi [ppp])) ; - ASSERT (Mi [ppp] != j) ; - } + Int ppp, nodeweight = (Mnw ? Mnw [j] : 1) ; + PRINT2 (("M(:,"ID") node weight "ID"\n", j, nodeweight)) ; + ASSERT (nodeweight > 0) ; + for (ppp = Mp [j] ; ppp < Mp [j+1] ; ppp++) + { + PRINT3 ((" "ID "\n", (Int) Mi [ppp])) ; + ASSERT (Mi [ppp] != j) ; + } } -#endif - - /* - METIS_ComputeVertexSeparator( - idx_t *nvtxs, number of nodes - idx_t *xadj, column pointers - idx_t *adjncy, row indices - idx_t *vwgt, vertex weights (NULL means unweighted) - idx_t *options, options (NULL means defaults) - idx_t *sepsize, separator size - idx_t *part); partition. part [i] = 0,1,2, where: - 0:left, 1:right, 2:separator - */ + #endif + // METIS_ComputeVertexSeparator( + // idx_t *nvtxs, number of nodes + // idx_t *xadj, column pointers + // idx_t *adjncy, row indices + // idx_t *vwgt, vertex weights (NULL means unweighted) + // idx_t *options, options (NULL means defaults) + // idx_t *sepsize, separator size + // idx_t *part); partition. part [i] = 0,1,2, where: + // 0:left, 1:right, 2:separator nn = n ; TEST_COVERAGE_PAUSE ; - ok = SuiteSparse_metis_METIS_ComputeVertexSeparator (&nn, Mp, Mi, Mnw, NULL, &csp, Mpart) ; + int metis_result = SuiteSparse_metis_METIS_ComputeVertexSeparator (&nn, + Mp, Mi, Mnw, NULL, &csp, Mpart) ; TEST_COVERAGE_RESUME ; csep = csp ; PRINT1 (("METIS csep "ID"\n", csep)) ; - /* ---------------------------------------------------------------------- */ - /* copy the results back from idx_t, if required */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // copy the results back from idx_t, if required + //-------------------------------------------------------------------------- - if (ok == METIS_OK && (sizeof (Int) != sizeof (idx_t))) + if (metis_result == METIS_OK && (sizeof (Int) != sizeof (idx_t))) { - for (j = 0 ; j < n ; j++) - { - Partition [j] = Mpart [j] ; - } + for (j = 0 ; j < n ; j++) + { + Partition [j] = Mpart [j] ; + } } - /* ---------------------------------------------------------------------- */ - /* free the workspace for METIS, if allocated */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and check for METIS error + //-------------------------------------------------------------------------- if (sizeof (Int) != sizeof (idx_t)) { - CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; - CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; + CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; + CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mnw, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mpart, Common) ; } - if (ok == METIS_ERROR_MEMORY) - { - ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory in METIS") ; - return (EMPTY) ; - } - else if (ok == METIS_ERROR_INPUT) - { - ERROR (CHOLMOD_INVALID, "invalid input to METIS") ; - return (EMPTY) ; - } - else if (ok == METIS_ERROR) - { - ERROR (CHOLMOD_INVALID, "unspecified METIS error") ; - return (EMPTY) ; - } + RETURN_IF_METIS_FAILED (metis_result, EMPTY) ; - /* ---------------------------------------------------------------------- */ - /* ensure a reasonable separator */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // ensure a reasonable separator + //-------------------------------------------------------------------------- - /* METIS can return a valid separator with no nodes in (for example) the - * left part. In this case, there really is no separator. CHOLMOD - * prefers, in this case, for all nodes to be in the separator (and both - * left and right parts to be empty). Also, if the graph is unconnected, - * METIS can return a valid empty separator. CHOLMOD prefers at least one - * node in the separator. Note that cholmod_nested_dissection only calls - * this routine on connected components, but cholmod_bisect can call this - * routine for any graph. */ + // METIS can return a valid separator with no nodes in (for example) the + // left part. In this case, there really is no separator. CHOLMOD + // prefers, in this case, for all nodes to be in the separator (and both + // left and right parts to be empty). Also, if the graph is unconnected, + // METIS can return a valid empty separator. CHOLMOD prefers at least one + // node in the separator. Note that cholmod_nested_dissection only calls + // this routine on connected components, but cholmod_bisect can call this + // routine for any graph. if (csep == 0) { - /* The separator is empty, select lightest node as separator. If - * ties, select the highest numbered node. */ - if (Anw == NULL) - { - lightest = n-1 ; - } - else + // The separator is empty, select lightest node as separator. If + // ties, select the highest numbered node. + lightest = n-1 ; + if (Anw != NULL) { - lightest = 0 ; + lightest = 0 ; for (j = 0 ; j < n ; j++) { if (Anw [j] <= Anw [lightest]) @@ -490,32 +476,32 @@ int64_t CHOLMOD(metis_bisector) /* returns separator size */ } } } - PRINT1 (("Force "ID" as sep\n", lightest)) ; - Partition [lightest] = 2 ; - csep = (Anw ? (Anw [lightest]) : 1) ; + PRINT1 (("Force "ID" as sep\n", lightest)) ; + Partition [lightest] = 2 ; + csep = (Anw ? (Anw [lightest]) : 1) ; } - /* determine the node weights in the left and right part of the graph */ + // determine the node weights in the left and right part of the graph nleft = 0 ; nright = 0 ; DEBUG (nsep = 0) ; for (j = 0 ; j < n ; j++) { - PRINT1 (("Partition ["ID"] = "ID"\n", j, Partition [j])) ; - if (Partition [j] == 0) - { - nleft += (Anw ? (Anw [j]) : 1) ; - } - else if (Partition [j] == 1) - { - nright += (Anw ? (Anw [j]) : 1) ; - } + PRINT1 (("Partition ["ID"] = "ID"\n", j, Partition [j])) ; + if (Partition [j] == 0) + { + nleft += (Anw ? (Anw [j]) : 1) ; + } + else if (Partition [j] == 1) + { + nright += (Anw ? (Anw [j]) : 1) ; + } #ifndef NDEBUG - else - { - ASSERT (Partition [j] == 2) ; - nsep += (Anw ? (Anw [j]) : 1) ; - } + else + { + ASSERT (Partition [j] == 2) ; + nsep += (Anw ? (Anw [j]) : 1) ; + } #endif } ASSERT (csep == nsep) ; @@ -524,29 +510,29 @@ int64_t CHOLMOD(metis_bisector) /* returns separator size */ if (csep < total_weight) { - /* The separator is less than the whole graph. Make sure the left and - * right parts are either both empty or both non-empty. */ - PRINT1 (("nleft "ID" nright "ID" csep "ID" tot "ID"\n", - nleft, nright, csep, total_weight)) ; - ASSERT (nleft + nright + csep == total_weight) ; - ASSERT (nleft > 0 || nright > 0) ; - if ((nleft == 0 && nright > 0) || (nleft > 0 && nright == 0)) - { - /* left or right is empty; put all nodes in the separator */ - PRINT1 (("Force all in sep\n")) ; - csep = total_weight ; - for (j = 0 ; j < n ; j++) - { - Partition [j] = 2 ; - } - } + // The separator is less than the whole graph. Make sure the left and + // right parts are either both empty or both non-empty. + PRINT1 (("nleft "ID" nright "ID" csep "ID" tot "ID"\n", + nleft, nright, csep, total_weight)) ; + ASSERT (nleft + nright + csep == total_weight) ; + ASSERT (nleft > 0 || nright > 0) ; + if ((nleft == 0 && nright > 0) || (nleft > 0 && nright == 0)) + { + // left or right is empty; put all nodes in the separator + PRINT1 (("Force all in sep\n")) ; + csep = total_weight ; + for (j = 0 ; j < n ; j++) + { + Partition [j] = 2 ; + } + } } ASSERT (CHOLMOD(dump_partition) (n, Ap, Ai, Anw, Partition, csep, Common)) ; - /* ---------------------------------------------------------------------- */ - /* return the sum of the weights of nodes in the separator */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return the sum of the weights of nodes in the separator + //-------------------------------------------------------------------------- return (csep) ; #else @@ -556,47 +542,43 @@ int64_t CHOLMOD(metis_bisector) /* returns separator size */ } -/* ========================================================================== */ -/* === cholmod_metis ======================================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_metis +//------------------------------------------------------------------------------ -/* CHOLMOD wrapper for the METIS_NodeND ordering routine. Creates A+A', - * A*A' or A(:,f)*A(:,f)' and then calls METIS_NodeND on the resulting graph. - * This routine is comparable to cholmod_nested_dissection, except that it - * calls METIS_NodeND directly, and it does not return the separator tree. - * - * workspace: Flag (nrow), Iwork (4*n+uncol) - * Allocates a temporary matrix B=A*A' or B=A. - */ +// CHOLMOD wrapper for the METIS_NodeND ordering routine. Creates A+A', +// A*A' or A(:,f)*A(:,f)' and then calls METIS_NodeND on the resulting graph. +// This routine is comparable to cholmod_nested_dissection, except that it +// calls METIS_NodeND directly, and it does not return the separator tree. +// +// workspace: Flag (nrow), Iwork (4*n+uncol) +// Allocates a temporary matrix B=A*A' or B=A. int CHOLMOD(metis) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int postorder, /* if TRUE, follow with etree or coletree postorder */ - /* ---- output --- */ - Int *Perm, /* size A->nrow, output permutation */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int postorder, // if TRUE, follow with etree or coletree postorder + // output: + Int *Perm, // size A->nrow, output permutation cholmod_common *Common ) { + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + #ifndef NPARTITION double d ; Int *Iperm, *Iwork, *Bp, *Bi ; idx_t *Mp, *Mi, *Mperm, *Miperm ; cholmod_sparse *B ; - Int i, j, n, nz, p, identity, uncol ; + Int i, j, n, nz, p, identity ; idx_t nn, zero = 0 ; - size_t n1, s ; - int ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -604,253 +586,257 @@ int CHOLMOD(metis) RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* quick return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return + //-------------------------------------------------------------------------- n = A->nrow ; if (n == 0) { - return (TRUE) ; + return (TRUE) ; } - n1 = ((size_t) n) + 1 ; + size_t n1 = A->nrow + 1 ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 4*n + uncol */ - uncol = (A->stype == 0) ? A->ncol : 0 ; - s = CHOLMOD(mult_size_t) (n, 4, &ok) ; + // s = 4*nrow + uncol + size_t uncol = (A->stype == 0) ? A->ncol : 0 ; + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 4, &ok) ; s = CHOLMOD(add_size_t) (s, uncol, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* convert the matrix to adjacency list form */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert the matrix to adjacency list form + //-------------------------------------------------------------------------- - /* The input graph for METIS must be symmetric, with both upper and lower - * parts present, and with no diagonal entries. The columns need not be - * sorted. - * B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present */ + // The input graph for METIS must be symmetric, with both upper and lower + // parts present, and with no diagonal entries. The columns need not be + // sorted. + // B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present if (A->stype) { - /* Add the upper/lower part to a symmetric lower/upper matrix by - * converting to unsymmetric mode */ - /* workspace: Iwork (nrow) */ - B = CHOLMOD(copy) (A, 0, -1, Common) ; + // Add the upper/lower part to a symmetric lower/upper matrix by + // converting to unsymmetric mode + // workspace: Iwork (nrow) + B = CHOLMOD(copy) (A, 0, -1, Common) ; } else { - /* B = A*A' or A(:,f)*A(:,f)', no diagonal */ - /* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */ - B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; + // B = A*A' or A(:,f)*A(:,f)', no diagonal + // workspace: Flag (nrow), Iwork (max (nrow,ncol)) + B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; } ASSERT (CHOLMOD(dump_sparse) (B, "B for NodeND", Common) >= 0) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } ASSERT (B->nrow == A->nrow) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- Iwork = Common->Iwork ; - Iperm = Iwork ; /* size n (i/i/l) */ + Iperm = Iwork ; // size n Bp = B->p ; Bi = B->i ; nz = Bp [n] ; - /* B does not include the diagonal, and both upper and lower parts. - * Common->anz includes the diagonal, and just the lower part of B */ + // B does not include the diagonal, and both upper and lower parts. + // Common->anz includes the diagonal, and just the lower part of B Common->anz = nz / 2 + n ; - /* ---------------------------------------------------------------------- */ - /* allocate the METIS input arrays, if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate the METIS input arrays, if needed + //-------------------------------------------------------------------------- if (sizeof (Int) == sizeof (idx_t)) { - /* This is the typical case. */ - Miperm = (idx_t *) Iperm ; - Mperm = (idx_t *) Perm ; - Mp = (idx_t *) Bp ; - Mi = (idx_t *) Bi ; + // This is the typical case. + Miperm = (idx_t *) Iperm ; + Mperm = (idx_t *) Perm ; + Mp = (idx_t *) Bp ; + Mi = (idx_t *) Bi ; } else { - /* allocate graph for METIS only if Int and idx_t differ */ - Miperm = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; - Mperm = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; - Mp = CHOLMOD(malloc) (n1, sizeof (idx_t), Common) ; - Mi = CHOLMOD(malloc) (nz, sizeof (idx_t), Common) ; - if (Common->status < CHOLMOD_OK) - { - /* out of memory */ - CHOLMOD(free_sparse) (&B, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Miperm, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mperm, Common) ; - CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; - CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; - return (FALSE) ; - } - for (j = 0 ; j <= n ; j++) - { - Mp [j] = Bp [j] ; - } - for (p = 0 ; p < nz ; p++) - { - Mi [p] = Bi [p] ; - } - } - - /* ---------------------------------------------------------------------- */ - /* METIS workarounds */ - /* ---------------------------------------------------------------------- */ + // allocate graph for METIS only if Int and idx_t differ + Miperm = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; + Mperm = CHOLMOD(malloc) (n, sizeof (idx_t), Common) ; + Mp = CHOLMOD(malloc) (n1, sizeof (idx_t), Common) ; + Mi = CHOLMOD(malloc) (nz, sizeof (idx_t), Common) ; + if (Common->status < CHOLMOD_OK) + { + // out of memory + CHOLMOD(free_sparse) (&B, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Miperm, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mperm, Common) ; + CHOLMOD(free) (n1, sizeof (idx_t), Mp, Common) ; + CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; + return (FALSE) ; + } + for (j = 0 ; j <= n ; j++) + { + Mp [j] = Bp [j] ; + } + for (p = 0 ; p < nz ; p++) + { + Mi [p] = Bi [p] ; + } + } + + //-------------------------------------------------------------------------- + // METIS workarounds + //-------------------------------------------------------------------------- identity = FALSE ; if (nz == 0) { - /* The matrix has no off-diagonal entries. METIS_NodeND fails in this - * case, so avoid using it. The best permutation is identity anyway, - * so this is an easy fix. */ - identity = TRUE ; - PRINT1 (("METIS:: no nz\n")) ; + // The matrix has no off-diagonal entries. METIS_NodeND fails in this + // case, so avoid using it. The best permutation is identity anyway, + // so this is an easy fix. + identity = TRUE ; + PRINT1 (("METIS:: no nz\n")) ; } else if (Common->metis_nswitch > 0) { - /* METIS_NodeND in METIS 4.0.1 gives a seg fault with one matrix of - * order n = 3005 and nz = 6,036,025, including the diagonal entries. - * The workaround is to return the identity permutation instead of using - * METIS for matrices of dimension 3000 or more and with density of 66% - * or more - admittedly an uncertain fix, but such matrices are so dense - * that any reasonable ordering will do, even identity (n^2 is only 50% - * higher than nz in this case). CHOLMOD's nested dissection method - * (cholmod_nested_dissection) has no problems with the same matrix, - * even though it too uses METIS_ComputeVertexSeparator. The matrix is - * derived from LPnetlib/lpi_cplex1 in the UF sparse matrix collection. - * If C is the lpi_cplex matrix (of order 3005-by-5224), A = (C*C')^2 - * results in the seg fault. The seg fault also occurs in the stand- - * alone onmetis program that comes with METIS. If a future version of - * METIS fixes this problem, then set Common->metis_nswitch to zero. - */ - d = ((double) nz) / (((double) n) * ((double) n)) ; - if (n > (Int) (Common->metis_nswitch) && d > Common->metis_dswitch) - { - identity = TRUE ; - PRINT1 (("METIS:: nswitch/dswitch activated\n")) ; - } + // METIS_NodeND in METIS 4.0.1 gives a seg fault with one matrix of + // order n = 3005 and nz = 6,036,025, including the diagonal entries. + // The workaround is to return the identity permutation instead of + // using METIS for matrices of dimension 3000 or more and with density + // of 66% or more - admittedly an uncertain fix, but such matrices are + // so dense that any reasonable ordering will do, even identity (n^2 is + // only 50% higher than nz in this case). CHOLMOD's nested dissection + // method (cholmod_nested_dissection) has no problems with the same + // matrix, even though it too uses METIS_ComputeVertexSeparator. The + // matrix is derived from LPnetlib/lpi_cplex1 in the SuiteSparse matrix + // collection. If C is the lpi_cplex matrix (of order 3005-by-5224), A + // = (C*C')^2 results in the seg fault. The seg fault also occurs in + // the stand- alone onmetis program that comes with METIS. If a future + // version of METIS fixes this problem, then set Common->metis_nswitch + // to zero. + d = ((double) nz) / (((double) n) * ((double) n)) ; + if (n > (Int) (Common->metis_nswitch) && d > Common->metis_dswitch) + { + identity = TRUE ; + PRINT1 (("METIS:: nswitch/dswitch activated\n")) ; + } } if (!identity && !metis_memory_ok (n, nz, Common)) { - /* METIS might ask for too much memory and thus terminate the program */ - identity = TRUE ; + // METIS might ask for too much memory and thus terminate the program + identity = TRUE ; } - /* ---------------------------------------------------------------------- */ - /* find the permutation */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the permutation + //-------------------------------------------------------------------------- + + int metis_result = METIS_OK ; if (identity) { - /* no need to do the postorder */ - postorder = FALSE ; - for (i = 0 ; i < n ; i++) - { - Mperm [i] = i ; - } + // no need to do the postorder + postorder = FALSE ; + for (i = 0 ; i < n ; i++) + { + Mperm [i] = i ; + } } else { -#ifdef DUMP_GRAPH - /* DUMP_GRAPH */ printf ("Calling METIS_NodeND n "ID" nz "ID"" - "density %g\n", n, nz, ((double) nz) / (((double) n) * ((double) n))); - dumpgraph (Mp, Mi, n, Common) ; -#endif - - /* - int METIS_NodeND( - idx_t *nvtxs, number of nodes - idx_t *xadj, column pointers - idx_t *adjncy, row indices - idx_t *vwgt, vertex weights (NULL means unweighted) - idx_t *options, options (NULL means defaults) - idx_t *perm, fill-reducing ordering - idx_t *iperm); inverse of perm - */ - - nn = n ; + #ifdef DUMP_GRAPH + printf ("Calling METIS_NodeND n "ID" nz "ID" density " // DUMP_GRAPH + "%g\n", n, nz, ((double) nz) / (((double) n) * ((double) n))) ; + dumpgraph (Mp, Mi, n, Common) ; + #endif + + // int METIS_NodeND( + // idx_t *nvtxs, number of nodes + // idx_t *xadj, column pointers + // idx_t *adjncy, row indices + // idx_t *vwgt, vertex weights (NULL means unweighted) + // idx_t *options, options (NULL means defaults) + // idx_t *perm, fill-reducing ordering + // idx_t *iperm); inverse of perm + + nn = n ; TEST_COVERAGE_PAUSE ; - SuiteSparse_metis_METIS_NodeND (&nn, Mp, Mi, NULL, NULL, Mperm, Miperm) ; + metis_result = SuiteSparse_metis_METIS_NodeND (&nn, Mp, Mi, + NULL, NULL, Mperm, Miperm) ; TEST_COVERAGE_RESUME ; - PRINT0 (("METIS_NodeND done\n")) ; + PRINT0 (("METIS_NodeND done\n")) ; } - /* ---------------------------------------------------------------------- */ - /* free the METIS input arrays */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace and check for METIS error + //-------------------------------------------------------------------------- if (sizeof (Int) != sizeof (idx_t)) { - for (i = 0 ; i < n ; i++) - { - Perm [i] = (Int) (Mperm [i]) ; - } - CHOLMOD(free) (n, sizeof (idx_t), Miperm, Common) ; - CHOLMOD(free) (n, sizeof (idx_t), Mperm, Common) ; - CHOLMOD(free) (n+1, sizeof (idx_t), Mp, Common) ; - CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; + for (i = 0 ; i < n ; i++) + { + Perm [i] = (Int) (Mperm [i]) ; + } + CHOLMOD(free) (n, sizeof (idx_t), Miperm, Common) ; + CHOLMOD(free) (n, sizeof (idx_t), Mperm, Common) ; + CHOLMOD(free) (n+1, sizeof (idx_t), Mp, Common) ; + CHOLMOD(free) (nz, sizeof (idx_t), Mi, Common) ; } CHOLMOD(free_sparse) (&B, Common) ; - /* ---------------------------------------------------------------------- */ - /* etree or column-etree postordering, using the Cholesky Module */ - /* ---------------------------------------------------------------------- */ + RETURN_IF_METIS_FAILED (metis_result, false) ; + + //-------------------------------------------------------------------------- + // etree or column-etree postordering, using the Cholesky Module + //-------------------------------------------------------------------------- if (postorder) { - Int *Parent, *Post, *NewPerm ; - Int k ; - - Parent = Iwork + 2*((size_t) n) + uncol ; /* size n = nrow */ - Post = Parent + n ; /* size n */ - - /* workspace: Iwork (2*nrow+uncol), Flag (nrow), Head (nrow+1) */ - CHOLMOD(analyze_ordering) (A, CHOLMOD_METIS, Perm, fset, fsize, - Parent, Post, NULL, NULL, NULL, Common) ; - if (Common->status == CHOLMOD_OK) - { - /* combine the METIS permutation with its postordering */ - NewPerm = Parent ; /* use Parent as workspace */ - for (k = 0 ; k < n ; k++) - { - NewPerm [k] = Perm [Post [k]] ; - } - for (k = 0 ; k < n ; k++) - { - Perm [k] = NewPerm [k] ; - } - } - } - - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + Int *Parent, *Post, *NewPerm ; + Int k ; + + Parent = Iwork + 2*((size_t) n) + uncol ; // size n = nrow + Post = Parent + n ; // size n + + // workspace: Iwork (2*nrow+uncol), Flag (nrow), Head (nrow+1) + CHOLMOD(analyze_ordering) (A, CHOLMOD_METIS, Perm, fset, fsize, + Parent, Post, NULL, NULL, NULL, Common) ; + if (Common->status == CHOLMOD_OK) + { + // combine the METIS permutation with its postordering + NewPerm = Parent ; // use Parent as workspace + for (k = 0 ; k < n ; k++) + { + NewPerm [k] = Perm [Post [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Perm [k] = NewPerm [k] ; + } + } + } + + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; PRINT1 (("cholmod_metis done\n")) ; return (Common->status == CHOLMOD_OK) ; #else diff --git a/CHOLMOD/Partition/cholmod_nesdis.c b/CHOLMOD/Partition/cholmod_nesdis.c index 43c9900793..fd4b07a15f 100644 --- a/CHOLMOD/Partition/cholmod_nesdis.c +++ b/CHOLMOD/Partition/cholmod_nesdis.c @@ -2,117 +2,116 @@ // CHOLMOD/Partition/cholmod_nesdis: CHOLMOD nested dissection, using METIS //------------------------------------------------------------------------------ -// CHOLMOD/Partition Module. Copyright (C) 2005-2022, University of Florida. +// CHOLMOD/Partition Module. Copyright (C) 2005-2023, University of Florida. // All Rights Reserved. Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ -/* CHOLMOD nested dissection and graph partitioning. - * - * cholmod_bisect: - * - * Finds a set of nodes that partitions the graph into two parts. - * Compresses the graph first. Requires METIS. - * - * cholmod_nested_dissection: - * - * Nested dissection, using its own compression and connected-commponents - * algorithms, an external graph partitioner (METIS), and a constrained - * minimum degree ordering algorithm (CCOLAMD or CSYMAMD). Typically - * gives better orderings than METIS_NodeND (about 5% to 10% fewer - * nonzeros in L). - * - * cholmod_collapse_septree: - * - * Prune the separator tree returned by cholmod_nested_dissection. - * - * This file contains several routines private to this file: - * - * partition compress and partition a graph - * clear_flag clear Common->Flag, but do not modify negative entries - * find_components find the connected components of a graph - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// CHOLMOD nested dissection and graph partitioning. +// +// cholmod_bisect: +// +// Finds a set of nodes that partitions the graph into two parts. +// Compresses the graph first. Requires METIS. +// +// cholmod_nested_dissection: +// +// Nested dissection, using its own compression and connected-commponents +// algorithms, an external graph partitioner (METIS), and a constrained +// minimum degree ordering algorithm (CCOLAMD or CSYMAMD). Typically +// gives better orderings than METIS_NodeND (about 5% to 10% fewer +// nonzeros in L). +// +// cholmod_collapse_septree: +// +// Prune the separator tree returned by cholmod_nested_dissection. +// +// This file contains several routines private to this file: +// +// partition compress and partition a graph +// clear_flag clear Common->Flag, but do not modify negative entries +// find_components find the connected components of a graph +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NPARTITION -/* ========================================================================== */ -/* === partition ============================================================ */ -/* ========================================================================== */ - -/* Find a set of nodes that partition a graph. The graph must be symmetric - * with no diagonal entries. To compress the graph first, compress is TRUE - * and on input Hash [j] holds the hash key for node j, which must be in the - * range 0 to csize-1. The input graph (Cp, Ci) is destroyed. Cew is all 1's - * on input and output. Cnw [j] > 0 is the initial weight of node j. On - * output, Cnw [i] = 0 if node i is absorbed into j and the original weight - * Cnw [i] is added to Cnw [j]. If compress is FALSE, the graph is not - * compressed and Cnw and Hash are unmodified. The partition itself is held in - * the output array Part of size n. Part [j] is 0, 1, or 2, depending on - * whether node j is in the left part of the graph, the right part, or the - * separator, respectively. Note that the input graph need not be connected, - * and the output subgraphs (the three parts) may also be unconnected. - * - * Returns the size of the separator, in terms of the sum of the weights of - * the nodes. It is guaranteed to be between 1 and the total weight of all - * the nodes. If it is of size less than the total weight, then both the left - * and right parts are guaranteed to be non-empty (this guarantee depends on - * cholmod_metis_bisector). - */ - -static int64_t partition /* size of separator or -1 if failure */ -( - /* inputs, not modified on output */ -#ifndef NDEBUG - Int csize, /* upper bound on # of edges in the graph; - * csize >= MAX (n, nnz(C)) must hold. */ -#endif - int compress, /* if TRUE the compress the graph first */ - - /* input/output */ - Int Hash [ ], /* Hash [i] = hash >= 0 is the hash function for node - * i on input. On output, Hash [i] = FLIP (j) if node - * i is absorbed into j. Hash [i] >= 0 if i has not - * been absorbed. */ +//------------------------------------------------------------------------------ +// partition +//------------------------------------------------------------------------------ - /* input graph, compressed graph of cn nodes on output */ +// Find a set of nodes that partition a graph. The graph must be symmetric +// with no diagonal entries. To compress the graph first, compress is TRUE +// and on input Hash [j] holds the hash key for node j, which must be in the +// range 0 to csize-1. The input graph (Cp, Ci) is destroyed. Cew is all 1's +// on input and output. Cnw [j] > 0 is the initial weight of node j. On +// output, Cnw [i] = 0 if node i is absorbed into j and the original weight +// Cnw [i] is added to Cnw [j]. If compress is FALSE, the graph is not +// compressed and Cnw and Hash are unmodified. The partition itself is held in +// the output array Part of size n. Part [j] is 0, 1, or 2, depending on +// whether node j is in the left part of the graph, the right part, or the +// separator, respectively. Note that the input graph need not be connected, +// and the output subgraphs (the three parts) may also be unconnected. +// +// Returns the size of the separator, in terms of the sum of the weights of +// the nodes. It is guaranteed to be between 1 and the total weight of all +// the nodes. If it is of size less than the total weight, then both the left +// and right parts are guaranteed to be non-empty (this guarantee depends on +// cholmod_metis_bisector). + +static int64_t partition // size of separator or -1 if failure +( + // inputs, not modified on output + #ifndef NDEBUG + Int csize, // upper bound on # of edges in the graph; + // csize >= MAX (n, nnz(C)) must hold. + #endif + int compress, // if TRUE the compress the graph first + + // input/output + Int Hash [ ], // Hash [i] = hash >= 0 is the hash function for node + // i on input. On output, Hash [i] = FLIP (j) if node + // i is absorbed into j. Hash [i] >= 0 if i has not + // been absorbed. + + // input graph, compressed graph of cn nodes on output cholmod_sparse *C, - /* input/output */ - Int Cnw [ ], /* size n. Cnw [j] > 0 is the weight of node j on - * input. On output, if node i is absorbed into - * node j, then Cnw [i] = 0 and the original weight of - * node i is added to Cnw [j]. The sum of Cnw [0..n-1] - * is not modified. */ + // input/output + Int Cnw [ ], // size n. Cnw [j] > 0 is the weight of node j on + // input. On output, if node i is absorbed into + // node j, then Cnw [i] = 0 and the original weight of + // node i is added to Cnw [j]. The sum of Cnw [0..n-1] + // is not modified. - /* workspace */ - Int Cew [ ], /* size csize, all 1's on input and output */ + // workspace + Int Cew [ ], // size csize, all 1's on input and output - /* more workspace, undefined on input and output */ - Int Cmap [ ], /* size n (i/i/l) */ + // more workspace, undefined on input and output + Int Cmap [ ], // size n - /* output */ - Int Part [ ], /* size n, Part [j] = 0, 1, or 2. */ + // output + Int Part [ ], // size n, Part [j] = 0, 1, or 2. cholmod_common *Common ) { + Int n, hash, head, i, j, k, p, pend, ilen, ilast, pi, piend, - jlen, ok, cn, csep, pdest, nodes_pruned, nz, total_weight, jscattered ; + jlen, ok, cn, csep, pdest, nodes_pruned, nz, total_weight, jscattered ; Int *Cp, *Ci, *Next, *Hhead ; -#ifndef NDEBUG + #ifndef NDEBUG Int cnt, pruned ; double work = 0, goodwork = 0 ; -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* quick return for small or empty graphs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return for small or empty graphs + //-------------------------------------------------------------------------- n = C->nrow ; Cp = C->p ; @@ -124,466 +123,463 @@ static int64_t partition /* size of separator or -1 if failure */ total_weight = 0 ; for (j = 0 ; j < n ; j++) { - ASSERT (Cnw [j] > 0) ; - total_weight += Cnw [j] ; + ASSERT (Cnw [j] > 0) ; + total_weight += Cnw [j] ; } if (n <= 2) { - /* very small graph */ - for (j = 0 ; j < n ; j++) - { - Part [j] = 2 ; - } - return (total_weight) ; + // very small graph + for (j = 0 ; j < n ; j++) + { + Part [j] = 2 ; + } + return (total_weight) ; } else if (nz <= 0) { - /* no edges, this is easy */ - PRINT2 (("diagonal matrix\n")) ; - k = n/2 ; - for (j = 0 ; j < k ; j++) - { - Part [j] = 0 ; - } - for ( ; j < n ; j++) - { - Part [j] = 1 ; - } - /* ensure the separator is not empty (required by nested dissection) */ - Part [n-1] = 2 ; - return (Cnw [n-1]) ; + // no edges, this is easy + PRINT2 (("diagonal matrix\n")) ; + k = n/2 ; + for (j = 0 ; j < k ; j++) + { + Part [j] = 0 ; + } + for ( ; j < n ; j++) + { + Part [j] = 1 ; + } + // ensure the separator is not empty (required by nested dissection) + Part [n-1] = 2 ; + return (Cnw [n-1]) ; } -#ifndef NDEBUG + #ifndef NDEBUG ASSERT (n > 1 && nz > 0) ; PRINT2 (("original graph:\n")) ; for (j = 0 ; j < n ; j++) { - PRINT2 ((""ID": ", j)) ; - for (p = Cp [j] ; p < Cp [j+1] ; p++) - { - i = Ci [p] ; - PRINT3 ((""ID" ", i)) ; - ASSERT (i >= 0 && i < n && i != j) ; - } - PRINT2 (("hash: "ID"\n", Hash [j])) ; + PRINT2 ((""ID": ", j)) ; + for (p = Cp [j] ; p < Cp [j+1] ; p++) + { + i = Ci [p] ; + PRINT3 ((""ID" ", i)) ; + ASSERT (i >= 0 && i < n && i != j) ; + } + PRINT2 (("hash: "ID"\n", Hash [j])) ; } DEBUG (for (p = 0 ; p < csize ; p++) ASSERT (Cew [p] == 1)) ; -#endif + #endif nodes_pruned = 0 ; if (compress) { - /* ------------------------------------------------------------------ */ - /* get workspace */ - /* ------------------------------------------------------------------ */ - - Next = Part ; /* use Part as workspace for Next [ */ - Hhead = Cew ; /* use Cew as workspace for Hhead [ */ - - /* ------------------------------------------------------------------ */ - /* create the hash buckets */ - /* ------------------------------------------------------------------ */ - - for (j = 0 ; j < n ; j++) - { - /* get the hash key for node j */ - hash = Hash [j] ; - ASSERT (hash >= 0 && hash < csize) ; - head = Hhead [hash] ; - if (head > EMPTY) - { - /* hash bucket for this hash key is empty. */ - head = EMPTY ; - } - else - { - /* hash bucket for this hash key is not empty. get old head */ - head = FLIP (head) ; - ASSERT (head >= 0 && head < n) ; - } - /* node j becomes the new head of the hash bucket. FLIP it so that - * we can tell the difference between an empty or non-empty hash - * bucket. */ - Hhead [hash] = FLIP (j) ; - Next [j] = head ; - ASSERT (head >= EMPTY && head < n) ; - } - -#ifndef NDEBUG - for (cnt = 0, k = 0 ; k < n ; k++) - { - ASSERT (Hash [k] >= 0 && Hash [k] < csize) ; /* k is alive */ - hash = Hash [k] ; - ASSERT (hash >= 0 && hash < csize) ; - head = Hhead [hash] ; - ASSERT (head < EMPTY) ; /* hash bucket not empty */ - j = FLIP (head) ; - ASSERT (j >= 0 && j < n) ; - if (j == k) - { - PRINT2 (("hash "ID": ", hash)) ; - for ( ; j != EMPTY ; j = Next [j]) - { - PRINT3 ((" "ID"", j)) ; - ASSERT (j >= 0 && j < n) ; - ASSERT (Hash [j] == hash) ; - cnt++ ; - ASSERT (cnt <= n) ; - } - PRINT2 (("\n")) ; - } - } - ASSERT (cnt == n) ; -#endif + //---------------------------------------------------------------------- + // get workspace + //---------------------------------------------------------------------- + + Next = Part ; // use Part as workspace for Next [ + Hhead = Cew ; // use Cew as workspace for Hhead [ + + //---------------------------------------------------------------------- + // create the hash buckets + //---------------------------------------------------------------------- + + for (j = 0 ; j < n ; j++) + { + // get the hash key for node j + hash = Hash [j] ; + ASSERT (hash >= 0 && hash < csize) ; + head = Hhead [hash] ; + if (head > EMPTY) + { + // hash bucket for this hash key is empty. + head = EMPTY ; + } + else + { + // hash bucket for this hash key is not empty. get old head + head = FLIP (head) ; + ASSERT (head >= 0 && head < n) ; + } + // node j becomes the new head of the hash bucket. FLIP it so that + // we can tell the difference between an empty or non-empty hash + // bucket. + Hhead [hash] = FLIP (j) ; + Next [j] = head ; + ASSERT (head >= EMPTY && head < n) ; + } + + #ifndef NDEBUG + for (cnt = 0, k = 0 ; k < n ; k++) + { + ASSERT (Hash [k] >= 0 && Hash [k] < csize) ; // k is alive + hash = Hash [k] ; + ASSERT (hash >= 0 && hash < csize) ; + head = Hhead [hash] ; + ASSERT (head < EMPTY) ; // hash bucket not empty + j = FLIP (head) ; + ASSERT (j >= 0 && j < n) ; + if (j == k) + { + PRINT2 (("hash "ID": ", hash)) ; + for ( ; j != EMPTY ; j = Next [j]) + { + PRINT3 ((" "ID"", j)) ; + ASSERT (j >= 0 && j < n) ; + ASSERT (Hash [j] == hash) ; + cnt++ ; + ASSERT (cnt <= n) ; + } + PRINT2 (("\n")) ; + } + } + ASSERT (cnt == n) ; + #endif + + //---------------------------------------------------------------------- + // scan the non-empty hash buckets for indistinguishable nodes + //---------------------------------------------------------------------- + + // If there are no hash collisions and no compression occurs, this takes + // O(n) time. If no hash collisions, but some nodes are removed, this + // takes time O(n+e) where e is the sum of the degress of the nodes + // that are removed. Even with many hash collisions (a rare case), + // this algorithm has never been observed to perform more than nnz(A) + // useless work. + // + // Cmap is used as workspace to mark nodes of the graph, [ + // for comparing the nonzero patterns of two nodes i and j. + + #define Cmap_MARK(i) Cmap [i] = j + #define Cmap_MARKED(i) (Cmap [i] == j) + + for (i = 0 ; i < n ; i++) + { + Cmap [i] = EMPTY ; + } - /* ------------------------------------------------------------------ */ - /* scan the non-empty hash buckets for indistinguishable nodes */ - /* ------------------------------------------------------------------ */ - - /* If there are no hash collisions and no compression occurs, this takes - * O(n) time. If no hash collisions, but some nodes are removed, this - * takes time O(n+e) where e is the sum of the degress of the nodes - * that are removed. Even with many hash collisions (a rare case), - * this algorithm has never been observed to perform more than nnz(A) - * useless work. - * - * Cmap is used as workspace to mark nodes of the graph, [ - * for comparing the nonzero patterns of two nodes i and j. - */ - -#define Cmap_MARK(i) Cmap [i] = j -#define Cmap_MARKED(i) (Cmap [i] == j) - - for (i = 0 ; i < n ; i++) - { - Cmap [i] = EMPTY ; - } - - for (k = 0 ; k < n ; k++) - { - hash = Hash [k] ; - ASSERT (hash >= FLIP (n-1) && hash < csize) ; - if (hash < 0) - { - /* node k has already been absorbed into some other node */ - ASSERT (FLIP (Hash [k]) >= 0 && FLIP (Hash [k] < n)) ; - continue ; - } - head = Hhead [hash] ; - ASSERT (head < EMPTY || head == 1) ; - if (head == 1) - { - /* hash bucket is already empty */ - continue ; - } - PRINT2 (("\n--------------------hash "ID":\n", hash)) ; - for (j = FLIP (head) ; j != EMPTY && Next[j] > EMPTY ; j = Next [j]) - { - /* compare j with all nodes i following it in hash bucket */ - ASSERT (j >= 0 && j < n && Hash [j] == hash) ; - p = Cp [j] ; - pend = Cp [j+1] ; - jlen = pend - p ; - jscattered = FALSE ; - DEBUG (for (i = 0 ; i < n ; i++) ASSERT (!Cmap_MARKED (i))) ; - DEBUG (pruned = FALSE) ; - ilast = j ; - for (i = Next [j] ; i != EMPTY ; i = Next [i]) - { - ASSERT (i >= 0 && i < n && Hash [i] == hash && i != j) ; - pi = Cp [i] ; - piend = Cp [i+1] ; - ilen = piend - pi ; - DEBUG (work++) ; - if (ilen != jlen) - { - /* i and j have different degrees */ - ilast = i ; - continue ; - } - /* scatter the pattern of node j, if not already */ - if (!jscattered) - { - Cmap_MARK (j) ; - for ( ; p < pend ; p++) - { - Cmap_MARK (Ci [p]) ; - } - jscattered = TRUE ; - DEBUG (work += jlen) ; - } - for (ok = Cmap_MARKED (i) ; ok && pi < piend ; pi++) - { - ok = Cmap_MARKED (Ci [pi]) ; - DEBUG (work++) ; - } - if (ok) - { - /* found it. kill node i and merge it into j */ - PRINT2 (("found "ID" absorbed into "ID"\n", i, j)) ; - Hash [i] = FLIP (j) ; - Cnw [j] += Cnw [i] ; - Cnw [i] = 0 ; - ASSERT (ilast != i && ilast >= 0 && ilast < n) ; - Next [ilast] = Next [i] ; /* delete i from bucket */ - nodes_pruned++ ; - DEBUG (goodwork += (ilen+1)) ; - DEBUG (pruned = TRUE) ; - } - else - { - /* i and j are different */ - ilast = i ; - } - } - DEBUG (if (pruned) goodwork += jlen) ; - } - /* empty the hash bucket, restoring Cew */ - Hhead [hash] = 1 ; - } - - DEBUG (if (((work - goodwork) / (double) nz) > 0.20) PRINT0 (( - "work %12g good %12g nz %12g (wasted work/nz: %6.2f )\n", - work, goodwork, (double) nz, (work - goodwork) / ((double) nz)))) ; - - /* All hash buckets now empty. Cmap no longer needed as workspace. ] - * Cew no longer needed as Hhead; Cew is now restored to all ones. ] - * Part no longer needed as workspace for Next. ] */ + for (k = 0 ; k < n ; k++) + { + hash = Hash [k] ; + ASSERT (hash >= FLIP (n-1) && hash < csize) ; + if (hash < 0) + { + // node k has already been absorbed into some other node + ASSERT (FLIP (Hash [k]) >= 0 && FLIP (Hash [k] < n)) ; + continue ; + } + head = Hhead [hash] ; + ASSERT (head < EMPTY || head == 1) ; + if (head == 1) + { + // hash bucket is already empty + continue ; + } + PRINT2 (("\n--------------------hash "ID":\n", hash)) ; + for (j = FLIP (head) ; j != EMPTY && Next[j] > EMPTY ; j = Next [j]) + { + // compare j with all nodes i following it in hash bucket + ASSERT (j >= 0 && j < n && Hash [j] == hash) ; + p = Cp [j] ; + pend = Cp [j+1] ; + jlen = pend - p ; + jscattered = FALSE ; + DEBUG (for (i = 0 ; i < n ; i++) ASSERT (!Cmap_MARKED (i))) ; + DEBUG (pruned = FALSE) ; + ilast = j ; + for (i = Next [j] ; i != EMPTY ; i = Next [i]) + { + ASSERT (i >= 0 && i < n && Hash [i] == hash && i != j) ; + pi = Cp [i] ; + piend = Cp [i+1] ; + ilen = piend - pi ; + DEBUG (work++) ; + if (ilen != jlen) + { + // i and j have different degrees + ilast = i ; + continue ; + } + // scatter the pattern of node j, if not already + if (!jscattered) + { + Cmap_MARK (j) ; + for ( ; p < pend ; p++) + { + Cmap_MARK (Ci [p]) ; + } + jscattered = TRUE ; + DEBUG (work += jlen) ; + } + for (ok = Cmap_MARKED (i) ; ok && pi < piend ; pi++) + { + ok = Cmap_MARKED (Ci [pi]) ; + DEBUG (work++) ; + } + if (ok) + { + // found it. kill node i and merge it into j + PRINT2 (("found "ID" absorbed into "ID"\n", i, j)) ; + Hash [i] = FLIP (j) ; + Cnw [j] += Cnw [i] ; + Cnw [i] = 0 ; + ASSERT (ilast != i && ilast >= 0 && ilast < n) ; + Next [ilast] = Next [i] ; // delete i from bucket + nodes_pruned++ ; + DEBUG (goodwork += (ilen+1)) ; + DEBUG (pruned = TRUE) ; + } + else + { + // i and j are different + ilast = i ; + } + } + DEBUG (if (pruned) goodwork += jlen) ; + } + // empty the hash bucket, restoring Cew + Hhead [hash] = 1 ; + } + + DEBUG (if (((work - goodwork) / (double) nz) > 0.20) PRINT0 (( + "work %12g good %12g nz %12g (wasted work/nz: %6.2f )\n", + work, goodwork, (double) nz, (work - goodwork) / ((double) nz)))) ; + + // All hash buckets now empty. Cmap no longer needed as workspace. ] + // Cew no longer needed as Hhead; Cew is now restored to all ones. ] + // Part no longer needed as workspace for Next. ] } - /* Edge weights are all one, node weights reflect node absorption */ + // Edge weights are all one, node weights reflect node absorption DEBUG (for (p = 0 ; p < csize ; p++) ASSERT (Cew [p] == 1)) ; DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) cnt += Cnw [j]) ; ASSERT (cnt == total_weight) ; - /* ---------------------------------------------------------------------- */ - /* compress and partition the graph */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compress and partition the graph + //-------------------------------------------------------------------------- if (nodes_pruned == 0) { - /* ------------------------------------------------------------------ */ - /* no pruning done at all. Do not create the compressed graph */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // no pruning done at all. Do not create the compressed graph + //---------------------------------------------------------------------- - /* FUTURE WORK: could call CHACO, SCOTCH, ... here too */ - csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ; + // FUTURE WORK: could call CHACO, SCOTCH, ... here too + csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ; } else if (nodes_pruned == n-1) { - /* ------------------------------------------------------------------ */ - /* only one node left. This is a dense graph */ - /* ------------------------------------------------------------------ */ + //---------------------------------------------------------------------- + // only one node left. This is a dense graph + //---------------------------------------------------------------------- - PRINT2 (("completely dense graph\n")) ; - csep = total_weight ; - for (j = 0 ; j < n ; j++) - { - Part [j] = 2 ; - } + PRINT2 (("completely dense graph\n")) ; + csep = total_weight ; + for (j = 0 ; j < n ; j++) + { + Part [j] = 2 ; + } } else { - /* ------------------------------------------------------------------ */ - /* compress the graph and partition the compressed graph */ - /* ------------------------------------------------------------------ */ - - /* ------------------------------------------------------------------ */ - /* create the map from the uncompressed graph to the compressed graph */ - /* ------------------------------------------------------------------ */ - - /* Cmap [j] = k if node j is alive and the kth node of compressed graph. - * The mapping is done monotonically (that is, k <= j) to simplify the - * uncompression later on. Cmap [j] = EMPTY if node j is dead. */ - - for (j = 0 ; j < n ; j++) - { - Cmap [j] = EMPTY ; - } - k = 0 ; - for (j = 0 ; j < n ; j++) - { - if (Cnw [j] > 0) - { - ASSERT (k <= j) ; - Cmap [j] = k++ ; - } - } - cn = k ; /* # of nodes in compressed graph */ - PRINT2 (("compressed graph from "ID" to "ID" nodes\n", n, cn)) ; - ASSERT (cn > 1 && cn == n - nodes_pruned) ; - - /* ------------------------------------------------------------------ */ - /* create the compressed graph */ - /* ------------------------------------------------------------------ */ - - k = 0 ; - pdest = 0 ; - for (j = 0 ; j < n ; j++) - { - if (Cnw [j] > 0) - { - /* node j in the full graph is node k in the compressed graph */ - ASSERT (k <= j && Cmap [j] == k) ; - p = Cp [j] ; - pend = Cp [j+1] ; - Cp [k] = pdest ; - Cnw [k] = Cnw [j] ; - for ( ; p < pend ; p++) - { - /* prune dead nodes, and remap to new node numbering */ - i = Ci [p] ; - ASSERT (i >= 0 && i < n && i != j) ; - i = Cmap [i] ; - ASSERT (i >= EMPTY && i < cn && i != k) ; - if (i > EMPTY) - { - ASSERT (pdest <= p) ; - Ci [pdest++] = i ; - } - } - k++ ; - } - } - Cp [cn] = pdest ; - C->nrow = cn ; - C->ncol = cn ; /* affects mem stats unless restored when C free'd */ - -#ifndef NDEBUG - PRINT2 (("pruned graph ("ID"/"ID") nodes, ("ID"/"ID") edges\n", - cn, n, pdest, nz)) ; - PRINT2 (("compressed graph:\n")) ; - for (cnt = 0, j = 0 ; j < cn ; j++) - { - PRINT2 ((""ID": ", j)) ; - for (p = Cp [j] ; p < Cp [j+1] ; p++) - { - i = Ci [p] ; - PRINT3 ((""ID" ", i)) ; - ASSERT (i >= 0 && i < cn && i != j) ; - } - PRINT2 (("weight: "ID"\n", Cnw [j])) ; - ASSERT (Cnw [j] > 0) ; - cnt += Cnw [j] ; - } - ASSERT (cnt == total_weight) ; - for (j = 0 ; j < n ; j++) PRINT2 (("Cmap ["ID"] = "ID"\n", j, Cmap[j])); - ASSERT (k == cn) ; -#endif + //---------------------------------------------------------------------- + // compress the graph and partition the compressed graph + //---------------------------------------------------------------------- - /* ------------------------------------------------------------------ */ - /* find the separator of the compressed graph */ - /* ------------------------------------------------------------------ */ - - /* FUTURE WORK: could call CHACO, SCOTCH, ... here too */ - csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ; - - if (csep < 0) - { - /* failed */ - return (-1) ; - } - - PRINT2 (("Part: ")) ; - DEBUG (for (j = 0 ; j < cn ; j++) PRINT2 ((""ID" ", Part [j]))) ; - PRINT2 (("\n")) ; - - /* Cp and Ci no longer needed */ - - /* ------------------------------------------------------------------ */ - /* find the separator of the uncompressed graph */ - /* ------------------------------------------------------------------ */ - - /* expand the separator to live nodes in the uncompressed graph */ - for (j = n-1 ; j >= 0 ; j--) - { - /* do this in reverse order so that Cnw can be expanded in place */ - k = Cmap [j] ; - ASSERT (k >= EMPTY && k < n) ; - if (k > EMPTY) - { - /* node k in compressed graph and is node j in full graph */ - ASSERT (k <= j) ; - ASSERT (Hash [j] >= EMPTY) ; - Part [j] = Part [k] ; - Cnw [j] = Cnw [k] ; - } - else - { - /* node j is a dead node */ - Cnw [j] = 0 ; - DEBUG (Part [j] = EMPTY) ; - ASSERT (Hash [j] < EMPTY) ; - } - } - - /* find the components for the dead nodes */ - for (i = 0 ; i < n ; i++) - { - if (Hash [i] < EMPTY) - { - /* node i has been absorbed into node j */ - j = FLIP (Hash [i]) ; - ASSERT (Part [i] == EMPTY && j >= 0 && j < n && Cnw [i] == 0) ; - Part [i] = Part [j] ; - } - ASSERT (Part [i] >= 0 && Part [i] <= 2) ; - } - -#ifndef NDEBUG - PRINT2 (("Part: ")) ; - for (cnt = 0, j = 0 ; j < n ; j++) - { - ASSERT (Part [j] != EMPTY) ; - PRINT2 ((""ID" ", Part [j])) ; - if (Part [j] == 2) cnt += Cnw [j] ; - } - PRINT2 (("\n")) ; - PRINT2 (("csep "ID" "ID"\n", cnt, csep)) ; - ASSERT (cnt == csep) ; - for (cnt = 0, j = 0 ; j < n ; j++) cnt += Cnw [j] ; - ASSERT (cnt == total_weight) ; -#endif + //---------------------------------------------------------------------- + // create the map from the uncompressed graph to the compressed graph + //---------------------------------------------------------------------- + + // Cmap [j] = k if node j is alive and the kth node of compressed graph. + // The mapping is done monotonically (that is, k <= j) to simplify the + // uncompression later on. Cmap [j] = EMPTY if node j is dead. + + for (j = 0 ; j < n ; j++) + { + Cmap [j] = EMPTY ; + } + k = 0 ; + for (j = 0 ; j < n ; j++) + { + if (Cnw [j] > 0) + { + ASSERT (k <= j) ; + Cmap [j] = k++ ; + } + } + cn = k ; // # of nodes in compressed graph + PRINT2 (("compressed graph from "ID" to "ID" nodes\n", n, cn)) ; + ASSERT (cn > 1 && cn == n - nodes_pruned) ; + + //---------------------------------------------------------------------- + // create the compressed graph + //---------------------------------------------------------------------- + + k = 0 ; + pdest = 0 ; + for (j = 0 ; j < n ; j++) + { + if (Cnw [j] > 0) + { + // node j in the full graph is node k in the compressed graph + ASSERT (k <= j && Cmap [j] == k) ; + p = Cp [j] ; + pend = Cp [j+1] ; + Cp [k] = pdest ; + Cnw [k] = Cnw [j] ; + for ( ; p < pend ; p++) + { + // prune dead nodes, and remap to new node numbering + i = Ci [p] ; + ASSERT (i >= 0 && i < n && i != j) ; + i = Cmap [i] ; + ASSERT (i >= EMPTY && i < cn && i != k) ; + if (i > EMPTY) + { + ASSERT (pdest <= p) ; + Ci [pdest++] = i ; + } + } + k++ ; + } + } + Cp [cn] = pdest ; + C->nrow = cn ; + C->ncol = cn ; // affects mem stats unless restored when C free'd + + #ifndef NDEBUG + PRINT2 (("pruned graph ("ID"/"ID") nodes, ("ID"/"ID") edges\n", + cn, n, pdest, nz)) ; + PRINT2 (("compressed graph:\n")) ; + for (cnt = 0, j = 0 ; j < cn ; j++) + { + PRINT2 ((""ID": ", j)) ; + for (p = Cp [j] ; p < Cp [j+1] ; p++) + { + i = Ci [p] ; + PRINT3 ((""ID" ", i)) ; + ASSERT (i >= 0 && i < cn && i != j) ; + } + PRINT2 (("weight: "ID"\n", Cnw [j])) ; + ASSERT (Cnw [j] > 0) ; + cnt += Cnw [j] ; + } + ASSERT (cnt == total_weight) ; + for (j = 0 ; j < n ; j++) PRINT2 (("Cmap ["ID"] = "ID"\n", j, Cmap[j])); + ASSERT (k == cn) ; + #endif + + //---------------------------------------------------------------------- + // find the separator of the compressed graph + //---------------------------------------------------------------------- + + // FUTURE WORK: could call CHACO, SCOTCH, ... here too + csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ; + + if (csep < 0) + { + // failed + return (-1) ; + } + + PRINT2 (("Part: ")) ; + DEBUG (for (j = 0 ; j < cn ; j++) PRINT2 ((""ID" ", Part [j]))) ; + PRINT2 (("\n")) ; + + // Cp and Ci no longer needed + + //---------------------------------------------------------------------- + // find the separator of the uncompressed graph + //---------------------------------------------------------------------- + + // expand the separator to live nodes in the uncompressed graph + for (j = n-1 ; j >= 0 ; j--) + { + // do this in reverse order so that Cnw can be expanded in place + k = Cmap [j] ; + ASSERT (k >= EMPTY && k < n) ; + if (k > EMPTY) + { + // node k in compressed graph and is node j in full graph + ASSERT (k <= j) ; + ASSERT (Hash [j] >= EMPTY) ; + Part [j] = Part [k] ; + Cnw [j] = Cnw [k] ; + } + else + { + // node j is a dead node + Cnw [j] = 0 ; + DEBUG (Part [j] = EMPTY) ; + ASSERT (Hash [j] < EMPTY) ; + } + } + + // find the components for the dead nodes + for (i = 0 ; i < n ; i++) + { + if (Hash [i] < EMPTY) + { + // node i has been absorbed into node j + j = FLIP (Hash [i]) ; + ASSERT (Part [i] == EMPTY && j >= 0 && j < n && Cnw [i] == 0) ; + Part [i] = Part [j] ; + } + ASSERT (Part [i] >= 0 && Part [i] <= 2) ; + } + + #ifndef NDEBUG + PRINT2 (("Part: ")) ; + for (cnt = 0, j = 0 ; j < n ; j++) + { + ASSERT (Part [j] != EMPTY) ; + PRINT2 ((""ID" ", Part [j])) ; + if (Part [j] == 2) cnt += Cnw [j] ; + } + PRINT2 (("\n")) ; + PRINT2 (("csep "ID" "ID"\n", cnt, csep)) ; + ASSERT (cnt == csep) ; + for (cnt = 0, j = 0 ; j < n ; j++) cnt += Cnw [j] ; + ASSERT (cnt == total_weight) ; + #endif } - /* ---------------------------------------------------------------------- */ - /* return the separator (or -1 if error) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return the separator (or -1 if error) + //-------------------------------------------------------------------------- PRINT2 (("Partition done, n "ID" csep "ID"\n", n, csep)) ; return (csep) ; } +//------------------------------------------------------------------------------ +// clear_flag +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === clear_flag =========================================================== */ -/* ========================================================================== */ - -/* A node j has been removed from the graph if Flag [j] < EMPTY. - * If Flag [j] >= EMPTY && Flag [j] < mark, then node j is alive but unmarked. - * Flag [j] == mark means that node j is alive and marked. Incrementing mark - * means that all nodes are either (still) dead, or live but unmarked. - * - * If Map is NULL, then on output, Common->mark < Common->Flag [i] for all i - * from 0 to Common->nrow. This is the same output condition as - * cholmod_clear_flag, except that this routine maintains the Flag [i] < EMPTY - * condition as well, if that condition was true on input. - * - * If Map is non-NULL, then on output, Common->mark < Common->Flag [i] for all - * i in the set Map [0..cn-1]. - * - * workspace: Flag (nrow) - */ +// A node j has been removed from the graph if Flag [j] < EMPTY. +// If Flag [j] >= EMPTY && Flag [j] < mark, then node j is alive but unmarked. +// Flag [j] == mark means that node j is alive and marked. Incrementing mark +// means that all nodes are either (still) dead, or live but unmarked. +// +// If Map is NULL, then on output, Common->mark < Common->Flag [i] for all i +// from 0 to Common->nrow. This is the same output condition as +// cholmod_clear_flag, except that this routine maintains the Flag [i] < EMPTY +// condition as well, if that condition was true on input. +// +// If Map is non-NULL, then on output, Common->mark < Common->Flag [i] for all +// i in the set Map [0..cn-1]. +// +// workspace: Flag (nrow) static int64_t clear_flag (Int *Map, Int cn, cholmod_common *Common) { @@ -594,115 +590,114 @@ static int64_t clear_flag (Int *Map, Int cn, cholmod_common *Common) PRINT2 (("new mark %ld\n", Common->mark)) ; if (Common->mark <= 0) { - nrow = Common->nrow ; - Flag = Common->Flag ; + nrow = Common->nrow ; + Flag = Common->Flag ; if (Map != NULL) { for (i = 0 ; i < cn ; i++) { - /* if Flag [Map [i]] < EMPTY, leave it alone */ + // if Flag [Map [i]] < EMPTY, leave it alone if (Flag [Map [i]] >= EMPTY) { Flag [Map [i]] = EMPTY ; } } - /* now Flag [Map [i]] <= EMPTY for all i */ + // now Flag [Map [i]] <= EMPTY for all i } else { for (i = 0 ; i < nrow ; i++) { - /* if Flag [i] < EMPTY, leave it alone */ + // if Flag [i] < EMPTY, leave it alone if (Flag [i] >= EMPTY) { Flag [i] = EMPTY ; } } - /* now Flag [i] <= EMPTY for all i */ + // now Flag [i] <= EMPTY for all i } - Common->mark = 0 ; + Common->mark = 0 ; } return (Common->mark) ; } +//------------------------------------------------------------------------------ +// find_components +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === find_components ====================================================== */ -/* ========================================================================== */ - -/* Find all connected components of the current subgraph C. The subgraph C - * consists of the nodes of B that appear in the set Map [0..cn-1]. If Map - * is NULL, then it is assumed to be the identity mapping - * (Map [0..cn-1] = 0..cn-1). - * - * A node j does not appear in B if it has been ordered (Flag [j] < EMPTY, - * which means that j has been ordered and is "deleted" from B). - * - * If the size of a component is large, it is placed on the component stack, - * Cstack. Otherwise, its nodes are ordered and it is not placed on the Cstack. - * - * A component S is defined by a "representative node" (repnode for short) - * called the snode, which is one of the nodes in the subgraph. Likewise, the - * subgraph C is defined by its repnode, called cnode. - * - * If Part is not NULL on input, then Part [i] determines how the components - * are placed on the stack. Components containing nodes i with Part [i] == 0 - * are placed first, followed by components with Part [i] == 1. - * - * The first node placed in each of the two parts is flipped when placed in - * the Cstack. This allows the components of the two parts to be found simply - * by traversing the Cstack. - * - * workspace: Flag (nrow) - */ +// Find all connected components of the current subgraph C. The subgraph C +// consists of the nodes of B that appear in the set Map [0..cn-1]. If Map +// is NULL, then it is assumed to be the identity mapping +// (Map [0..cn-1] = 0..cn-1). +// +// A node j does not appear in B if it has been ordered (Flag [j] < EMPTY, +// which means that j has been ordered and is "deleted" from B). +// +// If the size of a component is large, it is placed on the component stack, +// Cstack. Otherwise, its nodes are ordered and it is not placed on the Cstack. +// +// A component S is defined by a "representative node" (repnode for short) +// called the snode, which is one of the nodes in the subgraph. Likewise, the +// subgraph C is defined by its repnode, called cnode. +// +// If Part is not NULL on input, then Part [i] determines how the components +// are placed on the stack. Components containing nodes i with Part [i] == 0 +// are placed first, followed by components with Part [i] == 1. +// +// The first node placed in each of the two parts is flipped when placed in +// the Cstack. This allows the components of the two parts to be found simply +// by traversing the Cstack. +// +// workspace: Flag (nrow) static void find_components ( - /* inputs, not modified on output */ + // inputs, not modified on output cholmod_sparse *B, - Int Map [ ], /* size n, only Map [0..cn-1] used */ - Int cn, /* # of nodes in C */ - Int cnode, /* root node of component C, or EMPTY if C is the - * entire graph B */ + Int Map [ ], // size n, only Map [0..cn-1] used + Int cn, // # of nodes in C + Int cnode, // root node of component C, or EMPTY if C is the + // entire graph B - Int Part [ ], /* size cn, optional */ + Int Part [ ], // size cn, optional - /* input/output */ - Int Bnz [ ], /* size n. Bnz [j] = # nonzeros in column j of B. - * Reduce since B is pruned of dead nodes. */ + // input/output + Int Bnz [ ], // size n. Bnz [j] = # nonzeros in column j of B. + // Reduce since B is pruned of dead nodes. - Int CParent [ ], /* CParent [i] = j if component with repnode j is - * the parent of the component with repnode i. - * CParent [i] = EMPTY if the component with - * repnode i is a root of the separator tree. - * CParent [i] is -2 if i is not a repnode. */ - Int Cstack [ ], /* component stack for nested dissection */ - Int *top, /* Cstack [0..top] contains root nodes of the - * the components currently in the stack */ + Int CParent [ ], // CParent [i] = j if component with repnode j is + // the parent of the component with repnode i. + // CParent [i] = EMPTY if the component with + // repnode i is a root of the separator tree. + // CParent [i] is -2 if i is not a repnode. + Int Cstack [ ], // component stack for nested dissection + Int *top, // Cstack [0..top] contains root nodes of the + // the components currently in the stack - /* workspace, undefined on input and output: */ - Int Queue [ ], /* size n, for breadth-first search */ + // workspace, undefined on input and output: + Int Queue [ ], // size n, for breadth-first search cholmod_common *Common ) { + Int n, mark, cj, j, sj, sn, p, i, snode, pstart, pdest, pend, nd_components, - part, first, save_mark ; + part, first, save_mark ; Int *Bp, *Bi, *Flag ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- PRINT2 (("find components: cn %d\n", cn)) ; - Flag = Common->Flag ; /* size n */ + Flag = Common->Flag ; // size n - /* force initialization of Flag [Map [0..cn-1]] */ - save_mark = Common->mark ; /* save the current mark */ + // force initialization of Flag [Map [0..cn-1]] + save_mark = Common->mark ; // save the current mark Common->mark = EMPTY ; - /* clear Flag; preserve Flag [Map [i]] if Flag [Map [i]] already < EMPTY */ - /* this takes O(cn) time */ + // clear Flag; preserve Flag [Map [i]] if Flag [Map [i]] already < EMPTY + // this takes O(cn) time mark = clear_flag (Map, cn, Common) ; Bp = B->p ; @@ -711,112 +706,110 @@ static void find_components ASSERT (cnode >= EMPTY && cnode < n) ; ASSERT (IMPLIES (cnode >= 0, Flag [cnode] < EMPTY)) ; - /* get ordering parameters */ + // get ordering parameters nd_components = Common->method [Common->current].nd_components ; - /* ---------------------------------------------------------------------- */ - /* find the connected components of C via a breadth-first search */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the connected components of C via a breadth-first search + //-------------------------------------------------------------------------- part = (Part == NULL) ? 0 : 1 ; - /* examine each part (part 1 and then part 0) */ + // examine each part (part 1 and then part 0) for (part = (Part == NULL) ? 0 : 1 ; part >= 0 ; part--) { - /* first is TRUE for the first connected component in each part */ - first = TRUE ; - - /* find all connected components in the current part */ - for (cj = 0 ; cj < cn ; cj++) - { - /* get node snode, which is node cj of C. It might already be in - * the separator of C (and thus ordered, with Flag [snode] < EMPTY) - */ - snode = (Map == NULL) ? (cj) : (Map [cj]) ; - ASSERT (snode >= 0 && snode < n) ; - - if (Flag [snode] >= EMPTY && Flag [snode] < mark - && ((Part == NULL) || Part [cj] == part)) - { - - /* ---------------------------------------------------------- */ - /* find new connected component S */ - /* ---------------------------------------------------------- */ - - /* node snode is the repnode of a connected component S, the - * parent of which is cnode, the repnode of C. If cnode is - * EMPTY then C is the original graph B. */ - PRINT2 (("----------:::snode "ID" cnode "ID"\n", snode, cnode)); - - ASSERT (CParent [snode] == -2) ; - if (first || nd_components) - { - /* If this is the first node in this part, then it becomes - * the repnode of all components in this part, and all - * components in this part form a single node in the - * separator tree. If nd_components is TRUE, then all - * connected components form their own node in the - * separator tree. - */ - CParent [snode] = cnode ; - } - - /* place j in the queue and mark it */ - Queue [0] = snode ; - Flag [snode] = mark ; - sn = 1 ; - - /* breadth-first traversal, starting at node j */ - for (sj = 0 ; sj < sn ; sj++) - { - /* get node j from head of Queue and traverse its edges */ - j = Queue [sj] ; - PRINT2 ((" j: "ID"\n", j)) ; - ASSERT (j >= 0 && j < n) ; - ASSERT (Flag [j] == mark) ; - pstart = Bp [j] ; - pdest = pstart ; - pend = pstart + Bnz [j] ; - for (p = pstart ; p < pend ; p++) - { - i = Bi [p] ; - if (i != j && Flag [i] >= EMPTY) - { - /* node is still in the graph */ - Bi [pdest++] = i ; - if (Flag [i] < mark) - { - /* node i is in this component S, and unflagged - * (first time node i has been seen in this BFS) - * place node i in the queue and mark it */ - Queue [sn++] = i ; - Flag [i] = mark ; - } - } - } - /* edges to dead nodes have been removed */ - Bnz [j] = pdest - pstart ; - } - - /* ---------------------------------------------------------- */ - /* order S if it is small; place it on Cstack otherwise */ - /* ---------------------------------------------------------- */ - - PRINT2 (("sn "ID"\n", sn)) ; - - /* place the new component on the Cstack. Flip the node if - * is the first connected component of the current part, - * or if all components are treated as their own node in - * the separator tree. */ - Cstack [++(*top)] = - (first || nd_components) ? FLIP (snode) : snode ; - first = FALSE ; - } - } + // first is TRUE for the first connected component in each part + first = TRUE ; + + // find all connected components in the current part + for (cj = 0 ; cj < cn ; cj++) + { + // get node snode, which is node cj of C. It might already be in + // the separator of C (and thus ordered, with Flag [snode] < EMPTY) + snode = (Map == NULL) ? (cj) : (Map [cj]) ; + ASSERT (snode >= 0 && snode < n) ; + + if (Flag [snode] >= EMPTY && Flag [snode] < mark + && ((Part == NULL) || Part [cj] == part)) + { + + //-------------------------------------------------------------- + // find new connected component S + //-------------------------------------------------------------- + + // node snode is the repnode of a connected component S, the + // parent of which is cnode, the repnode of C. If cnode is + // EMPTY then C is the original graph B. + PRINT2 (("----------:::snode "ID" cnode "ID"\n", snode, cnode)); + + ASSERT (CParent [snode] == -2) ; + if (first || nd_components) + { + // If this is the first node in this part, then it becomes + // the repnode of all components in this part, and all + // components in this part form a single node in the + // separator tree. If nd_components is TRUE, then all + // connected components form their own node in the + // separator tree. + CParent [snode] = cnode ; + } + + // place j in the queue and mark it + Queue [0] = snode ; + Flag [snode] = mark ; + sn = 1 ; + + // breadth-first traversal, starting at node j + for (sj = 0 ; sj < sn ; sj++) + { + // get node j from head of Queue and traverse its edges + j = Queue [sj] ; + PRINT2 ((" j: "ID"\n", j)) ; + ASSERT (j >= 0 && j < n) ; + ASSERT (Flag [j] == mark) ; + pstart = Bp [j] ; + pdest = pstart ; + pend = pstart + Bnz [j] ; + for (p = pstart ; p < pend ; p++) + { + i = Bi [p] ; + if (i != j && Flag [i] >= EMPTY) + { + // node is still in the graph + Bi [pdest++] = i ; + if (Flag [i] < mark) + { + // node i is in this component S, and unflagged + // (first time node i has been seen in this BFS) + // place node i in the queue and mark it + Queue [sn++] = i ; + Flag [i] = mark ; + } + } + } + // edges to dead nodes have been removed + Bnz [j] = pdest - pstart ; + } + + //-------------------------------------------------------------- + // order S if it is small; place it on Cstack otherwise + //-------------------------------------------------------------- + + PRINT2 (("sn "ID"\n", sn)) ; + + // place the new component on the Cstack. Flip the node if + // is the first connected component of the current part, + // or if all components are treated as their own node in + // the separator tree. + Cstack [++(*top)] = + (first || nd_components) ? FLIP (snode) : snode ; + first = FALSE ; + } + } } - /* restore the flag (normally taking O(1) time except for Int overflow) */ + // restore the flag (normally taking O(1) time except for Int overflow) Common->mark = save_mark++ ; clear_flag (NULL, 0, Common) ; DEBUG (for (i = 0 ; i < n ; i++) ASSERT (Flag [i] < Common->mark)) ; @@ -824,46 +817,42 @@ static void find_components #endif -/* ========================================================================== */ -/* === cholmod_bisect ======================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_bisect +//------------------------------------------------------------------------------ -/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. - * - * workspace: Flag (nrow), - * Iwork (nrow if symmetric, max (nrow,ncol) if unsymmetric). - * Allocates a temporary matrix B=A*A' or B=A, - * and O(nnz(A)) temporary memory space. - */ +// Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. +// +// workspace: Flag (nrow), +// Iwork (nrow if symmetric, max (nrow,ncol) if unsymmetric). +// Allocates a temporary matrix B=A*A' or B=A, +// and O(nnz(A)) temporary memory space. -int64_t CHOLMOD(bisect) /* returns # of nodes in separator */ +int64_t CHOLMOD(bisect) // returns # of nodes in separator ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to bisect */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int compress, /* if TRUE, compress the graph first */ - /* ---- output --- */ - Int *Partition, /* size A->nrow. Node i is in the left graph if - * Partition [i] = 0, the right graph if 1, and in the - * separator if 2. */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to bisect + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + int compress, // if TRUE, compress the graph first + // output: + Int *Partition, // size A->nrow. Node i is in the left graph if + // Partition [i] = 0, the right graph if 1, and in the + // separator if 2. cholmod_common *Common ) { + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + #ifndef NPARTITION Int *Bp, *Bi, *Hash, *Cmap, *Bnw, *Bew, *Iwork ; cholmod_sparse *B ; UInt hash ; Int j, n, bnz, sepsize, p, pend ; - size_t csize, s ; - int ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; @@ -871,140 +860,141 @@ int64_t CHOLMOD(bisect) /* returns # of nodes in separator */ RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* quick return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return + //-------------------------------------------------------------------------- n = A->nrow ; if (n == 0) { - return (0) ; + return (0) ; } - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = n + MAX (n, A->ncol) */ - s = CHOLMOD(add_size_t) (A->nrow, MAX (A->nrow, A->ncol), &ok) ; + // s = nrow + MAX (nrow, ncol) + int ok = TRUE ; + size_t s = CHOLMOD(add_size_t) (A->nrow, MAX (A->nrow, A->ncol), &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (EMPTY) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (EMPTY) ; } - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; Iwork = Common->Iwork ; - Hash = Iwork ; /* size n, (i/l/l) */ - Cmap = Iwork + n ; /* size n, (i/i/l) */ + Hash = Iwork ; // size n + Cmap = Iwork + n ; // size n - /* ---------------------------------------------------------------------- */ - /* convert the matrix to adjacency list form */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert the matrix to adjacency list form + //-------------------------------------------------------------------------- - /* The input graph to must be symmetric, with no diagonal entries - * present. The columns need not be sorted. */ + // The input graph to must be symmetric, with no diagonal entries + // present. The columns need not be sorted. - /* B = A, A*A', or A(:,f)*A(:,f)', upper and lower parts present */ + // B = A, A*A', or A(:,f)*A(:,f)', upper and lower parts present if (A->stype) { - /* Add the upper/lower part to a symmetric lower/upper matrix by - * converting to unsymmetric mode */ - /* workspace: Iwork (nrow) */ - B = CHOLMOD(copy) (A, 0, -1, Common) ; + // Add the upper/lower part to a symmetric lower/upper matrix by + // converting to unsymmetric mode + // workspace: Iwork (nrow) + B = CHOLMOD(copy) (A, 0, -1, Common) ; } else { - /* B = A*A' or A(:,f)*A(:,f)', no diagonal */ - /* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */ - B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; + // B = A*A' or A(:,f)*A(:,f)', no diagonal + // workspace: Flag (nrow), Iwork (max (nrow,ncol)) + B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; } if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } Bp = B->p ; Bi = B->i ; bnz = Bp [n] ; ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ; - /* B does not include the diagonal, and both upper and lower parts. - * Common->anz includes the diagonal, and just the lower part of B */ + // B does not include the diagonal, and both upper and lower parts. + // Common->anz includes the diagonal, and just the lower part of B Common->anz = bnz / 2 + ((double) n) ; - /* Bew should be at least size n for the hash function to work well */ - /* this cannot cause overflow, because the matrix is already created */ - csize = MAX (((size_t) n) + 1, (size_t) bnz) ; + // Bew should be at least size n for the hash function to work well + // this cannot cause overflow, because the matrix is already created + size_t csize = MAX (((size_t) n) + 1, (size_t) bnz) ; - /* create the graph using Flag as workspace for node weights [ */ - Bnw = Common->Flag ; /* size n workspace */ + // create the graph using Flag as workspace for node weights [ + Bnw = Common->Flag ; // size n workspace - /* compute hash for each node if compression requested */ + // compute hash for each node if compression requested if (compress) { - for (j = 0 ; j < n ; j++) - { - hash = j ; - pend = Bp [j+1] ; - for (p = Bp [j] ; p < pend ; p++) - { - hash += Bi [p] ; - ASSERT (Bi [p] != j) ; - } - /* finalize the hash key for node j */ - hash %= csize ; - Hash [j] = (Int) hash ; - ASSERT (Hash [j] >= 0 && Hash [j] < csize) ; - } + for (j = 0 ; j < n ; j++) + { + hash = j ; + pend = Bp [j+1] ; + for (p = Bp [j] ; p < pend ; p++) + { + hash += Bi [p] ; + ASSERT (Bi [p] != j) ; + } + // finalize the hash key for node j + hash %= csize ; + Hash [j] = (Int) hash ; + ASSERT (Hash [j] >= 0 && Hash [j] < csize) ; + } } - /* allocate edge weights */ + // allocate edge weights Bew = CHOLMOD(malloc) (csize, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - CHOLMOD(free_sparse) (&B, Common) ; - CHOLMOD(free) (csize, sizeof (Int), Bew, Common) ; - return (EMPTY) ; + // out of memory + CHOLMOD(free_sparse) (&B, Common) ; + CHOLMOD(free) (csize, sizeof (Int), Bew, Common) ; + return (EMPTY) ; } - /* graph has unit node and edge weights */ + // graph has unit node and edge weights for (j = 0 ; j < n ; j++) { - Bnw [j] = 1 ; + Bnw [j] = 1 ; } for (s = 0 ; s < csize ; s++) { - Bew [s] = 1 ; + Bew [s] = 1 ; } - /* ---------------------------------------------------------------------- */ - /* compress and partition the graph */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compress and partition the graph + //-------------------------------------------------------------------------- sepsize = partition ( -#ifndef NDEBUG - csize, -#endif - compress, Hash, B, Bnw, Bew, Cmap, Partition, Common) ; + #ifndef NDEBUG + csize, + #endif + compress, Hash, B, Bnw, Bew, Cmap, Partition, Common) ; - /* contents of Bp, Bi, Bnw, and Bew no longer needed ] */ + // contents of Bp, Bi, Bnw, and Bew no longer needed ] - /* If partition fails, free the workspace below and return sepsize < 0 */ + // If partition fails, free the workspace below and return sepsize < 0 - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- - B->ncol = n ; /* restore size for memory usage statistics */ + B->ncol = n ; // restore size for memory usage statistics CHOLMOD(free_sparse) (&B, Common) ; Common->mark = EMPTY ; CLEAR_FLAG (Common) ; @@ -1017,68 +1007,63 @@ int64_t CHOLMOD(bisect) /* returns # of nodes in separator */ #endif } +//------------------------------------------------------------------------------ +// cholmod_nested_dissection +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_nested_dissection ============================================ */ -/* ========================================================================== */ - -/* This method uses a node bisector, applied recursively (but using a - * non-recursive algorithm). Once the graph is partitioned, it calls a - * constrained min degree code (CAMD or CSYMAMD for A+A', and CCOLAMD for A*A') - * to order all the nodes in the graph - but obeying the constraints determined - * by the separators. This routine is similar to METIS_NodeND, except for how - * it treats the leaf nodes. METIS_NodeND orders the leaves of the separator - * tree with MMD, ignoring the rest of the matrix when ordering a single leaf. - * This routine orders the whole matrix with CSYMAMD or CCOLAMD, all at once, - * when the graph partitioning is done. - * - * This function also returns a postorderd separator tree (CParent), and a - * mapping of nodes in the graph to nodes in the separator tree (Cmember). - * - * workspace: Flag (nrow), Head (nrow+1), Iwork (4*nrow + (ncol if unsymmetric)) - * Allocates a temporary matrix B=A*A' or B=A, - * and O(nnz(A)) temporary memory space. - * Allocates an additional 3*n*sizeof(Int) temporary workspace - */ - -int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ +// This method uses a node bisector, applied recursively (but using a +// non-recursive algorithm). Once the graph is partitioned, it calls a +// constrained min degree code (CAMD or CSYMAMD for A+A', and CCOLAMD for A*A') +// to order all the nodes in the graph - but obeying the constraints determined +// by the separators. This routine is similar to METIS_NodeND, except for how +// it treats the leaf nodes. METIS_NodeND orders the leaves of the separator +// tree with MMD, ignoring the rest of the matrix when ordering a single leaf. +// This routine orders the whole matrix with CSYMAMD or CCOLAMD, all at once, +// when the graph partitioning is done. +// +// This function also returns a postorderd separator tree (CParent), and a +// mapping of nodes in the graph to nodes in the separator tree (Cmember). +// +// workspace: Flag (nrow), Head (nrow+1), Iwork (4*nrow + (ncol if unsymmetric)) +// Allocates a temporary matrix B=A*A' or B=A, +// and O(nnz(A)) temporary memory space. +// Allocates an additional 3*n*sizeof(Int) temporary workspace + +int64_t CHOLMOD(nested_dissection) // returns # of components, or -1 if error ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to order */ - Int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - Int *Perm, /* size A->nrow, output permutation */ - Int *CParent, /* size A->nrow. On output, CParent [c] is the parent - * of component c, or EMPTY if c is a root, and where - * c is in the range 0 to # of components minus 1 */ - Int *Cmember, /* size A->nrow. Cmember [j] = c if node j of A is - * in component c */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to order + Int *fset, // subset of 0:(A->ncol)-1 + size_t fsize, // size of fset + // output: + Int *Perm, // size A->nrow, output permutation + Int *CParent, // size A->nrow. On output, CParent [c] is the parent + // of component c, or EMPTY if c is a root, and where + // c is in the range 0 to # of components minus 1 + Int *Cmember, // size A->nrow. Cmember [j] = c if node j of A is + // in component c cholmod_common *Common ) { + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + #ifndef NPARTITION double prune_dense, nd_oksep ; Int *Bp, *Bi, *Bnz, *Cstack, *Imap, *Map, *Flag, *Head, *Next, *Bnw, *Iwork, - *Ipost, *NewParent, *Hash, *Cmap, *Cp, *Ci, *Cew, *Cnw, *Part, *Post, - *Work3n ; + *Ipost, *NewParent, *Hash, *Cmap, *Cp, *Ci, *Cew, *Cnw, *Part, *Post, + *Work3n ; UInt hash ; - Int n, bnz, top, i, j, k, cnode, cdense, p, cj, cn, ci, cnz, mark, c, uncol, - sepsize, parent, ncomponents, threshold, ndense, pstart, pdest, pend, - nd_compress, nd_camd, csize, jnext, nd_small, total_weight, - nchild, child = EMPTY ; + Int n, bnz, top, i, j, k, cnode, cdense, p, cj, cn, ci, cnz, mark, c, + sepsize, parent, ncomponents, threshold, ndense, pstart, pdest, pend, + nd_compress, nd_camd, csize, jnext, nd_small, total_weight, + nchild, child = EMPTY ; cholmod_sparse *B, *C ; - size_t s ; - int ok = TRUE ; DEBUG (Int cnt) ; - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; RETURN_IF_NULL (Perm, EMPTY) ; @@ -1087,21 +1072,21 @@ int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* quick return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // quick return + //-------------------------------------------------------------------------- n = A->nrow ; if (n == 0) { - return (1) ; + return (1) ; } - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - /* get ordering parameters */ + // get ordering parameters prune_dense = Common->method [Common->current].prune_dense ; nd_compress = Common->method [Common->current].nd_compress ; nd_oksep = Common->method [Common->current].nd_oksep ; @@ -1111,81 +1096,82 @@ int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ nd_small = Common->method [Common->current].nd_small ; nd_small = MAX (4, nd_small) ; - PRINT0 (("nd_components %d nd_small %d nd_oksep %g\n", - Common->method [Common->current].nd_components, - nd_small, nd_oksep)) ; + PRINT0 (("nd_components %d nd_small %d nd_oksep %g\n", + Common->method [Common->current].nd_components, + nd_small, nd_oksep)) ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 4*n + uncol */ - uncol = (A->stype == 0) ? A->ncol : 0 ; - s = CHOLMOD(mult_size_t) (n, 4, &ok) ; + // s = 4*nrow + uncol + size_t uncol = (A->stype == 0) ? A->ncol : 0 ; + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (A->nrow, 4, &ok) ; s = CHOLMOD(add_size_t) (s, uncol, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (EMPTY) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (EMPTY) ; } - CHOLMOD(allocate_work) (n, s, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - Flag = Common->Flag ; /* size n */ - Head = Common->Head ; /* size n+1, all equal to -1 */ + Flag = Common->Flag ; // size n + Head = Common->Head ; // size n+1, all equal to -1 Iwork = Common->Iwork ; - Imap = Iwork ; /* size n, same as Queue in find_components */ - Map = Iwork + n ; /* size n */ - Bnz = Iwork + 2*((size_t) n) ; /* size n */ - Hash = Iwork + 3*((size_t) n) ; /* size n */ + Imap = Iwork ; // size n, same as Queue in find_components + Map = Iwork + n ; // size n + Bnz = Iwork + 2*((size_t) n) ; // size n + Hash = Iwork + 3*((size_t) n) ; // size n Work3n = CHOLMOD(malloc) (n, 3*sizeof (Int), Common) ; - Part = Work3n ; /* size n */ - Bnw = Part + n ; /* size n */ - Cnw = Bnw + n ; /* size n */ + Part = Work3n ; // size n + Bnw = Part + n ; // size n + Cnw = Bnw + n ; // size n - Cstack = Perm ; /* size n, use Perm as workspace for Cstack [ */ - Cmap = Cmember ; /* size n, use Cmember as workspace [ */ + Cstack = Perm ; // size n, use Perm as workspace for Cstack [ + Cmap = Cmember ; // size n, use Cmember as workspace [ if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } - /* ---------------------------------------------------------------------- */ - /* convert B to symmetric form with both upper/lower parts present */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // convert B to symmetric form with both upper/lower parts present + //-------------------------------------------------------------------------- - /* B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present */ + // B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present if (A->stype) { - /* Add the upper/lower part to a symmetric lower/upper matrix by - * converting to unsymmetric mode */ - /* workspace: Iwork (nrow) */ - B = CHOLMOD(copy) (A, 0, -1, Common) ; + // Add the upper/lower part to a symmetric lower/upper matrix by + // converting to unsymmetric mode + // workspace: Iwork (nrow) + B = CHOLMOD(copy) (A, 0, -1, Common) ; } else { - /* B = A*A' or A(:,f)*A(:,f)', no diagonal */ - /* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */ - B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; + // B = A*A' or A(:,f)*A(:,f)', no diagonal + // workspace: Flag (nrow), Iwork (max (nrow,ncol)) + B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ; } if (Common->status < CHOLMOD_OK) { - CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; - return (EMPTY) ; + CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; + return (EMPTY) ; } Bp = B->p ; Bi = B->i ; @@ -1194,33 +1180,33 @@ int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ csize = MAX (n, bnz) ; ASSERT (CHOLMOD(dump_sparse) (B, "B for nd:", Common) >= 0) ; - /* ---------------------------------------------------------------------- */ - /* initializations */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // initializations + //-------------------------------------------------------------------------- - /* all nodes start out unmarked and unordered (Type 4, see below) */ + // all nodes start out unmarked and unordered (Type 4, see below) Common->mark = EMPTY ; CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; ASSERT (Flag == Common->Flag) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; for (j = 0 ; j < n ; j++) { - CParent [j] = -2 ; + CParent [j] = -2 ; } - /* prune dense nodes from B */ + // prune dense nodes from B if (isnan (prune_dense) || prune_dense < 0) { - /* only remove completely dense nodes */ - threshold = n-2 ; + // only remove completely dense nodes + threshold = n-2 ; } else { - /* remove nodes with degree more than threshold */ - threshold = (Int) (MAX (16, prune_dense * sqrt ((double) (n)))) ; - threshold = MIN (n, threshold) ; + // remove nodes with degree more than threshold + threshold = (Int) (MAX (16, prune_dense * sqrt ((double) (n)))) ; + threshold = MIN (n, threshold) ; } ndense = 0 ; cnode = EMPTY ; @@ -1228,725 +1214,723 @@ int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ for (j = 0 ; j < n ; j++) { - Bnz [j] = Bp [j+1] - Bp [j] ; - if (Bnz [j] > threshold) - { - /* node j is dense, prune it from B */ - PRINT2 (("j is dense %d\n", j)) ; - ndense++ ; - if (cnode == EMPTY) - { - /* first dense node found becomes root of this component, - * which contains all of the dense nodes found here */ - cdense = j ; - cnode = j ; - CParent [cnode] = EMPTY ; - } - Flag [j] = FLIP (cnode) ; - } + Bnz [j] = Bp [j+1] - Bp [j] ; + if (Bnz [j] > threshold) + { + // node j is dense, prune it from B + PRINT2 (("j is dense %d\n", j)) ; + ndense++ ; + if (cnode == EMPTY) + { + // first dense node found becomes root of this component, + // which contains all of the dense nodes found here + cdense = j ; + cnode = j ; + CParent [cnode] = EMPTY ; + } + Flag [j] = FLIP (cnode) ; + } } B->packed = FALSE ; ASSERT (B->nz == NULL) ; if (ndense == n) { - /* all nodes removed: Perm is identity, all nodes in component zero, - * and the separator tree has just one node. */ - PRINT2 (("all nodes are dense\n")) ; - for (k = 0 ; k < n ; k++) - { - Perm [k] = k ; - Cmember [k] = 0 ; - } - CParent [0] = EMPTY ; - CHOLMOD(free_sparse) (&B, Common) ; - CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; - Common->mark = EMPTY ; - CLEAR_FLAG (Common) ; + // all nodes removed: Perm is identity, all nodes in component zero, + // and the separator tree has just one node. + PRINT2 (("all nodes are dense\n")) ; + for (k = 0 ; k < n ; k++) + { + Perm [k] = k ; + Cmember [k] = 0 ; + } + CParent [0] = EMPTY ; + CHOLMOD(free_sparse) (&B, Common) ; + CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; + Common->mark = EMPTY ; + CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - return (1) ; + return (1) ; } - /* Cp and Ci are workspace to construct the subgraphs to partition */ + // Cp and Ci are workspace to construct the subgraphs to partition C = CHOLMOD(allocate_sparse) (n, n, csize, FALSE, TRUE, 0, CHOLMOD_PATTERN, - Common) ; + Common) ; Cew = CHOLMOD(malloc) (csize, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - CHOLMOD(free_sparse) (&C, Common) ; - CHOLMOD(free_sparse) (&B, Common) ; - CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ; - CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; - Common->mark = EMPTY ; - CLEAR_FLAG (Common) ; + // out of memory + CHOLMOD(free_sparse) (&C, Common) ; + CHOLMOD(free_sparse) (&B, Common) ; + CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ; + CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; + Common->mark = EMPTY ; + CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - PRINT2 (("out of memory for C, etc\n")) ; - return (EMPTY) ; + PRINT2 (("out of memory for C, etc\n")) ; + return (EMPTY) ; } Cp = C->p ; Ci = C->i ; - /* create initial unit node and edge weights */ + // create initial unit node and edge weights for (j = 0 ; j < n ; j++) { - Bnw [j] = 1 ; + Bnw [j] = 1 ; } for (p = 0 ; p < csize ; p++) { - Cew [p] = 1 ; + Cew [p] = 1 ; } - /* push the initial connnected components of B onto the Cstack */ - top = EMPTY ; /* Cstack is empty */ - /* workspace: Flag (nrow), Iwork (nrow); use Imap as workspace for Queue [*/ + // push the initial connnected components of B onto the Cstack + top = EMPTY ; // Cstack is empty + // workspace: Flag (nrow), Iwork (nrow); use Imap as workspace for Queue [ find_components (B, NULL, n, cnode, NULL, - Bnz, CParent, Cstack, &top, Imap, Common) ; - /* done using Imap as workspace for Queue ] */ + Bnz, CParent, Cstack, &top, Imap, Common) ; + // done using Imap as workspace for Queue ] - /* Nodes can now be of Type 0, 1, 2, or 4 (see definition below) */ + // Nodes can now be of Type 0, 1, 2, or 4 (see definition below) - /* ---------------------------------------------------------------------- */ - /* while Cstack is not empty, do: */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // while Cstack is not empty, do: + //-------------------------------------------------------------------------- while (top >= 0) { - /* clear the Flag array, but do not modify negative entries in Flag */ - mark = clear_flag (NULL, 0, Common) ; - - DEBUG (for (i = 0 ; i < n ; i++) Imap [i] = EMPTY) ; - - /* ------------------------------------------------------------------ */ - /* get node(s) from the top of the Cstack */ - /* ------------------------------------------------------------------ */ - - /* i is the repnode of its (unordered) connected component. Get - * all repnodes for all connected components of a single part. If - * each connected component is to be ordered separately (nd_components - * is TRUE), then this while loop iterates just once. */ - - cnode = EMPTY ; - cn = 0 ; - while (cnode == EMPTY) - { - i = Cstack [top--] ; - - if (i < 0) - { - /* this is the last node in this component */ - i = FLIP (i) ; - cnode = i ; - } - - ASSERT (i >= 0 && i < n && Flag [i] >= EMPTY) ; - - /* place i in the queue and mark it */ - Map [cn] = i ; - Flag [i] = mark ; - Imap [i] = cn ; - cn++ ; - } - - ASSERT (cnode != EMPTY) ; - - /* During ordering, there are five kinds of nodes in the graph of B, - * based on Flag [j] and CParent [j] for nodes j = 0 to n-1: - * - * Type 0: If cnode is a repnode of an unordered component, then - * CParent [cnode] is in the range EMPTY to n-1 and - * Flag [cnode] >= EMPTY. This is a "live" node. - * - * Type 1: If cnode is a repnode of an ordered separator component, - * then Flag [cnode] < EMPTY and FLAG [cnode] = FLIP (cnode). - * CParent [cnode] is in the range EMPTY to n-1. cnode is a root of - * the separator tree if CParent [cnode] == EMPTY. This node is dead. - * - * Type 2: If node j isn't a repnode, has not been absorbed via - * graph compression into another node, but is in an ordered separator - * component, then cnode = FLIP (Flag [j]) gives the repnode of the - * component that contains j and CParent [j] is -2. This node is dead. - * Note that Flag [j] < EMPTY. - * - * Type 3: If node i has been absorbed via graph compression into some - * other node j = FLIP (Flag [i]) where j is not a repnode. - * CParent [j] is -2. Node i may or may not be in an ordered - * component. This node is dead. Note that Flag [j] < EMPTY. - * - * Type 4: If node j is "live" (not in an ordered component, and not - * absorbed into any other node), then Flag [j] >= EMPTY. - * - * Only "live" nodes (of type 0 or 4) are placed in a subgraph to be - * partitioned. Node j is alive if Flag [j] >= EMPTY, and dead if - * Flag [j] < EMPTY. - */ - - /* ------------------------------------------------------------------ */ - /* create the subgraph for this connected component C */ - /* ------------------------------------------------------------------ */ - - /* Do a breadth-first search of the graph starting at cnode. - * use Map [0..cn-1] for nodes in the component C [ - * use Cnw and Cew for node and edge weights of the resulting subgraph [ - * use Cp and Ci for the resulting subgraph [ - * use Imap [i] for all nodes i in B that are in the component C [ - */ - - cnz = 0 ; - total_weight = 0 ; - for (cj = 0 ; cj < cn ; cj++) - { - /* get node j from the head of the queue; it is node cj of C */ - j = Map [cj] ; - ASSERT (Flag [j] == mark) ; - Cp [cj] = cnz ; - Cnw [cj] = Bnw [j] ; - ASSERT (Cnw [cj] >= 0) ; - total_weight += Cnw [cj] ; - pstart = Bp [j] ; - pdest = pstart ; - pend = pstart + Bnz [j] ; - hash = cj ; - for (p = pstart ; p < pend ; p++) - { - i = Bi [p] ; - /* prune diagonal entries and dead edges from B */ - if (i != j && Flag [i] >= EMPTY) - { - /* live node i is in the current component */ - Bi [pdest++] = i ; - if (Flag [i] != mark) - { - /* First time node i has been seen, it is a new node - * of C. place node i in the queue and mark it */ - Map [cn] = i ; - Flag [i] = mark ; - Imap [i] = cn ; - cn++ ; - } - /* place the edge (cj,ci) in the adjacency list of cj */ - ci = Imap [i] ; - ASSERT (ci >= 0 && ci < cn && ci != cj && cnz < csize) ; - Ci [cnz++] = ci ; - hash += ci ; - } - } - /* edges to dead nodes have been removed */ - Bnz [j] = pdest - pstart ; - /* finalize the hash key for column j */ - hash %= csize ; - Hash [cj] = (Int) hash ; - ASSERT (Hash [cj] >= 0 && Hash [cj] < csize) ; - } - Cp [cn] = cnz ; - C->nrow = cn ; - C->ncol = cn ; /* affects mem stats unless restored when C free'd */ - - /* contents of Imap no longer needed ] */ - -#ifndef NDEBUG - for (cj = 0 ; cj < cn ; cj++) - { - j = Map [cj] ; - PRINT2 (("----------------------------C column cj: "ID" j: "ID"\n", - cj, j)) ; - ASSERT (j >= 0 && j < n) ; - ASSERT (Flag [j] >= EMPTY) ; - for (p = Cp [cj] ; p < Cp [cj+1] ; p++) - { - ci = Ci [p] ; - i = Map [ci] ; - PRINT3 (("ci: "ID" i: "ID"\n", ci, i)) ; - ASSERT (ci != cj && ci >= 0 && ci < cn) ; - ASSERT (i != j && i >= 0 && i < n) ; - ASSERT (Flag [i] >= EMPTY) ; - } - } -#endif + // clear the Flag array, but do not modify negative entries in Flag + mark = clear_flag (NULL, 0, Common) ; - PRINT0 (("consider cn %d nd_small %d ", cn, nd_small)) ; - if (cn < nd_small) /* could be 'total_weight < nd_small' instead */ - { - /* place all nodes in the separator */ - PRINT0 ((" too small\n")) ; - sepsize = total_weight ; - } - else - { - - /* Cp and Ci now contain the component, with cn nodes and cnz - * nonzeros. The mapping of a node cj into node j the main graph - * B is given by Map [cj] = j */ - PRINT0 ((" cut\n")) ; - - /* -------------------------------------------------------------- */ - /* compress and partition the graph C */ - /* -------------------------------------------------------------- */ - - /* The edge weights Cew [0..csize-1] are all 1's on input to and - * output from the partition routine. */ - - sepsize = partition ( -#ifndef NDEBUG - csize, -#endif - nd_compress, Hash, C, Cnw, Cew, - Cmap, Part, Common) ; - - /* contents of Cp and Ci no longer needed ] */ - - if (sepsize < 0) - { - /* failed */ - C->ncol = n ; /* restore size for memory usage statistics */ - CHOLMOD(free_sparse) (&C, Common) ; - CHOLMOD(free_sparse) (&B, Common) ; - CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ; - CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; - Common->mark = EMPTY ; - CLEAR_FLAG (Common) ; + DEBUG (for (i = 0 ; i < n ; i++) Imap [i] = EMPTY) ; + + //---------------------------------------------------------------------- + // get node(s) from the top of the Cstack + //---------------------------------------------------------------------- + + // i is the repnode of its (unordered) connected component. Get + // all repnodes for all connected components of a single part. If + // each connected component is to be ordered separately (nd_components + // is TRUE), then this while loop iterates just once. + + cnode = EMPTY ; + cn = 0 ; + while (cnode == EMPTY) + { + i = Cstack [top--] ; + + if (i < 0) + { + // this is the last node in this component + i = FLIP (i) ; + cnode = i ; + } + + ASSERT (i >= 0 && i < n && Flag [i] >= EMPTY) ; + + // place i in the queue and mark it + Map [cn] = i ; + Flag [i] = mark ; + Imap [i] = cn ; + cn++ ; + } + + ASSERT (cnode != EMPTY) ; + + // During ordering, there are five kinds of nodes in the graph of B, + // based on Flag [j] and CParent [j] for nodes j = 0 to n-1: + // + // Type 0: If cnode is a repnode of an unordered component, then + // CParent [cnode] is in the range EMPTY to n-1 and + // Flag [cnode] >= EMPTY. This is a "live" node. + // + // Type 1: If cnode is a repnode of an ordered separator component, + // then Flag [cnode] < EMPTY and FLAG [cnode] = FLIP (cnode). + // CParent [cnode] is in the range EMPTY to n-1. cnode is a root of + // the separator tree if CParent [cnode] == EMPTY. This node is dead. + // + // Type 2: If node j isn't a repnode, has not been absorbed via + // graph compression into another node, but is in an ordered separator + // component, then cnode = FLIP (Flag [j]) gives the repnode of the + // component that contains j and CParent [j] is -2. This node is dead. + // Note that Flag [j] < EMPTY. + // + // Type 3: If node i has been absorbed via graph compression into some + // other node j = FLIP (Flag [i]) where j is not a repnode. + // CParent [j] is -2. Node i may or may not be in an ordered + // component. This node is dead. Note that Flag [j] < EMPTY. + // + // Type 4: If node j is "live" (not in an ordered component, and not + // absorbed into any other node), then Flag [j] >= EMPTY. + // + // Only "live" nodes (of type 0 or 4) are placed in a subgraph to be + // partitioned. Node j is alive if Flag [j] >= EMPTY, and dead if + // Flag [j] < EMPTY. + + //---------------------------------------------------------------------- + // create the subgraph for this connected component C + //---------------------------------------------------------------------- + + // Do a breadth-first search of the graph starting at cnode. + // use Map [0..cn-1] for nodes in the component C [ + // use Cnw and Cew for node and edge weights of the resulting subgraph [ + // use Cp and Ci for the resulting subgraph [ + // use Imap [i] for all nodes i in B that are in the component C [ + + cnz = 0 ; + total_weight = 0 ; + for (cj = 0 ; cj < cn ; cj++) + { + // get node j from the head of the queue; it is node cj of C + j = Map [cj] ; + ASSERT (Flag [j] == mark) ; + Cp [cj] = cnz ; + Cnw [cj] = Bnw [j] ; + ASSERT (Cnw [cj] >= 0) ; + total_weight += Cnw [cj] ; + pstart = Bp [j] ; + pdest = pstart ; + pend = pstart + Bnz [j] ; + hash = cj ; + for (p = pstart ; p < pend ; p++) + { + i = Bi [p] ; + // prune diagonal entries and dead edges from B + if (i != j && Flag [i] >= EMPTY) + { + // live node i is in the current component + Bi [pdest++] = i ; + if (Flag [i] != mark) + { + // First time node i has been seen, it is a new node + // of C. place node i in the queue and mark it + Map [cn] = i ; + Flag [i] = mark ; + Imap [i] = cn ; + cn++ ; + } + // place the edge (cj,ci) in the adjacency list of cj + ci = Imap [i] ; + ASSERT (ci >= 0 && ci < cn && ci != cj && cnz < csize) ; + Ci [cnz++] = ci ; + hash += ci ; + } + } + // edges to dead nodes have been removed + Bnz [j] = pdest - pstart ; + // finalize the hash key for column j + hash %= csize ; + Hash [cj] = (Int) hash ; + ASSERT (Hash [cj] >= 0 && Hash [cj] < csize) ; + } + Cp [cn] = cnz ; + C->nrow = cn ; + C->ncol = cn ; // affects mem stats unless restored when C free'd + + // contents of Imap no longer needed ] + + #ifndef NDEBUG + for (cj = 0 ; cj < cn ; cj++) + { + j = Map [cj] ; + PRINT2 (("----------------------------C column cj: "ID" j: "ID"\n", + cj, j)) ; + ASSERT (j >= 0 && j < n) ; + ASSERT (Flag [j] >= EMPTY) ; + for (p = Cp [cj] ; p < Cp [cj+1] ; p++) + { + ci = Ci [p] ; + i = Map [ci] ; + PRINT3 (("ci: "ID" i: "ID"\n", ci, i)) ; + ASSERT (ci != cj && ci >= 0 && ci < cn) ; + ASSERT (i != j && i >= 0 && i < n) ; + ASSERT (Flag [i] >= EMPTY) ; + } + } + #endif + + PRINT0 (("consider cn %d nd_small %d ", cn, nd_small)) ; + if (cn < nd_small) // could be 'total_weight < nd_small' instead + { + // place all nodes in the separator + PRINT0 ((" too small\n")) ; + sepsize = total_weight ; + } + else + { + + // Cp and Ci now contain the component, with cn nodes and cnz + // nonzeros. The mapping of a node cj into node j the main graph + // B is given by Map [cj] = j + PRINT0 ((" cut\n")) ; + + //------------------------------------------------------------------ + // compress and partition the graph C + //------------------------------------------------------------------ + + // The edge weights Cew [0..csize-1] are all 1's on input to and + // output from the partition routine. + + sepsize = partition ( + #ifndef NDEBUG + csize, + #endif + nd_compress, Hash, C, Cnw, Cew, + Cmap, Part, Common) ; + + // contents of Cp and Ci no longer needed ] + + if (sepsize < 0) + { + // failed + C->ncol = n ; // restore size for memory usage statistics + CHOLMOD(free_sparse) (&C, Common) ; + CHOLMOD(free_sparse) (&B, Common) ; + CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ; + CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; + Common->mark = EMPTY ; + CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - return (EMPTY) ; - } - - /* -------------------------------------------------------------- */ - /* compress B based on how C was compressed */ - /* -------------------------------------------------------------- */ - - for (ci = 0 ; ci < cn ; ci++) - { - if (Hash [ci] < EMPTY) - { - /* ci is dead in C, having been absorbed into cj */ - cj = FLIP (Hash [ci]) ; - PRINT2 (("In C, "ID" absorbed into "ID" (wgt now "ID")\n", - ci, cj, Cnw [cj])) ; - /* i is dead in B, having been absorbed into j */ - i = Map [ci] ; - j = Map [cj] ; - PRINT2 (("In B, "ID" (wgt "ID") => "ID" (wgt "ID")\n", - i, Bnw [i], j, Bnw [j], Cnw [cj])) ; - /* more than one node may be absorbed into j. This is - * accounted for in Cnw [cj]. Assign it here rather - * than += Bnw [i] */ - Bnw [i] = 0 ; - Bnw [j] = Cnw [cj] ; - Flag [i] = FLIP (j) ; - } - } - - DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) cnt += Bnw [j]) ; - ASSERT (cnt == n) ; - } - - /* contents of Cnw [0..cn-1] no longer needed ] */ - - /* ------------------------------------------------------------------ */ - /* order the separator, and stack the components when C is split */ - /* ------------------------------------------------------------------ */ - - /* one more component has been found: either the separator of C, - * or all of C */ - - ASSERT (sepsize >= 0 && sepsize <= total_weight) ; - - PRINT0 (("sepsize %d tot %d : %8.4f ", sepsize, total_weight, - ((double) sepsize) / ((double) total_weight))) ; - - if (sepsize == total_weight || sepsize == 0 || - sepsize > nd_oksep * total_weight) - { - /* Order the nodes in the component. The separator is too large, - * or empty. Note that the partition routine cannot return a - * sepsize of zero, but it can return a separator consisting of the - * whole graph. The "sepsize == 0" test is kept, above, in case the - * partition routine changes. In either case, this component - * remains unsplit, and becomes a leaf of the separator tree. */ - PRINT2 (("cnode %d sepsize zero or all of graph: "ID"\n", - cnode, sepsize)) ; - for (cj = 0 ; cj < cn ; cj++) - { - j = Map [cj] ; - Flag [j] = FLIP (cnode) ; - PRINT2 ((" node cj: "ID" j: "ID" ordered\n", cj, j)) ; - } - ASSERT (Flag [cnode] == FLIP (cnode)) ; - ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ; - PRINT0 (("discarded\n")) ; - - } - else - { - - /* Order the nodes in the separator of C and find a new repnode - * cnode that is in the separator of C. This requires the separator - * to be non-empty. */ - PRINT0 (("sepsize not tiny: "ID"\n", sepsize)) ; - parent = CParent [cnode] ; - ASSERT (parent >= EMPTY && parent < n) ; - CParent [cnode] = -2 ; - cnode = EMPTY ; - for (cj = 0 ; cj < cn ; cj++) - { - j = Map [cj] ; - if (Part [cj] == 2) - { - /* All nodes in the separator become part of a component - * whose repnode is cnode */ - PRINT2 (("node cj: "ID" j: "ID" ordered\n", cj, j)) ; - if (cnode == EMPTY) - { - PRINT2(("------------new cnode: cj "ID" j "ID"\n", - cj, j)) ; - cnode = j ; - } - Flag [j] = FLIP (cnode) ; - } - else - { - PRINT2 ((" node cj: "ID" j: "ID" not ordered\n", - cj, j)) ; - } - } - ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ; - ASSERT (CParent [cnode] == -2) ; - CParent [cnode] = parent ; - - /* find the connected components when C is split, and push - * them on the Cstack. Use Imap as workspace for Queue. [ */ - /* workspace: Flag (nrow) */ - find_components (B, Map, cn, cnode, Part, Bnz, - CParent, Cstack, &top, Imap, Common) ; - /* done using Imap as workspace for Queue ] */ - } - /* contents of Map [0..cn-1] no longer needed ] */ + return (EMPTY) ; + } + + //------------------------------------------------------------------ + // compress B based on how C was compressed + //------------------------------------------------------------------ + + for (ci = 0 ; ci < cn ; ci++) + { + if (Hash [ci] < EMPTY) + { + // ci is dead in C, having been absorbed into cj + cj = FLIP (Hash [ci]) ; + PRINT2 (("In C, "ID" absorbed into "ID" (wgt now "ID")\n", + ci, cj, Cnw [cj])) ; + // i is dead in B, having been absorbed into j + i = Map [ci] ; + j = Map [cj] ; + PRINT2 (("In B, "ID" (wgt "ID") => "ID" (wgt "ID")\n", + i, Bnw [i], j, Bnw [j], Cnw [cj])) ; + // more than one node may be absorbed into j. This is + // accounted for in Cnw [cj]. Assign it here rather + // than += Bnw [i] + Bnw [i] = 0 ; + Bnw [j] = Cnw [cj] ; + Flag [i] = FLIP (j) ; + } + } + + DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) cnt += Bnw [j]) ; + ASSERT (cnt == n) ; + } + + // contents of Cnw [0..cn-1] no longer needed ] + + //---------------------------------------------------------------------- + // order the separator, and stack the components when C is split + //---------------------------------------------------------------------- + + // one more component has been found: either the separator of C, + // or all of C + + ASSERT (sepsize >= 0 && sepsize <= total_weight) ; + + PRINT0 (("sepsize %d tot %d : %8.4f ", sepsize, total_weight, + ((double) sepsize) / ((double) total_weight))) ; + + if (sepsize == total_weight || sepsize == 0 || + sepsize > nd_oksep * total_weight) + { + // Order the nodes in the component. The separator is too large, + // or empty. Note that the partition routine cannot return a + // sepsize of zero, but it can return a separator consisting of the + // whole graph. The "sepsize == 0" test is kept, above, in case the + // partition routine changes. In either case, this component + // remains unsplit, and becomes a leaf of the separator tree. + PRINT2 (("cnode %d sepsize zero or all of graph: "ID"\n", + cnode, sepsize)) ; + for (cj = 0 ; cj < cn ; cj++) + { + j = Map [cj] ; + Flag [j] = FLIP (cnode) ; + PRINT2 ((" node cj: "ID" j: "ID" ordered\n", cj, j)) ; + } + ASSERT (Flag [cnode] == FLIP (cnode)) ; + ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ; + PRINT0 (("discarded\n")) ; + + } + else + { + + // Order the nodes in the separator of C and find a new repnode + // cnode that is in the separator of C. This requires the separator + // to be non-empty. + PRINT0 (("sepsize not tiny: "ID"\n", sepsize)) ; + parent = CParent [cnode] ; + ASSERT (parent >= EMPTY && parent < n) ; + CParent [cnode] = -2 ; + cnode = EMPTY ; + for (cj = 0 ; cj < cn ; cj++) + { + j = Map [cj] ; + if (Part [cj] == 2) + { + // All nodes in the separator become part of a component + // whose repnode is cnode + PRINT2 (("node cj: "ID" j: "ID" ordered\n", cj, j)) ; + if (cnode == EMPTY) + { + PRINT2(("------------new cnode: cj "ID" j "ID"\n", + cj, j)) ; + cnode = j ; + } + Flag [j] = FLIP (cnode) ; + } + else + { + PRINT2 ((" node cj: "ID" j: "ID" not ordered\n", + cj, j)) ; + } + } + ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ; + ASSERT (CParent [cnode] == -2) ; + CParent [cnode] = parent ; + + // find the connected components when C is split, and push + // them on the Cstack. Use Imap as workspace for Queue. [ + // workspace: Flag (nrow) + find_components (B, Map, cn, cnode, Part, Bnz, + CParent, Cstack, &top, Imap, Common) ; + // done using Imap as workspace for Queue ] + } + // contents of Map [0..cn-1] no longer needed ] } - /* done using Cmember as workspace for Cmap ] */ - /* done using Perm as workspace for Cstack ] */ + // done using Cmember as workspace for Cmap ] + // done using Perm as workspace for Cstack ] - /* ---------------------------------------------------------------------- */ - /* place nodes removed via compression into their proper component */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // place nodes removed via compression into their proper component + //-------------------------------------------------------------------------- - /* At this point, all nodes are of Type 1, 2, or 3, as defined above. */ + // At this point, all nodes are of Type 1, 2, or 3, as defined above. for (i = 0 ; i < n ; i++) { - /* find the repnode cnode that contains node i */ - j = FLIP (Flag [i]) ; - PRINT2 (("\nfind component for "ID", in: "ID"\n", i, j)) ; - ASSERT (j >= 0 && j < n) ; - DEBUG (cnt = 0) ; - while (CParent [j] == -2) - { - j = FLIP (Flag [j]) ; - PRINT2 ((" walk up to "ID" ", j)) ; - ASSERT (j >= 0 && j < n) ; - PRINT2 ((" CParent "ID"\n", CParent [j])) ; - ASSERT (cnt < n) ; - DEBUG (cnt++) ; - } - cnode = j ; - ASSERT (cnode >= 0 && cnode < n) ; - ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ; - PRINT2 (("i "ID" is in component with cnode "ID"\n", i, cnode)) ; - ASSERT (Flag [cnode] == FLIP (cnode)) ; - - /* Mark all nodes along the path from i to cnode as being in the - * component whos repnode is cnode. Perform path compression. */ - j = FLIP (Flag [i]) ; - Flag [i] = FLIP (cnode) ; - DEBUG (cnt = 0) ; - while (CParent [j] == -2) - { - ASSERT (j >= 0 && j < n) ; - jnext = FLIP (Flag [j]) ; - PRINT2 ((" "ID" walk "ID" set cnode to "ID"\n", i, j, cnode)) ; - ASSERT (cnt < n) ; - DEBUG (cnt++) ; - Flag [j] = FLIP (cnode) ; - j = jnext ; - } + // find the repnode cnode that contains node i + j = FLIP (Flag [i]) ; + PRINT2 (("\nfind component for "ID", in: "ID"\n", i, j)) ; + ASSERT (j >= 0 && j < n) ; + DEBUG (cnt = 0) ; + while (CParent [j] == -2) + { + j = FLIP (Flag [j]) ; + PRINT2 ((" walk up to "ID" ", j)) ; + ASSERT (j >= 0 && j < n) ; + PRINT2 ((" CParent "ID"\n", CParent [j])) ; + ASSERT (cnt < n) ; + DEBUG (cnt++) ; + } + cnode = j ; + ASSERT (cnode >= 0 && cnode < n) ; + ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ; + PRINT2 (("i "ID" is in component with cnode "ID"\n", i, cnode)) ; + ASSERT (Flag [cnode] == FLIP (cnode)) ; + + // Mark all nodes along the path from i to cnode as being in the + // component whos repnode is cnode. Perform path compression. + j = FLIP (Flag [i]) ; + Flag [i] = FLIP (cnode) ; + DEBUG (cnt = 0) ; + while (CParent [j] == -2) + { + ASSERT (j >= 0 && j < n) ; + jnext = FLIP (Flag [j]) ; + PRINT2 ((" "ID" walk "ID" set cnode to "ID"\n", i, j, cnode)) ; + ASSERT (cnt < n) ; + DEBUG (cnt++) ; + Flag [j] = FLIP (cnode) ; + j = jnext ; + } } - /* At this point, all nodes fall into Types 1 or 2, as defined above. */ + // At this point, all nodes fall into Types 1 or 2, as defined above. -#ifndef NDEBUG + #ifndef NDEBUG for (j = 0 ; j < n ; j++) { - PRINT2 (("j %d CParent %d ", j, CParent [j])) ; - if (CParent [j] >= EMPTY && CParent [j] < n) - { - /* case 1: j is a repnode of a component */ - cnode = j ; - PRINT2 ((" a repnode\n")) ; - } - else - { - /* case 2: j is not a repnode of a component */ - cnode = FLIP (Flag [j]) ; - PRINT2 ((" repnode is %d\n", cnode)) ; - ASSERT (cnode >= 0 && cnode < n) ; - ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ; - } - ASSERT (Flag [cnode] == FLIP (cnode)) ; - /* case 3 no longer holds */ + PRINT2 (("j %d CParent %d ", j, CParent [j])) ; + if (CParent [j] >= EMPTY && CParent [j] < n) + { + // case 1: j is a repnode of a component + cnode = j ; + PRINT2 ((" a repnode\n")) ; + } + else + { + // case 2: j is not a repnode of a component + cnode = FLIP (Flag [j]) ; + PRINT2 ((" repnode is %d\n", cnode)) ; + ASSERT (cnode >= 0 && cnode < n) ; + ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ; + } + ASSERT (Flag [cnode] == FLIP (cnode)) ; + // case 3 no longer holds } -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- - C->ncol = n ; /* restore size for memory usage statistics */ + C->ncol = n ; // restore size for memory usage statistics CHOLMOD(free_sparse) (&C, Common) ; CHOLMOD(free_sparse) (&B, Common) ; CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ; CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ; - /* ---------------------------------------------------------------------- */ - /* handle dense nodes */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // handle dense nodes + //-------------------------------------------------------------------------- - /* The separator tree has nodes with either no children or two or more - * children - with one exception. There may exist a single root node with - * exactly one child, which holds the dense rows/columns of the matrix. - * Delete this node if it exists. */ + // The separator tree has nodes with either no children or two or more + // children - with one exception. There may exist a single root node with + // exactly one child, which holds the dense rows/columns of the matrix. + // Delete this node if it exists. if (ndense > 0) { - ASSERT (CParent [cdense] == EMPTY) ; /* cdense has no parent */ - /* find the children of cdense */ - nchild = 0 ; - for (j = 0 ; j < n ; j++) - { - if (CParent [j] == cdense) - { - nchild++ ; - child = j ; - } - } - if (nchild == 1) - { - /* the cdense node has just one child; merge the two nodes */ - PRINT1 (("root has one child\n")) ; - CParent [cdense] = -2 ; /* cdense is deleted */ - CParent [child] = EMPTY ; /* child becomes a root */ - for (j = 0 ; j < n ; j++) - { - if (Flag [j] == FLIP (cdense)) - { - /* j is a dense node */ - PRINT1 (("dense %d\n", j)) ; - Flag [j] = FLIP (child) ; - } - } - } + ASSERT (CParent [cdense] == EMPTY) ; // cdense has no parent + // find the children of cdense + nchild = 0 ; + for (j = 0 ; j < n ; j++) + { + if (CParent [j] == cdense) + { + nchild++ ; + child = j ; + } + } + if (nchild == 1) + { + // the cdense node has just one child; merge the two nodes + PRINT1 (("root has one child\n")) ; + CParent [cdense] = -2 ; // cdense is deleted + CParent [child] = EMPTY ; // child becomes a root + for (j = 0 ; j < n ; j++) + { + if (Flag [j] == FLIP (cdense)) + { + // j is a dense node + PRINT1 (("dense %d\n", j)) ; + Flag [j] = FLIP (child) ; + } + } + } } - /* ---------------------------------------------------------------------- */ - /* postorder the components */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // postorder the components + //-------------------------------------------------------------------------- DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) if (CParent [j] != -2) cnt++) ; - /* use Cmember as workspace for Post [ */ + // use Cmember as workspace for Post [ Post = Cmember ; - /* cholmod_postorder uses Head and Iwork [0..2n]. It does not use Flag, - * which here holds the mapping of nodes to repnodes. It ignores all nodes - * for which CParent [j] < -1, so it operates just on the repnodes. */ - /* workspace: Head (n), Iwork (2*n) */ + // cholmod_postorder uses Head and Iwork [0..2n]. It does not use Flag, + // which here holds the mapping of nodes to repnodes. It ignores all nodes + // for which CParent [j] < -1, so it operates just on the repnodes. + // workspace: Head (n), Iwork (2*n) ncomponents = CHOLMOD(postorder) (CParent, n, NULL, Post, Common) ; ASSERT (cnt == ncomponents) ; - /* use Iwork [0..n-1] as workspace for Ipost ( */ + // use Iwork [0..n-1] as workspace for Ipost ( Ipost = Iwork ; DEBUG (for (j = 0 ; j < n ; j++) Ipost [j] = EMPTY) ; - /* compute inverse postorder */ + // compute inverse postorder for (c = 0 ; c < ncomponents ; c++) { - cnode = Post [c] ; - ASSERT (cnode >= 0 && cnode < n) ; - Ipost [cnode] = c ; - ASSERT (Head [c] == EMPTY) ; + cnode = Post [c] ; + ASSERT (cnode >= 0 && cnode < n) ; + Ipost [cnode] = c ; + ASSERT (Head [c] == EMPTY) ; } - /* adjust the parent array */ - /* Iwork [n..2n-1] used for NewParent [ */ + // adjust the parent array + // Iwork [n..2n-1] used for NewParent [ NewParent = Iwork + n ; for (c = 0 ; c < ncomponents ; c++) { - parent = CParent [Post [c]] ; - NewParent [c] = (parent == EMPTY) ? EMPTY : (Ipost [parent]) ; + parent = CParent [Post [c]] ; + NewParent [c] = (parent == EMPTY) ? EMPTY : (Ipost [parent]) ; } for (c = 0 ; c < ncomponents ; c++) { - CParent [c] = NewParent [c] ; + CParent [c] = NewParent [c] ; } ASSERT (CHOLMOD(dump_parent) (CParent, ncomponents, "CParent", Common)) ; - /* Iwork [n..2n-1] no longer needed for NewParent ] */ - /* Cmember no longer needed for Post ] */ + // Iwork [n..2n-1] no longer needed for NewParent ] + // Cmember no longer needed for Post ] -#ifndef NDEBUG - /* count the number of children of each node */ + #ifndef NDEBUG + // count the number of children of each node for (c = 0 ; c < ncomponents ; c++) { - Cmember [c] = 0 ; + Cmember [c] = 0 ; } for (c = 0 ; c < ncomponents ; c++) { - if (CParent [c] != EMPTY) Cmember [CParent [c]]++ ; + if (CParent [c] != EMPTY) Cmember [CParent [c]]++ ; } for (c = 0 ; c < ncomponents ; c++) { - /* a node is either a leaf, or has 2 or more children */ - ASSERT (Cmember [c] == 0 || Cmember [c] >= 2) ; + // a node is either a leaf, or has 2 or more children + ASSERT (Cmember [c] == 0 || Cmember [c] >= 2) ; } -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* place each node in its component */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // place each node in its component + //-------------------------------------------------------------------------- for (j = 0 ; j < n ; j++) { - /* node j is in the cth component, whose repnode is cnode */ - cnode = FLIP (Flag [j]) ; - PRINT2 (("j "ID" flag "ID" cnode "ID"\n", - j, Flag [j], FLIP (Flag [j]))) ; - ASSERT (cnode >= 0 && cnode < n) ; - c = Ipost [cnode] ; - ASSERT (c >= 0 && c < ncomponents) ; - Cmember [j] = c ; + // node j is in the cth component, whose repnode is cnode + cnode = FLIP (Flag [j]) ; + PRINT2 (("j "ID" flag "ID" cnode "ID"\n", + j, Flag [j], FLIP (Flag [j]))) ; + ASSERT (cnode >= 0 && cnode < n) ; + c = Ipost [cnode] ; + ASSERT (c >= 0 && c < ncomponents) ; + Cmember [j] = c ; } - /* Flag no longer needed for the node-to-component mapping */ + // Flag no longer needed for the node-to-component mapping - /* done using Iwork [0..n-1] as workspace for Ipost ) */ + // done using Iwork [0..n-1] as workspace for Ipost ) - /* ---------------------------------------------------------------------- */ - /* clear the Flag array */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear the Flag array + //-------------------------------------------------------------------------- Common->mark = EMPTY ; CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* find the permutation */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the permutation + //-------------------------------------------------------------------------- PRINT1 (("nd_camd: %d A->stype %d\n", nd_camd, A->stype)) ; if (nd_camd) { - /* ------------------------------------------------------------------ */ - /* apply camd, csymamd, or ccolamd using the Cmember constraints */ - /* ------------------------------------------------------------------ */ - - if (A->stype != 0) - { - /* ordering A+A', so fset and fsize are ignored. - * Add the upper/lower part to a symmetric lower/upper matrix by - * converting to unsymmetric mode - * workspace: Iwork (nrow) */ - B = CHOLMOD(copy) (A, 0, -1, Common) ; - if (Common->status < CHOLMOD_OK) - { - PRINT0 (("make symmetric failed\n")) ; - return (EMPTY) ; - } - ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ; - PRINT2 (("nested dissection (2)\n")) ; - B->stype = -1 ; - if (nd_camd == 2) - { - /* workspace: Head (nrow+1), Iwork (nrow) if symmetric-upper */ - ok = CHOLMOD(csymamd) (B, Cmember, Perm, Common) ; - } - else - { - /* workspace: Head (nrow), Iwork (4*nrow) */ - ok = CHOLMOD(camd) (B, NULL, 0, Cmember, Perm, Common) ; - } - CHOLMOD(free_sparse) (&B, Common) ; - if (!ok) - { - /* failed */ - PRINT0 (("camd/csymamd failed\n")) ; - return (EMPTY) ; - } - } - else - { - /* ordering A*A' or A(:,f)*A(:,f)' */ - /* workspace: Iwork (nrow if no fset; MAX(nrow,ncol) if fset) */ - if (!CHOLMOD(ccolamd) (A, fset, fsize, Cmember, Perm, Common)) - { - /* ccolamd failed */ - PRINT2 (("ccolamd failed\n")) ; - return (EMPTY) ; - } - } + //---------------------------------------------------------------------- + // apply camd, csymamd, or ccolamd using the Cmember constraints + //---------------------------------------------------------------------- + + if (A->stype != 0) + { + // ordering A+A', so fset and fsize are ignored. + // Add the upper/lower part to a symmetric lower/upper matrix by + // converting to unsymmetric mode + // workspace: Iwork (nrow) + B = CHOLMOD(copy) (A, 0, -1, Common) ; + if (Common->status < CHOLMOD_OK) + { + PRINT0 (("make symmetric failed\n")) ; + return (EMPTY) ; + } + ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ; + PRINT2 (("nested dissection (2)\n")) ; + B->stype = -1 ; + if (nd_camd == 2) + { + // workspace: Head (nrow+1), Iwork (nrow) if symmetric-upper + ok = CHOLMOD(csymamd) (B, Cmember, Perm, Common) ; + } + else + { + // workspace: Head (nrow), Iwork (4*nrow) + ok = CHOLMOD(camd) (B, NULL, 0, Cmember, Perm, Common) ; + } + CHOLMOD(free_sparse) (&B, Common) ; + if (!ok) + { + // failed + PRINT0 (("camd/csymamd failed\n")) ; + return (EMPTY) ; + } + } + else + { + // ordering A*A' or A(:,f)*A(:,f)' + // workspace: Iwork (nrow if no fset; MAX(nrow,ncol) if fset) + if (!CHOLMOD(ccolamd) (A, fset, fsize, Cmember, Perm, Common)) + { + // ccolamd failed + PRINT2 (("ccolamd failed\n")) ; + return (EMPTY) ; + } + } } else { - /* ------------------------------------------------------------------ */ - /* natural ordering of each component */ - /* ------------------------------------------------------------------ */ - - /* use Iwork [0..n-1] for Next [ */ - Next = Iwork ; - - /* ------------------------------------------------------------------ */ - /* place the nodes in link lists, one list per component */ - /* ------------------------------------------------------------------ */ - - /* do so in reverse order, to preserve original ordering */ - for (j = n-1 ; j >= 0 ; j--) - { - /* node j is in the cth component */ - c = Cmember [j] ; - ASSERT (c >= 0 && c < ncomponents) ; - /* place node j in link list for component c */ - Next [j] = Head [c] ; - Head [c] = j ; - } - - /* ------------------------------------------------------------------ */ - /* order each node in each component */ - /* ------------------------------------------------------------------ */ - - k = 0 ; - for (c = 0 ; c < ncomponents ; c++) - { - for (j = Head [c] ; j != EMPTY ; j = Next [j]) - { - Perm [k++] = j ; - } - Head [c] = EMPTY ; - } - ASSERT (k == n) ; - - /* done using Iwork [0..n-1] for Next ] */ + //---------------------------------------------------------------------- + // natural ordering of each component + //---------------------------------------------------------------------- + + // use Iwork [0..n-1] for Next [ + Next = Iwork ; + + //---------------------------------------------------------------------- + // place the nodes in link lists, one list per component + //---------------------------------------------------------------------- + + // do so in reverse order, to preserve original ordering + for (j = n-1 ; j >= 0 ; j--) + { + // node j is in the cth component + c = Cmember [j] ; + ASSERT (c >= 0 && c < ncomponents) ; + // place node j in link list for component c + Next [j] = Head [c] ; + Head [c] = j ; + } + + //---------------------------------------------------------------------- + // order each node in each component + //---------------------------------------------------------------------- + + k = 0 ; + for (c = 0 ; c < ncomponents ; c++) + { + for (j = Head [c] ; j != EMPTY ; j = Next [j]) + { + Perm [k++] = j ; + } + Head [c] = EMPTY ; + } + ASSERT (k == n) ; + + // done using Iwork [0..n-1] for Next ] } - /* ---------------------------------------------------------------------- */ - /* clear workspace and return number of components */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear workspace and return number of components + //-------------------------------------------------------------------------- - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; return (ncomponents) ; #else Common->status = CHOLMOD_NOT_INSTALLED ; @@ -1954,230 +1938,227 @@ int64_t CHOLMOD(nested_dissection) /* returns # of components, or -1 if error */ #endif } -/* ========================================================================== */ -/* === cholmod_collapse_septree ============================================= */ -/* ========================================================================== */ - -/* cholmod_nested_dissection returns the separator tree that was used in the - * constrained minimum degree algorithm. Parameter settings (nd_small, - * nd_oksep, etc) that give a good fill-reducing ordering may give too fine of - * a separator tree for other uses (parallelism, multi-level LPDASA, etc). This - * function takes as input the separator tree computed by - * cholmod_nested_dissection, and collapses selected subtrees into single - * nodes. A subtree is collapsed if its root node (the separator) is large - * compared to the total number of nodes in the subtree, or if the subtree is - * small. Note that the separator tree may actually be a forest. - * - * nd_oksep and nd_small act just like the ordering parameters in Common. - * Returns the new number of nodes in the separator tree. - */ +//------------------------------------------------------------------------------ +// cholmod_collapse_septree +//------------------------------------------------------------------------------ + +// cholmod_nested_dissection returns the separator tree that was used in the +// constrained minimum degree algorithm. Parameter settings (nd_small, +// nd_oksep, etc) that give a good fill-reducing ordering may give too fine of +// a separator tree for other uses (parallelism, multi-level LPDASA, etc). This +// function takes as input the separator tree computed by +// cholmod_nested_dissection, and collapses selected subtrees into single +// nodes. A subtree is collapsed if its root node (the separator) is large +// compared to the total number of nodes in the subtree, or if the subtree is +// small. Note that the separator tree may actually be a forest. +// +// nd_oksep and nd_small act just like the ordering parameters in Common. +// Returns the new number of nodes in the separator tree. int64_t CHOLMOD(collapse_septree) ( - /* ---- input ---- */ - size_t n, /* # of nodes in the graph */ - size_t ncomponents, /* # of nodes in the separator tree (must be <= n) */ - double nd_oksep, /* collapse if #sep >= nd_oksep * #nodes in subtree */ - size_t nd_small, /* collapse if #nodes in subtree < nd_small */ - /* ---- in/out --- */ - Int *CParent, /* size ncomponents; from cholmod_nested_dissection */ - Int *Cmember, /* size n; from cholmod_nested_dissection */ - /* --------------- */ + // input: + size_t n, // # of nodes in the graph + size_t ncomponents, // # of nodes in the separator tree (must be <= n) + double nd_oksep, // collapse if #sep >= nd_oksep * #nodes in subtree + size_t nd_small, // collapse if #nodes in subtree < nd_small + // output: + Int *CParent, // size ncomponents; from cholmod_nested_dissection + Int *Cmember, // size n; from cholmod_nested_dissection cholmod_common *Common ) { + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + #ifndef NPARTITION Int *First, *Count, *Csubtree, *W, *Map ; Int c, j, k, nc, sepsize, total_weight, parent, nc_new, first ; - int collapse = FALSE, ok = TRUE ; - size_t s ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + int collapse = FALSE ; RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (CParent, EMPTY) ; RETURN_IF_NULL (Cmember, EMPTY) ; if (n < ncomponents) { - ERROR (CHOLMOD_INVALID, "invalid separator tree") ; - return (EMPTY) ; + ERROR (CHOLMOD_INVALID, "invalid separator tree") ; + return (EMPTY) ; } Common->status = CHOLMOD_OK ; nc = ncomponents ; if (n <= 1 || ncomponents <= 1) { - /* no change; tree is one node already */ - return (nc) ; + // no change; tree is one node already + return (nc) ; } nd_oksep = MAX (0, nd_oksep) ; nd_oksep = MIN (1, nd_oksep) ; nd_small = MAX (4, nd_small) ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- - /* s = 3*ncomponents */ - s = CHOLMOD(mult_size_t) (ncomponents, 3, &ok) ; + // s = 3*ncomponents + int ok = TRUE ; + size_t s = CHOLMOD(mult_size_t) (ncomponents, 3, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (EMPTY) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (EMPTY) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (EMPTY) ; + return (EMPTY) ; } W = Common->Iwork ; - Count = W ; W += ncomponents ; /* size ncomponents */ - Csubtree = W ; W += ncomponents ; /* size ncomponents */ - First = W ; W += ncomponents ; /* size ncomponents */ + Count = W ; W += ncomponents ; // size ncomponents + Csubtree = W ; W += ncomponents ; // size ncomponents + First = W ; W += ncomponents ; // size ncomponents - /* ---------------------------------------------------------------------- */ - /* find the first descendant of each node of the separator tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the first descendant of each node of the separator tree + //-------------------------------------------------------------------------- ASSERT (ncomponents >= 1 && ncomponents <= n) ; for (c = 0 ; c < nc ; c++) { - First [c] = EMPTY ; + First [c] = EMPTY ; } for (k = 0 ; k < nc ; k++) { - for (c = k ; c != EMPTY && First [c] == -1 ; c = CParent [c]) - { - ASSERT (c >= 0 && c < nc) ; - First [c] = k ; - } + for (c = k ; c != EMPTY && First [c] == -1 ; c = CParent [c]) + { + ASSERT (c >= 0 && c < nc) ; + First [c] = k ; + } } - /* ---------------------------------------------------------------------- */ - /* find the number of nodes of the graph in each node of the tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the number of nodes of the graph in each node of the tree + //-------------------------------------------------------------------------- for (c = 0 ; c < nc ; c++) { - Count [c] = 0 ; + Count [c] = 0 ; } for (j = 0 ; j < (Int) n ; j++) { - ASSERT (Cmember [j] >= 0 && Cmember [j] < nc) ; - Count [Cmember [j]]++ ; + ASSERT (Cmember [j] >= 0 && Cmember [j] < nc) ; + Count [Cmember [j]]++ ; } - /* ---------------------------------------------------------------------- */ - /* find the number of nodes in each subtree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the number of nodes in each subtree + //-------------------------------------------------------------------------- for (c = 0 ; c < nc ; c++) { - /* each subtree includes its root */ - Csubtree [c] = Count [c] ; - PRINT1 ((ID" size "ID" parent "ID" first "ID"\n", - c, Count [c], CParent [c], First [c])) ; + // each subtree includes its root + Csubtree [c] = Count [c] ; + PRINT1 ((ID" size "ID" parent "ID" first "ID"\n", + c, Count [c], CParent [c], First [c])) ; } for (c = 0 ; c < nc ; c++) { - /* add the subtree of the child, c, into the count of its parent */ - parent = CParent [c] ; - ASSERT (parent >= EMPTY && parent < nc) ; - if (parent != EMPTY) - { - Csubtree [parent] += Csubtree [c] ; - } + // add the subtree of the child, c, into the count of its parent + parent = CParent [c] ; + ASSERT (parent >= EMPTY && parent < nc) ; + if (parent != EMPTY) + { + Csubtree [parent] += Csubtree [c] ; + } } -#ifndef NDEBUG - /* the sum of the roots should be n */ + #ifndef NDEBUG + // the sum of the roots should be n j = 0 ; for (c = 0 ; c < nc ; c++) if (CParent [c] == EMPTY) j += Csubtree [c] ; ASSERT (j == (Int) n) ; -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* find subtrees to collapse */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find subtrees to collapse + //-------------------------------------------------------------------------- - /* consider all nodes in reverse post-order */ + // consider all nodes in reverse post-order for (c = nc-1 ; c >= 0 ; c--) { - /* consider the subtree rooted at node c */ - sepsize = Count [c] ; - total_weight = Csubtree [c] ; - PRINT1 (("Node "ID" sepsize "ID" subtree "ID" ratio %g\n", c, sepsize, - total_weight, ((double) sepsize)/((double) total_weight))) ; - first = First [c] ; - if (first < c && /* c must not be a leaf */ - (sepsize > nd_oksep * total_weight || total_weight < (int) nd_small)) - { - /* this separator is too large, or the subtree is too small. - * collapse the tree, by converting the entire subtree rooted at - * c into a single node. The subtree consists of all nodes from - * First[c] to the root c. Flag all nodes from First[c] to c-1 - * as dead. - */ - collapse = TRUE ; - for (k = first ; k < c ; k++) - { - CParent [k] = -2 ; - PRINT1 ((" collapse node "ID"\n", k)) ; - } - /* continue at the next node, first-1 */ - c = first ; - } + // consider the subtree rooted at node c + sepsize = Count [c] ; + total_weight = Csubtree [c] ; + PRINT1 (("Node "ID" sepsize "ID" subtree "ID" ratio %g\n", c, sepsize, + total_weight, ((double) sepsize)/((double) total_weight))) ; + first = First [c] ; + if (first < c && // c must not be a leaf + (sepsize > nd_oksep * total_weight || total_weight < (int) nd_small)) + { + // this separator is too large, or the subtree is too small. + // collapse the tree, by converting the entire subtree rooted at + // c into a single node. The subtree consists of all nodes from + // First[c] to the root c. Flag all nodes from First[c] to c-1 + // as dead. + collapse = TRUE ; + for (k = first ; k < c ; k++) + { + CParent [k] = -2 ; + PRINT1 ((" collapse node "ID"\n", k)) ; + } + // continue at the next node, first-1 + c = first ; + } } PRINT1 (("collapse: %d\n", collapse)) ; - /* ---------------------------------------------------------------------- */ - /* compress the tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // compress the tree + //-------------------------------------------------------------------------- - Map = Count ; /* Count no longer needed */ + Map = Count ; // Count no longer needed nc_new = nc ; if (collapse) { - nc_new = 0 ; - for (c = 0 ; c < nc ; c++) - { - Map [c] = nc_new ; - if (CParent [c] >= EMPTY) - { - /* node c is alive, and becomes node Map[c] in the new tree. - * Increment nc_new for the next node c. */ - nc_new++ ; - } - } - PRINT1 (("Collapse the tree from "ID" to "ID" nodes\n", nc, nc_new)) ; - ASSERT (nc_new > 0) ; - for (c = 0 ; c < nc ; c++) - { - parent = CParent [c] ; - if (parent >= EMPTY) - { - /* node c is alive */ - CParent [Map [c]] = (parent == EMPTY) ? EMPTY : Map [parent] ; - } - } - for (j = 0 ; j < (Int) n ; j++) - { - PRINT1 (("j "ID" Cmember[j] "ID" Map[Cmember[j]] "ID"\n", - j, Cmember [j], Map [Cmember [j]])) ; - Cmember [j] = Map [Cmember [j]] ; - } + nc_new = 0 ; + for (c = 0 ; c < nc ; c++) + { + Map [c] = nc_new ; + if (CParent [c] >= EMPTY) + { + // node c is alive, and becomes node Map[c] in the new tree. + // Increment nc_new for the next node c. + nc_new++ ; + } + } + PRINT1 (("Collapse the tree from "ID" to "ID" nodes\n", nc, nc_new)) ; + ASSERT (nc_new > 0) ; + for (c = 0 ; c < nc ; c++) + { + parent = CParent [c] ; + if (parent >= EMPTY) + { + // node c is alive + CParent [Map [c]] = (parent == EMPTY) ? EMPTY : Map [parent] ; + } + } + for (j = 0 ; j < (Int) n ; j++) + { + PRINT1 (("j "ID" Cmember[j] "ID" Map[Cmember[j]] "ID"\n", + j, Cmember [j], Map [Cmember [j]])) ; + Cmember [j] = Map [Cmember [j]] ; + } } - /* ---------------------------------------------------------------------- */ - /* return new size of separator tree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // return new size of separator tree + //-------------------------------------------------------------------------- return (nc_new) ; #else @@ -2185,3 +2166,4 @@ int64_t CHOLMOD(collapse_septree) return (EMPTY) ; #endif } + diff --git a/CHOLMOD/README.txt b/CHOLMOD/README.txt index 43ed5956c3..1e243bd1ec 100644 --- a/CHOLMOD/README.txt +++ b/CHOLMOD/README.txt @@ -13,26 +13,24 @@ http://www.suitesparse.com C and MATLAB interfaces. This code works on Microsoft Windows and many versions of Unix and Linux. -CHOLMOD v5.0.0 introduces the first part of support for single precision -sparse matrices, with the introduction of the new CHOLMOD:Utility Module. -Single precision is not yet incorporated into the remaining Modules, however. +CHOLMOD supports single precision sparse matrices (both real and complex), with +the introduction of the new CHOLMOD:Utility Module. -One CHOLMOD Module is copyrighted by the University of Florida (the -Partition Module). The rest are copyrighted by the authors: -Timothy A. Davis (all of them), and William W. Hager (the Modify Module). +One CHOLMOD Module is copyrighted by the University of Florida (the Partition +Module). The rest are copyrighted by the authors: Timothy A. Davis (all of +them), and William W. Hager (the Modify Module). CHOLMOD relies on several other packages: AMD, CAMD, COLAMD, CCOLAMD, -SuiteSparse_config, METIS, the BLAS, and LAPACK. All but METIS, the BLAS, and -LAPACK are part of SuiteSparse. +SuiteSparse_config, METIS, the BLAS, and LAPACK. All the BLAS and LAPACK are +part of SuiteSparse. -AMD is authored by T. Davis, Iain Duff, and Patrick Amestoy. -COLAMD is authored by T. Davis and Stefan Larimore, with algorithmic design -in collaboration with John Gilbert and Esmond Ng. -CCOLAMD is authored by T. Davis and Siva Rajamanickam. -CAMD is authored by T. Davis and Y. Chen. +AMD is authored by T. Davis, Iain Duff, and Patrick Amestoy. COLAMD is +authored by T. Davis and Stefan Larimore, with algorithmic design in +collaboration with John Gilbert and Esmond Ng. CCOLAMD is authored by T. Davis +and Siva Rajamanickam. CAMD is authored by T. Davis and Y. Chen. -LAPACK and the BLAS are authored by Jack Dongarra and many others. -LAPACK is available at http://www.netlib.org/lapack +LAPACK and the BLAS are authored by Jack Dongarra and many others. LAPACK is +available at http://www.netlib.org/lapack METIS 5.1.0 is authored by George Karypis, Univ. of Minnesota. Its use in CHOLMOD is optional. A copy is in SuiteSparse/SuiteSparse_metis, and it is @@ -41,9 +39,8 @@ SuiteSparse. If you do not wish to use METIS, compile with -DNPARTITION. -For use in MATLAB (on any system, including Windows): start MATLAB, -cd to the CHOLMOD/MATLAB directory, and type cholmod_make in the MATLAB -Command Window. +For use in MATLAB (on any system, including Windows): start MATLAB, cd to the +CHOLMOD/MATLAB directory, and type cholmod_make in the MATLAB Command Window. Acknowledgements: this work was supported in part by the National Science Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia National diff --git a/CHOLMOD/Supernodal/cholmod_l_super_numeric.c b/CHOLMOD/Supernodal/cholmod_l_super_numeric.c index 2f83c3388f..1188c4b2be 100644 --- a/CHOLMOD/Supernodal/cholmod_l_super_numeric.c +++ b/CHOLMOD/Supernodal/cholmod_l_super_numeric.c @@ -3,7 +3,7 @@ // int64_t version of cholmod_super_numeric //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Supernodal/cholmod_l_super_solve.c b/CHOLMOD/Supernodal/cholmod_l_super_solve.c index a1ff3b2868..d1c34bcbd6 100644 --- a/CHOLMOD/Supernodal/cholmod_l_super_solve.c +++ b/CHOLMOD/Supernodal/cholmod_l_super_solve.c @@ -3,7 +3,7 @@ // int64_t version of cholmod_super_solve //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Supernodal/cholmod_l_super_symbolic.c b/CHOLMOD/Supernodal/cholmod_l_super_symbolic.c index 8a9cd46adc..de728bcdc4 100644 --- a/CHOLMOD/Supernodal/cholmod_l_super_symbolic.c +++ b/CHOLMOD/Supernodal/cholmod_l_super_symbolic.c @@ -3,7 +3,7 @@ // int64_t version of cholmod_super_symbolic //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ diff --git a/CHOLMOD/Supernodal/cholmod_super_numeric.c b/CHOLMOD/Supernodal/cholmod_super_numeric.c index fd8f413fac..9050b1cd90 100644 --- a/CHOLMOD/Supernodal/cholmod_super_numeric.c +++ b/CHOLMOD/Supernodal/cholmod_super_numeric.c @@ -2,67 +2,64 @@ // CHOLMOD/Supernodal/cholmod_super_numeric: supernodal Cholesky factorization //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Computes the Cholesky factorization of A+beta*I or A*F+beta*I. Only the - * the lower triangular part of A+beta*I or A*F+beta*I is accessed. The - * matrices A and F must already be permuted according to the fill-reduction - * permutation L->Perm. cholmod_factorize is an "easy" wrapper for this code - * which applies that permutation. beta is real. - * - * Symmetric case: A is a symmetric (lower) matrix. F is not accessed. - * With a fill-reducing permutation, A(p,p) should be passed instead, where is - * p is L->Perm. - * - * Unsymmetric case: A is unsymmetric, and F must be present. Normally, F=A'. - * With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A - * and F, respectively, where f is a list of the subset of the columns of A. - * - * The input factorization L must be supernodal (L->is_super is TRUE). It can - * either be symbolic or numeric. In the first case, L has been analyzed by - * cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been - * numerically factorized. The numerical values are allocated here and the - * factorization is computed. In the second case, a prior matrix has been - * analyzed and numerically factorized, and a new matrix is being factorized. - * The numerical values of L are replaced with the new numerical factorization. - * - * L->is_ll is ignored, and set to TRUE. This routine always computes an LL' - * factorization. Supernodal LDL' factorization is not (yet) supported. - * FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE. - * - * Uses BLAS routines dsyrk, dgemm, dtrsm, and the LAPACK routine dpotrf. - * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm. - * - * If the matrix is not positive definite the routine returns TRUE, but sets - * Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at - * which the failure occurred. The supernode containing the non-positive - * diagonal entry is set to zero (this includes columns to the left of L->minor - * in the same supernode), as are all subsequent supernodes. - * - * workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 5*nsuper). - * Allocates temporary space of size L->maxcsize * sizeof(double) - * (twice that for the complex/zomplex case). - * - * If L is supernodal symbolic on input, it is converted to a supernodal numeric - * factor on output, with an xtype of real if A is real, or complex if A is - * complex or zomplex. If L is supernodal numeric on input, its xtype must - * match A (except that L can be complex and A zomplex). The xtype of A and F - * must match. - */ +// Computes the Cholesky factorization of A+beta*I or A*F+beta*I. Only the +// the lower triangular part of A+beta*I or A*F+beta*I is accessed. The +// matrices A and F must already be permuted according to the fill-reduction +// permutation L->Perm. cholmod_factorize is an "easy" wrapper for this code +// which applies that permutation. beta is real. +// +// Symmetric case: A is a symmetric (lower) matrix. F is not accessed. +// With a fill-reducing permutation, A(p,p) should be passed instead, where is +// p is L->Perm. +// +// Unsymmetric case: A is unsymmetric, and F must be present. Normally, F=A'. +// With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A +// and F, respectively, where f is a list of the subset of the columns of A. +// +// The input factorization L must be supernodal (L->is_super is TRUE). It can +// either be symbolic or numeric. In the first case, L has been analyzed by +// cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been +// numerically factorized. The numerical values are allocated here and the +// factorization is computed. In the second case, a prior matrix has been +// analyzed and numerically factorized, and a new matrix is being factorized. +// The numerical values of L are replaced with the new numerical factorization. +// +// L->is_ll is ignored, and set to TRUE. This routine always computes an LL' +// factorization. Supernodal LDL' factorization is not (yet) supported. +// FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE. +// +// If the matrix is not positive definite the routine returns TRUE, but sets +// Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at +// which the failure occurred. The supernode containing the non-positive +// diagonal entry is set to zero (this includes columns to the left of L->minor +// in the same supernode), as are all subsequent supernodes. +// +// workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 5*nsuper). +// Allocates temporary space of size L->maxcsize * sizeof(double) +// (twice that for the complex/zomplex case). +// +// If L is supernodal symbolic on input, it is converted to a supernodal numeric +// factor on output, with an xtype of real if A is real, or complex if A is +// complex or zomplex. If L is supernodal numeric on input, its xtype must +// match A (except that L can be complex and A zomplex). The xtype of A and F +// must match. The dtypes of all matrices must match. #include "cholmod_internal.h" #ifndef NGPL #ifndef NSUPERNODAL -/* ========================================================================== */ -/* === TEMPLATE codes for GPU and regular numeric factorization ============= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// GPU templates: double and double complex cases only +//------------------------------------------------------------------------------ +#define DOUBLE #ifdef CHOLMOD_INT64 #ifdef SUITESPARSE_CUDA #include "cholmod_gpu_kernels.h" @@ -70,110 +67,124 @@ #include "../GPU/t_cholmod_gpu.c" #define COMPLEX #include "../GPU/t_cholmod_gpu.c" -#define ZOMPLEX -/* no #include of "../GPU/t_cholmod_gpu.c". Zomplex case relies on complex */ #endif #endif +//------------------------------------------------------------------------------ +// CPU templates: all cases +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_super_numeric_worker.c" +#define COMPLEX +#include "t_cholmod_super_numeric_worker.c" +#define ZOMPLEX +#include "t_cholmod_super_numeric_worker.c" + +#undef DOUBLE +#define SINGLE #define REAL -#include "t_cholmod_super_numeric.c" +#include "t_cholmod_super_numeric_worker.c" #define COMPLEX -#include "t_cholmod_super_numeric.c" +#include "t_cholmod_super_numeric_worker.c" #define ZOMPLEX -#include "t_cholmod_super_numeric.c" +#include "t_cholmod_super_numeric_worker.c" -/* ========================================================================== */ -/* === cholmod_super_numeric ================================================ */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_super_numeric +//------------------------------------------------------------------------------ -/* Returns TRUE if successful, or if the matrix is not positive definite. - * Returns FALSE if out of memory, inputs are invalid, or other fatal error - * occurs. - */ +// Returns TRUE if successful, or if the matrix is not positive definite. +// Returns FALSE if out of memory, inputs are invalid, or other fatal error +// occurs. int CHOLMOD(super_numeric) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - double beta [2], /* beta*I is added to diagonal of matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // F = A' or A(:,f)' + double beta [2], // beta*I is added to diagonal of matrix to factorize + // input/output: + cholmod_factor *L, // factorization cholmod_common *Common ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + cholmod_dense *C ; Int *Super, *Map, *SuperMap ; size_t maxcsize ; - Int nsuper, n, i, k, s, stype, nrow ; - int ok = TRUE, symbolic ; - size_t t, w ; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + Int nsuper, n, i, k, s, nrow ; + int symbolic ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ; - stype = A->stype ; - if (stype < 0) + if (A->stype < 0) { - if (A->nrow != A->ncol || A->nrow != L->n) - { - ERROR (CHOLMOD_INVALID, "invalid dimensions") ; - return (FALSE) ; - } + if (A->nrow != A->ncol || A->nrow != L->n) + { + ERROR (CHOLMOD_INVALID, "invalid dimensions") ; + return (FALSE) ; + } } - else if (stype == 0) + else if (A->stype == 0) { - if (A->nrow != L->n) - { - ERROR (CHOLMOD_INVALID, "invalid dimensions") ; - return (FALSE) ; - } - RETURN_IF_NULL (F, FALSE) ; - RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; - if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0) - { - ERROR (CHOLMOD_INVALID, "F invalid") ; - return (FALSE) ; - } - if (A->xtype != F->xtype) - { - ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ; - return (FALSE) ; - } + if (A->nrow != L->n) + { + ERROR (CHOLMOD_INVALID, "invalid dimensions") ; + return (FALSE) ; + } + RETURN_IF_NULL (F, FALSE) ; + RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; + if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0) + { + ERROR (CHOLMOD_INVALID, "F invalid") ; + return (FALSE) ; + } + if (A->xtype != F->xtype || A->dtype != F->dtype) + { + ERROR (CHOLMOD_INVALID, "A and F must have same xtype and dtype") ; + return (FALSE) ; + } } else { - /* symmetric upper case not suppored */ - ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ; - return (FALSE) ; + // symmetric upper case not supported + ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ; + return (FALSE) ; } if (!(L->is_super)) { - ERROR (CHOLMOD_INVALID, "L not supernodal") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L not supernodal") ; + return (FALSE) ; } if (L->xtype != CHOLMOD_PATTERN) { - if (! ((A->xtype == CHOLMOD_REAL && L->xtype == CHOLMOD_REAL) - || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX) - || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX))) - { - ERROR (CHOLMOD_INVALID, "complex type mismatch") ; - return (FALSE) ; - } + if (! ((A->xtype == CHOLMOD_REAL && L->xtype == CHOLMOD_REAL) + || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX) + || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX))) + { + ERROR (CHOLMOD_INVALID, "complex type mismatch") ; + return (FALSE) ; + } + if (A->dtype != L->dtype) + { + ERROR (CHOLMOD_INVALID, "A and L must have the same dtype") ; + return (FALSE) ; + } } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace in Common */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace in Common + //-------------------------------------------------------------------------- nsuper = L->nsuper ; maxcsize = L->maxcsize ; @@ -183,126 +194,148 @@ int CHOLMOD(super_numeric) PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ; ASSERT (nsuper >= 0 && maxcsize > 0) ; - /* w = 2*n + 5*nsuper */ - w = CHOLMOD(mult_size_t) (n, 2, &ok) ; - t = CHOLMOD(mult_size_t) (nsuper, 5, &ok) ; + // w = 2*nrow + 5*nsuper + int ok = TRUE ; + size_t w = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ; + size_t t = CHOLMOD(mult_size_t) (L->nsuper, 5, &ok) ; w = CHOLMOD(add_size_t) (w, t, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, w, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { - return (FALSE) ; + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* get the current factor L and allocate numerical part, if needed */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get the current factor L and allocate numerical part, if needed + //-------------------------------------------------------------------------- Super = L->super ; symbolic = (L->xtype == CHOLMOD_PATTERN) ; if (symbolic) { - /* convert to supernodal numeric by allocating L->x */ - CHOLMOD(change_factor) ( - (A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX, - TRUE, TRUE, TRUE, TRUE, L, Common) ; - if (Common->status < CHOLMOD_OK) - { - /* the factor L remains in symbolic supernodal form */ - return (FALSE) ; - } + // convert to supernodal numeric by allocating L->x + L->dtype = A->dtype ; // ensure L has the same dtype as A + CHOLMOD(change_factor) ( + (A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX, + TRUE, TRUE, TRUE, TRUE, L, Common) ; + if (Common->status < CHOLMOD_OK) + { + // the factor L remains in symbolic supernodal form + return (FALSE) ; + } } - ASSERT (L->dtype == CHOLMOD_DOUBLE) ; // FIXME - ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ; + ASSERT (L->dtype == A->dtype) ; + ASSERT (L->dtype == CHOLMOD_DOUBLE || L->dtype == CHOLMOD_SINGLE) ; + ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ; - /* supernodal LDL' is not supported */ + // supernodal LDL' is not supported L->is_ll = TRUE ; - /* ---------------------------------------------------------------------- */ - /* get more workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get more workspace + //-------------------------------------------------------------------------- - C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ; + C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype + L->dtype, + Common) ; if (Common->status < CHOLMOD_OK) { - int status = Common->status ; - if (symbolic) - { - /* Change L back to symbolic, since the numeric values are not - * initialized. This cannot fail. */ - CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, - L, Common) ; - } - /* the factor L is now back to the form it had on input */ - Common->status = status ; - return (FALSE) ; + int status = Common->status ; + if (symbolic) + { + // Change L back to symbolic, since the numeric values are not + // initialized. This cannot fail. + CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, + Common) ; + } + // the factor L is now back to the form it had on input + Common->status = status ; + return (FALSE) ; } - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - SuperMap = Common->Iwork ; /* size n (i/i/l) */ - Map = Common->Flag ; /* size n, use Flag as workspace for Map array */ + SuperMap = Common->Iwork ; // size n + Map = Common->Flag ; // size n, use Flag as workspace for Map array for (i = 0 ; i < n ; i++) { - Map [i] = EMPTY ; + Map [i] = EMPTY ; } - /* ---------------------------------------------------------------------- */ - /* find the mapping of nodes to relaxed supernodes */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the mapping of nodes to relaxed supernodes + //-------------------------------------------------------------------------- - /* SuperMap [k] = s if column k is contained in supernode s */ + // SuperMap [k] = s if column k is contained in supernode s for (s = 0 ; s < nsuper ; s++) { - PRINT1 (("Super ["ID"] "ID" ncols "ID"\n", - s, Super[s], Super[s+1]-Super[s])); - for (k = Super [s] ; k < Super [s+1] ; k++) - { - SuperMap [k] = s ; - PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ; - } + PRINT1 (("Super ["ID"] "ID" ncols "ID"\n", + s, Super[s], Super[s+1]-Super[s])) ; + for (k = Super [s] ; k < Super [s+1] ; k++) + { + SuperMap [k] = s ; + PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ; + } } - /* ---------------------------------------------------------------------- */ - /* supernodal numerical factorization, using template routine */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // supernodal numerical factorization, using template routine + //-------------------------------------------------------------------------- + + float s_beta [2] ; + s_beta [0] = (float) beta [0] ; + s_beta [1] = (float) beta [1] ; - switch (A->xtype) + switch ((A->xtype + A->dtype) % 8) { - case CHOLMOD_REAL: - ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ; - break ; - - case CHOLMOD_COMPLEX: - ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - /* This operates on complex L, not zomplex */ - ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ; - break ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + ok = rs_cholmod_super_numeric_worker (A, F, s_beta, L, C, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + ok = cs_cholmod_super_numeric_worker (A, F, s_beta, L, C, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + // A is zomplex, but L is complex + ok = zs_cholmod_super_numeric_worker (A, F, s_beta, L, C, Common) ; + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + ok = rd_cholmod_super_numeric_worker (A, F, beta, L, C, Common) ; + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + ok = cd_cholmod_super_numeric_worker (A, F, beta, L, C, Common) ; + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + // A is zomplex, but L is complex + ok = zd_cholmod_super_numeric_worker (A, F, beta, L, C, Common) ; + break ; } - /* ---------------------------------------------------------------------- */ - /* clear Common workspace, free temp workspace C, and return */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // clear Common workspace, free temp workspace C, and return + //-------------------------------------------------------------------------- - /* Flag array was used as workspace, clear it */ + // Flag array was used as workspace, clear it Common->mark = EMPTY ; - /* CHOLMOD(clear_flag) (Common) ; */ CLEAR_FLAG (Common) ; ASSERT (check_flag (Common)) ; - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; CHOLMOD(free_dense) (&C, Common) ; return (ok) ; } + #endif #endif + diff --git a/CHOLMOD/Supernodal/cholmod_super_solve.c b/CHOLMOD/Supernodal/cholmod_super_solve.c index 9f06669995..bd74a79927 100644 --- a/CHOLMOD/Supernodal/cholmod_super_solve.c +++ b/CHOLMOD/Supernodal/cholmod_super_solve.c @@ -2,59 +2,68 @@ // CHOLMOD/Supernodal/cholmod_super_solve: solve using supernodal factorization //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Solve Lx=b or L'x=b for a supernodal factorization. These routines do not - * apply the permutation L->Perm. See cholmod_solve for a more general - * interface that performs that operation. - */ +// Solve Lx=b or L'x=b for a supernodal factorization. These routines do not +// apply the permutation L->Perm. See cholmod_solve for a more general +// interface that performs that operation. +// +// L is supernodal, and real or complex (not pattern, nor zomplex). The xtype +// and dtype of L, X, and E must match. #include "cholmod_internal.h" #ifndef NGPL #ifndef NSUPERNODAL -/* ========================================================================== */ -/* === TEMPLATE ============================================================= */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// t_cholmod_super_solve +//------------------------------------------------------------------------------ + +#define DOUBLE +#define REAL +#include "t_cholmod_super_solve_worker.c" +#define COMPLEX +#include "t_cholmod_super_solve_worker.c" +#undef DOUBLE +#define SINGLE #define REAL -#include "t_cholmod_super_solve.c" +#include "t_cholmod_super_solve_worker.c" #define COMPLEX -#include "t_cholmod_super_solve.c" - -/* ========================================================================== */ -/* === cholmod_super_lsolve ================================================= */ -/* ========================================================================== */ - -/* Solve Lx=b where x and b are of size n-by-nrhs. b is overwritten by the - * solution x. On input, b is stored in col-major order with leading dimension - * of d, and on output x is stored in the same manner. - * - * The contents of the workspace E are undefined on both input and output. - * - * workspace: none - */ - -int CHOLMOD(super_lsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ +#include "t_cholmod_super_solve_worker.c" + +//------------------------------------------------------------------------------ +// cholmod_super_lsolve: solve x=L\b +//------------------------------------------------------------------------------ + +// Solve Lx=b where x and b are of size n-by-nrhs. b is overwritten by the +// solution x. On input, b is stored in col-major order with leading dimension +// of d, and on output x is stored in the same manner. +// +// The contents of the workspace E are undefined on both input and output. +// +// workspace: none + +int CHOLMOD(super_lsolve) // TRUE if OK, FALSE if BLAS overflow occured ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the forward solve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to Lx=b on output */ - /* ---- workspace ---- */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the forward solve + // input/output: + cholmod_dense *X, // b on input, solution to Lx=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) { - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; @@ -63,91 +72,99 @@ int CHOLMOD(super_lsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; - if (L->xtype != X->xtype) + + if (L->xtype != X->xtype || L->dtype != X->dtype) { - ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L and X must have the same xtype and dtype") ; + return (FALSE) ; } - if (L->xtype != E->xtype) + if (L->xtype != E->xtype || L->dtype != E->dtype) { - ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L and E must have the same xtype and dtype") ; + return (FALSE) ; } + if (X->d < X->nrow || L->n != X->nrow) { - ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; + return (FALSE) ; } if (E->nzmax < X->ncol * (L->maxesize)) { - ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; + return (FALSE) ; } if (!(L->is_ll) || !(L->is_super)) { - ERROR (CHOLMOD_INVALID, "L not supernodal") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L not supernodal") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ; if (L->n == 0 || X->ncol == 0) { - /* nothing to do */ - return (TRUE) ; + // nothing to do + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* solve Lx=b using template routine */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve Lx=b using template routine + //-------------------------------------------------------------------------- - switch (L->xtype) + switch ((L->xtype + L->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_super_lsolve_worker (L, X, E, Common) ; + break ; - case CHOLMOD_REAL: - r_cholmod_super_lsolve (L, X, E, Common) ; - break ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_super_lsolve_worker (L, X, E, Common) ; + break ; - case CHOLMOD_COMPLEX: - c_cholmod_super_lsolve (L, X, E, Common) ; - break ; - } + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_super_lsolve_worker (L, X, E, Common) ; + break ; - if (sizeof (SUITESPARSE_BLAS_INT) < sizeof (Int) && !Common->blas_ok) - { - ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_super_lsolve_worker (L, X, E, Common) ; + break ; } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + CHECK_FOR_BLAS_INTEGER_OVERFLOW ; return (Common->blas_ok) ; } +//------------------------------------------------------------------------------ +// cholmod_super_ltsolve: solve x=L'\b +//------------------------------------------------------------------------------ -/* ========================================================================== */ -/* === cholmod_super_ltsolve ================================================ */ -/* ========================================================================== */ - -/* Solve L'x=b where x and b are of size n-by-nrhs. b is overwritten by the - * solution x. On input, b is stored in col-major order with leading dimension - * of d, and on output x is stored in the same manner. - * - * The contents of the workspace E are undefined on both input and output. - * - * workspace: none - */ +// Solve L'x=b where x and b are of size n-by-nrhs. b is overwritten by the +// solution x. On input, b is stored in col-major order with leading dimension +// of d, and on output x is stored in the same manner. +// +// The contents of the workspace E are undefined on both input and output. +// +// workspace: none -int CHOLMOD(super_ltsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ +int CHOLMOD(super_ltsolve) // TRUE if OK, FALSE if BLAS overflow occured ( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the backsolve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to L'x=b on output */ - /* ---- workspace ---- */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ + // input: + cholmod_factor *L, // factor to use for the backsolve + // input/output: + cholmod_dense *X, // b on input, solution to L'x=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) cholmod_common *Common ) { - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; @@ -156,60 +173,72 @@ int CHOLMOD(super_ltsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; - if (L->xtype != X->xtype) + + if (L->xtype != X->xtype || L->dtype != X->dtype) { - ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L and X must have the same xtype and dtype") ; + return (FALSE) ; } - if (L->xtype != E->xtype) + if (L->xtype != E->xtype || L->dtype != E->dtype) { - ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L and E must have the same xtype and dtype") ; + return (FALSE) ; } + if (X->d < X->nrow || L->n != X->nrow) { - ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; + return (FALSE) ; } if (E->nzmax < X->ncol * (L->maxesize)) { - ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; + return (FALSE) ; } if (!(L->is_ll) || !(L->is_super)) { - ERROR (CHOLMOD_INVALID, "L not supernodal") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "L not supernodal") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ; if (L->n == 0 || X->ncol == 0) { - /* nothing to do */ - return (TRUE) ; + // nothing to do + return (TRUE) ; } - /* ---------------------------------------------------------------------- */ - /* solve Lx=b using template routine */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // solve Lx=b using template routine + //-------------------------------------------------------------------------- - switch (L->xtype) + switch ((L->xtype + L->dtype) % 8) { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_super_ltsolve_worker (L, X, E, Common) ; + break ; - case CHOLMOD_REAL: - r_cholmod_super_ltsolve (L, X, E, Common) ; - break ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_super_ltsolve_worker (L, X, E, Common) ; + break ; - case CHOLMOD_COMPLEX: - c_cholmod_super_ltsolve (L, X, E, Common) ; - break ; - } + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_super_ltsolve_worker (L, X, E, Common) ; + break ; - if (sizeof (SUITESPARSE_BLAS_INT) < sizeof (Int) && !Common->blas_ok) - { - ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_super_ltsolve_worker (L, X, E, Common) ; + break ; } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + CHECK_FOR_BLAS_INTEGER_OVERFLOW ; return (Common->blas_ok) ; } + #endif #endif + diff --git a/CHOLMOD/Supernodal/cholmod_super_symbolic.c b/CHOLMOD/Supernodal/cholmod_super_symbolic.c index a41b0dea86..3c684a87e8 100644 --- a/CHOLMOD/Supernodal/cholmod_super_symbolic.c +++ b/CHOLMOD/Supernodal/cholmod_super_symbolic.c @@ -2,83 +2,81 @@ // CHOLMOD/Supernodal/cholmod_super_symbolic: symbolic supernodal analysis //------------------------------------------------------------------------------ -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ -/* Supernodal symbolic analysis of the LL' factorization of A, A*A', - * A(:,f)*A(:,f)'. - * - * This routine must be preceded by a simplicial symbolic analysis - * (cholmod_rowcolcounts). See cholmod_analyze.c for an example of how to use - * this routine. - * - * The user need not call this directly; cholmod_analyze is a "simple" wrapper - * for this routine. - * - * Symmetric case: - * - * A is stored in column form, with entries stored in the upper triangular - * part. Entries in the lower triangular part are ignored. - * - * Unsymmetric case: - * - * A is stored in column form. If F is equal to the transpose of A, then - * A*A' is analyzed. F can include a subset of the columns of A - * (F=A(:,f)'), in which case F*F' is analyzed. - * - * Requires Parent and L->ColCount to be defined on input; these are the - * simplicial Parent and ColCount arrays as computed by cholmod_rowcolcounts. - * Does not use L->Perm; the input matrices A and F must already be properly - * permuted. Allocates and computes the supernodal pattern of L (L->super, - * L->pi, L->px, and L->s). Does not allocate the real part (L->x). - * - * Supports any xtype (pattern, real, complex, or zomplex). - */ +// Supernodal symbolic analysis of the LL' factorization of A, A*A', +// A(:,f)*A(:,f)'. +// +// This routine must be preceded by a simplicial symbolic analysis +// (cholmod_rowcolcounts). See cholmod_analyze.c for an example of how to use +// this routine. +// +// The user need not call this directly; cholmod_analyze is a "simple" wrapper +// for this routine. +// +// Symmetric case: +// +// A is stored in column form, with entries stored in the upper triangular +// part. Entries in the lower triangular part are ignored. +// +// Unsymmetric case: +// +// A is stored in column form. If F is equal to the transpose of A, then +// A*A' is analyzed. F can include a subset of the columns of A +// (F=A(:,f)'), in which case F*F' is analyzed. +// +// Requires Parent and L->ColCount to be defined on input; these are the +// simplicial Parent and ColCount arrays as computed by cholmod_rowcolcounts. +// Does not use L->Perm; the input matrices A and F must already be properly +// permuted. Allocates and computes the supernodal pattern of L (L->super, +// L->pi, L->px, and L->s). Does not allocate the real part (L->x). +// +// Supports any xtype (pattern, real, complex, or zomplex) and any dtype. #include "cholmod_internal.h" #ifndef NGPL #ifndef NSUPERNODAL -/* ========================================================================== */ -/* === subtree ============================================================== */ -/* ========================================================================== */ - -/* In the symmetric case, traverse the kth row subtree from the nonzeros in - * A (0:k1-1,k) and add the new entries found to the pattern of the kth row - * of L. The current supernode s contains the diagonal block k1:k2-1, so it - * can be skipped. - * - * In the unsymmetric case, the nonzero pattern of A*F is computed one column - * at a time (thus, the total time spent in this function is bounded below by - * the time taken to multiply A*F, which can be high if A is tall and thin). - * The kth column is A*F(:,k), or the set union of all columns A(:,j) for which - * F(j,k) is nonzero. This routine is called once for each entry j. Only the - * upper triangular part is needed, so only A (0:k1-1,j) is accessed, where - * k1:k2-1 are the columns of the current supernode s (k is in the range k1 to - * k2-1). - * - * If A is sorted, then the total time taken by this function is proportional - * to the number of nonzeros in the strictly block upper triangular part of A, - * plus the number of entries in the strictly block lower triangular part of - * the supernodal part of L. This excludes entries in the diagonal blocks - * corresponding to the columns in each supernode. That is, if k1:k2-1 are - * in a single supernode, then only A (0:k1-1,k1:k2-1) are accessed. - * - * For the unsymmetric case, only the strictly block upper triangular part - * of A*F is constructed. - * - * Only adds column indices corresponding to the leading columns of each - * relaxed supernode. - */ +//------------------------------------------------------------------------------ +// subtree +//------------------------------------------------------------------------------ + +// In the symmetric case, traverse the kth row subtree from the nonzeros in +// A (0:k1-1,k) and add the new entries found to the pattern of the kth row +// of L. The current supernode s contains the diagonal block k1:k2-1, so it +// can be skipped. +// +// In the unsymmetric case, the nonzero pattern of A*F is computed one column +// at a time (thus, the total time spent in this function is bounded below by +// the time taken to multiply A*F, which can be high if A is tall and thin). +// The kth column is A*F(:,k), or the set union of all columns A(:,j) for which +// F(j,k) is nonzero. This routine is called once for each entry j. Only the +// upper triangular part is needed, so only A (0:k1-1,j) is accessed, where +// k1:k2-1 are the columns of the current supernode s (k is in the range k1 to +// k2-1). +// +// If A is sorted, then the total time taken by this function is proportional +// to the number of nonzeros in the strictly block upper triangular part of A, +// plus the number of entries in the strictly block lower triangular part of +// the supernodal part of L. This excludes entries in the diagonal blocks +// corresponding to the columns in each supernode. That is, if k1:k2-1 are +// in a single supernode, then only A (0:k1-1,k1:k2-1) are accessed. +// +// For the unsymmetric case, only the strictly block upper triangular part +// of A*F is constructed. +// +// Only adds column indices corresponding to the leading columns of each +// relaxed supernode. static void subtree ( - /* inputs, not modified: */ - Int j, /* j = k for symmetric case */ + // inputs, not modified: + Int j, // j = k for symmetric case Int k, Int Ap [ ], Int Ai [ ], @@ -86,10 +84,10 @@ static void subtree Int SuperMap [ ], Int Sparent [ ], Int mark, - Int sorted, /* true if the columns of A are sorted */ - Int k1, /* only consider A (0:k1-1,k) */ + Int sorted, // true if the columns of A are sorted + Int k1, // only consider A (0:k1-1,k) - /* input/output: */ + // input/output: Int Flag [ ], Int Ls [ ], Int Lpi2 [ ] @@ -101,26 +99,26 @@ static void subtree for ( ; p < pend ; p++) { - i = Ai [p] ; - if (i < k1) - { - /* (i,k) is an entry in the upper triangular part of A or A*F'. - * symmetric case: A(i,k) is nonzero (j=k). - * unsymmetric case: A(i,j) and F(j,k) are both nonzero. - * - * Column i is in supernode si = SuperMap [i]. Follow path from si - * to root of supernodal etree, stopping at the first flagged - * supernode. The root of the row subtree is supernode SuperMap[k], - * which is flagged already. This traversal will stop there, or it - * might stop earlier if supernodes have been flagged by previous - * calls to this routine for the same k. */ - for (si = SuperMap [i] ; Flag [si] < mark ; si = Sparent [si]) - { - ASSERT (si <= SuperMap [k]) ; - Ls [Lpi2 [si]++] = k ; - Flag [si] = mark ; - } - } + i = Ai [p] ; + if (i < k1) + { + // (i,k) is an entry in the upper triangular part of A or A*F'. + // symmetric case: A(i,k) is nonzero (j=k). + // unsymmetric case: A(i,j) and F(j,k) are both nonzero. + // + // Column i is in supernode si = SuperMap [i]. Follow path from si + // to root of supernodal etree, stopping at the first flagged + // supernode. The root of the row subtree is supernode SuperMap[k], + // which is flagged already. This traversal will stop there, or it + // might stop earlier if supernodes have been flagged by previous + // calls to this routine for the same k. + for (si = SuperMap [i] ; Flag [si] < mark ; si = Sparent [si]) + { + ASSERT (si <= SuperMap [k]) ; + Ls [Lpi2 [si]++] = k ; + Flag [si] = mark ; + } + } else if (sorted) { break ; @@ -128,61 +126,58 @@ static void subtree } } +// clear workspace used by cholmod_super_symbolic +#define FREE_WORKSPACE \ +{ \ + CLEAR_FLAG (Common) ; \ + ASSERT (check_flag (Common)) ; \ + for (k = 0 ; k <= nfsuper ; k++) \ + { \ + Head [k] = EMPTY ; \ + } \ + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; \ +} -/* clear workspace used by cholmod_super_symbolic */ -#define FREE_WORKSPACE \ -{ \ - CLEAR_FLAG (Common) ; \ - ASSERT (check_flag (Common)) ; \ - for (k = 0 ; k <= nfsuper ; k++) \ - { \ - Head [k] = EMPTY ; \ - } \ - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \ -} \ - - -/* ========================================================================== */ -/* === cholmod_super_symbolic2 ============================================== */ -/* ========================================================================== */ +//------------------------------------------------------------------------------ +// cholmod_super_symbolic2 +//------------------------------------------------------------------------------ -/* Analyze for supernodal Cholesky or multifrontal QR. */ +// Analyze for supernodal Cholesky or multifrontal QR. int CHOLMOD(super_symbolic2) ( - /* ---- input ---- */ - int for_whom, /* FOR_SPQR (0): for SPQR but not GPU-accelerated - FOR_CHOLESKY (1): for Cholesky (GPU or not) - FOR_SPQRGPU (2): for SPQR with GPU acceleration */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - Int *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ + // input: + int for_whom, // FOR_SPQR (0): for SPQR but not GPU-accelerated + // FOR_CHOLESKY (1): for Cholesky (GPU or not) + // FOR_SPQRGPU (2): for SPQR with GPU acceleration + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + Int *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) { - double zrelax0, zrelax1, zrelax2, xxsize ; + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + double zrelax0, zrelax1, zrelax2 ; Int *Wi, *Wj, *Super, *Snz, *Ap, *Ai, *Flag, *Head, *Ls, *Lpi, *Lpx, *Fnz, - *Sparent, *Anz, *SuperMap, *Merged, *Nscol, *Zeros, *Fp, *Fj, - *ColCount, *Lpi2, *Lsuper, *Iwork ; - Int nsuper, d, n, j, k, s, mark, parent, p, pend, k1, k2, packed, nscol, - nsrow, ndrow1, ndrow2, stype, ssize, xsize, sparent, plast, slast, - csize, maxcsize, ss, nscol0, nscol1, ns, nfsuper, newzeros, totzeros, - merge, snext, esize, maxesize, nrelax0, nrelax1, nrelax2, Asorted ; - size_t w ; - int ok = TRUE, find_xsize ; + *Sparent, *Anz, *SuperMap, *Merged, *Nscol, *Zeros, *Fp, *Fj, + *ColCount, *Lpi2, *Lsuper, *Iwork ; + Int nsuper, d, n, j, k, s, mark, parent, p, pend, k1, k2, packed, + ndrow1, ndrow2, stype, sparent, plast, slast, + csize, maxcsize, ss, nscol0, nscol1, ns, nfsuper, newzeros, totzeros, + merge, snext, esize, maxesize, nrelax0, nrelax1, nrelax2, Asorted ; + int find_xsize ; const char* env_use_gpu; const char* env_max_bytes; size_t max_bytes; const char* env_max_fraction; - double max_fraction; - - /* ---------------------------------------------------------------------- */ - /* check inputs */ - /* ---------------------------------------------------------------------- */ + double max_fraction ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; @@ -193,144 +188,146 @@ int CHOLMOD(super_symbolic2) stype = A->stype ; if (stype < 0) { - /* invalid symmetry; symmetric lower form not supported */ - ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; - return (FALSE) ; + // invalid symmetry; symmetric lower form not supported + ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; + return (FALSE) ; } if (stype == 0) { - /* F must be present in the unsymmetric case */ - RETURN_IF_NULL (F, FALSE) ; + // F must be present in the unsymmetric case + RETURN_IF_NULL (F, FALSE) ; } if (L->is_super) { - /* L must be a simplicial symbolic factor */ - ERROR (CHOLMOD_INVALID, "L must be symbolic on input") ; - return (FALSE) ; + // L must be a simplicial symbolic factor + ERROR (CHOLMOD_INVALID, "L must be symbolic on input") ; + return (FALSE) ; } Common->status = CHOLMOD_OK ; - /* ---------------------------------------------------------------------- */ - /* allocate workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate workspace + //-------------------------------------------------------------------------- n = A->nrow ; - /* w = 5*n */ - w = CHOLMOD(mult_size_t) (n, 5, &ok) ; + // w = 5*nrow + int ok = TRUE ; + size_t w = CHOLMOD(mult_size_t) (A->nrow, 5, &ok) ; if (!ok) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return (FALSE) ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; + return (FALSE) ; } - CHOLMOD(allocate_work) (n, w, 0, Common) ; + CHOLMOD(allocate_work) (A->nrow, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { - /* out of memory */ - return (FALSE) ; + // out of memory + return (FALSE) ; } - ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; + ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, 0, Common)) ; - /* ---------------------------------------------------------------------- */ - /* allocate GPU workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // allocate GPU workspace + //-------------------------------------------------------------------------- - L->useGPU = 0 ; /* only used for Cholesky factorization, not QR */ + L->useGPU = 0 ; // only used for Cholesky factorization, not QR -#ifdef SUITESPARSE_CUDA + #ifdef SUITESPARSE_CUDA - /* GPU module is installed */ + // GPU module is installed if ( for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY ) { - /* only allocate GPU workspace for supernodal Cholesky, and only when - the GPU is requested and available. */ + // only allocate GPU workspace for supernodal Cholesky, and only when + // the GPU is requested and available. max_bytes = 0; max_fraction = 0; -#ifdef CHOLMOD_INT64 + #ifdef CHOLMOD_INT64 if ( Common->useGPU == EMPTY ) { - /* useGPU not explicity requested by the user, but not explicitly - * prohibited either. Query OS environment variables for request.*/ - env_use_gpu = getenv("CHOLMOD_USE_GPU"); + // useGPU not explicity requested by the user, but not explicitly + // prohibited either. Query OS environment variables for request. + env_use_gpu = getenv("CHOLMOD_USE_GPU") ; if ( env_use_gpu ) { - /* CHOLMOD_USE_GPU environment variable is set to something */ + // CHOLMOD_USE_GPU environment variable is set to something if ( atoi ( env_use_gpu ) == 0 ) { - Common->useGPU = 0; /* don't use the gpu */ + Common->useGPU = 0; // don't use the gpu } else { - Common->useGPU = 1; /* use the gpu */ - env_max_bytes = getenv("CHOLMOD_GPU_MEM_BYTES"); - env_max_fraction = getenv("CHOLMOD_GPU_MEM_FRACTION"); + Common->useGPU = 1; // use the gpu + env_max_bytes = getenv("CHOLMOD_GPU_MEM_BYTES") ; + env_max_fraction = getenv("CHOLMOD_GPU_MEM_FRACTION") ; if ( env_max_bytes ) { - max_bytes = atol(env_max_bytes); + max_bytes = atol(env_max_bytes) ; Common->maxGpuMemBytes = max_bytes; } if ( env_max_fraction ) { - max_fraction = atof (env_max_fraction); + max_fraction = atof (env_max_fraction) ; if ( max_fraction < 0 ) max_fraction = 0; if ( max_fraction > 1 ) max_fraction = 1; Common->maxGpuMemFraction = max_fraction; - } + } } } else { - /* CHOLMOD_USE_GPU environment variable not set, so no GPU - * acceleration will be used */ + // CHOLMOD_USE_GPU environment variable not set, so no GPU + // acceleration will be used Common->useGPU = 0; } - /* fprintf (stderr, "useGPU queried: %d\n", Common->useGPU) ; */ + // fprintf (stderr, "useGPU queried: %d\n", Common->useGPU) ; } - /* Ensure that a GPU is present */ + // Ensure that a GPU is present if ( Common->useGPU == 1 ) { - /* fprintf (stderr, "\nprobe GPU:\n") ; */ - Common->useGPU = CHOLMOD(gpu_probe) (Common); // Cholesky only, not SPQR - /* fprintf (stderr, "\nprobe GPU: result %d\n", Common->useGPU) ; */ + // fprintf (stderr, "\nprobe GPU:\n") ; + // Cholesky only, not SPQR + Common->useGPU = CHOLMOD(gpu_probe) (Common) ; + // fprintf (stderr, "\nprobe GPU: result %d\n", Common->useGPU) ; } if ( Common->useGPU == 1 ) { - /* Cholesky + GPU, so allocate space */ - /* fprintf (stderr, "allocate GPU:\n") ; */ - CHOLMOD(gpu_allocate) ( Common ); // Cholesky only, not SPQR - /* fprintf (stderr, "allocate GPU done\n") ; */ + // Cholesky + GPU, so allocate space + // fprintf (stderr, "allocate GPU:\n") ; + // Cholesky only, not SPQR + CHOLMOD(gpu_allocate) ( Common ) ; + // fprintf (stderr, "allocate GPU done\n") ; } -#else - /* GPU acceleration is only supported for long int version */ + #else + // GPU acceleration is only supported for long int version Common->useGPU = 0; -#endif - - /* Cache the fact that the symbolic factorization supports - * GPU acceleration */ - L->useGPU = Common->useGPU; + #endif + // Cache the fact that the symbolic factorization supports + // GPU acceleration + L->useGPU = Common->useGPU ; } -#else - /* GPU module is not installed */ + #else + // GPU module is not installed Common->useGPU = 0 ; -#endif + #endif - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- - /* A is now either A or triu(A(p,p)) for the symmetric case. It is either - * A or A(p,f) for the unsymmetric case (both in column form). It can be - * either packed or unpacked, and either sorted or unsorted. Entries in - * the lower triangular part may be present if A is symmetric, but these - * are ignored. */ + // A is now either A or triu(A(p,p)) for the symmetric case. It is either + // A or A(p,f) for the unsymmetric case (both in column form). It can be + // either packed or unpacked, and either sorted or unsorted. Entries in + // the lower triangular part may be present if A is symmetric, but these + // are ignored. Ap = A->p ; Ai = A->i ; @@ -338,19 +335,19 @@ int CHOLMOD(super_symbolic2) if (stype != 0) { - /* F not accessed */ - Fp = NULL ; - Fj = NULL ; - Fnz = NULL ; - packed = TRUE ; + // F not accessed + Fp = NULL ; + Fj = NULL ; + Fnz = NULL ; + packed = TRUE ; } else { - /* F = A(:,f) or A(p,f) in packed row form, either sorted or unsorted */ - Fp = F->p ; - Fj = F->i ; - Fnz = F->nz ; - packed = F->packed ; + // F = A(:,f) or A(p,f) in packed row form, either sorted or unsorted + Fp = F->p ; + Fj = F->i ; + Fnz = F->nz ; + packed = F->packed ; } ColCount = L->ColCount ; @@ -369,339 +366,331 @@ int CHOLMOD(super_symbolic2) ASSERT (CHOLMOD(dump_parent) (Parent, n, "Parent", Common)) ; - /* ---------------------------------------------------------------------- */ - /* get workspace */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // get workspace + //-------------------------------------------------------------------------- - /* Sparent, Snz, and Merged could be allocated later, of size nfsuper */ + // Sparent, Snz, and Merged could be allocated later, of size nfsuper Iwork = Common->Iwork ; - Wi = Iwork ; /* size n (i/l/l). Lpi2 is i/l/l */ - Wj = Iwork + n ; /* size n (i/l/l). Zeros is i/l/l */ - Sparent = Iwork + 2*((size_t) n) ; /* size nfsuper <= n [ */ - Snz = Iwork + 3*((size_t) n) ; /* size nfsuper <= n [ */ - Merged = Iwork + 4*((size_t) n) ; /* size nfsuper <= n [ */ + Wi = Iwork ; // size n + Wj = Iwork + n ; // size n + Sparent = Iwork + 2*((size_t) n) ; // size nfsuper <= n [ + Snz = Iwork + 3*((size_t) n) ; // size nfsuper <= n [ + Merged = Iwork + 4*((size_t) n) ; // size nfsuper <= n [ - Flag = Common->Flag ; /* size n */ - Head = Common->Head ; /* size n+1 */ + Flag = Common->Flag ; // size n + Head = Common->Head ; // size n+1 - /* ---------------------------------------------------------------------- */ - /* find the fundamental supernodes */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the fundamental supernodes + //-------------------------------------------------------------------------- - /* count the number of children of each node, using Wi [ */ + // count the number of children of each node, using Wi [ for (j = 0 ; j < n ; j++) { - Wi [j] = 0 ; + Wi [j] = 0 ; } for (j = 0 ; j < n ; j++) { - parent = Parent [j] ; - if (parent != EMPTY) - { - Wi [parent]++ ; - } + parent = Parent [j] ; + if (parent != EMPTY) + { + Wi [parent]++ ; + } } - Super = Head ; /* use Head [0..nfsuper] as workspace for Super list ( */ + Super = Head ; // use Head [0..nfsuper] as workspace for Super list ( - /* column 0 always starts a new supernode */ - nfsuper = (n == 0) ? 0 : 1 ; /* number of fundamental supernodes */ + // column 0 always starts a new supernode + nfsuper = (n == 0) ? 0 : 1 ; // number of fundamental supernodes Super [0] = 0 ; for (j = 1 ; j < n ; j++) { - /* check if j starts new supernode, or in the same supernode as j-1 */ - if (Parent [j-1] != j /* parent of j-1 is not j */ - || (ColCount [j-1] != ColCount [j] + 1) /* j-1 not subset of j*/ - || Wi [j] > 1 /* j has more than one child */ -#ifdef SUITESPARSE_CUDA - /* Ensure that the supernode will fit in the GPU buffers */ - /* Data size of 16 bytes must be assumed for case of PATTERN */ - || (for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY && L->useGPU && - (j-Super[nfsuper-1]+1) * - ColCount[Super[nfsuper-1]] * sizeof(double) * 2 >= - Common->devBuffSize) -#endif - ) - { - /* j is the leading node of a supernode */ - Super [nfsuper++] = j ; - } + // check if j starts new supernode, or in the same supernode as j-1 + if (Parent [j-1] != j // parent of j-1 is not j + || (ColCount [j-1] != ColCount [j] + 1) // j-1 not subset of j + || Wi [j] > 1 // j has more than one child + #ifdef SUITESPARSE_CUDA + // Ensure that the supernode will fit in the GPU buffers + // Data size of 16 bytes must be assumed for case of PATTERN + || (for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY && L->useGPU && + (j-Super[nfsuper-1]+1) * + ColCount[Super[nfsuper-1]] * sizeof(double) * 2 >= + Common->devBuffSize) + #endif + ) + { + // j is the leading node of a supernode + Super [nfsuper++] = j ; + } } Super [nfsuper] = n ; - /* contents of Wi no longer needed for child count ] */ + // contents of Wi no longer needed for child count ] - Nscol = Wi ; /* use Wi as size-nfsuper workspace for Nscol [ */ + Nscol = Wi ; // use Wi as size-nfsuper workspace for Nscol [ - /* ---------------------------------------------------------------------- */ - /* find the mapping of fundamental nodes to supernodes */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the mapping of fundamental nodes to supernodes + //-------------------------------------------------------------------------- - SuperMap = Wj ; /* use Wj as workspace for SuperMap [ */ + SuperMap = Wj ; // use Wj as workspace for SuperMap [ - /* SuperMap [k] = s if column k is contained in supernode s */ + // SuperMap [k] = s if column k is contained in supernode s for (s = 0 ; s < nfsuper ; s++) { - for (k = Super [s] ; k < Super [s+1] ; k++) - { - SuperMap [k] = s ; - } + for (k = Super [s] ; k < Super [s+1] ; k++) + { + SuperMap [k] = s ; + } } - /* ---------------------------------------------------------------------- */ - /* construct the fundamental supernodal etree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct the fundamental supernodal etree + //-------------------------------------------------------------------------- for (s = 0 ; s < nfsuper ; s++) { - j = Super [s+1] - 1 ; /* last node in supernode s */ - parent = Parent [j] ; /* parent of last node */ - Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; - PRINT1 (("Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; + j = Super [s+1] - 1 ; // last node in supernode s + parent = Parent [j] ; // parent of last node + Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; + PRINT1 (("Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; } - /* contents of Wj no longer needed as workspace for SuperMap ] - * SuperMap will be recomputed below, for the relaxed supernodes. */ + // contents of Wj no longer needed as workspace for SuperMap ] + // SuperMap will be recomputed below, for the relaxed supernodes. - Zeros = Wj ; /* use Wj for Zeros, workspace of size nfsuper [ */ + Zeros = Wj ; // use Wj for Zeros, workspace of size nfsuper [ - /* ---------------------------------------------------------------------- */ - /* relaxed amalgamation */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // relaxed amalgamation + //-------------------------------------------------------------------------- for (s = 0 ; s < nfsuper ; s++) { - Merged [s] = EMPTY ; /* s not merged into another */ - Nscol [s] = Super [s+1] - Super [s] ; /* # of columns in s */ - Zeros [s] = 0 ; /* # of zero entries in s */ - ASSERT (s <= Super [s]) ; - Snz [s] = ColCount [Super [s]] ; /* # of entries in leading col of s */ - PRINT2 (("lnz ["ID"] "ID"\n", s, Snz [s])) ; + Merged [s] = EMPTY ; // s not merged into another + Nscol [s] = Super [s+1] - Super [s] ; // # of columns in s + Zeros [s] = 0 ; // # of zero entries in s + ASSERT (s <= Super [s]) ; + Snz [s] = ColCount [Super [s]] ; // # of entries in leading col of s + PRINT2 (("lnz ["ID"] "ID"\n", s, Snz [s])) ; } for (s = nfsuper-2 ; s >= 0 ; s--) { double lnz1 ; - /* should supernodes s and s+1 merge into a new node s? */ - PRINT1 (("\n========= Check relax of s "ID" and s+1 "ID"\n", s, s+1)) ; - - ss = Sparent [s] ; - if (ss == EMPTY) - { - PRINT1 (("s "ID" is a root, no merge with s+1 = "ID"\n", s, s+1)) ; - continue ; - } - - /* find the current parent of s (perform path compression as needed) */ - for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = Merged [ss]) ; - sparent = ss ; - PRINT2 (("Current sparent of s "ID" is "ID"\n", s, sparent)) ; - - /* ss is the current parent of s */ - for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = snext) - { - snext = Merged [ss] ; - PRINT2 (("ss "ID" is dead, merged into snext "ID"\n", ss, snext)) ; - Merged [ss] = sparent ; - } - - /* if s+1 is not the current parent of s, do not merge */ - if (sparent != s+1) - { - continue ; - } - - nscol0 = Nscol [s] ; /* # of columns in s */ - nscol1 = Nscol [s+1] ; /* # of columns in s+1 */ - ns = nscol0 + nscol1 ; - PRINT2 (("ns "ID" nscol0 "ID" nscol1 "ID"\n", ns, nscol0, nscol1)) ; - - totzeros = Zeros [s+1] ; /* current # of zeros in s+1 */ - lnz1 = (double) (Snz [s+1]) ; /* # entries in leading column of s+1 */ - - /* determine if supernodes s and s+1 should merge */ - if (ns <= nrelax0) - { - PRINT2 (("ns is tiny ("ID"), so go ahead and merge\n", ns)) ; - merge = TRUE ; - } - else - { - /* use double to avoid integer overflow */ - double lnz0 = Snz [s] ; /* # entries in leading column of s */ - double xnewzeros = nscol0 * (lnz1 + nscol0 - lnz0) ; - - /* use Int for the final update of Zeros [s] below */ - newzeros = nscol0 * (Snz [s+1] + nscol0 - Snz [s]) ; - ASSERT (newzeros == xnewzeros) ; - - PRINT2 (("lnz0 %g lnz1 %g xnewzeros %g\n", lnz0, lnz1, xnewzeros)) ; - if (xnewzeros == 0) - { - /* no new zeros, so go ahead and merge */ - PRINT2 (("no new fillin, so go ahead and merge\n")) ; - merge = TRUE ; - } - else - { - /* # of zeros if merged */ - double xtotzeros = ((double) totzeros) + xnewzeros ; - - /* xtotsize: total size of merged supernode, if merged: */ - double xns = (double) ns ; - double xtotsize = (xns * (xns+1) / 2) + xns * (lnz1 - nscol1) ; - double z = xtotzeros / xtotsize ; - - Int totsize ; - totsize = (ns * (ns+1) / 2) + ns * (Snz [s+1] - nscol1) ; - - PRINT2 (("oldzeros "ID" newzeros "ID" xtotsize %g z %g\n", - Zeros [s+1], newzeros, xtotsize, z)) ; - - /* use Int for the final update of Zeros [s] below */ - totzeros += newzeros ; - - /* do not merge if supernode would become too big - * (Int overflow). Continue computing; not (yet) an error. */ - /* fl.pt. compare, but no NaN's can occur here */ - merge = ((ns <= nrelax1 && z < zrelax0) || - (ns <= nrelax2 && z < zrelax1) || - (z < zrelax2)) && - (xtotsize < ((double) Int_max) / sizeof (double)) ; - - } - } - -#ifdef SUITESPARSE_CUDA - if ( for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY && L->useGPU ) { - /* Ensure that the aggregated supernode fits in the device - supernode buffers */ - double xns = (double) ns; - if ( ((xns * xns) + xns * (lnz1 - nscol1))*sizeof(double)*2 >= - Common->devBuffSize ) { - merge = FALSE; - } - } -#endif + // should supernodes s and s+1 merge into a new node s? + PRINT1 (("\n========= Check relax of s "ID" and s+1 "ID"\n", s, s+1)) ; + + ss = Sparent [s] ; + if (ss == EMPTY) + { + PRINT1 (("s "ID" is a root, no merge with s+1 = "ID"\n", s, s+1)) ; + continue ; + } + + // find the current parent of s (perform path compression as needed) + for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = Merged [ss]) ; + sparent = ss ; + PRINT2 (("Current sparent of s "ID" is "ID"\n", s, sparent)) ; + + // ss is the current parent of s + for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = snext) + { + snext = Merged [ss] ; + PRINT2 (("ss "ID" is dead, merged into snext "ID"\n", ss, snext)) ; + Merged [ss] = sparent ; + } + + // if s+1 is not the current parent of s, do not merge + if (sparent != s+1) + { + continue ; + } + + nscol0 = Nscol [s] ; // # of columns in s + nscol1 = Nscol [s+1] ; // # of columns in s+1 + ns = nscol0 + nscol1 ; + PRINT2 (("ns "ID" nscol0 "ID" nscol1 "ID"\n", ns, nscol0, nscol1)) ; + + totzeros = Zeros [s+1] ; // current # of zeros in s+1 + lnz1 = (double) (Snz [s+1]) ; // # entries in leading column of s+1 + + // determine if supernodes s and s+1 should merge + if (ns <= nrelax0) + { + PRINT2 (("ns is tiny ("ID"), so go ahead and merge\n", ns)) ; + merge = TRUE ; + } + else + { + // use double to avoid integer overflow; approximations are OK + double lnz0 = Snz [s] ; // # entries in leading column of s + double xnewzeros = nscol0 * (lnz1 + nscol0 - lnz0) ; + + // use Int for the final update of Zeros [s] below + newzeros = nscol0 * (Snz [s+1] + nscol0 - Snz [s]) ; + ASSERT (newzeros == xnewzeros) ; - if (merge) - { - PRINT1 (("Merge node s ("ID") and s+1 ("ID")\n", s, s+1)) ; - Zeros [s] = totzeros ; - Merged [s+1] = s ; - Snz [s] = nscol0 + Snz [s+1] ; - Nscol [s] += Nscol [s+1] ; - } + PRINT2 (("lnz0 %g lnz1 %g xnewzeros %g\n", lnz0, lnz1, xnewzeros)) ; + if (xnewzeros == 0) + { + // no new zeros, so go ahead and merge + PRINT2 (("no new fillin, so go ahead and merge\n")) ; + merge = TRUE ; + } + else + { + // # of zeros if merged + double xtotzeros = ((double) totzeros) + xnewzeros ; + + // xtotsize: total size of merged supernode, if merged: + double xns = (double) ns ; + double xtotsize = (xns * (xns+1) / 2) + xns * (lnz1 - nscol1) ; + double z = xtotzeros / xtotsize ; + + Int totsize ; + totsize = (ns * (ns+1) / 2) + ns * (Snz [s+1] - nscol1) ; + + PRINT2 (("oldzeros "ID" newzeros "ID" xtotsize %g z %g\n", + Zeros [s+1], newzeros, xtotsize, z)) ; + + // use Int for the final update of Zeros [s] below + totzeros += newzeros ; + + // do not merge if supernode would become too big + // (Int overflow). Continue computing; not (yet) an error. + // fl.pt. compare, but no NaN's can occur here + merge = ((ns <= nrelax1 && z < zrelax0) || + (ns <= nrelax2 && z < zrelax1) || + (z < zrelax2)) && + (xtotsize < ((double) Int_max) / sizeof (double)) ; + + } + } + + #ifdef SUITESPARSE_CUDA + if ( for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY && L->useGPU ) { + // Ensure that the aggregated supernode fits in the device + // supernode buffers + double xns = (double) ns; + if ( ((xns * xns) + xns * (lnz1 - nscol1))*sizeof(double)*2 >= + Common->devBuffSize ) { + merge = FALSE; + } + } + #endif + + if (merge) + { + PRINT1 (("Merge node s ("ID") and s+1 ("ID")\n", s, s+1)) ; + Zeros [s] = totzeros ; + Merged [s+1] = s ; + Snz [s] = nscol0 + Snz [s+1] ; + Nscol [s] += Nscol [s+1] ; + } } - /* contents of Wj no longer needed for Zeros ] */ - /* contents of Wi no longer needed for Nscol ] */ - /* contents of Sparent no longer needed (recomputed below) */ + // contents of Wj no longer needed for Zeros ] + // contents of Wi no longer needed for Nscol ] + // contents of Sparent no longer needed (recomputed below) - /* ---------------------------------------------------------------------- */ - /* construct the relaxed supernode list */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct the relaxed supernode list + //-------------------------------------------------------------------------- nsuper = 0 ; for (s = 0 ; s < nfsuper ; s++) { - if (Merged [s] == EMPTY) - { - PRINT1 (("live supernode: "ID" snz "ID"\n", s, Snz [s])) ; - Super [nsuper] = Super [s] ; - Snz [nsuper] = Snz [s] ; - nsuper++ ; - } + if (Merged [s] == EMPTY) + { + PRINT1 (("live supernode: "ID" snz "ID"\n", s, Snz [s])) ; + Super [nsuper] = Super [s] ; + Snz [nsuper] = Snz [s] ; + nsuper++ ; + } } Super [nsuper] = n ; PRINT1 (("Fundamental supernodes: "ID" relaxed "ID"\n", nfsuper, nsuper)) ; - /* Merged no longer needed ] */ + // Merged no longer needed ] - /* ---------------------------------------------------------------------- */ - /* find the mapping of relaxed nodes to supernodes */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // find the mapping of relaxed nodes to supernodes + //-------------------------------------------------------------------------- - /* use Wj as workspace for SuperMap { */ + // use Wj as workspace for SuperMap { - /* SuperMap [k] = s if column k is contained in supernode s */ + // SuperMap [k] = s if column k is contained in supernode s for (s = 0 ; s < nsuper ; s++) { - for (k = Super [s] ; k < Super [s+1] ; k++) - { - SuperMap [k] = s ; - } + for (k = Super [s] ; k < Super [s+1] ; k++) + { + SuperMap [k] = s ; + } } - /* ---------------------------------------------------------------------- */ - /* construct the relaxed supernodal etree */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct the relaxed supernodal etree + //-------------------------------------------------------------------------- for (s = 0 ; s < nsuper ; s++) { - j = Super [s+1] - 1 ; /* last node in supernode s */ - parent = Parent [j] ; /* parent of last node */ - Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; - PRINT1 (("new Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; + j = Super [s+1] - 1 ; // last node in supernode s + parent = Parent [j] ; // parent of last node + Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; + PRINT1 (("new Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; } - /* ---------------------------------------------------------------------- */ - /* determine the size of L->s and L->x */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // determine the size of L->s and L->x + //-------------------------------------------------------------------------- - ssize = 0 ; - xsize = 0 ; - xxsize = 0 ; + size_t ssize = 0 ; + size_t xsize = 0 ; find_xsize = for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY || for_whom == CHOLMOD_ANALYZE_FOR_SPQRGPU ; for (s = 0 ; s < nsuper ; s++) { - nscol = Super [s+1] - Super [s] ; - nsrow = Snz [s] ; - ASSERT (nscol > 0) ; - ssize += nsrow ; + // do the computations in 64-bits to guard against integer overflow + uint64_t nscol = (uint64_t) (Super [s+1] - Super [s]) ; + uint64_t nsrow = (uint64_t) Snz [s] ; + // ssize += nsrow + ssize = CHOLMOD(add_size_t) (ssize, (size_t) nsrow, &ok) ; if (find_xsize) { - xsize += nscol * nsrow ; - /* also compute xsize in double to guard against Int overflow */ - xxsize += ((double) nscol) * ((double) nsrow) ; + // c = nscol * nsrow + uint64_t c = 0 ; + ok = ok && cholmod_mult_uint64_t (&c, nscol, nsrow) ; + // xsize += c + xsize = CHOLMOD(add_size_t) (xsize, c, &ok) ; } - if (ssize < 0 ||(find_xsize && xxsize > (double) Int_max)) - { - /* Int overflow, clear workspace and return. - QR factorization will not use xxsize, so that error is ignored. - For Cholesky factorization, however, memory of space xxsize - will be allocated, so this is a failure. Both QR and Cholesky - fail if ssize overflows. */ - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - FREE_WORKSPACE ; - return (FALSE) ; - } - ASSERT (ssize > 0) ; - ASSERT (IMPLIES (find_xsize, xsize > 0)) ; } - xsize = MAX (1, xsize) ; - ssize = MAX (1, ssize) ; - PRINT1 (("ix sizes: "ID" "ID" nsuper "ID"\n", ssize, xsize, nsuper)) ; - - /* ---------------------------------------------------------------------- */ - /* allocate L (all except real part L->x) */ - /* ---------------------------------------------------------------------- */ - L->ssize = ssize ; - L->xsize = xsize ; + ok = ok && (ssize < Int_max) && (xsize < Int_max) ; + L->ssize = (ok) ? MAX (1, ssize) : SIZE_MAX ; + L->xsize = (ok) ? MAX (1, xsize) : SIZE_MAX ; + Common->status = (ok) ? CHOLMOD_OK : CHOLMOD_TOO_LARGE ; L->nsuper = nsuper ; - CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common); + //-------------------------------------------------------------------------- + // allocate L (all except real part L->x) + //-------------------------------------------------------------------------- + + if (ok) + { + CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, + Common) ; + } if (Common->status < CHOLMOD_OK) { - /* out of memory; L is still a valid simplicial symbolic factor */ - FREE_WORKSPACE ; - return (FALSE) ; + // out of memory; L is still a valid simplicial symbolic factor + FREE_WORKSPACE ; + return (FALSE) ; } DEBUG (CHOLMOD(dump_factor) (L, "L to symbolic super", Common)) ; @@ -710,37 +699,41 @@ int CHOLMOD(super_symbolic2) Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; - Ls [0] = 0 ; /* flag for cholmod_check_factor; supernodes are defined */ + Ls [0] = 0 ; // flag for cholmod_check_factor; supernodes are defined Lsuper = L->super ; - /* copy the list of relaxed supernodes into the final list in L */ + // copy the list of relaxed supernodes into the final list in L for (s = 0 ; s <= nsuper ; s++) { - Lsuper [s] = Super [s] ; + Lsuper [s] = Super [s] ; } - /* Head no longer needed as workspace for fundamental Super list ) */ + // Head no longer needed as workspace for fundamental Super list ) - Super = Lsuper ; /* Super is now the list of relaxed supernodes */ + Super = Lsuper ; // Super is now the list of relaxed supernodes - /* ---------------------------------------------------------------------- */ - /* construct column pointers of relaxed supernodal pattern (L->pi) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct column pointers of relaxed supernodal pattern (L->pi) + //-------------------------------------------------------------------------- p = 0 ; for (s = 0 ; s < nsuper ; s++) { - Lpi [s] = p ; - p += Snz [s] ; - PRINT1 (("Snz ["ID"] = "ID", Super ["ID"] = "ID"\n", - s, Snz [s], s, Super[s])) ; + Lpi [s] = p ; + p += Snz [s] ; + PRINT1 (("Snz ["ID"] = "ID", Super ["ID"] = "ID"\n", + s, Snz [s], s, Super[s])) ; } Lpi [nsuper] = p ; ASSERT ((Int) (L->ssize) == MAX (1,p)) ; - /* ---------------------------------------------------------------------- */ - /* construct pointers for supernodal values (L->px) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // construct pointers for supernodal values (L->px) + //-------------------------------------------------------------------------- + + // L->px is not needed for non-GPU accelerated QR factorization. + // Use a magic number to tell cholmod_check_factor to ignore Lpx. + Lpx [0] = 123456 ; if (for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY || for_whom == CHOLMOD_ANALYZE_FOR_SPQRGPU) @@ -749,169 +742,159 @@ int CHOLMOD(super_symbolic2) p = 0 ; for (s = 0 ; s < nsuper ; s++) { - nscol = Super [s+1] - Super [s] ; /* number of columns in s */ - nsrow = Snz [s] ; /* # of rows, incl triangular part*/ - Lpx [s] = p ; /* pointer to numerical part of s */ + Int nscol = Super [s+1] - Super [s] ; // number of columns in s + Int nsrow = Snz [s] ; // # of rows, incl triangular part + Lpx [s] = p ; // pointer to numerical part of s p += nscol * nsrow ; } Lpx [s] = p ; ASSERT ((Int) (L->xsize) == MAX (1,p)) ; } - else - { - /* L->px is not needed for non-GPU accelerated QR factorization (it may - * lead to Int overflow, anyway, if xsize caused Int overflow above). - * Use a magic number to tell cholmod_check_factor to ignore Lpx. */ - Lpx [0] = 123456 ; - } - /* Snz no longer needed ] */ + // Snz no longer needed ] - /* ---------------------------------------------------------------------- */ - /* symbolic analysis to construct the relaxed supernodal pattern (L->s) */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // symbolic analysis to construct the relaxed supernodal pattern (L->s) + //-------------------------------------------------------------------------- - Lpi2 = Wi ; /* copy Lpi into Lpi2, using Wi as workspace for Lpi2 [ */ + Lpi2 = Wi ; // copy Lpi into Lpi2, using Wi as workspace for Lpi2 [ for (s = 0 ; s < nsuper ; s++) { - Lpi2 [s] = Lpi [s] ; + Lpi2 [s] = Lpi [s] ; } Asorted = A->sorted ; for (s = 0 ; s < nsuper ; s++) { - /* sth supernode is in columns k1 to k2-1. - * compute nonzero pattern of L (k1:k2-1,:). */ - - /* place rows k1 to k2-1 in leading column of supernode s */ - k1 = Super [s] ; - k2 = Super [s+1] ; - PRINT1 (("=========>>> Supernode "ID" k1 "ID" k2-1 "ID"\n", - s, k1, k2-1)) ; - for (k = k1 ; k < k2 ; k++) - { - Ls [Lpi2 [s]++] = k ; - } - - /* compute nonzero pattern each row k1 to k2-1 */ - for (k = k1 ; k < k2 ; k++) - { - /* compute row k of L. In the symmetric case, the pattern of L(k,:) - * is the set of nodes reachable in the supernodal etree from any - * row i in the nonzero pattern of A(0:k,k). In the unsymmetric - * case, the pattern of the kth column of A*A' is the set union - * of all columns A(0:k,j) for each nonzero F(j,k). */ - - /* clear the Flag array and mark the current supernode */ - /* mark = CHOLMOD(clear_flag) (Common) ; */ - CLEAR_FLAG (Common) ; - mark = Common->mark ; - Flag [s] = mark ; - ASSERT (s == SuperMap [k]) ; - - /* traverse the row subtree for each nonzero in A or AA' */ - if (stype != 0) - { - subtree (k, k, Ap, Ai, Anz, SuperMap, Sparent, mark, + // sth supernode is in columns k1 to k2-1. + // compute nonzero pattern of L (k1:k2-1,:). + + // place rows k1 to k2-1 in leading column of supernode s + k1 = Super [s] ; + k2 = Super [s+1] ; + PRINT1 (("=========>>> Supernode "ID" k1 "ID" k2-1 "ID"\n", + s, k1, k2-1)) ; + for (k = k1 ; k < k2 ; k++) + { + Ls [Lpi2 [s]++] = k ; + } + + // compute nonzero pattern each row k1 to k2-1 + for (k = k1 ; k < k2 ; k++) + { + // compute row k of L. In the symmetric case, the pattern of L(k,:) + // is the set of nodes reachable in the supernodal etree from any + // row i in the nonzero pattern of A(0:k,k). In the unsymmetric + // case, the pattern of the kth column of A*A' is the set union + // of all columns A(0:k,j) for each nonzero F(j,k). + + // clear the Flag array and mark the current supernode + CLEAR_FLAG (Common) ; + mark = Common->mark ; + Flag [s] = mark ; + ASSERT (s == SuperMap [k]) ; + + // traverse the row subtree for each nonzero in A or AA' + if (stype != 0) + { + subtree (k, k, Ap, Ai, Anz, SuperMap, Sparent, mark, Asorted, k1, Flag, Ls, Lpi2) ; - } - else - { - /* for each j nonzero in F (:,k) do */ - p = Fp [k] ; - pend = (packed) ? (Fp [k+1]) : (p + Fnz [k]) ; - for ( ; p < pend ; p++) - { - subtree (Fj [p], k, Ap, Ai, Anz, SuperMap, Sparent, mark, - Asorted, k1, Flag, Ls, Lpi2) ; - } - } - } + } + else + { + // for each j nonzero in F (:,k) do + p = Fp [k] ; + pend = (packed) ? (Fp [k+1]) : (p + Fnz [k]) ; + for ( ; p < pend ; p++) + { + subtree (Fj [p], k, Ap, Ai, Anz, SuperMap, Sparent, mark, + Asorted, k1, Flag, Ls, Lpi2) ; + } + } + } } -#ifndef NDEBUG + + #ifndef NDEBUG for (s = 0 ; s < nsuper ; s++) { - PRINT1 (("Lpi2[s] "ID" Lpi[s+1] "ID"\n", Lpi2 [s], Lpi [s+1])) ; - ASSERT (Lpi2 [s] == Lpi [s+1]) ; - CHOLMOD(dump_super) (s, Super, Lpi, Ls, NULL, NULL, 0, Common) ; + PRINT1 (("Lpi2[s] "ID" Lpi[s+1] "ID"\n", Lpi2 [s], Lpi [s+1])) ; + ASSERT (Lpi2 [s] == Lpi [s+1]) ; + CHOLMOD(dump_super) (s, Super, Lpi, Ls, NULL, NULL, 0, 0, Common) ; } -#endif - - /* contents of Wi no longer needed for Lpi2 ] */ - /* Sparent no longer needed ] */ - - /* ---------------------------------------------------------------------- */ - /* determine the largest update matrix (L->maxcsize) */ - /* ---------------------------------------------------------------------- */ - - /* maxcsize could be determined before L->s is allocated and defined, which - * would mean that all memory requirements for both the symbolic and numeric - * factorizations could be computed using O(nnz(A)+O(n)) space. However, it - * would require a lot of extra work. The analysis phase, above, would need - * to be duplicated, but with Ls not kept; instead, the algorithm would keep - * track of the current s and slast for each supernode d, and update them - * when a new row index appears in supernode d. An alternative would be to - * do this computation only if the allocation of L->s failed, in which case - * the following code would be skipped. - * - * The csize for a supernode is the size of its largest contribution to - * a subsequent ancestor supernode. For example, suppose the rows of #'s - * in the figure below correspond to the columns of a subsequent supernode, - * and the dots are the entries in that ancestore. - * - * c - * c c - * c c c - * x x x - * x x x - * # # # . - * # # # . . - * * * * . . - * * * * . . - * * * * . . - * . . - * - * Then for this update, the csize is 3-by-2, or 6, because there are 3 - * rows of *'s which is the number of rows in the update, and there are - * 2 rows of #'s, which is the number columns in the update. The csize - * of a supernode is the largest such contribution for any ancestor - * supernode. maxcsize, for the whole matrix, has a rough upper bound of - * the maximum size of any supernode. This bound is loose, because the - * the contribution must be less than the size of the ancestor supernodal - * that it's updating. maxcsize of a completely dense matrix, with one - * supernode, is zero. - * - * maxesize is the column dimension for the workspace E needed for the - * solve. E is of size nrhs-by-maxesize, where the nrhs is the number of - * columns in the right-hand-side. The maxesize is the largest esize of - * any supernode. The esize of a supernode is the number of row indices - * it contains, excluding the column indices of the supernode itself. - * For the following example, esize is 4: - * - * c - * c c - * c c c - * x x x - * x x x - * x x x - * x x x - * - * maxesize can be no bigger than n. - */ + #endif + + // contents of Wi no longer needed for Lpi2 ] + // Sparent no longer needed ] + + //-------------------------------------------------------------------------- + // determine the largest update matrix (L->maxcsize) + //-------------------------------------------------------------------------- + + // maxcsize could be determined before L->s is allocated and defined, which + // would mean that all memory requirements for both the symbolic and numeric + // factorizations could be computed using O(nnz(A)+O(n)) space. However, it + // would require a lot of extra work. The analysis phase, above, would need + // to be duplicated, but with Ls not kept; instead, the algorithm would keep + // track of the current s and slast for each supernode d, and update them + // when a new row index appears in supernode d. An alternative would be to + // do this computation only if the allocation of L->s failed, in which case + // the following code would be skipped. + // + // The csize for a supernode is the size of its largest contribution to + // a subsequent ancestor supernode. For example, suppose the rows of #'s + // in the figure below correspond to the columns of a subsequent supernode, + // and the dots are the entries in that ancestore. + // + // c + // c c + // c c c + // x x x + // x x x + // # # # . + // # # # . . + // * * * . . + // * * * . . + // * * * . . + // . . + // + // Then for this update, the csize is 3-by-2, or 6, because there are 3 + // rows of *'s which is the number of rows in the update, and there are + // 2 rows of #'s, which is the number columns in the update. The csize + // of a supernode is the largest such contribution for any ancestor + // supernode. maxcsize, for the whole matrix, has a rough upper bound of + // the maximum size of any supernode. This bound is loose, because the + // the contribution must be less than the size of the ancestor supernodal + // that it's updating. maxcsize of a completely dense matrix, with one + // supernode, is zero. + // + // maxesize is the column dimension for the workspace E needed for the + // solve. E is of size nrhs-by-maxesize, where the nrhs is the number of + // columns in the right-hand-side. The maxesize is the largest esize of + // any supernode. The esize of a supernode is the number of row indices + // it contains, excluding the column indices of the supernode itself. + // For the following example, esize is 4: + // + // c + // c c + // c c c + // x x x + // x x x + // x x x + // x x x + // + // maxesize can be no bigger than n. maxcsize = 1 ; maxesize = 1 ; - /* Do not need to guard csize against Int overflow since xsize is OK. */ - if (for_whom == CHOLMOD_ANALYZE_FOR_CHOLESKY || for_whom == CHOLMOD_ANALYZE_FOR_SPQRGPU) { - /* this is not needed for non-GPU accelerated QR factorization */ + // this is not needed for non-GPU accelerated QR factorization for (d = 0 ; d < nsuper ; d++) { - nscol = Super [d+1] - Super [d] ; + Int nscol = Super [d+1] - Super [d] ; p = Lpi [d] + nscol ; plast = p ; pend = Lpi [d+1] ; @@ -923,7 +906,7 @@ int CHOLMOD(super_symbolic2) s = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ; if (s != slast) { - /* row i is the start of a new supernode */ + // row i is the start of a new supernode ndrow1 = p - plast ; ndrow2 = pend - plast ; csize = ndrow2 * ndrow1 ; @@ -938,51 +921,52 @@ int CHOLMOD(super_symbolic2) PRINT1 (("max csize "ID"\n", maxcsize)) ; } - /* Wj no longer needed for SuperMap } */ + // Wj no longer needed for SuperMap } L->maxcsize = maxcsize ; L->maxesize = maxesize ; L->is_super = TRUE ; ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_ll) ; - /* ---------------------------------------------------------------------- */ - /* supernodal symbolic factorization is complete */ - /* ---------------------------------------------------------------------- */ + //-------------------------------------------------------------------------- + // supernodal symbolic factorization is complete + //-------------------------------------------------------------------------- FREE_WORKSPACE ; return (TRUE) ; } -/* ========================================================================== */ -/* === cholmod_super_symbolic =============================================== */ -/* ========================================================================== */ - -/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric - * factorization. The user need not call this directly; cholmod_analyze is - * a "simple" wrapper for this routine. - * - * This function does all the analysis for a supernodal Cholesky factorization. - * - * workspace: Flag (nrow), Head (nrow), Iwork (2*nrow), - * and temporary space of size 3*nfsuper*sizeof(Int), where nfsuper <= n - * is the number of fundamental supernodes. - */ +//------------------------------------------------------------------------------ +// cholmod_super_symbolic +//------------------------------------------------------------------------------ + +// Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric +// factorization. The user need not call this directly; cholmod_analyze is +// a "simple" wrapper for this routine. +// +// This function does all the analysis for a supernodal Cholesky factorization. +// +// workspace: Flag (nrow), Head (nrow), Iwork (2*nrow), +// and temporary space of size 3*nfsuper*sizeof(Int), where nfsuper <= n +// is the number of fundamental supernodes. int CHOLMOD(super_symbolic) ( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to analyze */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - Int *Parent, /* elimination tree */ - /* ---- in/out --- */ - cholmod_factor *L, /* simplicial symbolic on input, - * supernodal symbolic on output */ - /* --------------- */ + // input: + cholmod_sparse *A, // matrix to analyze + cholmod_sparse *F, // F = A' or A(:,f)' + Int *Parent, // elimination tree + // input/output: + cholmod_factor *L, // simplicial symbolic on input, + // supernodal symbolic on output cholmod_common *Common ) { + return (CHOLMOD(super_symbolic2) (CHOLMOD_ANALYZE_FOR_CHOLESKY, A, F, Parent, L, Common)) ; } + #endif #endif + diff --git a/CHOLMOD/Supernodal/t_cholmod_super_numeric.c b/CHOLMOD/Supernodal/t_cholmod_super_numeric.c deleted file mode 100644 index b15b5ce34a..0000000000 --- a/CHOLMOD/Supernodal/t_cholmod_super_numeric.c +++ /dev/null @@ -1,1140 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Supernodal/t_cholmod_super_numeric: cholmod_super_numeric template -//------------------------------------------------------------------------------ - -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Template routine for cholmod_super_numeric. All xtypes supported, except - * that a zomplex A and F result in a complex L (there is no supernodal - * zomplex L). - */ - -/* ========================================================================== */ -/* === complex arithmetic =================================================== */ -/* ========================================================================== */ - -#include "cholmod_template.h" - -#undef L_ENTRY -#undef L_CLEAR -#undef L_ASSIGN -#undef L_MULTADD -#undef L_ASSEMBLE -#undef L_ASSEMBLESUB - -#ifdef REAL - -/* -------------------------------------------------------------------------- */ -/* A, F, and L are all real */ -/* -------------------------------------------------------------------------- */ - -#define L_ENTRY 1 -#define L_CLEAR(Lx,p) Lx [p] = 0 -#define L_ASSIGN(Lx,q, Ax,Az,p) Lx [q] = Ax [p] -#define L_MULTADD(Lx,q, Ax,Az,p, f) Lx [q] += Ax [p] * f [0] -#define L_ASSEMBLE(Lx,q,b) Lx [q] += b [0] -#define L_ASSEMBLESUB(Lx,q,C,p) Lx [q] -= C [p] - -#else - -/* -------------------------------------------------------------------------- */ -/* A and F are complex or zomplex, L and C are complex */ -/* -------------------------------------------------------------------------- */ - -#define L_ENTRY 2 -#define L_CLEAR(Lx,p) Lx [2*(p)] = 0 ; Lx [2*(p)+1] = 0 -#define L_ASSEMBLE(Lx,q,b) Lx [2*(q)] += b [0] ; -#define L_ASSEMBLESUB(Lx,q,C,p) \ - Lx [2*(q) ] -= C [2*(p) ] ; \ - Lx [2*(q)+1] -= C [2*(p)+1] ; - -#ifdef COMPLEX - -/* -------------------------------------------------------------------------- */ -/* A, F, L, and C are all complex */ -/* -------------------------------------------------------------------------- */ - -#define L_ASSIGN(Lx,q, Ax,Az,p) \ - Lx [2*(q) ] = Ax [2*(p) ] ; \ - Lx [2*(q)+1] = Ax [2*(p)+1] - -#define L_MULTADD(Lx,q, Ax,Az,p, f) \ - Lx [2*(q) ] += Ax [2*(p) ] * f [0] - Ax [2*(p)+1] * f [1] ; \ - Lx [2*(q)+1] += Ax [2*(p)+1] * f [0] + Ax [2*(p) ] * f [1] - -#else - -/* -------------------------------------------------------------------------- */ -/* A and F are zomplex, L and C is complex */ -/* -------------------------------------------------------------------------- */ - -#define L_ASSIGN(Lx,q, Ax,Az,p) \ - Lx [2*(q) ] = Ax [p] ; \ - Lx [2*(q)+1] = Az [p] ; - -#define L_MULTADD(Lx,q, Ax,Az,p, f) \ - Lx [2*(q) ] += Ax [p] * f [0] - Az [p] * f [1] ; \ - Lx [2*(q)+1] += Az [p] * f [0] + Ax [p] * f [1] - -#endif -#endif - - -/* ========================================================================== */ -/* === t_cholmod_super_numeric ============================================== */ -/* ========================================================================== */ - -/* This function returns FALSE only if integer overflow occurs in the BLAS. - * It returns TRUE otherwise whether or not the matrix is positive definite. */ - -static int TEMPLATE (cholmod_super_numeric) -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to factorize */ - cholmod_sparse *F, /* F = A' or A(:,f)' */ - double beta [2], /* beta*I is added to diagonal of matrix to factorize */ - /* ---- in/out --- */ - cholmod_factor *L, /* factorization */ - /* -- workspace -- */ - cholmod_dense *Cwork, /* size (L->maxcsize)-by-1 */ - /* --------------- */ - cholmod_common *Common - ) -{ - double one [2], zero [2], tstart ; - double *Lx, *Ax, *Fx, *Az, *Fz, *C ; - Int *Super, *Head, *Ls, *Lpi, *Lpx, *Map, *SuperMap, *RelativeMap, *Next, - *Lpos, *Fp, *Fi, *Fnz, *Ap, *Ai, *Anz, *Iwork, *Next_save, *Lpos_save, - *Previous; - Int nsuper, n, j, i, k, s, p, pend, k1, k2, nscol, psi, psx, psend, nsrow, - pj, d, kd1, kd2, info, ndcol, ndrow, pdi, pdx, pdend, pdi1, pdi2, pdx1, - ndrow1, ndrow2, px, dancestor, sparent, dnext, nsrow2, ndrow3, pk, pf, - pfend, stype, Apacked, Fpacked, q, imap, repeat_supernode, nscol2, ss, - tail, nscol_new = 0; - info = 0 ; - - /* ---------------------------------------------------------------------- */ - /* declarations for the GPU */ - /* ---------------------------------------------------------------------- */ - - /* these variables are not used if the GPU module is not installed */ - -#ifdef SUITESPARSE_CUDA - Int ndescendants, mapCreatedOnGpu, supernodeUsedGPU, - idescendant, dlarge, dsmall, skips ; - int iHostBuff, iDevBuff, useGPU, GPUavailable ; - cholmod_gpu_pointers *gpu_p, gpu_pointer_struct ; - gpu_p = &gpu_pointer_struct ; -#endif - - /* ---------------------------------------------------------------------- */ - /* guard against integer overflow in the BLAS */ - /* ---------------------------------------------------------------------- */ - - /* If integer overflow occurs in the BLAS, Common->status is set to - * CHOLMOD_TOO_LARGE, and the contents of Lx are undefined. */ - Common->blas_ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - nsuper = L->nsuper ; - n = L->n ; - - C = Cwork->x ; /* workspace of size L->maxcsize */ - - one [0] = 1.0 ; /* ALPHA for *syrk, *herk, *gemm, and *trsm */ - one [1] = 0. ; - zero [0] = 0. ; /* BETA for *syrk, *herk, and *gemm */ - zero [1] = 0. ; - - /* Iwork must be of size 2n + 5*nsuper, allocated in the caller, - * cholmod_super_numeric. The memory cannot be allocated here because the - * cholmod_super_numeric initializes SuperMap, and cholmod_allocate_work - * does not preserve existing workspace if the space needs to be increase - * in size. */ - - /* allocate integer workspace */ - Iwork = Common->Iwork ; - SuperMap = Iwork ; /* size n (i/i/l) */ - RelativeMap = Iwork + n ; /* size n (i/i/l) */ - Next = Iwork + 2*((size_t) n) ; /* size nsuper*/ - Lpos = Iwork + 2*((size_t) n) + nsuper ; /* size nsuper*/ - Next_save = Iwork + 2*((size_t) n) + 2*((size_t) nsuper) ;/* size nsuper*/ - Lpos_save = Iwork + 2*((size_t) n) + 3*((size_t) nsuper) ;/* size nsuper*/ - Previous = Iwork + 2*((size_t) n) + 4*((size_t) nsuper) ;/* size nsuper*/ - - Map = Common->Flag ; /* size n, use Flag as workspace for Map array */ - Head = Common->Head ; /* size n+1, only Head [0..nsuper-1] used */ - - Ls = L->s ; - Lpi = L->pi ; - Lpx = L->px ; - - Super = L->super ; - - Lx = L->x ; - -#ifdef SUITESPARSE_CUDA - /* local copy of useGPU */ - if ( (Common->useGPU == 1) && L->useGPU) - { - /* Initialize the GPU. If not found, don't use it. */ - useGPU = TEMPLATE2 (CHOLMOD (gpu_init)) - (C, L, Common, nsuper, n, Lpi[nsuper]-Lpi[0], gpu_p) ; - } - else - { - useGPU = 0; - } - /* fprintf (stderr, "local useGPU %d\n", useGPU) ; */ -#endif - -#ifndef NTIMER - /* clear GPU / CPU statistics */ - Common->CHOLMOD_CPU_GEMM_CALLS = 0 ; - Common->CHOLMOD_CPU_SYRK_CALLS = 0 ; - Common->CHOLMOD_CPU_TRSM_CALLS = 0 ; - Common->CHOLMOD_CPU_POTRF_CALLS = 0 ; - Common->CHOLMOD_GPU_GEMM_CALLS = 0 ; - Common->CHOLMOD_GPU_SYRK_CALLS = 0 ; - Common->CHOLMOD_GPU_TRSM_CALLS = 0 ; - Common->CHOLMOD_GPU_POTRF_CALLS = 0 ; - Common->CHOLMOD_CPU_GEMM_TIME = 0 ; - Common->CHOLMOD_CPU_SYRK_TIME = 0 ; - Common->CHOLMOD_CPU_TRSM_TIME = 0 ; - Common->CHOLMOD_CPU_POTRF_TIME = 0 ; - Common->CHOLMOD_GPU_GEMM_TIME = 0 ; - Common->CHOLMOD_GPU_SYRK_TIME = 0 ; - Common->CHOLMOD_GPU_TRSM_TIME = 0 ; - Common->CHOLMOD_GPU_POTRF_TIME = 0 ; - Common->CHOLMOD_ASSEMBLE_TIME = 0 ; - Common->CHOLMOD_ASSEMBLE_TIME2 = 0 ; -#endif - - stype = A->stype ; - - if (stype != 0) - { - /* F not accessed */ - Fp = NULL ; - Fi = NULL ; - Fx = NULL ; - Fz = NULL ; - Fnz = NULL ; - Fpacked = TRUE ; - } - else - { - Fp = F->p ; - Fi = F->i ; - Fx = F->x ; - Fz = F->z ; - Fnz = F->nz ; - Fpacked = F->packed ; - } - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - Anz = A->nz ; - Apacked = A->packed ; - - /* clear the Map so that changes in the pattern of A can be detected */ - - #ifdef _OPENMP - int nthreads = cholmod_nthreads ((double) n, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - if ( n > 128 ) schedule (static) - - for (i = 0 ; i < n ; i++) - { - Map [i] = EMPTY ; - } - - /* If the matrix is not positive definite, the supernode s containing the - * first zero or negative diagonal entry of L is repeated (but factorized - * only up to just before the problematic diagonal entry). The purpose is - * to provide MATLAB with [R,p]=chol(A); columns 1 to p-1 of L=R' are - * required, where L(p,p) is the problematic diagonal entry. The - * repeat_supernode flag tells us whether this is the repeated supernode. - * Once supernode s is repeated, the factorization is terminated. */ - repeat_supernode = FALSE ; - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) - { - /* Case of GPU, zero all supernodes at one time for better performance*/ - TEMPLATE2 (CHOLMOD (gpu_clear_memory))(Lx, L->xsize, - Common->nthreads_max); - } -#endif - - /* ---------------------------------------------------------------------- */ - /* supernodal numerical factorization */ - /* ---------------------------------------------------------------------- */ - - for (s = 0 ; s < nsuper ; s++) - { - - /* ------------------------------------------------------------------ */ - /* get the size of supernode s */ - /* ------------------------------------------------------------------ */ - - k1 = Super [s] ; /* s contains columns k1 to k2-1 of L */ - k2 = Super [s+1] ; - nscol = k2 - k1 ; /* # of columns in all of s */ - psi = Lpi [s] ; /* pointer to first row of s in Ls */ - psx = Lpx [s] ; /* pointer to first row of s in Lx */ - psend = Lpi [s+1] ; /* pointer just past last row of s in Ls */ - nsrow = psend - psi ; /* # of rows in all of s */ - - PRINT1 (("====================================================\n" - "S "ID" k1 "ID" k2 "ID" nsrow "ID" nscol "ID" psi "ID" psend " - ""ID" psx "ID"\n", s, k1, k2, nsrow, nscol, psi, psend, psx)) ; - /* ------------------------------------------------------------------ */ - /* zero the supernode s */ - /* ------------------------------------------------------------------ */ - - ASSERT ((size_t) (psx + nsrow*nscol) <= L->xsize) ; - - pend = psx + nsrow * nscol ; /* s is nsrow-by-nscol */ - -#ifdef SUITESPARSE_CUDA - if ( !useGPU ) -#endif - { - /* Case of no GPU, zero individual supernodes */ - - #ifdef _OPENMP - double work = (double) (pend - psx) * L_ENTRY ; - int nthreads = cholmod_nthreads (work, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - schedule (static) if ( pend - psx > 1024 ) - - for (p = psx ; p < pend ; p++) { - L_CLEAR (Lx,p); - } - } - - /* ------------------------------------------------------------------ */ - /* construct the scattered Map for supernode s */ - /* ------------------------------------------------------------------ */ - - /* If row i is the kth row in s, then Map [i] = k. Similarly, if - * column j is the kth column in s, then Map [j] = k. */ - - #ifdef _OPENMP - int nthreads = cholmod_nthreads ((double) nsrow, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - if ( nsrow > 128 ) - - for (k = 0 ; k < nsrow ; k++) - { - PRINT1 ((" "ID" map "ID"\n", Ls [psi+k], k)) ; - Map [Ls [psi + k]] = k ; - } - - /* ------------------------------------------------------------------ */ - /* when using GPU, reorder supernodes by levels.*/ - /* (all supernodes in a level are independent) */ - /* ------------------------------------------------------------------ */ - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) - { - TEMPLATE2 (CHOLMOD (gpu_reorder_descendants)) - ( Common, Super, &s, Lpi, Lpos, Head, Next, Previous, - &ndescendants, &tail, &mapCreatedOnGpu, gpu_p ) ; - } -#endif - - /* ------------------------------------------------------------------ */ - /* copy matrix into supernode s (lower triangular part only) */ - /* ------------------------------------------------------------------ */ - - pk = psx ; - - #ifdef _OPENMP - double work ; - if (stype != 0) - { - Int pfirst = Ap [k1] ; - Int plast = (Apacked) ? (Ap [k2]) : (pfirst + Anz [k2-1]) ; - work = (double) (plast - pfirst) ; - } - else - { - Int pfirst = Fp [k1] ; - Int plast = (Fpacked) ? (Fp [k2]) : (pfirst + Fnz [k2-1]) ; - work = (double) (plast - pfirst) ; - } - nthreads = cholmod_nthreads (work, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - private ( p, pend, pfend, pf, i, j, imap, q ) if ( k2-k1 > 64 ) - - for (k = k1 ; k < k2 ; k++) - { - if (stype != 0) - { - /* copy the kth column of A into the supernode */ - p = Ap [k] ; - pend = (Apacked) ? (Ap [k+1]) : (p + Anz [k]) ; - for ( ; p < pend ; p++) - { - /* row i of L is located in row Map [i] of s */ - i = Ai [p] ; - if (i >= k) - { - /* This test is here simply to avoid a segfault. If - * the test is false, the numeric factorization of A - * is undefined. It does not detect all invalid - * entries, only some of them (when debugging is - * enabled, and Map is cleared after each step, then - * all entries not in the pattern of L are detected). */ - imap = Map [i] ; - if (imap >= 0 && imap < nsrow) - { - /* Lx [Map [i] + pk] = Ax [p] ; */ - L_ASSIGN (Lx,(imap+(psx+(k-k1)*nsrow)), Ax,Az,p) ; - } - } - } - } - else - { - double fjk[2]; - /* copy the kth column of A*F into the supernode */ - pf = Fp [k] ; - pfend = (Fpacked) ? (Fp [k+1]) : (p + Fnz [k]) ; - for ( ; pf < pfend ; pf++) - { - j = Fi [pf] ; - - /* fjk = Fx [pf] ; */ - L_ASSIGN (fjk,0, Fx,Fz,pf) ; - - p = Ap [j] ; - pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i >= k) - { - /* See the discussion of imap above. */ - imap = Map [i] ; - if (imap >= 0 && imap < nsrow) - { - /* Lx [Map [i] + pk] += Ax [p] * fjk ; */ - L_MULTADD (Lx,(imap+(psx+(k-k1)*nsrow)), - Ax,Az,p, fjk) ; - } - } - } - } - } - } - - /* add beta to the diagonal of the supernode, if nonzero */ - if (beta [0] != 0.0) - { - /* note that only the real part of beta is used */ - pk = psx ; - for (k = k1 ; k < k2 ; k++) - { - /* Lx [pk] += beta [0] ; */ - L_ASSEMBLE (Lx,pk, beta) ; - pk += nsrow + 1 ; /* advance to the next diagonal entry */ - } - } - - PRINT1 (("Supernode with just A: repeat: "ID"\n", repeat_supernode)) ; - DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, - Common)) ; - PRINT1 (("\n\n")) ; - - /* ------------------------------------------------------------------ */ - /* save/restore the list of supernodes */ - /* ------------------------------------------------------------------ */ - - if (!repeat_supernode) - { - /* Save the list of pending descendants in case s is not positive - * definite. Also save Lpos for each descendant d, so that we can - * find which part of d is used to update s. */ - for (d = Head [s] ; d != EMPTY ; d = Next [d]) - { - Lpos_save [d] = Lpos [d] ; - Next_save [d] = Next [d] ; - } - } - else - { - for (d = Head [s] ; d != EMPTY ; d = Next [d]) - { - Lpos [d] = Lpos_save [d] ; - Next [d] = Next_save [d] ; - } - } - - /* ------------------------------------------------------------------ */ - /* update supernode s with each pending descendant d */ - /* ------------------------------------------------------------------ */ - -#ifndef NDEBUG - for (d = Head [s] ; d != EMPTY ; d = Next [d]) - { - PRINT1 (("\nWill update "ID" with Child: "ID"\n", s, d)) ; - DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, - Common)) ; - } - PRINT1 (("\nNow factorizing supernode "ID":\n", s)) ; -#endif - -#ifdef SUITESPARSE_CUDA - /* initialize the buffer counter */ - if ( useGPU ) { - Common->ibuffer = 0; - supernodeUsedGPU = 0; - idescendant = 0; - d = Head[s]; - dnext = d; - dlarge = Next[d]; - dsmall = tail; - GPUavailable = 1; - skips = 0; - } - else - { - dnext = Head[s]; - } -#else - /* GPU module not installed */ - dnext = Head[s]; -#endif - - while - -#ifdef SUITESPARSE_CUDA - ( (!useGPU && (dnext != EMPTY)) - || (useGPU && (idescendant < ndescendants))) -#else - - ( dnext != EMPTY ) -#endif - { - -#ifdef SUITESPARSE_CUDA - - if ( useGPU ) { - - /* Conditionally select the next descendant supernode to - * assemble. - * + first, select the largest descendant - * + subsequently, if gpu host buffers are available, select - * the largest remaining descendant for assembly on the GPU - * + otherwise select the smallest remaining descendant for - * assembly on the CPU - * - * The objective is to keep the GPU busy assembling the largest - * descendants, and simultaneously keep the CPU busy assembling - * the smallest descendants. - * - * As this is called for every descendent supernode, moving - * this code to t_cholmod_gpu incurs substantial overhead - - * ~20 GF/s on audikw_1 - so it is being left here. - */ - - iHostBuff = - (Common->ibuffer) % CHOLMOD_HOST_SUPERNODE_BUFFERS; - cudaError_t cuErr; - - if ( idescendant > 0 ) { - if ( GPUavailable == -1 || skips > 0) { - d = dsmall; - dsmall = Previous[dsmall]; - skips--; - } - else { - cuErr = cudaEventQuery - ( Common->updateCBuffersFree[iHostBuff] ); - if ( cuErr == cudaSuccess ) { - /* buffers are available, so assemble a large - * descendant (anticipating that this will be - * assembled on the GPU) */ - d = dlarge; - dlarge = Next[dlarge]; - GPUavailable = 1; - skips = 0; - } - else { - /* buffers are not available, so the GPU is busy, - * so assemble a small descendant (anticipating - * that it will be assembled on the host) */ - d = dsmall; - dsmall = Previous[dsmall]; - GPUavailable = 0; - - /* if the GPUs are busy, then do this many - * supernodes on the CPU before querying GPUs - * again. */ - skips = CHOLMOD_GPU_SKIP; - } - } - } - - idescendant++; - - } - else - { - d = dnext; - } -#else - /* GPU module not installed at compile time */ - d = dnext ; -#endif - /* -------------------------------------------------------------- */ - /* get the size of supernode d */ - /* -------------------------------------------------------------- */ - - kd1 = Super [d] ; /* d contains cols kd1 to kd2-1 of L */ - kd2 = Super [d+1] ; - ndcol = kd2 - kd1 ; /* # of columns in all of d */ - pdi = Lpi [d] ; /* pointer to first row of d in Ls */ - pdx = Lpx [d] ; /* pointer to first row of d in Lx */ - pdend = Lpi [d+1] ; /* pointer just past last row of d in Ls */ - ndrow = pdend - pdi ; /* # rows in all of d */ - - PRINT1 (("Child: ")) ; - DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, - Common)) ; - - /* -------------------------------------------------------------- */ - /* find the range of rows of d that affect rows k1 to k2-1 of s */ - /* -------------------------------------------------------------- */ - - p = Lpos [d] ; /* offset of 1st row of d affecting s */ - pdi1 = pdi + p ; /* ptr to 1st row of d affecting s in Ls */ - pdx1 = pdx + p ; /* ptr to 1st row of d affecting s in Lx */ - - /* there must be at least one row remaining in d to update s */ - ASSERT (pdi1 < pdend) ; - PRINT1 (("Lpos[d] "ID" pdi1 "ID" Ls[pdi1] "ID"\n", - Lpos[d], pdi1, Ls [pdi1])) ; - ASSERT (Ls [pdi1] >= k1 && Ls [pdi1] < k2) ; - - for (pdi2 = pdi1 ; pdi2 < pdend && Ls [pdi2] < k2 ; pdi2++) ; - ndrow1 = pdi2 - pdi1 ; /* # rows in first part of d */ - ndrow2 = pdend - pdi1 ; /* # rows in remaining d */ - - /* rows Ls [pdi1 ... pdi2-1] are in the range k1 to k2-1. Since d - * affects s, this set cannot be empty. */ - ASSERT (pdi1 < pdi2 && pdi2 <= pdend) ; - PRINT1 (("ndrow1 "ID" ndrow2 "ID"\n", ndrow1, ndrow2)) ; - DEBUG (for (p = pdi1 ; p < pdi2 ; p++) - PRINT1 (("Ls["ID"] "ID"\n", p, Ls[p]))) ; - - /* -------------------------------------------------------------- */ - /* construct the update matrix C for this supernode d */ - /* -------------------------------------------------------------- */ - - /* C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except - * that k1:n-1 refers to all of the rows in L, but many of the - * rows are all zero. Supernode d holds columns kd1 to kd2-1 of L. - * Nonzero rows in the range k1:k2-1 are in the list - * Ls [pdi1 ... pdi2-1], of size ndrow1. Nonzero rows in the range - * k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2. Let - * L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let - * L2 = L (Ls [pdi2 ... pdend], kd1:kd2-1). C is ndrow2-by-ndrow1. - * Let C1 be the first ndrow1 rows of C and let C2 be the last - * ndrow2-ndrow1 rows of C. Only the lower triangular part of C1 - * needs to be computed since C1 is symmetric. - */ - - /* maxcsize is the largest size of C for all pairs (d,s) */ - ASSERT (ndrow2 * ndrow1 <= ((Int) L->maxcsize)) ; - - /* compute leading ndrow1-by-ndrow1 lower triangular block of C, - * C1 = L1*L1' */ - - ndrow3 = ndrow2 - ndrow1 ; /* number of rows of C2 */ - ASSERT (ndrow3 >= 0) ; - - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) { - /* set up GPU to assemble new supernode */ - if ( GPUavailable == 1) { - if ( ndrow2 * L_ENTRY >= CHOLMOD_ND_ROW_LIMIT && - ndcol * L_ENTRY >= CHOLMOD_ND_COL_LIMIT ) { - if ( ! mapCreatedOnGpu ) { - TEMPLATE2 ( CHOLMOD (gpu_initialize_supernode)) - ( Common, nscol, nsrow, psi, gpu_p ); - mapCreatedOnGpu = 1; - } - } - else { - /* we've reached the limit of GPU-eligible descendants - * flag to stop stop performing cudaEventQueries */ - GPUavailable = -1; - } - } - } -#endif - -#ifdef SUITESPARSE_CUDA - if ( !useGPU - || GPUavailable!=1 - || !TEMPLATE2 (CHOLMOD (gpu_updateC)) (ndrow1, ndrow2, ndrow, - ndcol, nsrow, pdx1, pdi1, Lx, C, Common, gpu_p)) -#endif - { - /* GPU not installed, or not used */ -#ifndef NTIMER - - Common->CHOLMOD_CPU_SYRK_CALLS++ ; - tstart = SuiteSparse_time () ; -#endif - -#ifdef REAL - SUITESPARSE_BLAS_dsyrk ("L", "N", - ndrow1, ndcol, /* N, K: L1 is ndrow1-by-ndcol*/ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*pdx1, ndrow, /* A, LDA: L1, ndrow */ - zero, /* BETA: 0 */ - C, ndrow2, /* C, LDC: C1 */ - Common->blas_ok) ; -#else - SUITESPARSE_BLAS_zherk ("L", "N", - ndrow1, ndcol, /* N, K: L1 is ndrow1-by-ndcol*/ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*pdx1, ndrow, /* A, LDA: L1, ndrow */ - zero, /* BETA: 0 */ - C, ndrow2, /* C, LDC: C1 */ - Common->blas_ok) ; -#endif - -#ifndef NTIMER - Common->CHOLMOD_CPU_SYRK_TIME += SuiteSparse_time () - tstart ; -#endif - /* compute remaining (ndrow2-ndrow1)-by-ndrow1 block of C, - * C2 = L2*L1' */ - if (ndrow3 > 0) - { -#ifndef NTIMER - Common->CHOLMOD_CPU_GEMM_CALLS++ ; - tstart = SuiteSparse_time () ; -#endif - -#ifdef REAL - SUITESPARSE_BLAS_dgemm ("N", "C", - ndrow3, ndrow1, ndcol, /* M, N, K */ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*(pdx1 + ndrow1), /* A, LDA: L2 */ - ndrow, /* ndrow */ - Lx + L_ENTRY*pdx1, /* B, LDB: L1 */ - ndrow, /* ndrow */ - zero, /* BETA: 0 */ - C + L_ENTRY*ndrow1, /* C, LDC: C2 */ - ndrow2, - Common->blas_ok) ; -#else - SUITESPARSE_BLAS_zgemm ("N", "C", - ndrow3, ndrow1, ndcol, /* M, N, K */ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*(pdx1 + ndrow1), /* A, LDA: L2 */ - ndrow, /* ndrow */ - Lx + L_ENTRY*pdx1, /* B, LDB: L1, ndrow */ - ndrow, - zero, /* BETA: 0 */ - C + L_ENTRY*ndrow1, /* C, LDC: C2 */ - ndrow2, - Common->blas_ok) ; -#endif - -#ifndef NTIMER - Common->CHOLMOD_CPU_GEMM_TIME += - SuiteSparse_time () - tstart ; -#endif - } - - /* ---------------------------------------------------------- */ - /* construct relative map to assemble d into s */ - /* ---------------------------------------------------------- */ - - DEBUG (CHOLMOD(dump_real) ("C", C, ndrow2, ndrow1, TRUE, - L_ENTRY, Common)) ; - - #ifdef _OPENMP - int nthreads = cholmod_nthreads ((double) ndrow2, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - if ( ndrow2 > 64 ) - - for (i = 0 ; i < ndrow2 ; i++) - { - RelativeMap [i] = Map [Ls [pdi1 + i]] ; - ASSERT (RelativeMap [i] >= 0 && RelativeMap [i] < nsrow) ; - } - - /* ---------------------------------------------------------- */ - /* assemble C into supernode s using the relative map */ - /* ---------------------------------------------------------- */ - - #ifdef _OPENMP - double work = (double) ndcol * (double) ndrow2 * L_ENTRY ; - nthreads = cholmod_nthreads (work, Common) ; - #endif - -#pragma omp parallel for num_threads(nthreads) \ - private ( j, i, px, q ) if (ndrow1 > 64 ) - - for (j = 0 ; j < ndrow1 ; j++) /* cols k1:k2-1 */ - { - ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ; - ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ; - px = psx + RelativeMap [j] * nsrow ; - for (i = j ; i < ndrow2 ; i++) /* rows k1:n-1 */ - { - ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ; - ASSERT (RelativeMap [i] >= j && RelativeMap[i] < nsrow); - /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */ - q = px + RelativeMap [i] ; - L_ASSEMBLESUB (Lx,q, C, i+ndrow2*j) ; - } - } - - } -#ifdef SUITESPARSE_CUDA - else - { - supernodeUsedGPU = 1; /* GPU was used for this supernode*/ - Common->ibuffer++; /* gpu_updateC is asynchronous, so use - * the next host buffer for the next - * supernode */ - Common->ibuffer = Common->ibuffer% - (CHOLMOD_HOST_SUPERNODE_BUFFERS*CHOLMOD_DEVICE_STREAMS); - } -#endif - - /* -------------------------------------------------------------- */ - /* prepare this supernode d for its next ancestor */ - /* -------------------------------------------------------------- */ - - dnext = Next [d] ; - - if (!repeat_supernode) - { - /* If node s is being repeated, Head [dancestor] has already - * been cleared (set to EMPTY). It must remain EMPTY. The - * dancestor will not be factorized since the factorization - * terminates at node s. */ - Lpos [d] = pdi2 - pdi ; - if (Lpos [d] < ndrow) - { - dancestor = SuperMap [Ls [pdi2]] ; - ASSERT (dancestor > s && dancestor < nsuper) ; - /* place d in the link list of its next ancestor */ - Next [d] = Head [dancestor] ; - Head [dancestor] = d ; - } - } - - } /* end of descendant supernode loop */ - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) { - iHostBuff = (Common->ibuffer)%CHOLMOD_HOST_SUPERNODE_BUFFERS; - iDevBuff = (Common->ibuffer)%CHOLMOD_DEVICE_STREAMS; - - /* combine updates assembled on the GPU with updates - * assembled on the CPU */ - TEMPLATE2 ( CHOLMOD (gpu_final_assembly )) - ( Common, Lx, psx, nscol, nsrow, supernodeUsedGPU, - &iHostBuff, &iDevBuff, gpu_p ); - } -#endif - - PRINT1 (("\nSupernode with contributions A: repeat: "ID"\n", - repeat_supernode)) ; - DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, - Common)) ; - PRINT1 (("\n\n")) ; - - /* ------------------------------------------------------------------ */ - /* factorize diagonal block of supernode s in LL' */ - /* ------------------------------------------------------------------ */ - - /* The current supernode s is ready to factorize. It has been updated - * by all descendant supernodes. Let S = the current supernode, which - * holds rows k1:n-1 and columns k1:k2-1 of the updated matrix. It - * splits into two parts: the square diagonal block S1, and the - * rectangular part S2. Here, S1 is factorized into L1*L1' and - * overwritten by L1. - * - * If supernode s is being repeated, only factorize it up to but not - * including the column containing the problematic entry. - */ - - nscol2 = (repeat_supernode) ? (nscol_new) : (nscol) ; - -#ifdef SUITESPARSE_CUDA - if ( !useGPU - || !supernodeUsedGPU - || !TEMPLATE2 (CHOLMOD (gpu_lower_potrf))(nscol2, nsrow, psx, Lx, - &info, Common, gpu_p)) -#endif - { - /* Note that the GPU will not be used for the triangular solve */ -#ifdef SUITESPARSE_CUDA - supernodeUsedGPU = 0; -#endif -#ifndef NTIMER - Common->CHOLMOD_CPU_POTRF_CALLS++ ; - tstart = SuiteSparse_time () ; -#endif -#ifdef REAL - SUITESPARSE_LAPACK_dpotrf ("L", - nscol2, /* N: nscol2 */ - Lx + L_ENTRY*psx, nsrow, /* A, LDA: S1, nsrow */ - info, /* INFO */ - Common->blas_ok) ; -#else - SUITESPARSE_LAPACK_zpotrf ("L", - nscol2, /* N: nscol2 */ - Lx + L_ENTRY*psx, nsrow, /* A, LDA: S1, nsrow */ - info, /* INFO */ - Common->blas_ok) ; -#endif -#ifndef NTIMER - Common->CHOLMOD_CPU_POTRF_TIME += SuiteSparse_time ()- tstart ; -#endif - } - - /* ------------------------------------------------------------------ */ - /* check if the matrix is not positive definite */ - /* ------------------------------------------------------------------ */ - - if (repeat_supernode) - { - /* the leading part has been refactorized; it must have succeeded */ - info = 0 ; - - /* zero out the rest of this supernode */ - p = psx + nsrow * nscol_new ; - pend = psx + nsrow * nscol ; /* s is nsrow-by-nscol */ - for ( ; p < pend ; p++) - { - /* Lx [p] = 0 ; */ - L_CLEAR (Lx,p) ; - } - } - - /* info is set to one in SUITESPARSE_LAPACK_*potrf if blas_ok is FALSE. - * It is set to zero in dpotrf/zpotrf if the factorization was - * successful. */ - if (sizeof (SUITESPARSE_BLAS_INT) < sizeof (Int) && !Common->blas_ok) - { - ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; - } - - if (info != 0) - { - /* Matrix is not positive definite. dpotrf/zpotrf do NOT report an - * error if the diagonal of L has NaN's, only if it has a zero. */ - if (Common->status == CHOLMOD_OK) - { - ERROR (CHOLMOD_NOT_POSDEF, "matrix not positive definite") ; - } - - /* L->minor is the column of L that contains a zero or negative - * diagonal term. */ - L->minor = k1 + info - 1 ; - - /* clear the link lists of all subsequent supernodes */ - for (ss = s+1 ; ss < nsuper ; ss++) - { - Head [ss] = EMPTY ; - } - - /* zero this supernode, and all remaining supernodes */ - pend = L->xsize ; - for (p = psx ; p < pend ; p++) - { - /* Lx [p] = 0. ; */ - L_CLEAR (Lx,p) ; - } - - /* If L is indefinite, it still contains useful information. - * Supernodes 0 to s-1 are valid, similar to MATLAB [R,p]=chol(A), - * where the 1-based p is identical to the 0-based L->minor. Since - * L->minor is in the current supernode s, it and any columns to the - * left of it in supernode s are also all zero. This differs from - * [R,p]=chol(A), which contains nonzero rows 1 to p-1. Fix this - * by setting repeat_supernode to TRUE, and repeating supernode s. - * - * If Common->quick_return_if_not_posdef is true, then the entire - * supernode s is not factorized; it is left as all zero. - */ - - if (info == 1 || Common->quick_return_if_not_posdef) - { - /* If the first column of supernode s contains a zero or - * negative diagonal entry, then it is already properly set to - * zero. Also, info will be 1 if integer overflow occured in - * the BLAS. */ - Head [s] = EMPTY ; -#ifdef SUITESPARSE_CUDA - if ( useGPU ) { - CHOLMOD (gpu_end) (Common) ; - } -#endif - return (Common->status >= CHOLMOD_OK) ; - } - else - { - /* Repeat supernode s, but only factorize it up to but not - * including the column containing the problematic diagonal - * entry. */ - repeat_supernode = TRUE ; - s-- ; - nscol_new = info - 1 ; - continue ; - } - } - - /* ------------------------------------------------------------------ */ - /* compute the subdiagonal block and prepare supernode for its parent */ - /* ------------------------------------------------------------------ */ - - nsrow2 = nsrow - nscol2 ; - if (nsrow2 > 0) - { - /* The current supernode is columns k1 to k2-1 of L. Let L1 be the - * diagonal block (factorized by dpotrf/zpotrf above; rows/cols - * k1:k2-1), and L2 be rows k2:n-1 and columns k1:k2-1 of L. The - * triangular system to solve is L2*L1' = S2, where S2 is - * overwritten with L2. More precisely, L2 = S2 / L1' in MATLAB - * notation. - */ - -#ifdef SUITESPARSE_CUDA - if ( !useGPU - || !supernodeUsedGPU - || !TEMPLATE2 (CHOLMOD(gpu_triangular_solve)) - (nsrow2, nscol2, nsrow, psx, Lx, Common, gpu_p)) -#endif - { -#ifndef NTIMER - Common->CHOLMOD_CPU_TRSM_CALLS++ ; - tstart = SuiteSparse_time () ; -#endif - -#ifdef REAL - SUITESPARSE_BLAS_dtrsm ("R", "L", "C", "N", - nsrow2, nscol2, /* M, N */ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*psx, nsrow, /* A, LDA: L1, nsrow */ - Lx + L_ENTRY*(psx + nscol2), /* B, LDB, L2, nsrow */ - nsrow, - Common->blas_ok) ; -#else - SUITESPARSE_BLAS_ztrsm ("R", "L", "C", "N", - nsrow2, nscol2, /* M, N */ - one, /* ALPHA: 1 */ - Lx + L_ENTRY*psx, nsrow, /* A, LDA: L1, nsrow */ - Lx + L_ENTRY*(psx + nscol2), /* B, LDB, L2, nsrow */ - nsrow, - Common->blas_ok) ; -#endif - -#ifndef NTIMER - Common->CHOLMOD_CPU_TRSM_TIME += SuiteSparse_time () - tstart ; -#endif - } - - if (!Common->blas_ok) - { - ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; - } - - if (!repeat_supernode) - { - /* Lpos [s] is offset of first row of s affecting its parent */ - Lpos [s] = nscol ; - sparent = SuperMap [Ls [psi + nscol]] ; - ASSERT (sparent != EMPTY) ; - ASSERT (Ls [psi + nscol] >= Super [sparent]) ; - ASSERT (Ls [psi + nscol] < Super [sparent+1]) ; - ASSERT (SuperMap [Ls [psi + nscol]] == sparent) ; - ASSERT (sparent > s && sparent < nsuper) ; - /* place s in link list of its parent */ - Next [s] = Head [sparent] ; - Head [sparent] = s ; - } - } - else - { -#ifdef SUITESPARSE_CUDA - TEMPLATE2 ( CHOLMOD (gpu_copy_supernode) ) - ( Common, Lx, psx, nscol, nscol2, nsrow, - supernodeUsedGPU, iHostBuff, gpu_p); -#endif - } - - Head [s] = EMPTY ; /* link list for supernode s no longer needed */ - - /* clear the Map (debugging only, to detect changes in pattern of A) */ - DEBUG (for (k = 0 ; k < nsrow ; k++) Map [Ls [psi + k]] = EMPTY) ; - DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, - Common)) ; - - if (repeat_supernode) - { - /* matrix is not positive definite; finished clean-up for supernode - * containing negative diagonal */ - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) - { - CHOLMOD (gpu_end) (Common) ; - } -#endif - return (Common->status >= CHOLMOD_OK) ; - } - } - - /* success; matrix is positive definite */ - L->minor = n ; - -#ifdef SUITESPARSE_CUDA - if ( useGPU ) - { - CHOLMOD (gpu_end) (Common) ; - } -#endif - - return (Common->status >= CHOLMOD_OK) ; - -} - -#undef PATTERN -#undef REAL -#undef COMPLEX -#undef ZOMPLEX diff --git a/CHOLMOD/Supernodal/t_cholmod_super_numeric_worker.c b/CHOLMOD/Supernodal/t_cholmod_super_numeric_worker.c new file mode 100644 index 0000000000..8cec363cb4 --- /dev/null +++ b/CHOLMOD/Supernodal/t_cholmod_super_numeric_worker.c @@ -0,0 +1,1281 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Supernodal/t_cholmod_super_numeric: cholmod_super_numeric template +//------------------------------------------------------------------------------ + +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cholmod_template.h" + +// Template routine for cholmod_super_numeric. All xtypes supported, except +// that a zomplex A and F result in a complex L (there is no supernodal zomplex +// L). The GPU is only used for the double cases, not single. All dtypes are +// supported (A, L and F must have the same dtype). + +//------------------------------------------------------------------------------ +// complex arithmetic +//------------------------------------------------------------------------------ + +#undef L_ENTRY +#undef L_CLEAR +#undef L_ASSIGN +#undef L_MULTADD +#undef L_ASSEMBLE +#undef L_ASSEMBLESUB + +#ifdef REAL + + //-------------------------------------------------------------------------- + // A, F, and L are all real + //-------------------------------------------------------------------------- + + #define L_ENTRY 1 + #define L_CLEAR(Lx,p) Lx [p] = 0 + #define L_ASSIGN(Lx,q, Ax,Az,p) Lx [q] = Ax [p] + #define L_MULTADD(Lx,q, Ax,Az,p, f) Lx [q] += Ax [p] * f [0] + #define L_ASSEMBLE(Lx,q,b) Lx [q] += b [0] + #define L_ASSEMBLESUB(Lx,q,C,p) Lx [q] -= C [p] + +#else + + //-------------------------------------------------------------------------- + // A and F are complex or zomplex, L and C are complex + //-------------------------------------------------------------------------- + + #define L_ENTRY 2 + #define L_CLEAR(Lx,p) Lx [2*(p)] = 0 ; Lx [2*(p)+1] = 0 + #define L_ASSEMBLE(Lx,q,b) Lx [2*(q)] += b [0] ; + #define L_ASSEMBLESUB(Lx,q,C,p) \ + Lx [2*(q) ] -= C [2*(p) ] ; \ + Lx [2*(q)+1] -= C [2*(p)+1] ; + + #ifdef COMPLEX + + //---------------------------------------------------------------------- + // A, F, L, and C are all complex + //---------------------------------------------------------------------- + + #define L_ASSIGN(Lx,q, Ax,Az,p) \ + Lx [2*(q) ] = Ax [2*(p) ] ; \ + Lx [2*(q)+1] = Ax [2*(p)+1] + + #define L_MULTADD(Lx,q, Ax,Az,p, f) \ + Lx [2*(q) ] += Ax [2*(p) ] * f [0] - Ax [2*(p)+1] * f [1] ; \ + Lx [2*(q)+1] += Ax [2*(p)+1] * f [0] + Ax [2*(p) ] * f [1] + + #else + + //---------------------------------------------------------------------- + // A and F are zomplex, L and C is complex + //---------------------------------------------------------------------- + + #define L_ASSIGN(Lx,q, Ax,Az,p) \ + Lx [2*(q) ] = Ax [p] ; \ + Lx [2*(q)+1] = Az [p] ; + + #define L_MULTADD(Lx,q, Ax,Az,p, f) \ + Lx [2*(q) ] += Ax [p] * f [0] - Az [p] * f [1] ; \ + Lx [2*(q)+1] += Az [p] * f [0] + Ax [p] * f [1] + + #endif +#endif + +//------------------------------------------------------------------------------ +// blas_dump +//------------------------------------------------------------------------------ + +#undef BLAS_DUMP_TO_FILE +#undef WHICH + +#ifdef BLAS_DUMP + + #if (defined (DOUBLE) && defined (REAL)) + #define WHICH 0 + #elif (defined (SINGLE) && defined (REAL)) + #define WHICH 1 + #elif (defined (DOUBLE) && !defined (REAL)) + #define WHICH 2 + #elif (defined (SINGLE) && !defined (REAL)) + #define WHICH 3 + #endif + + #define BLAS_DUMP_TO_FILE(kernel,m,n,k,lda,ldb,ldc) \ + { \ + if (Common->blas_dump != NULL) \ + { \ + fprintf (Common->blas_dump, \ + "%2d %d %d %6d %6d %6d %6d %6d %6d %12.4e\n", \ + kernel + WHICH, /* dgemm, sgemm, etc. */ \ + (int) sizeof (SUITESPARSE_BLAS_INT), /* BLAS integer */ \ + (int) sizeof (Int), /* CHOLMOD index */ \ + (int) m, (int) n, (int) k, /* problem size */ \ + (int) lda, (int) ldb, (int) ldc, /* leading dimensions */\ + blas_time) ; /* time taken */ \ + } \ + } + +#else + + #define BLAS_DUMP_TO_FILE(kernel,m,n,k,lda,ldb,ldc) + +#endif + +//------------------------------------------------------------------------------ +// t_cholmod_super_numeric +//------------------------------------------------------------------------------ + +// This function returns FALSE only if integer overflow occurs in the BLAS. +// It returns TRUE otherwise whether or not the matrix is positive definite. + +static int TEMPLATE (cholmod_super_numeric_worker) +( + // input: + cholmod_sparse *A, // matrix to factorize + cholmod_sparse *F, // F = A' or A(:,f)' + Real beta [2], // beta*I is added to diagonal of matrix to factorize + // input/output: + cholmod_factor *L, // factorization + // workspace: + cholmod_dense *Cwork, // size (L->maxcsize)-by-1 + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + Real one [2], zero [2] ; + #ifdef BLAS_TIMER + double tstart, blas_time ; + #endif + Real *Lx, *Ax, *Fx, *Az, *Fz, *C ; + Int *Super, *Head, *Ls, *Lpi, *Lpx, *Map, *SuperMap, *RelativeMap, *Next, + *Lpos, *Fp, *Fi, *Fnz, *Ap, *Ai, *Anz, *Iwork, *Next_save, *Lpos_save, + *Previous; + Int nsuper, n, j, i, k, s, p, pend, k1, k2, nscol, psi, psx, psend, nsrow, + pj, d, kd1, kd2, info, ndcol, ndrow, pdi, pdx, pdend, pdi1, pdi2, pdx1, + ndrow1, ndrow2, px, dancestor, sparent, dnext, nsrow2, ndrow3, pk, pf, + pfend, stype, Apacked, Fpacked, q, imap, repeat_supernode, nscol2, ss, + tail, nscol_new = 0; + info = 0 ; + + ASSERT (L->dtype == A->dtype) ; + + //-------------------------------------------------------------------------- + // declarations for the GPU + //-------------------------------------------------------------------------- + + // these variables are not used if the GPU module is not installed + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + Int ndescendants, mapCreatedOnGpu, supernodeUsedGPU, + idescendant, dlarge, dsmall, skips ; + int iHostBuff, iDevBuff, useGPU, GPUavailable ; + cholmod_gpu_pointers *gpu_p, gpu_pointer_struct ; + gpu_p = &gpu_pointer_struct ; + #endif + + //-------------------------------------------------------------------------- + // guard against integer overflow in the BLAS + //-------------------------------------------------------------------------- + + // If integer overflow occurs in the BLAS, Common->status is set to + // CHOLMOD_TOO_LARGE, and the contents of Lx are undefined. + Common->blas_ok = TRUE ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + nsuper = L->nsuper ; + n = L->n ; + + C = Cwork->x ; // workspace of size L->maxcsize + + one [0] = 1.0 ; // ALPHA for *syrk, *herk, *gemm, and *trsm + one [1] = 0. ; + zero [0] = 0. ; // BETA for *syrk, *herk, and *gemm + zero [1] = 0. ; + + // Iwork must be of size 2n + 5*nsuper, allocated in the caller, + // cholmod_super_numeric. The memory cannot be allocated here because the + // cholmod_super_numeric initializes SuperMap, and cholmod_allocate_work + // does not preserve existing workspace if the space needs to be increase + // in size. + + // allocate integer workspace + Iwork = Common->Iwork ; + SuperMap = Iwork ; // size n + RelativeMap = Iwork + n ; // size n + Next = Iwork + 2*((size_t) n) ; // size nsuper + Lpos = Iwork + 2*((size_t) n) + nsuper ; // size nsuper + Next_save = Iwork + 2*((size_t) n) + 2*((size_t) nsuper) ;// size nsuper + Lpos_save = Iwork + 2*((size_t) n) + 3*((size_t) nsuper) ;// size nsuper + Previous = Iwork + 2*((size_t) n) + 4*((size_t) nsuper) ;// size nsuper + + Map = Common->Flag ; // size n, use Flag as workspace for Map array + Head = Common->Head ; // size n+1, only Head [0..nsuper-1] used + + Ls = L->s ; + Lpi = L->pi ; + Lpx = L->px ; + + Super = L->super ; + + Lx = L->x ; + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + // local copy of useGPU + if ( (Common->useGPU == 1) && L->useGPU) + { + // Initialize the GPU. If not found, don't use it. + useGPU = TEMPLATE2 (CHOLMOD (gpu_init)) + (C, L, Common, nsuper, n, Lpi[nsuper]-Lpi[0], gpu_p) ; + } + else + { + useGPU = 0; + } + // fprintf (stderr, "local useGPU %d\n", useGPU) ; + #endif + + #ifdef BLAS_TIMER + // clear GPU / CPU statistics + Common->CHOLMOD_CPU_GEMM_CALLS = 0 ; + Common->CHOLMOD_CPU_SYRK_CALLS = 0 ; + Common->CHOLMOD_CPU_TRSM_CALLS = 0 ; + Common->CHOLMOD_CPU_POTRF_CALLS = 0 ; + Common->CHOLMOD_GPU_GEMM_CALLS = 0 ; + Common->CHOLMOD_GPU_SYRK_CALLS = 0 ; + Common->CHOLMOD_GPU_TRSM_CALLS = 0 ; + Common->CHOLMOD_GPU_POTRF_CALLS = 0 ; + Common->CHOLMOD_CPU_GEMM_TIME = 0 ; + Common->CHOLMOD_CPU_SYRK_TIME = 0 ; + Common->CHOLMOD_CPU_TRSM_TIME = 0 ; + Common->CHOLMOD_CPU_POTRF_TIME = 0 ; + Common->CHOLMOD_GPU_GEMM_TIME = 0 ; + Common->CHOLMOD_GPU_SYRK_TIME = 0 ; + Common->CHOLMOD_GPU_TRSM_TIME = 0 ; + Common->CHOLMOD_GPU_POTRF_TIME = 0 ; + Common->CHOLMOD_ASSEMBLE_TIME = 0 ; + Common->CHOLMOD_ASSEMBLE_TIME2 = 0 ; + #endif + + stype = A->stype ; + + if (stype != 0) + { + // F not accessed + Fp = NULL ; + Fi = NULL ; + Fx = NULL ; + Fz = NULL ; + Fnz = NULL ; + Fpacked = TRUE ; + } + else + { + ASSERT (F != NULL) ; + ASSERT (L->dtype == F->dtype) ; + Fp = F->p ; + Fi = F->i ; + Fx = F->x ; + Fz = F->z ; + Fnz = F->nz ; + Fpacked = F->packed ; + } + + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + Az = A->z ; + Anz = A->nz ; + Apacked = A->packed ; + + // clear the Map so that changes in the pattern of A can be detected + + #ifdef _OPENMP + int nthreads = cholmod_nthreads ((double) n, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + if ( n > 128 ) schedule (static) + for (i = 0 ; i < n ; i++) + { + Map [i] = EMPTY ; + } + + // If the matrix is not positive definite, the supernode s containing the + // first zero or negative diagonal entry of L is repeated (but factorized + // only up to just before the problematic diagonal entry). The purpose is + // to provide MATLAB with [R,p]=chol(A) ; columns 1 to p-1 of L=R' are + // required, where L(p,p) is the problematic diagonal entry. The + // repeat_supernode flag tells us whether this is the repeated supernode. + // Once supernode s is repeated, the factorization is terminated. + repeat_supernode = FALSE ; + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + // Case of GPU, zero all supernodes at one time for better performance + int nthreads = cholmod_nthreads ((double) L->xsize, Common) ; + TEMPLATE2 (CHOLMOD (gpu_clear_memory))(Lx, L->xsize, nthreads) ; + } + #endif + + //-------------------------------------------------------------------------- + // supernodal numerical factorization + //-------------------------------------------------------------------------- + + for (s = 0 ; s < nsuper ; s++) + { + + //---------------------------------------------------------------------- + // get the size of supernode s + //---------------------------------------------------------------------- + + k1 = Super [s] ; // s contains columns k1 to k2-1 of L + k2 = Super [s+1] ; + nscol = k2 - k1 ; // # of columns in all of s + psi = Lpi [s] ; // pointer to first row of s in Ls + psx = Lpx [s] ; // pointer to first row of s in Lx + psend = Lpi [s+1] ; // pointer just past last row of s in Ls + nsrow = psend - psi ; // # of rows in all of s + + PRINT1 (("====================================================\n" + "S "ID" k1 "ID" k2 "ID" nsrow "ID" nscol "ID" psi "ID" psend " + ""ID" psx "ID"\n", s, k1, k2, nsrow, nscol, psi, psend, psx)) ; + + //---------------------------------------------------------------------- + // zero the supernode s + //---------------------------------------------------------------------- + + ASSERT ((size_t) (psx + nsrow*nscol) <= L->xsize) ; + + pend = psx + nsrow * nscol ; // s is nsrow-by-nscol + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( !useGPU ) + #endif + { + // Case of no GPU, zero individual supernodes + + #ifdef _OPENMP + double work = (double) (pend - psx) * L_ENTRY ; + int nthreads = cholmod_nthreads (work, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + schedule (static) if ( pend - psx > 1024 ) + for (p = psx ; p < pend ; p++) + { + L_CLEAR (Lx,p) ; + } + } + + //---------------------------------------------------------------------- + // construct the scattered Map for supernode s + //---------------------------------------------------------------------- + + // If row i is the kth row in s, then Map [i] = k. Similarly, if + // column j is the kth column in s, then Map [j] = k. + + #ifdef _OPENMP + int nthreads = cholmod_nthreads ((double) nsrow, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + if ( nsrow > 128 ) + for (k = 0 ; k < nsrow ; k++) + { + PRINT1 ((" "ID" map "ID"\n", Ls [psi+k], k)) ; + Map [Ls [psi + k]] = k ; + } + + //---------------------------------------------------------------------- + // when using GPU, reorder supernodes by levels. + // (all supernodes in a level are independent) + //---------------------------------------------------------------------- + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + TEMPLATE2 (CHOLMOD (gpu_reorder_descendants)) + ( Common, Super, &s, Lpi, Lpos, Head, Next, Previous, + &ndescendants, &tail, &mapCreatedOnGpu, gpu_p ) ; + } + #endif + + //---------------------------------------------------------------------- + // copy matrix into supernode s (lower triangular part only) + //---------------------------------------------------------------------- + + pk = psx ; + + #ifdef _OPENMP + double work ; + if (stype != 0) + { + Int pfirst = Ap [k1] ; + Int plast = (Apacked) ? (Ap [k2]) : (pfirst + Anz [k2-1]) ; + work = (double) (plast - pfirst) ; + } + else + { + Int pfirst = Fp [k1] ; + Int plast = (Fpacked) ? (Fp [k2]) : (pfirst + Fnz [k2-1]) ; + work = (double) (plast - pfirst) ; + } + nthreads = cholmod_nthreads (work, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + private ( p, pend, pfend, pf, i, j, imap, q ) if ( k2-k1 > 64 ) + for (k = k1 ; k < k2 ; k++) + { + if (stype != 0) + { + + //-------------------------------------------------------------- + // copy the kth column of A into the supernode + //-------------------------------------------------------------- + + p = Ap [k] ; + pend = (Apacked) ? (Ap [k+1]) : (p + Anz [k]) ; + for ( ; p < pend ; p++) + { + // row i of L is located in row Map [i] of s + i = Ai [p] ; + if (i >= k) + { + // This test is here simply to avoid a segfault. If + // the test is false, the numeric factorization of A + // is undefined. It does not detect all invalid + // entries, only some of them (when debugging is + // enabled, and Map is cleared after each step, then + // all entries not in the pattern of L are detected). + imap = Map [i] ; + if (imap >= 0 && imap < nsrow) + { + // Lx [Map [i] + pk] = Ax [p] + L_ASSIGN (Lx,(imap+(psx+(k-k1)*nsrow)), Ax,Az,p) ; + } + } + } + } + else + { + + //-------------------------------------------------------------- + // copy the kth column of A*F into the supernode + //-------------------------------------------------------------- + + Real fjk[2] ; + pf = Fp [k] ; + pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; + for ( ; pf < pfend ; pf++) + { + j = Fi [pf] ; + + // fjk = Fx [pf] + L_ASSIGN (fjk,0, Fx,Fz,pf) ; + + p = Ap [j] ; + pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + if (i >= k) + { + // See the discussion of imap above. + imap = Map [i] ; + if (imap >= 0 && imap < nsrow) + { + // Lx [Map [i] + pk] += Ax [p] * fjk + L_MULTADD (Lx,(imap+(psx+(k-k1)*nsrow)), + Ax,Az,p, fjk) ; + } + } + } + } + } + } + + // add beta to the diagonal of the supernode, if nonzero + if (beta [0] != 0.0) + { + // note that only the real part of beta is used + pk = psx ; + for (k = k1 ; k < k2 ; k++) + { + // Lx [pk] += beta [0] + L_ASSEMBLE (Lx,pk, beta) ; + pk += nsrow + 1 ; // advance to the next diagonal entry + } + } + + PRINT1 (("Supernode with just A: repeat: "ID"\n", repeat_supernode)) ; + DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L->dtype, + L_ENTRY, Common)) ; + PRINT1 (("\n\n")) ; + + //---------------------------------------------------------------------- + // save/restore the list of supernodes + //---------------------------------------------------------------------- + + if (!repeat_supernode) + { + + // Save the list of pending descendants in case s is not positive + // definite. Also save Lpos for each descendant d, so that we can + // find which part of d is used to update s. + for (d = Head [s] ; d != EMPTY ; d = Next [d]) + { + Lpos_save [d] = Lpos [d] ; + Next_save [d] = Next [d] ; + } + } + else + { + // restore Lpos from prior failed supernode + for (d = Head [s] ; d != EMPTY ; d = Next [d]) + { + Lpos [d] = Lpos_save [d] ; + Next [d] = Next_save [d] ; + } + } + + //---------------------------------------------------------------------- + // update supernode s with each pending descendant d + //---------------------------------------------------------------------- + + #ifndef NDEBUG + for (d = Head [s] ; d != EMPTY ; d = Next [d]) + { + PRINT1 (("\nWill update "ID" with Child: "ID"\n", s, d)) ; + DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L->dtype, + L_ENTRY, Common)) ; + } + PRINT1 (("\nNow factorizing supernode "ID":\n", s)) ; + #endif + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + // initialize the buffer counter + Common->ibuffer = 0; + supernodeUsedGPU = 0; + idescendant = 0; + d = Head[s] ; + dnext = d; + dlarge = Next[d] ; + dsmall = tail; + GPUavailable = 1; + skips = 0; + } + else + #endif + { + // GPU not installed or not used + dnext = Head [s] ; + } + + while + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + ( (!useGPU && (dnext != EMPTY)) + || (useGPU && (idescendant < ndescendants))) + #else + ( dnext != EMPTY ) + #endif + { + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + + // Conditionally select the next descendant supernode to + // assemble. + // + first, select the largest descendant + // + subsequently, if gpu host buffers are available, select + // the largest remaining descendant for assembly on the GPU + // + otherwise select the smallest remaining descendant for + // assembly on the CPU + // + // The objective is to keep the GPU busy assembling the largest + // descendants, and simultaneously keep the CPU busy assembling + // the smallest descendants. + // + // As this is called for every descendent supernode, moving + // this code to t_cholmod_gpu incurs substantial overhead - + // ~20 GF/s on audikw_1 - so it is being left here. + + iHostBuff = + (Common->ibuffer) % CHOLMOD_HOST_SUPERNODE_BUFFERS; + cudaError_t cuErr; + + if ( idescendant > 0 ) { + if ( GPUavailable == -1 || skips > 0) { + d = dsmall; + dsmall = Previous[dsmall] ; + skips--; + } + else { + cuErr = cudaEventQuery + ( Common->updateCBuffersFree[iHostBuff] ) ; + if ( cuErr == cudaSuccess ) { + // buffers are available, so assemble a large + // descendant (anticipating that this will be + // assembled on the GPU) + d = dlarge; + dlarge = Next[dlarge] ; + GPUavailable = 1; + skips = 0; + } + else + { + // buffers are not available, so the GPU is busy, + // so assemble a small descendant (anticipating + // that it will be assembled on the host) + d = dsmall; + dsmall = Previous[dsmall] ; + GPUavailable = 0; + + // if the GPUs are busy, then do this many + // supernodes on the CPU before querying GPUs + // again. + skips = CHOLMOD_GPU_SKIP; + } + } + } + + idescendant++; + + } + else + #endif + { + // GPU not installed or not used + d = dnext ; + } + + //------------------------------------------------------------------ + // get the size of supernode d + //------------------------------------------------------------------ + + kd1 = Super [d] ; // d contains cols kd1 to kd2-1 of L + kd2 = Super [d+1] ; + ndcol = kd2 - kd1 ; // # of columns in all of d + pdi = Lpi [d] ; // pointer to first row of d in Ls + pdx = Lpx [d] ; // pointer to first row of d in Lx + pdend = Lpi [d+1] ; // pointer just past last row of d in Ls + ndrow = pdend - pdi ; // # rows in all of d + + PRINT1 (("Child: ")) ; + DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L->dtype, + L_ENTRY, Common)) ; + + //------------------------------------------------------------------ + // find the range of rows of d that affect rows k1 to k2-1 of s + //------------------------------------------------------------------ + + p = Lpos [d] ; // offset of 1st row of d affecting s + pdi1 = pdi + p ; // ptr to 1st row of d affecting s in Ls + pdx1 = pdx + p ; // ptr to 1st row of d affecting s in Lx + + // there must be at least one row remaining in d to update s + ASSERT (pdi1 < pdend) ; + PRINT1 (("Lpos[d] "ID" pdi1 "ID" Ls[pdi1] "ID"\n", + Lpos[d], pdi1, Ls [pdi1])) ; + ASSERT (Ls [pdi1] >= k1 && Ls [pdi1] < k2) ; + + for (pdi2 = pdi1 ; pdi2 < pdend && Ls [pdi2] < k2 ; pdi2++) ; + ndrow1 = pdi2 - pdi1 ; // # rows in first part of d + ndrow2 = pdend - pdi1 ; // # rows in remaining d + + // rows Ls [pdi1 ... pdi2-1] are in the range k1 to k2-1. Since d + // affects s, this set cannot be empty. + ASSERT (pdi1 < pdi2 && pdi2 <= pdend) ; + PRINT1 (("ndrow1 "ID" ndrow2 "ID"\n", ndrow1, ndrow2)) ; + DEBUG (for (p = pdi1 ; p < pdi2 ; p++) + PRINT1 (("Ls["ID"] "ID"\n", p, Ls[p]))) ; + + //------------------------------------------------------------------ + // construct the update matrix C for this supernode d + //------------------------------------------------------------------ + + // C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except + // that k1:n-1 refers to all of the rows in L, but many of the + // rows are all zero. Supernode d holds columns kd1 to kd2-1 of L. + // Nonzero rows in the range k1:k2-1 are in the list + // Ls [pdi1 ... pdi2-1], of size ndrow1. Nonzero rows in the range + // k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2. Let + // L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let + // L2 = L (Ls [pdi2 ... pdend], kd1:kd2-1). C is ndrow2-by-ndrow1. + // Let C1 be the first ndrow1 rows of C and let C2 be the last + // ndrow2-ndrow1 rows of C. Only the lower triangular part of C1 + // needs to be computed since C1 is symmetric. + + // maxcsize is the largest size of C for all pairs (d,s) + ASSERT (ndrow2 * ndrow1 <= ((Int) L->maxcsize)) ; + + // compute leading ndrow1-by-ndrow1 lower triangular block of C, + // C1 = L1*L1' + + ndrow3 = ndrow2 - ndrow1 ; // number of rows of C2 + ASSERT (ndrow3 >= 0) ; + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + // set up GPU to assemble new supernode + if ( GPUavailable == 1) { + if ( ndrow2 * L_ENTRY >= CHOLMOD_ND_ROW_LIMIT && + ndcol * L_ENTRY >= CHOLMOD_ND_COL_LIMIT ) { + if ( ! mapCreatedOnGpu ) { + TEMPLATE2 ( CHOLMOD (gpu_initialize_supernode)) + ( Common, nscol, nsrow, psi, gpu_p ) ; + mapCreatedOnGpu = 1; + } + } + else { + // we've reached the limit of GPU-eligible descendants + // flag to stop stop performing cudaEventQueries + GPUavailable = -1; + } + } + } + #endif + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( !useGPU + || GPUavailable!=1 + || !TEMPLATE2 (CHOLMOD (gpu_updateC)) (ndrow1, ndrow2, ndrow, + ndcol, nsrow, pdx1, pdi1, Lx, C, Common, gpu_p)) + #endif + { + // GPU not installed, or not used + + #ifdef BLAS_TIMER + Common->CHOLMOD_CPU_SYRK_CALLS++ ; + tstart = SuiteSparse_time () ; + #endif + + #if (defined (DOUBLE) && defined (REAL)) + SUITESPARSE_BLAS_dsyrk ("L", "N", + ndrow1, ndcol, // N, K: L1 is ndrow1-by-ndcol + one, // ALPHA: 1 + Lx + L_ENTRY*pdx1, ndrow, // A, LDA: L1, ndrow + zero, // BETA: 0 + C, ndrow2, // C, LDC: C1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + SUITESPARSE_BLAS_ssyrk ("L", "N", + ndrow1, ndcol, // N, K: L1 is ndrow1-by-ndcol + one, // ALPHA: 1 + Lx + L_ENTRY*pdx1, ndrow, // A, LDA: L1, ndrow + zero, // BETA: 0 + C, ndrow2, // C, LDC: C1 + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + SUITESPARSE_BLAS_zherk ("L", "N", + ndrow1, ndcol, // N, K: L1 is ndrow1-by-ndcol + one, // ALPHA: 1 + Lx + L_ENTRY*pdx1, ndrow, // A, LDA: L1, ndrow + zero, // BETA: 0 + C, ndrow2, // C, LDC: C1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + SUITESPARSE_BLAS_cherk ("L", "N", + ndrow1, ndcol, // N, K: L1 is ndrow1-by-ndcol + one, // ALPHA: 1 + Lx + L_ENTRY*pdx1, ndrow, // A, LDA: L1, ndrow + zero, // BETA: 0 + C, ndrow2, // C, LDC: C1 + Common->blas_ok) ; + #endif + + #ifdef BLAS_TIMER + blas_time = SuiteSparse_time () - tstart ; + Common->CHOLMOD_CPU_SYRK_TIME += blas_time ; + BLAS_DUMP_TO_FILE (0, // dsyrk ("L", "N", ...) + ndrow1, ndcol, 0, // N, K, 0 + ndrow, ndrow2, 0) ; // LDA, LDC, 0 + #endif + + // compute remaining (ndrow2-ndrow1)-by-ndrow1 block of C, + // C2 = L2*L1' + if (ndrow3 > 0) + { + + #ifdef BLAS_TIMER + Common->CHOLMOD_CPU_GEMM_CALLS++ ; + tstart = SuiteSparse_time () ; + #endif + + #if (defined (DOUBLE) && defined (REAL)) + SUITESPARSE_BLAS_dgemm ("N", "C", + ndrow3, ndrow1, ndcol, // M, N, K + one, // ALPHA: 1 + Lx + L_ENTRY*(pdx1 + ndrow1), // A, LDA: L2 + ndrow, // ndrow + Lx + L_ENTRY*pdx1, // B, LDB: L1 + ndrow, // ndrow + zero, // BETA: 0 + C + L_ENTRY*ndrow1, // C, LDC: C2 + ndrow2, + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + SUITESPARSE_BLAS_sgemm ("N", "C", + ndrow3, ndrow1, ndcol, // M, N, K + one, // ALPHA: 1 + Lx + L_ENTRY*(pdx1 + ndrow1), // A, LDA: L2 + ndrow, // ndrow + Lx + L_ENTRY*pdx1, // B, LDB: L1 + ndrow, // ndrow + zero, // BETA: 0 + C + L_ENTRY*ndrow1, // C, LDC: C2 + ndrow2, + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + SUITESPARSE_BLAS_zgemm ("N", "C", + ndrow3, ndrow1, ndcol, // M, N, K + one, // ALPHA: 1 + Lx + L_ENTRY*(pdx1 + ndrow1), // A, LDA: L2 + ndrow, // ndrow + Lx + L_ENTRY*pdx1, // B, LDB: L1, ndrow + ndrow, + zero, // BETA: 0 + C + L_ENTRY*ndrow1, // C, LDC: C2 + ndrow2, + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + SUITESPARSE_BLAS_cgemm ("N", "C", + ndrow3, ndrow1, ndcol, // M, N, K + one, // ALPHA: 1 + Lx + L_ENTRY*(pdx1 + ndrow1), // A, LDA: L2 + ndrow, // ndrow + Lx + L_ENTRY*pdx1, // B, LDB: L1, ndrow + ndrow, + zero, // BETA: 0 + C + L_ENTRY*ndrow1, // C, LDC: C2 + ndrow2, + Common->blas_ok) ; + #endif + + #ifdef BLAS_TIMER + blas_time = SuiteSparse_time () - tstart ; + Common->CHOLMOD_CPU_GEMM_TIME += blas_time ; + BLAS_DUMP_TO_FILE (4, // dgemm ("N", "C", ...) + ndrow3, ndrow1, ndcol, // M, N, K + ndrow, ndrow, ndrow2) ; // LDA, LDB, LDC + #endif + } + + //-------------------------------------------------------------- + // construct relative map to assemble d into s + //-------------------------------------------------------------- + + DEBUG (CHOLMOD(dump_real) ("C", C, L->dtype, + ndrow2, ndrow1, TRUE, L_ENTRY, Common)) ; + + #ifdef _OPENMP + int nthreads = cholmod_nthreads ((double) ndrow2, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + if ( ndrow2 > 64 ) + for (i = 0 ; i < ndrow2 ; i++) + { + RelativeMap [i] = Map [Ls [pdi1 + i]] ; + ASSERT (RelativeMap [i] >= 0 && RelativeMap [i] < nsrow) ; + } + + //-------------------------------------------------------------- + // assemble C into supernode s using the relative map + //-------------------------------------------------------------- + + #ifdef _OPENMP + double work = (double) ndcol * (double) ndrow2 * L_ENTRY ; + nthreads = cholmod_nthreads (work, Common) ; + #endif + + #pragma omp parallel for num_threads(nthreads) \ + private ( j, i, px, q ) if (ndrow1 > 64 ) + for (j = 0 ; j < ndrow1 ; j++) // cols k1:k2-1 + { + ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ; + ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ; + px = psx + RelativeMap [j] * nsrow ; + for (i = j ; i < ndrow2 ; i++) // rows k1:n-1 + { + ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ; + ASSERT (RelativeMap [i] >= j && RelativeMap[i] < nsrow); + // Lx [px + RelativeMap [i]] -= C [i + pj] + q = px + RelativeMap [i] ; + L_ASSEMBLESUB (Lx,q, C, i+ndrow2*j) ; + } + } + + } + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + else + { + supernodeUsedGPU = 1; // GPU was used for this supernode + Common->ibuffer++; // gpu_updateC is asynchronous, so use + // the next host buffer for the next + // supernode + Common->ibuffer = Common->ibuffer% + (CHOLMOD_HOST_SUPERNODE_BUFFERS*CHOLMOD_DEVICE_STREAMS) ; + } + #endif + + //------------------------------------------------------------------ + // prepare this supernode d for its next ancestor + //------------------------------------------------------------------ + + dnext = Next [d] ; + + if (!repeat_supernode) + { + // If node s is being repeated, Head [dancestor] has already + // been cleared (set to EMPTY). It must remain EMPTY. The + // dancestor will not be factorized since the factorization + // terminates at node s. + Lpos [d] = pdi2 - pdi ; + if (Lpos [d] < ndrow) + { + dancestor = SuperMap [Ls [pdi2]] ; + ASSERT (dancestor > s && dancestor < nsuper) ; + // place d in the link list of its next ancestor + Next [d] = Head [dancestor] ; + Head [dancestor] = d ; + } + } + + } // end of descendant supernode loop + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) { + iHostBuff = (Common->ibuffer)%CHOLMOD_HOST_SUPERNODE_BUFFERS; + iDevBuff = (Common->ibuffer)%CHOLMOD_DEVICE_STREAMS; + + // combine updates assembled on the GPU with updates + // assembled on the CPU + TEMPLATE2 ( CHOLMOD (gpu_final_assembly )) + ( Common, Lx, psx, nscol, nsrow, supernodeUsedGPU, + &iHostBuff, &iDevBuff, gpu_p ) ; + } + #endif + + PRINT1 (("\nSupernode with contributions A: repeat: "ID"\n", + repeat_supernode)) ; + DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L->dtype, + L_ENTRY, Common)) ; + PRINT1 (("\n\n")) ; + + //---------------------------------------------------------------------- + // factorize diagonal block of supernode s in LL' + //---------------------------------------------------------------------- + + // The current supernode s is ready to factorize. It has been updated + // by all descendant supernodes. Let S = the current supernode, which + // holds rows k1:n-1 and columns k1:k2-1 of the updated matrix. It + // splits into two parts: the square diagonal block S1, and the + // rectangular part S2. Here, S1 is factorized into L1*L1' and + // overwritten by L1. + // + // If supernode s is being repeated, only factorize it up to but not + // including the column containing the problematic entry. + + nscol2 = (repeat_supernode) ? (nscol_new) : (nscol) ; + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( !useGPU + || !supernodeUsedGPU + || !TEMPLATE2 (CHOLMOD (gpu_lower_potrf))(nscol2, nsrow, psx, Lx, + &info, Common, gpu_p)) + #endif + { + // Note that the GPU will not be used for the triangular solve + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + supernodeUsedGPU = 0; + #endif + #ifdef BLAS_TIMER + Common->CHOLMOD_CPU_POTRF_CALLS++ ; + tstart = SuiteSparse_time () ; + #endif + + #if (defined (DOUBLE) && defined (REAL)) + SUITESPARSE_LAPACK_dpotrf ("L", + nscol2, // N: nscol2 + Lx + L_ENTRY*psx, nsrow, // A, LDA: S1, nsrow + info, // INFO + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + SUITESPARSE_LAPACK_spotrf ("L", + nscol2, // N: nscol2 + Lx + L_ENTRY*psx, nsrow, // A, LDA: S1, nsrow + info, // INFO + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + SUITESPARSE_LAPACK_zpotrf ("L", + nscol2, // N: nscol2 + Lx + L_ENTRY*psx, nsrow, // A, LDA: S1, nsrow + info, // INFO + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + SUITESPARSE_LAPACK_cpotrf ("L", + nscol2, // N: nscol2 + Lx + L_ENTRY*psx, nsrow, // A, LDA: S1, nsrow + info, // INFO + Common->blas_ok) ; + #endif + + #ifdef BLAS_TIMER + blas_time = SuiteSparse_time () - tstart ; + Common->CHOLMOD_CPU_POTRF_TIME += blas_time ; + BLAS_DUMP_TO_FILE (8, // dpotrf ("L", ... ) + nscol2, 0, 0, // N, 0, 0 + nsrow, 0, 0) ; // LDA, 0, 0 + #endif + } + + //---------------------------------------------------------------------- + // check if the matrix is not positive definite + //---------------------------------------------------------------------- + + if (repeat_supernode) + { + // the leading part has been refactorized; it must have succeeded + info = 0 ; + + // zero out the rest of this supernode + p = psx + nsrow * nscol_new ; + pend = psx + nsrow * nscol ; // s is nsrow-by-nscol + for ( ; p < pend ; p++) + { + // Lx [p] = 0 + L_CLEAR (Lx,p) ; + } + } + + // info is set to one in SUITESPARSE_LAPACK_*potrf if blas_ok is FALSE. + // It is set to zero in dpotrf/zpotrf if the factorization was + // successful. + CHECK_FOR_BLAS_INTEGER_OVERFLOW ; + + if (info != 0) + { + // Matrix is not positive definite. dpotrf/zpotrf do NOT report an + // error if the diagonal of L has NaN's, only if it has a zero. + if (Common->status == CHOLMOD_OK) + { + ERROR (CHOLMOD_NOT_POSDEF, "matrix not positive definite") ; + } + + // L->minor is the column of L that contains a zero or negative + // diagonal term. + L->minor = k1 + info - 1 ; + + // clear the link lists of all subsequent supernodes + for (ss = s+1 ; ss < nsuper ; ss++) + { + Head [ss] = EMPTY ; + } + + // zero this supernode, and all remaining supernodes + pend = L->xsize ; + for (p = psx ; p < pend ; p++) + { + // Lx [p] = 0 + L_CLEAR (Lx,p) ; + } + + // If L is indefinite, it still contains useful information. + // Supernodes 0 to s-1 are valid, similar to MATLAB [R,p]=chol(A), + // where the 1-based p is identical to the 0-based L->minor. Since + // L->minor is in the current supernode s, it and any columns to the + // left of it in supernode s are also all zero. This differs from + // [R,p]=chol(A), which contains nonzero rows 1 to p-1. Fix this + // by setting repeat_supernode to TRUE, and repeating supernode s. + // + // If Common->quick_return_if_not_posdef is true, then the entire + // supernode s is not factorized; it is left as all zero. + + if (info == 1 || Common->quick_return_if_not_posdef) + { + // If the first column of supernode s contains a zero or + // negative diagonal entry, then it is already properly set to + // zero. Also, info will be 1 if integer overflow occured in + // the BLAS. + Head [s] = EMPTY ; + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) { + CHOLMOD (gpu_end) (Common) ; + } + #endif + return (Common->status >= CHOLMOD_OK) ; + } + else + { + // Repeat supernode s, but only factorize it up to but not + // including the column containing the problematic diagonal + // entry. + repeat_supernode = TRUE ; + s-- ; + nscol_new = info - 1 ; + continue ; + } + } + + //---------------------------------------------------------------------- + // compute the subdiagonal block and prepare supernode for its parent + //---------------------------------------------------------------------- + + nsrow2 = nsrow - nscol2 ; + if (nsrow2 > 0) + { + // The current supernode is columns k1 to k2-1 of L. Let L1 be the + // diagonal block (factorized by dpotrf/zpotrf above; rows/cols + // k1:k2-1), and L2 be rows k2:n-1 and columns k1:k2-1 of L. The + // triangular system to solve is L2*L1' = S2, where S2 is + // overwritten with L2. More precisely, L2 = S2 / L1' in MATLAB + // notation. + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( !useGPU + || !supernodeUsedGPU + || !TEMPLATE2 (CHOLMOD(gpu_triangular_solve)) + (nsrow2, nscol2, nsrow, psx, Lx, Common, gpu_p)) + #endif + { + #ifdef BLAS_TIMER + Common->CHOLMOD_CPU_TRSM_CALLS++ ; + tstart = SuiteSparse_time () ; + #endif + + #if (defined (DOUBLE) && defined (REAL)) + SUITESPARSE_BLAS_dtrsm ("R", "L", "C", "N", + nsrow2, nscol2, // M, N + one, // ALPHA: 1 + Lx + L_ENTRY*psx, nsrow, // A, LDA: L1, nsrow + Lx + L_ENTRY*(psx + nscol2), // B, LDB, L2, nsrow + nsrow, + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + SUITESPARSE_BLAS_strsm ("R", "L", "C", "N", + nsrow2, nscol2, // M, N + one, // ALPHA: 1 + Lx + L_ENTRY*psx, nsrow, // A, LDA: L1, nsrow + Lx + L_ENTRY*(psx + nscol2), // B, LDB, L2, nsrow + nsrow, + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + SUITESPARSE_BLAS_ztrsm ("R", "L", "C", "N", + nsrow2, nscol2, // M, N + one, // ALPHA: 1 + Lx + L_ENTRY*psx, nsrow, // A, LDA: L1, nsrow + Lx + L_ENTRY*(psx + nscol2), // B, LDB, L2, nsrow + nsrow, + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + SUITESPARSE_BLAS_ctrsm ("R", "L", "C", "N", + nsrow2, nscol2, // M, N + one, // ALPHA: 1 + Lx + L_ENTRY*psx, nsrow, // A, LDA: L1, nsrow + Lx + L_ENTRY*(psx + nscol2), // B, LDB, L2, nsrow + nsrow, + Common->blas_ok) ; + #endif + + #ifdef BLAS_TIMER + blas_time = SuiteSparse_time () - tstart ; + Common->CHOLMOD_CPU_TRSM_TIME += blas_time ; + BLAS_DUMP_TO_FILE (12, // dtrsm ("R", "L", "C", "N"...) + nsrow2, nscol2, 0, // M, N + nsrow, nsrow, 0) ; // LDA, LDB + #endif + } + + CHECK_FOR_BLAS_INTEGER_OVERFLOW ; + + if (!repeat_supernode) + { + // Lpos [s] is offset of first row of s affecting its parent + Lpos [s] = nscol ; + sparent = SuperMap [Ls [psi + nscol]] ; + ASSERT (sparent != EMPTY) ; + ASSERT (Ls [psi + nscol] >= Super [sparent]) ; + ASSERT (Ls [psi + nscol] < Super [sparent+1]) ; + ASSERT (SuperMap [Ls [psi + nscol]] == sparent) ; + ASSERT (sparent > s && sparent < nsuper) ; + // place s in link list of its parent + Next [s] = Head [sparent] ; + Head [sparent] = s ; + } + } + else + { + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + TEMPLATE2 ( CHOLMOD (gpu_copy_supernode) ) + ( Common, Lx, psx, nscol, nscol2, nsrow, + supernodeUsedGPU, iHostBuff, gpu_p) ; + #endif + } + + Head [s] = EMPTY ; // link list for supernode s no longer needed + + // clear the Map (debugging only, to detect changes in pattern of A) + DEBUG (for (k = 0 ; k < nsrow ; k++) Map [Ls [psi + k]] = EMPTY) ; + DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L->dtype, + L_ENTRY, Common)) ; + + if (repeat_supernode) + { + // matrix is not positive definite; finished clean-up for supernode + // containing negative diagonal + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + CHOLMOD (gpu_end) (Common) ; + } + #endif + return (Common->status >= CHOLMOD_OK) ; + } + } + + // success; matrix is positive definite + L->minor = n ; + + #if (defined (SUITESPARSE_CUDA) && defined (DOUBLE)) + if ( useGPU ) + { + CHOLMOD (gpu_end) (Common) ; + } + #endif + + return (Common->status >= CHOLMOD_OK) ; +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Supernodal/t_cholmod_super_solve.c b/CHOLMOD/Supernodal/t_cholmod_super_solve.c deleted file mode 100644 index 333ef2045b..0000000000 --- a/CHOLMOD/Supernodal/t_cholmod_super_solve.c +++ /dev/null @@ -1,433 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Supernodal/t_cholmod_super_solve: template for cholmod_super_solve -//------------------------------------------------------------------------------ - -// CHOLMOD/Supernodal Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Template routine for cholmod_super_solve. Supports real or complex L. */ - -#include "cholmod_template.h" - -static void TEMPLATE (cholmod_super_lsolve) -( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the forward solve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to Lx=b on output */ - /* ---- workspace ---- */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ - cholmod_common *Common -) -{ - double *Lx, *Xx, *Ex ; - double minus_one [2], one [2] ; - Int *Lpi, *Lpx, *Ls, *Super ; - Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, - nsrow2, n, ps2, j, i, d, nrhs ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - nrhs = X->ncol ; - Ex = E->x ; - Xx = X->x ; - n = L->n ; - d = X->d ; - - nsuper = L->nsuper ; - Lpi = L->pi ; - Lpx = L->px ; - Ls = L->s ; - Super = L->super ; - Lx = L->x ; - minus_one [0] = -1.0 ; - minus_one [1] = 0 ; - one [0] = 1.0 ; - one [1] = 0 ; - - /* ---------------------------------------------------------------------- */ - /* solve Lx=b */ - /* ---------------------------------------------------------------------- */ - - if (nrhs == 1) - { - - for (s = 0 ; s < nsuper ; s++) - { - k1 = Super [s] ; - k2 = Super [s+1] ; - psi = Lpi [s] ; - psend = Lpi [s+1] ; - psx = Lpx [s] ; - nsrow = psend - psi ; - nscol = k2 - k1 ; - nsrow2 = nsrow - nscol ; - ps2 = psi + nscol ; - ASSERT ((size_t) nsrow2 <= L->maxesize) ; - - /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal. - * L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of - * nsrow. x1 is nscol-by-nsrow, with leading dimension n. - * E is nsrow2-by-1, with leading dimension nsrow2. - */ - - /* gather X into E */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */ - ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; - } - -#ifdef REAL - - /* solve L1*x1 (that is, x1 = L1\x1) */ - SUITESPARSE_BLAS_dtrsv ("L", "N", "N", - nscol, /* N: L1 is nscol-by-nscol */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - Common->blas_ok) ; - - /* E = E - L2*x1 */ - SUITESPARSE_BLAS_dgemv ("N", - nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - one, /* BETA: 1 */ - Ex, 1, /* Y, INCY: E */ - Common->blas_ok) ; - -#else - - /* solve L1*x1 (that is, x1 = L1\x1) */ - SUITESPARSE_BLAS_ztrsv ("L", "N", "N", - nscol, /* N: L1 is nscol-by-nscol */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - Common->blas_ok) ; - - /* E = E - L2*x1 */ - SUITESPARSE_BLAS_zgemv ("N", - nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - one, /* BETA: 1 */ - Ex, 1, /* Y, INCY: E */ - Common->blas_ok) ; - -#endif - - /* scatter E back into X */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - /* Xx [Ls [ps2 + ii]] = Ex [ii] ; */ - ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ; - } - } - } - else - { - - for (s = 0 ; s < nsuper ; s++) - { - k1 = Super [s] ; - k2 = Super [s+1] ; - psi = Lpi [s] ; - psend = Lpi [s+1] ; - psx = Lpx [s] ; - nsrow = psend - psi ; - nscol = k2 - k1 ; - nsrow2 = nsrow - nscol ; - ps2 = psi + nscol ; - ASSERT ((size_t) nsrow2 <= L->maxesize) ; - - /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */ - - /* gather X into E */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - i = Ls [ps2 + ii] ; - for (j = 0 ; j < nrhs ; j++) - { - /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */ - ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; - } - } - -#ifdef REAL - - /* solve L1*x1 */ - SUITESPARSE_BLAS_dtrsm ("L", "L", "N", "N", - nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ - one, /* ALPHA: 1 */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, d, /* B, LDB: x1 */ - Common->blas_ok) ; - - /* E = E - L2*x1 */ - if (nsrow2 > 0) - { - SUITESPARSE_BLAS_dgemm ("N", "N", - nsrow2, nrhs, nscol, /* M, N, K */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Xx + ENTRY_SIZE*k1, d, /* B, LDB: X1 */ - one, /* BETA: 1 */ - Ex, nsrow2, /* C, LDC: E */ - Common->blas_ok) ; - } - -#else - - /* solve L1*x1 */ - SUITESPARSE_BLAS_ztrsm ("L", "L", "N", "N", - nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ - one, /* ALPHA: 1 */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, d, /* B, LDB: x1 */ - Common->blas_ok) ; - - /* E = E - L2*x1 */ - if (nsrow2 > 0) - { - SUITESPARSE_BLAS_zgemm ("N", "N", - nsrow2, nrhs, nscol, /* M, N, K */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Xx + ENTRY_SIZE*k1, d, /* B, LDB: X1 */ - one, /* BETA: 1 */ - Ex, nsrow2, /* C, LDC: E */ - Common->blas_ok) ; - } - -#endif - - /* scatter E back into X */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - i = Ls [ps2 + ii] ; - for (j = 0 ; j < nrhs ; j++) - { - /* Xx [i + j*d] = Ex [ii + j*nsrow2] ; */ - ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ; - } - } - } - } -} - - -static void TEMPLATE (cholmod_super_ltsolve) -( - /* ---- input ---- */ - cholmod_factor *L, /* factor to use for the forward solve */ - /* ---- output ---- */ - cholmod_dense *X, /* b on input, solution to Lx=b on output */ - /* ---- workspace ---- */ - cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ - /* --------------- */ - cholmod_common *Common -) -{ - double *Lx, *Xx, *Ex ; - double minus_one [2], one [2] ; - Int *Lpi, *Lpx, *Ls, *Super ; - Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, - nsrow2, n, ps2, j, i, d, nrhs ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - nrhs = X->ncol ; - Ex = E->x ; - Xx = X->x ; - n = L->n ; - d = X->d ; - - nsuper = L->nsuper ; - Lpi = L->pi ; - Lpx = L->px ; - Ls = L->s ; - Super = L->super ; - Lx = L->x ; - minus_one [0] = -1.0 ; - minus_one [1] = 0 ; - one [0] = 1.0 ; - one [1] = 0 ; - - /* ---------------------------------------------------------------------- */ - /* solve L'x=b */ - /* ---------------------------------------------------------------------- */ - - if (nrhs == 1) - { - - for (s = nsuper-1 ; s >= 0 ; s--) - { - k1 = Super [s] ; - k2 = Super [s+1] ; - psi = Lpi [s] ; - psend = Lpi [s+1] ; - psx = Lpx [s] ; - nsrow = psend - psi ; - nscol = k2 - k1 ; - nsrow2 = nsrow - nscol ; - ps2 = psi + nscol ; - ASSERT ((size_t) nsrow2 <= L->maxesize) ; - - /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal. - * L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of - * nsrow. x1 is nscol-by-nsrow, with leading dimension n. - * E is nsrow2-by-1, with leading dimension nsrow2. - */ - - /* gather X into E */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */ - ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; - } - -#ifdef REAL - - /* x1 = x1 - L2'*E */ - SUITESPARSE_BLAS_dgemv ("C", - nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Ex, 1, /* X, INCX: Ex */ - one, /* BETA: 1 */ - Xx + ENTRY_SIZE*k1, 1, /* Y, INCY: x1 */ - Common->blas_ok) ; - - /* solve L1'*x1 */ - SUITESPARSE_BLAS_dtrsv ("L", "C", "N", - nscol, /* N: L1 is nscol-by-nscol */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - Common->blas_ok) ; - -#else - - /* x1 = x1 - L2'*E */ - SUITESPARSE_BLAS_zgemv ("C", - nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Ex, 1, /* X, INCX: Ex */ - one, /* BETA: 1 */ - Xx + ENTRY_SIZE*k1, 1, /* Y, INCY: x1 */ - Common->blas_ok) ; - - /* solve L1'*x1 */ - SUITESPARSE_BLAS_ztrsv ("L", "C", "N", - nscol, /* N: L1 is nscol-by-nscol */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ - Common->blas_ok) ; - -#endif - - } - } - else - { - - for (s = nsuper-1 ; s >= 0 ; s--) - { - k1 = Super [s] ; - k2 = Super [s+1] ; - psi = Lpi [s] ; - psend = Lpi [s+1] ; - psx = Lpx [s] ; - nsrow = psend - psi ; - nscol = k2 - k1 ; - nsrow2 = nsrow - nscol ; - ps2 = psi + nscol ; - ASSERT ((size_t) nsrow2 <= L->maxesize) ; - - /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */ - - /* gather X into E */ - for (ii = 0 ; ii < nsrow2 ; ii++) - { - i = Ls [ps2 + ii] ; - for (j = 0 ; j < nrhs ; j++) - { - /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */ - ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; - } - } - -#ifdef REAL - - /* x1 = x1 - L2'*E */ - if (nsrow2 > 0) - { - SUITESPARSE_BLAS_dgemm ("C", "N", - nscol, nrhs, nsrow2, /* M, N, K */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Ex, nsrow2, /* B, LDB: E */ - one, /* BETA: 1 */ - Xx + ENTRY_SIZE*k1, d, /* C, LDC: x1 */ - Common->blas_ok) ; - } - - /* solve L1'*x1 */ - SUITESPARSE_BLAS_dtrsm ("L", "L", "C", "N", - nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ - one, /* ALPHA: 1 */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, d, /* B, LDB: x1 */ - Common->blas_ok) ; - -#else - - /* x1 = x1 - L2'*E */ - if (nsrow2 > 0) - { - SUITESPARSE_BLAS_zgemm ("C", "N", - nscol, nrhs, nsrow2, /* M, N, K */ - minus_one, /* ALPHA: -1 */ - Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ - nsrow, - Ex, nsrow2, /* B, LDB: E */ - one, /* BETA: 1 */ - Xx + ENTRY_SIZE*k1, d, /* C, LDC: x1 */ - Common->blas_ok) ; - } - - /* solve L1'*x1 */ - SUITESPARSE_BLAS_ztrsm ("L", "L", "C", "N", - nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ - one, /* ALPHA: 1 */ - Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ - Xx + ENTRY_SIZE*k1, d, /* B, LDB: x1 */ - Common->blas_ok) ; - -#endif - - } - } -} - -#undef PATTERN -#undef REAL -#undef COMPLEX -#undef ZOMPLEX diff --git a/CHOLMOD/Supernodal/t_cholmod_super_solve_worker.c b/CHOLMOD/Supernodal/t_cholmod_super_solve_worker.c new file mode 100644 index 0000000000..b9340c543f --- /dev/null +++ b/CHOLMOD/Supernodal/t_cholmod_super_solve_worker.c @@ -0,0 +1,586 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Supernodal/t_cholmod_super_solve: template for cholmod_super_solve +//------------------------------------------------------------------------------ + +// CHOLMOD/Supernodal Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Template routine for cholmod_super_solve. Supports real or complex L, +// not pattern, nor complex. All dtypes are supported. + +#include "cholmod_template.h" + +//------------------------------------------------------------------------------ +// t_cholmod_super_lsolve_worker: solve x = L\b +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_super_lsolve_worker) +( + // input: + cholmod_factor *L, // factor to use for the forward solve + // input/output: + cholmod_dense *X, // b on input, solution to Lx=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Lx, *Xx, *Ex ; + Real minus_one [2], one [2] ; + Int *Lpi, *Lpx, *Ls, *Super ; + Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, + nsrow2, n, ps2, j, i, d, nrhs ; + + nrhs = X->ncol ; + Ex = E->x ; + Xx = X->x ; + n = L->n ; + d = X->d ; + + nsuper = L->nsuper ; + Lpi = L->pi ; + Lpx = L->px ; + Ls = L->s ; + Super = L->super ; + Lx = L->x ; + minus_one [0] = -1.0 ; + minus_one [1] = 0 ; + one [0] = 1.0 ; + one [1] = 0 ; + + //-------------------------------------------------------------------------- + // solve Lx=b + //-------------------------------------------------------------------------- + + if (nrhs == 1) + { + + for (s = 0 ; s < nsuper ; s++) + { + k1 = Super [s] ; + k2 = Super [s+1] ; + psi = Lpi [s] ; + psend = Lpi [s+1] ; + psx = Lpx [s] ; + nsrow = psend - psi ; + nscol = k2 - k1 ; + nsrow2 = nsrow - nscol ; + ps2 = psi + nscol ; + ASSERT ((size_t) nsrow2 <= L->maxesize) ; + + // L1 is nscol-by-nscol, lower triangular with non-unit diagonal. + // L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of + // nsrow. x1 is nscol-by-nsrow, with leading dimension n. + // E is nsrow2-by-1, with leading dimension nsrow2. + + // gather X into E + for (ii = 0 ; ii < nsrow2 ; ii++) + { + // Ex [ii] = Xx [Ls [ps2 + ii]] + ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; + } + + #if (defined (DOUBLE) && defined (REAL)) + // solve L1*x1 (that is, x1 = L1\x1) + SUITESPARSE_BLAS_dtrsv ("L", "N", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + // E = E - L2*x1 + SUITESPARSE_BLAS_dgemv ("N", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + one, // BETA: 1 + Ex, 1, // Y, INCY: E + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + // solve L1*x1 (that is, x1 = L1\x1) + SUITESPARSE_BLAS_strsv ("L", "N", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + // E = E - L2*x1 + SUITESPARSE_BLAS_sgemv ("N", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + one, // BETA: 1 + Ex, 1, // Y, INCY: E + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + // solve L1*x1 (that is, x1 = L1\x1) + SUITESPARSE_BLAS_ztrsv ("L", "N", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + // E = E - L2*x1 + SUITESPARSE_BLAS_zgemv ("N", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + one, // BETA: 1 + Ex, 1, // Y, INCY: E + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + // solve L1*x1 (that is, x1 = L1\x1) + SUITESPARSE_BLAS_ctrsv ("L", "N", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + // E = E - L2*x1 + SUITESPARSE_BLAS_cgemv ("N", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + one, // BETA: 1 + Ex, 1, // Y, INCY: E + Common->blas_ok) ; + #endif + + // scatter E back into X + for (ii = 0 ; ii < nsrow2 ; ii++) + { + // Xx [Ls [ps2 + ii]] = Ex [ii] + ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ; + } + } + + } + else + { + + for (s = 0 ; s < nsuper ; s++) + { + k1 = Super [s] ; + k2 = Super [s+1] ; + psi = Lpi [s] ; + psend = Lpi [s+1] ; + psx = Lpx [s] ; + nsrow = psend - psi ; + nscol = k2 - k1 ; + nsrow2 = nsrow - nscol ; + ps2 = psi + nscol ; + ASSERT ((size_t) nsrow2 <= L->maxesize) ; + + // E is nsrow2-by-nrhs, with leading dimension nsrow2. + + // gather X into E + for (ii = 0 ; ii < nsrow2 ; ii++) + { + i = Ls [ps2 + ii] ; + for (j = 0 ; j < nrhs ; j++) + { + // Ex [ii + j*nsrow2] = Xx [i + j*d] + ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; + } + } + + #if (defined (DOUBLE) && defined (REAL)) + // solve L1*x1 + SUITESPARSE_BLAS_dtrsm ("L", "L", "N", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + // E = E - L2*x1 + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_dgemm ("N", "N", + nsrow2, nrhs, nscol, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, d, // B, LDB: X1 + one, // BETA: 1 + Ex, nsrow2, // C, LDC: E + Common->blas_ok) ; + } + + #elif (defined (SINGLE) && defined (REAL)) + // solve L1*x1 + SUITESPARSE_BLAS_strsm ("L", "L", "N", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + // E = E - L2*x1 + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_sgemm ("N", "N", + nsrow2, nrhs, nscol, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, d, // B, LDB: X1 + one, // BETA: 1 + Ex, nsrow2, // C, LDC: E + Common->blas_ok) ; + } + + #elif (defined (DOUBLE) && !defined (REAL)) + // solve L1*x1 + SUITESPARSE_BLAS_ztrsm ("L", "L", "N", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + // E = E - L2*x1 + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_zgemm ("N", "N", + nsrow2, nrhs, nscol, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, d, // B, LDB: X1 + one, // BETA: 1 + Ex, nsrow2, // C, LDC: E + Common->blas_ok) ; + } + + #elif (defined (SINGLE) && !defined (REAL)) + // solve L1*x1 + SUITESPARSE_BLAS_ctrsm ("L", "L", "N", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + // E = E - L2*x1 + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_cgemm ("N", "N", + nsrow2, nrhs, nscol, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Xx + ENTRY_SIZE*k1, d, // B, LDB: X1 + one, // BETA: 1 + Ex, nsrow2, // C, LDC: E + Common->blas_ok) ; + } + #endif + + // scatter E back into X + for (ii = 0 ; ii < nsrow2 ; ii++) + { + i = Ls [ps2 + ii] ; + for (j = 0 ; j < nrhs ; j++) + { + // Xx [i + j*d] = Ex [ii + j*nsrow2] + ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ; + } + } + } + } +} + +//------------------------------------------------------------------------------ +// t_cholmod_super_ltsolve_worker: solve x=L'\b +//------------------------------------------------------------------------------ + +static void TEMPLATE (cholmod_super_ltsolve_worker) +( + // input: + cholmod_factor *L, // factor to use for the forward solve + // input/output: + cholmod_dense *X, // b on input, solution to Lx=b on output + // workspace: + cholmod_dense *E, // workspace of size nrhs*(L->maxesize) + cholmod_common *Common +) +{ + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + Real *Lx, *Xx, *Ex ; + Real minus_one [2], one [2] ; + Int *Lpi, *Lpx, *Ls, *Super ; + Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, + nsrow2, n, ps2, j, i, d, nrhs ; + + nrhs = X->ncol ; + Ex = E->x ; + Xx = X->x ; + n = L->n ; + d = X->d ; + + nsuper = L->nsuper ; + Lpi = L->pi ; + Lpx = L->px ; + Ls = L->s ; + Super = L->super ; + Lx = L->x ; + minus_one [0] = -1.0 ; + minus_one [1] = 0 ; + one [0] = 1.0 ; + one [1] = 0 ; + #ifdef DOUBLE + ASSERT (L->dtype == CHOLMOD_DOUBLE) ; + #else + ASSERT (L->dtype == CHOLMOD_SINGLE) ; + #endif + ASSERT (L->dtype == X->dtype) ; + + //-------------------------------------------------------------------------- + // solve L'x=b + //-------------------------------------------------------------------------- + + if (nrhs == 1) + { + + for (s = nsuper-1 ; s >= 0 ; s--) + { + k1 = Super [s] ; + k2 = Super [s+1] ; + psi = Lpi [s] ; + psend = Lpi [s+1] ; + psx = Lpx [s] ; + nsrow = psend - psi ; + nscol = k2 - k1 ; + nsrow2 = nsrow - nscol ; + ps2 = psi + nscol ; + ASSERT ((size_t) nsrow2 <= L->maxesize) ; + + // L1 is nscol-by-nscol, lower triangular with non-unit diagonal. + // L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of + // nsrow. x1 is nscol-by-nsrow, with leading dimension n. + // E is nsrow2-by-1, with leading dimension nsrow2. + + // gather X into E + for (ii = 0 ; ii < nsrow2 ; ii++) + { + // Ex [ii] = Xx [Ls [ps2 + ii]] + ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; + } + + #if (defined (DOUBLE) && defined (REAL)) + // x1 = x1 - L2'*E + SUITESPARSE_BLAS_dgemv ("C", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, 1, // X, INCX: Ex + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, 1, // Y, INCY: x1 + Common->blas_ok) ; + // solve L1'*x1 + SUITESPARSE_BLAS_dtrsv ("L", "C", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + // x1 = x1 - L2'*E + SUITESPARSE_BLAS_sgemv ("C", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, 1, // X, INCX: Ex + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, 1, // Y, INCY: x1 + Common->blas_ok) ; + // solve L1'*x1 + SUITESPARSE_BLAS_strsv ("L", "C", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + // x1 = x1 - L2'*E + SUITESPARSE_BLAS_zgemv ("C", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, 1, // X, INCX: Ex + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, 1, // Y, INCY: x1 + Common->blas_ok) ; + // solve L1'*x1 + SUITESPARSE_BLAS_ztrsv ("L", "C", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + // x1 = x1 - L2'*E + SUITESPARSE_BLAS_cgemv ("C", + nsrow2, nscol, // M, N: L2 is nsrow2-by-nscol + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, 1, // X, INCX: Ex + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, 1, // Y, INCY: x1 + Common->blas_ok) ; + // solve L1'*x1 + SUITESPARSE_BLAS_ctrsv ("L", "C", "N", + nscol, // N: L1 is nscol-by-nscol + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, 1, // X, INCX: x1 + Common->blas_ok) ; + #endif + } + + } + else + { + + for (s = nsuper-1 ; s >= 0 ; s--) + { + k1 = Super [s] ; + k2 = Super [s+1] ; + psi = Lpi [s] ; + psend = Lpi [s+1] ; + psx = Lpx [s] ; + nsrow = psend - psi ; + nscol = k2 - k1 ; + nsrow2 = nsrow - nscol ; + ps2 = psi + nscol ; + ASSERT ((size_t) nsrow2 <= L->maxesize) ; + + // E is nsrow2-by-nrhs, with leading dimension nsrow2. + + // gather X into E + for (ii = 0 ; ii < nsrow2 ; ii++) + { + i = Ls [ps2 + ii] ; + for (j = 0 ; j < nrhs ; j++) + { + // Ex [ii + j*nsrow2] = Xx [i + j*d] + ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; + } + } + + #if (defined (DOUBLE) && defined (REAL)) + // x1 = x1 - L2'*E + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_dgemm ("C", "N", + nscol, nrhs, nsrow2, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, nsrow2, // B, LDB: E + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, d, // C, LDC: x1 + Common->blas_ok) ; + } + // solve L1'*x1 + SUITESPARSE_BLAS_dtrsm ("L", "L", "C", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && defined (REAL)) + // x1 = x1 - L2'*E + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_sgemm ("C", "N", + nscol, nrhs, nsrow2, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, nsrow2, // B, LDB: E + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, d, // C, LDC: x1 + Common->blas_ok) ; + } + // solve L1'*x1 + SUITESPARSE_BLAS_strsm ("L", "L", "C", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + + #elif (defined (DOUBLE) && !defined (REAL)) + // x1 = x1 - L2'*E + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_zgemm ("C", "N", + nscol, nrhs, nsrow2, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, nsrow2, // B, LDB: E + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, d, // C, LDC: x1 + Common->blas_ok) ; + } + // solve L1'*x1 + SUITESPARSE_BLAS_ztrsm ("L", "L", "C", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + + #elif (defined (SINGLE) && !defined (REAL)) + // x1 = x1 - L2'*E + if (nsrow2 > 0) + { + SUITESPARSE_BLAS_cgemm ("C", "N", + nscol, nrhs, nsrow2, // M, N, K + minus_one, // ALPHA: -1 + Lx + ENTRY_SIZE*(psx + nscol), // A, LDA: L2 + nsrow, + Ex, nsrow2, // B, LDB: E + one, // BETA: 1 + Xx + ENTRY_SIZE*k1, d, // C, LDC: x1 + Common->blas_ok) ; + } + // solve L1'*x1 + SUITESPARSE_BLAS_ctrsm ("L", "L", "C", "N", + nscol, nrhs, // M, N: x1 is nscol-by-nrhs + one, // ALPHA: 1 + Lx + ENTRY_SIZE*psx, nsrow, // A, LDA: L1 + Xx + ENTRY_SIZE*k1, d, // B, LDB: x1 + Common->blas_ok) ; + #endif + } + } +} + +#undef PATTERN +#undef REAL +#undef COMPLEX +#undef ZOMPLEX + diff --git a/CHOLMOD/Tcov/.gitignore b/CHOLMOD/Tcov/.gitignore index 3259887a47..21b260a820 100644 --- a/CHOLMOD/Tcov/.gitignore +++ b/CHOLMOD/Tcov/.gitignore @@ -12,3 +12,15 @@ n_*.c ui_*.c ul_*.c o* +di_demo* +si_demo* +dl_demo* +sl_demo* +di_test +si_test +dl_test +sl_test +di_read +si_read +dl_read +sl_read diff --git a/CHOLMOD/Tcov/Makefile b/CHOLMOD/Tcov/Makefile index 012e8fc5ed..dba682be09 100644 --- a/CHOLMOD/Tcov/Makefile +++ b/CHOLMOD/Tcov/Makefile @@ -1,19 +1,19 @@ -#=============================================================================== +#------------------------------------------------------------------------------- # CHOLMOD/Tcov/Makefile -#=============================================================================== +#------------------------------------------------------------------------------- -# ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +#------------------------------------------------------------------------------- +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ -# ------------------------------------------------------------------------------ +#------------------------------------------------------------------------------- # To compile and run: use "make". # This test only works in Linux. default: go -################################################################################ +#------------------------------------------------------------------------------- # SuiteSparse root directory SUITESPARSE ?= $(realpath $(CURDIR)/../..) @@ -45,8 +45,8 @@ default: go else # with CUDA for CHOLMOD and SPQR GPU_BLAS_PATH = $(CUDA_PATH) - # GPU_CONFIG must include -DSUITESPARSE_CUDA to compile SuiteSparse for the - # GPU. You can add additional GPU-related flags to it as well. + # GPU_CONFIG must include -DSUITESPARSE_CUDA to compile SuiteSparse for + # the GPU. You can add additional GPU-related flags to it as well. # with 4 cores (default): GPU_CONFIG = -DSUITESPARSE_CUDA # For example, to compile CHOLMOD for 10 CPU cores when using the GPU: @@ -73,7 +73,7 @@ default: go # location of TCOV test output TCOV_TMP ?= ../build -################################################################################ +#------------------------------------------------------------------------------- # without valgrind V = @@ -83,10 +83,10 @@ CF = -O0 -g --coverage -fprofile-abs-path -DTEST_COVERAGE -DBLAS32 -fopenmp # with valgrind # V = valgrind --suppressions=suppress --quiet # COVER = -# CF = -O0 -g +# CF = -O0 -g -DTEST_COVERAGE -DBLAS32 -fopenmp # Temp directory -T = $(TCOV_TMP)/CHOLMOD_TCOV_TMP +T = $(TCOV_TMP)/T # Tcov requires gcc CC = gcc @@ -101,7 +101,7 @@ C = $(CC) $(CF) $(CHOLMOD_CONFIG) $(NANTESTS) CN = $(CC) -O0 -g -fopenmp $(CHOLMOD_CONFIG) $(NANTESTS) # LDLIBS = -L$(SUITESPARSE)/lib -lsuitesparseconfig \ -# -lm $(LAPACK) $(BLAS) -lrt -Wl,-rpath=$(SUITESPARSE)/lib +# -lm $(LAPACK) $(BLAS) -lrt -Wl,-rpath=$(SUITESPARSE)/lib LDLIBS = -lm $(LAPACK) $(BLAS) @@ -113,9 +113,9 @@ endif #------------------------------------------------------------------------------- I = -I.. -I../../AMD/Include -I../../COLAMD/Include \ - -I../SuiteSparse_metis/include -I../../CCOLAMD/Include \ - -I../../CAMD/Include \ - -I../Include -I../../SuiteSparse_config $(CUDA_INC) \ + -I../SuiteSparse_metis/include -I../../CCOLAMD/Include \ + -I../../CAMD/Include \ + -I../Include -I../../SuiteSparse_config $(CUDA_INC) \ -I../Check -I../Cholesky -I../Demo -I../Supernodal \ -I../Partition -I../Modify -I../MatrixOps -I../GPU \ -I../SuiteSparse_metis \ @@ -127,61 +127,102 @@ I = -I.. -I../../AMD/Include -I../../COLAMD/Include \ I += $(GPU_CONFIG) -ccode: cm cl zdemo ldemo cmread clread - -TEST = cm.c \ - test_ops.c null.c null2.c lpdemo.c memory.c solve.c aug.c unpack.c \ - raw_factor.c cctest.c ctest.c amdtest.c camdtest.c huge.c - -LTEST = cl.c amdtest_l.c camdtest_l.c huge_l.c +ccode: \ + di_test dl_test si_test sl_test \ + di_demo dl_demo si_demo sl_demo \ + di_read dl_read si_read sl_read + +PROGS = \ + di_test dl_test si_test sl_test \ + di_demo dl_demo si_demo sl_demo \ + di_read dl_read si_read sl_read + +TEMPLATES = \ + t_amdtest.c \ + t_aug.c \ + t_camdtest.c \ + t_cctest.c \ + t_cm.c \ + t_read_triplet.c \ + t_rhs.c \ + t_znorm_diag.c \ + t_prand.c \ + t_perm_matrix.c \ + t_rand_dense.c \ + t_ptest.c \ + t_ctest.c \ + t_huge.c \ + t_lpdemo.c \ + t_memory.c \ + t_null2.c \ + t_basic.c \ + t_overflow_tests.c \ + t_cat_tests.c \ + t_null.c \ + t_raw_factor.c \ + t_solve.c \ + t_test_ops.c \ + t_test_ops2.c \ + t_dense_tests.c \ + t_dtype_tests.c \ + t_common_tests.c \ + t_error_tests.c \ + t_tofrom_tests.c \ + t_suitesparse.c \ + t_unpack.c + +DL_TEST = dl_test.c dl_amdtest.c dl_camdtest.c dl_huge.c +DI_TEST = di_test.c di_amdtest.c di_camdtest.c di_huge.c +SL_TEST = sl_test.c sl_amdtest.c sl_camdtest.c sl_huge.c +SI_TEST = si_test.c si_amdtest.c si_camdtest.c si_huge.c INC = ../Include/cholmod.h \ - ../Include/cholmod_internal.h \ - ../Include/cholmod_template.h + ../Include/cholmod_internal.h \ + ../Include/cholmod_template.h AMDSRC = ../../AMD/Source/amd_1.c \ - ../../AMD/Source/amd_2.c \ - ../../AMD/Source/amd_aat.c \ - ../../AMD/Source/amd_control.c \ - ../../AMD/Source/amd_defaults.c \ - ../../AMD/Source/amd_info.c \ - ../../AMD/Source/amd_order.c \ - ../../AMD/Source/amd_postorder.c \ - ../../AMD/Source/amd_post_tree.c \ - ../../AMD/Source/amd_preprocess.c \ - ../../AMD/Source/amd_valid.c \ - ../../AMD/Include/amd.h \ - ../../AMD/Include/amd_internal.h + ../../AMD/Source/amd_2.c \ + ../../AMD/Source/amd_aat.c \ + ../../AMD/Source/amd_control.c \ + ../../AMD/Source/amd_defaults.c \ + ../../AMD/Source/amd_info.c \ + ../../AMD/Source/amd_order.c \ + ../../AMD/Source/amd_postorder.c \ + ../../AMD/Source/amd_post_tree.c \ + ../../AMD/Source/amd_preprocess.c \ + ../../AMD/Source/amd_valid.c \ + ../../AMD/Include/amd.h \ + ../../AMD/Include/amd_internal.h AMDOBJ = \ - zz_amd_1.o \ - zz_amd_2.o \ - zz_amd_aat.o \ - zz_amd_control.o \ - zz_amd_defaults.o \ - zz_amd_info.o \ - zz_amd_order.o \ - zz_amd_postorder.o \ - zz_amd_post_tree.o \ - zz_amd_preprocess.o \ - zz_amd_valid.o -# add this to AMDOBJ if debugging is enabled -# zz_amd_dump.o \ + zz_amd_1.o \ + zz_amd_2.o \ + zz_amd_aat.o \ + zz_amd_control.o \ + zz_amd_defaults.o \ + zz_amd_info.o \ + zz_amd_order.o \ + zz_amd_postorder.o \ + zz_amd_post_tree.o \ + zz_amd_preprocess.o \ + zz_amd_valid.o + # add this to AMDOBJ if debugging is enabled + # zz_amd_dump.o \ LAMDOBJ = \ - zl_amd_1.o \ - zl_amd_2.o \ - zl_amd_aat.o \ - zl_amd_control.o \ - zl_amd_defaults.o \ - zl_amd_info.o \ - zl_amd_order.o \ - zl_amd_postorder.o \ - zl_amd_post_tree.o \ - zl_amd_preprocess.o \ - zl_amd_valid.o -# add this to LAMDOBJ if debugging is enabled -# zl_amd_dump.o \ + zl_amd_1.o \ + zl_amd_2.o \ + zl_amd_aat.o \ + zl_amd_control.o \ + zl_amd_defaults.o \ + zl_amd_info.o \ + zl_amd_order.o \ + zl_amd_postorder.o \ + zl_amd_post_tree.o \ + zl_amd_preprocess.o \ + zl_amd_valid.o + # add this to LAMDOBJ if debugging is enabled + # zl_amd_dump.o \ COLAMDSRC = ../../COLAMD/Source/colamd.c @@ -193,8 +234,8 @@ LCOLAMDOBJ = zl_colamd.o # When using the Partition Module: CCOLAMDSRC = \ - ../../CCOLAMD/Source/ccolamd.c \ - ../../CCOLAMD/Include/ccolamd.h + ../../CCOLAMD/Source/ccolamd.c \ + ../../CCOLAMD/Include/ccolamd.h CCOLAMDOBJ = zz_ccolamd.o @@ -205,61 +246,61 @@ $(CCOLAMDOBJ): $(CCOLAMDSRC) $(LCCOLAMDOBJ): $(CCOLAMDSRC) IPARTITION_OBJ = \ - z_ccolamd.o \ - z_csymamd.o \ - z_camd.o \ - z_metis.o \ - n_metis_wrapper.o \ - z_nesdis.o + z_ccolamd.o \ + z_csymamd.o \ + z_camd.o \ + z_metis.o \ + n_metis_wrapper.o \ + z_nesdis.o LPARTITION_OBJ = \ - l_ccolamd.o \ - l_csymamd.o \ - l_camd.o \ - l_metis.o \ - n_metis_wrapper.o \ - l_nesdis.o + l_ccolamd.o \ + l_csymamd.o \ + l_camd.o \ + l_metis.o \ + n_metis_wrapper.o \ + l_nesdis.o CAMDSRC = ../../CAMD/Source/camd_1.c \ - ../../CAMD/Source/camd_2.c \ - ../../CAMD/Source/camd_aat.c \ - ../../CAMD/Source/camd_control.c \ - ../../CAMD/Source/camd_defaults.c \ - ../../CAMD/Source/camd_info.c \ - ../../CAMD/Source/camd_order.c \ - ../../CAMD/Source/camd_postorder.c \ - ../../CAMD/Source/camd_preprocess.c \ - ../../CAMD/Source/camd_valid.c \ - ../../CAMD/Include/camd.h \ - ../../CAMD/Include/camd_internal.h + ../../CAMD/Source/camd_2.c \ + ../../CAMD/Source/camd_aat.c \ + ../../CAMD/Source/camd_control.c \ + ../../CAMD/Source/camd_defaults.c \ + ../../CAMD/Source/camd_info.c \ + ../../CAMD/Source/camd_order.c \ + ../../CAMD/Source/camd_postorder.c \ + ../../CAMD/Source/camd_preprocess.c \ + ../../CAMD/Source/camd_valid.c \ + ../../CAMD/Include/camd.h \ + ../../CAMD/Include/camd_internal.h CAMDOBJ = \ - zz_camd_1.o \ - zz_camd_2.o \ - zz_camd_aat.o \ - zz_camd_control.o \ - zz_camd_defaults.o \ - zz_camd_info.o \ - zz_camd_order.o \ - zz_camd_postorder.o \ - zz_camd_preprocess.o \ - zz_camd_valid.o -# add this to CAMDOBJ if debugging is enabled -# zz_camd_dump.o \ + zz_camd_1.o \ + zz_camd_2.o \ + zz_camd_aat.o \ + zz_camd_control.o \ + zz_camd_defaults.o \ + zz_camd_info.o \ + zz_camd_order.o \ + zz_camd_postorder.o \ + zz_camd_preprocess.o \ + zz_camd_valid.o + # add this to CAMDOBJ if debugging is enabled + # zz_camd_dump.o \ LCAMDOBJ = \ - zl_camd_1.o \ - zl_camd_2.o \ - zl_camd_aat.o \ - zl_camd_control.o \ - zl_camd_defaults.o \ - zl_camd_info.o \ - zl_camd_order.o \ - zl_camd_postorder.o \ - zl_camd_preprocess.o \ - zl_camd_valid.o -# add this to LCAMDOBJ if debugging is enabled -# zl_camd_dump.o \ + zl_camd_1.o \ + zl_camd_2.o \ + zl_camd_aat.o \ + zl_camd_control.o \ + zl_camd_defaults.o \ + zl_camd_info.o \ + zl_camd_order.o \ + zl_camd_postorder.o \ + zl_camd_preprocess.o \ + zl_camd_valid.o + # add this to LCAMDOBJ if debugging is enabled + # zl_camd_dump.o \ $(CAMDOBJ): $(CAMDSRC) @@ -270,13 +311,13 @@ $(LCAMDOBJ): $(CAMDSRC) # with empty ones (see immediately below), and then you do not need a copy of # CCOLAMD: # CCOLAMDSRC = -# CCOLAMDOBJ = +# CCOLAMDOBJ = # LCCOLAMDOBJ = -# IPARTITION_OBJ = -# LPARTITION_OBJ = -# CAMDSRC = -# CAMDOBJ = -# LCAMDOBJ = +# IPARTITION_OBJ = +# LPARTITION_OBJ = +# CAMDSRC = +# CAMDOBJ = +# LCAMDOBJ = #------------------------------------------------------------------------------- IUTIL_OBJ = \ @@ -420,77 +461,77 @@ LUTIL_OBJ = \ ul_zeros.o IOBJ = $(IUTIL_OBJ) \ - z_check.o \ - z_read.o \ - z_write.o \ - z_amd.o \ - z_analyze.o \ - z_colamd.o \ - z_etree.o \ - z_factorize.o \ - z_postorder.o \ - z_rcond.o \ - z_resymbol.o \ - z_rowcolcounts.o \ - z_rowfac.o \ - z_solve.o \ - z_spsolve.o \ - z_drop.o \ - z_horzcat.o \ - z_norm.o \ - z_scale.o \ - z_sdmult.o \ - z_ssmult.o \ - z_submatrix.o \ - z_vertcat.o \ - z_symmetry.o \ - z_rowadd.o \ - z_rowdel.o \ - z_updown.o \ - z_super_numeric.o \ - z_super_solve.o \ - z_super_symbolic.o \ - $(IPARTITION_OBJ) + z_check.o \ + z_read.o \ + z_write.o \ + z_amd.o \ + z_analyze.o \ + z_colamd.o \ + z_etree.o \ + z_factorize.o \ + z_postorder.o \ + z_rcond.o \ + z_resymbol.o \ + z_rowcolcounts.o \ + z_rowfac.o \ + z_solve.o \ + z_spsolve.o \ + z_drop.o \ + z_horzcat.o \ + z_norm.o \ + z_scale.o \ + z_sdmult.o \ + z_ssmult.o \ + z_submatrix.o \ + z_vertcat.o \ + z_symmetry.o \ + z_rowadd.o \ + z_rowdel.o \ + z_updown.o \ + z_super_numeric.o \ + z_super_solve.o \ + z_super_symbolic.o \ + $(IPARTITION_OBJ) LOBJ = $(LUTIL_OBJ) \ - l_check.o \ - l_read.o \ - l_write.o \ - l_amd.o \ - l_analyze.o \ - l_colamd.o \ - l_etree.o \ - l_factorize.o \ - l_postorder.o \ - l_rcond.o \ - l_resymbol.o \ - l_rowcolcounts.o \ - l_rowfac.o \ - l_solve.o \ - l_spsolve.o \ - l_drop.o \ - l_horzcat.o \ - l_norm.o \ - l_scale.o \ - l_sdmult.o \ - l_ssmult.o \ - l_submatrix.o \ - l_vertcat.o \ - l_symmetry.o \ - l_rowadd.o \ - l_rowdel.o \ - l_updown.o \ - l_super_numeric.o \ - l_super_solve.o \ - l_super_symbolic.o \ - $(LPARTITION_OBJ) + l_check.o \ + l_read.o \ + l_write.o \ + l_amd.o \ + l_analyze.o \ + l_colamd.o \ + l_etree.o \ + l_factorize.o \ + l_postorder.o \ + l_rcond.o \ + l_resymbol.o \ + l_rowcolcounts.o \ + l_rowfac.o \ + l_solve.o \ + l_spsolve.o \ + l_drop.o \ + l_horzcat.o \ + l_norm.o \ + l_scale.o \ + l_sdmult.o \ + l_ssmult.o \ + l_submatrix.o \ + l_vertcat.o \ + l_symmetry.o \ + l_rowadd.o \ + l_rowdel.o \ + l_updown.o \ + l_super_numeric.o \ + l_super_solve.o \ + l_super_symbolic.o \ + $(LPARTITION_OBJ) ifneq ($(GPU_CONFIG),) IGPU = l_gpu_kernels.o z_gpu.o LGPU = l_gpu_kernels.o l_gpu.o else - IGPU = - LGPU = + IGPU = + LGPU = endif CONFIG = zz_SuiteSparse_config.o @@ -503,227 +544,344 @@ IALL = $(IOBJ) $(AMDOBJ) $(COLAMDOBJ) $(CCOLAMDOBJ) $(CAMDOBJ) $(CONFIG) $( LALL = $(LOBJ) $(LAMDOBJ) $(LCOLAMDOBJ) $(LCCOLAMDOBJ) $(LCAMDOBJ) $(CONFIG) $(ILOBJ) $(LGPU) -cm: $(IALL) $(TEST) cm.h Makefile - $(C) $(I) $(TEST) -o cm $(IALL) $(LDLIBS) +di_test: $(IALL) $(DI_TEST) cm.h Makefile $(TEMPLATES) + $(C) $(I) $(DI_TEST) -o di_test $(IALL) $(LDLIBS) + +dl_test: $(LALL) $(DL_TEST) cm.h Makefile $(TEMPLATES) + $(C) $(I) $(DL_TEST) -o dl_test $(LALL) $(LDLIBS) -cl: $(LALL) $(LTEST) cm.h Makefile cm.c \ - test_ops.c null.c null2.c lpdemo.c memory.c solve.c aug.c unpack.c \ - raw_factor.c cctest.c ctest.c amdtest.c camdtest.c huge.c - $(C) $(I) $(LTEST) -o cl $(LALL) $(LDLIBS) +si_test: $(IALL) $(SI_TEST) cm.h Makefile $(TEMPLATES) + $(C) $(I) $(SI_TEST) -o si_test $(IALL) $(LDLIBS) -cmread: $(IALL) cmread.c Makefile - $(C) $(I) cmread.c -o cmread $(IALL) $(LDLIBS) +sl_test: $(IALL) $(SL_TEST) cm.h Makefile $(TEMPLATES) + $(C) $(I) $(SL_TEST) -o sl_test $(LALL) $(LDLIBS) -clread: $(LALL) clread.c Makefile - $(C) $(I) clread.c -o clread $(LALL) $(LDLIBS) +di_read: $(IALL) di_read.c Makefile t_cmread.c t_znorm_diag.c + $(C) $(I) di_read.c -o di_read $(IALL) $(LDLIBS) -zdemo: $(IALL) ../Demo/cholmod_demo.c cm.h Makefile \ +dl_read: $(LALL) dl_read.c Makefile t_cmread.c t_znorm_diag.c + $(C) $(I) dl_read.c -o dl_read $(LALL) $(LDLIBS) + +si_read: $(IALL) si_read.c Makefile t_cmread.c t_znorm_diag.c + $(C) $(I) si_read.c -o si_read $(IALL) $(LDLIBS) + +sl_read: $(LALL) sl_read.c Makefile t_cmread.c t_znorm_diag.c + $(C) $(I) sl_read.c -o sl_read $(LALL) $(LDLIBS) + +di_demo: $(IALL) ../Demo/cholmod_di_demo.c Makefile \ ../Demo/cholmod_demo.h - - ln -s ../Demo/cholmod_demo.c zdemo.c - $(C) $(I) -I../Demo zdemo.c -o zdemo $(IALL) $(LDLIBS) + - ln -s ../Demo/cholmod_di_demo.c di_demo.c + $(C) $(I) -I../Demo di_demo.c -o di_demo $(IALL) $(LDLIBS) -ldemo: $(LALL) ../Demo/cholmod_l_demo.c cm.h Makefile \ +si_demo: $(IALL) ../Demo/cholmod_si_demo.c Makefile \ ../Demo/cholmod_demo.h - - ln -s ../Demo/cholmod_l_demo.c ldemo.c - $(C) $(I) -I../Demo ldemo.c -o ldemo $(LALL) $(LDLIBS) + - ln -s ../Demo/cholmod_si_demo.c si_demo.c + $(C) $(I) -I../Demo si_demo.c -o si_demo $(IALL) $(LDLIBS) -compile: zdemo ldemo cmread clread cm cl +dl_demo: $(LALL) ../Demo/cholmod_dl_demo.c Makefile \ + ../Demo/cholmod_demo.h + - ln -s ../Demo/cholmod_dl_demo.c dl_demo.c + $(C) $(I) -I../Demo dl_demo.c -o dl_demo $(LALL) $(LDLIBS) -go: zdemo ldemo cmread clread cm cl +sl_demo: $(LALL) ../Demo/cholmod_sl_demo.c Makefile \ + ../Demo/cholmod_demo.h + - ln -s ../Demo/cholmod_sl_demo.c sl_demo.c + $(C) $(I) -I../Demo sl_demo.c -o sl_demo $(LALL) $(LDLIBS) + +compile: ccode + +go: ccode mkdir -p $(T) - $(V) ./cl < Matrix/galenet > $(T)/l_galenet.out - $(V) ./cl -m < Matrix/z5lo > $(T)/l_z5lo.out - $(V) ./zdemo ../Demo/Matrix/bcsstk01.tri > $(T)/demo_k1.out - $(V) ./zdemo ../Demo/Matrix/bcsstk02.tri > $(T)/demo_k2.out - $(V) ./zdemo < ../Demo/Matrix/lp_afiro.tri > $(T)/demo_afiro.out - $(V) ./zdemo < ../Demo/Matrix/can___24.mtx > $(T)/demo_can24.out - $(V) ./zdemo < ../Demo/Matrix/c.tri > $(T)/demo_c.out - $(V) ./zdemo < ../Demo/Matrix/d.tri > $(T)/demo_d.out - $(V) ./zdemo < ../Demo/Matrix/up.tri > $(T)/demo_up.out - $(V) ./zdemo < ../Demo/Matrix/c.mtx > $(T)/demo_c_mtx.out - $(V) ./zdemo < ../Demo/Matrix/0.tri > $(T)/demo_0.out - $(V) ./zdemo < Matrix/3_2 > $(T)/demo_3_2.out - $(V) ./zdemo < Matrix/c5lo > $(T)/demo_c5lo.out - $(V) ./zdemo < Matrix/c10 > $(T)/demo_c10.out - $(V) ./zdemo no_such_file > $(T)/demo_no_such_file.out - $(V) ./zdemo ../Demo/Matrix/mangle1.mtx > $(T)/demo_mangle1.out - $(V) ./zdemo ../Demo/Matrix/mangle2.mtx > $(T)/demo_mangle2.out - $(V) ./zdemo ../Demo/Matrix/mangle3.mtx > $(T)/demo_mangle3.out - $(V) ./zdemo ../Demo/Matrix/mangle4.mtx > $(T)/demo_mangle4.out - $(V) ./zdemo ../Demo/Matrix/pts5ldd03.mtx > $(T)/demo_pts5ldd03.out - $(V) ./ldemo ../Demo/Matrix/bcsstk01.tri > $(T)/ldemo_k1.out - $(V) ./ldemo ../Demo/Matrix/bcsstk02.tri > $(T)/ldemo_k2.out - $(V) ./ldemo < ../Demo/Matrix/lp_afiro.tri > $(T)/ldemo_afiro.out - $(V) ./ldemo < ../Demo/Matrix/can___24.mtx > $(T)/ldemo_can24.out - $(V) ./ldemo < ../Demo/Matrix/c.tri > $(T)/ldemo_c.out - $(V) ./ldemo ../Demo/Matrix/c.tri 1 > $(T)/ldemo_c_zomplex.out - $(V) ./ldemo < ../Demo/Matrix/d.tri > $(T)/ldemo_d.out - $(V) ./ldemo ../Demo/Matrix/d.tri 1 > $(T)/ldemo_d.out - $(V) ./ldemo < ../Demo/Matrix/up.tri > $(T)/ldemo_up.out - $(V) ./ldemo ../Demo/Matrix/up.tri 1 > $(T)/ldemo_up_zomplex.out - $(V) ./ldemo < ../Demo/Matrix/c.mtx > $(T)/ldemo_c_mtx.out - $(V) ./ldemo ../Demo/Matrix/c.mtx 1 > $(T)/ldemo_c_mtx_zomplex.out - $(V) ./ldemo < ../Demo/Matrix/0.tri > $(T)/ldemo_0.out - $(V) ./ldemo < Matrix/3_2 > $(T)/ldemo_3_2.out - $(V) ./ldemo < Matrix/c5lo > $(T)/ldemo_c5lo.out - $(V) ./ldemo < Matrix/c10 > $(T)/ldemo_c10.out - $(V) ./ldemo no_such_file > $(T)/ldemo_no_such_file.out - $(V) ./ldemo ../Demo/Matrix/mangle1.mtx > $(T)/ldemo_mangle1.out - $(V) ./ldemo ../Demo/Matrix/mangle2.mtx > $(T)/ldemo_mangle2.out - $(V) ./ldemo ../Demo/Matrix/mangle3.mtx > $(T)/ldemo_mangle3.out - $(V) ./ldemo ../Demo/Matrix/mangle4.mtx > $(T)/ldemo_mangle4.out - $(V) ./ldemo ../Demo/Matrix/pts5ldd03.mtx > $(T)/ldemo_pts5ldd03.out - - grep resid $(T)/demo* - $(V) ./cmread no_such_file > $(T)/no_such_file.out - $(V) ./cmread Matrix/crud1 > $(T)/crud1.out - $(V) ./cmread Matrix/crud2 > $(T)/crud2.out - $(V) ./cmread Matrix/fullcrud.mtx > $(T)/fullcrud.out - $(V) ./cmread Matrix/fullcrud1.mtx > $(T)/fullcrud1.out - $(V) ./cmread Matrix/fullcrud2.mtx > $(T)/fullcrud2.out - $(V) ./cmread Matrix/3by0.mtx > $(T)/3by0.out - $(V) ./cmread Matrix/fullrza.mtx > $(T)/fullrza.out - $(V) ./cmread Matrix/fullrsa.mtx > $(T)/fullrsa.out - $(V) ./cmread Matrix/fullcsa.mtx > $(T)/fullcsa.out - $(V) ./cmread Matrix/fullcza.mtx > $(T)/fullcza.out - $(V) ./cmread Matrix/fullcha.mtx > $(T)/fullcha.out - $(V) ./cmread Matrix/cha.mtx > $(T)/cha.out - $(V) ./cmread Matrix/cza.mtx > $(T)/cza.out - $(V) ./cmread Matrix/csa.mtx > $(T)/csa.out - $(V) ./cmread Matrix/one > $(T)/one.out - $(V) ./cmread Matrix/rza.mtx > $(T)/rza.out - $(V) ./cmread ../Demo/Matrix/mangle5.tri > $(T)/mangle5.out - $(V) ./cmread ../Demo/Matrix/mangle6.tri > $(T)/mangle6.out - $(V) ./cmread ../Demo/Matrix/mangle7.tri > $(T)/mangle6.out - $(V) ./cmread ../Demo/Matrix/mangle8.tri > $(T)/mangle8.out - $(V) ./cmread ../Demo/Matrix/empty.tri > $(T)/empty.out - $(V) ./cmread ../Demo/Matrix/one.tri > $(T)/one.out - $(V) ./cmread Matrix/plskz362.mtx > $(T)/plskz363.out - $(V) ./cmread Matrix/2diag.tri > $(T)/2diag.out - $(V) ./cmread Matrix/r5lo > $(T)/r5lo.out - $(V) ./cmread Matrix/r5lo2 > $(T)/r5lo2.out - - diff $(T)/r5lo.out $(T)/r5lo2.out - $(V) ./cmread Matrix/cs.mtx > $(T)/cs.out - $(V) ./cmread Matrix/2lo.tri > $(T)/2lo.out - $(V) ./cmread Matrix/2.tri > $(T)/2.out - $(V) ./cmread Matrix/2up.tri > $(T)/2up.out - $(V) ./cmread Matrix/huge.tri > $(T)/huge.out - $(V) ./cmread Matrix/1e99 > $(T)/1e99.out - $(V) ./clread no_such_file > $(T)/l_no_such_file.out - $(V) ./clread Matrix/crud1 > $(T)/l_crud1.out - $(V) ./clread Matrix/crud2 > $(T)/l_crud2.out - $(V) ./clread Matrix/fullcrud.mtx > $(T)/l_fullcrud.out - $(V) ./clread Matrix/fullcrud1.mtx > $(T)/l_fullcrud1.out - $(V) ./clread Matrix/fullcrud2.mtx > $(T)/l_fullcrud2.out - $(V) ./clread Matrix/3by0.mtx > $(T)/l_3by0.out - $(V) ./clread Matrix/fullrza.mtx > $(T)/l_fullrza.out - $(V) ./clread Matrix/fullrsa.mtx > $(T)/l_fullrsa.out - $(V) ./clread Matrix/fullcsa.mtx > $(T)/l_fullcsa.out - $(V) ./clread Matrix/fullcza.mtx > $(T)/l_fullcza.out - $(V) ./clread Matrix/fullcha.mtx > $(T)/l_fullcha.out - $(V) ./clread Matrix/cha.mtx > $(T)/l_cha.out - $(V) ./clread Matrix/cza.mtx > $(T)/l_cza.out - $(V) ./clread Matrix/csa.mtx > $(T)/l_csa.out - $(V) ./clread Matrix/one > $(T)/l_one.out - $(V) ./clread Matrix/rza.mtx > $(T)/l_rza.out - $(V) ./clread ../Demo/Matrix/mangle5.tri > $(T)/l_mangle5.out - $(V) ./clread ../Demo/Matrix/mangle6.tri > $(T)/l_mangle6.out - $(V) ./clread ../Demo/Matrix/mangle7.tri > $(T)/l_mangle6.out - $(V) ./clread ../Demo/Matrix/mangle8.tri > $(T)/l_mangle8.out - $(V) ./clread ../Demo/Matrix/empty.tri > $(T)/l_empty.out - $(V) ./clread ../Demo/Matrix/one.tri > $(T)/l_one.out - $(V) ./clread Matrix/plskz362.mtx > $(T)/l_plskz363.out - $(V) ./clread Matrix/2diag.tri > $(T)/l_2diag.out - $(V) ./clread Matrix/r5lo > $(T)/l_r5lo.out - $(V) ./clread Matrix/r5lo2 > $(T)/l_r5lo2.out - - diff $(T)/r5lo.out $(T)/r5lo2.out - $(V) ./clread Matrix/cs.mtx > $(T)/l_cs.out - $(V) ./clread Matrix/2lo.tri > $(T)/l_l_2lo.out - $(V) ./clread Matrix/2.tri > $(T)/l_2.out - $(V) ./clread Matrix/2up.tri > $(T)/l_2up.out - $(V) ./clread Matrix/huge.tri > $(T)/l_huge.out - $(V) ./clread Matrix/1e99 > $(T)/l_1e99.out - $(V) ./cm < Matrix/galenet > $(T)/galenet.out - - $(COVER) - $(V) ./cm < Matrix/5by50 > $(T)/5by50.out - $(V) ./cl < Matrix/5by50 > $(T)/l_5by50.out - - $(COVER) - $(V) ./cm < Matrix/r5lo > $(T)/r5lo.out - $(V) ./cl < Matrix/r5lo > $(T)/l_r5lo.out - $(V) ./cm < Matrix/r5up > $(T)/r5up.out - $(V) ./cl < Matrix/r5up > $(T)/l_r5up.out - $(V) ./cm < Matrix/r5up2 > $(T)/r5up2.out - $(V) ./cl < Matrix/r5up2 > $(T)/l_r5up2.out - $(V) ./cm < Matrix/c5up2 > $(T)/c5up2.out - $(V) ./cl < Matrix/c5up2 > $(T)/l_c5up2.out - $(V) ./cm < Matrix/z5up2 > $(T)/z5up2.out - $(V) ./cl < Matrix/z5up2 > $(T)/l_z5up2.out - $(V) ./cm -m < Matrix/z5lo > $(T)/z5lo.out - $(V) ./cm < Matrix/ibm32 > $(T)/ibm.out - $(V) ./cl < Matrix/ibm32 > $(T)/l_ibm.out - - $(COVER) - $(V) ./cm -m < Matrix/c5lo > $(T)/c5lo.out - $(V) ./cl -m < Matrix/c5lo > $(T)/l_c5lo.out - $(V) ./cm -m < Matrix/z10 > $(T)/z10.out - $(V) ./cl -m < Matrix/z10 > $(T)/l_z10.out - $(V) ./cm -m < Matrix/z5up > $(T)/z5up.out - $(V) ./cl -m < Matrix/z5up > $(T)/l_z5up.out - - $(COVER) - $(V) ./cm -s < Matrix/3singular > $(T)/3singular.out - $(V) ./cl -s < Matrix/3singular > $(T)/l_3singular.out - $(V) ./cm -s < Matrix/z3singular > $(T)/z3singular.out - $(V) ./cl -s < Matrix/z3singular > $(T)/l_z3singular.out - $(V) ./cm -s < Matrix/c3singular > $(T)/c3singular.out - $(V) ./cl -s < Matrix/c3singular > $(T)/l_c3singular.out - $(V) ./cm -m < Matrix/0 > $(T)/0.out - $(V) ./cl -m < Matrix/0 > $(T)/l_0.out - $(V) ./cm -m < Matrix/afiro > $(T)/afiro.out - $(V) ./cl -m < Matrix/afiro > $(T)/l_afiro.out - - $(COVER) - $(V) ./cm -m < Matrix/k01up > $(T)/k01up.out - $(V) ./cl -m < Matrix/k01up > $(T)/l_k01up.out - - $(COVER) - $(V) ./cm < Matrix/diag > $(T)/diag.out - $(V) ./cl < Matrix/diag > $(T)/l_diag.out - $(V) ./cm -m < Matrix/ex5lo > $(T)/ex5lo.out - $(V) ./cl -m < Matrix/ex5lo > $(T)/l_ex5lo.out - - $(COVER) - $(V) ./cm < Matrix/20lo > $(T)/20lo.out - $(V) ./cl < Matrix/20lo > $(T)/l_20lo.out - $(V) ./cm < Matrix/z30lo > $(T)/z30lo.out - $(V) ./cl < Matrix/z30lo > $(T)/l_z30lo.out - - $(COVER) - $(V) ./cm -m < Matrix/z30up > $(T)/z30up.out - $(V) ./cl -m < Matrix/z30up > $(T)/l_z30up.out - $(V) ./cm < Matrix/c10 > $(T)/c10.out - $(V) ./cl < Matrix/c10 > $(T)/l_c10.out - $(V) ./cm < Matrix/c30lo > $(T)/c30lo.out - $(V) ./cl < Matrix/c30lo > $(T)/l_c30lo.out - - $(COVER) - $(V) ./cm < Matrix/C9840 > $(T)/C9840.out - $(V) ./cl < Matrix/C9840 > $(T)/l_C9840.out - - $(COVER) - $(V) ./cm -m < Matrix/c30up > $(T)/c30up.out - $(V) ./cl -m < Matrix/c30up > $(T)/l_c30up.out - $(V) ./cm < Matrix/pi > $(T)/pi.out - $(V) ./cl < Matrix/pi > $(T)/l_pi.out - $(V) ./cm < Matrix/cpi > $(T)/cpi.out - $(V) ./cl < Matrix/cpi > $(T)/l_cpi.out - $(V) ./cm < Matrix/1_0 > $(T)/1_0.out - $(V) ./cl < Matrix/1_0 > $(T)/l_1_0.out - $(V) ./cm -s < Matrix/3b > $(T)/3b.out - $(V) ./cl -s < Matrix/3b > $(T)/l_3b.out - $(V) ./cm -s < Matrix/cza > $(T)/cza2.out - $(V) ./cl -s < Matrix/cza > $(T)/l_cza2.out - $(V) ./cm < Matrix/0_1 > $(T)/0_1.out - $(V) ./cl < Matrix/0_1 > $(T)/l_0_1.out - - $(COVER) - $(V) ./cm -n < Matrix/galenet > $(T)/galenet_nan.out - - $(COVER) - $(V) ./cl -n < Matrix/galenet > $(T)/l_galenet_nan.out - - $(COVER) - $(V) ./cm < Matrix/zero > $(T)/zero.out - $(V) ./cl < Matrix/zero > $(T)/l_zero.out - - $(COVER) + # total test time: about 22 minutes including compilation: + $(V) ./di_read -x Matrix/crud1 > $(T)/di_read_crud1.out + $(V) ./dl_read -x Matrix/crud1 > $(T)/dl_read_crud1.out + $(V) ./si_read -x Matrix/crud1 > $(T)/si_read_crud1.out + $(V) ./sl_read -x Matrix/crud1 > $(T)/sl_read_crud1.out + # + $(V) ./di_read -x Matrix/crud2 > $(T)/di_read_crud2.out + $(V) ./dl_read -x Matrix/crud2 > $(T)/dl_read_crud2.out + $(V) ./si_read -x Matrix/crud2 > $(T)/si_read_crud2.out + $(V) ./sl_read -x Matrix/crud2 > $(T)/sl_read_crud2.out + # + $(V) ./di_read -x Matrix/fullcrud.mtx > $(T)/di_read_fullcrud.out + $(V) ./dl_read -x Matrix/fullcrud.mtx > $(T)/dl_read_fullcrud.out + $(V) ./si_read -x Matrix/fullcrud.mtx > $(T)/si_read_fullcrud.out + $(V) ./sl_read -x Matrix/fullcrud.mtx > $(T)/sl_read_fullcrud.out + # + $(V) ./di_read -x Matrix/fullcrud1.mtx > $(T)/di_read_fullcrud1.out + $(V) ./dl_read -x Matrix/fullcrud1.mtx > $(T)/dl_read_fullcrud1.out + $(V) ./si_read -x Matrix/fullcrud1.mtx > $(T)/si_read_fullcrud1.out + $(V) ./sl_read -x Matrix/fullcrud1.mtx > $(T)/sl_read_fullcrud1.out + # + $(V) ./di_read -x Matrix/fullcrud2.mtx > $(T)/di_read_fullcrud2.out + $(V) ./dl_read -x Matrix/fullcrud2.mtx > $(T)/dl_read_fullcrud2.out + $(V) ./si_read -x Matrix/fullcrud2.mtx > $(T)/si_read_fullcrud2.out + $(V) ./sl_read -x Matrix/fullcrud2.mtx > $(T)/sl_read_fullcrud2.out + # + $(V) ./di_read Matrix/3by0.mtx > $(T)/di_read_3by0.out + $(V) ./dl_read Matrix/3by0.mtx > $(T)/dl_read_3by0.out + $(V) ./si_read Matrix/3by0.mtx > $(T)/si_read_3by0.out + $(V) ./sl_read Matrix/3by0.mtx > $(T)/sl_read_3by0.out + # + $(V) ./di_read Matrix/fullrza.mtx > $(T)/di_read_fullrza.out + $(V) ./dl_read Matrix/fullrza.mtx > $(T)/dl_read_fullrza.out + $(V) ./si_read Matrix/fullrza.mtx > $(T)/si_read_fullrza.out + $(V) ./sl_read Matrix/fullrza.mtx > $(T)/sl_read_fullrza.out + # + $(V) ./di_read Matrix/fullrsa.mtx > $(T)/di_read_fullrsa.out + $(V) ./dl_read Matrix/fullrsa.mtx > $(T)/dl_read_fullrsa.out + $(V) ./si_read Matrix/fullrsa.mtx > $(T)/si_read_fullrsa.out + $(V) ./sl_read Matrix/fullrsa.mtx > $(T)/sl_read_fullrsa.out + # + $(V) ./di_read Matrix/fullcsa.mtx > $(T)/di_read_fullcsa.out + $(V) ./dl_read Matrix/fullcsa.mtx > $(T)/dl_read_fullcsa.out + $(V) ./si_read Matrix/fullcsa.mtx > $(T)/si_read_fullcsa.out + $(V) ./sl_read Matrix/fullcsa.mtx > $(T)/sl_read_fullcsa.out + # + $(V) ./di_read Matrix/cha.mtx > $(T)/di_read_cha.out + $(V) ./dl_read Matrix/cha.mtx > $(T)/dl_read_cha.out + $(V) ./si_read Matrix/cha.mtx > $(T)/si_read_cha.out + $(V) ./sl_read Matrix/cha.mtx > $(T)/sl_read_cha.out + # + $(V) ./di_read Matrix/rza.mtx > $(T)/di_read_rza.out + $(V) ./dl_read Matrix/rza.mtx > $(T)/dl_read_rza.out + $(V) ./si_read Matrix/rza.mtx > $(T)/si_read_rza.out + $(V) ./sl_read Matrix/rza.mtx > $(T)/sl_read_rza.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle1.mtx > $(T)/di_read_mangle1.out + $(V) ./dl_read -x ../Demo/Matrix/mangle1.mtx > $(T)/dl_read_mangle1.out + $(V) ./si_read -x ../Demo/Matrix/mangle1.mtx > $(T)/si_read_mangle1.out + $(V) ./sl_read -x ../Demo/Matrix/mangle1.mtx > $(T)/sl_read_mangle1.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle2.mtx > $(T)/di_read_mangle2.out + $(V) ./dl_read -x ../Demo/Matrix/mangle2.mtx > $(T)/dl_read_mangle2.out + $(V) ./si_read -x ../Demo/Matrix/mangle2.mtx > $(T)/si_read_mangle2.out + $(V) ./sl_read -x ../Demo/Matrix/mangle2.mtx > $(T)/sl_read_mangle2.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle3.mtx > $(T)/di_read_mangle3.out + $(V) ./dl_read -x ../Demo/Matrix/mangle3.mtx > $(T)/dl_read_mangle3.out + $(V) ./si_read -x ../Demo/Matrix/mangle3.mtx > $(T)/si_read_mangle3.out + $(V) ./sl_read -x ../Demo/Matrix/mangle3.mtx > $(T)/sl_read_mangle3.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle4.mtx > $(T)/di_read_mangle4.out + $(V) ./dl_read -x ../Demo/Matrix/mangle4.mtx > $(T)/dl_read_mangle4.out + $(V) ./si_read -x ../Demo/Matrix/mangle4.mtx > $(T)/si_read_mangle4.out + $(V) ./sl_read -x ../Demo/Matrix/mangle4.mtx > $(T)/sl_read_mangle4.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle5.tri > $(T)/di_read_mangle5.out + $(V) ./dl_read -x ../Demo/Matrix/mangle5.tri > $(T)/dl_read_mangle5.out + $(V) ./si_read -x ../Demo/Matrix/mangle5.tri > $(T)/si_read_mangle5.out + $(V) ./sl_read -x ../Demo/Matrix/mangle5.tri > $(T)/sl_read_mangle5.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle6.tri > $(T)/di_read_mangle6.out + $(V) ./dl_read -x ../Demo/Matrix/mangle6.tri > $(T)/dl_read_mangle6.out + $(V) ./si_read -x ../Demo/Matrix/mangle6.tri > $(T)/si_read_mangle6.out + $(V) ./sl_read -x ../Demo/Matrix/mangle6.tri > $(T)/sl_read_mangle6.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle7.tri > $(T)/di_read_mangle7.out + $(V) ./dl_read -x ../Demo/Matrix/mangle7.tri > $(T)/dl_read_mangle7.out + $(V) ./si_read -x ../Demo/Matrix/mangle7.tri > $(T)/si_read_mangle7.out + $(V) ./sl_read -x ../Demo/Matrix/mangle7.tri > $(T)/sl_read_mangle7.out + # + $(V) ./di_read -x ../Demo/Matrix/mangle8.tri > $(T)/di_read_mangle8.out + $(V) ./dl_read -x ../Demo/Matrix/mangle8.tri > $(T)/dl_read_mangle8.out + $(V) ./si_read -x ../Demo/Matrix/mangle8.tri > $(T)/si_read_mangle8.out + $(V) ./sl_read -x ../Demo/Matrix/mangle8.tri > $(T)/sl_read_mangle8.out + # + $(V) ./di_read Matrix/2diag.tri > $(T)/di_read_2diag.out + $(V) ./dl_read Matrix/2diag.tri > $(T)/dl_read_2diag.out + $(V) ./si_read Matrix/2diag.tri > $(T)/si_read_2diag.out + $(V) ./sl_read Matrix/2diag.tri > $(T)/sl_read_2diag.out + # + $(V) ./di_read Matrix/r5lo2 > $(T)/di_read_r5lo2.out + $(V) ./dl_read Matrix/r5lo2 > $(T)/dl_read_r5lo2.out + $(V) ./si_read Matrix/r5lo2 > $(T)/si_read_r5lo2.out + $(V) ./sl_read Matrix/r5lo2 > $(T)/sl_read_r5lo2.out + # + $(V) ./di_read Matrix/2lo.tri > $(T)/di_read_2lo.out + $(V) ./dl_read Matrix/2lo.tri > $(T)/dl_read_2lo.out + $(V) ./si_read Matrix/2lo.tri > $(T)/si_read_2lo.out + $(V) ./sl_read Matrix/2lo.tri > $(T)/sl_read_2lo.out + # + $(V) ./di_read Matrix/2.tri > $(T)/di_read_2.out + $(V) ./dl_read Matrix/2.tri > $(T)/dl_read_2.out + $(V) ./si_read Matrix/2.tri > $(T)/si_read_2.out + $(V) ./sl_read Matrix/2.tri > $(T)/sl_read_2.out + # + $(V) ./di_read Matrix/2up.tri > $(T)/di_read_2up.out + $(V) ./dl_read Matrix/2up.tri > $(T)/dl_read_2up.out + $(V) ./si_read Matrix/2up.tri > $(T)/si_read_2up.out + $(V) ./sl_read Matrix/2up.tri > $(T)/sl_read_2up.out + # + $(V) ./di_read Matrix/1e99 > $(T)/di_read_1e99.out + $(V) ./dl_read Matrix/1e99 > $(T)/dl_read_1e99.out + $(V) ./si_read Matrix/1e99 > $(T)/si_read_1e99.out + $(V) ./sl_read Matrix/1e99 > $(T)/sl_read_1e99.out + $(COVER) + # time: - coverage: ~4910 demo bcsstk01: + $(V) ./di_demo ../Demo/Matrix/bcsstk01.tri > $(T)/di_demo_k1.out + $(V) ./dl_demo ../Demo/Matrix/bcsstk01.tri > $(T)/dl_demo_k1.out + $(V) ./si_demo ../Demo/Matrix/bcsstk01.tri > $(T)/si_demo_k1.out + $(V) ./sl_demo ../Demo/Matrix/bcsstk01.tri > $(T)/sl_demo_k1.out + $(COVER) + # time: - coverage: ~2550 demo bcsstk02: + $(V) ./di_demo ../Demo/Matrix/bcsstk02.tri > $(T)/di_demo_k2.out + $(V) ./dl_demo ../Demo/Matrix/bcsstk02.tri > $(T)/dl_demo_k2.out + $(V) ./si_demo ../Demo/Matrix/bcsstk02.tri > $(T)/si_demo_k2.out + $(V) ./sl_demo ../Demo/Matrix/bcsstk02.tri > $(T)/sl_demo_k2.out + $(COVER) + # time: - coverage: ~1560 demo d: + $(V) ./di_demo < ../Demo/Matrix/d.tri > $(T)/di_demo_d.out + $(V) ./dl_demo < ../Demo/Matrix/d.tri > $(T)/dl_demo_d.out + $(V) ./dl_demo ../Demo/Matrix/d.tri 1 > $(T)/dl_demo_d.out + $(V) ./si_demo < ../Demo/Matrix/d.tri > $(T)/si_demo_d.out + $(V) ./sl_demo < ../Demo/Matrix/d.tri > $(T)/sl_demo_d.out + $(V) ./sl_demo ../Demo/Matrix/d.tri 1 > $(T)/sl_demo_d.out + $(COVER) + # time: - coverage: 30 demo up: + $(V) ./di_demo < ../Demo/Matrix/up.tri > $(T)/di_demo_up.out + $(V) ./dl_demo < ../Demo/Matrix/up.tri > $(T)/dl_demo_up.out + $(V) ./dl_demo ../Demo/Matrix/up.tri 1 > $(T)/dl_demo_up_z.out + $(V) ./si_demo < ../Demo/Matrix/up.tri > $(T)/si_demo_up.out + $(V) ./sl_demo < ../Demo/Matrix/up.tri > $(T)/sl_demo_up.out + $(V) ./sl_demo ../Demo/Matrix/up.tri 1 > $(T)/sl_demo_up_z.out + $(COVER) + # time: - coverage: 4 demo 3_2: + $(V) ./di_demo < Matrix/3_2 > $(T)/di_demo_3_2.out + $(V) ./dl_demo < Matrix/3_2 > $(T)/dl_demo_3_2.out + $(V) ./si_demo < Matrix/3_2 > $(T)/si_demo_3_2.out + $(V) ./sl_demo < Matrix/3_2 > $(T)/sl_demo_3_2.out + $(COVER) + # time: 8 coverage: ~19300 matrix: c5up2 + $(V) ./di_test -e14 < Matrix/c5up2 > $(T)/di_test_c5up2.out + $(V) ./dl_test -e14 < Matrix/c5up2 > $(T)/dl_test_c5up2.out + $(V) ./si_test -e5 < Matrix/c5up2 > $(T)/si_test_c5up2.out + $(V) ./sl_test -e5 < Matrix/c5up2 > $(T)/sl_test_c5up2.out + $(COVER) + # time: 0 coverage: ~350 matrix: zero: + $(V) ./di_test < Matrix/zero > $(T)/di_test_zero.out + $(V) ./dl_test < Matrix/zero > $(T)/dl_test_zero.out + $(V) ./si_test < Matrix/zero > $(T)/si_test_zero.out + $(V) ./sl_test < Matrix/zero > $(T)/sl_test_zero.out + $(COVER) + # time: 6 coverage: ~850 cza: + $(V) ./di_test -s < Matrix/cza > $(T)/di_test_cza.out + $(V) ./dl_test -s < Matrix/cza > $(T)/dl_test_cza.out + $(V) ./si_test -s < Matrix/cza > $(T)/si_test_cza.out + $(V) ./sl_test -s < Matrix/cza > $(T)/sl_test_cza.out + $(COVER) + # time: 16 coverage: ~3170 z5up: + $(V) ./di_test -m -e14 < Matrix/z5up > $(T)/di_test_z5up.out + $(V) ./dl_test -m -e14 < Matrix/z5up > $(T)/dl_test_z5up.out + $(V) ./si_test -m -e5 < Matrix/z5up > $(T)/si_test_z5up.out + $(V) ./sl_test -m -e5 < Matrix/z5up > $(T)/sl_test_z5up.out + $(COVER) + # time: 11 coverage: ~8180 write: + $(V) ./di_test -e5 < Matrix/write.tri > $(T)/di_test_write.out + $(V) ./dl_test -e5 < Matrix/write.tri > $(T)/dl_test_write.out + $(COVER) + # time: 13 coverage: ~2640 pi: + $(V) ./di_test -e11 < Matrix/pi > $(T)/di_test_pi.out + $(V) ./dl_test -e11 < Matrix/pi > $(T)/dl_test_pi.out + $(V) ./si_test -e2 < Matrix/pi > $(T)/si_test_pi.out + $(V) ./sl_test -e2 < Matrix/pi > $(T)/sl_test_pi.out + $(COVER) + # time: 20 coverage: ~5150 r5lo: + $(V) ./di_test -e11 < Matrix/r5lo > $(T)/di_test_r5lo.out + $(V) ./dl_test -e11 < Matrix/r5lo > $(T)/dl_test_r5lo.out + $(V) ./si_test -e2 < Matrix/r5lo > $(T)/si_test_r5lo.out + $(V) ./sl_test -e2 < Matrix/r5lo > $(T)/sl_test_r5lo.out + $(COVER) + # time: 25 coverage: ~1760 5by50: + $(V) ./di_test -e9 < Matrix/5by50 > $(T)/di_test_5by50.out + $(V) ./dl_test -e9 < Matrix/5by50 > $(T)/dl_test_5by50.out + $(V) ./si_test -e3 < Matrix/5by50 > $(T)/si_test_5by50.out + $(V) ./sl_test -e3 < Matrix/5by50 > $(T)/sl_test_5by50.out + $(COVER) + # time: 25 coverage: ~1090 diag: + $(V) ./di_test -e11 < Matrix/diag > $(T)/di_test_diag.out + $(V) ./dl_test -e11 < Matrix/diag > $(T)/dl_test_diag.out + $(V) ./si_test -e2 < Matrix/diag > $(T)/si_test_diag.out + $(V) ./sl_test -e2 < Matrix/diag > $(T)/sl_test_diag.out + $(COVER) + # time: 17 coverage: 52 0: + $(V) ./di_test -m -e14 < Matrix/0 > $(T)/di_test_0.out + $(V) ./dl_test -m -e14 < Matrix/0 > $(T)/dl_test_0.out + $(V) ./si_test -m -e5 < Matrix/0 > $(T)/si_test_0.out + $(V) ./sl_test -m -e5 < Matrix/0 > $(T)/sl_test_0.out + $(COVER) + # time: 66 coverage: ~1900 ex50lo: + $(V) ./di_test -m -e7 < Matrix/ex5lo > $(T)/di_test_ex5lo.out + $(V) ./dl_test -m -e7 < Matrix/ex5lo > $(T)/dl_test_ex5lo.out + $(V) ./si_test -m -e3 < Matrix/ex5lo > $(T)/si_test_ex5lo.out + $(V) ./sl_test -m -e3 < Matrix/ex5lo > $(T)/sl_test_ex5lo.out + $(COVER) + # time: 20 coverage: 22 c10: + $(V) ./di_test -e12 < Matrix/c10 > $(T)/di_test_c10.out + $(V) ./dl_test -e12 < Matrix/c10 > $(T)/dl_test_c10.out + $(V) ./si_test -e4 < Matrix/c10 > $(T)/si_test_c10.out + $(V) ./sl_test -e4 < Matrix/c10 > $(T)/sl_test_c10.out + $(COVER) + # time: 46 coverage: 224 z30lo: + $(V) ./di_test -e12 < Matrix/z30lo > $(T)/di_test_z30lo.out + $(V) ./dl_test -e12 < Matrix/z30lo > $(T)/dl_test_z30lo.out + $(V) ./si_test -e4 < Matrix/z30lo > $(T)/si_test_z30lo.out + $(V) ./sl_test -e4 < Matrix/z30lo > $(T)/sl_test_z30lo.out + $(COVER) + # time: 40 coverage: 168 c30lo_singular: + $(V) ./di_test -s < Matrix/c30lo_singular > $(T)/di_test_c30lo.out + $(V) ./dl_test -s < Matrix/c30lo_singular > $(T)/dl_test_c30lo.out + $(V) ./si_test -s < Matrix/c30lo_singular > $(T)/si_test_c30lo.out + $(V) ./sl_test -s < Matrix/c30lo_singular > $(T)/sl_test_c30lo.out + $(COVER) + # time: 46 coverage: 14 c30up: + $(V) ./di_test -e12 < Matrix/c30up > $(T)/di_test_c30up.out + $(V) ./dl_test -e12 < Matrix/c30up > $(T)/dl_test_c30up.out + $(V) ./si_test -e4 < Matrix/c30up > $(T)/si_test_c30up.out + $(V) ./sl_test -e4 < Matrix/c30up > $(T)/sl_test_c30up.out + $(COVER) + # time: 58 coverage: 18 z10: + $(V) ./di_test -m -e11 < Matrix/z10 > $(T)/di_test_z10.out + $(V) ./dl_test -m -e11 < Matrix/z10 > $(T)/dl_test_z10.out + $(V) ./si_test -m -e4 < Matrix/z10 > $(T)/si_test_z10.out + $(V) ./sl_test -m -e4 < Matrix/z10 > $(T)/sl_test_z10.out + $(COVER) + # time: 60 coverage: 18 galenet: + $(V) ./dl_test -e8 < Matrix/galenet > $(T)/dl_test_galenet.out + $(V) ./di_test -e8 < Matrix/galenet > $(T)/di_test_galenet.out + $(V) ./si_test -e2 < Matrix/galenet > $(T)/si_test_galenet.out + $(V) ./sl_test -e2 < Matrix/galenet > $(T)/sl_test_galenet.out + $(COVER) + # time: 76 coverage: 44 20lo: + $(V) ./di_test -e12 < Matrix/20lo > $(T)/di_test_20lo.out + $(V) ./dl_test -e12 < Matrix/20lo > $(T)/dl_test_20lo.out + $(V) ./si_test -e3 < Matrix/20lo > $(T)/si_test_20lo.out + $(V) ./sl_test -e3 < Matrix/20lo > $(T)/sl_test_20lo.out + $(COVER) + # time: 112 coverage: 400 ibm32: + $(V) ./di_test -e8 < Matrix/ibm32 > $(T)/di_test_ibm.out + $(V) ./dl_test -e8 < Matrix/ibm32 > $(T)/dl_test_ibm.out + $(V) ./si_test < Matrix/ibm32 > $(T)/si_test_ibm.out + $(V) ./sl_test < Matrix/ibm32 > $(T)/sl_test_ibm.out + $(COVER) + # time: 106 coverage: 10 C9840: + $(V) ./di_test -e11 < Matrix/C9840 > $(T)/di_test_C9840.out + $(V) ./dl_test -e11 < Matrix/C9840 > $(T)/dl_test_C9840.out + $(V) ./si_test -e2 < Matrix/C9840 > $(T)/si_test_C9840.out + $(V) ./sl_test -e2 < Matrix/C9840 > $(T)/sl_test_C9840.out + $(COVER) + # time: 205 coverage: 32 afiro: + $(V) ./di_test -m -e7 < Matrix/afiro > $(T)/di_test_afiro.out + $(V) ./dl_test -m -e7 < Matrix/afiro > $(T)/dl_test_afiro.out + $(V) ./si_test -m -e2 < Matrix/afiro > $(T)/si_test_afiro.out + $(V) ./sl_test -m -e2 < Matrix/afiro > $(T)/sl_test_afiro.out + $(COVER) + # time: 260 coverage: 6 k01up: + $(V) ./di_test -m -e10 < Matrix/k01up > $(T)/di_test_k01up.out + $(V) ./dl_test -m -e10 < Matrix/k01up > $(T)/dl_test_k01up.out + $(V) ./si_test -m -e4 < Matrix/k01up > $(T)/si_test_k01up.out + $(V) ./sl_test -m -e4 < Matrix/k01up > $(T)/sl_test_k01up.out + $(COVER) cov: - $(COVER) @@ -733,10 +891,10 @@ cov: # make gpu # setenv CHOLMOD_USE_GPU 0 # make gpu -gpu: ldemo - ./ldemo ../../../Matrix/nd6k.mtx - ./ldemo ../../../Matrix/nd6k_complex.mtx - ./ldemo ../../../Matrix/nd6k_complex.mtx 1 +gpu: dl_demo + ./dl_demo ../../../Matrix/nd6k.mtx + ./dl_demo ../../../Matrix/nd6k_complex.mtx + ./dl_demo ../../../Matrix/nd6k_complex.mtx 1 - $(COVER) purge: clean @@ -744,11 +902,13 @@ purge: clean distclean: clean clean: - - $(RM) cm cl cmread clread *.c.gcov *.out zdemo ldemo - - $(RM) leak zz_*.c z_*.c *.a l_*.c zl_*.c cov.sort ldemo.c zdemo.c - - $(RM) -r cm.profile cmread.profile zdemo.profile $(T) - - $(RM) -r cl.profile clread.profile ldemo.profile + - $(RM) $(PROGS) + - $(RM) *.c.gcov *.out + - $(RM) leak zz_*.c z_*.c *.a l_*.c zl_*.c cov.sort + - $(RM) -r *.profile $(T) - $(RM) temp*.mtx timelog.m l_*.cu + - $(RM) si_demo.c sl_demo.c + - $(RM) di_demo.c dl_demo.c - $(RM) ui_*.c ul_*.c u_*.c n_*.c - $(RM) -r $(PURGE) - $(RM) -r $(CLEAN) @@ -1617,7 +1777,7 @@ z_rowfac.o: ../Cholesky/cholmod_rowfac.c - ln -s $< z_rowfac.c $(C) -c $(I) z_rowfac.c -#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- z_ccolamd.o: ../Partition/cholmod_ccolamd.c - ln -s $< z_ccolamd.c $(C) -c $(I) z_ccolamd.c @@ -1650,7 +1810,7 @@ z_horzcat.o: ../MatrixOps/cholmod_horzcat.c $(C) -c $(I) z_horzcat.c z_norm.o: ../MatrixOps/cholmod_norm.c - $- ln -s $< z_norm.c + - ln -s $< z_norm.c $(C) -c $(I) z_norm.c z_scale.o: ../MatrixOps/cholmod_scale.c @@ -1777,7 +1937,7 @@ l_rowfac.o: ../Cholesky/cholmod_l_rowfac.c - ln -s $< l_rowfac.c $(C) -c $(I) l_rowfac.c -#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- l_ccolamd.o: ../Partition/cholmod_l_ccolamd.c - ln -s $< l_ccolamd.c $(C) -c $(I) l_ccolamd.c @@ -1868,9 +2028,10 @@ l_super_solve.o: ../Supernodal/cholmod_l_super_solve.c - ln -s $< l_super_solve.c $(C) -c $(I) l_super_solve.c +#------------------------------------------------------------------------------- + # GPU kernels only use int64_t: l_gpu_kernels.o: ../GPU/cholmod_gpu_kernels.cu - ln -s $< l_gpu_kernels.cu $(NVCC) $(CHOLMOD_CONFIG) -I../../SuiteSparse_config -Xcompiler -fPIC -O3 -c l_gpu_kernels.cu -#------------------------------------------------------------------------------- diff --git a/CHOLMOD/Tcov/Matrix/0_1 b/CHOLMOD/Tcov/Matrix/0_1 deleted file mode 100644 index 006db41c14..0000000000 --- a/CHOLMOD/Tcov/Matrix/0_1 +++ /dev/null @@ -1 +0,0 @@ -0 1 0 0 diff --git a/CHOLMOD/Tcov/Matrix/1_0 b/CHOLMOD/Tcov/Matrix/1_0 deleted file mode 100644 index 0dea48b753..0000000000 --- a/CHOLMOD/Tcov/Matrix/1_0 +++ /dev/null @@ -1 +0,0 @@ -1 0 0 0 diff --git a/CHOLMOD/Tcov/Matrix/2_3 b/CHOLMOD/Tcov/Matrix/2_3 deleted file mode 100644 index b84a0009d3..0000000000 --- a/CHOLMOD/Tcov/Matrix/2_3 +++ /dev/null @@ -1,7 +0,0 @@ -2 3 6 0 -0 0 9.4423471389861624e-01 -1 0 8.3855545301913648e-01 -0 1 2.5842740296885991e-01 -1 1 4.2898125196177306e-02 -0 2 5.8847897639891693e-03 -1 2 5.7441796740690909e-01 diff --git a/CHOLMOD/Tcov/Matrix/3b b/CHOLMOD/Tcov/Matrix/3b deleted file mode 100644 index 9ea6497554..0000000000 --- a/CHOLMOD/Tcov/Matrix/3b +++ /dev/null @@ -1,5 +0,0 @@ -3 3 4 -0 0 1 -2 0 1 -0 1 1 -0 2 1 diff --git a/CHOLMOD/Tcov/Matrix/3singular b/CHOLMOD/Tcov/Matrix/3singular deleted file mode 100644 index 4d80e17e40..0000000000 --- a/CHOLMOD/Tcov/Matrix/3singular +++ /dev/null @@ -1,5 +0,0 @@ -3 3 4 1 -0 0 9.4423471389861624e-01 -0 1 8.3855545301913648e-01 -1 1 4.2898125196177306e-02 -1 2 5.7441796740690909e-01 diff --git a/CHOLMOD/Tcov/Matrix/4 b/CHOLMOD/Tcov/Matrix/4 deleted file mode 100644 index d17570b53d..0000000000 --- a/CHOLMOD/Tcov/Matrix/4 +++ /dev/null @@ -1,17 +0,0 @@ -4 4 16 0 -0 0 8.4472150190817474e-01 -1 0 3.6775288246828447e-01 -2 0 6.2080133182114383e-01 -3 0 7.3127726446634478e-01 -0 1 1.9389317998466821e-01 -1 1 9.0481233416635698e-01 -2 1 5.6920574967174709e-01 -3 1 6.3178992922175603e-01 -0 2 2.3441295540825388e-01 -1 2 5.4878212553858818e-01 -2 2 9.3158335257969060e-01 -3 2 3.3519743020639464e-01 -0 3 6.5553105501201447e-01 -1 3 3.9190420688900335e-01 -2 3 6.2731478808399666e-01 -3 3 6.9908013774533750e-01 diff --git a/CHOLMOD/Tcov/Matrix/4lo b/CHOLMOD/Tcov/Matrix/4lo deleted file mode 100644 index 4177a3920f..0000000000 --- a/CHOLMOD/Tcov/Matrix/4lo +++ /dev/null @@ -1,11 +0,0 @@ -4 4 10 -1 -0 0 1.0828864476260923e+01 -1 0 1.6627011669737349e-01 -2 0 3.9390600531964565e-01 -3 0 5.2075748437407210e-01 -1 1 1.0703683667405754e+01 -2 1 5.2206091530257359e-01 -3 1 9.3289705665171452e-01 -2 2 1.0081073725242863e+01 -3 2 8.5112240092385527e-01 -3 3 1.0888832610299779e+01 diff --git a/CHOLMOD/Tcov/Matrix/5 b/CHOLMOD/Tcov/Matrix/5 deleted file mode 100644 index 8e58c54dee..0000000000 --- a/CHOLMOD/Tcov/Matrix/5 +++ /dev/null @@ -1,16 +0,0 @@ -5 5 15 1 -0 0 2.3128893423956103e+00 -0 1 2.0414504875924515e+00 -1 1 2.3404148406122136e+00 -0 2 1.3087150593318868e+00 -1 2 1.0697105858626588e+00 -2 2 1.1518495146909449e+00 -0 3 1.8412759629133451e+00 -1 3 1.6127622826156847e+00 -2 3 9.9254946878554184e-01 -3 3 1.5263467772586621e+00 -0 4 1.1506154116930891e+00 -1 4 8.5366433729208291e-01 -2 4 5.8985415046641843e-01 -3 4 8.4135254506414192e-01 -4 4 9.2240833463986371e-01 diff --git a/CHOLMOD/Tcov/Matrix/README.txt b/CHOLMOD/Tcov/Matrix/README.txt new file mode 100644 index 0000000000..7f6b14d278 --- /dev/null +++ b/CHOLMOD/Tcov/Matrix/README.txt @@ -0,0 +1,7 @@ +Test matrices for test coverage. + +*.mtx files are in Matrix Market format. + +The remainder are in a simple triplet format, +defined by the read_triplet method. + diff --git a/CHOLMOD/Tcov/Matrix/a1 b/CHOLMOD/Tcov/Matrix/a1 deleted file mode 100644 index 97afc3b0c9..0000000000 --- a/CHOLMOD/Tcov/Matrix/a1 +++ /dev/null @@ -1 +0,0 @@ -70000 70000 0 2 diff --git a/CHOLMOD/Tcov/Matrix/a2 b/CHOLMOD/Tcov/Matrix/a2 deleted file mode 100644 index 060e904cd1..0000000000 --- a/CHOLMOD/Tcov/Matrix/a2 +++ /dev/null @@ -1 +0,0 @@ -200 200 0 2 diff --git a/CHOLMOD/Tcov/Matrix/c30lo b/CHOLMOD/Tcov/Matrix/c30lo_singular similarity index 99% rename from CHOLMOD/Tcov/Matrix/c30lo rename to CHOLMOD/Tcov/Matrix/c30lo_singular index ddf763623d..300c68fc22 100644 --- a/CHOLMOD/Tcov/Matrix/c30lo +++ b/CHOLMOD/Tcov/Matrix/c30lo_singular @@ -32,7 +32,7 @@ 20 5 0.552673 -0.434441 23 5 0.919957 -0.273088 28 5 0.569206 -0.474041 -6 6 6.06059 0 +6 6 0 0 12 6 0.994295 0.982709 13 6 0.0099273 -0.700857 17 6 0.422452 -0.253561 diff --git a/CHOLMOD/Tcov/Matrix/c3singular b/CHOLMOD/Tcov/Matrix/c3singular deleted file mode 100644 index f772d136df..0000000000 --- a/CHOLMOD/Tcov/Matrix/c3singular +++ /dev/null @@ -1,5 +0,0 @@ -3 3 4 1 1 -0 0 9.4423471389861624e-01 0.1 -0 1 8.3855545301913648e-01 0.2 -1 1 4.2898125196177306e-02 0.03 -1 2 5.7441796740690909e-01 0.04 diff --git a/CHOLMOD/Tcov/Matrix/c5lo b/CHOLMOD/Tcov/Matrix/c5lo deleted file mode 100644 index 4046dc5cd4..0000000000 --- a/CHOLMOD/Tcov/Matrix/c5lo +++ /dev/null @@ -1,12 +0,0 @@ -5 5 11 -1 1 -0 0 2.43872 0 -1 0 0.261819 -0.16627 -2 0 0.724062 0.804517 -4 0 0.281634 0.828864 -1 1 4.21742 0 -2 1 1.69463 -0.324218 -3 1 1.23492 0.0754504 -2 2 4.77818 0 -3 2 0.902819 0.460806 -3 3 3.51267 0 -4 4 6.25922 0 diff --git a/CHOLMOD/Tcov/Matrix/c5up b/CHOLMOD/Tcov/Matrix/c5up deleted file mode 100644 index 7dfb288045..0000000000 --- a/CHOLMOD/Tcov/Matrix/c5up +++ /dev/null @@ -1,12 +0,0 @@ -5 5 11 1 1 -0 0 2.43872 0 -0 1 0.261819 0.16627 -1 1 4.21742 0 -0 2 0.724062 -0.804517 -1 2 1.69463 0.324218 -2 2 4.77818 0 -1 3 1.23492 -0.0754504 -2 3 0.902819 -0.460806 -3 3 3.51267 0 -0 4 0.281634 -0.828864 -4 4 6.25922 0 diff --git a/CHOLMOD/Tcov/Matrix/cha b/CHOLMOD/Tcov/Matrix/cha deleted file mode 100644 index c4e49e9562..0000000000 --- a/CHOLMOD/Tcov/Matrix/cha +++ /dev/null @@ -1,7 +0,0 @@ -3 3 6 -1 1 -0 0 .3017459522995293 0 -1 0 1.5579100867466829 .4760037225690294 -2 0 .874925450215774 .12614853881500188 -1 1 1.7073102613255353 -1 -2 1 1.4933320877092915 -.3859196475147934 -2 2 1.6432583214706855 0 diff --git a/CHOLMOD/Tcov/Matrix/cpi b/CHOLMOD/Tcov/Matrix/cpi deleted file mode 100644 index 1c42281212..0000000000 --- a/CHOLMOD/Tcov/Matrix/cpi +++ /dev/null @@ -1,2 +0,0 @@ -1 1 1 0 1 -0 0 3.1415926535897931e+00 0 diff --git a/CHOLMOD/Tcov/Matrix/cs.mtx b/CHOLMOD/Tcov/Matrix/cs.mtx deleted file mode 100644 index cacae9bf4c..0000000000 --- a/CHOLMOD/Tcov/Matrix/cs.mtx +++ /dev/null @@ -1,7 +0,0 @@ -%%MatrixMarket matrix coordinate complex symmetric -3 3 5 -1 1 1. 0. -3 1 2. -1. -2 2 1. 0. -3 2 3. 0. -3 3 42. 0. diff --git a/CHOLMOD/Tcov/Matrix/csa.mtx b/CHOLMOD/Tcov/Matrix/csa.mtx deleted file mode 100644 index bb73a55ac6..0000000000 --- a/CHOLMOD/Tcov/Matrix/csa.mtx +++ /dev/null @@ -1,8 +0,0 @@ -%%MatrixMarket matrix coordinate complex symmetric -3 3 6 -1 1 1.692442835648649 1.0056257679925018 -2 1 1.1972899647794608 1.0140887595727812 -3 1 .8839245189325227 1.1111155889323803 -2 2 1.6762368901047735 .37930749509434997 -3 2 .39912053189281554 .49619555718182407 -3 3 1.663592035219213 1.0833477077961753 diff --git a/CHOLMOD/Tcov/Matrix/cza.mtx b/CHOLMOD/Tcov/Matrix/cza.mtx deleted file mode 100644 index 6bb32d71db..0000000000 --- a/CHOLMOD/Tcov/Matrix/cza.mtx +++ /dev/null @@ -1,5 +0,0 @@ -%%MatrixMarket matrix coordinate complex skew-symmetric -3 3 3 -2 1 .23113851357428783 .6154323481000947 -3 1 .6068425835417866 .7919370374270354 -3 2 .7620968330273947 .176266144494618 diff --git a/CHOLMOD/Tcov/Matrix/fullcha.mtx b/CHOLMOD/Tcov/Matrix/fullcha.mtx deleted file mode 100644 index cea660bbe9..0000000000 --- a/CHOLMOD/Tcov/Matrix/fullcha.mtx +++ /dev/null @@ -1,8 +0,0 @@ -%%MatrixMarket matrix array complex Hermitian -2 2 -1.3 2.3 - -3.4 1.7 - -% comment here -7.7 8.0 diff --git a/CHOLMOD/Tcov/Matrix/fullcza.mtx b/CHOLMOD/Tcov/Matrix/fullcza.mtx deleted file mode 100644 index ee6860f265..0000000000 --- a/CHOLMOD/Tcov/Matrix/fullcza.mtx +++ /dev/null @@ -1,3 +0,0 @@ -%%MatrixMarket matrix array complex skew-symmetric -2 2 -3.4 2.99 diff --git a/CHOLMOD/Tcov/Matrix/huge.tri b/CHOLMOD/Tcov/Matrix/huge.tri deleted file mode 100644 index b1032a3ce5..0000000000 --- a/CHOLMOD/Tcov/Matrix/huge.tri +++ /dev/null @@ -1,2 +0,0 @@ -1 1 2147483647 0 -1 1 1 diff --git a/CHOLMOD/Tcov/Matrix/int_overflow.tri b/CHOLMOD/Tcov/Matrix/int_overflow.tri new file mode 100644 index 0000000000..0125b5f239 --- /dev/null +++ b/CHOLMOD/Tcov/Matrix/int_overflow.tri @@ -0,0 +1,2 @@ +9223372036854775806 9223372036854775806 1 +0 0 0 diff --git a/CHOLMOD/Tcov/Matrix/itest2 b/CHOLMOD/Tcov/Matrix/itest2 deleted file mode 100644 index 964f63e88f..0000000000 --- a/CHOLMOD/Tcov/Matrix/itest2 +++ /dev/null @@ -1,27 +0,0 @@ -9 13 26 0 -0 0 -1.0000000000000000e+00 -1 1 -1.0000000000000000e+00 -2 2 1.0000000000000000e+00 -3 3 1.0000000000000000e+00 -4 4 1.0000000000000000e+00 -5 5 -1.0000000000000000e+00 -6 6 1.0000000000000000e+00 -7 7 1.0000000000000000e+00 -8 8 -1.0000000000000000e+00 -0 9 -5.0000000000000000e-01 -1 9 2.0000000000000000e+00 -2 9 3.0000000000000000e+00 -6 9 1.0000000000000000e+00 -7 9 1.0000000000000000e+00 -0 10 1.0000000000000000e+00 -1 10 -1.0000000000000000e+00 -2 10 1.0000000000000000e+00 -7 10 2.0000000000000000e+00 -8 10 1.0000000000000000e+00 -4 11 3.0000000000000000e+00 -5 11 1.0000000000000000e+00 -7 11 1.0000000000000000e+00 -8 11 1.0000000000000000e+00 -3 12 1.0000000000000000e+00 -4 12 -1.0000000000000000e+00 -6 12 1.0000000000000000e+00 diff --git a/CHOLMOD/Tcov/Matrix/itest6 b/CHOLMOD/Tcov/Matrix/itest6 deleted file mode 100644 index f501985ccb..0000000000 --- a/CHOLMOD/Tcov/Matrix/itest6 +++ /dev/null @@ -1,30 +0,0 @@ -11 17 29 0 -0 0 1.0000000000000000e+00 -1 1 1.0000000000000000e+00 -2 2 1.0000000000000000e+00 -3 3 -1.0000000000000000e+00 -4 4 -1.0000000000000000e+00 -5 5 1.0000000000000000e+00 -6 6 -1.0000000000000000e+00 -7 7 1.0000000000000000e+00 -10 8 -1.0000000000000000e+00 -1 9 1.0000000000000000e+00 -3 10 -1.0000000000000000e+00 -4 10 -1.0000000000000000e+00 -8 10 1.0000000000000000e+00 -9 10 1.0000000000000000e+00 -10 10 1.0000000000000000e+00 -0 11 8.0000000000000004e-01 -3 11 1.0000000000000000e+00 -5 11 1.0000000000000000e+00 -8 11 -5.0000000000000003e-02 -9 11 -4.0000000000000001e-02 -0 12 1.0000000000000000e+00 -4 12 1.0000000000000000e+00 -9 12 -5.0000000000000003e-02 -6 13 -3.0000000000000000e+00 -7 13 5.0000000000000000e-01 -2 14 2.0000000000000000e+00 -7 14 5.9999999999999998e-01 -6 15 1.0000000000000000e+00 -2 16 -1.0000000000000000e+00 diff --git a/CHOLMOD/Tcov/Matrix/mega.tri b/CHOLMOD/Tcov/Matrix/mega.tri index 8206f68ec7..f69af6df57 100644 --- a/CHOLMOD/Tcov/Matrix/mega.tri +++ b/CHOLMOD/Tcov/Matrix/mega.tri @@ -1,2 +1,2 @@ 4000000000 4000000000 1 0 -2 2 2 +2 2 2 diff --git a/CHOLMOD/Tcov/Matrix/plskz362.mtx b/CHOLMOD/Tcov/Matrix/plskz362.mtx deleted file mode 100644 index 64a267b8a4..0000000000 --- a/CHOLMOD/Tcov/Matrix/plskz362.mtx +++ /dev/null @@ -1,882 +0,0 @@ -%%MatrixMarket matrix coordinate real skew-symmetric -362 362 880 -131 1 1.7894386746670e-01 -247 1 1.8205396002412e-01 -131 2 -1.7894386746670e-01 -132 2 2.2320075046728e-01 -246 2 -2.0996332659141e-01 -248 2 2.0653877287252e-01 -133 3 2.0234999005106e-01 -250 3 2.0270353889326e-01 -133 4 -2.0234999005106e-01 -134 4 2.0923910092574e-01 -247 4 -1.8205396002412e-01 -251 4 2.1813885071807e-01 -134 5 -2.0923910092574e-01 -135 5 2.0470011219100e-01 -248 5 -2.0653877287252e-01 -252 5 2.1662365901288e-01 -135 6 -2.0470011219100e-01 -136 6 2.1479132055547e-01 -249 6 -2.2150044298031e-01 -253 6 2.2479903478463e-01 -137 7 1.8400450834498e-01 -255 7 1.9485289290002e-01 -137 8 -1.8400450834498e-01 -138 8 2.1763369147243e-01 -256 8 2.2292283278508e-01 -138 9 -2.1763369147243e-01 -139 9 2.2086479595542e-01 -250 9 -2.0492846318567e-01 -257 9 2.1757988168264e-01 -139 10 -2.2086479595542e-01 -140 10 2.2770400624121e-01 -251 10 -2.2053319681944e-01 -258 10 2.3493007714438e-01 -140 11 -2.2770400624121e-01 -141 11 2.3829522909032e-01 -252 11 -2.1900137399448e-01 -259 11 2.4662593281078e-01 -141 12 -2.3829522909032e-01 -142 12 2.3326694510829e-01 -253 12 -2.2726648471735e-01 -260 12 2.3698949197964e-01 -142 13 -2.3326694510829e-01 -143 13 1.8720619834467e-01 -254 13 -2.2342127810557e-01 -261 13 2.1567450925956e-01 -144 14 2.3702256082853e-01 -255 14 -1.9910717959662e-01 -262 14 2.4866512134844e-01 -144 15 -2.3702256082853e-01 -145 15 2.2773629988335e-01 -256 15 -2.2778997962478e-01 -263 15 2.3884672754661e-01 -145 16 -2.2773629988335e-01 -146 16 2.3690647129761e-01 -257 16 -2.2233037413011e-01 -264 16 2.1540353103193e-01 -146 17 -2.3690647129761e-01 -147 17 2.5884346650191e-01 -258 17 -2.4005938206231e-01 -265 17 2.5325677444290e-01 -147 18 -2.5884346650191e-01 -148 18 2.5072165633847e-01 -259 18 -2.5201059715616e-01 -266 18 2.6037405298922e-01 -148 19 -2.5072165633847e-01 -149 19 2.2449202727592e-01 -260 19 -2.4216376077267e-01 -267 19 2.3853939729595e-01 -149 20 -2.2449202727592e-01 -261 20 -2.2038340109012e-01 -268 20 2.1065429994046e-01 -150 21 2.4284448641010e-01 -269 21 2.4528693972316e-01 -150 22 -2.4284448641010e-01 -151 22 2.6451975735519e-01 -270 22 2.6715429823318e-01 -151 23 -2.6451975735519e-01 -152 23 2.5850333639767e-01 -262 23 -2.5670771353918e-01 -271 23 2.7301591722063e-01 -152 24 -2.5850333639767e-01 -153 24 2.3446376549787e-01 -263 24 -2.4657176278811e-01 -272 24 2.5526977764261e-01 -153 25 -2.3446376549787e-01 -154 25 2.4081047563398e-01 -264 25 -2.2237034144402e-01 -273 25 2.2101853352824e-01 -154 26 -2.4081047563398e-01 -155 26 2.6306260928478e-01 -265 26 -2.6144787476827e-01 -274 26 2.5677115298498e-01 -155 27 -2.6306260928478e-01 -156 27 2.5670771353918e-01 -266 27 -2.6879534791745e-01 -275 27 2.6903761506705e-01 -156 28 -2.5670771353918e-01 -157 28 2.3286055181749e-01 -267 28 -2.4625449253516e-01 -276 28 2.5406741794425e-01 -157 29 -2.3286055181749e-01 -268 29 -2.1746750566251e-01 -277 29 2.2525215074905e-01 -158 30 2.5501264226593e-01 -278 30 2.2806851855898e-01 -158 31 -2.5501264226593e-01 -159 31 2.8077266529936e-01 -269 31 -2.5566405201691e-01 -279 31 2.7403681408641e-01 -159 32 -2.8077266529936e-01 -160 32 2.8722747954845e-01 -270 32 -2.7845653126546e-01 -280 32 2.7399806910226e-01 -160 33 -2.8722747954845e-01 -161 33 2.8137701971765e-01 -271 33 -2.8456613197800e-01 -281 33 2.8569558873488e-01 -161 34 -2.8137701971765e-01 -162 34 2.5325804310034e-01 -272 34 -2.6606922400037e-01 -282 34 2.7463021935917e-01 -162 35 -2.5325804310034e-01 -163 35 2.4839036226323e-01 -273 35 -2.3036894633053e-01 -283 35 2.3677793275082e-01 -163 36 -2.4839036226323e-01 -164 36 2.7401098470570e-01 -274 36 -2.6763411654647e-01 -284 36 2.4364333717513e-01 -164 37 -2.7401098470570e-01 -165 37 2.7779487160137e-01 -275 37 -2.8041952372450e-01 -285 37 2.6424073133390e-01 -165 38 -2.7779487160137e-01 -166 38 2.5756718196542e-01 -276 38 -2.6481599725780e-01 -286 38 2.6438801152799e-01 -166 39 -2.5756718196542e-01 -167 39 1.9344427135511e-01 -277 39 -2.3478167101365e-01 -287 39 2.5194109795446e-01 -167 40 -1.9344427135511e-01 -288 40 1.7822870108302e-01 -168 41 2.6200642447937e-01 -278 41 -2.3982889621872e-01 -289 41 1.9870919788377e-01 -168 42 -2.6200642447937e-01 -169 42 2.8086401998800e-01 -279 42 -2.8816755184317e-01 -290 42 2.7648271076323e-01 -169 43 -2.8086401998800e-01 -170 43 2.8643770003522e-01 -280 43 -2.8812680896974e-01 -291 43 2.7720362091861e-01 -170 44 -2.8643770003522e-01 -171 44 2.9344262924826e-01 -281 44 -3.0042751245882e-01 -292 44 2.9062860231936e-01 -171 45 -2.9344262924826e-01 -172 45 2.7289261393843e-01 -282 45 -2.8879155612256e-01 -293 45 2.8865601776802e-01 -172 46 -2.7289261393843e-01 -173 46 2.4374565386139e-01 -283 46 -2.4898741228897e-01 -294 46 2.6642016070429e-01 -173 47 -2.4374565386139e-01 -174 47 2.4459508403589e-01 -284 47 -2.5620683202994e-01 -295 47 2.3977993988924e-01 -174 48 -2.4459508403589e-01 -175 48 2.6300522929833e-01 -285 48 -2.7786633303118e-01 -296 48 2.3128988726234e-01 -175 49 -2.6300522929833e-01 -176 49 2.7226091722564e-01 -286 49 -2.7802120774429e-01 -297 49 2.4717335838910e-01 -176 50 -2.7226091722564e-01 -177 50 2.5285516717993e-01 -287 50 -2.6493246773524e-01 -298 50 2.7379455143293e-01 -177 51 -2.5285516717993e-01 -288 51 -1.8741908320057e-01 -299 51 2.4292547350353e-01 -178 52 2.3049043348752e-01 -289 52 -2.1063428950144e-01 -178 53 -2.3049043348752e-01 -179 53 2.8913281984800e-01 -290 53 -2.9307520719353e-01 -300 53 2.2363516846498e-01 -179 54 -2.8913281984800e-01 -180 54 2.9842753509627e-01 -291 54 -2.9383938117234e-01 -301 54 2.7396825878091e-01 -180 55 -2.9842753509627e-01 -181 55 3.0294620888785e-01 -292 55 -3.0807003304469e-01 -302 55 2.9816220060904e-01 -181 56 -3.0294620888785e-01 -182 56 2.9950120407591e-01 -293 56 -3.0597906820824e-01 -303 56 2.9108802959430e-01 -182 57 -2.9950120407591e-01 -183 57 2.7856800666622e-01 -294 57 -2.8240877551945e-01 -304 57 2.9031661357366e-01 -183 58 -2.7856800666622e-01 -184 58 2.3976607247747e-01 -295 58 -2.5416980096116e-01 -305 58 2.7363100765308e-01 -184 59 -2.3976607247747e-01 -185 59 2.2590444277820e-01 -296 59 -2.4517023666347e-01 -306 59 2.2886312904348e-01 -185 60 -2.2590444277820e-01 -186 60 2.6379652464769e-01 -297 60 -2.6200691906786e-01 -307 60 2.2422425149919e-01 -186 61 -2.6379652464769e-01 -187 61 2.8053415290542e-01 -298 61 -2.9022572394548e-01 -308 61 2.8248661482402e-01 -187 62 -2.8053415290542e-01 -188 62 2.3521137971195e-01 -299 62 -2.5750410679604e-01 -309 62 2.8264222912262e-01 -188 63 -2.3521137971195e-01 -310 63 1.7063891350592e-01 -189 64 2.1741547382158e-01 -300 64 -2.3875098182565e-01 -189 65 -2.1741547382158e-01 -190 65 2.9217757197206e-01 -301 65 -2.9248615601015e-01 -190 66 -2.9217757197206e-01 -191 66 3.0544409912131e-01 -302 66 -3.1831540015520e-01 -311 66 2.4457832102235e-01 -191 67 -3.0544409912131e-01 -192 67 3.0066491010079e-01 -303 67 -3.1076307604193e-01 -312 67 2.2209062926350e-01 -192 68 -3.0066491010079e-01 -193 68 3.0488572995876e-01 -304 68 -3.0993951893511e-01 -313 68 2.7996705480263e-01 -193 69 -3.0488572995876e-01 -194 69 2.8198257964140e-01 -305 69 -2.9212610960759e-01 -314 69 2.9832220480277e-01 -194 70 -2.8198257964140e-01 -195 70 2.4256190944343e-01 -306 70 -2.4433230756091e-01 -315 70 2.6189476781938e-01 -195 71 -2.4256190944343e-01 -196 71 2.6256367224552e-01 -307 71 -2.3937988180484e-01 -316 71 2.3333690483106e-01 -196 72 -2.6256367224552e-01 -197 72 3.0381540328037e-01 -308 72 -3.0158027963477e-01 -317 72 2.8976625627556e-01 -197 73 -3.0381540328037e-01 -198 73 2.4734937343014e-01 -309 73 -3.0174641212114e-01 -318 73 3.0998802403762e-01 -198 74 -2.4734937343014e-01 -310 74 -1.8217263598046e-01 -319 74 2.2460375739663e-01 -199 75 1.3523538160650e-01 -311 75 -2.6274762743727e-01 -199 76 -1.3523538160650e-01 -200 76 2.0749736227062e-01 -312 76 -2.3858936340357e-01 -320 76 1.1648591138401e-01 -200 77 -2.0749736227062e-01 -201 77 2.9307085064937e-01 -313 77 -3.0076532990537e-01 -321 77 2.6340719075624e-01 -201 78 -2.9307085064937e-01 -202 78 3.0016859180739e-01 -314 78 -3.2048405269991e-01 -322 78 3.1268290639157e-01 -202 79 -3.0016859180739e-01 -203 79 2.7219739396643e-01 -315 79 -2.8135048353893e-01 -323 79 2.9301163843528e-01 -203 80 -2.7219739396643e-01 -204 80 2.8315376802648e-01 -316 80 -2.5067110560594e-01 -324 80 2.6232904628678e-01 -204 81 -2.8315376802648e-01 -205 81 3.1823831851795e-01 -317 81 -3.1129249734618e-01 -325 81 3.0772321845276e-01 -205 82 -3.1823831851795e-01 -206 82 3.1386451818410e-01 -318 82 -3.3301650575321e-01 -326 82 3.1101366962713e-01 -206 83 -3.1386451818410e-01 -207 83 2.3647090797091e-01 -319 83 -2.4128918754032e-01 -327 83 2.3205142437563e-01 -207 84 -2.3647090797091e-01 -208 85 2.1574760545568e-01 -320 85 -1.2581962693410e-01 -328 85 1.8900633364513e-01 -208 86 -2.1574760545568e-01 -209 86 3.0790911918009e-01 -321 86 -2.8451332937126e-01 -329 86 2.9643073766043e-01 -209 87 -3.0790911918009e-01 -210 87 3.3032344497883e-01 -322 87 -3.3773738097103e-01 -330 87 3.1872075468380e-01 -210 88 -3.3032344497883e-01 -211 88 3.0661339373328e-01 -323 88 -3.1648990506450e-01 -331 88 3.0195637814043e-01 -211 89 -3.0661339373328e-01 -212 89 3.1180727165326e-01 -324 89 -2.8334879596703e-01 -332 89 2.9253528930303e-01 -212 90 -3.1180727165326e-01 -213 90 3.2430356678224e-01 -325 90 -3.3238028603348e-01 -333 90 3.1301683612926e-01 -213 91 -3.2430356678224e-01 -214 91 2.4646422753283e-01 -326 91 -3.3593439257121e-01 -334 91 2.8062077342597e-01 -214 92 -2.4646422753283e-01 -327 92 -2.5064510632723e-01 -215 93 3.0121251054058e-01 -328 93 -2.0510202819789e-01 -335 93 2.9194220430986e-01 -215 94 -3.0121251054058e-01 -216 94 3.3384502123356e-01 -329 94 -3.2167464625024e-01 -336 94 3.3267668525417e-01 -216 95 -3.3384502123356e-01 -217 95 3.1384756991614e-01 -330 95 -3.4586287112023e-01 -337 95 3.1714694492401e-01 -217 96 -3.1384756991614e-01 -218 96 3.1214662415157e-01 -331 96 -3.2767084779377e-01 -338 96 2.8689034969695e-01 -218 97 -3.1214662415157e-01 -219 97 3.1884613706131e-01 -332 97 -3.1744746325890e-01 -339 97 3.0729769882796e-01 -219 98 -3.1884613706131e-01 -220 98 2.9027714707103e-01 -333 98 -3.3967320942133e-01 -340 98 2.8013574456061e-01 -220 99 -2.9027714707103e-01 -334 99 -3.0451831255663e-01 -341 99 2.3452750533748e-01 -221 100 3.1104107390269e-01 -342 100 2.8975450057068e-01 -221 101 -3.1104107390269e-01 -222 101 3.5331719555291e-01 -335 101 -3.1805724416657e-01 -343 101 3.4125946511723e-01 -222 102 -3.5331719555291e-01 -223 102 3.4417650094110e-01 -336 102 -3.6243553740557e-01 -344 102 2.8618462812071e-01 -223 103 -3.4417650094110e-01 -224 103 3.1648173712373e-01 -337 103 -3.4551661873224e-01 -345 103 3.2608093721956e-01 -224 104 -3.1648173712373e-01 -225 104 3.0679739376667e-01 -338 104 -3.1255348714757e-01 -346 104 2.9632018478180e-01 -225 105 -3.0679739376667e-01 -226 105 2.9079421505946e-01 -339 105 -3.3478633025670e-01 -347 105 2.9414790747695e-01 -226 106 -2.9079421505946e-01 -227 106 2.4169740958637e-01 -340 106 -3.0519466384836e-01 -348 106 2.7323686142172e-01 -227 107 -2.4169740958637e-01 -228 107 2.0504842010519e-01 -341 107 -2.5550664113548e-01 -349 107 2.4216521146197e-01 -228 108 -2.0504842010519e-01 -350 108 1.8886311898917e-01 -229 109 2.5697379235389e-01 -351 109 1.1364029032608e-01 -229 110 -2.5697379235389e-01 -230 110 3.5194790601286e-01 -342 110 -3.1672607637050e-01 -352 110 3.2191373504816e-01 -230 111 -3.5194790601286e-01 -231 111 2.9639845873140e-01 -343 111 -3.7302534110082e-01 -353 111 2.6538723791096e-01 -231 112 -2.9639845873140e-01 -232 112 2.8873350923462e-01 -344 112 -3.1282390507723e-01 -232 113 -2.8873350923462e-01 -233 113 3.3508646443864e-01 -345 113 -3.5643393155707e-01 -354 113 2.9517933393996e-01 -233 114 -3.3508646443864e-01 -234 114 3.0956485664500e-01 -346 114 -3.2390292226859e-01 -355 114 3.2719136111752e-01 -234 115 -3.0956485664500e-01 -235 115 3.0256938542762e-01 -347 115 -3.2152844019429e-01 -356 115 2.6724903345295e-01 -235 116 -3.0256938542762e-01 -236 116 2.9912332311749e-01 -348 116 -2.9867090543010e-01 -357 116 2.7026794478080e-01 -236 117 -2.9912332311749e-01 -237 117 2.4990404541487e-01 -349 117 -2.6470697472763e-01 -358 117 2.6398227434690e-01 -237 118 -2.4990404541487e-01 -350 118 -2.0644329779424e-01 -238 119 2.4634257093659e-01 -351 119 -1.2456494835979e-01 -359 119 1.1063378194732e-01 -238 120 -2.4634257093659e-01 -239 120 2.4557188837902e-01 -352 120 -3.5286048343876e-01 -360 120 2.5609766026744e-01 -239 121 -2.4557188837902e-01 -353 121 -2.9089988674677e-01 -240 122 3.1369746041338e-01 -354 122 -3.2355600626858e-01 -240 123 -3.1369746041338e-01 -241 123 3.1511856950614e-01 -355 123 -3.5864546706477e-01 -361 123 2.9675210602434e-01 -241 124 -3.1511856950614e-01 -242 124 2.5215500196100e-01 -356 124 -2.9294066352479e-01 -362 124 2.2730433925327e-01 -242 125 -2.5215500196100e-01 -243 125 2.5295915517268e-01 -357 125 -2.9624979387439e-01 -243 126 -2.5295915517268e-01 -358 126 -2.8935985888075e-01 -244 127 1.4384379164060e-01 -359 127 -1.2155098560242e-01 -244 128 -1.4384379164060e-01 -360 128 -2.8136905805863e-01 -245 129 2.2091193063941e-01 -361 129 -3.2603523383146e-01 -245 130 -2.2091193063941e-01 -362 130 -2.4973444802870e-01 -246 131 1.9728317431352e-03 -247 131 6.9856107791924e-04 -248 131 7.9251199913931e-04 -246 132 2.1017546499047e-03 -248 132 6.3537045392035e-04 -249 132 6.8139669391192e-04 -247 133 -6.1775748500427e-04 -250 133 -2.0549452401837e-03 -251 133 -2.0105852808203e-03 -247 134 -5.9741807526187e-04 -248 134 -6.7776606529239e-04 -251 134 -2.0294652224793e-03 -252 134 -2.0336813664884e-03 -248 135 -6.9279474555165e-04 -249 135 -7.4298080161848e-04 -252 135 -2.0207481271866e-03 -253 135 -2.0011067655784e-03 -249 136 -7.0807448389322e-04 -253 136 -2.0271576625603e-03 -254 136 -2.0375197646483e-03 -255 137 -4.7242030561448e-03 -256 137 -4.7139828695702e-03 -250 138 -3.3800031123132e-03 -256 138 -4.7399008865957e-03 -257 138 -4.7546533832281e-03 -250 139 -3.3734260283026e-03 -251 139 -3.4134682624579e-03 -257 139 -4.7649810580514e-03 -258 139 -4.7224994539142e-03 -251 140 -3.3946100151375e-03 -252 140 -3.3907435646859e-03 -258 140 -4.7360447039778e-03 -259 140 -4.7165409029822e-03 -252 141 -3.3695582027725e-03 -253 141 -3.3862933516686e-03 -259 141 -4.7344563590043e-03 -260 141 -4.7582120754946e-03 -253 142 -3.3980340354524e-03 -254 142 -3.3885167108877e-03 -260 142 -4.7445630944389e-03 -261 142 -4.8212755553691e-03 -254 143 -3.5880918325072e-03 -261 143 -4.7078193003237e-03 -255 144 -6.0478818296921e-03 -256 144 -6.0483232225887e-03 -262 144 -7.3309631902234e-03 -263 144 -7.3482425540405e-03 -256 145 -6.0695313823997e-03 -257 145 -6.0555041465254e-03 -263 145 -7.3310530027921e-03 -264 145 -7.3995490809672e-03 -257 146 -6.0402937541300e-03 -258 146 -6.0785067754902e-03 -264 146 -7.4465295505038e-03 -265 146 -7.3269744094594e-03 -258 147 -6.0375685298858e-03 -259 147 -6.0541496228191e-03 -265 147 -7.3684475022482e-03 -266 147 -7.3492755672236e-03 -259 148 -6.0727925562264e-03 -260 148 -6.0504480029790e-03 -266 148 -7.3342039251743e-03 -267 148 -7.3935535465318e-03 -260 149 -6.1361369572858e-03 -261 149 -6.0583999007374e-03 -267 149 -7.3279754928342e-03 -268 149 -7.4080768302097e-03 -269 150 -9.7984631450170e-03 -270 150 -9.7920509630917e-03 -262 151 -8.5848353233091e-03 -270 151 -9.7985110246030e-03 -271 151 -9.7900948261514e-03 -262 152 -8.5952935673211e-03 -263 152 -8.5799695578306e-03 -271 152 -9.7862087063027e-03 -272 152 -9.8121076338584e-03 -263 153 -8.6411582301488e-03 -264 153 -8.5789260416926e-03 -272 153 -9.7890182681274e-03 -273 153 -9.8559227427435e-03 -264 154 -8.5777503709045e-03 -265 154 -8.6789329351710e-03 -273 154 -9.8907330047400e-03 -274 154 -9.7861172346674e-03 -265 155 -8.5957465047369e-03 -266 155 -8.6145813607985e-03 -274 155 -9.8210739919117e-03 -275 155 -9.7930823668607e-03 -266 156 -8.6366945612071e-03 -267 156 -8.5812872450912e-03 -275 156 -9.7869336027116e-03 -276 156 -9.8105250364786e-03 -267 157 -8.6471297129987e-03 -268 157 -8.5775003421375e-03 -276 157 -9.7895568156891e-03 -277 157 -9.8289418507043e-03 -269 158 -1.0963790611681e-02 -278 158 -1.2207211150118e-02 -279 158 -1.2063499237174e-02 -269 159 -1.0957231731269e-02 -270 159 -1.0957985505898e-02 -279 159 -1.2087967291670e-02 -280 159 -1.2088085484709e-02 -270 160 -1.0949986475332e-02 -271 160 -1.0957502702740e-02 -280 160 -1.2110228475686e-02 -281 160 -1.2074321656703e-02 -271 161 -1.0969396816120e-02 -272 161 -1.0947718045680e-02 -281 161 -1.2064400645042e-02 -282 161 -1.2087956499735e-02 -272 162 -1.1003660117185e-02 -273 162 -1.0957717461839e-02 -282 162 -1.2066952327660e-02 -283 162 -1.2135066892666e-02 -273 163 -1.0950654823363e-02 -274 163 -1.1035205481025e-02 -283 163 -1.2111038108518e-02 -284 163 -1.2083953417382e-02 -274 164 -1.0951989636394e-02 -275 164 -1.0978351815563e-02 -284 164 -1.2218404280388e-02 -285 164 -1.2098882720795e-02 -275 165 -1.0968126625110e-02 -276 165 -1.0947708732704e-02 -285 165 -1.2113467885502e-02 -286 165 -1.2112830920185e-02 -276 166 -1.0982275174975e-02 -277 166 -1.0956753178020e-02 -286 166 -1.2061214550631e-02 -287 166 -1.2086161381243e-02 -277 167 -1.1279069267114e-02 -287 167 -1.2350223848775e-02 -288 167 -1.2156210430612e-02 -278 168 -1.3133909526278e-02 -279 168 -1.3236758919715e-02 -289 168 -1.4811597986188e-02 -290 168 -1.4125406979020e-02 -279 169 -1.3145705700350e-02 -280 169 -1.3145585306663e-02 -290 169 -1.4140636031234e-02 -291 169 -1.4138834734089e-02 -280 170 -1.3131408954368e-02 -281 170 -1.3167657238554e-02 -291 170 -1.4154796515141e-02 -292 170 -1.4125621940340e-02 -281 171 -1.3143905827332e-02 -282 171 -1.3121597442955e-02 -292 171 -1.4136575727972e-02 -293 171 -1.4141153932662e-02 -282 172 -1.3178394897771e-02 -283 172 -1.3136064651122e-02 -293 172 -1.4126093123575e-02 -294 172 -1.4147001969150e-02 -283 173 -1.3142086866186e-02 -284 173 -1.3170171486360e-02 -294 173 -1.4143702713512e-02 -295 173 -1.4141123166526e-02 -284 174 -1.3166178674358e-02 -285 174 -1.3300946214953e-02 -295 174 -1.4143712736313e-02 -296 174 -1.4180631608356e-02 -285 175 -1.3176321122221e-02 -286 175 -1.3177012954164e-02 -296 175 -1.4310920198823e-02 -297 175 -1.4188770845907e-02 -286 176 -1.3141817034401e-02 -287 176 -1.3118981837026e-02 -297 176 -1.4244538614832e-02 -298 176 -1.4128700559453e-02 -287 177 -1.3166490940790e-02 -288 177 -1.3564652162220e-02 -298 177 -1.4137108348028e-02 -299 177 -1.4162111322740e-02 -289 178 -1.5099099250674e-02 -290 178 -1.5628202493353e-02 -300 178 -1.5992634720472e-02 -290 179 -1.5087006662633e-02 -291 179 -1.5088788317954e-02 -300 179 -1.6614491592512e-02 -301 179 -1.6018792358445e-02 -291 180 -1.5074068313771e-02 -292 180 -1.5101654298306e-02 -301 180 -1.6067766913482e-02 -302 180 -1.5972680464071e-02 -292 181 -1.5089230980965e-02 -293 181 -1.5084723257567e-02 -302 181 -1.5981199469683e-02 -303 181 -1.6002302954640e-02 -293 182 -1.5092692290745e-02 -294 182 -1.5078370001794e-02 -303 182 -1.5991101504950e-02 -304 182 -1.5993514116271e-02 -294 183 -1.5087106695518e-02 -295 183 -1.5100531356694e-02 -304 183 -1.5968042913548e-02 -305 183 -1.5982579483982e-02 -295 184 -1.5131925118591e-02 -296 184 -1.5093395848797e-02 -305 184 -1.6054565687096e-02 -306 184 -1.6009731373750e-02 -296 185 -1.5167629639734e-02 -297 185 -1.5313911467844e-02 -306 185 -1.5968012014033e-02 -307 185 -1.5975964166117e-02 -297 186 -1.5076606200159e-02 -298 186 -1.5192192924357e-02 -307 186 -1.6254344832012e-02 -308 186 -1.5980088003370e-02 -298 187 -1.5103723583835e-02 -299 187 -1.5095271858238e-02 -308 187 -1.5969672914008e-02 -309 187 -1.5969498083167e-02 -299 188 -1.5182989318407e-02 -309 188 -1.6162618332853e-02 -310 188 -1.6943180571846e-02 -300 189 -1.6921845499249e-02 -301 189 -1.7676994043793e-02 -301 190 -1.6810585302450e-02 -302 190 -1.6906652872301e-02 -311 190 -1.7940280714919e-02 -302 191 -1.6841201127855e-02 -303 191 -1.6819649663111e-02 -311 191 -1.8114749744180e-02 -312 191 -1.8617336564398e-02 -303 192 -1.6832710349928e-02 -304 192 -1.6830219819518e-02 -312 192 -1.8523449826292e-02 -313 192 -1.7665513865540e-02 -304 193 -1.6819082332512e-02 -305 193 -1.6808182726985e-02 -313 193 -1.7690027578274e-02 -314 193 -1.7606136273500e-02 -305 194 -1.6834970750185e-02 -306 194 -1.6924804273294e-02 -314 194 -1.7600330845891e-02 -315 194 -1.7669788342614e-02 -306 195 -1.6813539668740e-02 -307 195 -1.6806262490319e-02 -315 195 -1.7616449470477e-02 -316 195 -1.7621635573690e-02 -307 196 -1.6844510892189e-02 -308 196 -1.7028055885310e-02 -316 196 -1.7761139305214e-02 -317 196 -1.7641935225225e-02 -308 197 -1.6807614160346e-02 -309 197 -1.6807771526530e-02 -317 197 -1.7631377929719e-02 -318 197 -1.7589683399698e-02 -309 198 -1.7224460499764e-02 -310 198 -1.7476645915395e-02 -318 198 -1.7957751444323e-02 -319 198 -1.7712210101373e-02 -311 199 -2.2768258591630e-02 -312 199 -2.1568400795210e-02 -320 199 -1.9264390988390e-02 -312 200 -1.8552519339984e-02 -313 200 -1.9735126615081e-02 -320 200 -2.2458954590065e-02 -321 200 -1.9468063694578e-02 -313 201 -1.8339558880280e-02 -314 201 -1.8429116283725e-02 -321 201 -1.9146637880653e-02 -322 201 -1.9022070743806e-02 -314 202 -1.8386665093694e-02 -315 202 -1.8339876932493e-02 -322 202 -1.9005877725085e-02 -323 202 -1.9016803559754e-02 -315 203 -1.8345949954127e-02 -316 203 -1.8357450808276e-02 -323 203 -1.9030881991553e-02 -324 203 -1.9028413763319e-02 -316 204 -1.8417455518062e-02 -317 204 -1.8439996767919e-02 -324 204 -1.9083851702276e-02 -325 204 -1.9041973717467e-02 -317 205 -1.8320965936641e-02 -318 205 -1.8359149298318e-02 -325 205 -1.9025094346906e-02 -326 205 -1.9015898676243e-02 -318 206 -1.8377301800695e-02 -319 206 -1.8867819960584e-02 -326 206 -1.9007154199139e-02 -327 206 -1.9976829385277e-02 -319 207 -1.8335108972714e-02 -327 207 -1.9012930175404e-02 -320 208 -2.2386213143942e-02 -321 208 -2.0473993150001e-02 -328 208 -2.0429504015305e-02 -329 208 -2.1153673098602e-02 -321 209 -1.9670349453766e-02 -322 209 -1.9744969383580e-02 -329 209 -2.0240367118332e-02 -330 209 -2.0217544871201e-02 -322 210 -1.9644512586596e-02 -323 210 -1.9637974303534e-02 -330 210 -2.0238076466689e-02 -331 210 -2.0321831611897e-02 -323 211 -1.9652422244129e-02 -324 211 -1.9670205205463e-02 -331 211 -2.0221800678159e-02 -332 211 -2.0250632088177e-02 -324 212 -1.9693931667653e-02 -325 212 -1.9692398593922e-02 -332 212 -2.0274157092454e-02 -333 212 -2.0214223752962e-02 -325 213 -1.9646344391630e-02 -326 213 -1.9655813365535e-02 -333 213 -2.0237742758141e-02 -334 213 -2.0467669471536e-02 -326 214 -2.0677279736099e-02 -327 214 -1.9640826528704e-02 -334 214 -2.0349271354998e-02 -328 215 -2.2202272439947e-02 -329 215 -2.0814066750059e-02 -335 215 -2.1264565894731e-02 -336 215 -2.1328156283991e-02 -329 216 -2.0757028902068e-02 -330 216 -2.0774376834719e-02 -336 216 -2.1247738392389e-02 -337 216 -2.1286914410688e-02 -330 217 -2.0875324926931e-02 -331 217 -2.0782672090035e-02 -337 217 -2.1245461733705e-02 -338 217 -2.1353819802451e-02 -331 218 -2.0789242592128e-02 -332 218 -2.0759566215865e-02 -338 218 -2.1342459087916e-02 -339 218 -2.1253090275256e-02 -332 219 -2.0751353961338e-02 -333 219 -2.0810153884880e-02 -339 219 -2.1269978759942e-02 -340 219 -2.1455750224748e-02 -333 220 -2.1049704869965e-02 -334 220 -2.0788435042524e-02 -340 220 -2.1268639739171e-02 -341 220 -2.1782680713500e-02 -335 221 -2.1711364740604e-02 -342 221 -2.2187537649084e-02 -343 221 -2.2194438852950e-02 -335 222 -2.1798257126547e-02 -336 222 -2.1713701022417e-02 -343 222 -2.2138055939386e-02 -344 222 -2.2653008672599e-02 -336 223 -2.1741359702095e-02 -337 223 -2.1702123643759e-02 -344 223 -2.2532362445328e-02 -345 223 -2.2160833664848e-02 -337 224 -2.1803877069219e-02 -338 224 -2.1700091531592e-02 -345 224 -2.2121721231640e-02 -346 224 -2.2178860527325e-02 -338 225 -2.1708905979591e-02 -339 225 -2.1802879895215e-02 -346 225 -2.2138079028525e-02 -347 225 -2.2145801080232e-02 -339 226 -2.1947547929219e-02 -340 226 -2.1736982453316e-02 -347 226 -2.2116970578317e-02 -348 226 -2.2173122147155e-02 -340 227 -2.2345377142270e-02 -341 227 -2.1746708086130e-02 -348 227 -2.2259876865378e-02 -349 227 -2.2117457270514e-02 -341 228 -2.2276639032371e-02 -349 228 -2.2391319831000e-02 -350 228 -2.2209010470150e-02 -342 229 -2.3031192948706e-02 -351 229 -3.1036565396689e-02 -352 229 -2.3392665536114e-02 -342 230 -2.2605263599959e-02 -343 230 -2.2547996032506e-02 -352 230 -2.2953936867909e-02 -353 230 -2.3812177616085e-02 -343 231 -2.3139034222770e-02 -344 231 -2.2541890331203e-02 -353 231 -2.3006217004607e-02 -344 232 -2.2586225024929e-02 -345 232 -2.3039010003142e-02 -354 232 -2.2850000465831e-02 -345 233 -2.2553508646577e-02 -346 233 -2.2506095574222e-02 -354 233 -2.3053220078321e-02 -355 233 -2.2858573485030e-02 -346 234 -2.2530641080911e-02 -347 234 -2.2522410465275e-02 -355 234 -2.2873925060540e-02 -356 234 -2.3119933498266e-02 -347 235 -2.2551970235518e-02 -348 235 -2.2498848538416e-02 -356 235 -2.3045080081472e-02 -357 235 -2.3012708559401e-02 -348 236 -2.2499070332828e-02 -349 236 -2.2645272939780e-02 -357 236 -2.2982688222153e-02 -358 236 -2.3047630634916e-02 -349 237 -2.2547080153426e-02 -350 237 -2.2876153721564e-02 -358 237 -2.2873299385024e-02 -351 238 -2.8652695999957e-02 -352 238 -2.4734234858025e-02 -359 238 -3.1505406094690e-02 -360 238 -2.3469166553793e-02 -352 239 -2.4761513636274e-02 -353 239 -2.3525533566828e-02 -360 239 -2.3471702861440e-02 -354 240 -2.3182320124702e-02 -355 240 -2.3394935135128e-02 -361 240 -2.3500720063575e-02 -355 241 -2.3380417879601e-02 -356 241 -2.3217150216752e-02 -361 241 -2.3507477492065e-02 -362 241 -2.4765539927519e-02 -356 242 -2.3450242310157e-02 -357 242 -2.3492609487996e-02 -362 242 -2.3597608323347e-02 -357 243 -2.3480299424824e-02 -358 243 -2.3396694069705e-02 -359 244 -2.4037061235891e-02 -360 244 -2.9354762384126e-02 -361 245 -2.5591333590874e-02 -362 245 -2.3915340143662e-02 diff --git a/CHOLMOD/Tcov/Matrix/r5up b/CHOLMOD/Tcov/Matrix/r5up deleted file mode 100644 index 5de0efcf83..0000000000 --- a/CHOLMOD/Tcov/Matrix/r5up +++ /dev/null @@ -1,11 +0,0 @@ -5 5 10 1 0 -0 0 2.43872 -1 1 4.21742 -0 2 0.724062 -1 2 1.69463 -2 2 4.77818 -1 3 1.23492 -2 3 0.902819 -3 3 3.51267 -0 4 0.281634 -4 4 6.25922 diff --git a/CHOLMOD/Tcov/Matrix/r5up2 b/CHOLMOD/Tcov/Matrix/r5up2 deleted file mode 100644 index c6250ce199..0000000000 --- a/CHOLMOD/Tcov/Matrix/r5up2 +++ /dev/null @@ -1,11 +0,0 @@ -5 5 10 1 0 -0 0 2.43872 -1 1 4.21742 -2 0 0.724062 -1 2 1.69463 -2 2 4.77818 -1 3 1.23492 -2 3 0.902819 -3 3 3.51267 -0 4 0.281634 -4 4 6.25922 diff --git a/CHOLMOD/Tcov/Matrix/tribig b/CHOLMOD/Tcov/Matrix/tribig deleted file mode 100644 index bae68467cd..0000000000 --- a/CHOLMOD/Tcov/Matrix/tribig +++ /dev/null @@ -1 +0,0 @@ -1000000 1000000 0 3 diff --git a/CHOLMOD/Tcov/Matrix/write.tri b/CHOLMOD/Tcov/Matrix/write.tri new file mode 100644 index 0000000000..3993588b9a --- /dev/null +++ b/CHOLMOD/Tcov/Matrix/write.tri @@ -0,0 +1,8 @@ +7 7 7 1 +0 0 1.01e-05 +1 1 2.01e-05 +2 2 2.01e-05 +3 3 2.01e-05 +4 4 2.01e-05 +5 5 2.01e-05 +6 6 2.01e-05 diff --git a/CHOLMOD/Tcov/Matrix/z30up b/CHOLMOD/Tcov/Matrix/z30up deleted file mode 100644 index 0a88cb92a4..0000000000 --- a/CHOLMOD/Tcov/Matrix/z30up +++ /dev/null @@ -1,115 +0,0 @@ -30 30 114 1 2 -0 0 4.98585 0 -1 1 2.80724 0 -2 2 6.14737 0 -3 3 6.78061 0 -4 4 5.13451 0 -1 5 0.254769 -0.397184 -4 5 0.640815 -0.511311 -5 5 2.14374 0 -0 6 0.121047 -0.335197 -1 6 0.170793 0.700635 -6 6 6.06059 0 -7 7 5.05057 0 -2 8 0.239313 -0.594663 -8 8 5.50746 0 -0 9 0.450754 -0.655531 -9 9 2.46098 0 -1 10 0.865603 -0.413629 -10 10 4.12445 0 -10 11 0.934237 0.999447 -11 11 3.87788 0 -0 12 0.23788 0.548513 -5 12 0.645831 0.26177 -6 12 0.994295 -0.982709 -8 12 0.314217 -0.484964 -12 12 2.83077 0 -4 13 0.870381 0.571057 -6 13 0.0099273 0.700857 -8 13 0.365078 -0.114613 -9 13 0.13701 0.962288 -13 13 6.16576 0 -0 14 0.734908 0.634266 -5 14 0.843869 -0.489345 -13 14 0.818756 -0.750518 -14 14 6.1932 0 -12 15 1.13292 0.348118 -13 15 0.430166 -0.739993 -15 15 4.25807 0 -11 16 0.264449 -0.961636 -16 16 6.78301 0 -5 17 0.1739 -0.185904 -6 17 0.422452 0.253561 -11 17 0.855976 0.873451 -17 17 3.71627 0 -1 18 0.23235 -0.655213 -8 18 0.457354 0.96137 -11 18 0.450689 0.0720592 -13 18 0.412219 0.553408 -16 18 0.90161 0.291984 -17 18 0.815935 -0.732651 -18 18 6.34966 0 -0 19 0.0491625 0.680204 -9 19 0.591525 -0.365374 -11 19 0.1603 -0.0588622 -19 19 5.84718 0 -0 20 0.982988 0.498305 -5 20 0.552673 0.434441 -6 20 0.439791 -0.806638 -8 20 0.400074 0.562458 -9 20 0.119747 -0.140044 -10 20 0.198789 0.616621 -14 20 0.687324 -0.803026 -18 20 0.625201 0.11334 -20 20 4.22081 0 -1 21 0.804872 -0.837585 -7 21 0.375885 0.754551 -18 21 0.00558394 -0.857964 -20 21 0.00987646 0.791123 -21 21 5.1031 0 -9 22 0.0381288 -0.566773 -10 22 0.458598 -0.823008 -16 22 0.191116 -0.601987 -19 22 0.69318 -0.0534444 -21 22 0.75367 0.670004 -22 22 6.75845 0 -2 23 0.0497545 -0.565739 -5 23 0.919957 0.273088 -12 23 0.664931 -0.049278 -13 23 0.844722 0.626235 -15 23 0.367753 0.536852 -23 23 5.20005 0 -0 24 0.715883 -0.391904 -1 24 0.908398 -0.371608 -21 24 0.419858 -0.814952 -23 24 0.620801 -0.0595041 -24 24 3.23664 0 -0 25 0.892842 -0.627315 -6 25 0.340048 -0.703568 -9 25 0.731277 0.0889618 -11 25 0.872855 -0.360311 -18 25 0.297406 -0.335755 -25 25 3.76351 0 -1 26 0.231894 -0.425253 -8 26 0.39324 -0.664856 -10 26 0.869867 -0.673949 -13 26 0.193893 0.271308 -14 26 0.346112 -0.083881 -18 26 0.904812 0.409072 -19 26 0.650106 -0.356656 -26 26 2.9393 0 -0 27 0.273102 -0.69908 -15 27 0.155613 -0.915942 -22 27 0.793872 -0.200876 -27 27 4.45322 0 -4 28 0.190887 -0.776401 -5 28 0.569206 0.474041 -11 28 0.63179 0.908989 -13 28 0.890322 -0.431873 -17 28 0.46077 -0.422227 -28 28 4.04637 0 -12 29 0.234413 0.596247 -13 29 0.548782 0.328955 -20 29 0.733363 -0.898252 -25 29 0.931583 0.478194 -29 29 4.31763 0 diff --git a/CHOLMOD/Tcov/Matrix/z3singular b/CHOLMOD/Tcov/Matrix/z3singular deleted file mode 100644 index e06bcfd2f1..0000000000 --- a/CHOLMOD/Tcov/Matrix/z3singular +++ /dev/null @@ -1,5 +0,0 @@ -3 3 4 1 2 -0 0 9.4423471389861624e-01 0.1 -0 1 8.3855545301913648e-01 0.2 -1 1 4.2898125196177306e-02 0.03 -1 2 5.7441796740690909e-01 0.04 diff --git a/CHOLMOD/Tcov/Matrix/z5lo b/CHOLMOD/Tcov/Matrix/z5lo deleted file mode 100644 index 1dcfa832b8..0000000000 --- a/CHOLMOD/Tcov/Matrix/z5lo +++ /dev/null @@ -1,12 +0,0 @@ -5 5 11 -1 2 -0 0 2.43872 0 -1 0 0.261819 -0.16627 -2 0 0.724062 0.804517 -4 0 0.281634 0.828864 -1 1 4.21742 0 -2 1 1.69463 -0.324218 -3 1 1.23492 0.0754504 -2 2 4.77818 0 -3 2 0.902819 0.460806 -3 3 3.51267 0 -4 4 6.25922 0 diff --git a/CHOLMOD/Tcov/Matrix/z5up2 b/CHOLMOD/Tcov/Matrix/z5up2 deleted file mode 100644 index 8900257b4f..0000000000 --- a/CHOLMOD/Tcov/Matrix/z5up2 +++ /dev/null @@ -1,12 +0,0 @@ -5 5 11 1 2 -0 0 2.43872 0 -0 1 0.261819 0.16627 -1 1 4.21742 0 -2 0 0.724062 -0.804517 -1 2 1.69463 0.324218 -2 2 4.77818 0 -1 3 1.23492 -0.0754504 -2 3 0.902819 -0.460806 -3 3 3.51267 0 -0 4 0.281634 -0.828864 -4 4 6.25922 0 diff --git a/CHOLMOD/Tcov/README.txt b/CHOLMOD/Tcov/README.txt index 09b109690c..966cde688b 100644 --- a/CHOLMOD/Tcov/README.txt +++ b/CHOLMOD/Tcov/README.txt @@ -2,47 +2,30 @@ Tcov directory: Torture test for CHOLMOD, with statement coverage. http://www.suitesparse.com -------------------------------------------------------------------------------- -This test suite is not required to compile and use CHOLMOD. It is thus -not ported to all architectures. Linux is required. +This test suite is not required to compile and use CHOLMOD. It is thus not +ported to all architectures. Linux is required, and a recent version of +gcc (with the -fprofile-abs-path option). -Requires all CHOLMOD modules except the Partition Module, which it can -optionally use (and test). Also acts as a statement coverage test for -AMD, COLAMD, and CCOLAMD. +Requires all CHOLMOD modules: AMD, CAMD, COLAMD, CCOLAMD, and +SuiteSparse_config. This test acts as a full statement coverage test for all +of these packages. Type "make" in this directory to compile CHOLMOMD with statement coverage testing, and to run the tests. Type ./go to test the GPU. -Note that about 500MB of disk space is required, mostly in the -CHOLMOD_TCOV_TMP directory. - -(Nearly) every line of AMD, CAMD, COLAMD, CCOLAMD, and CHOLMOD will be exercised, -and their results checked. The line "All tests passed" should be -printed for each test on stderr. Some matrices will report NaN as their -maximum error; these are the four singular test matrices (Matrix/1_0, -Matrix/3singular, Matrix/c3singluar, and Matrix/z3singular). These test -results are expected. Nan's appear in CHOLMOD_TCOV_TMP/galenet_nan.out -and CHOLMOD_TCOV_TMP/l_galenet_nan.out; these are generated intentionally, -to test the code's NaN-handling features. +Every line of CHOLMOD, AMD, CAMD, COLAMD, CCOLAMD, and SuiteSparse_config will +be exercised, and their results checked. Some matrices will report NaN as +their maximum error (Matrix/c30lo_singular and Matrix/cza for example). These +test results are expected (see the -s flag on the test input commands). Note that many, many error messages will appear in the test output itself -(CHOLMOD_TCOV_TMP/*.out), because all of CHOLMOD's error handling is -checked as well. These errors are expected. Any unexpected error will cause -the test to fail. The last line of each output file should be "All tests -successful". - -To remove all but the original source files type "make clean". +(../build/T/*.out), because all of CHOLMOD's error handling is checked as well. +These errors are expected. Any unexpected error will cause the test to fail. +The last line of each output file should be "All tests passed", and each test +prints "Test OK" or "Test FAIL" on stderr. If any tests pass, the 'make' will +halt on that test. -On the Mac (OSX 10.6.1, Snow Leopard), you may see errors like this: +This test takes about 20 to 25 minutes. - cl(32662) malloc: *** mmap(size=121600000000000) failed (error code=12) - *** error: can't allocate region - *** set a breakpoint in malloc_error_break to debug - - That is not an error. The test code is rigorously testing the CHOLMOD - memory management wrappers, by trying to allocate a huge amount of space - with the expectation that it must fail. This to ensure the memory - management routines properly handle that case. For some reason unknown to - me, the Mac "malloc" function feels the need to print an error on stdout - when attempting to malloc something too big. It should simply and quietly - return a NULL instead, as Linux does. Thus, ignore these errors. +To remove all but the original source files type "make clean". diff --git a/CHOLMOD/Tcov/amdtest.c b/CHOLMOD/Tcov/amdtest.c deleted file mode 100644 index 4301193103..0000000000 --- a/CHOLMOD/Tcov/amdtest.c +++ /dev/null @@ -1,378 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/amdtest: test coverage of AMD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test for amd v2.0 */ - -#undef ASSERT -#include "amd.h" -#include "amd_internal.h" -#undef FLIP -#undef UNFLIP -#undef ASSERT -#include "cm.h" - - -/* ========================================================================== */ -/* === amdtest ============================================================== */ -/* ========================================================================== */ - -void amdtest (cholmod_sparse *A) -{ - double Control [AMD_CONTROL], Info [AMD_INFO], alpha ; - Int *P, *Cp, *Ci, *Sp, *Si, *Bp, *Bi, *Ep, *Ei, *Fp, *Fi, - *Len, *Nv, *Next, *Head, *Elen, *Deg, *Wi, *W, *Flag ; - cholmod_sparse *C, *B, *S, *E, *F ; - Int i, j, n, nrow, ncol, ok, cnz, bnz, p, trial, sorted ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - printf ("\nAMD test\n") ; - - if (A == NULL) - { - return ; - } - - if (A->stype) - { - B = CHOLMOD(copy) (A, 0, 0, cm) ; - } - else - { - B = CHOLMOD(aat) (A, NULL, 0, 0, cm) ; - } - - if (A->nrow != A->ncol) - { - F = CHOLMOD(copy_sparse) (B, cm) ; - OK (F->nrow == F->ncol) ; - CHOLMOD(sort) (F, cm) ; - } - else - { - /* A is square and unsymmetric, and may have entries in A+A' that - * are not in A */ - F = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sort) (F, cm) ; - } - - C = CHOLMOD(copy_sparse) (B, cm) ; - - nrow = C->nrow ; - ncol = C->ncol ; - n = nrow ; - OK (nrow == ncol) ; - - Cp = C->p ; - Ci = C->i ; - - Bp = B->p ; - Bi = B->i ; - - /* ---------------------------------------------------------------------- */ - /* S = sorted form of B, using AMD_preprocess */ - /* ---------------------------------------------------------------------- */ - - cnz = CHOLMOD(nnz) (C, cm) ; - S = CHOLMOD(allocate_sparse) (n, n, cnz, TRUE, TRUE, 0, CHOLMOD_PATTERN, - cm); - Sp = S->p ; - Si = S->i ; - - W = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Flag = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace for amd */ - /* ---------------------------------------------------------------------- */ - - P = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; - - Len = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Nv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Next = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Head = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; - Elen = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Deg = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Wi = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - - /* ---------------------------------------------------------------------- */ - - for (sorted = 0 ; sorted <= 1 ; sorted++) - { - - if (sorted) CHOLMOD(sort) (C, cm) ; - - Cp = C->p ; - Ci = C->i ; - - /* ------------------------------------------------------------------ */ - /* order C with AMD_order */ - /* ------------------------------------------------------------------ */ - - AMD_defaults (Control) ; - AMD_defaults (NULL) ; - AMD_control (Control) ; - AMD_control (NULL) ; - AMD_info (NULL) ; - - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; - - /* no dense rows/cols */ - alpha = Control [AMD_DENSE] ; - Control [AMD_DENSE] = -1 ; - AMD_control (Control) ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=-1)", cm)) ; - - /* many dense rows/cols */ - Control [AMD_DENSE] = 0 ; - AMD_control (Control) ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=0)", cm)) ; - Control [AMD_DENSE] = alpha ; - - /* no aggressive absorption */ - Control [AMD_AGGRESSIVE] = FALSE ; - AMD_control (Control) ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (no agg) ", cm)) ; - Control [AMD_AGGRESSIVE] = TRUE ; - - /* ------------------------------------------------------------------ */ - /* order F with AMD_order */ - /* ------------------------------------------------------------------ */ - - Fp = F->p ; - Fi = F->i ; - ok = AMD_order (n, Fp, Fi, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "F: AMD permutation", cm)) ; - - /* ------------------------------------------------------------------ */ - /* order S with AMD_order */ - /* ------------------------------------------------------------------ */ - - ok = AMD_order (n, Sp, Si, P, Control, Info) ; - printf ("amd return value: "ID"\n", ok) ; - AMD_info (Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; - - /* ------------------------------------------------------------------ */ - /* order E with AMD_2, which destroys its contents */ - /* ------------------------------------------------------------------ */ - - E = CHOLMOD(copy) (B, 0, -1, cm) ; /* remove diagonal entries */ - bnz = CHOLMOD(nnz) (E, cm) ; - - /* add the bare minimum extra space to E */ - ok = CHOLMOD(reallocate_sparse) (bnz + n, E, cm) ; - OK (ok) ; - Ep = E->p ; - Ei = E->i ; - - for (j = 0 ; j < n ; j++) - { - Len [j] = Ep [j+1] - Ep [j] ; - } - - printf ("calling AMD_2:\n") ; - if (n > 0) - { - AMD_2 (n, Ep, Ei, Len, E->nzmax, Ep [n], Nv, Next, P, Head, Elen, - Deg, Wi, Control, Info) ; - AMD_info (Info) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; - } - - /* ------------------------------------------------------------------ */ - /* error tests */ - /* ------------------------------------------------------------------ */ - - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - ok = AMD_order (-1, Cp, Ci, P, Control, Info) ; - OK (ok == AMD_INVALID); - ok = AMD_order (0, Cp, Ci, P, Control, Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - ok = AMD_order (n, NULL, Ci, P, Control, Info) ; - OK (ok == AMD_INVALID); - ok = AMD_order (n, Cp, NULL, P, Control, Info) ; - OK (ok == AMD_INVALID); - ok = AMD_order (n, Cp, Ci, NULL, Control, Info) ; - OK (ok == AMD_INVALID); - - if (n > 0) - { - printf ("AMD error tests:\n") ; - - p = Cp [n] ; - Cp [n] = -1 ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - OK (ok == AMD_INVALID) ; - - if (SIZE_MAX/2 == Int_max) - { - Cp [n] = Int_max ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - printf ("AMD status is "ID"\n", ok) ; - OK (ok == AMD_OUT_OF_MEMORY) ; - } - - Cp [n] = p ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - if (Cp [n] > 0) - { - printf ("Mangle column zero:\n") ; - i = Ci [0] ; - Ci [0] = -1 ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - AMD_info (Info) ; - OK (ok == AMD_INVALID) ; - Ci [0] = i ; - } - } - - ok = AMD_valid (n, n, Sp, Si) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - ok = AMD_valid (-1, n, Sp, Si) ; OK (ok == AMD_INVALID) ; - ok = AMD_valid (n, -1, Sp, Si) ; OK (ok == AMD_INVALID) ; - ok = AMD_valid (n, n, NULL, Si) ; OK (ok == AMD_INVALID) ; - ok = AMD_valid (n, n, Sp, NULL) ; OK (ok == AMD_INVALID) ; - - if (n > 0 && Sp [n] > 0) - { - - p = Sp [n] ; - Sp [n] = -1 ; - ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; - Sp [n] = p ; - - p = Sp [0] ; - Sp [0] = -1 ; - ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; - Sp [0] = p ; - - p = Sp [1] ; - Sp [1] = -1 ; - ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; - Sp [1] = p ; - - i = Si [0] ; - Si [0] = -1 ; - ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; - Si [0] = i ; - - } - - ok = AMD_valid (n, n, Sp, Si) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - ok = AMD_valid (n, n, Sp, Si) ; - OK (ok == AMD_OK) ; - - if (n > 0 && Bp [n] > 0) - { - - p = Bp [n] ; - Bp [n] = -1 ; - ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; - Bp [n] = p ; - - - p = Bp [1] ; - Bp [1] = -1 ; - ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; - Bp [1] = p ; - - i = Bi [0] ; - Bi [0] = -1 ; - ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; - Bi [0] = i ; - } - - AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - - Info [AMD_STATUS] = 777 ; - AMD_info (Info) ; - - /* ------------------------------------------------------------------ */ - /* memory tests */ - /* ------------------------------------------------------------------ */ - - if (n > 0) - { - - normal_memory_handler ( ) ; - - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; - - test_memory_handler ( ) ; - - for (trial = 0 ; trial < 6 ; trial++) - { - my_tries = trial ; - printf ("AMD memory trial "ID"\n", trial) ; - ok = AMD_order (n, Cp, Ci, P, Control, Info) ; - AMD_info (Info) ; - OK (ok == AMD_OUT_OF_MEMORY - || (sorted ? (ok == AMD_OK) : (ok >= AMD_OK))) ; - } - normal_memory_handler ( ) ; - OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; - - } - - CHOLMOD(free_sparse) (&E, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* free everything */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free) (n, sizeof (Int), Len, cm) ; - CHOLMOD(free) (n, sizeof (Int), Nv, cm) ; - CHOLMOD(free) (n, sizeof (Int), Next, cm) ; - CHOLMOD(free) (n+1, sizeof (Int), Head, cm) ; - CHOLMOD(free) (n, sizeof (Int), Elen, cm) ; - CHOLMOD(free) (n, sizeof (Int), Deg, cm) ; - CHOLMOD(free) (n, sizeof (Int), Wi, cm) ; - - CHOLMOD(free) (n+1, sizeof (Int), P, cm) ; - - CHOLMOD(free) (n, sizeof (Int), W, cm) ; - CHOLMOD(free) (n, sizeof (Int), Flag, cm) ; - - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&B, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; -} diff --git a/CHOLMOD/Tcov/aug.c b/CHOLMOD/Tcov/aug.c deleted file mode 100644 index f65137b703..0000000000 --- a/CHOLMOD/Tcov/aug.c +++ /dev/null @@ -1,240 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/aug: test with an augmented system -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Create the augmented system S = [-I A' ; A alpha*I], solve Sx=b, and return - * the residual. The system solved is (alpha*I + A*A')*x=b. - * - * r1 = norm (Sx-b) - * r2 = norm ((alpha*I+AA')x-b) - * alpha = norm(A) - */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === aug ================================================================== */ -/* ========================================================================== */ - -double aug (cholmod_sparse *A) -{ - double r, maxerr = 0, bnorm, anorm ; - cholmod_sparse *S, *Im, *In, *At, *A1, *A2, *Sup ; - cholmod_dense *Alpha, *B, *Baug, *X, *W1, *W2, *R, *X2, X2mat ; - cholmod_factor *L ; - double *b, *baug, *rx, *w, *x ; - Int nrow, ncol, nrhs, i, j, d, d2, save, save2, save3 ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "cm: no A for aug") ; - return (1) ; - } - - if (A->xtype != CHOLMOD_REAL) - { - return (0) ; - } - - /* ---------------------------------------------------------------------- */ - /* A is m-by-n, B must be m-by-nrhs */ - /* ---------------------------------------------------------------------- */ - - nrow = A->nrow ; - ncol = A->ncol ; - B = rhs (A, 5, A->nrow + 7) ; - - /* ---------------------------------------------------------------------- */ - /* create scalars */ - /* ---------------------------------------------------------------------- */ - - bnorm = CHOLMOD(norm_dense) (B, 0, cm) ; - anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; - - Alpha = CHOLMOD(eye) (1, 1, CHOLMOD_REAL, cm) ; - if (Alpha != NULL) - { - ((double *) (Alpha->x)) [0] = anorm ; - } - - CHOLMOD(print_dense) (M1, "MinusOne", cm) ; - CHOLMOD(print_dense) (Alpha, "Alpha = norm(A)", cm) ; - - /* ---------------------------------------------------------------------- */ - /* create augmented system, S = [-I A' ; A anorm*I] */ - /* ---------------------------------------------------------------------- */ - - Im = CHOLMOD(speye) (nrow, nrow, CHOLMOD_REAL, cm) ; - In = CHOLMOD(speye) (ncol, ncol, CHOLMOD_REAL, cm) ; - CHOLMOD(scale) (Alpha, CHOLMOD_SCALAR, Im, cm) ; - CHOLMOD(scale) (M1, CHOLMOD_SCALAR, In, cm) ; - At = CHOLMOD(transpose) (A, 2, cm) ; - - /* use one of two equivalent methods */ - if (nrow % 2) - { - /* S = [[-In A'] ; [A alpha*Im]] */ - A1 = CHOLMOD(horzcat) (In, At, TRUE, cm) ; - A2 = CHOLMOD(horzcat) (A, Im, TRUE, cm) ; - S = CHOLMOD(vertcat) (A1, A2, TRUE, cm) ; - } - else - { - /* S = [[-In ; A] [A' ; alpha*Im]] */ - A1 = CHOLMOD(vertcat) (In, A, TRUE, cm) ; - A2 = CHOLMOD(vertcat) (At, Im, TRUE, cm) ; - S = CHOLMOD(horzcat) (A1, A2, TRUE, cm) ; - } - - CHOLMOD(free_sparse) (&Im, cm) ; - CHOLMOD(free_sparse) (&In, cm) ; - - CHOLMOD(print_sparse) (S, "S, augmented system", cm) ; - - /* make a symmetric (upper) copy of S */ - Sup = CHOLMOD(copy) (S, 1, 1, cm) ; - - CHOLMOD(print_sparse) (S, "S, augmented system (upper)", cm) ; - CHOLMOD(print_sparse) (Sup, "Sup", cm) ; - - /* ---------------------------------------------------------------------- */ - /* create augmented right-hand-side, Baug = [ zeros(ncol,nrhs) ; B ] */ - /* ---------------------------------------------------------------------- */ - - b = NULL ; - d = 0 ; - nrhs = 0 ; - d2 = 0 ; - if (B != NULL) - { - nrhs = B->ncol ; - d = B->d ; - b = B->x ; - Baug = CHOLMOD(zeros) (nrow+ncol, nrhs, CHOLMOD_REAL, cm) ; - if (Baug != NULL) - { - d2 = Baug->d ; - baug = Baug->x ; - for (j = 0 ; j < nrhs ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - baug [(i+ncol)+j*d2] = b [i+j*d] ; - } - } - } - } - else - { - Baug = NULL ; - } - - /* ---------------------------------------------------------------------- */ - /* solve Sx=baug */ - /* ---------------------------------------------------------------------- */ - - /* S is symmetric indefinite, so do not use a supernodal LL' */ - save = cm->supernodal ; - save2 = cm->final_asis ; - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_asis = TRUE ; - save3 = cm->metis_memory ; - cm->metis_memory = 2.0 ; - L = CHOLMOD(analyze) (Sup, cm) ; - CHOLMOD(factorize) (Sup, L, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L, Baug, cm) ; - cm->supernodal = save ; - cm->final_asis = save2 ; - cm->metis_memory = save3 ; - - /* ---------------------------------------------------------------------- */ - /* compute the residual */ - /* ---------------------------------------------------------------------- */ - - r = resid (Sup, X, Baug) ; - MAXERR (maxerr, r, 1) ; - - /* ---------------------------------------------------------------------- */ - /* create a shallow submatrix of X, X2 = X (ncol:end, :) */ - /* ---------------------------------------------------------------------- */ - - if (X == NULL) - { - X2 = NULL ; - } - else - { - X2 = &X2mat ; - X2->nrow = nrow ; - X2->ncol = nrhs ; - X2->nzmax = X->nzmax ; - X2->d = X->d ; - X2->x = ((double *) X->x) + ncol ; - X2->z = NULL ; - X2->xtype = X->xtype ; - X2->dtype = X->dtype ; - } - - CHOLMOD(print_dense) (X, "X", cm) ; - CHOLMOD(print_dense) (X2, "X2 = X (ncol:end,:)", cm) ; - - /* ---------------------------------------------------------------------- */ - /* compute norm ((alpha*I + A*A')*x-b) */ - /* ---------------------------------------------------------------------- */ - - /* W1 = A'*X2 */ - W1 = CHOLMOD(zeros) (ncol, nrhs, CHOLMOD_REAL, cm) ; - CHOLMOD(sdmult) (A, TRUE, one, zero, X2, W1, cm) ; - - /* W2 = A*W1 */ - W2 = CHOLMOD(zeros) (nrow, nrhs, CHOLMOD_REAL, cm) ; - CHOLMOD(sdmult) (A, FALSE, one, zero, W1, W2, cm) ; - - /* R = alpha*x + w2 - b */ - R = CHOLMOD(zeros) (nrow, nrhs, CHOLMOD_REAL, cm) ; - - if (R != NULL && W2 != NULL && X != NULL) - { - w = W2->x ; - rx = R->x ; - x = X2->x ; - for (j = 0 ; j < nrhs ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - rx [i+j*nrow] = anorm * x [i+j*d2] + w [i+j*nrow] - b [i+j*d] ; - } - } - } - - r = CHOLMOD(norm_dense) (R, 1, cm) ; - MAXERR (maxerr, r, bnorm) ; - - /* ---------------------------------------------------------------------- */ - /* free everything */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free_sparse) (&At, cm) ; - CHOLMOD(free_sparse) (&A1, cm) ; - CHOLMOD(free_sparse) (&A2, cm) ; - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&Sup, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&R, cm) ; - CHOLMOD(free_dense) (&W1, cm) ; - CHOLMOD(free_dense) (&W2, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free_dense) (&Baug, cm) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Alpha, cm) ; - - progress (0, '.') ; - return (maxerr) ; -} diff --git a/CHOLMOD/Tcov/camdtest.c b/CHOLMOD/Tcov/camdtest.c deleted file mode 100644 index 6cde21e4a9..0000000000 --- a/CHOLMOD/Tcov/camdtest.c +++ /dev/null @@ -1,416 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/camdtest: test of CAMD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test for camd v2.0 */ - -#undef ASSERT -#include "cm.h" -#undef FLIP -#undef UNFLIP - -#undef ASSERT -#ifndef NCAMD -#include "camd.h" -#include "camd_internal.h" - -/* ========================================================================== */ -/* === camdtest ============================================================= */ -/* ========================================================================== */ - -void camdtest (cholmod_sparse *A) -{ - double Control [CAMD_CONTROL], Info [CAMD_INFO], alpha ; - Int *P, *Cp, *Ci, *Sp, *Si, *Bp, *Bi, *Ep, *Ei, *Fp, *Fi, - *Len, *Nv, *Next, *Head, *Elen, *Deg, *Wi, *W, *Flag, *BucketSet, - *Constraint ; - cholmod_sparse *C, *B, *S, *E, *F ; - Int i, j, n, nrow, ncol, ok, cnz, bnz, p, trial, sorted ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - printf ("\nCAMD test\n") ; - - if (A == NULL) - { - return ; - } - - if (A->stype) - { - B = CHOLMOD(copy) (A, 0, 0, cm) ; - } - else - { - B = CHOLMOD(aat) (A, NULL, 0, 0, cm) ; - } - - if (A->nrow != A->ncol) - { - F = CHOLMOD(copy_sparse) (B, cm) ; - OK (F->nrow == F->ncol) ; - CHOLMOD(sort) (F, cm) ; - } - else - { - /* A is square and unsymmetric, and may have entries in A+A' that - * are not in A */ - F = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sort) (F, cm) ; - } - - C = CHOLMOD(copy_sparse) (B, cm) ; - - nrow = C->nrow ; - ncol = C->ncol ; - n = nrow ; - OK (nrow == ncol) ; - - Cp = C->p ; - Ci = C->i ; - - Bp = B->p ; - Bi = B->i ; - - /* ---------------------------------------------------------------------- */ - /* S = sorted form of B, using CAMD_preprocess */ - /* ---------------------------------------------------------------------- */ - - cnz = CHOLMOD(nnz) (C, cm) ; - S = CHOLMOD(allocate_sparse) (n, n, cnz, TRUE, TRUE, 0, CHOLMOD_PATTERN, - cm); - Sp = S->p ; - Si = S->i ; - - W = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Flag = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace for camd */ - /* ---------------------------------------------------------------------- */ - - P = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; - Constraint = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - for (i = 0 ; i < n ; i++) - { - Constraint [i] = my_rand () % (MIN (n,6)) ; - } - - ok = CAMD_cvalid (n, Constraint) ; OK (ok) ; - if (n > 0) - { - Constraint [0] = -1 ; - ok = CAMD_cvalid (n, Constraint) ; OK (!ok) ; - Constraint [0] = 0 ; - } - ok = CAMD_cvalid (n, Constraint) ; OK (ok) ; - ok = CAMD_cvalid (n, NULL) ; OK (ok) ; - - Len = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Nv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Next = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Head = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; - Elen = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Deg = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Wi = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; - BucketSet = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - - /* ---------------------------------------------------------------------- */ - - for (sorted = 0 ; sorted <= 1 ; sorted++) - { - - if (sorted) CHOLMOD(sort) (C, cm) ; - - Cp = C->p ; - Ci = C->i ; - - /* ------------------------------------------------------------------ */ - /* order C with CAMD_order */ - /* ------------------------------------------------------------------ */ - - CAMD_defaults (Control) ; - CAMD_defaults (NULL) ; - CAMD_control (Control) ; - CAMD_control (NULL) ; - CAMD_info (NULL) ; - - ok = CAMD_order (n, Cp, Ci, P, Control, Info, Constraint) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; - - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; - - /* no dense rows/cols */ - alpha = Control [CAMD_DENSE] ; - Control [CAMD_DENSE] = -1 ; - CAMD_control (Control) ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (alpha=-1)", cm)) ; - - /* many dense rows/cols */ - Control [CAMD_DENSE] = 0 ; - CAMD_control (Control) ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (alpha=0)", cm)) ; - Control [CAMD_DENSE] = alpha ; - - /* no aggressive absorption */ - Control [CAMD_AGGRESSIVE] = FALSE ; - CAMD_control (Control) ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (no agg) ", cm)) ; - Control [CAMD_AGGRESSIVE] = TRUE ; - - /* ------------------------------------------------------------------ */ - /* order F with CAMD_order */ - /* ------------------------------------------------------------------ */ - - Fp = F->p ; - Fi = F->i ; - ok = CAMD_order (n, Fp, Fi, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "F: CAMD permutation", cm)) ; - - /* ------------------------------------------------------------------ */ - /* order S with CAMD_order */ - /* ------------------------------------------------------------------ */ - - ok = CAMD_order (n, Sp, Si, P, Control, Info, NULL) ; - printf ("camd return value: "ID"\n", ok) ; - CAMD_info (Info) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; - - /* ------------------------------------------------------------------ */ - /* order E with CAMD_2, which destroys its contents */ - /* ------------------------------------------------------------------ */ - - E = CHOLMOD(copy) (B, 0, -1, cm) ; /* remove diagonal entries */ - bnz = CHOLMOD(nnz) (E, cm) ; - - /* add the bare minimum extra space to E */ - ok = CHOLMOD(reallocate_sparse) (bnz + n, E, cm) ; - OK (ok) ; - Ep = E->p ; - Ei = E->i ; - - for (j = 0 ; j < n ; j++) - { - Len [j] = Ep [j+1] - Ep [j] ; - } - - printf ("calling CAMD_2:\n") ; - if (n > 0) - { - CAMD_2 (n, Ep, Ei, Len, E->nzmax, Ep [n], Nv, Next, P, Head, Elen, - Deg, Wi, NULL, Info, NULL, BucketSet) ; - CAMD_info (Info) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD2 permutation", cm)) ; - } - - /* ------------------------------------------------------------------ */ - /* error tests */ - /* ------------------------------------------------------------------ */ - - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - ok = CAMD_order (-1, Cp, Ci, P, Control, Info, NULL) ; - OK (ok == CAMD_INVALID); - ok = CAMD_order (0, Cp, Ci, P, Control, Info, NULL) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - ok = CAMD_order (n, NULL, Ci, P, Control, Info, NULL) ; - OK (ok == CAMD_INVALID); - ok = CAMD_order (n, Cp, NULL, P, Control, Info, NULL) ; - OK (ok == CAMD_INVALID); - ok = CAMD_order (n, Cp, Ci, NULL, Control, Info, NULL) ; - OK (ok == CAMD_INVALID); - - if (n > 0) - { - printf ("CAMD error tests:\n") ; - - p = Cp [n] ; - Cp [n] = -1 ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - OK (ok == CAMD_INVALID) ; - - if (SIZE_MAX/2 == Int_max) - { - Cp [n] = Int_max ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - printf ("CAMD status is "ID"\n", ok) ; - OK (ok == CAMD_OUT_OF_MEMORY) ; - } - - Cp [n] = p ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - if (Cp [n] > 0) - { - printf ("Mangle column zero:\n") ; - i = Ci [0] ; - Ci [0] = -1 ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - CAMD_info (Info) ; - OK (ok == CAMD_INVALID) ; - Ci [0] = i ; - } - } - - ok = CAMD_valid (n, n, Sp, Si) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - ok = CAMD_valid (-1, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; - ok = CAMD_valid (n, -1, Sp, Si) ; OK (ok == CAMD_INVALID) ; - ok = CAMD_valid (n, n, NULL, Si) ; OK (ok == CAMD_INVALID) ; - ok = CAMD_valid (n, n, Sp, NULL) ; OK (ok == CAMD_INVALID) ; - - if (n > 0 && Sp [n] > 0) - { - - p = Sp [n] ; - Sp [n] = -1 ; - ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; - Sp [n] = p ; - - p = Sp [0] ; - Sp [0] = -1 ; - ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; - Sp [0] = p ; - - p = Sp [1] ; - Sp [1] = -1 ; - ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; - Sp [1] = p ; - - i = Si [0] ; - Si [0] = -1 ; - ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; - Si [0] = i ; - - } - - ok = CAMD_valid (n, n, Sp, Si) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - ok = CAMD_valid (n, n, Sp, Si) ; - OK (ok == CAMD_OK) ; - - if (n > 0 && Bp [n] > 0) - { - - p = Bp [n] ; - Bp [n] = -1 ; - ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; - Bp [n] = p ; - - - p = Bp [1] ; - Bp [1] = -1 ; - ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; - Bp [1] = p ; - - i = Bi [0] ; - Bi [0] = -1 ; - ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; - Bi [0] = i ; - } - - CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; - - Info [CAMD_STATUS] = 777 ; - CAMD_info (Info) ; - - /* ------------------------------------------------------------------ */ - /* memory tests */ - /* ------------------------------------------------------------------ */ - - if (n > 0) - { - - normal_memory_handler ( ) ; - - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; - - test_memory_handler ( ) ; - - for (trial = 0 ; trial < 6 ; trial++) - { - my_tries = trial ; - printf ("CAMD memory trial "ID"\n", trial) ; - ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; - CAMD_info (Info) ; - OK (ok == CAMD_OUT_OF_MEMORY - || (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK))) ; - } - normal_memory_handler ( ) ; - OK (CHOLMOD(print_perm) (P, n, n, "CAMD2 permutation", cm)) ; - - } - - CHOLMOD(free_sparse) (&E, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* free everything */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free) (n, sizeof (Int), Len, cm) ; - CHOLMOD(free) (n, sizeof (Int), Nv, cm) ; - CHOLMOD(free) (n, sizeof (Int), Next, cm) ; - CHOLMOD(free) (n+1, sizeof (Int), Head, cm) ; - CHOLMOD(free) (n, sizeof (Int), Elen, cm) ; - CHOLMOD(free) (n, sizeof (Int), Deg, cm) ; - CHOLMOD(free) (n+1, sizeof (Int), Wi, cm) ; - CHOLMOD(free) (n, sizeof (Int), BucketSet, cm) ; - - CHOLMOD(free) (n+1, sizeof (Int), P, cm) ; - CHOLMOD(free) (n, sizeof (Int), Constraint, cm) ; - - CHOLMOD(free) (n, sizeof (Int), W, cm) ; - CHOLMOD(free) (n, sizeof (Int), Flag, cm) ; - - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&B, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; -} - -#else - -void camdtest (cholmod_sparse *A) -{ - if (A == NULL) - { - return ; - } - cm->print = 1 ; -} -#endif diff --git a/CHOLMOD/Tcov/cctest.c b/CHOLMOD/Tcov/cctest.c deleted file mode 100644 index 1408607a5f..0000000000 --- a/CHOLMOD/Tcov/cctest.c +++ /dev/null @@ -1,391 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/cctest: test for CCOLAMD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test for ccolamd v1.0. Not used if NCAMD defined at compile time. */ - -#include "cm.h" - -#ifndef NCAMD -#include "ccolamd.h" - -/* ========================================================================== */ -/* === check_constraints ==================================================== */ -/* ========================================================================== */ - -/* Check to see if P obeys the constraints */ -Int check_constraints (Int *P, Int *Cmember, Int n) -{ - Int c, clast, k, i ; - if ((P == NULL) || !CHOLMOD(print_perm) (P, n, n, "ccolamd perm", cm)) - { - printf ("cctest: Perm is bad\n") ; - return (FALSE) ; - } - clast = EMPTY ; - for (k = 0 ; k < n ; k++) - { - i = P [k] ; - c = Cmember [i] ; - if (c < clast) - { - printf ("cctest: constraints are incorrect\n") ; - return (FALSE) ; - } - clast = c ; - } - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === cctest =============================================================== */ -/* ========================================================================== */ - -void cctest (cholmod_sparse *A) -{ - - double knobs [CCOLAMD_KNOBS], knobs2 [CCOLAMD_KNOBS] ; - Int *P, *Cmember, *Cp, *Ci, *Front_npivcol, *Front_nrows, *Front_ncols, - *Front_parent, *Front_cols, *InFront, *Si, *Sp ; - cholmod_sparse *C, *A2, *B, *S ; - Int nrow, ncol, alen, ok, stats [CCOLAMD_STATS], csets, i, nfr, c, p ; - size_t s ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - my_srand (42) ; /* RAND reset */ - - printf ("\nCCOLAMD test\n") ; - - if (A == NULL) - { - return ; - } - - if (A->stype) - { - A2 = CHOLMOD(copy) (A, 0, 0, cm) ; - B = A2 ; - } - else - { - A2 = NULL ; - B = A ; - } - S = CHOLMOD(copy_sparse) (A, cm) ; - - nrow = B->nrow ; - ncol = B->ncol ; - Si = S->i ; - Sp = S->p ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace and Cmember for ccolamd */ - /* ---------------------------------------------------------------------- */ - - P = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - Front_npivcol = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - Front_nrows = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - Front_ncols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - Front_parent = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - Front_cols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - InFront = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; - - csets = MIN (6, nrow) ; - for (i = 0 ; i < nrow ; i++) - { - Cmember [i] = nrand (csets) ; - } - - CCOLAMD_set_defaults (knobs) ; - CCOLAMD_set_defaults (knobs2) ; - CCOLAMD_set_defaults (NULL) ; - CCOLAMD_report (NULL) ; - CSYMAMD_report (NULL) ; - - alen = CCOLAMD_recommended (B->nzmax, ncol, nrow) ; - C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - Cp = C->p ; - Ci = C->i ; - - /* ---------------------------------------------------------------------- */ - /* order with ccolamd */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - CHOLMOD(print_sparse) (C, "C for ccolamd", cm) ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, NULL, stats, Cmember) ; - CCOLAMD_report (stats) ; - OK (ok) ; - ok = stats [CCOLAMD_STATUS] ; - ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; - OK (ok) ; - - /* permutation returned in C->p, if the ordering succeeded */ - /* make sure P obeys the constraints */ - OK (check_constraints (Cp, Cmember, nrow)) ; - - /* ---------------------------------------------------------------------- */ - /* order with ccolamd2 */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = CCOLAMD_2 (ncol, nrow, alen, Ci, Cp, NULL, stats, - Front_npivcol, Front_nrows, Front_ncols, Front_parent, - Front_cols, &nfr, InFront, Cmember) ; - CCOLAMD_report (stats) ; - OK (check_constraints (Cp, Cmember, nrow)) ; - - /* ---------------------------------------------------------------------- */ - /* with a small dense-row threshold */ - /* ---------------------------------------------------------------------- */ - - knobs2 [CCOLAMD_DENSE_ROW] = 0 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; - CCOLAMD_report (stats) ; - - knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; - knobs2 [CCOLAMD_DENSE_COL] = 0 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; - CCOLAMD_report (stats) ; - - knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; - knobs2 [CCOLAMD_DENSE_COL] = -1 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; - CCOLAMD_report (stats) ; - - knobs2 [CCOLAMD_DENSE_COL] = 0 ; - - /* ---------------------------------------------------------------------- */ - /* duplicate entries */ - /* ---------------------------------------------------------------------- */ - - if (ncol > 2 && nrow > 2) - { - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; - OK (ok) ; - if (Cp [1] - Cp [0] > 2) - { - Ci [0] = Ci [1] ; - } - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; - CCOLAMD_report (stats) ; - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "ccolamd perm", cm)) ; - } - - /* ---------------------------------------------------------------------- */ - /* csymamd */ - /* ---------------------------------------------------------------------- */ - - if (nrow == ncol) - { - Int n = nrow ; - - void * (*calloc_func) (size_t, size_t) ; - void (*free_func) (void *) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; - OK (ok) ; - OK (check_constraints (P, Cmember, n)) ; - CSYMAMD_report (stats) ; - - /* ------------------------------------------------------------------ */ - /* csymamd errors */ - /* ------------------------------------------------------------------ */ - - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, NULL, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - - ok = CSYMAMD_MAIN (n, NULL, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - - ok = CSYMAMD_MAIN (n, Si, NULL, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - - ok = CSYMAMD_MAIN (-1, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - - p = Sp [n] ; - Sp [n] = -1 ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - Sp [n] = p ; - - Sp [0] = -1 ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - Sp [0] = 0 ; - - if (n > 2 && Sp [n] > 3) - { - p = Sp [1] ; - Sp [1] = -1 ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - Sp [1] = p ; - - i = Si [0] ; - Si [0] = -1 ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; NOT (ok); - CSYMAMD_report (stats) ; - Si [0] = i ; - - /* ok, but jumbled */ - i = Si [0] ; - Si [0] = Si [1] ; - Si [1] = i ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; OK (ok); - CSYMAMD_report (stats) ; - i = Si [0] ; - Si [0] = Si [1] ; - Si [1] = i ; - - test_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func, - Cmember, A->stype) ; - NOT (ok) ; - CSYMAMD_report (stats) ; - normal_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - } - } - - /* ---------------------------------------------------------------------- */ - /* error tests */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = CCOLAMD_MAIN (ncol, nrow, 0, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CCOLAMD_MAIN (ncol, nrow, alen, NULL, Cp, knobs, stats, Cmember); NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, NULL, knobs, stats, Cmember); NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, NULL, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CCOLAMD_MAIN (-1, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CCOLAMD_MAIN (ncol, -1, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - Cp [nrow] = -1 ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - Cp [0] = 1 ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; NOT (ok) ; - CCOLAMD_report (stats) ; - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - - if (nrow > 0 && alen > 0 && Cp [1] > 0) - { - c = Cmember [0] ; - Cmember [0] = -1 ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); - CCOLAMD_report (stats) ; - Cmember [0] = c ; - - p = Cp [1] ; - Cp [1] = -1 ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); - CCOLAMD_report (stats) ; - Cp [1] = p ; - - i = Ci [0] ; - Ci [0] = -1 ; - ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ;NOT(ok); - CCOLAMD_report (stats) ; - Ci [0] = i ; - } - - s = CCOLAMD_recommended (-1, 0, 0) ; - OK (s == 0) ; - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free) (nrow+1, sizeof (Int), Front_npivcol, cm) ; - CHOLMOD(free) (nrow+1, sizeof (Int), Front_nrows, cm) ; - CHOLMOD(free) (nrow+1, sizeof (Int), Front_ncols, cm) ; - CHOLMOD(free) (nrow+1, sizeof (Int), Front_parent, cm) ; - CHOLMOD(free) (nrow+1, sizeof (Int), Front_cols, cm) ; - CHOLMOD(free) (nrow+1, sizeof (Int), P, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; - CHOLMOD(free) (ncol, sizeof (Int), InFront, cm) ; - - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&A2, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - cm->print = 1 ; -} - -#else - -void cctest (cholmod_sparse *A) -{ - if (A == NULL) - { - return ; - } - - cm->print = 1 ; -} -#endif diff --git a/CHOLMOD/Tcov/cl.c b/CHOLMOD/Tcov/cl.c deleted file mode 100644 index 4d0a25386e..0000000000 --- a/CHOLMOD/Tcov/cl.c +++ /dev/null @@ -1,27 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/cl: int64_t version of Tcov/cm test program -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -#define CHOLMOD_INT64 -#include "cm.c" -#include "test_ops.c" -#include "null.c" -#include "null2.c" -#include "lpdemo.c" -#include "memory.c" -#include "solve.c" -#include "aug.c" -#include "unpack.c" -#include "raw_factor.c" -#include "cctest.c" -#include "ctest.c" -// #include "amdtest.c" -// #include "camdtest.c" -// #include "huge.c" - diff --git a/CHOLMOD/Tcov/cm.c b/CHOLMOD/Tcov/cm.c deleted file mode 100644 index 823cdd0d97..0000000000 --- a/CHOLMOD/Tcov/cm.c +++ /dev/null @@ -1,1779 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/cm: CHOLMOD test program -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* A program for exhaustive statement-coverage for CHOLMOD, AMD, COLAMD, and - * CCOLAMD. It tests every line of code in all three packages. - * - * For a complete test, all CHOLMOD modules, AMD, COLAMD, CCOLAMD, METIS, - * LAPACK, and the BLAS are required. A partial test can be performed without - * the Supernodal and/or Partition modules. METIS is not required if the - * Partition module is not installed. LAPACK and the BLAS are not required - * if the Supernodal module is not installed. - * - * Usage: - * - * cm < input > output - * - * where "input" contains a sparse matrix in triplet form. The first line of - * the file contains four or five integers: - * - * nrow ncol nnz stype complex - * - * where the matrix is nrow-by-ncol. nnz is the number of (i,j,aij) triplets - * in the rest of the file, one triplet per line. stype is -1 (symmetric - * with entries in lower triangular part provided), 0 (unsymmetric), or 1 - * (symmetric upper). If the 5th entry is missing, or 0, then the matrix is - * real; if 1 the matrix is complex, if 2 the matrix is zomplex. Each - * subsequent line contains - * - * i j aij - * - * for the row index, column index, and value of A(i,j). Duplicate entries - * are summed. If stype is 2 or 3, the rest of the file is ignored, and a - * special test matrix is constructed (2: arrowhead, 3: tridiagonal plus a - * dense row). Test matrices are located in the Matrix/ subdirectory. - * - * For complex matrices, each line consists of - * - * i j xij zij - * - * where xij is the real part of A(i,j) and zij is the imaginary part. - * - * cm takes one optional parameter. If present (it does not matter what the - * argument is, actually) then extension memory-failure tests are performed. - */ - -#include "cm.h" - -/* ========================================================================== */ -/* === global variables ===================================================== */ -/* ========================================================================== */ - -double zero [2], one [2], minusone [2] ; -cholmod_common Common, *cm ; -cholmod_dense *M1 ; -Int dot = 0 ; -double Zero [2] ; - - -/* ========================================================================== */ -/* === my_rand ============================================================== */ -/* ========================================================================== */ - -/* The POSIX example of rand, duplicated here so that the same sequence will - * be generated on different machines. */ - -static unsigned long next = 1 ; - -/* RAND_MAX assumed to be 32767 */ -Int my_rand (void) -{ - next = next * 1103515245 + 12345 ; - return ((unsigned)(next/65536) % /* 32768 */ (MY_RAND_MAX + 1)) ; -} - -void my_srand (unsigned seed) -{ - next = seed ; -} - -unsigned long my_seed (void) -{ - return (next) ; -} - - -/* ========================================================================== */ -/* === progress ============================================================= */ -/* ========================================================================== */ - -/* print a "." on stderr to indicate progress */ - -#define LINEWIDTH 70 -#define COUNT 100 - -void progress (Int force, char s) -{ - dot++ ; - if (force) - { - dot += (COUNT - (dot % COUNT)) ; - } - if (dot % COUNT == 0) - { - fprintf (stderr, "%c", s) ; - } - if (dot % (COUNT*LINEWIDTH) == 0) - { - fprintf (stderr, "\n") ; - } - fflush (stdout) ; - fflush (stderr) ; -} - - -/* ========================================================================== */ -/* === my_handler =========================================================== */ -/* ========================================================================== */ - -/* An error occurred that should not have occurred */ - -void my_handler (int status, const char *file, int line, const char *msg) -{ - printf ("Error handler: file %s line %d status %d: %s\n", - file, line, status, msg) ; - if (status < CHOLMOD_OK || status > CHOLMOD_DSMALL) - { - fprintf (stderr, "\n\n************************************************" - "********************************\n" - "*** Test failure: file: %s line: %d\n" - "*** status: %d message: %s\n" - "***********************************************************" - "*********************\n", file, line, status, msg); - fflush (stderr) ; - fflush (stdout) ; - abort ( ) ; - } -} - - -/* ========================================================================== */ -/* === Assert =============================================================== */ -/* ========================================================================== */ - -void Assert (int truth, char *file, int line) -{ - if (!truth) - { - my_handler (-1, file, line, "") ; - } -} - - -/* ========================================================================== */ -/* === nrand ================================================================ */ -/* ========================================================================== */ - -/* return a random Int between 0 and n-1 */ - -Int nrand (Int n) -{ - return ((n <= 0) ? (0) : (rand ( ) % n)) ; -} - -/* ========================================================================== */ -/* === xrand ================================================================ */ -/* ========================================================================== */ - -/* return a random double between 0 and x */ - -double xrand (double range) -{ - return ((range * (double) (my_rand ( ))) / MY_RAND_MAX) ; -} - - -/* ========================================================================== */ -/* === prand ================================================================ */ -/* ========================================================================== */ - -/* allocate and construct a random permutation of 0:n-1 */ - -Int *prand (Int n) -{ - Int *P ; - Int t, j, k ; - P = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - if (P == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot create random perm") ; - return (NULL) ; - } - for (k = 0 ; k < n ; k++) - { - P [k] = k ; - } - for (k = 0 ; k < n-1 ; k++) - { - j = k + nrand (n-k) ; - t = P [j] ; - P [j] = P [k] ; - P [k] = t ; - } - CHOLMOD(print_perm) (P, n, n, "Prandom", cm) ; - return (P) ; -} - - -/* ========================================================================== */ -/* === rand_set ============================================================= */ -/* ========================================================================== */ - -/* allocate and construct a random set of 0:n-1, possibly with duplicates */ - -Int *rand_set (Int len, Int n) -{ - Int *cset ; - Int k ; - cset = CHOLMOD(malloc) (len, sizeof (Int), cm) ; - if (cset == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot create random set") ; - return (NULL) ; - } - for (k = 0 ; k < len ; k++) - { - cset [k] = nrand (n) ; - } - CHOLMOD(print_subset) (cset, len, n, "random cset", cm) ; - return (cset) ; -} - - -/* ========================================================================== */ -/* === read_triplet ========================================================= */ -/* ========================================================================== */ - -/* Read a triplet matrix from a file. */ - -#define MAXLINE 1024 - -cholmod_triplet *read_triplet -( - FILE *f -) -{ - cholmod_triplet *T ; - double *Tx, *Tz ; - long long x1, x2, x3, x4, x5 ; - Int *Ti, *Tj ; - Int n, j, k, nrow, ncol, nz, stype, arrowhead, tridiag_plus_denserow, - xtype, is_complex ; - char s [MAXLINE] ; - - /* ---------------------------------------------------------------------- */ - /* read in a triplet matrix from a file */ - /* ---------------------------------------------------------------------- */ - - dot = 0 ; - xtype = 0 ; - if (fgets (s, MAXLINE, f) == NULL) - { - return (NULL) ; - } - - x1 = 0 ; - x2 = 0 ; - x3 = 0 ; - x4 = 0 ; - x5 = 0 ; - k = sscanf (s, "%lld %lld %lld %lld %lld\n", &x1, &x2, &x3, &x4, &x5) ; - nrow = x1 ; - ncol = x2 ; - nz = x3 ; - stype = x4 ; - xtype = x5 ; - - xtype++ ; - is_complex = (xtype != CHOLMOD_REAL) ; - - printf ("read_triplet: nrow "ID" ncol "ID" nz "ID" stype "ID" xtype "ID"\n", - nrow, ncol, nz, stype, xtype) ; - - arrowhead = FALSE ; - tridiag_plus_denserow = FALSE ; - - n = MAX (nrow, ncol) ; - if (stype == 2) - { - /* ignore nz and the rest of the file, and create an arrowhead matrix */ - arrowhead = TRUE ; - nz = nrow + ncol + 1 ; - stype = (nrow == ncol) ? (1) : (0) ; - } - else if (stype == 3) - { - tridiag_plus_denserow = TRUE ; - nrow = n ; - ncol = n ; - nz = 4*n + 4 ; - stype = 0 ; - } - - T = CHOLMOD(allocate_triplet) (nrow, ncol, nz, stype, - is_complex ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL, cm) ; - if (T == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot create triplet matrix") ; - return (NULL) ; - } - Ti = T->i ; - Tj = T->j ; - Tx = T->x ; - Tz = T->z ; - - if (arrowhead) - { - for (k = 0 ; k < MIN (nrow,ncol) ; k++) - { - Ti [k] = k ; - Tj [k] = k ; - Tx [k] = nrow + xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = nrow + xrand (1) ; /* RAND */ - } - } - for (j = 0 ; j < ncol ; j++) - { - Ti [k] = 0 ; - Tj [k] = j ; - Tx [k] = - xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = - xrand (1) ; /* RAND */ - } - k++ ; - } - T->nnz = k ; - } - else if (tridiag_plus_denserow) - { - /* dense row, except for the last column */ - for (k = 0 ; k < n-1 ; k++) - { - Ti [k] = 0 ; - Tj [k] = k ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - } - - /* diagonal */ - for (j = 0 ; j < n ; j++) - { - Ti [k] = j ; - Tj [k] = j ; - Tx [k] = nrow + xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = nrow + xrand (1) ; /* RAND */ - } - k++ ; - } - - /* superdiagonal */ - for (j = 1 ; j < n ; j++) - { - Ti [k] = j-1 ; - Tj [k] = j ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - k++ ; - } - - /* subdiagonal */ - for (j = 0 ; j < n-1 ; j++) - { - Ti [k] = j+1 ; - Tj [k] = j ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - k++ ; - } - - /* a few extra terms in the last column */ - Ti [k] = MAX (0, n-3) ; - Tj [k] = n-1 ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - k++ ; - - Ti [k] = MAX (0, n-4) ; - Tj [k] = n-1 ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - k++ ; - - Ti [k] = MAX (0, n-5) ; - Tj [k] = n-1 ; - Tx [k] = xrand (1) ; /* RAND */ - if (is_complex) - { - Tz [k] = xrand (1) ; /* RAND */ - } - k++ ; - - T->nnz = k ; - } - else - { - if (is_complex) - { - for (k = 0 ; k < nz ; k++) - { - if (fscanf (f,""ID" "ID" %lg %lg\n", Ti+k, Tj+k, Tx+k, Tz+k) - == EOF) - { - ERROR (CHOLMOD_INVALID, "Error reading triplet matrix\n") ; - } - } - } - else - { - for (k = 0 ; k < nz ; k++) - { - if (fscanf (f, ""ID" "ID" %lg\n", Ti+k, Tj+k, Tx+k) == EOF) - { - ERROR (CHOLMOD_INVALID, "Error reading triplet matrix\n") ; - } - } - } - T->nnz = nz ; - } - - CHOLMOD(triplet_xtype) (xtype, T, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print the triplet matrix */ - /* ---------------------------------------------------------------------- */ - - cm->print = 4 ; - CHOLMOD(print_triplet) (T, "T input", cm) ; - cm->print = 1 ; - fprintf (stderr, "Test matrix: "ID"-by-"ID" with "ID" entries, stype: "ID - "\n", - (Int) T->nrow, (Int) T->ncol, (Int) T->nnz, (Int) T->stype) ; - printf ("\n\n======================================================\n" - "Test matrix: "ID"-by-"ID" with "ID" entries, stype: "ID"\n", - (Int) T->nrow, (Int) T->ncol, (Int) T->nnz, (Int) T->stype) ; - - if (MAX (nrow, ncol) > NLARGE) - { - fprintf (stderr, "Please wait, this will take a while ...") ; - dot = 39*LINEWIDTH ; - } - return (T) ; -} - - -/* ========================================================================== */ -/* === zeros ================================================================ */ -/* ========================================================================== */ - -/* Same as cholmod_zeros or cholmod_l_zeros, except it allows for a leading - * dimension that is different than nrow */ - -cholmod_dense *zeros (Int nrow, Int ncol, Int d, Int xtype) -{ - cholmod_dense *X ; - double *Xx, *Xz ; - Int i, nz ; - X = CHOLMOD(allocate_dense) (nrow, ncol, d, xtype, cm) ; - if (X == NULL) - { - return (NULL) ; - } - Xx = X->x ; - Xz = X->z ; - nz = MAX (1, X->nzmax) ; - switch (X->xtype) - { - case CHOLMOD_REAL: - for (i = 0 ; i < nz ; i++) - { - Xx [i] = 0 ; - } - break ; - case CHOLMOD_COMPLEX: - for (i = 0 ; i < 2*nz ; i++) - { - Xx [i] = 0 ; - } - break ; - case CHOLMOD_ZOMPLEX: - for (i = 0 ; i < nz ; i++) - { - Xx [i] = 0 ; - } - for (i = 0 ; i < nz ; i++) - { - Xz [i] = 0 ; - } - break ; - } - return (X) ; -} - - -/* ========================================================================== */ -/* === xtrue ================================================================ */ -/* ========================================================================== */ - -/* Allocate and construct a dense matrix, X(i,j) = i+j*d+1 */ - -cholmod_dense *xtrue (Int nrow, Int ncol, Int d, Int xtype) -{ - double *x, *z ; - cholmod_dense *X ; - Int j, i ; - X = zeros (nrow, ncol, d, xtype) ; - if (X == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot create dense matrix") ; - return (NULL) ; - } - x = X->x ; - z = X->z ; - - if (xtype == CHOLMOD_REAL) - { - for (j = 0 ; j < ncol ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - x [i+j*d] = i+j*d + 1 ; - } - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - for (j = 0 ; j < ncol ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - x [2*(i+j*d) ] = i+j*d + 1 ; - x [2*(i+j*d)+1] = ((double) (j+i*d + 1))/10 ; - } - } - } - else - { - for (j = 0 ; j < ncol ; j++) - { - for (i = 0 ; i < nrow ; i++) - { - x [i+j*d] = i+j*d + 1 ; - z [i+j*d] = ((double) (j+i*d + 1))/10 ; - } - } - } - return (X) ; -} - - -/* ========================================================================== */ -/* === rhs ================================================================== */ -/* ========================================================================== */ - -/* Create a right-hand-side, b = A*x, where x is a known solution */ - -cholmod_dense *rhs (cholmod_sparse *A, Int nrhs, Int d) -{ - Int n ; - cholmod_dense *W, *Z, *B ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute rhs") ; - return (NULL) ; - } - - n = A->nrow ; - - /* B = zeros (n,rhs) but with leading dimension d */ - B = zeros (n, nrhs, d, A->xtype) ; - - /* ---------------------------------------------------------------------- */ - /* create a known solution */ - /* ---------------------------------------------------------------------- */ - - Z = xtrue (n, nrhs, d, A->xtype) ; - - /* ---------------------------------------------------------------------- */ - /* compute B = A*Z or A*A'*Z */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0) - { - /* W = A'*Z */ - W = CHOLMOD(zeros) (A->ncol, nrhs, A->xtype, cm) ; - CHOLMOD(sdmult) (A, TRUE, one, zero, Z, W, cm) ; - /* B = A*W */ - CHOLMOD(sdmult) (A, FALSE, one, zero, W, B, cm) ; - CHOLMOD(free_dense) (&W, cm) ; - } - else - { - /* B = A*Z */ - CHOLMOD(sdmult) (A, FALSE, one, zero, Z, B, cm) ; - } - CHOLMOD(free_dense) (&Z, cm) ; - return (B) ; -} - - -/* ========================================================================== */ -/* === resid ================================================================ */ -/* ========================================================================== */ - -/* compute r = norm (A*x-b)/norm(b) or r = norm (A*A'*x-b)/norm(b) */ - -double resid (cholmod_sparse *A, cholmod_dense *X, cholmod_dense *B) -{ - double r, bnorm ; - cholmod_dense *R, *X2, *B2 ; - cholmod_sparse *C, *A2 ; - Int d, n, nrhs, xtype ; - - if (A == NULL || X == NULL || B == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute resid") ; - return (1) ; - } - - cm->status = CHOLMOD_OK ; - n = B->nrow ; - - /* ---------------------------------------------------------------------- */ - /* convert all inputs to an identical xtype */ - /* ---------------------------------------------------------------------- */ - - xtype = MAX (A->xtype, X->xtype) ; - xtype = MAX (xtype, B->xtype) ; - A2 = NULL ; - B2 = NULL ; - X2 = NULL ; - if (A->xtype != xtype) - { - A2 = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sparse_xtype) (xtype, A2, cm) ; - A = A2 ; - } - if (X->xtype != xtype) - { - X2 = CHOLMOD(copy_dense) (X, cm) ; - CHOLMOD(dense_xtype) (xtype, X2, cm) ; - X = X2 ; - } - if (B->xtype != xtype) - { - B2 = CHOLMOD(copy_dense) (B, cm) ; - CHOLMOD(dense_xtype) (xtype, B2, cm) ; - B = B2 ; - } - - if (cm->status < CHOLMOD_OK) - { - ERROR (CHOLMOD_INVALID, "cannot compute resid") ; - CHOLMOD(free_sparse) (&A2, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - return (1) ; - } - - /* ---------------------------------------------------------------------- */ - /* get the right-hand-side, B, and its norm */ - /* ---------------------------------------------------------------------- */ - - nrhs = B->ncol ; - d = B->d ; - if (nrhs == 1) - { - /* inf-norm, 1-norm, or 2-norm (random choice) */ - bnorm = CHOLMOD(norm_dense) (B, nrand (2), cm) ; - } - else - { - /* inf-norm or 1-norm (random choice) */ - bnorm = CHOLMOD(norm_dense) (B, nrand (1), cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* compute the residual */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0) - { - if (n < 10 && A->xtype == CHOLMOD_REAL) - { - /* test cholmod_aat, C = A*A' */ - C = CHOLMOD(aat) (A, NULL, 0, 1, cm) ; - - /* R = B */ - R = CHOLMOD(copy_dense) (B, cm) ; - /* R = C*X - R */ - CHOLMOD(sdmult) (C, FALSE, one, minusone, X, R, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - - } - else - { - /* W = A'*X */ - cholmod_dense *W ; - W = CHOLMOD(zeros) (A->ncol, nrhs, A->xtype, cm) ; - CHOLMOD(sdmult) (A, TRUE, one, zero, X, W, cm) ; - /* R = B */ - R = CHOLMOD(copy_dense) (B, cm) ; - /* R = A*W - R */ - CHOLMOD(sdmult) (A, FALSE, one, minusone, W, R, cm) ; - CHOLMOD(free_dense) (&W, cm) ; - } - } - else - { - /* R = B */ - R = CHOLMOD(copy_dense) (B, cm) ; - /* R = A*X - R */ - CHOLMOD(sdmult) (A, FALSE, one, minusone, X, R, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* r = norm (R) / norm (B) */ - /* ---------------------------------------------------------------------- */ - - r = CHOLMOD(norm_dense) (R, 1, cm) ; - - CHOLMOD(free_dense) (&R, cm) ; - CHOLMOD(free_sparse) (&A2, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - - if (bnorm > 0) - { - r /= bnorm ; - } - return (r) ; -} - - -/* ========================================================================== */ -/* === resid_sparse ========================================================= */ -/* ========================================================================== */ - -/* compute r = norm (A*x-b)/norm(b) or r = norm (A*A'*x-b)/norm(b) */ - -double resid_sparse (cholmod_sparse *A, cholmod_sparse *X, cholmod_sparse *B) -{ - double r, bnorm ; - cholmod_sparse *R, *W, *AT, *W2 ; - cholmod_dense *X2, *B2 ; - Int n, nrhs, xtype ; - - if (A == NULL || X == NULL || B == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute resid") ; - return (1) ; - } - - /* ---------------------------------------------------------------------- */ - /* compute the residual */ - /* ---------------------------------------------------------------------- */ - - xtype = MAX (A->xtype, X->xtype) ; - xtype = MAX (xtype, B->xtype) ; - - if (xtype > CHOLMOD_REAL) - { - - /* ------------------------------------------------------------------ */ - /* convert X and B to dense if any is complex or zomplex */ - /* ------------------------------------------------------------------ */ - - X2 = CHOLMOD(sparse_to_dense) (X, cm) ; - B2 = CHOLMOD(sparse_to_dense) (B, cm) ; - r = resid (A, X2, B2) ; - CHOLMOD(free_dense) (&X2, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - - } - else - { - - /* ------------------------------------------------------------------ */ - /* all inputs are real */ - /* ------------------------------------------------------------------ */ - - n = B->nrow ; - nrhs = B->ncol ; - /* inf-norm or 1-norm (random choice) */ - bnorm = CHOLMOD(norm_sparse) (B, nrand (1), cm) ; - - if (A->stype == 0) - { - /* W = A'*X */ - AT = CHOLMOD(transpose) (A, 1, cm) ; - W = CHOLMOD(ssmult) (AT, X, 0, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - /* W2 = A*W */ - W2 = CHOLMOD(ssmult) (A, W, 0, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&W, cm) ; - /* R = W2 - B */ - R = CHOLMOD(add) (W2, B, one, minusone, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&W2, cm) ; - } - else - { - /* W = A*X */ - W = CHOLMOD(ssmult) (A, X, 0, TRUE, FALSE, cm) ; - /* R = W - B */ - R = CHOLMOD(add) (W, B, one, minusone, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&W, cm) ; - } - - r = CHOLMOD(norm_sparse) (R, 1, cm) ; - CHOLMOD(free_sparse) (&R, cm) ; - if (bnorm > 0) - { - r /= bnorm ; - } - } - - return (r) ; -} - - -/* ========================================================================== */ -/* === resid3 =============================================================== */ -/* ========================================================================== */ - -/* r = norm (A1*A2*A3*x - b) / norm (b) */ - -double resid3 (cholmod_sparse *A1, cholmod_sparse *A2, cholmod_sparse *A3, - cholmod_dense *X, cholmod_dense *B) -{ - double r, bnorm ; - cholmod_dense *R, *W1, *W2, *X2, *B2 ; - cholmod_sparse *C1, *C2, *C3 ; - Int n, nrhs, d, xtype ; - - if (A1 == NULL || X == NULL || B == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute resid3") ; - return (1) ; - } - - cm->status = CHOLMOD_OK ; - - n = B->nrow ; - - /* ---------------------------------------------------------------------- */ - /* convert all inputs to an identical xtype */ - /* ---------------------------------------------------------------------- */ - - xtype = MAX (A1->xtype, X->xtype) ; - xtype = MAX (xtype, B->xtype) ; - if (A2 != NULL) - { - xtype = MAX (xtype, A2->xtype) ; - } - if (A3 != NULL) - { - xtype = MAX (xtype, A3->xtype) ; - } - - C1 = NULL ; - C2 = NULL ; - C3 = NULL ; - B2 = NULL ; - X2 = NULL ; - - if (A1->xtype != xtype) - { - C1 = CHOLMOD(copy_sparse) (A1, cm) ; - CHOLMOD(sparse_xtype) (xtype, C1, cm) ; - A1 = C1 ; - } - - if (A2 != NULL && A2->xtype != xtype) - { - C2 = CHOLMOD(copy_sparse) (A2, cm) ; - CHOLMOD(sparse_xtype) (xtype, C2, cm) ; - A2 = C2 ; - } - - if (A3 != NULL && A3->xtype != xtype) - { - C3 = CHOLMOD(copy_sparse) (A3, cm) ; - CHOLMOD(sparse_xtype) (xtype, C3, cm) ; - A3 = C3 ; - } - - if (X->xtype != xtype) - { - X2 = CHOLMOD(copy_dense) (X, cm) ; - CHOLMOD(dense_xtype) (xtype, X2, cm) ; - X = X2 ; - } - - if (B->xtype != xtype) - { - B2 = CHOLMOD(copy_dense) (B, cm) ; - CHOLMOD(dense_xtype) (xtype, B2, cm) ; - B = B2 ; - } - - if (cm->status < CHOLMOD_OK) - { - ERROR (CHOLMOD_INVALID, "cannot compute resid3") ; - CHOLMOD(free_sparse) (&C1, cm) ; - CHOLMOD(free_sparse) (&C2, cm) ; - CHOLMOD(free_sparse) (&C3, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - return (1) ; - } - - /* ---------------------------------------------------------------------- */ - /* get B and its norm */ - /* ---------------------------------------------------------------------- */ - - nrhs = B->ncol ; - d = B->d ; - bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; - - /* ---------------------------------------------------------------------- */ - /* compute the residual */ - /* ---------------------------------------------------------------------- */ - - if (A3 != NULL) - { - /* W1 = A3*X */ - W1 = CHOLMOD(zeros) (n, nrhs, xtype, cm) ; - CHOLMOD(sdmult) (A3, FALSE, one, zero, X, W1, cm) ; - } - else - { - W1 = X ; - } - - if (A2 != NULL) - { - /* W2 = A2*W1 */ - W2 = CHOLMOD(eye) (n, nrhs, xtype, cm) ; - CHOLMOD(sdmult) (A2, FALSE, one, zero, W1, W2, cm) ; - } - else - { - W2 = W1 ; - } - - /* R = B */ - R = CHOLMOD(copy_dense) (B, cm) ; - - /* R = A1*W2 - R */ - CHOLMOD(sdmult) (A1, FALSE, one, minusone, W2, R, cm) ; - - /* ---------------------------------------------------------------------- */ - /* r = norm (R) / norm (B) */ - /* ---------------------------------------------------------------------- */ - - r = CHOLMOD(norm_dense) (R, 1, cm) ; - CHOLMOD(free_dense) (&R, cm) ; - - CHOLMOD(free_sparse) (&C1, cm) ; - CHOLMOD(free_sparse) (&C2, cm) ; - CHOLMOD(free_sparse) (&C3, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - - if (A3 != NULL) - { - CHOLMOD(free_dense) (&W1, cm) ; - } - if (A2 != NULL) - { - CHOLMOD(free_dense) (&W2, cm) ; - } - if (bnorm > 0) - { - r /= bnorm ; - } - return (r) ; -} - - -/* ========================================================================== */ -/* === pnorm ================================================================ */ -/* ========================================================================== */ - -/* r = norm (x-Pb) or r = norm(x-P'b). This is lengthy because CHOLMOD does - * not provide any operations on dense matrices, and because it used to test - * the sparse-to-dense conversion routine. Multiple methods are used to compute - * the same thing. - */ - -double pnorm (cholmod_dense *X, Int *P, cholmod_dense *B, Int inv) -{ - cholmod_dense *R, *X2, *B2 ; - cholmod_factor *L ; - double *xx, *xz, *bx, *bz, *rx, *rz ; - Int *Pinv, *Perm ; - double rnorm, r ; - Int i, j, k, n, nrhs, xtype, ok, save, lxtype ; - - if (X == NULL || P == NULL || B == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute pnorm") ; - return (1) ; - } - - save = cm->prefer_zomplex ; - n = X->nrow ; - nrhs = X->ncol ; - rnorm = 0 ; - - Pinv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - if (Pinv != NULL) - { - for (k = 0 ; k < n ; k++) - { - Pinv [P [k]] = k ; - } - } - - xtype = MAX (X->xtype, B->xtype) ; - - R = CHOLMOD(zeros) (n, nrhs, CHOLMOD_ZOMPLEX, cm) ; - B2 = CHOLMOD(copy_dense) (B, cm) ; - ok = R != NULL && B2 != NULL ; - ok = ok && CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX, B2, cm) ; - - for (lxtype = CHOLMOD_REAL ; ok && lxtype <= CHOLMOD_ZOMPLEX ; lxtype++) - { - /* create a fake factor object */ - L = CHOLMOD(allocate_factor) (n, cm) ; - CHOLMOD(change_factor) (lxtype, TRUE, FALSE, TRUE, TRUE, L, cm) ; - ok = ok && (L != NULL && L->Perm != NULL && Pinv != NULL) ; - if (ok) - { - L->ordering = CHOLMOD_GIVEN ; - Perm = L->Perm ; - for (k = 0 ; k < n ; k++) - { - Perm [k] = Pinv [k] ; - } - } - for (k = 0 ; k <= 1 ; k++) - { - /* solve the inverse permutation system, X2 = P*X or X2 = P'*X */ - cm->prefer_zomplex = k ; - X2 = CHOLMOD(solve) (inv ? CHOLMOD_Pt : CHOLMOD_P, L, X, cm) ; - - ok = ok && CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX, X2, cm) ; - if (ok && X2 != NULL) - { - rx = R->x ; - rz = R->z ; - xx = X2->x ; - xz = X2->z ; - bx = B2->x ; - bz = B2->z ; - for (j = 0 ; j < nrhs ; j++) - { - for (i = 0 ; i < n ; i++) - { - rx [i+j*n] = xx [i+j*n] - bx [i+j*n] ; - rz [i+j*n] = xz [i+j*n] - bz [i+j*n] ; - } - } - } - r = CHOLMOD(norm_dense) (R, 0, cm) ; - rnorm = MAX (r, rnorm) ; - CHOLMOD(free_dense) (&X2, cm) ; - } - CHOLMOD(free_factor) (&L, cm) ; - } - - CHOLMOD(free_dense) (&B2, cm) ; - CHOLMOD(free_dense) (&R, cm) ; - - if (xtype == CHOLMOD_REAL) - { - /* X and B are both real */ - cholmod_sparse *Bs, *Pb ; - Bs = CHOLMOD(dense_to_sparse) (B, TRUE, cm) ; - Pb = CHOLMOD(submatrix) (Bs, inv ? Pinv : P, n, NULL, -1, TRUE, TRUE,cm); - X2 = CHOLMOD(sparse_to_dense) (Pb, cm) ; - R = CHOLMOD(zeros) (n, nrhs, CHOLMOD_REAL, cm) ; - if (R != NULL && X != NULL && X2 != NULL) - { - rx = R->x ; - xx = X->x ; - bx = X2->x ; - for (j = 0 ; j < nrhs ; j++) - { - for (i = 0 ; i < n ; i++) - { - rx [i+j*n] = xx [i+j*n] - bx [i+j*n] ; - } - } - } - CHOLMOD(free_sparse) (&Bs, cm) ; - CHOLMOD(free_sparse) (&Pb, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - r = CHOLMOD(norm_dense) (R, 1, cm) ; - rnorm = MAX (rnorm, r) ; - CHOLMOD(free_dense) (&R, cm) ; - } - - CHOLMOD(free) (n, sizeof (Int), Pinv, cm) ; - cm->prefer_zomplex = save ; - return (rnorm) ; -} - - -/* ========================================================================== */ -/* === prune_row ============================================================ */ -/* ========================================================================== */ - -/* Set row k and column k of a packed matrix A to zero. Set A(k,k) to 1 - * if space is available. */ - -void prune_row (cholmod_sparse *A, Int k) -{ - double *Ax ; - Int *Ap, *Ai ; - Int ncol, p, i, j, nz ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "nothing to prune") ; - return ; - } - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - nz = 0 ; - ncol = A->ncol ; - - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - Ap [j] = nz ; - if (j == k && nz < Ap [j+1]) - { - Ai [nz] = k ; - Ax [nz] = 1 ; - nz++ ; - } - else - { - for ( ; p < Ap [j+1] ; p++) - { - i = Ai [p] ; - if (i != k) - { - Ai [nz] = i ; - Ax [nz] = Ax [p] ; - nz++ ; - } - } - } - } - Ap [ncol] = nz ; -} - - -/* ========================================================================== */ -/* === do_matrix =========================================================== */ -/* ========================================================================== */ - -double do_matrix (cholmod_sparse *A) -{ - double err, maxerr = 0 ; - Int print, precise, maxprint, minprint, nmethods ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "no matrix") ; - return (1) ; - } - - /* ---------------------------------------------------------------------- */ - /* determine print level, based on matrix size */ - /* ---------------------------------------------------------------------- */ - - if (A->nrow <= 4) - { - minprint = 5 ; - maxprint = 5 ; - } - else if (A->nrow <= 8) - { - minprint = 4 ; - maxprint = 4 ; - } - else - { - minprint = 1 ; - maxprint = 1 ; - } - - /* ---------------------------------------------------------------------- */ - /* for all print levels and precisions, do: */ - /* ---------------------------------------------------------------------- */ - - for (print = minprint ; print <= maxprint ; print++) - { - for (precise = 0 ; precise <= (print >= 4) ? 1 : 0 ; precise++) - { - Int save1, save2 ; - - maxerr = 0 ; - my_srand (42) ; /* RAND reset */ - cm->print = print ; - cm->precise = precise ; - printf ("\n----------Print level %d precise: %d\n", - cm->print, cm->precise) ; - - save1 = cm->final_asis ; - save2 = cm->final_super ; - cm->final_asis = FALSE ; - cm->final_super = TRUE ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - cm->final_asis = save1 ; - cm->final_super = save2 ; - - /* -------------------------------------------------------------- */ - /* test various matrix operations */ - /* -------------------------------------------------------------- */ - - err = test_ops (A) ; /* RAND */ - MAXERR (maxerr, err, 1) ; - - /* -------------------------------------------------------------- */ - /* solve the augmented system */ - /* -------------------------------------------------------------- */ - - err = aug (A) ; /* no random number use */ - MAXERR (maxerr, err, 1) ; - - /* -------------------------------------------------------------- */ - /* solve using different methods */ - /* -------------------------------------------------------------- */ - - printf ("test_solver (1)\n") ; - cm->nmethods = 9 ; - cm->final_asis = TRUE ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (2)\n") ; - cm->final_asis = TRUE ; - for (nmethods = 0 ; nmethods < 7 ; nmethods++) - { - cm->nmethods = nmethods ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - } - - printf ("test_solver (3)\n") ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NESDIS ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (3b)\n") ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NESDIS ; - cm->method [0].nd_camd = 2 ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (3c)\n") ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (4)\n") ; - cm->nmethods = 1 ; - cm->method[0].ordering = CHOLMOD_METIS ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (5)\n") ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_AMD ; - CHOLMOD(free_work) (cm) ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - printf ("test_solver (6)\n") ; - cm->nmethods = 1 ; - cm->method[0].ordering = CHOLMOD_COLAMD ; - err = test_solver (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - /* -------------------------------------------------------------- */ - /* restore default control parameters */ - /* -------------------------------------------------------------- */ - - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; - } - } - - printf ("do_matrix max error %.1g\n", maxerr) ; - - return (maxerr) ; -} - - -/* ========================================================================== */ -/* === main ================================================================= */ -/* ========================================================================== */ - -/* Usage: - * cm < matrix do not perform intensive memory-failure tests - * cm -m < matrix do perform memory tests - * cm -s < matrix matrix is singular, nan error expected - * - * (The memory tests are performed if any argument is given to cm). - */ - -int main (int argc, char **argv) -{ - cholmod_triplet *T ; - cholmod_sparse *A, *C, *AT ; - char *s ; - double err = 0, maxerr = 0 ; - Int n = 0, nmin = 0, nrow = 0, ncol = 0, save ; - int singular, do_memory, i, do_nantests, ok ; - double v = CHOLMOD_VERSION, tic [2], t ; - int version [3] ; - char *p ; - const char* env_use_gpu; - - SuiteSparse_start ( ) ; - SuiteSparse_tic (tic) ; - printf ("Testing CHOLMOD (%g): %d ", v, CHOLMOD(version) (version)) ; - printf ("(%d.%d.%d)\n", version [0], version [1], version [2]) ; - v = SUITESPARSE_VERSION ; - printf ("for SuiteSparse (%g): %d ", v, SuiteSparse_version (version)) ; - printf ("(%d.%d.%d)\n", version [0], version [1], version [2]) ; - printf ("%s: argc: %d\n", argv [0], argc) ; - my_srand (42) ; /* RAND */ - - /* Ignore floating point exceptions. Infs and NaNs are generated - on purpose. */ - signal (SIGFPE, SIG_IGN) ; - - /* query the CHOLMOD_USE_GPU environment variable */ - env_use_gpu = getenv ("CHOLMOD_USE_GPU") ; - if ( env_use_gpu ) - { - /* CHOLMOD_USE_GPU environment variable is set to something */ - if ( atoi ( env_use_gpu ) == 0 ) - { - printf ("CHOLMOD_USE_GPU 0\n") ; - } - else - { - printf ("CHOLMOD_USE_GPU 1 (ignored for this test)\n") ; - } - } - else - { - printf ("CHOLMOD_USE_GPU not present\n") ; - } - - fflush (stdout) ; - - singular = FALSE ; - do_memory = FALSE ; - do_nantests = FALSE ; - for (i = 1 ; i < argc ; i++) - { - s = argv [i] ; - if (s [0] == '-' && s [1] == 'm') do_memory = TRUE ; - if (s [0] == '-' && s [1] == 's') singular = TRUE ; - if (s [0] == '-' && s [1] == 'n') do_nantests = TRUE ; - } - - printf ("do_memory: %d singular: %d\n", do_memory, singular) ; - - /* ---------------------------------------------------------------------- */ - /* test SuiteSparse malloc functions */ - /* ---------------------------------------------------------------------- */ - - p = SuiteSparse_malloc (0, 0) ; - OKP (p) ; - p [0] = 'a' ; - SuiteSparse_free (p) ; - p = SuiteSparse_calloc (0, 0) ; - OKP (p) ; - p [0] = 'a' ; - p = SuiteSparse_realloc (0, 0, 0, p, &ok) ; - OK (ok) ; - OKP (p) ; - p [0] = 'a' ; - SuiteSparse_free (p) ; - p = SuiteSparse_malloc (INT64_MAX, 1024) ; - NOP (p) ; - p = SuiteSparse_calloc (INT64_MAX, 1024) ; - NOP (p) ; - p = SuiteSparse_realloc (0, 0, 0, NULL, &ok) ; - OK (ok) ; - OKP (p) ; - p [0] = 'a' ; - SuiteSparse_free (p) ; - p = SuiteSparse_realloc (INT64_MAX, 0, 1024, NULL, &ok) ; - NOP (p) ; - NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* initialize CHOLMOD */ - /* ---------------------------------------------------------------------- */ - - cm = &Common ; - OK (CHOLMOD(start) (cm)) ; cm->useGPU = 0 ; - - /* ---------------------------------------------------------------------- */ - /* test all methods with NULL common */ - /* ---------------------------------------------------------------------- */ - - /* no user error handler, since lots of errors will be raised here */ - cm->error_handler = NULL ; - null_test (NULL) ; - save = cm->itype ; - cm->itype = -999 ; - null_test (cm) ; - cm->itype = save ; - null_test2 ( ) ; - CHOLMOD(finish) (cm) ; - OK (cm->malloc_count == 0) ; - OK (CHOLMOD(start) (cm)) ; cm->useGPU = 0 ; - - /* ---------------------------------------------------------------------- */ - /* create basic scalars */ - /* ---------------------------------------------------------------------- */ - - Zero [0] = 0 ; - Zero [1] = 0 ; - - zero [0] = 0 ; - zero [1] = 0 ; - one [0] = 1 ; - one [1] = 0 ; - minusone [0] = -1 ; - minusone [1] = 0 ; - M1 = CHOLMOD(ones) (1, 1, CHOLMOD_REAL, cm) ; - - if (M1 != NULL) - { - ((double *) (M1->x)) [0] = -1 ; - } - - /* ---------------------------------------------------------------------- */ - /* read in a triplet matrix and use it to test CHOLMOD */ - /* ---------------------------------------------------------------------- */ - - for ( ; (T = read_triplet (stdin)) != NULL ; ) /* RAND */ - { - - if (T->nrow > 1000000) - { - /* do huge-problem tests only, but only for 32-bit systems */ - if (sizeof (Int) == sizeof (int)) - { - huge ( ) ; - } - CHOLMOD(free_triplet) (&T, cm) ; - continue ; - } - - maxerr = 0 ; - CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; - cm->error_handler = my_handler ; - cm->print = 4 ; - cm->precise = FALSE ; - cm->nmethods = 8 ; - - /* ------------------------------------------------------------------ */ - /* convert triplet to sparse matrix */ - /* ------------------------------------------------------------------ */ - - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - AT = CHOLMOD(transpose) (A, 0, cm) ; - OK (CHOLMOD(print_sparse) (A, "Test matrix, A", cm)) ; - C = unpack (A) ; /* RAND */ - OK (CHOLMOD(print_sparse) (C, "Unpacked/unsorted version of A", cm)) ; - - cm->print = 1 ; - - if (T != NULL) - { - nrow = T->nrow ; - ncol = T->ncol ; - n = MAX (nrow, ncol) ; - nmin = MIN (nrow, ncol) ; - } - - /* ------------------------------------------------------------------ */ - /* basic error tests */ - /* ------------------------------------------------------------------ */ - -// printf ("null2:: start malloc count "ID" inuse "ID"\n", -// (Int) cm->malloc_count, -// (Int) cm->memory_inuse) ; - - null2 (T, do_nantests) ; /* RAND */ - -// printf ("null2:: done malloc count "ID" inuse "ID"\n", -// (Int) cm->malloc_count, -// (Int) cm->memory_inuse) ; - - printf ("Null2 OK : no error\n") ; - if (do_nantests) - { - maxerr = 0 ; - goto done ; /* yes, this is ugly */ - } - - /* ------------------------------------------------------------------ */ - /* raw factorization tests */ - /* ------------------------------------------------------------------ */ - - cm->error_handler = NULL ; - err = raw_factor (A, 2) ; /* RAND */ - cm->error_handler = my_handler ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error %.1g\n", err) ; - - err = raw_factor2 (A, 0., 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error2 %.1g\n", err) ; - - err = raw_factor2 (A, 1e-16, 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error3 %.1g\n", err) ; - - if (n < 1000 && A && T && A->stype == 1) - { - /* factorize a symmetric matrix (upper part stored), possibly - * with ignored entries in lower triangular part. */ - cholmod_sparse *F ; - int save = T->stype ; - - printf ("triplet to sparse:\n") ; - T->stype = 0 ; - F = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - T->stype = save ; - // OKP (F) ; - - /* - ET = CHOLMOD(transpose) (E, 2, cm) ; - if (E) E->stype = 0 ; - if (ET) ET->stype = 0 ; - F = CHOLMOD(add) (E, ET, one, one, 1, 1, cm) ; - */ - - if (F) F->stype = 1 ; - - err = raw_factor2 (F, 0., 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error4 %.1g\n", err) ; - - err = raw_factor2 (F, 1e-16, 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error5 %.1g\n", err) ; - - cm->dbound = 1e-15 ; - - err = raw_factor2 (F, 0., 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error6 %.1g\n", err) ; - - err = raw_factor2 (F, 1e-16, 0) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error7 %.1g\n", err) ; - - err = raw_factor2 (F, 1e-16, 1) ; - MAXERR (maxerr, err, 1) ; - printf ("raw factorization error8 %.1g\n", err) ; - - cm->dbound = 0 ; - - /* - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&ET, cm) ; - */ - - CHOLMOD(free_sparse) (&F, cm) ; - } - - /* ------------------------------------------------------------------ */ - /* matrix ops */ - /* ------------------------------------------------------------------ */ - - err = test_ops (A) ; /* RAND */ - MAXERR (maxerr, err, 1) ; - printf ("initial testops error %.1g\n", err) ; - - /* ------------------------------------------------------------------ */ - /* analyze, factorize, solve */ - /* ------------------------------------------------------------------ */ - - err = solve (A) ; /* RAND */ - MAXERR (maxerr, err, 1) ; - printf ("initial solve error %.1g\n", err) ; - - /* ------------------------------------------------------------------ */ - /* CCOLAMD tests */ - /* ------------------------------------------------------------------ */ - - cctest (A) ; /* RAND reset */ - cctest (AT) ; /* RAND reset */ - - /* ------------------------------------------------------------------ */ - /* COLAMD tests */ - /* ------------------------------------------------------------------ */ - - ctest (A) ; - ctest (AT) ; - - /* ------------------------------------------------------------------ */ - /* AMD tests */ - /* ------------------------------------------------------------------ */ - - if (n < NLARGE || A->stype) - { - /* for unsymmetric matrices, this forms A*A' and A'*A, which can - * fail if A has a dense row or column. So it is only done for - * modest-sized unsymmetric matrices. */ - amdtest (A) ; - amdtest (AT) ; - camdtest (A) ; /* RAND */ - camdtest (AT) ; /* RAND */ - } - - if (n < NSMALL) - { - - /* -------------------------------------------------------------- */ - /* do_matrix with an unpacked matrix */ - /* -------------------------------------------------------------- */ - - /* try with an unpacked matrix, and a non-default dbound */ - cm->dbound = 1e-15 ; - err = do_matrix (C) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - cm->dbound = 0 ; - - /* -------------------------------------------------------------- */ - /* do_matrix: analyze, factorize, and solve, with many options */ - /* -------------------------------------------------------------- */ - - err = do_matrix (A) ; /* RAND reset */ - MAXERR (maxerr, err, 1) ; - - /* -------------------------------------------------------------- */ - /* pretend to solve an LP */ - /* -------------------------------------------------------------- */ - - if (nrow != ncol) - { - cm->print = 2 ; - err = lpdemo (T) ; /* RAND */ - cm->print = 1 ; - MAXERR (maxerr, err, 1) ; - cm->print = 5; CHOLMOD(print_common) ("Common", cm);cm->print=1; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_COLAMD ; - err = lpdemo (T) ; /* RAND */ - MAXERR (maxerr, err, 1) ; - printf ("initial lp error %.1g, dbound %g\n", err, cm->dbound) ; - cm->nmethods = 0 ; - cm->method [0].ordering = CHOLMOD_GIVEN ; - } - } - - progress (1, '|') ; - - if (n < NSMALL && do_memory) - { - - /* -------------------------------------------------------------- */ - /* Exhaustive memory-error handling */ - /* -------------------------------------------------------------- */ - - memory_tests (T) ; /* RAND */ - } - - /* ------------------------------------------------------------------ */ - /* free matrices and print results */ - /* ------------------------------------------------------------------ */ - - done: /* an ugly "goto" target; added to minimize code changes - * when added "do_nantests", for version 1.0.2 */ - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_sparse) (&A, cm) ; - CHOLMOD(free_triplet) (&T, cm) ; - - fprintf (stderr, "\n " - " Test OK") ; - if (nrow <= ncol && !singular) - { - /* maxerr should be NaN if nrow > ncol, so don't print it */ - fprintf (stderr, ", maxerr %.1g", maxerr) ; - } - fprintf (stderr, "\n") ; - my_srand (42) ; /* RAND reset */ - } - - /* ---------------------------------------------------------------------- */ - /* finalize CHOLMOD */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free_dense) (&M1, cm) ; - CHOLMOD(finish) (cm) ; - - cm->print = 5 ; OK (CHOLMOD(print_common) ("cm", cm)) ; - - printf ("FINAL::malloc count "ID" inuse "ID"\n", - (Int) cm->malloc_count, - (Int) cm->memory_inuse) ; - - OK (cm->malloc_count == 0) ; - OK (cm->memory_inuse == 0) ; - t = SuiteSparse_toc (tic) ; - if (nrow > ncol) - { - /* maxerr should be NaN, so don't print it */ - printf ("All tests successful: time %.1g\n", t) ; - } - else - { - printf ("All tests successful: max error %.1g time: %.1g\n", maxerr, t); - } - - SuiteSparse_finish ( ) ; - return (0) ; -} diff --git a/CHOLMOD/Tcov/cm.h b/CHOLMOD/Tcov/cm.h index 8a326b8d5c..b59414b944 100644 --- a/CHOLMOD/Tcov/cm.h +++ b/CHOLMOD/Tcov/cm.h @@ -2,12 +2,15 @@ // CHOLMOD/Tcov/cm.h: include file for CHOLMOD test programs //------------------------------------------------------------------------------ -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ +#ifndef CM_H +#define CM_H + #define SUITESPARSE_BLAS_DEFINITIONS #include "cholmod.h" #include @@ -16,10 +19,21 @@ #include #include -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ #include "cholmod_internal.h" +#ifdef SINGLE + // single precision + #define Real float +#else + // double precision + #ifndef DOUBLE + #define DOUBLE + #endif + #define Real double +#endif + #define EMPTY (-1) #define TRUE 1 #define FALSE 0 @@ -36,32 +50,35 @@ #define MY_RAND_MAX 32767 -#define MAXERR(maxerr,err,anorm) \ -{ \ - if (ISNAN (maxerr)) \ - { \ - /* do nothing */ ; \ - } \ - else if (ISNAN (err)) \ - { \ - maxerr = err ; \ - } \ - else if (anorm > 0) \ - { \ - if ((err/anorm) > maxerr) maxerr = (err/anorm) ; \ - } \ - else \ - { \ - if (err > maxerr) maxerr = err ; \ - } \ - /* printf ("MAXERR: %7.2e %7.2e %7.2e in %d : %s\n", \ - maxerr, err, (double) anorm, __LINE__, __FILE__ ) ; */ \ +#define MAXLINE 1024 + +#define MAXERR(maxerr,err,anorm) \ +{ \ + double a = (double) anorm ; \ + if (ISNAN (maxerr)) \ + { \ + ; \ + } \ + else if (ISNAN (err)) \ + { \ + maxerr = err ; \ + } \ + else if (a > 0) \ + { \ + if ((err/a) > maxerr) maxerr = (err/a) ; \ + } \ + else \ + { \ + if (err > maxerr) maxerr = err ; \ + } \ + /* printf ("maxerr %g err %g anorm %g at %d:%s\n", */ \ + /* maxerr, err, a, __LINE__, __FILE__) ; */ \ } -#define OKP(p) Assert ((p) != NULL, __FILE__, __LINE__) -#define OK(truth) Assert (truth, __FILE__, __LINE__) -#define NOT(truth) Assert (!(truth), __FILE__, __LINE__) -#define NOP(p) Assert ((p) == NULL, __FILE__, __LINE__) +#define OKP(p) Assert ((p) != NULL, __FILE__, __LINE__) +#define OK(truth) Assert (truth, __FILE__, __LINE__) +#define NOT(truth) Assert (!(truth), __FILE__, __LINE__) +#define NOP(p) Assert ((p) == NULL, __FILE__, __LINE__) #define NSMALL 200 #define NLARGE 1000 @@ -70,9 +87,9 @@ #define ERROR(status,message) \ CHOLMOD(error) (status, __FILE__, __LINE__, message, cm) -/* -------------------------------------------------------------------------- */ -/* global variables */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// global variables +//------------------------------------------------------------------------------ #ifndef EXTERN #define EXTERN extern @@ -80,27 +97,29 @@ EXTERN double zero [2], one [2], minusone [2] ; EXTERN cholmod_common Common, *cm ; -EXTERN cholmod_dense *M1 ; EXTERN int64_t my_tries ; EXTERN double Zero [2] ; -/* -------------------------------------------------------------------------- */ -/* prototypes */ -/* -------------------------------------------------------------------------- */ +//------------------------------------------------------------------------------ +// prototypes +//------------------------------------------------------------------------------ void null_test (cholmod_common *) ; void null_test2 (void) ; void Assert (int truth, char *file, int line) ; Int nrand (Int n) ; Int *prand (Int n) ; + +double ptest (cholmod_sparse *A, cholmod_sparse *B, Int *perm, Int n) ; cholmod_triplet *read_triplet (FILE *f) ; double test_ops (cholmod_sparse *A) ; -cholmod_dense *xtrue (Int nrow, Int ncol, Int d, Int xtype) ; +double test_ops2 (cholmod_sparse *A) ; +cholmod_dense *xtrue (Int nrow, Int ncol, Int d, int xdtype, int tweak) ; double resid (cholmod_sparse *A, cholmod_dense *X, cholmod_dense *B) ; double solve (cholmod_sparse *A) ; double aug (cholmod_sparse *A) ; double do_matrix (cholmod_sparse *A) ; -cholmod_dense *rhs (cholmod_sparse *A, Int nrhs, Int d) ; +cholmod_dense *rhs (cholmod_sparse *A, Int nrhs, Int d, int tweak) ; void prune_row (cholmod_sparse *A, Int k) ; double pnorm (cholmod_dense *X, Int *P, cholmod_dense *B, Int inv) ; double test_solver (cholmod_sparse *A) ; @@ -113,7 +132,7 @@ double xrand (double range) ; double lp_resid (cholmod_sparse *A, Int *rflag, Int *fset, Int fsize, double beta [2], cholmod_dense *X, cholmod_dense *B) ; double lpdemo (cholmod_triplet *T) ; -cholmod_sparse *lp_prune ( cholmod_sparse *A, Int *rflag, Int *fset, Int fsize); +cholmod_sparse *lp_prune (cholmod_sparse *A, Int *rflag, Int *fset, Int fsize); void null2 (cholmod_triplet *Tok, int do_nantests) ; void *my_malloc2 (size_t size) ; void *my_calloc2 (size_t n, size_t size) ; @@ -121,8 +140,8 @@ void *my_realloc2 (void *p, size_t size) ; void my_free2 (void *p) ; void memory_tests (cholmod_triplet *T) ; void progress (Int force, char s) ; -void test_memory_handler ( void ) ; -void normal_memory_handler ( void ) ; +void test_memory_handler (void) ; +void normal_memory_handler (void) ; cholmod_sparse *unpack (cholmod_sparse *A) ; Int nzdiag (cholmod_sparse *A) ; Int check_partition (cholmod_sparse *A, Int *Part) ; @@ -138,114 +157,144 @@ Int check_constraints (Int *P, Int *Cmember, Int n) ; void ctest (cholmod_sparse *A) ; void amdtest (cholmod_sparse *A) ; double resid_sparse (cholmod_sparse *A, cholmod_sparse *X, cholmod_sparse *B) ; -cholmod_dense *zeros (Int nrow, Int ncol, Int d, Int xtype) ; +cholmod_dense *zeros (Int nrow, Int ncol, Int d, int xdtype) ; void huge (void) ; void camdtest (cholmod_sparse *A) ; +void basic1 (cholmod_common *) ; +void overflow_tests (cholmod_common *cm) ; +void sparse_dump (cholmod_sparse *A, char *filename, cholmod_common *cm) ; +void factor_dump (cholmod_factor *L, char *L_filename, char *P_filename, + cholmod_common *cm) ; +void dense_dump (cholmod_dense *X, char *filename, cholmod_common *cm) ; +void Int_dump (Int *P, Int n, char *filename, cholmod_common *cm) ; +double znorm_diag (cholmod_sparse *A, cholmod_common *cm) ; + +cholmod_dense *rand_dense +( + Int nrow, + Int ncol, + int xdtype, + cholmod_common *Common +) ; + +cholmod_sparse *perm_matrix (Int *perm, Int n, int xdtype, + cholmod_common *Common) ; -/* -------------------------------------------------------------------------- */ -/* AMD, COLAMD, and CCOLAMD */ -/* -------------------------------------------------------------------------- */ +double cat_tests (cholmod_sparse *A, cholmod_common *cm) ; +double dense_tests (cholmod_sparse *A, cholmod_common *cm) ; +double dtype_tests (cholmod_sparse *A, cholmod_common *cm) ; +void common_tests (cholmod_common *cm) ; +void error_tests (cholmod_sparse *A, cholmod_common *cm) ; +double tofrom_tests (cholmod_sparse *A, cholmod_common *cm) ; +double suitesparse_tests (void) ; + +//------------------------------------------------------------------------------ +// AMD, COLAMD, and CCOLAMD +//------------------------------------------------------------------------------ #ifdef CHOLMOD_INT64 -#define AMD_order amd_l_order -#define AMD_defaults amd_l_defaults -#define AMD_control amd_l_control -#define AMD_info amd_l_info -#define AMD_1 amd_l1 -#define AMD_2 amd_l2 -#define AMD_valid amd_l_valid -#define AMD_aat amd_l_aat -#define AMD_postorder amd_l_postorder -#define AMD_post_tree amd_l_post_tree -#define AMD_dump amd_l_dump -#define AMD_debug amd_l_debug -#define AMD_debug_init amd_l_debug_init -#define AMD_preprocess amd_l_preprocess - -#define CAMD_order camd_l_order -#define CAMD_defaults camd_l_defaults -#define CAMD_control camd_l_control -#define CAMD_info camd_l_info -#define CAMD_1 camd_l1 -#define CAMD_2 camd_l2 -#define CAMD_valid camd_l_valid -#define CAMD_cvalid camd_l_cvalid -#define CAMD_aat camd_l_aat -#define CAMD_postorder camd_l_postorder -#define CAMD_dump camd_l_dump -#define CAMD_debug camd_l_debug -#define CAMD_debug_init camd_l_debug_init -#define CAMD_preprocess camd_l_preprocess - -#define CCOLAMD_recommended ccolamd_l_recommended -#define CCOLAMD_set_defaults ccolamd_l_set_defaults -#define CCOLAMD_2 ccolamd2_l -#define CCOLAMD_MAIN ccolamd_l -#define CCOLAMD_apply_order ccolamd_l_apply_order -#define CCOLAMD_postorder ccolamd_l_postorder -#define CCOLAMD_post_tree ccolamd_l_post_tree -#define CCOLAMD_fsize ccolamd_l_fsize -#define CSYMAMD_MAIN csymamd_l -#define CCOLAMD_report ccolamd_l_report -#define CSYMAMD_report csymamd_l_report - -#define COLAMD_recommended colamd_l_recommended -#define COLAMD_set_defaults colamd_l_set_defaults -#define COLAMD_MAIN colamd_l -#define SYMAMD_MAIN symamd_l -#define COLAMD_report colamd_l_report -#define SYMAMD_report symamd_l_report + #define AMD_order amd_l_order + #define AMD_defaults amd_l_defaults + #define AMD_control amd_l_control + #define AMD_info amd_l_info + #define AMD_1 amd_l1 + #define AMD_2 amd_l2 + #define AMD_valid amd_l_valid + #define AMD_aat amd_l_aat + #define AMD_postorder amd_l_postorder + #define AMD_post_tree amd_l_post_tree + #define AMD_dump amd_l_dump + #define AMD_debug amd_l_debug + #define AMD_debug_init amd_l_debug_init + #define AMD_preprocess amd_l_preprocess + + #define CAMD_order camd_l_order + #define CAMD_defaults camd_l_defaults + #define CAMD_control camd_l_control + #define CAMD_info camd_l_info + #define CAMD_1 camd_l1 + #define CAMD_2 camd_l2 + #define CAMD_valid camd_l_valid + #define CAMD_cvalid camd_l_cvalid + #define CAMD_aat camd_l_aat + #define CAMD_postorder camd_l_postorder + #define CAMD_dump camd_l_dump + #define CAMD_debug camd_l_debug + #define CAMD_debug_init camd_l_debug_init + #define CAMD_preprocess camd_l_preprocess + + #define CCOLAMD_recommended ccolamd_l_recommended + #define CCOLAMD_set_defaults ccolamd_l_set_defaults + #define CCOLAMD_2 ccolamd2_l + #define CCOLAMD_MAIN ccolamd_l + #define CCOLAMD_apply_order ccolamd_l_apply_order + #define CCOLAMD_postorder ccolamd_l_postorder + #define CCOLAMD_post_tree ccolamd_l_post_tree + #define CCOLAMD_fsize ccolamd_l_fsize + #define CSYMAMD_MAIN csymamd_l + #define CCOLAMD_report ccolamd_l_report + #define CSYMAMD_report csymamd_l_report + + #define COLAMD_recommended colamd_l_recommended + #define COLAMD_set_defaults colamd_l_set_defaults + #define COLAMD_MAIN colamd_l + #define SYMAMD_MAIN symamd_l + #define COLAMD_report colamd_l_report + #define SYMAMD_report symamd_l_report #else -#define AMD_order amd_order -#define AMD_defaults amd_defaults -#define AMD_control amd_control -#define AMD_info amd_info -#define AMD_1 amd_1 -#define AMD_2 amd_2 -#define AMD_valid amd_valid -#define AMD_aat amd_aat -#define AMD_postorder amd_postorder -#define AMD_post_tree amd_post_tree -#define AMD_dump amd_dump -#define AMD_debug amd_debug -#define AMD_debug_init amd_debug_init -#define AMD_preprocess amd_preprocess - -#define CAMD_order camd_order -#define CAMD_defaults camd_defaults -#define CAMD_control camd_control -#define CAMD_info camd_info -#define CAMD_1 camd_1 -#define CAMD_2 camd_2 -#define CAMD_valid camd_valid -#define CAMD_cvalid camd_cvalid -#define CAMD_aat camd_aat -#define CAMD_postorder camd_postorder -#define CAMD_dump camd_dump -#define CAMD_debug camd_debug -#define CAMD_debug_init camd_debug_init -#define CAMD_preprocess camd_preprocess - -#define CCOLAMD_recommended ccolamd_recommended -#define CCOLAMD_set_defaults ccolamd_set_defaults -#define CCOLAMD_2 ccolamd2 -#define CCOLAMD_MAIN ccolamd -#define CCOLAMD_apply_order ccolamd_apply_order -#define CCOLAMD_postorder ccolamd_postorder -#define CCOLAMD_post_tree ccolamd_post_tree -#define CCOLAMD_fsize ccolamd_fsize -#define CSYMAMD_MAIN csymamd -#define CCOLAMD_report ccolamd_report -#define CSYMAMD_report csymamd_report - -#define COLAMD_recommended colamd_recommended -#define COLAMD_set_defaults colamd_set_defaults -#define COLAMD_MAIN colamd -#define SYMAMD_MAIN symamd -#define COLAMD_report colamd_report -#define SYMAMD_report symamd_report + #define AMD_order amd_order + #define AMD_defaults amd_defaults + #define AMD_control amd_control + #define AMD_info amd_info + #define AMD_1 amd_1 + #define AMD_2 amd_2 + #define AMD_valid amd_valid + #define AMD_aat amd_aat + #define AMD_postorder amd_postorder + #define AMD_post_tree amd_post_tree + #define AMD_dump amd_dump + #define AMD_debug amd_debug + #define AMD_debug_init amd_debug_init + #define AMD_preprocess amd_preprocess + + #define CAMD_order camd_order + #define CAMD_defaults camd_defaults + #define CAMD_control camd_control + #define CAMD_info camd_info + #define CAMD_1 camd_1 + #define CAMD_2 camd_2 + #define CAMD_valid camd_valid + #define CAMD_cvalid camd_cvalid + #define CAMD_aat camd_aat + #define CAMD_postorder camd_postorder + #define CAMD_dump camd_dump + #define CAMD_debug camd_debug + #define CAMD_debug_init camd_debug_init + #define CAMD_preprocess camd_preprocess + + #define CCOLAMD_recommended ccolamd_recommended + #define CCOLAMD_set_defaults ccolamd_set_defaults + #define CCOLAMD_2 ccolamd2 + #define CCOLAMD_MAIN ccolamd + #define CCOLAMD_apply_order ccolamd_apply_order + #define CCOLAMD_postorder ccolamd_postorder + #define CCOLAMD_post_tree ccolamd_post_tree + #define CCOLAMD_fsize ccolamd_fsize + #define CSYMAMD_MAIN csymamd + #define CCOLAMD_report ccolamd_report + #define CSYMAMD_report csymamd_report + + #define COLAMD_recommended colamd_recommended + #define COLAMD_set_defaults colamd_set_defaults + #define COLAMD_MAIN colamd + #define SYMAMD_MAIN symamd + #define COLAMD_report colamd_report + #define SYMAMD_report symamd_report #endif + +#endif + diff --git a/CHOLMOD/Tcov/cmread.c b/CHOLMOD/Tcov/cmread.c deleted file mode 100644 index 5f366c56dd..0000000000 --- a/CHOLMOD/Tcov/cmread.c +++ /dev/null @@ -1,116 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/cmread: test program that reads in a sparse matrix -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Read in a matrix from a file and print it out. - * - * Usage: - * cmread matrixfile - * cmread < matrixfile - */ - -#include "cholmod.h" - -#ifdef CHOLMOD_INT64 -#define CHOLMOD(routine) cholmod_l_ ## routine -#define Int int64_t -#define UInt uint64_t -#else -#define CHOLMOD(routine) cholmod_ ## routine -#define Int int32_t -#define UInt uint32_t -#endif - -int main (int argc, char **argv) -{ - cholmod_sparse *A, *C, *Z ; - cholmod_dense *X ; - cholmod_triplet *T ; - void *V ; - FILE *f, *f2 ; - cholmod_common Common, *cm ; - int mtype, prefer, option ; - - /* ---------------------------------------------------------------------- */ - /* get the file containing the input matrix */ - /* ---------------------------------------------------------------------- */ - - if (argc > 1) - { - if ((f = fopen (argv [1], "r")) == NULL) - { - printf ("cannot open file: %s\n", argv [1]) ; - return (0) ; - } - } - else - { - f = stdin ; - } - - /* ---------------------------------------------------------------------- */ - /* start CHOLMOD, read the matrix, print it, and free it */ - /* ---------------------------------------------------------------------- */ - - cm = &Common ; - CHOLMOD (start) (cm) ; - cm->print = 5 ; - A = CHOLMOD (read_sparse) (f, cm) ; - if (argc > 1) fclose (f) ; - CHOLMOD (print_sparse) (A, "A", cm) ; - - if (argc > 1) - { - for (prefer = 0 ; prefer <= 2 ; prefer++) - { - printf ("\n---------------------- Prefer: %d\n", prefer) ; - f = fopen (argv [1], "r") ; - V = CHOLMOD (read_matrix) (f, prefer, &mtype, cm) ; - if (V != NULL) switch (mtype) - { - case CHOLMOD_TRIPLET: - T = V ; - CHOLMOD (print_triplet) (T, "T", cm) ; - CHOLMOD (free_triplet) (&T, cm) ; - break ; - case CHOLMOD_SPARSE: - C = V ; - CHOLMOD (print_sparse) (C, "C", cm) ; - Z = CHOLMOD (speye) (C->nrow, C->ncol, CHOLMOD_PATTERN, cm); - for (option = 0 ; option <= 2 ; option++) - { - int asym ; - Int xmatch = 0, pmatch = 0, nzoff = 0, nzd = 0 ; - asym = CHOLMOD (symmetry) (C, option, - &xmatch, &pmatch, &nzoff, &nzd, cm) ; - f2 = fopen ("temp5.mtx", "w") ; - CHOLMOD (write_sparse) (f2, C, Z, NULL, cm) ; - fclose (f2) ; - printf ("asym %d\n", asym) ; - } - CHOLMOD (free_sparse) (&C, cm) ; - CHOLMOD (free_sparse) (&Z, cm) ; - break ; - case CHOLMOD_DENSE: - X = V ; - CHOLMOD (print_dense) (X, "X", cm) ; - f2 = fopen ("temp5.mtx", "w") ; - CHOLMOD (write_dense) (f2, X, NULL, cm) ; - fclose (f2) ; - CHOLMOD (free_dense) (&X, cm) ; - break ; - } - fclose (f) ; - } - } - - CHOLMOD (free_sparse) (&A, cm) ; - CHOLMOD (finish) (cm) ; - return (0) ; -} diff --git a/CHOLMOD/Tcov/cov.awk b/CHOLMOD/Tcov/cov.awk index 5744b40065..23db56450e 100644 --- a/CHOLMOD/Tcov/cov.awk +++ b/CHOLMOD/Tcov/cov.awk @@ -11,7 +11,7 @@ if ((p+0) != 100) { - printf "%8s %s\n", p, f + printf "%8s %s\n", p, f } } diff --git a/CHOLMOD/Tcov/covall b/CHOLMOD/Tcov/covall index 9667506cbd..043aa3d2be 100755 --- a/CHOLMOD/Tcov/covall +++ b/CHOLMOD/Tcov/covall @@ -1,12 +1,13 @@ #!/bin/bash # ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ # ------------------------------------------------------------------------------ ./gcovs z_*.c zz_*.c l_*.c ui_*.c ul_*.c zl_*.c ./covs *.gcov > covs.out -echo -n "statments not yet tested: " +echo -n "statements not yet tested: " grep -c "#####" covs.out +exit 0 diff --git a/CHOLMOD/Tcov/cover b/CHOLMOD/Tcov/cover index 6bcc04093a..630667b6f3 100755 --- a/CHOLMOD/Tcov/cover +++ b/CHOLMOD/Tcov/cover @@ -1,7 +1,7 @@ #!/bin/bash # ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ # ------------------------------------------------------------------------------ @@ -10,8 +10,8 @@ echo '=================================================================' for file in $@ do - echo $file - echo '=================================================================' - grep "#####" -A5 -B5 $file - echo '=================================================================' + echo $file + echo '=================================================================' + grep "#####" -A5 -B5 $file + echo '=================================================================' done diff --git a/CHOLMOD/Tcov/covs b/CHOLMOD/Tcov/covs index af690c0e45..ebc9933821 100755 --- a/CHOLMOD/Tcov/covs +++ b/CHOLMOD/Tcov/covs @@ -1,7 +1,7 @@ #!/bin/bash # ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ # ------------------------------------------------------------------------------ @@ -10,8 +10,8 @@ echo '=================================================================' for file in $@ do - echo $file - grep "#####" -A5 -B5 $file | grep -v "\<_" | grep -v "return 0;" | \ - grep -v "#####:[ ]*[0-9]*:[{}]" - echo '=================================================================' + echo $file + grep "#####" -A5 -B5 $file | grep -v "\<_" | grep -v "return 0;" | \ + grep -v "#####:[ ]*[0-9]*:[{}]" + echo '=================================================================' done diff --git a/CHOLMOD/Tcov/ctest.c b/CHOLMOD/Tcov/ctest.c deleted file mode 100644 index 87882faec3..0000000000 --- a/CHOLMOD/Tcov/ctest.c +++ /dev/null @@ -1,337 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/ctest: test for COLAMD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test for colamd v2.4 */ - -#include "cm.h" -#include "colamd.h" - - -/* ========================================================================== */ -/* === ctest ================================================================ */ -/* ========================================================================== */ - -void ctest (cholmod_sparse *A) -{ - double knobs [COLAMD_KNOBS], knobs2 [COLAMD_KNOBS] ; - Int *P, *Cp, *Ci, *Si, *Sp ; - cholmod_sparse *C, *A2, *B, *S, *BT ; - Int nrow, ncol, alen, ok, stats [COLAMD_STATS], i, p, trial ; - size_t s ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - printf ("\nCOLAMD test\n") ; - - if (A == NULL) - { - return ; - } - - if (A->stype) - { - A2 = CHOLMOD(copy) (A, 0, 0, cm) ; - B = A2 ; - } - else - { - A2 = NULL ; - B = A ; - } - - nrow = B->nrow ; - ncol = B->ncol ; - S = NULL ; - - /* ---------------------------------------------------------------------- */ - /* allocate workspace colamd */ - /* ---------------------------------------------------------------------- */ - - P = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; - - COLAMD_set_defaults (knobs) ; - COLAMD_set_defaults (knobs2) ; - COLAMD_set_defaults (NULL) ; - COLAMD_report (NULL) ; - SYMAMD_report (NULL) ; - - alen = COLAMD_recommended (B->nzmax, ncol, nrow) ; - C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - Cp = C->p ; - Ci = C->i ; - - /* ---------------------------------------------------------------------- */ - /* order with colamd */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - CHOLMOD(print_sparse) (C, "C for colamd", cm) ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, NULL, stats) ; - COLAMD_report (stats) ; - OK (ok) ; - ok = stats [COLAMD_STATUS] ; - ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ; - OK (ok) ; - - /* permutation returned in C->p, if the ordering succeeded */ - /* make sure P obeys the constraints */ - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; - - /* ---------------------------------------------------------------------- */ - /* with different dense thresholds */ - /* ---------------------------------------------------------------------- */ - - printf ("\nall dense rows:\n") ; - knobs2 [COLAMD_DENSE_ROW] = 0 ; - knobs2 [COLAMD_DENSE_COL] = 0.5 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; - COLAMD_report (stats) ; - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; - - printf ("\nall dense cols:\n") ; - knobs2 [COLAMD_DENSE_ROW] = 0.5 ; - knobs2 [COLAMD_DENSE_COL] = 0 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; - COLAMD_report (stats) ; - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; - - printf ("\nno dense rows/cols:\n") ; - knobs2 [COLAMD_DENSE_ROW] = -1 ; - knobs2 [COLAMD_DENSE_COL] = -1 ; - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; - COLAMD_report (stats) ; - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; - - knobs2 [COLAMD_DENSE_ROW] = 0.5 ; - knobs2 [COLAMD_DENSE_COL] = 0.5 ; - - /* ---------------------------------------------------------------------- */ - /* duplicate entries */ - /* ---------------------------------------------------------------------- */ - - if (ncol > 2 && nrow > 2) - { - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; - OK (ok) ; - if (Cp [1] - Cp [0] > 2) - { - Ci [0] = Ci [1] ; - } - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; - COLAMD_report (stats) ; - OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; - } - - /* ---------------------------------------------------------------------- */ - /* symamd */ - /* ---------------------------------------------------------------------- */ - - if (nrow == ncol) - { - Int n = nrow ; - - BT = CHOLMOD(transpose) (B, 0, cm) ; OKP(BT); - S = CHOLMOD(add) (B, BT, one, one, FALSE, FALSE, cm) ; - CHOLMOD(free_sparse) (&BT, cm) ; - Si = S->i ; - Sp = S->p ; - - void * (*calloc_func) (size_t, size_t) ; - void (*free_func) (void *) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - OK (ok) ; - OK (CHOLMOD(print_perm) (P, n, n, "symamd perm", cm)) ; - SYMAMD_report (stats) ; - - /* ------------------------------------------------------------------ */ - /* symamd errors */ - /* ------------------------------------------------------------------ */ - - test_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - for (trial = 0 ; trial < 3 ; trial++) - { - my_tries = trial ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok) ; - } - my_tries = 3 ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - OK (ok) ; - normal_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, NULL, - calloc_func, - free_func) ; - NOT (ok); - - ok = SYMAMD_MAIN (n, NULL, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - - ok = SYMAMD_MAIN (n, Si, NULL, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - - ok = SYMAMD_MAIN (-1, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - - p = Sp [n] ; - Sp [n] = -1 ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - Sp [n] = p ; - - Sp [0] = -1 ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - Sp [0] = 0 ; - - if (n > 2 && Sp [n] > 3) - { - p = Sp [1] ; - Sp [1] = -1 ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - Sp [1] = p ; - - i = Si [0] ; - Si [0] = -1 ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - Si [0] = i ; - - /* ok, but jumbled */ - i = Si [0] ; - Si [0] = Si [1] ; - Si [1] = i ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - OK (ok); - SYMAMD_report (stats) ; - OK (CHOLMOD(print_perm) (P, nrow, nrow, "symamd perm", cm)) ; - i = Si [0] ; - Si [0] = Si [1] ; - Si [1] = i ; - - test_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, - calloc_func, - free_func) ; - NOT (ok); - SYMAMD_report (stats) ; - normal_memory_handler ( ) ; - calloc_func = SuiteSparse_config_calloc_func_get ( ) ; - free_func = SuiteSparse_config_free_func_get ( ) ; - } - } - - /* ---------------------------------------------------------------------- */ - /* error tests */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - ok = COLAMD_MAIN (ncol, nrow, 0, Ci, Cp, knobs, stats) ; NOT (ok) ; - COLAMD_report (stats) ; - - ok = COLAMD_MAIN (ncol, nrow, alen, NULL, Cp, knobs, stats); NOT (ok) ; - COLAMD_report (stats) ; - - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, NULL, knobs, stats); NOT (ok) ; - COLAMD_report (stats) ; - - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, NULL) ; NOT (ok) ; - COLAMD_report (stats) ; - - ok = COLAMD_MAIN (-1, nrow, alen, Ci, Cp, knobs, stats) ; NOT (ok) ; - COLAMD_report (stats) ; - - ok = COLAMD_MAIN (ncol, -1, alen, Ci, Cp, knobs, stats) ; NOT (ok) ; - COLAMD_report (stats) ; - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - Cp [nrow] = -1 ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; NOT (ok) ; - COLAMD_report (stats) ; - - Cp [0] = 1 ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; NOT (ok) ; - COLAMD_report (stats) ; - - ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; - - if (nrow > 0 && alen > 0 && Cp [1] > 0) - { - - p = Cp [1] ; - Cp [1] = -1 ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; NOT(ok); - COLAMD_report (stats) ; - Cp [1] = p ; - - i = Ci [0] ; - Ci [0] = -1 ; - ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; NOT(ok); - COLAMD_report (stats) ; - Ci [0] = i ; - } - - s = COLAMD_recommended (-1, 0, 0) ; - OK (s == 0) ; - - /* ---------------------------------------------------------------------- */ - /* free workspace */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free) (nrow+1, sizeof (Int), P, cm) ; - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&A2, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; -} diff --git a/CHOLMOD/Tcov/di_amdtest.c b/CHOLMOD/Tcov/di_amdtest.c new file mode 100644 index 0000000000..ead32e2b93 --- /dev/null +++ b/CHOLMOD/Tcov/di_amdtest.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/di_amdtest: double/int32_t version of amdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_amdtest.c" + diff --git a/CHOLMOD/Tcov/di_camdtest.c b/CHOLMOD/Tcov/di_camdtest.c new file mode 100644 index 0000000000..9e81ee3004 --- /dev/null +++ b/CHOLMOD/Tcov/di_camdtest.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/di_camdtest: double/int32_t version of camdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_camdtest.c" + diff --git a/CHOLMOD/Tcov/di_huge.c b/CHOLMOD/Tcov/di_huge.c new file mode 100644 index 0000000000..d8e5c86538 --- /dev/null +++ b/CHOLMOD/Tcov/di_huge.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/di_huge: double/int32_t version of huge +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_huge.c" + diff --git a/CHOLMOD/Tcov/di_read.c b/CHOLMOD/Tcov/di_read.c new file mode 100644 index 0000000000..96cb40c736 --- /dev/null +++ b/CHOLMOD/Tcov/di_read.c @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/di_read: double/int32_t version of cmread +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_cmread.c" diff --git a/CHOLMOD/Tcov/di_test.c b/CHOLMOD/Tcov/di_test.c new file mode 100644 index 0000000000..593a18b0e1 --- /dev/null +++ b/CHOLMOD/Tcov/di_test.c @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/di_test: double/int32_t version of Tcov/cm test program +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_cm.c" +#include "t_test_ops.c" +#include "t_test_ops2.c" +#include "t_null.c" +#include "t_null2.c" +#include "t_lpdemo.c" +#include "t_memory.c" +#include "t_solve.c" +#include "t_aug.c" +#include "t_unpack.c" +#include "t_raw_factor.c" +#include "t_cctest.c" +#include "t_ctest.c" +#include "t_basic.c" +#include "t_overflow_tests.c" +#include "t_dump.c" +#include "t_read_triplet.c" +#include "t_rhs.c" +#include "t_znorm_diag.c" +#include "t_prand.c" +#include "t_perm_matrix.c" +#include "t_ptest.c" +#include "t_rand_dense.c" +#include "t_cat_tests.c" +#include "t_dense_tests.c" +#include "t_dtype_tests.c" +#include "t_common_tests.c" +#include "t_error_tests.c" +#include "t_tofrom_tests.c" +#include "t_suitesparse.c" diff --git a/CHOLMOD/Tcov/camdtest_l.c b/CHOLMOD/Tcov/dl_amdtest.c similarity index 65% rename from CHOLMOD/Tcov/camdtest_l.c rename to CHOLMOD/Tcov/dl_amdtest.c index f8566e040e..a30e6da70a 100644 --- a/CHOLMOD/Tcov/camdtest_l.c +++ b/CHOLMOD/Tcov/dl_amdtest.c @@ -1,14 +1,17 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Tcov/camdtest_l: int64_t version of camdtest +// CHOLMOD/Tcov/dl_amdtest: int64_t version of amdtest //------------------------------------------------------------------------------ -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ +#define DOUBLE #define CHOLMOD_INT64 +#define DTYPE CHOLMOD_DOUBLE + #define DLONG -#include "camdtest.c" +#include "t_amdtest.c" diff --git a/CHOLMOD/Tcov/dl_camdtest.c b/CHOLMOD/Tcov/dl_camdtest.c new file mode 100644 index 0000000000..bbd2779204 --- /dev/null +++ b/CHOLMOD/Tcov/dl_camdtest.c @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/dl_camdtest: double/int64_t version of camdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_DOUBLE + +#define DLONG +#include "t_camdtest.c" + diff --git a/CHOLMOD/Tcov/huge_l.c b/CHOLMOD/Tcov/dl_huge.c similarity index 64% rename from CHOLMOD/Tcov/huge_l.c rename to CHOLMOD/Tcov/dl_huge.c index be413254de..60f3b7dbad 100644 --- a/CHOLMOD/Tcov/huge_l.c +++ b/CHOLMOD/Tcov/dl_huge.c @@ -1,14 +1,16 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Tcov/huge_l: int64_t version of huge +// CHOLMOD/Tcov/dl_huge: double/int64_t version of huge //------------------------------------------------------------------------------ -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ +#define DOUBLE #define CHOLMOD_INT64 -#include "cholmod_internal.h" -#include "huge.c" +#define DTYPE CHOLMOD_DOUBLE + +#include "t_huge.c" diff --git a/CHOLMOD/Tcov/clread.c b/CHOLMOD/Tcov/dl_read.c similarity index 63% rename from CHOLMOD/Tcov/clread.c rename to CHOLMOD/Tcov/dl_read.c index 811d5c8f50..f9808f983c 100644 --- a/CHOLMOD/Tcov/clread.c +++ b/CHOLMOD/Tcov/dl_read.c @@ -1,12 +1,15 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Tcov/clread: int64_t version of cmread +// CHOLMOD/Tcov/dl_read: double/int64_t version of cmread //------------------------------------------------------------------------------ -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ +#define DOUBLE #define CHOLMOD_INT64 -#include "cmread.c" +#define DTYPE CHOLMOD_DOUBLE + +#include "t_cmread.c" diff --git a/CHOLMOD/Tcov/dl_test.c b/CHOLMOD/Tcov/dl_test.c new file mode 100644 index 0000000000..636e4e40e3 --- /dev/null +++ b/CHOLMOD/Tcov/dl_test.c @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/dl_test: double/int64_t version of Tcov/cm test program +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define DOUBLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_DOUBLE + +#include "t_cm.c" +#include "t_test_ops.c" +#include "t_test_ops2.c" +#include "t_null.c" +#include "t_null2.c" +#include "t_lpdemo.c" +#include "t_memory.c" +#include "t_solve.c" +#include "t_aug.c" +#include "t_unpack.c" +#include "t_raw_factor.c" +#include "t_cctest.c" +#include "t_ctest.c" +#include "t_basic.c" +#include "t_overflow_tests.c" +#include "t_dump.c" +#include "t_read_triplet.c" +#include "t_rhs.c" +#include "t_znorm_diag.c" +#include "t_prand.c" +#include "t_perm_matrix.c" +#include "t_ptest.c" +#include "t_rand_dense.c" +#include "t_cat_tests.c" +#include "t_dense_tests.c" +#include "t_dtype_tests.c" +#include "t_common_tests.c" +#include "t_error_tests.c" +#include "t_tofrom_tests.c" +#include "t_suitesparse.c" diff --git a/CHOLMOD/Tcov/gcovs b/CHOLMOD/Tcov/gcovs index 38286f6754..cbd62d63cb 100755 --- a/CHOLMOD/Tcov/gcovs +++ b/CHOLMOD/Tcov/gcovs @@ -1,7 +1,7 @@ #!/bin/bash # ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ # ------------------------------------------------------------------------------ @@ -9,5 +9,5 @@ # usage: gcovs files for file in $@ do - gcov -fl $file > /dev/null + gcov -fl $file > /dev/null done diff --git a/CHOLMOD/Tcov/go b/CHOLMOD/Tcov/go index 9e20bacf98..5783db8a8b 100755 --- a/CHOLMOD/Tcov/go +++ b/CHOLMOD/Tcov/go @@ -1,7 +1,7 @@ #!/bin/bash # ------------------------------------------------------------------------------ -# CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +# CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. # All Rights Reserved. # SPDX-License-Identifier: GPL-2.0+ # ------------------------------------------------------------------------------ diff --git a/CHOLMOD/Tcov/huge.c b/CHOLMOD/Tcov/huge.c deleted file mode 100644 index 78c6f2ed19..0000000000 --- a/CHOLMOD/Tcov/huge.c +++ /dev/null @@ -1,255 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/huge: test program for CHOLMOD on huge matrices -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Tests on huge matrices */ - -#include "cm.h" -#include "amd.h" -#ifndef NCAMD -#include "camd.h" -#endif - -#undef ERROR -#include "cholmod_internal.h" - -#undef ERROR -#define ERROR(status,message) \ - CHOLMOD(error) (status, __FILE__, __LINE__, message, cm) - -/* ========================================================================== */ -/* === huge ================================================================= */ -/* ========================================================================== */ - -void huge ( ) -{ - cholmod_sparse *A, *C ; - cholmod_triplet *T ; - cholmod_factor *L ; - cholmod_dense *X ; - size_t n, nbig ; - int ok = TRUE, save ; - Int junk = 0 ; - FILE *f ; - double beta [2] ; - - n = SIZE_MAX ; - CHOLMOD (free_work) (cm) ; - CHOLMOD (allocate_work) (n, 0, 0, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - n = CHOLMOD(add_size_t) (n, 1, &ok) ; NOT (ok) ; - - /* create a fake zero sparse matrix, with huge dimensions */ - A = CHOLMOD (spzeros) (1, 1, 0, CHOLMOD_REAL, cm) ; - A->nrow = SIZE_MAX ; - A->ncol = SIZE_MAX ; - A->stype = 0 ; - - /* create a fake factor, with huge dimensions. */ - L = CHOLMOD (allocate_factor) (1, cm) ; - OKP (L) ; - L->n = SIZE_MAX ; - CHOLMOD (factorize) (A, L, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - /* free the fake factor */ - L->n = 1 ; - CHOLMOD (free_factor) (&L, cm) ; - - /* create a valid factor to test resymbol */ - C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL, cm) ; - C->stype = 1 ; - L = CHOLMOD (analyze) (C, cm) ; - OKP (L) ; - CHOLMOD (factorize) (C, L, cm) ; - ok = CHOLMOD (resymbol) (C, NULL, 0, 0, L, cm) ; - OK (ok) ; - C->nrow = SIZE_MAX ; - C->ncol = SIZE_MAX ; - L->n = SIZE_MAX ; - - ok = CHOLMOD (resymbol) (C, NULL, 0, 0, L, cm) ; - NOT (ok) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - printf ("rowfac:\n") ; - beta [0] = 1 ; - beta [1] = 0 ; - C->xtype = CHOLMOD_COMPLEX ; - L->xtype = CHOLMOD_COMPLEX ; - ok = CHOLMOD (rowfac) (C, NULL, beta, 0, 0, L, cm) ; - printf ("rowfac %d\n", cm->status) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - C->xtype = CHOLMOD_REAL ; - L->xtype = CHOLMOD_REAL ; - printf ("rowfac done:\n") ; - - C->stype = -1 ; - ok = CHOLMOD (resymbol_noperm) (C, NULL, 0, 0, L, cm) ; - NOT (ok) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - C->ncol = 1 ; - CHOLMOD (rowadd) (0, C, L, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - CHOLMOD (rowdel) (0, C, L, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - C->ncol = 4 ; - CHOLMOD (updown) (1, C, L, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - C->nrow = 1 ; - C->ncol = 1 ; - L->n = 1 ; - CHOLMOD (free_sparse) (&C, cm) ; - CHOLMOD (free_factor) (&L, cm) ; - - C = CHOLMOD (allocate_sparse) (SIZE_MAX, SIZE_MAX, SIZE_MAX, - 0, 0, 0, 0, cm) ; - printf ("cm->status %d\n", cm->status) ; - NOP (C) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - CHOLMOD (rowcolcounts) (A, NULL, 0, - &junk, &junk, &junk, &junk, &junk, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - C = CHOLMOD (submatrix) (A, &junk, SIZE_MAX/4, &junk, SIZE_MAX/4, - 0, 0, cm) ; - - NOP (C) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - ok = CHOLMOD (transpose_unsym) (A, 0, &junk, &junk, SIZE_MAX, A, cm) ; - NOT (ok) ; - OK (cm->status == CHOLMOD_TOO_LARGE || - cm->status == CHOLMOD_OUT_OF_MEMORY || - cm->status == CHOLMOD_INVALID); - - A->stype = 1 ; - ok = CHOLMOD (transpose_sym) (A, 0, &junk, A, cm) ; - NOT (ok) ; - OK (cm->status == CHOLMOD_TOO_LARGE || - cm->status == CHOLMOD_OUT_OF_MEMORY || - cm->status == CHOLMOD_INVALID); - - C = CHOLMOD (ptranspose) (A, 0, &junk, NULL, 0, cm) ; - NOP (C) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - A->stype = 0 ; - - CHOLMOD (amd) (A, NULL, 0, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - L = CHOLMOD (analyze) (A, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - NOP (L) ; - -#ifndef NCAMD - CHOLMOD (camd) (A, NULL, 0, &junk, NULL, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); -#endif - - printf ("calling colamd\n") ; - CHOLMOD (colamd) (A, NULL, 0, 0, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - -#ifndef NCAMD - printf ("calling ccolamd\n") ; - CHOLMOD (ccolamd) (A, NULL, 0, NULL, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); -#endif - - CHOLMOD (etree) (A, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - L = CHOLMOD (allocate_factor) (SIZE_MAX, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - NOP (L) ; - -#ifndef NPARTITION - CHOLMOD (metis) (A, NULL, 0, 0, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - CHOLMOD (bisect) (A, NULL, 0, 0, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - CHOLMOD (nested_dissection) (A, NULL, 0, &junk, &junk, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); -#endif - - CHOLMOD (postorder) (&junk, SIZE_MAX, &junk, &junk, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - - /* causes overflow in 32-bit version, but not 64-bit */ - f = fopen ("../Tcov/Matrix/mega.tri", "r") ; - T = CHOLMOD (read_triplet) (f, cm) ; - if (sizeof (Int) == sizeof (int)) - { - NOP (T) ; - OK (cm->status != CHOLMOD_OK) ; - } - CHOLMOD (free_triplet) (&T, cm) ; - fclose (f) ; - - n = SIZE_MAX ; - X = CHOLMOD (allocate_dense) (n, 1, n, CHOLMOD_REAL, cm) ; - printf ("status %d\n", cm->status) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - NOP (X) ; - - /* supernodal symbolic test */ - C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL, cm) ; - C->stype = 1 ; - save = cm->supernodal ; - cm->supernodal = CHOLMOD_SIMPLICIAL ; - L = CHOLMOD (analyze) (C, cm) ; - OKP (L) ; - junk = 0 ; - C->nrow = SIZE_MAX ; - C->ncol = SIZE_MAX ; - L->n = SIZE_MAX ; - CHOLMOD (super_symbolic) (C, C, &junk, L, cm) ; - OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); - cm->supernodal = save ; - C->nrow = 1 ; - C->ncol = 1 ; - L->n = 1 ; - CHOLMOD (free_sparse) (&C, cm) ; - CHOLMOD (free_factor) (&L, cm) ; - - /* supernodal numeric test */ - C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL, cm) ; - C->stype = -1 ; - save = cm->supernodal ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - L = CHOLMOD (analyze) (C, cm) ; - OKP (L) ; - OK (cm->status == CHOLMOD_OK) ; - C->nrow = SIZE_MAX ; - C->ncol = SIZE_MAX ; - L->n = SIZE_MAX ; - CHOLMOD (super_numeric) (C, C, beta, L, cm) ; - cm->supernodal = save ; - C->nrow = 1 ; - C->ncol = 1 ; - L->n = 1 ; - CHOLMOD (free_sparse) (&C, cm) ; - CHOLMOD (free_factor) (&L, cm) ; - - /* free the fake matrix */ - A->nrow = 1 ; - A->ncol = 1 ; - CHOLMOD (free_sparse) (&A, cm) ; - - fprintf (stderr, "\n") ; -} diff --git a/CHOLMOD/Tcov/leak.c b/CHOLMOD/Tcov/leak.c deleted file mode 100644 index 9202c598e2..0000000000 --- a/CHOLMOD/Tcov/leak.c +++ /dev/null @@ -1,123 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/leak: look for CHOLMOD memory leaks -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Look for CHOLMOD memory leaks. Run cm with - * cholmod_dump >= cholmod_dump_malloc (see Check/cholmod_check.c), - * to get output file. Then grep "cnt:" output | leak - */ - -#include -#include -#include - -#define LEN 2048 -char line [LEN] ; -char operation [LEN] ; -char s_cnt [LEN] ; -char s_inuse [LEN] ; - -int block [LEN] ; -int blocksize [LEN] ; - -#define FALSE 0 -#define TRUE 1 - -int main (void) -{ - int p, size, cnt2, inuse2, nblocks, found, b, bfound, nlines ; - - nblocks = 0 ; - nlines = 0 ; - - while (fgets (line, LEN, stdin) != NULL) - { - sscanf (line, "%s %x %d %s %d %s %d\n", - operation, &p, &size, s_cnt, &cnt2, s_inuse, &inuse2) ; - nlines++ ; - - printf ("%d:: %s %x %d %s %d %s %d\n", - nlines, operation, p, size, s_cnt, cnt2, s_inuse, inuse2) ; - - /* determine operation */ - if (strcmp (operation, "cholmod_malloc") == 0 || - strcmp (operation, "cholmod_realloc_new:") == 0 || - strcmp (operation, "cholmod_calloc") == 0) - { - - /* p = malloc (size) */ - for (b = 0 ; b < nblocks ; b++) - { - if (p == block [b]) - { - printf ("duplicate!\n") ; - abort ( ) ; - } - } - - if (nblocks >= LEN) - { - printf ("out of space!\n") ; - abort ( ) ; - } - - /* add the new block to the list */ - block [nblocks] = p ; - blocksize [nblocks] = size ; - nblocks++ ; - - } - - else if (strcmp (operation, "cholmod_free") == 0 || - strcmp (operation, "cholmod_realloc_old:") == 0) - { - - /* p = free (size) */ - found = FALSE ; - for (b = 0 ; !found && b < nblocks ; b++) - { - if (p == block [b]) - { - bfound = b ; - found = TRUE ; - } - } - if (!found) - { - printf ("not found!\n") ; - abort ( ) ; - } - - if (size != blocksize [bfound]) - { - printf ("wrong size! %x : %d vs %d\n", - p, size, blocksize[bfound]) ; - abort ( ) ; - } - - /* remove the block from the list */ - --nblocks ; - block [bfound] = block [nblocks] ; - blocksize [bfound] = blocksize [nblocks] ; - - } - else - { - printf ("unrecognized!\n") ; - abort ( ) ; - } - - if (cnt2 != nblocks) - { - printf ("nblocks wrong! %d %d\n", nblocks, cnt2) ; - } - - } - return (0) ; -} diff --git a/CHOLMOD/Tcov/lpdemo.c b/CHOLMOD/Tcov/lpdemo.c deleted file mode 100644 index fd206765dc..0000000000 --- a/CHOLMOD/Tcov/lpdemo.c +++ /dev/null @@ -1,930 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/lpdemo: test program with an LP-style operations in CHOLMOD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* A rectangular matrix is being tested (# nrows < # cols). This is a - * linear programming problem. Process the system using the same kind of - * operations that occur in an LP solver (the LP Dual Active Set Algorithm). - * This routine does not actually solve the LP. It simply mimics the kind - * of matrix operations that occur in LPDASA. - * - * The active set f is held in fset [0..fsize-1]. It is a subset of the columns - * of A. Columns not in the fset are in the list fnot [0..ncol-fsize-1]. - * - * Rows can be added and deleted from A as well. A "dead" row is one that has - * been (temporarily) set to zero in A. If row i is dead, rflag [i] is 0, - * and 1 otherwise. - * - * The list r of "live" rows is kept in rset [0..rsize-1]. The list of "dead" - * rows is kept in rnot [0..nrow-rsize-1]. - * - * The system to solve as r and/or f change is (beta*I + A(r,f)*A(r,f)') x = b. - * If a row i is deleted from A, it is set to zero. Row i of L and D are set - * to the ith row of the identity matrix. - */ - -#include "cm.h" -#define MAXCOLS 8 - - -/* ========================================================================== */ -/* === Lcheck =============================================================== */ -/* ========================================================================== */ - -/* Testing only: make sure there are no dead rows in L (excluding diagonal) */ - -static void Lcheck (cholmod_factor *L, Int *rflag) -{ - Int *Lp, *Li, *Lnz ; - Int i, n, j, p, pend ; - double *Lx ; - - if (L == NULL) - { - return ; - } - - Lp = L->p ; - Li = L->i ; - Lx = L->x ; - Lnz = L->nz ; - n = L->n ; - - for (j = 0 ; j < n ; j++) - { - p = Lp [j] ; - pend = p + Lnz [j] ; - for (p++ ; p < pend ; p++) - { - i = Li [p] ; - OK (IMPLIES (!rflag [i], Lx [p] == 0)) ; - } - } -} - - -/* ========================================================================== */ -/* === lp_prune ============================================================= */ -/* ========================================================================== */ - -/* C = A (r,f), except that C and A have the same row dimension. Row i of C - * and A(:,f) are equal if row i is in the rset. Row i of C is zero - * otherwise. C has as many columns as the size of f. */ - -cholmod_sparse *lp_prune -( - cholmod_sparse *A, - Int *rflag, - Int *fset, - Int fsize -) -{ - cholmod_sparse *C ; - double *Ax, *Cx ; - Int *Ai, *Ap, *Ci, *Cp ; - Int i, kk, j, p, nz, nf, ncol ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "nothing to prune") ; - return (NULL) ; - } - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - ncol = A->ncol ; - nf = (fset == NULL) ? ncol : fsize ; - - OK (fsize >= 0) ; - - C = CHOLMOD(allocate_sparse) (A->nrow, nf, A->nzmax, A->sorted, - TRUE, 0, CHOLMOD_REAL, cm) ; - - if (C == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot create pruned C") ; - return (NULL) ; - } - - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - - nz = 0 ; - - for (kk = 0 ; kk < nf ; kk++) - { - j = (fset == NULL) ? (kk) : (fset [kk]) ; - Cp [kk] = nz ; - for (p = Ap [j] ; p < Ap [j+1] ; p++) - { - i = Ai [p] ; - if (rflag [i]) - { - Ci [nz] = i ; - Cx [nz] = Ax [p] ; - nz++ ; - } - } - } - Cp [nf] = nz ; - return (C) ; -} - - -/* ========================================================================== */ -/* === lp_resid ============================================================= */ -/* ========================================================================== */ - -/* Compute the 2-norm of the residual. - * norm ((beta*I + C*C')y(r) - b(r)), where C = A (r,f). - */ - -double lp_resid -( - cholmod_sparse *A, - Int *rflag, - Int *fset, - Int fsize, - double beta [2], - cholmod_dense *Y, - cholmod_dense *B -) -{ - cholmod_dense *R ; - double *Rx, *Yx ; - double rnorm, bnorm, ynorm, norm ; - cholmod_sparse *C ; - cholmod_dense *W ; - Int i, nrow ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot compute LP resid") ; - return (1) ; - } - - nrow = A->nrow ; - R = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL, cm) ; - - /* C = A(r,f). In LPDASA, we do this in place, without making a copy. */ - C = lp_prune (A, rflag, fset, fsize) ; - - /* W = C'*Y */ - OK (fsize >= 0) ; - W = CHOLMOD(zeros) (fsize, 1, CHOLMOD_REAL, cm) ; - CHOLMOD(sdmult) (C, TRUE, one, zero, Y, W, cm) ; - - /* R = B */ - CHOLMOD(copy_dense2) (B, R, cm) ; - - /* R = C*W - R */ - CHOLMOD(sdmult) (C, FALSE, one, minusone, W, R, cm) ; - - /* R = R + beta*Y, (beta = 1 for dropped rows) */ - if (R != NULL && Y != NULL) - { - Rx = R->x ; - Yx = Y->x ; - for (i = 0 ; i < nrow ; i++) - { - if (rflag [i]) - { - Rx [i] += beta [0] * Yx [i] ; - } - else - { - Rx [i] += Yx [i] ; - } - } - } - - /* rnorm = norm (R) */ - rnorm = CHOLMOD(norm_dense) (R, 2, cm) ; - bnorm = CHOLMOD(norm_dense) (B, 2, cm) ; - ynorm = CHOLMOD(norm_dense) (Y, 2, cm) ; - norm = MAX (bnorm, ynorm) ; - if (norm > 0) - { - rnorm /= norm ; - } - - CHOLMOD(print_dense) (R, "R, resid", cm) ; - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_dense) (&W, cm) ; - CHOLMOD(free_dense) (&R, cm) ; - - return (rnorm) ; -} - - -/* ========================================================================== */ -/* === get_row ============================================================== */ -/* ========================================================================== */ - -/* S = column i of beta*I + A(r,f)*A(r,f)' */ - -cholmod_sparse *get_row -( - cholmod_sparse *A, - Int i, - Int *rflag, - Int *fset, - Int fsize, - double beta [2] -) -{ - cholmod_sparse *Ri, *R, *C, *S ; - double *Sx ; - Int *Sp, *Si ; - Int p, ii, found ; - - if (rflag [i] == 0) - { - S = CHOLMOD(speye) (A->nrow, A->nrow, CHOLMOD_REAL, cm) ; - CHOLMOD(print_sparse) (S, "S identity", cm) ; - return (S) ; - } - OK (fsize >= 0) ; - - /* Getting row i of A is expensive. In LPDASA, we maintain - * a copy of A(r,f)', and extact row i as column i of that - * matrix. We compute S = A(r,f)*A(i,f)' and S(i) += beta - * in a single pass. This is a simpler but slower method. */ - - /* R = A (i,f)' */ - Ri = CHOLMOD(submatrix) (A, &i, 1, fset, fsize, TRUE, FALSE, cm) ; - R = CHOLMOD(transpose) (Ri, 1, cm) ; - CHOLMOD(free_sparse) (&Ri, cm) ; - - /* C = A (r,f) */ - C = lp_prune (A, rflag, fset, fsize) ; - - /* S = C*R */ - S = CHOLMOD(ssmult) (C, R, 0, TRUE, TRUE, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&R, cm) ; - - if (S == NULL) - { - return (NULL) ; - } - - /* S (i) += beta */ - found = FALSE ; - Sp = S->p ; - Si = S->i ; - Sx = S->x ; - for (p = Sp [0] ; p < Sp [1] ; p++) - { - ii = Si [p] ; - if (ii == i) - { - found = TRUE ; - Sx [p] += beta [0] ; - break ; - } - } - if (!found) - { - /* oops, row index i is not present in S. Add it. */ - CHOLMOD(reallocate_sparse) (S->nzmax+1, S, cm) ; - OK (Sp [1] < (Int) (S->nzmax)) ; - Si = S->i ; - Sx = S->x ; - Si [Sp [1]] = i ; - Sx [Sp [1]] = beta [0] ; - Sp [1]++ ; - S->sorted = FALSE ; - } - - CHOLMOD(print_sparse) (S, "S", cm) ; - - return (S) ; -} - - -/* ========================================================================== */ -/* === lpdemo =============================================================== */ -/* ========================================================================== */ - -double lpdemo (cholmod_triplet *T) -{ - double r, maxerr = 0, anorm, bnorm, norm, xnorm, ynorm ; - double *b = NULL, *Yx = NULL, *Xx = NULL, *Sx ; - cholmod_sparse *A, *AT, *Apermuted, *C, *S, *Row ; - cholmod_dense *X, *B, *Y, *DeltaB, *R ; - cholmod_factor *L ; - Int *init, *rset, *rnot, *fset, *fnot, *rflag, *P, *Pinv, *Lperm, *fflag, - *Sp, *Si, *StaticParent ; - Int i, j, k, nrow, ncol, fsize, cols [MAXCOLS+1], trial, rank, kk, rsize, - p, op, ok ; - double beta [2], bk [2], yk [2] ; - - /* ---------------------------------------------------------------------- */ - /* convert T into a sparse matrix A */ - /* ---------------------------------------------------------------------- */ - - if (T == NULL || T->ncol == 0) - { - /* nothing to do */ - return (0) ; - } - - if (T->xtype != CHOLMOD_REAL) - { - return (0) ; - } - - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "cannot continue LP demo") ; - return (1) ; - } - - nrow = A->nrow ; - ncol = A->ncol ; - - anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; - - /* switch for afiro, but not galenet */ - cm->supernodal_switch = 5 ; - - /* ---------------------------------------------------------------------- */ - /* select a random initial row and column basis */ - /* ---------------------------------------------------------------------- */ - - /* select an initial fset of size nrow */ - init = prand (ncol) ; /* RAND */ - fset = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; - fnot = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; - fflag = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; - fsize = MIN (nrow, ncol) ; - - if (init != NULL && fset != NULL && fflag != NULL) - { - for (k = 0 ; k < fsize ; k++) - { - j = init [k] ; - fset [k] = j ; - fflag [j] = 1 ; - } - for ( ; k < ncol ; k++) - { - j = init [k] ; - fnot [k-fsize] = j ; - fflag [j] = 0 ; - } - } - - CHOLMOD(free) (ncol, sizeof (Int), init, cm) ; - - /* all rows are live */ - rsize = nrow ; - rflag = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - rset = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - rnot = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - - if (rset != NULL && rflag != NULL) - { - for (i = 0 ; i < nrow ; i++) - { - rflag [i] = 1 ; - rset [i] = i ; - } - } - - /* ---------------------------------------------------------------------- */ - /* factorize the first matrix, beta*I + A(p,f)*A(p,f)' */ - /* ---------------------------------------------------------------------- */ - - beta [0] = 1e-6 ; - beta [1] = 0 ; - - /* Need to prune entries due to relaxed amalgamation, or else - * cholmod_row_subtree will not be able to find all the entries in row - * k of L. */ - cm->final_resymbol = TRUE ; - - cm->final_asis = FALSE ; - cm->final_super = FALSE ; - cm->final_ll = FALSE ; - cm->final_pack = FALSE ; - cm->final_monotonic = FALSE ; - - L = CHOLMOD(analyze_p) (A, NULL, fset, fsize, cm) ; - CHOLMOD(factorize_p) (A, beta, fset, fsize, L, cm) ; - - /* get a copy of the fill-reducing permutation P and compute its inverse */ - Lperm = (L != NULL) ? (L->Perm) : NULL ; - P = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - - if (P != NULL && Pinv != NULL && Lperm != NULL) - { - for (k = 0 ; k < nrow ; k++) - { - P [k] = Lperm [k] ; - Pinv [P [k]] = k ; - } - } - else - { - P = CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; - Pinv = CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; - } - - if (cm->print > 1) - { - k = cm->print ; - cm->print = 5 ; - CHOLMOD(print_common) ("cm for lpdemo", cm) ; - cm->print = k ; - } - - /* ---------------------------------------------------------------------- */ - /* A=P*A: permute the rows of A according to P */ - /* ---------------------------------------------------------------------- */ - - /* This is done just once, since the system will be solved and modified - * many times. It's faster, and easier, to work in the permuted ordering - * rather than the original ordering. */ - - /* A will become unsorted later on; don't bother to sort it here */ - Apermuted = CHOLMOD(submatrix) (A, P, nrow, NULL, -1, TRUE, TRUE, cm) ; - CHOLMOD(free_sparse) (&A, cm) ; - A = Apermuted ; - - /* ---------------------------------------------------------------------- */ - /* find the etree of A*A' */ - /* ---------------------------------------------------------------------- */ - - /* Since the fset is a subset of 0:ncol-1, and rset is a subset of 0:nrow-1, - * the nonzero pattern of the Cholesky factorization of A(r,f)*A(r,f)' is a - * subset of the Cholesky factorization of A*A'. After many updates/ - * downdates/rowadds/rowdels, any given row i of L may have entries that - * are not in the factorization of A (r,f)*A(r,f)'. To drop a row using - * cholmod_rowdel, we either need to know the pattern of the ith row of L, - * we can pass NULL and have cholmod_rowdel look at each column 0 to i-1. - * The StaticParent array is the etree of A*A', and it suffices to compute - * the pattern of the ith row of L based on that etree, and A and A' - * (ignoring the fset and rset). This gives us an upper bound on the - * nonzero pattern of the ith row of the current L (the factorization - * of A(r,f)*A(r,f)'. - */ - - /* AT = nonzero pattern of A', used for row-subtree computations */ - AT = CHOLMOD(transpose) (A, 0, cm) ; - - /* Row = cholmod_row_subtree workspace (unsorted, packed, unsym, pattern) */ - Row = CHOLMOD(allocate_sparse) (nrow, 1, nrow, FALSE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - - /* Compute the "static" etree; the etree of A*A' */ - StaticParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - CHOLMOD(etree) (AT, StaticParent, cm) ; - - /* ---------------------------------------------------------------------- */ - /* compute initial right-hand-side */ - /* ---------------------------------------------------------------------- */ - - /* If row i of the original A and B is row k of the permuted P*A and P*B, - * then P [k] = i and Pinv [i] = k. Row indices of A now refer to the - * permuted form of A, not the original A. Likewise, row k of B will - * refer to the permuted row k = Pinv [i], not the original row i. In a - * real program, this would affect how B is computed. This program just - * creates a random B anyway, so the order of B does not matter. It does - * use Pinv [i], just to show you how you would do it. - */ - - B = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL, cm) ; - - if (B != NULL && Pinv != NULL) - { - b = B->x ; - for (i = 0 ; i < nrow ; i++) - { - /* row i of the original B is row k of the permuted B */ - k = Pinv [i] ; - b [k] = xrand (1.) ; /* RAND */ - } - } - - /* ---------------------------------------------------------------------- */ - /* solve the system */ - /* ---------------------------------------------------------------------- */ - - /* Solve the system (beta*I + A(:,f)*A(:,f)')y=b without using L->Perm, - * since A and B have already been permuted according to L->Perm. */ - - DeltaB = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL, cm) ; - - /* solve Lx=b */ - X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; - - /* solve DL'y=x */ - Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; - - r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; - MAXERR (maxerr, r, 1) ; - - bk [0] = 0 ; - bk [1] = 0 ; - - yk [0] = 0 ; - yk [1] = 0 ; - - bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; - - /* ---------------------------------------------------------------------- */ - /* modify the system */ - /* ---------------------------------------------------------------------- */ - - ok = (fset != NULL && fnot != NULL && fflag != NULL && - rset != NULL && rnot != NULL && rflag != NULL && - B != NULL && Y != NULL && X != NULL && Row != NULL && A != NULL && - AT != NULL && StaticParent != NULL && DeltaB != NULL && L != NULL && - L->xtype != CHOLMOD_PATTERN && !(L->is_ll) && !(L->is_super)) ; - - for (trial = 1 ; ok && trial < MAX (64, 2*ncol) ; trial++) - { - /* select an operation at random */ - op = nrand (6) ; /* RAND */ - - Xx = X->x ; - Yx = Y->x ; - - switch (op) - { - - /* -------------------------------------------------------------- */ - case 0: /* update */ - /* -------------------------------------------------------------- */ - - /* pick some columns at random, but not all columns */ - rank = 1 + nrand (MAXCOLS+4) ; /* RAND */ - rank = MIN (rank, MAXCOLS) ; - - rank = MIN (rank, ncol-fsize-1) ; - if (rank <= 0) - { - continue ; - } - - /* remove the columns from fnot and add them to fset */ - for (k = 0 ; k < rank ; k++) - { - kk = nrand (ncol-fsize) ; /* RAND */ - j = fnot [kk] ; - fnot [kk] = fnot [ncol-fsize-1] ; - fset [fsize++] = j ; - OK (fsize < ncol) ; - cols [k] = j ; - fflag [j] = 1 ; - } - - /* update L, and the solution to Lx=b+deltaB */ - C = lp_prune (A, rflag, cols, rank) ; - ok = CHOLMOD(updown_solve) (TRUE, C, L, X, DeltaB, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - break ; - - /* -------------------------------------------------------------- */ - case 1: /* downdate */ - /* -------------------------------------------------------------- */ - - /* pick some columns at random, but not all columns */ - rank = 1 + nrand (MAXCOLS+4) ; /* RAND */ - rank = MIN (rank, MAXCOLS) ; - - rank = MIN (rank, fsize-1) ; - if (rank <= 0) - { - continue ; - } - - /* remove the columns from fset and add them to fnot */ - for (k = 0 ; k < rank ; k++) - { - kk = nrand (fsize) ; /* RAND */ - j = fset [kk] ; - fset [kk] = fset [fsize-1] ; - fnot [ncol-fsize] = j ; - fsize-- ; - OK (fsize > 0) ; - cols [k] = j ; - fflag [j] = 0 ; - } - - /* downdate L, and the solution to Lx=b+deltaB */ - C = lp_prune (A, rflag, cols, rank) ; - ok = CHOLMOD(updown_solve) (FALSE, C, L, X, DeltaB, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - break ; - - /* -------------------------------------------------------------- */ - case 2: /* resymbol (no change to numerical values) */ - /* -------------------------------------------------------------- */ - - /* let resymbol handle the fset */ - C = lp_prune (A, rflag, NULL, 0) ; - ok = CHOLMOD(resymbol_noperm) (C, fset, fsize, TRUE, L, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - break; - - /* -------------------------------------------------------------- */ - case 3: /* add row */ - /* -------------------------------------------------------------- */ - - /* remove a row from rnot and add to rset */ - if (nrow == rsize) - { - continue ; - } - kk = nrand (nrow-rsize) ; /* RAND */ - i = rnot [kk] ; - - OK (rflag [i] == 0) ; - - rnot [kk] = rnot [nrow-rsize-1] ; - rset [rsize++] = i ; - rflag [i] = 1 ; - - /* S = column i of beta*I + A(r,f)*A(r,f)' */ - S = get_row (A, i, rflag, fset, fsize, beta) ; - ok = (S != NULL) ; - - if (ok) - { - /* pick a random right-hand-side for this new row */ - b [i] = 1 ; /* xrand (1) */ /* was RAND */ - bk [0] = b [i] ; - bk [1] = 0 ; - ok = CHOLMOD(rowadd_solve) (i, S, bk, L, X, DeltaB, cm) ; - } - - CHOLMOD(free_sparse) (&S, cm) ; - break ; - - /* -------------------------------------------------------------- */ - case 4: /* delete row */ - /* -------------------------------------------------------------- */ - - /* remove a row from rset and add to rnot */ - if (rsize == 0) - { - continue ; - } - kk = nrand (rsize) ; /* RAND */ - i = rset [kk] ; - - OK (rflag [i] == 1) ; - rset [kk] = rset [rsize-1] ; - rnot [nrow-rsize] = i ; - rsize-- ; - - /* S = column i of beta*I + A(r,f)*A(r,f)' */ - S = get_row (A, i, rflag, fset, fsize, beta) ; - ok = (S != NULL) ; - - if (ok) - { - /* B = B - S * y(i) */ - Sp = S->p ; - Si = S->i ; - Sx = S->x ; - for (p = 0 ; p < Sp [1] ; p++) - { - b [Si [p]] -= Sx [p] * Yx [i] ; - } - /* B(i) = y(i) */ - b [i] = Yx [i] ; - - yk [0] = Yx [i] ; - yk [1] = 0 ; - - /* pick a method arbitrarily */ - if (trial % 2) - { - /* get upper bound nonzero pattern of L(i,0:i-1) */ - CHOLMOD(row_subtree) (A, AT, i, StaticParent, Row, cm) ; - ok = CHOLMOD(rowdel_solve) (i, Row, yk, L, X, DeltaB, - cm) ; - } - else - { - /* Look in all cols 0 to i-1 for entries in L(i,0:i-1). - * This is more costly, but requires no knowledge of - * an upper bound on the pattern of L. */ - ok = CHOLMOD(rowdel_solve) (i, NULL, yk, L, X, DeltaB, - cm) ; - } - - /* for testing only, to ensure cholmod_row_subtree worked */ - if (ok) - { - rflag [i] = 0 ; - Lcheck (L, rflag) ; - } - } - - if (ok) - { - /* let resymbol handle the fset */ - C = lp_prune (A, rflag, NULL, 0) ; - ok = CHOLMOD(resymbol_noperm) (C, fset, fsize, TRUE, L, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - } - - CHOLMOD(free_sparse) (&S, cm) ; - break ; - - /* -------------------------------------------------------------- */ - case 5: /* convert, just for testing */ - /* -------------------------------------------------------------- */ - - /* convert to LDL', optionally packed */ - if (trial % 2) - { - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, - TRUE, TRUE, L, cm) ; - } - else - { - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, - FALSE, TRUE, L, cm) ; - } - break ; - - } - - if (ok) - { - - /* scale B and X if their norm is getting large */ - ynorm = CHOLMOD(norm_dense) (Y, 1, cm) ; - bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; - xnorm = CHOLMOD(norm_dense) (X, 1, cm) ; - norm = MAX (bnorm, xnorm) ; - norm = MAX (norm, ynorm) ; - if (norm > 1e10) - { - for (i = 0 ; i < nrow ; i++) - { - Xx [i] /= norm ; - b [i] /= norm ; - } - } - - CHOLMOD(free_dense) (&Y, cm) ; - Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; - - r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; - OK (!ISNAN (r)) ; - MAXERR (maxerr, r, 1) ; - if (r > 1e-6 && cm->print > 1) - { - printf ("lp err %.1g operation: "ID" ok "ID"\n", r, op, ok) ; - } - ok = (Y != NULL) ; - } - } - - CHOLMOD(free_dense) (&Y, cm) ; - OK (CHOLMOD(print_common) ("cm in lpdemo", cm)) ; - - /* ---------------------------------------------------------------------- */ - /* convert to LDL packed, LDL unpacked or LL packed and solve again */ - /* ---------------------------------------------------------------------- */ - - /* solve the new system and check the residual */ - - CHOLMOD(print_factor) (L, "L final, for convert", cm) ; - if (ok) - { - switch (nrand (3)) /* RAND */ - { - /* pick one at random */ - case 0: - { - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, - TRUE, L, cm) ; - Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; - break ; - } - case 1: - { - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, - TRUE, L, cm) ; - Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; - break ; - } - case 2: - { - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, TRUE, FALSE, TRUE, - TRUE, L, cm) ; - Y = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; - break ; - } - } - r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; - OK (!ISNAN (r)) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(print_factor) (L, "L after convert", cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* rank-1 update, but only partial Lx=b update */ - /* ---------------------------------------------------------------------- */ - - if (ok && fsize < ncol && nrow > 3) - { - Int colmark [1] ; - - j = fnot [0] ; - fnot [0] = fnot [ncol-fsize-1] ; - fset [fsize++] = j ; - OK (fsize <= ncol) ; - cols [0] = j ; - fflag [j] = 1 ; - - for (colmark [0] = 0 ; colmark [0] <= nrow ; colmark [0]++) - { - cholmod_factor *L2 ; - cholmod_dense *X2 ; - double *X2x ; - L2 = CHOLMOD(copy_factor) (L, cm) ; - X2 = CHOLMOD(copy_dense) (X, cm) ; - X2x = (X2 == NULL) ? NULL : X2->x ; - - /* fprintf (stderr, "check colmark "ID"\n", colmark [0]) ; */ - printf ("check cholmark "ID"\n", colmark [0]) ; - /* colmark [0] = 3 ; */ - - /* update L, and the solution to Lx=b+deltaB, - * but only update solution in rows 0 to colmark[0] */ - C = lp_prune (A, rflag, cols, 1) ; - ok = CHOLMOD(updown_mark) (TRUE, C, colmark, L2, X2, DeltaB, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - - /* compare with Lr=b+deltaB */ - R = CHOLMOD(solve) (CHOLMOD_L, L2, B, cm) ; - r = -1 ; - if (ok && R != NULL) - { - double *Rx ; - Rx = R->x ; - r = 0 ; - for (i = 0 ; i < colmark [0] ; i++) - { - r = MAX (r, fabs (X2x [i] - Rx [i])) ; - } - MAXERR (maxerr, r, 1) ; - } - printf ("check cholmark resid %6.2e\n", r) ; - CHOLMOD(free_dense) (&R, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - CHOLMOD(free_factor) (&L2, cm) ; - } - } - - /* ---------------------------------------------------------------------- */ - /* free everything */ - /* ---------------------------------------------------------------------- */ - - /* restore defaults */ - cm->final_resymbol = FALSE ; - cm->final_asis = TRUE ; - cm->supernodal_switch = 40 ; - - CHOLMOD(free) (nrow, sizeof (Int), StaticParent, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), rflag, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), rset, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), rnot, cm) ; - CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; - CHOLMOD(free) (ncol, sizeof (Int), fnot, cm) ; - CHOLMOD(free) (ncol, sizeof (Int), fflag, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_sparse) (&Row, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_sparse) (&A, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Y, cm) ; - CHOLMOD(free_dense) (&DeltaB, cm) ; - - progress (0, '.') ; - return (maxerr) ; -} diff --git a/CHOLMOD/Tcov/memory.c b/CHOLMOD/Tcov/memory.c deleted file mode 100644 index b28cd4305e..0000000000 --- a/CHOLMOD/Tcov/memory.c +++ /dev/null @@ -1,358 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/memory: memory-failure testing in CHOLMOD -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Extensive memory-failure testing for CHOLMOD. - * - * my_malloc2, my_calloc2, and my_realloc2 pretend to fail if my_tries goes to - * zero, to test CHOLMOD's memory error handling. No failure occurs if - * my_tries is negative. - */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === my_tries ============================================================= */ -/* ========================================================================== */ - -int64_t my_tries = -1 ; /* a global variable */ - - -/* ========================================================================== */ -/* === my_malloc2 =========================================================== */ -/* ========================================================================== */ - -void *my_malloc2 (size_t size) -{ - void *p ; - if (my_tries == 0) - { - /* pretend to fail */ - // printf ("(my_malloc2 pretend to fail)\n") ; - return (NULL) ; - } - if (my_tries > 0) - { - my_tries-- ; - } - p = malloc (size) ; - /* printf ("p %p\n", p) ; */ - return (p) ; -} - - -/* ========================================================================== */ -/* === my_calloc2 =========================================================== */ -/* ========================================================================== */ - -void *my_calloc2 (size_t n, size_t size) -{ - void *p ; - if (my_tries == 0) - { - /* pretend to fail */ - // printf ("(my_calloc2 pretend to fail)\n") ; - return (NULL) ; - } - if (my_tries > 0) - { - my_tries-- ; - } - p = calloc (n, size) ; - /* printf ("p %p\n", p) ; */ - return (p) ; -} - - -/* ========================================================================== */ -/* === my_realloc2 ========================================================== */ -/* ========================================================================== */ - -void *my_realloc2 (void *p, size_t size) -{ - void *p2 ; - if (my_tries == 0) - { - /* pretend to fail */ - // printf ("(my_realloc2 pretend to fail)\n") ; - return (NULL) ; - } - if (my_tries > 0) - { - my_tries-- ; - } - p2 = realloc (p, size) ; - /* printf ("p2 %p\n", p2) ; */ - return (p2) ; -} - - -/* ========================================================================== */ -/* === my_free2 ============================================================= */ -/* ========================================================================== */ - -void my_free2 (void *p) -{ - free (p) ; -} - - -/* ========================================================================== */ -/* === normal_memory_handler ================================================ */ -/* ========================================================================== */ - -void normal_memory_handler ( void ) -{ - SuiteSparse_config_malloc_func_set (malloc) ; - SuiteSparse_config_calloc_func_set (calloc) ; - SuiteSparse_config_realloc_func_set (realloc) ; - SuiteSparse_config_free_func_set (free) ; - - cm->error_handler = my_handler ; - CHOLMOD(free_work) (cm) ; -} - - -/* ========================================================================== */ -/* === test_memory_handler ================================================== */ -/* ========================================================================== */ - -void test_memory_handler ( void ) -{ - SuiteSparse_config_malloc_func_set (my_malloc2) ; - SuiteSparse_config_calloc_func_set (my_calloc2) ; - SuiteSparse_config_realloc_func_set (my_realloc2) ; - SuiteSparse_config_free_func_set (my_free2) ; - - cm->error_handler = NULL ; - CHOLMOD(free_work) (cm) ; - my_tries = 0 ; -} - - -/* ========================================================================== */ -/* === memory tests ========================================================= */ -/* ========================================================================== */ - -void memory_tests (cholmod_triplet *T) -{ - double err ; - cholmod_sparse *A ; - Int trial ; - size_t count, inuse ; - - test_memory_handler ( ) ; - inuse = cm->memory_inuse ; - - cm->nmethods = 8 ; - cm->print = 0 ; - cm->final_resymbol = TRUE ; - - cm->final_asis = FALSE ; - cm->final_super = FALSE ; - cm->final_ll = FALSE ; - cm->final_pack = FALSE ; - cm->final_monotonic = FALSE ; - - /* ---------------------------------------------------------------------- */ - /* test raw factorizations */ - /* ---------------------------------------------------------------------- */ - - printf ("==================================== fac memory test\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - my_srand (trial+1) ; /* RAND reset */ - err = raw_factor (A, FALSE) ; /* RAND */ - CHOLMOD(free_sparse) (&A, cm) ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - CHOLMOD(free_work) (cm) ; - printf ("memory test: fac error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - - /* ---------------------------------------------------------------------- */ - /* test raw factorizations (rowfac_mask) */ - /* ---------------------------------------------------------------------- */ - - printf ("==================================== fac memory test2\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - my_srand (trial+1) ; /* RAND reset */ - err = raw_factor2 (A, 0., 0) ; /* RAND */ - CHOLMOD(free_sparse) (&A, cm) ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - CHOLMOD(free_work) (cm) ; - printf ("memory test: fac error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - - /* ---------------------------------------------------------------------- */ - /* test augmented system solver */ - /* ---------------------------------------------------------------------- */ - - printf ("==================================== aug memory test\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - err = aug (A) ; /* no random number use */ - CHOLMOD(free_sparse) (&A, cm) ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - CHOLMOD(free_work) (cm) ; - printf ("memory test: aug error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - - /* ---------------------------------------------------------------------- */ - /* test ops */ - /* ---------------------------------------------------------------------- */ - - printf ("==================================== test_ops memory test\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - my_srand (trial+1) ; /* RAND reset */ - err = test_ops (A) ; /* RAND */ - CHOLMOD(free_sparse) (&A, cm) ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - printf ("inuse "ID" "ID"\n", (Int) inuse, (Int) (cm->memory_inuse)) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - printf ("memory test: testops error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - - /* ---------------------------------------------------------------------- */ - /* test lpdemo */ - /* ---------------------------------------------------------------------- */ - - if (T == NULL || T->nrow != T->ncol) - { - printf ("==================================== lpdemo memory test\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - my_srand (trial+1) ; /* RAND reset */ - err = lpdemo (T) ; /* RAND */ - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - CHOLMOD(free_work) (cm) ; - printf ("memory test: lpdemo error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - - /* ---------------------------------------------------------------------- */ - /* test solver */ - /* ---------------------------------------------------------------------- */ - - printf ("==================================== solve memory test\n") ; - count = cm->malloc_count ; - my_tries = -1 ; - for (trial = 0 ; my_tries <= 0 ; trial++) - { - CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->metis_memory = 2.0 ; - cm->nmethods = 4 ; - cm->print = 0 ; - fflush (stdout) ; - my_tries = trial ; - A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; - my_srand (trial+1) ; /* RAND reset */ - err = solve (A) ; /* RAND */ - CHOLMOD(free_sparse) (&A, cm) ; - OK (CHOLMOD(print_common) ("cm", cm)) ; - CHOLMOD(free_work) (cm) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - } - CHOLMOD(free_work) (cm) ; - printf ("memory test: solve error %.1g trials "ID"\n", err, trial) ; - printf ("initial count: "ID" final count "ID"\n", - (Int) count, (Int) cm->malloc_count) ; - printf ("initial inuse: "ID" final inuse "ID"\n", - (Int) inuse, (Int) cm->memory_inuse) ; - OK (count == cm->malloc_count) ; - OK (inuse == cm->memory_inuse) ; - cm->supernodal = CHOLMOD_AUTO ; - progress (1, '|') ; - - /* ---------------------------------------------------------------------- */ - /* restore original memory handler */ - /* ---------------------------------------------------------------------- */ - - normal_memory_handler ( ) ; - cm->print = 1 ; - - printf ("All memory tests OK, no error\n") ; -} diff --git a/CHOLMOD/Tcov/null.c b/CHOLMOD/Tcov/null.c deleted file mode 100644 index 1f13e8fbc1..0000000000 --- a/CHOLMOD/Tcov/null.c +++ /dev/null @@ -1,359 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/null: test CHOLMOD with NULL and erroneous inputs -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test CHOLMOD with NULL pointers, and other error cases. */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === my_hander2 =========================================================== */ -/* ========================================================================== */ - -void my_handler2 (int status, const char *file, int line, const char *msg) -{ - printf ("This ERROR is expected: file %s line %d\n%d: %s\n", - file, line, status, msg) ; -} - - -/* ========================================================================== */ -/* === null_test ============================================================ */ -/* ========================================================================== */ - -/* This routine is not called during memory testing */ - -void null_test (cholmod_common *cn) -{ - cholmod_sparse *A = NULL, *F = NULL, *C = NULL, *R = NULL, *B = NULL ; - cholmod_factor *L = NULL ; - cholmod_triplet *T = NULL ; - cholmod_dense *X = NULL, *DeltaB = NULL, *S = NULL, *Y = NULL, *E = NULL ; - void *p = NULL, *ii = NULL, *jj = NULL, *xx = NULL, *zz = NULL ; - Int *Perm = NULL, *fset = NULL, *Parent = NULL, *Post = NULL, - *RowCount = NULL, *ColCount = NULL, *First = NULL, *Level = NULL, - *UserPerm = NULL, *colmark = NULL, *Constraints = NULL, - *r = NULL, *c = NULL, *Set = NULL ; - char *name = NULL ; - double alpha [2], beta [2], bk [2], yk [2], rcond ; - double dj = 1, nm = 0, tol = 0 ; - int ok, stype = 0, xtype = 0, sorted = 0, packed = 0, nint = 0, update = 0, - postorder = 0, pack = 0, values = 0, mode = 0, sys = 0, norm = 0, - to_xtype = 0, to_ll = 0, to_super = 0, to_packed = 0, to_monotonic = 0, - scale = 0, transpose = 0, option = 0, ordering = 0, prefer = 0, - mtype = 0, asym = 0 ; - int64_t lr = 0, k1 = 0, k2 = 0 ; - size_t j = 0, need = 0, n = 0, mr = 0, nrow = 0, ncol = 0, iworksize = 0, - newsize = 0, fsize = 0, d = 0, nzmax = 0, nnew = 0, size = 0, - nold = 0, xwork = 0, kstart = 0, kend = 0, nr = 0, nc = 0, len = 0, - krow = 0, k = 0 ; - -#ifndef NPARTITION - Int *Anw = NULL, *Aew = NULL, *Partition = NULL, *CParent = NULL, - *Cmember = NULL ; - Int compress = 0 ; -#endif - -#ifndef NCAMD - Int *Cmem2 = NULL ; -#endif - - /* ---------------------------------------------------------------------- */ - /* Utility */ - /* ---------------------------------------------------------------------- */ - - if (cn == NULL) - { - ok = CHOLMOD(start)(cn) ; NOT (ok) ; - } - ok = CHOLMOD(finish)(cn) ; NOT (ok) ; - ok = CHOLMOD(defaults)(cn) ; NOT (ok) ; - mr = CHOLMOD(maxrank)(n, cn) ; NOT (mr>0) ; - ok = CHOLMOD(allocate_work)(nrow, iworksize, xwork, cn) ; NOT (ok) ; - ok = CHOLMOD(free_work)(cn) ; NOT (ok) ; - lr = CHOLMOD(clear_flag)(cn) ; NOT (lr>=0) ; - - dj = CHOLMOD(dbound)(dj, cn) ; OK (dj==0) ; - ok = CHOLMOD(error)(CHOLMOD_INVALID, __FILE__, __LINE__, "oops", cn) ; - NOT (ok) ; - A = CHOLMOD(allocate_sparse)(nrow, ncol, nzmax, sorted, - packed, stype, xtype, cn) ; NOP (A) ; - ok = CHOLMOD(free_sparse)(&A, cn) ; NOT (ok) ; - ok = CHOLMOD(reallocate_sparse)(newsize, A, cn) ; NOT (ok) ; - lr = CHOLMOD(nnz)(A, cn) ; NOT (lr>=0) ; - A = CHOLMOD(speye)(nrow, ncol, xtype, cn) ; NOP (A) ; - A = CHOLMOD(spzeros)(nrow, ncol, 0, xtype, cn) ; NOP (A) ; - A = CHOLMOD(ptranspose)(A, values, Perm, fset, fsize, cn); NOP (A) ; - A = CHOLMOD(transpose)(A, values, cn) ; NOP (A) ; - ok = CHOLMOD(transpose_unsym)(A, values, Perm, fset, fsize, F, cn) ; - NOT (ok) ; - ok = CHOLMOD(transpose_sym)(A, values, Perm, F, cn) ; NOT (ok) ; - ok = CHOLMOD(sort)(A, cn) ; NOT (ok) ; - A = CHOLMOD(copy_sparse)(A, cn) ; NOP (A) ; - C = CHOLMOD(aat)(A, fset, fsize, mode, cn) ; NOP (C) ; - - L = CHOLMOD(allocate_factor)(n, cn) ; NOP (L) ; - ok = CHOLMOD(free_factor)(&L, cn) ; NOT (ok) ; - ok = CHOLMOD(reallocate_factor)(newsize, L, cn) ; NOT (ok) ; - ok = CHOLMOD(change_factor)(0, 0, 0, 0, 0, L, cn) ; NOT (ok) ; - ok = CHOLMOD(pack_factor)(L, cn) ; NOT (ok) ; - ok = CHOLMOD(change_factor)(to_xtype, to_ll, to_super, - to_packed, to_monotonic, L, cn) ; NOT (ok) ; - ok = CHOLMOD(reallocate_column)(j, need, L, cn) ; NOT (ok) ; - A = CHOLMOD(factor_to_sparse)(L, cn) ; NOP (A) ; - L = CHOLMOD(copy_factor)(L, cn) ; NOP (L) ; - - X = CHOLMOD(allocate_dense)(nrow, ncol, d, xtype, cn) ; NOP (X) ; - X = CHOLMOD(zeros)(nrow, ncol, xtype, cn) ; NOP (X) ; - X = CHOLMOD(ones)(nrow, ncol, xtype, cn) ; NOP (X) ; - X = CHOLMOD(eye)(nrow, ncol, xtype, cn) ; NOP (X) ; - ok = CHOLMOD(free_dense)(&X, cn) ; NOT (ok) ; - X = CHOLMOD(sparse_to_dense)(A, cn) ; NOP (X) ; - A = CHOLMOD(dense_to_sparse)(X, values, cn) ; NOP (A) ; - Y = CHOLMOD(copy_dense)(X, cn) ; NOP (X) ; - ok = CHOLMOD(copy_dense2)(X, Y, cn) ; NOT (ok) ; - - T = CHOLMOD(allocate_triplet)(nrow, ncol, nzmax, - stype, xtype, cn) ; NOP (T) ; - ok = CHOLMOD(free_triplet)(&T, cn) ; NOT (ok) ; - T = CHOLMOD(sparse_to_triplet)(A, cn) ; NOP (T) ; - A = CHOLMOD(triplet_to_sparse)(T, 0, cn) ; NOP (A) ; - T = CHOLMOD(copy_triplet)(T, cn) ; NOP (T) ; - ok = CHOLMOD(reallocate_triplet)(nzmax, T, cn) ; NOT (ok) ; - - lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cn) ; NOT (lr>=0) ; - p = CHOLMOD(malloc)(n, size, cn) ; NOP (p) ; - p = CHOLMOD(calloc)(n, size, cn) ; NOP (p) ; - p = CHOLMOD(free)(n, size, p, cn) ; NOP (p) ; - p = CHOLMOD(realloc)(nnew, size, p, &n, cn) ; NOP (p) ; - ok = CHOLMOD(realloc_multiple)(nnew, nint, xtype, - &ii, &jj, &xx, &zz, &nold, cn) ; NOT (ok) ; - - C = CHOLMOD(band)(A, k1, k2, mode, cn) ; NOP (C) ; - ok = CHOLMOD(band_inplace)(k1, k2, mode, A, cn) ; NOT (ok) ; - - ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL, L, cn) ; NOT (ok) ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL, A, cn) ; NOT (ok) ; - ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL, X, cn) ; NOT (ok) ; - ok = CHOLMOD(triplet_xtype)(CHOLMOD_REAL, T, cn) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* Cholesky */ - /* ---------------------------------------------------------------------- */ - - L = CHOLMOD(analyze)(A, cn) ; NOP (L) ; - L = CHOLMOD(analyze_p)(A, UserPerm, fset, fsize, cn) ; NOP (L) ; - ok = CHOLMOD(factorize)(A, L, cn) ; NOT (ok) ; - ok = CHOLMOD(factorize_p)(A, beta, fset, fsize, L, cn) ; NOT (ok) ; - rcond = CHOLMOD(rcond)(L, cn) ; NOT (rcond>=0) ; - X = CHOLMOD(solve)(sys, L, Y, cn) ; NOP (X) ; - C = CHOLMOD(spsolve)(sys, L, B, cn) ; NOP (C) ; - ok = CHOLMOD(etree)(A, Parent, cn) ; NOT (ok) ; - ok = CHOLMOD(rowcolcounts)(A, fset, fsize, Parent, Post, - RowCount, ColCount, First, Level, cn) ; NOT (ok) ; - ok = CHOLMOD(amd)(A, fset, fsize, Perm, cn) ; NOT (ok) ; - ok = CHOLMOD(camd)(A, fset, fsize, Constraints, Perm, cn) ; NOT (ok) ; - ok = CHOLMOD(colamd)(A, fset, fsize, postorder, Perm, cn) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(A, F, beta, kstart, kend, L, cn) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, F, krow, Parent, R, cn) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, c, 0, krow, L, R, cn) ; NOT (ok) ; - ok = CHOLMOD(resymbol)(A, fset, fsize, pack, L, cn) ; NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(A, fset, fsize, pack, L, cn) ;NOT (ok) ; - ok = CHOLMOD(analyze_ordering)(A, ordering, Perm, fset, - fsize, Parent, Post, ColCount, First, Level, cn) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* Modify */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(updown)(update, C, L, cn) ; NOT (ok) ; - ok = CHOLMOD(updown_solve)(update, C, L, X, DeltaB, cn) ; NOT (ok) ; - ok = CHOLMOD(updown_mark)(update, C, colmark, L, X, DeltaB, - cn) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(k, R, L, cn) ; NOT (ok) ; - ok = CHOLMOD(rowadd_solve)(k, R, bk, L, X, DeltaB, cn) ; NOT (ok) ; - ok = CHOLMOD(rowadd_mark)(k, R, bk, colmark, L, X, DeltaB, - cn) ; NOT (ok) ; - ok = CHOLMOD(rowdel)(k, R, L, cn) ; NOT (ok) ; - ok = CHOLMOD(rowdel_solve)(k, R, yk, L, X, DeltaB, cn) ; NOT (ok) ; - ok = CHOLMOD(rowdel_mark)(k, R, yk, colmark, L, X, DeltaB, - cn) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* MatrixOps */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(add)(A, B, alpha, beta, values, sorted, cn) ; NOP (C) ; - - C = CHOLMOD(copy)(A, stype, mode, cn) ; NOP (C) ; - ok = CHOLMOD(drop)(tol, A, cn) ; NOT (ok) ; - nm = CHOLMOD(norm_dense)(X, norm, cn) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_sparse)(A, norm, cn) ; NOT (nm>=0) ; - C = CHOLMOD(horzcat)(A, B, values, cn) ; NOP (C) ; - ok = CHOLMOD(scale)(S, scale, A, cn) ; NOT (ok) ; - ok = CHOLMOD(sdmult)(A, transpose, alpha, beta, X, Y, cn) ; NOT (ok) ; - C = CHOLMOD(ssmult)(A, B, stype, values, sorted, cn) ; NOP (C) ; - C = CHOLMOD(submatrix)(A, r, nr, c, nc, values, sorted, - cn) ; NOP (C) ; - C = CHOLMOD(vertcat)(A, B, values, cn) ; NOP (C) ; - asym = CHOLMOD(symmetry)(A, option, NULL, NULL, NULL, NULL, - cn) ; NOT(asym>=0) ; - - /* ---------------------------------------------------------------------- */ - /* Supernodal */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(super_symbolic)(A, F, Parent, L, cn) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(A, F, beta, L, cn) ; NOT (ok) ; - ok = CHOLMOD(super_lsolve)(L, X, E, cn) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, E, cn) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* Check */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(check_common)(cn) ; NOT (ok) ; - ok = CHOLMOD(print_common)(name, cn) ; NOT (ok) ; - - ok = CHOLMOD(check_sparse)(A, cn) ; NOT (ok) ; - ok = CHOLMOD(print_sparse)(A, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_dense)(X, cn) ; NOT (ok) ; - ok = CHOLMOD(print_dense)(X, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_factor)(L, cn) ; NOT (ok) ; - ok = CHOLMOD(print_factor)(L, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_triplet)(T, cn) ; NOT (ok) ; - ok = CHOLMOD(print_triplet)(T, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_subset)(Set, len, n, cn) ; NOT (ok) ; - ok = CHOLMOD(print_subset)(Set, len, n, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_perm)(Perm, n, n, cn) ; NOT (ok) ; - ok = CHOLMOD(print_perm)(Perm, n, n, name, cn) ; NOT (ok) ; - ok = CHOLMOD(check_parent)(Parent, n, cn) ; NOT (ok) ; - ok = CHOLMOD(print_parent)(Parent, n, name, cn) ; NOT (ok) ; - - A = CHOLMOD(read_sparse)(NULL, cn) ; NOP (A) ; - p = CHOLMOD(read_matrix)(NULL, prefer, &mtype, cn) ; NOP (p) ; - X = CHOLMOD(read_dense)(NULL, cn) ; NOP (X) ; - T = CHOLMOD(read_triplet)(NULL, cn) ; NOP (T) ; - - asym = CHOLMOD(write_dense) (NULL, NULL, NULL, cn) ; NOT (asym>=0) ; - asym = CHOLMOD(write_dense) ((FILE *) 1, NULL, NULL, cn) ; NOT (asym>=0) ; - - asym = CHOLMOD(write_sparse)(NULL, NULL, NULL, NULL, cn) ; NOT (asym>=0) ; - asym = CHOLMOD(write_sparse)((FILE *) 1, NULL, NULL, NULL, - cn) ; NOT (asym>=0) ; - - /* ---------------------------------------------------------------------- */ - /* Partition */ - /* ---------------------------------------------------------------------- */ - -#ifndef NPARTITION - lr = CHOLMOD(nested_dissection)(A, fset, fsize, Perm, - CParent, Cmember, cn) ; NOT (lr >= 0) ; - lr = CHOLMOD(collapse_septree) (n, n, 1., 4, - CParent, Cmember, cn) ; NOT (lr >= 0) ; - ok = CHOLMOD(metis)(A, fset, fsize, postorder, Perm, cn) ; NOT (ok) ; - lr = CHOLMOD(bisect)(A, fset, fsize, compress, - Partition, cn) ; NOT (lr >= 0) ; - lr = CHOLMOD(metis_bisector)(A, Anw, Aew, Partition, cn) ; NOT (lr >= 0) ; -#endif - -#ifndef NCAMD - ok = CHOLMOD(ccolamd)(A, fset, fsize, Cmem2, Perm, cn) ; NOT (ok) ; - ok = CHOLMOD(csymamd)(A, Cmem2, Perm, cn) ; NOT (ok) ; -#endif - -} - -/* ========================================================================== */ -/* === null_test2 =========================================================== */ -/* ========================================================================== */ - -void null_test2 (void) -{ - cholmod_dense *X, *Xbad = NULL ; - cholmod_sparse *Sbad = NULL, *A ; - int ok ; - - /* ---------------------------------------------------------------------- */ - /* Test Common */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(allocate_work)(SIZE_MAX, 1, 1, cm) ; NOT (ok) ; - ok = CHOLMOD(allocate_work)(1, SIZE_MAX, 1, cm) ; NOT (ok) ; - ok = CHOLMOD(allocate_work)(1, 1, SIZE_MAX, cm) ; NOT (ok) ; - - /* free a NULL pointer */ - CHOLMOD(free)(42, sizeof (char), NULL, cm) ; - cm->print = 5 ; CHOLMOD(print_common)("cm", cm) ; cm->print = 3 ; - - cm->maxrank = 3 ; - cm->maxrank = CHOLMOD(maxrank)(5, cm) ; OK (cm->maxrank == 4) ; - cm->maxrank = 1 ; - cm->maxrank = CHOLMOD(maxrank)(5, cm) ; OK (cm->maxrank == 2) ; - cm->maxrank = 8 ; - - /* test the error handler */ - cm->error_handler = my_handler2 ; - CHOLMOD(drop)(0., NULL, cm) ; - cm->error_handler = NULL ; - - /* ---------------------------------------------------------------------- */ - /* dense */ - /* ---------------------------------------------------------------------- */ - - X = CHOLMOD(allocate_dense)(5, 4, 1, CHOLMOD_REAL, cm) ; - OKP (X) ; - OK (X->d == 5) ; - CHOLMOD(free_dense)(&X, cm) ; - - X = CHOLMOD(allocate_dense)(1, Int_max, 1, CHOLMOD_REAL, cm) ; NOP (X) ; - X = CHOLMOD(allocate_dense)(1, 1, 1, CHOLMOD_PATTERN, cm) ; NOP (X) ; - CHOLMOD(free_dense)(&X, cm) ; - - /* free a NULL dense matrix */ - ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; - ok = CHOLMOD(free_dense)(NULL, cm) ; OK (ok) ; - - /* make an invalid sparse matrix */ - printf ("\nspeye:\n") ; - Sbad = CHOLMOD(speye)(2, 3, CHOLMOD_REAL, cm) ; - OKP (Sbad) ; - - Sbad->stype = 1 ; - ok = CHOLMOD(check_sparse)(Sbad, cm) ; NOT (ok) ; - printf ("\nSparse to dense:\n") ; - X = CHOLMOD(sparse_to_dense)(Sbad, cm) ; NOP (X) ; - ok = CHOLMOD(free_sparse)(&Sbad, cm) ; OK (ok) ; - - /* make an invalid dense matrix */ - Xbad = CHOLMOD(eye)(4, 4, CHOLMOD_REAL, cm) ; OKP (Xbad) ; - Xbad->d = 1 ; - ok = CHOLMOD(check_dense)(Xbad, cm) ; NOT (ok) ; - A = CHOLMOD(dense_to_sparse)(Xbad, TRUE, cm) ; - ok = CHOLMOD(free_dense)(&Xbad, cm) ; OK (ok) ; - CHOLMOD(print_common)("cm", cm) ; - cm->print = 5 ; CHOLMOD(print_sparse)(A, "Bad A", cm) ; cm->print = 3 ; - NOP (A) ; - - /* ---------------------------------------------------------------------- */ - /* sparse */ - /* ---------------------------------------------------------------------- */ - - /* free a NULL sparse matrix */ - ok = CHOLMOD(free_sparse)(&A, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(NULL, cm) ; OK (ok) ; - A = CHOLMOD(copy_sparse)(NULL, cm) ; NOP (A) ; - - /* ---------------------------------------------------------------------- */ - /* error tests done */ - /* ---------------------------------------------------------------------- */ - - printf ("------------------ null tests done\n") ; -} diff --git a/CHOLMOD/Tcov/null2.c b/CHOLMOD/Tcov/null2.c deleted file mode 100644 index 72a0e1bc88..0000000000 --- a/CHOLMOD/Tcov/null2.c +++ /dev/null @@ -1,3500 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/null2: test CHOLMOD with NULL and erroneous inputs -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Null and error tests, continued. */ - -#include "cm.h" -#include "amd.h" -#ifndef NCAMD -#include "camd.h" -#endif - -#define CSETSIZE 5 - - -/* ========================================================================== */ -/* === null2 ================================================================ */ -/* ========================================================================== */ - -void null2 (cholmod_triplet *Tok, int do_nantests) -{ - double nm, gsave0, gsave1, r, anorm, beta [2], maxerr, xnan, rcond, - ax, az, bx, bz, cx, cz, dx, dz, fx, fz ; - cholmod_sparse *A, *C, *AT, *E, *F, *G, *Sok, *R0, *R1, *Aboth, *Axbad, *I1, - *Abad, *R, *Acopy, *R3, *Abad2, *I, *I3, *Abad3, *AA, *Rt, *AF, *AFT, - *I7, *C2, *R2, *Z ; - cholmod_dense *Xok, *Bok, *Two, *X, *W, *XX, *YY, *Xbad2, *B, *Scale, - *Y, *X1, *B1, *B2, *X7, *B7 ; - cholmod_factor *L, *L2, *L3, *L4, *L5, *L6, *Lcopy, *Lbad, *L7 ; - cholmod_triplet *T, *T2, *Tz, *T3 ; - Int *fsetok, *Pok, *Flag, *Head, *Cp, *Ci, *P2, *Parent, *Lperm, - *Lp, *Li, *Lnz, *Lprev, *Lnext, *Ls, *Lpi, *Lpx, *Super, *Tj, *Ti, - *Enz, *Ep, *Post, *Cmember, *CParent, *Partition, *Pinv, *ATi, *ATp, - *LColCount, *ColCount, *First, *Level, *fsetbad, *Pbad, *Lz, - *R2p, *R2i ; - double *Xwork, *Cx, *x, *Lx, *Tx, *Az, *R2x ; - size_t size, nznew, gsave2 ; - int64_t lr ; - void *pp, *ii, *jj, *xx ; - Int p, i, j, d, nrhs, nrow, ncol, stype, fsizeok, nz, ok, n2, trial, anz, - nzmax, cset [CSETSIZE], Axbad_type, isreal, xtype, enz, Lxtype, Cxtype, - Xxtype, Txtype, Abad2xtype, k, xtype2, Abad3xtype, save1, save2, save3, - save4, ok1, fnz ; - int option, asym ; - FILE *f ; - - beta [0] = 1e-6 ; - beta [1] = 0 ; - xnan = 0 ; - - xtype = Tok->xtype ; - printf ("Tok xtype is %d\n", (int) xtype) ; - isreal = (xtype == CHOLMOD_REAL) ; - - /* ---------------------------------------------------------------------- */ - /* hypot and divcomplex */ - /* ---------------------------------------------------------------------- */ - - maxerr = 0 ; - ax = 4.3 ; - az = 9.2 ; - for (i = 0 ; i <= 1 ; i++) - { - if (i == 0) - { - bx = 3.14159 ; - bz = -1.2 ; - } - else - { - bx = 0.9 ; - bz = -1.2 ; - } - /* c = a/b */ - CHOLMOD(divcomplex)(ax, az, bx, bz, &cx, &cz) ; - /* d = c*b */ - dx = cx * bx - cz * bz ; - dz = cz * bx + cx * bz ; - /* e = d-a, which should be zero */ - fx = dx - ax ; - fz = dz - az ; - r = CHOLMOD(hypot)(fx, fz) ; - MAXERR (maxerr, r, 1) ; - OK (r < 1e-14) ; - } - - /* ---------------------------------------------------------------------- */ - /* create objects to test */ - /* ---------------------------------------------------------------------- */ - - printf ("\n------------------------null2 tests:\n") ; - - cm->error_handler = my_handler ; - - CHOLMOD(check_triplet)(Tok, cm) ; - nrhs = 5 ; - nrow = Tok->nrow ; - ncol = Tok->ncol ; - d = nrow + 2 ; - - A = CHOLMOD(triplet_to_sparse)(Tok, 0, cm) ; /* [ */ - - anorm = CHOLMOD(norm_sparse)(A, 1, cm) ; - anz = A->nzmax ; - - AT = CHOLMOD(transpose)(A, 2, cm) ; /* [ */ - - printf ("xtrue:\n") ; - Xok = xtrue (nrow, nrhs, d, xtype) ; /* [ */ - - printf ("rhs:\n") ; - Bok = rhs (A, nrhs, d) ; /* [ */ - printf ("fset:\n") ; - - fsetok = prand (ncol) ; /* [ */ /* RAND */ - fsetbad = prand (ncol) ; /* [ */ /* RAND */ - - if (ncol > 0) - { - fsetbad [0] = -1 ; - } - Pbad = prand (nrow) ; /* [ */ /* RAND */ - - if (nrow > 0) - { - Pbad [0] = -1 ; - } - I1 = CHOLMOD(speye)(nrow+1, nrow+1, xtype, cm) ; /* [ */ - - fsizeok = (ncol < 2) ? ncol : (ncol/2) ; - Pok = prand (nrow) ; /* [ */ /* RAND */ - - R2 = CHOLMOD(allocate_sparse)(nrow, 1, nrow, FALSE, TRUE, 0, /* [ */ - CHOLMOD_REAL, cm) ; - OKP (R2) ; - - R2p = R2->p ; - R2i = R2->i ; - R2x = R2->x ; - for (i = 0 ; i < nrow ; i++) - { - R2i [i] = Pok [i] ; - R2x [i] = 1 ; - } - R2p [0] = 0 ; - R2p [1] = nrow ; - - stype = A->stype ; - Two = CHOLMOD(zeros)(1, 1, xtype, cm) ; /* [ */ - *((double *)(Two->x)) = 2 ; - - Pinv = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; /* [ */ - Parent = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - Post = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - Cmember = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - CParent = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - Partition = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - ColCount = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - First = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - Level = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - - printf ("etree:\n") ; - - if (AT->stype >= 0) - { - /* AT is unsymmetric, or symmetric/upper */ - CHOLMOD(etree)(AT, Parent, cm) ; - } - else - { - /* A is symmetric/upper */ - CHOLMOD(etree)(A, Parent, cm) ; - } - CHOLMOD(check_parent)(Parent, nrow, cm) ; - for (cm->print = 0 ; cm->print <= ((nrow <= 30) ? 5 : 4) ; cm->print++) - { - CHOLMOD(print_parent)(Parent, nrow, "Parent", cm) ; - } - cm->print = 1 ; - - /* get row 0 and row 1 of A */ - R0 = NULL ; - R1 = NULL ; - Aboth = NULL ; - Sok = NULL ; - - if (isreal) - { - Aboth = CHOLMOD(copy)(A, 0, 1, cm) ; /* [ */ - Sok = CHOLMOD(copy)(A, 0, 0, cm) ; - Aboth->sorted = FALSE ; - } - - if (isreal) /* [ */ - { - if (nrow > 1) - { - cm->print = 4 ; - if (nrow < 10) - { - ok = CHOLMOD(print_sparse)(Aboth, "Aboth", cm) ; OK (ok) ; - } - i = 0 ; - R0 = CHOLMOD(submatrix)(Aboth, &i, 1, NULL, -1, TRUE, TRUE, cm) ; - ok = CHOLMOD(print_sparse)(R0, "Row zero", cm) ; OK (ok) ; - i = 1 ; - R1 = CHOLMOD(submatrix)(Aboth, &i, 1, NULL, -1, TRUE, TRUE, cm) ; - ok = CHOLMOD(print_sparse)(R1, "Row one", cm) ; OK (ok) ; - Rt = CHOLMOD(transpose)(R1, 1, cm) ; - - C = CHOLMOD(ssmult)(R0, Rt, 0, TRUE, TRUE, cm) ; OKP (C) ; - ok = CHOLMOD(print_sparse)(C, "(Row zero)*(Row one)'", cm) ;OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&Rt, cm) ; OK (ok) ; - cm->print = 1 ; - } - } - - /* Abad: symmetric but not square, or null if A is square */ - if (A->nrow != A->ncol) - { - Abad = CHOLMOD(copy_sparse)(A, cm) ; /* [ */ - Abad->stype = 1 ; - } - else - { - Abad = NULL ; - } - - /* Abad2: sparse matrix with invalid xtype */ - printf ("allocate Abad2:\n") ; - Abad2 = CHOLMOD(copy_sparse)(A, cm) ; /* [ */ - cm->print = 4 ; - CHOLMOD(print_sparse)(Abad2, "Abad2", cm) ; - cm->print = 1 ; - Abad2xtype = Abad2->xtype ; - Abad2->xtype = -999 ; - - /* Xbad2: dense matrix with invalid xtype */ - printf ("allocate Xbad2:\n") ; - Xbad2 = CHOLMOD(zeros)(2, 2, CHOLMOD_REAL, cm) ; /* [ */ - Xbad2->xtype = -911 ; - - /* ---------------------------------------------------------------------- */ - /* expect lots of errors */ - /* ---------------------------------------------------------------------- */ - - printf ("\n------------------------null2 tests: ERRORs will occur\n") ; - cm->error_handler = NULL ; - - /* ---------------------------------------------------------------------- */ - /* transpose */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(transpose)(Abad2, 1, cm) ; NOP (C) ; - ok = CHOLMOD(sort)(Abad2, cm) ; NOT (ok) ; - ok = CHOLMOD(sort)(NULL, cm) ; NOT (ok) ; - - if (nrow > 0) - { - C = CHOLMOD(ptranspose)(A, 1, Pbad, NULL, 0, cm) ; NOP (C) ; - } - - if (A->stype == 0) - { - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, TRUE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, - C, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, - C, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, Pok, NULL, 0, - C, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, Pok, fsetok, fsizeok, - C, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, NULL, fsetok, fsizeok, - C, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, - -(A->stype), CHOLMOD_PATTERN, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, NULL, fsetok, fsizeok, - C, cm) ; OK (ok); - - E = CHOLMOD(allocate_sparse)(nrow, ncol, anz, TRUE, FALSE, - (A->stype), CHOLMOD_PATTERN, cm) ; OKP (C) ; - enz = CHOLMOD(nnz)(E, cm) ; - OK (enz == 0) ; - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, Pok, nrow, - E, cm) ; OK (ok); - ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; - - } - else - { - // A is symmetric so transpose_unsym will fail - C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, TRUE, - -(A->stype), xtype, cm) ; OKP (C) ; - ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, - C, cm) ; NOT (ok); - OK (cm->status == CHOLMOD_INVALID) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - - if (A->nrow != A->ncol) - { - ok = CHOLMOD(transpose_sym)(A, 1, NULL, C, cm) ; NOT (ok) ; - } - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - /* Abad3: sparse matrix with invalid xtype [ */ - printf ("allocate Abad3:\n") ; - C = CHOLMOD(copy_sparse)(A, cm) ; - Abad3 = CHOLMOD(transpose)(A, 1, cm) ; OKP (Abad3) ; - E = CHOLMOD(transpose)(A, 1, cm) ; OKP (E) ; - Abad3xtype = Abad3->xtype ; - Abad3->xtype = -999 ; - - ok = CHOLMOD(transpose_sym)(C, 1, NULL, Abad3, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(Abad3, 1, NULL, C, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, Abad3, cm) ;NOT (ok); - ok = CHOLMOD(transpose_unsym)(Abad3, 1, NULL, NULL, 0, C, cm) ;NOT (ok); - - printf ("xtypes %d %d %d\n", C->xtype, E->xtype, (int) xtype) ; - - switch (xtype) - { - case CHOLMOD_REAL: - printf ("make E complex:1\n") ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_COMPLEX, E, cm) ; - OK (ok) ; - break ; - case CHOLMOD_COMPLEX: - printf ("make E zomplex\n") ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX, E, cm) ; - OK (ok) ; - break ; - case CHOLMOD_ZOMPLEX: - printf ("make E complex\n") ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_COMPLEX, E, cm) ; - OK (ok) ; - break ; - } - - printf ("xtypes %d %d %d now\n", C->xtype, E->xtype, (int) xtype) ; - printf ("dtypes %d %d\n", C->dtype, E->dtype) ; - - printf ("mismatch start [:\n") ; - ok = CHOLMOD(transpose_sym)(C, 1, NULL, E, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(E, 1, NULL, C, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(C, 2, NULL, E, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(E, 2, NULL, C, cm) ; NOT (ok) ; - - printf ("unsym transpose:\n") ; - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, E, cm) ; - NOT (ok); - - ok = CHOLMOD(transpose_unsym)(E, 1, NULL, NULL, 0, C, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(C, 2, NULL, NULL, 0, E, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(E, 2, NULL, NULL, 0, C, cm) ; NOT (ok); - printf ("mismatch done ]\n") ; - - printf ("wrong dim [:\n") ; - ok = CHOLMOD(transpose_sym)(C, 1, NULL, I1, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(I1, 1, NULL, C, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, I1, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(I1, 1, NULL, NULL, 0, C, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(C, 2, NULL, NULL, 0, I1, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(I1, 2, NULL, NULL, 0, C, cm) ; NOT (ok); - printf ("wrong dim ]\n") ; - - nz = CHOLMOD(nnz)(C, cm) ; - if (nz > 10) - { - printf ("F too small [:\n") ; - F = CHOLMOD(allocate_sparse)(C->ncol, C->nrow, C->nzmax-5, TRUE, TRUE, - -(C->stype), C->xtype, cm) ; OKP (F) ; - ok = CHOLMOD(transpose_sym)(C, 1, NULL, F, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, F, cm) ; NOT (ok); - CHOLMOD(free_sparse)(&F, cm) ; - printf ("F too small ]\n") ; - } - - ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, NULL, cm) ; NOT (ok); - ok = CHOLMOD(transpose_unsym)(NULL, 1, NULL, NULL, 0, C, cm) ; NOT (ok); - - ok = CHOLMOD(transpose_sym)(C, 1, NULL, NULL, cm) ; NOT (ok); - ok = CHOLMOD(transpose_sym)(NULL, 1, NULL, C, cm) ; NOT (ok); - - CHOLMOD(free_sparse)(&C, cm) ; - CHOLMOD(free_sparse)(&E, cm) ; - - Abad3->xtype = Abad3xtype ; - CHOLMOD(free_sparse)(&Abad3, cm) ; /* ] */ - - cm->status = CHOLMOD_OK ; - - /* ---------------------------------------------------------------------- */ - /* aat */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(aat)(NULL, NULL, 0, 0, cm) ; NOP (C) ; - if (stype) - { - C = CHOLMOD(aat)(A, fsetok, fsizeok, 0, cm) ; - NOP (C) ; - } - else - { - C = CHOLMOD(aat)(A, fsetok, fsizeok, 0, cm) ; OKP (C) ; - CHOLMOD(free_sparse)(&C, cm) ; - C = CHOLMOD(aat)(Abad2, fsetok, fsizeok, 0, cm) ; NOP (C) ; - } - - /* ---------------------------------------------------------------------- */ - /* add */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(add)(A, NULL, one, one, TRUE, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(add)(NULL, AT, one, one, TRUE, TRUE, cm) ; NOP (C) ; - - if (A->nrow == A->ncol && isreal) - { - C = CHOLMOD(add)(A, AT, one, one, TRUE, TRUE, cm) ; - OKP (C) ; - /* C should equal 2*A if A=A' */ - if (stype) - { - double *s ; - - E = CHOLMOD(copy_sparse)(A, cm) ; - CHOLMOD(scale)(Two, CHOLMOD_SCALAR, E, cm) ; - F = CHOLMOD(add)(C, E, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(drop)(0., F, cm) ; - nz = CHOLMOD(nnz)(F, cm) ; - OK (nz == 0) ; - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&F, cm) ; - - Scale = CHOLMOD(zeros)(nrow, 1, CHOLMOD_REAL, cm) ; - - s = Scale->x ; - for (i = 0 ; i < nrow ; i++) - { - s [i] = 2 ; - } - E = CHOLMOD(copy_sparse)(A, cm) ; - CHOLMOD(scale)(Scale, CHOLMOD_ROW, E, cm) ; - F = CHOLMOD(add)(C, E, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(drop)(0., F, cm) ; - nz = CHOLMOD(nnz)(F, cm) ; - r = CHOLMOD(norm_sparse)(F, 0, cm) ; - OK (nz == 0) ; - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&F, cm) ; - - E = CHOLMOD(copy_sparse)(A, cm) ; - CHOLMOD(scale)(Scale, CHOLMOD_COL, E, cm) ; - F = CHOLMOD(add)(C, E, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(drop)(0., F, cm) ; - nz = CHOLMOD(nnz)(F, cm) ; - r = CHOLMOD(norm_sparse)(F, 0, cm) ; - OK (nz == 0) ; - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&F, cm) ; - - for (i = 0 ; i < nrow ; i++) - { - s [i] = sqrt (2) ; - } - E = CHOLMOD(copy_sparse)(A, cm) ; - CHOLMOD(scale)(Scale, CHOLMOD_SYM, E, cm) ; - F = CHOLMOD(add)(C, E, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(drop)(0., F, cm) ; - nz = CHOLMOD(nnz)(F, cm) ; - r = CHOLMOD(norm_sparse)(F, 0, cm) ; - OK (r < 1e-12*anorm) ; - - Scale->x = NULL ; - CHOLMOD(scale)(Scale, CHOLMOD_SYM, E, cm) ; - Scale->x = s ; - - OKP (E) ; - OKP (cm) ; - ok = CHOLMOD(scale)(NULL, CHOLMOD_ROW, E, cm) ; NOT (ok) ; - ok = CHOLMOD(scale)(Scale, CHOLMOD_SYM, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(scale)(NULL, CHOLMOD_SYM, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(scale)(Scale, -1, E, cm) ; NOT (ok) ; - - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&F, cm) ; - CHOLMOD(free_dense)(&Scale, cm) ; - - } - CHOLMOD(free_sparse)(&C, cm) ; - } - - Axbad = CHOLMOD(copy_sparse)(A, cm) ; /* [ */ - Axbad_type = Axbad->xtype ; - Axbad->xtype = CHOLMOD_COMPLEX ; - C = CHOLMOD(add)(A, Axbad, one, one, TRUE, TRUE, cm) ; - bool Axbad_is_ok = (Axbad_type == CHOLMOD_COMPLEX) ; - if (Axbad_is_ok) - { - OKP (C) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - else - { - NOP (C) ; - } - - if (nrow > 1 && xtype == CHOLMOD_REAL) - { - /* C = A (0,:) + A (1,:) */ - C = CHOLMOD(add)(R0, R1, one, one, TRUE, TRUE, cm) ; OKP (C) ; - OK (CHOLMOD(check_sparse)(C, cm)) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(NULL, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* sparse */ - /* ---------------------------------------------------------------------- */ - - cm->print = 4 ; - - ok = CHOLMOD(reallocate_sparse)(10, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(reallocate_sparse)(2 * Abad2->nzmax, Abad2, cm) ; NOT (ok) ; - - C = CHOLMOD(copy_sparse)(Abad2, cm) ; NOP (C) ; - C = CHOLMOD(allocate_sparse)(2, 3, 6, TRUE, TRUE, 1, 0, cm) ; NOP (C) ; - - C = CHOLMOD(copy)(A, 0, -1, cm) ; OKP (C) ; - E = unpack (C) ; OKP (E) ; - F = CHOLMOD(copy_sparse)(E, cm) ; OKP (F) ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL, C, cm) ; OK (ok) ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL, F, cm) ; OK (ok) ; - /* G = C-F */ - G = CHOLMOD(add)(C, F, one, minusone, TRUE, FALSE, cm) ; OKP (G) ; - ok = CHOLMOD(drop)(0., G, cm) ; OK (ok) ; - nz = CHOLMOD(nnz)(G, cm) ; - CHOLMOD(print_sparse)(C, "C", cm) ; - CHOLMOD(print_sparse)(E, "E", cm) ; - CHOLMOD(print_sparse)(F, "F", cm) ; - CHOLMOD(print_sparse)(G, "G", cm) ; - - OK (nz == 0) ; - CHOLMOD(free_sparse)(&C, cm) ; - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&F, cm) ; - CHOLMOD(free_sparse)(&G, cm) ; - - cm->print = 1 ; - - /* ---------------------------------------------------------------------- */ - /* scale */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(scale)(Two, -1, C, cm) ; NOT (ok) ; - if (nrow > 1) - { - E = CHOLMOD(copy_sparse)(A, cm) ; OKP (E) ; - CHOLMOD(scale)(Two, CHOLMOD_ROW, E, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* amd */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(amd)(NULL, NULL, 0, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(amd)(A, NULL, 0, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(amd)(NULL, NULL, 0, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; - cm->current = -1 ; - ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; - cm->current = 0 ; - ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "AMD perm", cm) ; OK (ok) ; - i = cm->print ; - cm->print = 4 ; - if (A->nrow < 1000 && isreal) - { - CHOLMOD(print_sparse)(Aboth, "Aboth", cm) ; - ok = CHOLMOD(amd)(Aboth, NULL, 0, Pok, cm) ; OK (ok) ; - } - cm->print = i ; - ok = CHOLMOD(amd)(Abad2, NULL, 0, Pok, cm) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* camd */ - /* ---------------------------------------------------------------------- */ - -#ifndef NCAMD - ok = CHOLMOD(camd)(NULL, NULL, 0, NULL, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(camd)(A, NULL, 0, NULL, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(camd)(NULL, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; OK (ok) ; - cm->current = -1 ; - ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; OK (ok) ; - cm->current = 0 ; - ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "CAMD perm", cm) ; OK (ok) ; - i = cm->print ; - cm->print = 4 ; - if (A->nrow < 1000 && isreal) - { - CHOLMOD(print_sparse)(Aboth, "Aboth", cm) ; - ok = CHOLMOD(camd)(Aboth, NULL, 0, NULL, Pok, cm) ; OK (ok) ; - } - cm->print = i ; - ok = CHOLMOD(camd)(Abad2, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; -#endif - - /* ---------------------------------------------------------------------- */ - /* analyze */ - /* ---------------------------------------------------------------------- */ - - cm->print = 4 ; - ok = CHOLMOD(print_common)("OKcm", cm) ; OK (ok) ; - - cm->nmethods = 1 ; - cm->method [0].ordering = -1 ; - ok = CHOLMOD(print_common)("Bad cm", cm) ; NOT (ok) ; - ok = CHOLMOD(analyze_ordering)(NULL, 0, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, cm) ; NOT (ok) ; - L = CHOLMOD(analyze)(NULL, cm) ; NOP (L) ; - L = CHOLMOD(analyze)(Abad2, cm) ; NOP (L) ; - L = CHOLMOD(analyze)(A, cm) ; NOP (L) ; - - /* test AMD backup strategy */ - cm->nmethods = 2 ; - cm->method [0].ordering = -1 ; - cm->method [1].ordering = -1 ; - L = CHOLMOD(analyze)(A, cm) ; OKP (L) ; - - cm->nmethods = 0 ; /* restore defaults */ - cm->method [0].ordering = CHOLMOD_GIVEN ; - cm->method [1].ordering = CHOLMOD_AMD ; - cm->print = 4 ; - ok = CHOLMOD(print_common)("OKcm", cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L, "L symbolic", cm) ; OK (ok) ; - cm->print = 1 ; - ok = CHOLMOD(free_factor)(&L, cm) ; OK (ok) ; - ok = CHOLMOD(free_factor)(&L, cm) ; OK (ok) ; - ok = CHOLMOD(free_factor)(NULL, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* band */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(band)(NULL, 0, 0, 0, cm) ; NOP (C) ; - C = CHOLMOD(band)(Abad2, 0, 0, 0, cm) ; NOP (C) ; - - /* ---------------------------------------------------------------------- */ - /* ccolamd */ - /* ---------------------------------------------------------------------- */ - -#ifndef NCAMD - ok = CHOLMOD(ccolamd)(NULL, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, NULL, cm) ; NOT (ok) ; - - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; - if (stype) - { - NOT (ok) ; - } - else - { - OK (ok) ; - } - - cm->current = -1 ; - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; - cm->current = 0 ; - if (stype) - { - NOT (ok) ; - } - else - { - OK (ok) ; - } -#endif - - /* ---------------------------------------------------------------------- */ - /* copy */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(print_sparse)(Abad, "Abad", cm) ; - - C = CHOLMOD(copy)(Abad, 0, 1, cm) ; - CHOLMOD(print_sparse)(C, "copy of Abad", cm) ; - NOP (C) ; - - C = CHOLMOD(copy_sparse)(Abad, cm) ; - CHOLMOD(print_sparse)(C, "another copy of Abad", cm) ; - NOP (C) ; - - C = CHOLMOD(copy)(A, 0, -1, cm) ; OKP (C) ; - OK (nzdiag (C) == 0) ; - - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* submatrix */ - /* ---------------------------------------------------------------------- */ - - if (A->nrow == A->ncol) - { - /* submatrix cannot operation on symmetric matrices */ - C = CHOLMOD(copy)(A, 1, 0, cm) ; OKP (C) ; - E = CHOLMOD(submatrix)(C, NULL, -1, NULL, -1, TRUE, TRUE, cm); NOP (E) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - - E = CHOLMOD(submatrix)(Abad2, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; NOP(E) ; - - if (A->stype == 0 && isreal) - { - /* E = A(:,:) */ - E = CHOLMOD(submatrix)(NULL, NULL,-1, NULL,-1, TRUE, TRUE, cm) ; NOP(E); - E = CHOLMOD(submatrix)(A, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; OKP(E) ; - /* C = A-E */ - C = CHOLMOD(add)(A, E, one, minusone, TRUE, TRUE, cm) ; OKP (C) ; - ok = CHOLMOD(drop)(0., C, cm) ; OK (ok) ; - ok = CHOLMOD(drop)(0., Abad2, cm) ; NOT(ok) ; - nz = CHOLMOD(nnz)(C, cm) ; - OK (nz == 0) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; - - i = -1 ; - E = CHOLMOD(submatrix)(A, &i, 1, NULL, -1, TRUE, TRUE, cm) ; NOP(E) ; - E = CHOLMOD(submatrix)(A, NULL, -1, &i, 1, TRUE, TRUE, cm) ; NOP(E) ; - E = CHOLMOD(submatrix)(A, &i, 1, &i, 1, TRUE, TRUE, cm) ; NOP(E) ; - i = 0 ; - j = -1 ; - E = CHOLMOD(submatrix)(A, &i, 1, &j, 1, TRUE, TRUE, cm) ; NOP(E) ; - } - - /* ---------------------------------------------------------------------- */ - /* read */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(read_sparse)(NULL, cm) ; NOP (C) ; - X = CHOLMOD(read_dense)(NULL, cm) ; NOP (X) ; - pp = CHOLMOD(read_matrix)(NULL, 1, NULL, cm) ; NOP (pp) ; - pp = CHOLMOD(read_matrix)((FILE *) 1, 1, NULL, cm) ; NOP (pp) ; - T3 = CHOLMOD(read_triplet)(NULL, cm) ; NOP (T3) ; - - /* ---------------------------------------------------------------------- */ - /* write */ - /* ---------------------------------------------------------------------- */ - - asym = CHOLMOD(write_sparse) (NULL, NULL, NULL, NULL, cm) ; NOT (asym>=0); - asym = CHOLMOD(write_sparse) ((FILE *) 1, NULL, NULL, NULL, cm) ; - NOT (asym>=0); - - asym = CHOLMOD(write_dense) (NULL, NULL, NULL, cm) ; NOT (asym>=0); - asym = CHOLMOD(write_dense) ((FILE *) 1, NULL, NULL, cm) ; NOT (asym>=0); - - f = fopen ("temp4.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, NULL, "garbage.txt", cm) ; - fclose (f) ; - printf ("write_sparse, asym: %d\n", asym) ; - OK (asym == EMPTY) ; - - if (A != NULL) - { - save1 = A->xtype ; - A->xtype = 999 ; - f = fopen ("temp4.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, NULL, NULL, cm) ; - fclose (f) ; - printf ("write_sparse, asym: %d\n", asym) ; - OK (asym == EMPTY) ; - A->xtype = save1 ; - } - - Z = CHOLMOD(speye) (nrow+1, ncol+1, CHOLMOD_PATTERN, cm) ; - f = fopen ("temp4.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; - fclose (f) ; - printf ("write_sparse, asym: %d with Z\n", asym) ; - OK (asym == EMPTY) ; - - Z->xtype = 999 ; - f = fopen ("temp4.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; - fclose (f) ; - printf ("write_sparse, asym: %d with Z2\n", asym) ; - OK (asym == EMPTY) ; - Z->xtype = CHOLMOD_PATTERN ; - - CHOLMOD(free_sparse) (&Z, cm) ; - - Z = CHOLMOD(speye) (0, ncol+1, CHOLMOD_PATTERN, cm) ; - f = fopen ("temp4.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; - fclose (f) ; - printf ("write_sparse, asym: %d with Z\n", asym) ; - if (A == NULL) - { - OK (asym == EMPTY) ; - } - else - { - OK (asym > EMPTY) ; - } - CHOLMOD(free_sparse) (&Z, cm) ; - - X = CHOLMOD(ones) (4, 4, CHOLMOD_REAL, cm) ; - f = fopen ("temp6.mtx", "w") ; - asym = CHOLMOD(write_dense) (f, X, "garbage.txt", cm) ; - fclose (f) ; - OK (asym == EMPTY) ; - - X->xtype = 999 ; - f = fopen ("temp6.mtx", "w") ; - asym = CHOLMOD(write_dense) (f, X, NULL, cm) ; - fclose (f) ; - OK (asym == EMPTY) ; - X->xtype = CHOLMOD_REAL ; - CHOLMOD(free_dense) (&X, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print_common */ - /* ---------------------------------------------------------------------- */ - - cm->print = 4 ; - ok = CHOLMOD(print_common)("Null", NULL) ; NOT (ok) ; - for (cm->status = CHOLMOD_INVALID ; cm->status <= CHOLMOD_DSMALL ; - cm->status++) - { - ok = CHOLMOD(print_common)("status", cm) ; OK (ok) ; - } - cm->status = 999 ; - ok = CHOLMOD(print_common)("bad status", cm) ; NOT (ok) ; - cm->status = CHOLMOD_OK ; - - Flag = cm->Flag ; - cm->Flag = NULL ; - ok = CHOLMOD(print_common)("bad Flag", cm) ; NOT (ok) ; - cm->Flag = Flag ; - ok = CHOLMOD(print_common)("ok Flag", cm) ; OK (ok) ; - - Flag [0] = Int_max ; - ok = CHOLMOD(print_common)("bad Flag", cm) ; NOT (ok) ; - Flag [0] = -1 ; - ok = CHOLMOD(print_common)("ok Flag", cm) ; OK (ok) ; - - Head = cm->Head ; - cm->Head = NULL ; - ok = CHOLMOD(print_common)("bad Head", cm) ; NOT (ok) ; - cm->Head = Head ; - ok = CHOLMOD(print_common)("ok Head", cm) ; OK (ok) ; - - Head [0] = Int_max ; - ok = CHOLMOD(print_common)("bad Head", cm) ; NOT (ok) ; - Head [0] = -1 ; - ok = CHOLMOD(print_common)("ok Head", cm) ; OK (ok) ; - - cm->status = CHOLMOD_OK ; - printf ("\nbad Xwork:\n") ; - Xwork = cm->Xwork ; - cm->Xwork = NULL ; - ok = CHOLMOD(print_common)("bad Xwork", cm) ; NOT (ok) ; - cm->Xwork = Xwork ; - ok = CHOLMOD(print_common)("ok Xwork", cm) ; OK (ok) ; - - Xwork [0] = 1 ; - ok = CHOLMOD(print_common)("bad Xwork", cm) ; NOT (ok) ; - Xwork [0] = 0 ; - ok = CHOLMOD(print_common)("ok Xwork", cm) ; OK (ok) ; - - p = cm->nmethods ; - i = cm->method [0].ordering ; - cm->nmethods = 1 ; - cm->method [0].ordering = 999 ; - ok = CHOLMOD(print_common)("bad method", cm) ; NOT (ok) ; - cm->nmethods = p ; - cm->method [0].ordering = i ; - - /* ---------------------------------------------------------------------- */ - /* print_sparse */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(copy_sparse)(A, cm) ; OKP (C) ; - - cm->print = 3 ; - C->itype = EMPTY ; - ok = CHOLMOD(print_sparse)(C, "CIbad", cm) ; NOT (ok) ; - C->itype = cm->itype ; - cm->print = 1 ; - - cm->print = 4 ; -#if defined ( CHOLMOD_INT64 ) - C->itype = CHOLMOD_INT ; -#else - C->itype = CHOLMOD_LONG ; -#endif - ok = CHOLMOD(print_sparse)(C, "Cibad2", cm) ; NOT (ok) ; - C->itype = cm->itype ; - cm->print = 1 ; - - C->dtype = CHOLMOD_SINGLE ; - ok = CHOLMOD(print_sparse)(C, "C single: OK", cm) ; OK (ok) ; - C->dtype = EMPTY ; - ok = CHOLMOD(print_sparse)(C, "CDbad", cm) ; NOT (ok) ; - C->dtype = CHOLMOD_DOUBLE ; - - Cxtype = C->xtype ; - C->xtype = EMPTY ; - ok = CHOLMOD(print_sparse)(C, "CXbad", cm) ; NOT (ok) ; - C->xtype = Cxtype ; - - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - - C->p = NULL ; - ok = CHOLMOD(print_sparse)(C, "Cp bad", cm) ; NOT (ok) ; - C->p = Cp ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - C->i = NULL ; - ok = CHOLMOD(print_sparse)(C, "Ci bad", cm) ; NOT (ok) ; - C->i = Ci ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - C->x = NULL ; - ok = CHOLMOD(print_sparse)(C, "Cx bad", cm) ; NOT (ok) ; - C->x = Cx ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - Cp [0] = 42 ; - ok = CHOLMOD(print_sparse)(C, "Cp [0] bad", cm) ; NOT (ok) ; - Cp [0] = 0 ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - p = Cp [ncol] ; - Cp [ncol] = C->nzmax + 10 ; - ok = CHOLMOD(print_sparse)(C, "Cp [ncol] bad", cm) ; NOT (ok) ; - Cp [ncol] = p ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - p = Cp [ncol] ; - Cp [ncol] = -1 ; - ok = CHOLMOD(print_sparse)(C, "Cp [ncol] neg", cm) ; NOT (ok) ; - Cp [ncol] = p ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - - if (ncol > 0) - { - p = Cp [1] ; - Cp [1] = 2*nrow + 1 ; - ok = CHOLMOD(print_sparse)(C, "Cp [1] bad", cm) ; NOT (ok) ; - Cp [1] = p ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - } - - if (ncol > 2) - { - p = Cp [2] ; - Cp [2] = Cp [1] - 1 ; - ok = CHOLMOD(print_sparse)(C, "Cp [2] bad", cm) ; NOT (ok) ; - Cp [2] = p ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - } - - if (Cp [ncol] > 0) - { - i = Ci [0] ; - Ci [0] = -1 ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] neg", cm) ; NOT (ok) ; - Ci [0] = i ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - } - - if (ncol > 0 && C->sorted && Cp [1] - Cp [0] > 2) - { - i = Ci [0] ; - Ci [0] = nrow-1 ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; NOT (ok) ; - Ci [0] = i ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - } - - if (ncol > 0 && C->sorted && ncol > 2 && Cp [1] - Cp [0] > 2) - { - /* swap the first two entries */ - p = Ci [0] ; - Ci [0] = Ci [1] ; - Ci [1] = p ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; NOT (ok) ; - C->sorted = FALSE ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; OK (ok) ; - Ci [1] = Ci [0] ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] duplicate", cm) ; NOT (ok) ; - Ci [1] = p ; - ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; OK (ok) ; - p = Ci [0] ; - Ci [0] = Ci [1] ; - Ci [1] = p ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - C->sorted = TRUE ; - ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; - } - - E = CHOLMOD(copy_sparse)(C, cm) ; OKP (E) ; - Enz = CHOLMOD(malloc)(ncol, sizeof (Int), cm) ; OKP (Enz) ; - E->nz = Enz ; - Ep = E->p ; - for (j = 0 ; j < ncol ; j++) - { - Enz [j] = Ep [j+1] - Ep [j] ; - } - E->packed = FALSE ; - ok = CHOLMOD(print_sparse)(E, "E unpacked ok", cm) ; OK (ok) ; - - ok = CHOLMOD(band_inplace)(0, 0, 0, E, cm) ; NOT (ok) ; - - E->nz = NULL ; - ok = CHOLMOD(print_sparse)(E, "E unpacked bad", cm) ; NOT (ok) ; - E->nz = Enz ; - ok = CHOLMOD(print_sparse)(E, "E unpacked ok", cm) ; OK (ok) ; - - F = CHOLMOD(copy)(E, 0, 0, cm) ; - cm->print = 4 ; - ok = CHOLMOD(print_sparse)(F, "F pattern ok", cm) ; OK (ok) ; - cm->print = 1 ; - - CHOLMOD(free_sparse)(&F, cm) ; - CHOLMOD(free_sparse)(&E, cm) ; - CHOLMOD(free_sparse)(&C, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print_dense */ - /* ---------------------------------------------------------------------- */ - - X = CHOLMOD(sparse_to_dense)(NULL, cm) ; NOP (X) ; - X = CHOLMOD(sparse_to_dense)(Abad2, cm) ; NOP (X) ; - C = CHOLMOD(dense_to_sparse)(NULL, TRUE, cm) ; NOP (C) ; - - X = CHOLMOD(copy_dense)(Xok, cm) ; - - ok = CHOLMOD(print_dense)(NULL, "null", cm) ; NOT (ok) ; - - x = X->x ; - X->x = NULL ; - ok = CHOLMOD(print_dense)(X, "Xnull", cm) ; NOT (ok) ; - X->x = x ; - ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; - - X->nzmax = 1 ; - ok = CHOLMOD(print_dense)(X, "X nzmax too small", cm) ; NOT (ok) ; - X->nzmax = Xok->nzmax ; - ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; - - X->d = -1 ; - ok = CHOLMOD(print_dense)(X, "X d too small", cm) ; NOT (ok) ; - X->d = Xok->d ; - ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; - - Xxtype = X->xtype ; - X->xtype = CHOLMOD_PATTERN ; - ok = CHOLMOD(print_dense)(X, "X pattern", cm) ; NOT (ok) ; - - X->xtype = -1 ; - ok = CHOLMOD(print_dense)(X, "X unknown", cm) ; NOT (ok) ; - X->xtype = Xxtype ; - ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; - - X->dtype = CHOLMOD_SINGLE ; - ok = CHOLMOD(print_dense)(X, "X float: OK", cm) ; OK (ok) ; - X->dtype = -1 ; - ok = CHOLMOD(print_dense)(X, "X unknown", cm) ; NOT (ok) ; - X->dtype = CHOLMOD_DOUBLE ; - ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; - - CHOLMOD(free_dense)(&X, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print_subset */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(check_subset)(NULL, 0, 0, cm) ; OK (ok) ; - ok = CHOLMOD(print_subset)(NULL, 0, 0, "null", cm) ; OK (ok) ; - - for (i = 0 ; i < CSETSIZE ; i++) - { - cset [i] = i ; - } - - for (cm->print = 0 ; cm->print <= 5 ; cm->print++) - { - ok = CHOLMOD(print_subset)(NULL, -1, 10, "[0:9]", cm) ; - OK (ok) ; - ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset OK", cm) ; - OK (ok) ; - cset [0] = -1 ; - ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset bad", cm) ; - NOT (ok) ; - cset [0] = CSETSIZE-1 ; - ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset OK", cm) ; - OK (ok) ; - } - - cm->print = 1 ; - - /* ---------------------------------------------------------------------- */ - /* print_perm */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(check_perm)(NULL, 0, 0, cm) ; OK (ok) ; - - for (cm->print = 3 ; cm->print <= 4 ; cm->print++) - { - ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P OK", cm) ; - OK (ok) ; - if (nrow > 0) - { - p = Pok [0] ; - Pok [0] = 2*ncol + 1 ; - ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P bad", cm) ; - NOT (ok) ; - Pok [0] = p ; - ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P OK", cm) ; - } - OK (ok) ; - } - cm->print = 1 ; - - n2 = 2 * cm->nrow ; - P2 = prand (n2) ; /* RAND */ - - for (cm->print = 3 ; cm->print <= 4 ; cm->print++) - { - ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 OK", cm) ; - OK (ok) ; - p = P2 [0] ; - P2 [0] = -1 ; - ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 bad", cm) ; - NOT (ok) ; - P2 [0] = p ; - ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 OK", cm) ; - OK (ok) ; - } - cm->print = 1 ; - - CHOLMOD(free)(2 * (cm->nrow), sizeof (Int), P2, cm) ; - - /* ---------------------------------------------------------------------- */ - /* print_parent */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(print_parent)(NULL, 0, "null", cm) ; NOT (ok) ; - if (nrow > 0) - { - i = Parent [0] ; - Parent [0] = -2 ; - ok = CHOLMOD(print_parent)(Parent, nrow, "bad Parent", cm) ; NOT (ok) ; - Parent [0] = i ; - ok = CHOLMOD(print_parent)(Parent, nrow, "OK Parent", cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* print_factor */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0) - { - L = CHOLMOD(allocate_factor)(nrow, cm) ; OKP (L) ; - ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; NOT (ok) ; - CHOLMOD(free_factor)(&L, cm) ; - } - - ok = CHOLMOD(print_factor)(NULL, "L null", cm) ; NOT (ok) ; - - /* create a valid symbolic supernodal L */ - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_asis = TRUE ; - L = CHOLMOD(analyze)(A, cm) ; /* [ */ OKP (L) ; - ok = CHOLMOD(print_factor)(L, "L ok", cm) ; OK (ok) ; - - ok = CHOLMOD(change_factor)(CHOLMOD_ZOMPLEX, TRUE, TRUE, TRUE, TRUE, L, cm); - NOT (ok) ; - - OK (L->xtype == CHOLMOD_PATTERN) ; - OK (L->is_super) ; - - L->itype = -1 ; - ok = CHOLMOD(print_factor)(L, "L int unknown", cm) ; NOT (ok) ; - L->itype = cm->itype ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - cm->print = 4 ; -#if defined ( CHOLMOD_INT64 ) - L->itype = CHOLMOD_INT ; -#else - L->itype = CHOLMOD_LONG ; -#endif - ok = CHOLMOD(print_factor)(L, "L bad itype", cm) ; NOT (ok) ; - L->itype = cm->itype ; - cm->print = 1 ; - - cm->print = 4 ; - - i = L->ordering ; - L->ordering = -1 ; - ok = CHOLMOD(print_factor)(L, "L bad ordering", cm) ; NOT (ok) ; - L->ordering = CHOLMOD_GIVEN ; - ok = CHOLMOD(print_factor)(L, "L given ordering", cm) ; OK (ok) ; - L->ordering = i ; - - Lxtype = L->xtype ; - L->xtype = CHOLMOD_REAL ; - ok = CHOLMOD(print_factor)(L, "L real", cm) ; NOT (ok) ; - L->xtype = CHOLMOD_COMPLEX ; - ok = CHOLMOD(print_factor)(L, "L complex", cm) ; NOT (ok) ; - L->xtype = CHOLMOD_ZOMPLEX ; - ok = CHOLMOD(print_factor)(L, "L zomplex", cm) ; NOT (ok) ; - L->xtype = -1 ; - ok = CHOLMOD(print_factor)(L, "L unknown", cm) ; NOT (ok) ; - L->xtype = CHOLMOD_PATTERN ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - L->xtype = Lxtype ; - - /* ---------------------------------------------------------------------- */ - /* supernodal factor */ - /* ---------------------------------------------------------------------- */ - - /* create a valid supernodal numeric L (simplicial if Supernodal - * module not installed) */ - ok = CHOLMOD(factorize)(A, L, cm) ; - OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; - - if (L->is_super) - { - /* there is no supernodal zomplex L */ - ok = CHOLMOD(factor_xtype)(CHOLMOD_ZOMPLEX, L, cm) ; NOT (ok) ; - } - - /* pack the simplicial factor, or return silently if supernodal */ - ok = CHOLMOD(pack_factor)(L, cm) ; OK (ok) ; - - Lbad = CHOLMOD(copy_factor)(L, cm) ; /* [ */ - Lxtype = L->xtype ; - Lbad->xtype = -1 ; - - OK (L->is_super && L->xtype != CHOLMOD_PATTERN && L->is_ll) ; - - if (A->stype == 0) - { - ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; NOT (ok) ; - } - ok = CHOLMOD(super_symbolic)(A, Abad2, Parent, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_symbolic)(Abad2, A, Parent, L, cm) ; NOT (ok) ; - - W = CHOLMOD(zeros)(L->maxesize, 1, L->xtype, cm) ; OKP (W) ; - X = CHOLMOD(ones)(nrow, 1, L->xtype, cm) ; OKP (X) ; - ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; OK (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; OK (ok) ; - - ok = CHOLMOD(super_lsolve)(Lbad, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(Lbad, X, W, cm) ; NOT (ok) ; - - XX = CHOLMOD(zeros)(nrow, 1, - L->xtype == CHOLMOD_REAL ? CHOLMOD_COMPLEX : CHOLMOD_REAL, cm) ; - ok = CHOLMOD(super_lsolve)(L, X, XX, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, XX, cm) ; NOT (ok) ; - CHOLMOD(free_dense)(&XX, cm) ; - - ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; OK (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; OK (ok) ; - - x = X->x ; - X->x = NULL ; - ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; NOT (ok) ; - X->x = x ; - - x = W->x ; - W->x = NULL ; - ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; NOT (ok) ; - W->x = x ; - CHOLMOD(free_dense)(&X, cm) ; - CHOLMOD(free_dense)(&W, cm) ; - - cm->precise = TRUE ; - ok = CHOLMOD(print_factor)(L, "L supernodal (precise)", cm) ; OK (ok) ; - cm->precise = FALSE ; - ok = CHOLMOD(print_factor)(L, "L supernodal", cm) ; OK (ok) ; - cm->print = 1 ; - - /* cannot realloc a supernodal L */ - ok = CHOLMOD(reallocate_factor)(10000, L, cm) ; NOT (ok) ; - ok = CHOLMOD(reallocate_factor)(10000, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(pack_factor)(NULL, cm) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* print factor */ - /* ---------------------------------------------------------------------- */ - - Lxtype = L->xtype ; - - i = cm->print ; - cm->print = 4 ; - L->xtype = CHOLMOD_PATTERN ; - ok = CHOLMOD(print_factor)(L, "L pattern", cm) ; OK (ok) ; - C = CHOLMOD(factor_to_sparse)(L, cm) ; NOP (C) ; - L->xtype = Lxtype ; - cm->print = i ; - - /* check with bad L factor */ - ok = CHOLMOD(print_factor)(Lbad, "L unknown", cm) ; NOT (ok) ; - ok = CHOLMOD(reallocate_factor)(999, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(pack_factor)(Lbad, cm) ; NOT (ok) ; - C = CHOLMOD(factor_to_sparse)(Lbad, cm) ; NOP (C) ; - L2 = CHOLMOD(copy_factor)(Lbad, cm) ; NOP (L2) ; - ok = CHOLMOD(factorize)(A, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(A, NULL, 0, TRUE, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(nrow-2, A, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel)(nrow-2, NULL, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(A, AT, beta, 1, 2, Lbad, cm) ; NOT (ok) ; - ok = CHOLMOD(updown)(+1, A, Lbad, cm) ; NOT (ok) ; - - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - L->dtype = CHOLMOD_SINGLE ; - ok = CHOLMOD(print_factor)(L, "L float: OK", cm) ; OK (ok) ; - L->dtype = -1 ; - ok = CHOLMOD(print_factor)(L, "L unknown", cm) ; NOT (ok) ; - L->dtype = CHOLMOD_DOUBLE ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - if (nrow > 0) - { - Lperm = L->Perm ; - p = Lperm [0] ; - Lperm [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L perm invalid", cm) ; NOT (ok) ; - Lperm [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - } - - LColCount = L->ColCount ; - L->ColCount = NULL ; - ok = CHOLMOD(print_factor)(L, "L no colcount", cm) ; NOT (ok) ; - L->ColCount = LColCount ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - if (nrow > 0) - { - LColCount = L->ColCount ; - p = LColCount [0] ; - LColCount [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L colcount vad", cm) ; NOT (ok) ; - LColCount [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* print simplicial factor */ - /* ---------------------------------------------------------------------- */ - - /* check LDL' unpacked */ - ok = CHOLMOD(print_factor)(L, "L OK for L2 copy", cm) ; OK (ok) ; - L2 = CHOLMOD(copy_factor)(L, cm) ; /* [ */ OKP (L2) ; - ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, - TRUE, L2, cm) ; - - /* check LDL' packed */ - L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; - ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, TRUE, - TRUE, L3, cm) ; - ok = CHOLMOD(print_factor)(L3, "L3 OK", cm) ; OK (ok) ; - CHOLMOD(free_factor)(&L3, cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L2, "L2 OK", cm) ; OK (ok) ; - ok = CHOLMOD(pack_factor)(L2, cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L2, "L2 OK packed", cm) ; OK (ok) ; - - /* create a simplicial factor from scratch */ - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_asis = TRUE ; - L6 = CHOLMOD(analyze)(A, cm) ; /* [ */ OKP (L6) ; - ok = CHOLMOD(factorize)(A, L6, cm) ; - OK (cm->status >= CHOLMOD_OK) ; - cm->supernodal = CHOLMOD_AUTO ; - - ok = CHOLMOD(print_sparse)(A, "A OK", cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L6, "L6 OK", cm) ; OK (ok) ; - - Lz = L6->z ; - L6->z = NULL ; - ok = CHOLMOD(print_factor)(L6, "L6 no z", cm) ; - if (L6->xtype == CHOLMOD_ZOMPLEX) - { - NOT (ok) ; - } - else - { - OK (ok) ; - } - L6->z = Lz ; - CHOLMOD(free_factor)(&L6, cm) ; /* ] */ - - Az = A->z ; - A->z = NULL ; - ok = CHOLMOD(print_sparse)(A, "A no z", cm) ; - if (A->xtype == CHOLMOD_ZOMPLEX) - { - NOT (ok) ; - } - else - { - OK (ok) ; - } - A->z = Az ; - - Lp = L2->p ; - Li = L2->i ; - Lx = L2->x ; - Lnz = L2->nz ; - Lnext = L2->next ; - Lprev = L2->prev ; - - OK (Lp [0] == 0) ; - - L2->p = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no p", cm) ; NOT (ok) ; - L2->p = Lp ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - L2->i = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no i", cm) ; NOT (ok) ; - L2->i = Li ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - L2->x = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no x", cm) ; NOT (ok) ; - L2->x = Lx ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - L2->nz = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no nz", cm) ; NOT (ok) ; - L2->nz = Lnz ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - L2->next = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no next", cm) ; NOT (ok) ; - L2->next = Lnext ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - L2->prev = NULL ; - ok = CHOLMOD(print_factor)(L2, "L no prev", cm) ; NOT (ok) ; - L2->prev = Lprev ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - if (nrow > 0) - { - p = Lp [0] ; - Lp [0] = -1 ; - ok = CHOLMOD(print_factor)(L2, "Lp bad", cm) ; NOT (ok) ; - Lp [0] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Li [0] ; - Li [0] = -1 ; - ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; - Li [0] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Lnz [0] ; - Lnz [0] = -1 ; - ok = CHOLMOD(print_factor)(L2, "Lnz bad", cm) ; NOT (ok) ; - Lnz [0] = p ; - } - - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - OK (Lnz != NULL) ; - - if (nrow > 0 && Lnz [0] > 3) - { - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - p = Li [1] ; - Li [1] = nrow ; - ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; - Li [1] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK again", cm) ; OK (ok) ; - - p = Li [2] ; - Li [2] = Li [1] ; - ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; - Li [2] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - } - - /* check LDL' dynamic link list */ - ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, - FALSE, L2, cm) ; - OK (ok) ; - ok = CHOLMOD(print_factor)(L2, "L2 OK", cm) ; OK (ok) ; - OK (L2->xtype != CHOLMOD_PATTERN && !(L2->is_ll) && !(L2->is_super)) ; - - /* cannot do a supernodal factorization on a dynamic LDL' factor */ - ok = CHOLMOD(super_numeric)(AT, NULL, Zero, L2, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(I1, NULL, Zero, L2, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(I1, I1, Zero, L2, cm) ; NOT (ok) ; - - G = CHOLMOD(copy)(I1, 1, 0, cm) ; OKP (G) ; - ok = CHOLMOD(super_numeric)(G, NULL, Zero, L2, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&G, cm) ; OK (ok) ; - - G = CHOLMOD(copy)(I1, -1, 0, cm) ; OKP (G) ; - ok = CHOLMOD(super_numeric)(G, NULL, Zero, L2, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&G, cm) ; OK (ok) ; - - ok = CHOLMOD(super_numeric)(AT, I1, Zero, L2, cm) ; NOT (ok) ; - W = CHOLMOD(zeros)(nrow, 1, CHOLMOD_REAL, cm) ; OKP (W) ; - X = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL, cm) ; OKP (X) ; - ok = CHOLMOD(super_lsolve)(L2, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve)(L2, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(free_dense)(&W, cm) ; OK (ok) ; - ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; - - Lnext = L2->next ; - Lprev = L2->prev ; - - if (nrow > 3) - { - - p = Lnext [nrow+1] ; - Lnext [nrow+1] = -1 ; - ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; - Lnext [nrow+1] = -p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Lnext [2] ; - Lnext [2] = 2 ; - ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; - Lnext [2] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Lnext [2] ; - Lnext [2] = -1 ; - ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; - Lnext [2] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Lprev [2] ; - Lprev [2] = -9 ; - ok = CHOLMOD(print_factor)(L2, "Lprev bad", cm) ; NOT (ok) ; - Lprev [2] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - p = Lnext [nrow] ; - Lnext [nrow] = 0 ; - ok = CHOLMOD(print_factor)(L2, "Lnext/prev bad", cm) ; NOT (ok) ; - Lnext [nrow] = p ; - ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; - - /* make a non-monotonic copy of L2 and then mangle it */ - L6 = CHOLMOD(copy_factor)(L2, cm) ; - ok = CHOLMOD(reallocate_column)(0, nrow, L6, cm) ; - if (ok && !(L6->is_monotonic)) - { - ok = CHOLMOD(print_factor)(L6, "L6 monotonic OK ", cm) ; OK (ok) ; - L6->is_monotonic = TRUE ; - ok = CHOLMOD(print_factor)(L6, "L6 monotonic bad", cm) ; NOT (ok) ; - } - CHOLMOD(free_factor)(&L6, cm) ; - } - - - L6 = CHOLMOD(copy_factor)(L, cm) ; OKP (L6) ; - I = CHOLMOD(speye)(nrow, nrow, L->xtype, cm) ; OKP (I) ; - I3 = CHOLMOD(speye)(nrow, nrow, L->xtype-1, cm) ; OKP (I3) ; - - - ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; OK (ok) ; - ok = CHOLMOD(super_numeric)(I, I3, beta, L6, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(I, Abad2, beta, L6, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(I, I, beta, Lbad, cm) ; NOT (ok) ; - I->stype = -1 ; - ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; OK (ok) ; - ok = CHOLMOD(super_numeric)(I, NULL, beta, L6, cm) ; OK (ok) ; - I3->stype = -1 ; - - cm->print = 4 ; - CHOLMOD(print_sparse)(I3, "I3", cm) ; - CHOLMOD(print_factor)(L6, "L6", cm) ; - cm->print = 1 ; - - ok = CHOLMOD(super_numeric)(I3, NULL, beta, L6, cm) ; NOT (ok) ; - CHOLMOD(free_sparse)(&I, cm) ; - I = CHOLMOD(speye)(nrow+1, nrow+1, L->xtype, cm) ; OKP (I) ; - I->stype = -1 ; - ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; NOT (ok) ; - - - CHOLMOD(free_sparse)(&I, cm) ; - CHOLMOD(free_sparse)(&I3, cm) ; - ok = CHOLMOD(free_factor)(&L6, cm) ; OK (ok) ; - - /* check the supernodal L */ - Ls = L->s ; - Lpi = L->pi ; - Lpx = L->px ; - Super = L->super ; - Lx = L->x ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - L->s = NULL ; - ok = CHOLMOD(print_factor)(L, "L no s", cm) ; NOT (ok) ; - L->s = Ls ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - L->pi = NULL ; - ok = CHOLMOD(print_factor)(L, "L no pi", cm) ; NOT (ok) ; - L->pi = Lpi ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - L->px = NULL ; - ok = CHOLMOD(print_factor)(L, "L no px", cm) ; NOT (ok) ; - L->px = Lpx ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - L->super = NULL ; - ok = CHOLMOD(print_factor)(L, "L no super", cm) ; NOT (ok) ; - L->super = Super ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - - L->x = NULL ; - ok = CHOLMOD(print_factor)(L, "L no x", cm) ; NOT (ok) ; - L->x = Lx ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - p = Ls [0] ; - Ls [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L bad s", cm) ; NOT (ok) ; - Ls [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - p = Lpi [0] ; - Lpi [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L bad pi", cm) ; NOT (ok) ; - Lpi [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - p = Lpx [0] ; - Lpx [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L bad px", cm) ; NOT (ok) ; - Lpx [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - if (nrow > 0) - { - p = Super [0] ; - Super [0] = -1 ; - ok = CHOLMOD(print_factor)(L, "L bad super", cm) ; NOT (ok) ; - Super [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - - p = Ls [0] ; - Ls [0] = 42 ; - ok = CHOLMOD(print_factor)(L, "L bad s", cm) ; NOT (ok) ; - Ls [0] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - } - - if (nrow > 0 && Lpi [1] - Lpi [0] > 3) - { - p = Ls [2] ; - Ls [2] = Ls [1] ; - ok = CHOLMOD(print_factor)(L, "L unsorted s", cm) ; NOT (ok) ; - Ls [2] = p ; - ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* Cholesky */ - /* ---------------------------------------------------------------------- */ - - /* test the supernodal symbolic L */ - L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; - ok = CHOLMOD(change_factor)(CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, - L3, cm) ; - OK (ok) ; - - Ls = L3->s ; - Lpi = L3->pi ; - Super = L3->super ; - - if (nrow > 0) - { - p = Ls [0] ; - Ls [0] = 42 ; - ok = CHOLMOD(print_factor)(L3, "Lsym bad s", cm) ; NOT (ok) ; - Ls [0] = p ; - ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; - } - - if (nrow > 0 && Lpi [1] - Lpi [0] > 3) - { - p = Ls [2] ; - Ls [2] = Ls [1] ; - ok = CHOLMOD(print_factor)(L3, "Lsym unsorted s", cm) ; NOT (ok) ; - Ls [2] = p ; - ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; - } - - if (nrow > 0 && L->nsuper > 0) - { - Int nscol = Super [1] ; - Int nsrow = Lpi [1] - Lpi [0] ; - if (nsrow > nscol + 1) - { - p = Ls [nscol] ; - Ls [nscol] = Ls [nscol+1] ; - ok = CHOLMOD(print_factor)(L3, "Lsym unsorted s2", cm) ; NOT (ok) ; - Ls [nscol] = p ; - ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; - } - } - CHOLMOD(free_factor)(&L3, cm) ; - - /* (re)factorize as LL' */ - L5 = CHOLMOD(copy_factor)(L, cm) ; /* [ */ OKP (L5) ; - - ok = CHOLMOD(factor_xtype)(-1, L, cm) ; NOT (ok) ; - ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL, NULL, cm) ; NOT (ok) ; - - L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; - CHOLMOD(print_factor)(L3, "L3 before factorize", cm) ; - ok = CHOLMOD(change_factor)(L3->xtype, TRUE, FALSE, TRUE, TRUE, L3, cm) ; - OK (ok) ; - - Acopy = CHOLMOD(copy_sparse)(A, cm) ; /* [ */ - CHOLMOD(sparse_xtype)(L3->xtype, Acopy, cm) ; - - CHOLMOD(print_sparse)(Acopy, "Acopy for factorize", cm) ; - - ok = CHOLMOD(factorize)(Acopy, L3, cm) ; - OK (ok || cm->status >= CHOLMOD_OK) ; - ok = CHOLMOD(free_factor)(&L3, cm) ; OK (ok) ; - - CHOLMOD(print_sparse)(A, "A for factorize", cm) ; - CHOLMOD(print_factor)(L3, "L3 for factorize", cm) ; - - /* refactor, but with wrong-sized A */ - ok = CHOLMOD(print_sparse)(I1, "I1", cm) ; OK (ok) ; - ok = CHOLMOD(factorize)(I1, L, cm) ; NOT (ok) ; - ok = CHOLMOD(factorize)(Abad2, L, cm) ; NOT (ok) ; - C = CHOLMOD(transpose)(I1, 0, cm) ; OKP (C) ; - ok = CHOLMOD(print_sparse)(C, "C = I1'", cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L, "L OK ", cm) ; OK (ok) ; - - /* refactor, with invalid A (NULL, or symmetric but not square) */ - ok = CHOLMOD(print_sparse)(Abad, "Abad", cm) ; NOT (ok) ; - ok = CHOLMOD(factorize)(Abad, L, cm) ; NOT (ok) ; - - /* refactorize supernodal LL' */ - printf ("refactorize here\n") ; - ok = CHOLMOD(print_sparse)(Acopy, "Acopy refactorize", cm) ; OK (ok) ; - ok = CHOLMOD(print_factor)(L, "L for refactorize", cm) ; OK (ok) ; - - printf ("L->xtype for refactorize %d\n", L->xtype) ; - ok = CHOLMOD(factorize)(Acopy, L, cm) ; - OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; - ok = CHOLMOD(print_factor)(L, "L ok, here", cm) ; OK (ok) ; - - ok = CHOLMOD(factorize)(Acopy, L, cm) ; - OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; - ok = CHOLMOD(print_factor)(L, "L ok, here2", cm) ; OK (ok) ; - - /* solve */ - B = CHOLMOD(ones)(nrow, 0, CHOLMOD_REAL, cm) ; OKP (B) ; - X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; OKP (X) ; - ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; - - X = CHOLMOD(solve)(-1, L, B, cm) ; NOP (X) ; - ok = CHOLMOD(free_dense)(&B, cm) ; OK (ok) ; - - B = CHOLMOD(zeros)(nrow+1, 0, CHOLMOD_REAL, cm) ; OKP (B) ; - X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; NOP (X) ; - - B->xtype = 0 ; - X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; NOP (X) ; - B->xtype = CHOLMOD_REAL ; - ok = CHOLMOD(free_dense)(&B, cm) ; OK (ok) ; - - /* sparse solve */ - if (nrow < 100 && A->stype != 0) - { - /* solve A*C=I, so C should equal A inverse */ - I = CHOLMOD(speye)(nrow, nrow, CHOLMOD_REAL, cm) ; OKP (I) ; - C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; OKP (C) ; - /* compute norm of A*C-I */ - if (xtype == CHOLMOD_REAL) - { - E = CHOLMOD(ssmult)(A, C, 0, TRUE, FALSE, cm) ; OKP (E) ; - F = CHOLMOD(add)(E, I, minusone, one, TRUE, FALSE, cm) ;OKP (F) ; - cm->print = 4 ; - ok = CHOLMOD(print_sparse)(F, "A*inv(A)-I", cm) ; OK (ok) ; - cm->print = 1 ; - r = CHOLMOD(norm_sparse)(F, 1, cm) ; - OK (! (r < 0)) ; - MAXERR (maxerr, r, 1) ; - ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&F, cm) ; OK (ok) ; - } - CHOLMOD(free_sparse)(&C, cm) ; - - /* check error cases for sparse solve */ - C = CHOLMOD(spsolve)(CHOLMOD_A, NULL, I, cm) ; NOP (C) ; - C = CHOLMOD(spsolve)(CHOLMOD_A, Lbad, I, cm) ; NOP (C) ; - C = CHOLMOD(spsolve)(CHOLMOD_A, L, NULL, cm) ; NOP (C) ; - I->xtype = 0 ; - C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; - I->xtype = CHOLMOD_REAL ; - I->stype = -1 ; - C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; - ok = CHOLMOD(free_sparse)(&I, cm) ; OK (ok) ; - I = CHOLMOD(speye)(nrow+1, nrow+1, CHOLMOD_REAL, cm) ; OKP (I) ; - C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; - ok = CHOLMOD(free_sparse)(&I, cm) ; OK (ok) ; - } - - /* resymbol */ - ok = CHOLMOD(resymbol)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, FALSE, L, cm) ; - OK (ok) ; - ok = CHOLMOD(resymbol)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - - ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, FALSE, Lbad, cm); - NOT (ok) ; - - ok = CHOLMOD(resymbol_noperm)(Acopy, NULL, 0, TRUE, L2, cm) ; - if (Acopy->stype <= 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - - ok = CHOLMOD(resymbol_noperm)(Abad2, NULL, 0, TRUE, L2, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol)(Abad2, NULL, 0, TRUE, L2, cm) ; NOT (ok) ; - - ok = CHOLMOD(resymbol_noperm)(Acopy, NULL, 0, TRUE, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol)(Acopy, NULL, 0, TRUE, L2, cm) ; OK (ok) ; - - if (ncol > 0) - { - ok = CHOLMOD(print_perm)(fsetbad, ncol, ncol, "bad fset", cm) ; - NOT (ok) ; - } - - if (ncol > 1) - { - ok = CHOLMOD(resymbol)(Acopy, fsetok, ncol/2, TRUE, L2, cm) ; OK (ok) ; - ok = CHOLMOD(resymbol)(Acopy, fsetbad, ncol/2, TRUE, L2, cm) ; - if (Acopy->stype) - { - /* fset is ignored */ - OK (ok) ; - } - else - { - NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(Acopy, fsetbad, ncol/2, TRUE, L2, cm); - NOT (ok) ; - } - Acopy->sorted = FALSE ; - ok = CHOLMOD(resymbol)(Acopy, fsetok, ncol/2, TRUE, L2, cm) ; - OK (ok) ; - Acopy->sorted = TRUE ; - } - - cm->print = 4 ; - gsave0 = cm->grow0 ; - gsave1 = cm->grow1 ; - gsave2 = cm->grow2 ; - - /* reallocate column */ - L4 = NULL ; - if (nrow > 0) - { - ok = CHOLMOD(print_factor)(L, "L ok, for colrealloc", cm) ; OK (ok) ; - L4 = CHOLMOD(copy_factor)(L, cm) ; - ok = CHOLMOD(print_factor)(L4, "L4 ok, for colrealloc", cm) ; OK (ok) ; - OK (nrow == (Int)(L->n)) ; - ok = CHOLMOD(reallocate_column)(nrow, 1, L4, cm) ; NOT (ok) ; -// ok = CHOLMOD(reallocate_column)(nrow-1, 0, L4, cm) ; NOT (ok) ; - ok = CHOLMOD(reallocate_column)(nrow-1, 10, L4, cm) ; OK (ok) ; - - cm->grow0 = 2e10 ; - cm->grow1 = 2 ; - - /* this may or may not fail */ - ok = CHOLMOD(reallocate_column)(0, 10, L4, cm) ; - CHOLMOD(print_common)("OK or too large", cm) ; - ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; - } - - cm->grow0 = gsave0 ; - cm->grow1 = gsave1 ; - cm->grow2 = gsave2 ; - - if (ok && nrow > 2) - { - L4 = CHOLMOD(copy_factor)(L, cm) ; - ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L4, cm) ; OK (ok) ; - - /* make it non-monotonic and then monotonic (LDL' unpacked) */ - ok = CHOLMOD(reallocate_column)(0, nrow-1, L4, cm) ; OK (ok) ; - - /* this should be OK for small matrices, but fail for large ones */ - cm->grow0 = nrow ; - cm->grow1 = nrow ; - cm->grow2 = nrow ; - ok = CHOLMOD(change_factor)(CHOLMOD_REAL, FALSE, FALSE, FALSE, TRUE, - L4, cm) ; - - ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; - L4 = CHOLMOD(copy_factor)(L, cm) ; - ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L4, cm) ; OK (ok) ; - ok = CHOLMOD(pack_factor)(L4, cm) ; OK (ok) ; - - /* now try to make L4 really huge */ - - /* - cm->print = 5 ; - CHOLMOD(print_sparse) (A, "A for huge", cm) ; - CHOLMOD(print_factor) (L4, "L4 for huge", cm) ; - */ - - if (ok && !(L->is_super) && L->xtype != CHOLMOD_PATTERN) - { - - cm->grow0 = gsave0 ; - cm->grow1 = gsave1 ; - cm->grow2 = gsave2 ; - - ok = CHOLMOD(reallocate_column)(0, nrow-1, L4, cm) ; OK (ok) ; - - cm->grow0 = nrow ; - cm->grow1 = nrow ; - cm->grow2 = nrow ; - - /* - CHOLMOD(print_factor) (L4, "L4 for huge, realloced", cm) ; - printf ("L4 for huge is monotonic: %d\n", L4->is_monotonic) ; - */ - - if (!(L4->is_monotonic)) - { - /* printf ("Make L4 really huge: ") ; */ - ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, FALSE, FALSE, - TRUE, L4, cm) ; - printf ("L4 huge ok: "ID"\n", ok) ; - } - } - ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; - } - - cm->grow0 = gsave0 ; - cm->grow1 = gsave1 ; - cm->grow2 = gsave2 ; - - cm->print = 1 ; - - /* ---------------------------------------------------------------------- */ - /* more error tests */ - /* ---------------------------------------------------------------------- */ - - cm->error_handler = NULL ; - - /* ---------------------------------------------------------------------- */ - /* modify */ - /* ---------------------------------------------------------------------- */ - - X = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL, cm) ; OKP (X) ; - R = CHOLMOD(dense_to_sparse)(X, TRUE, cm) ; /* [ */ - OKP (R) ; - - if (isreal) - { - C = CHOLMOD(speye)(nrow, 1, CHOLMOD_REAL, cm) ; OKP (C) ; - ok = CHOLMOD(updown)(+1, C, L, cm) ; OK (ok) ; - X1 = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL, cm) ; - B1 = CHOLMOD(eye)(nrow, 1, CHOLMOD_REAL, cm) ; - ok = CHOLMOD(updown_solve)(+1, C, L, X1, B1, cm) ; OK (ok) ; - B1->xtype = -999 ; - ok = CHOLMOD(updown_solve)(+1, C, L, X1, B1, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd_solve)(0, R, beta, L, X1, B1, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel_solve)(0, R, beta, L, X1, B1, cm) ; NOT (ok) ; - B1->xtype = CHOLMOD_REAL ; - CHOLMOD(free_dense)(&B1, cm) ; - B2 = CHOLMOD(ones)(nrow, 2, CHOLMOD_REAL, cm) ; - ok = CHOLMOD(updown_solve)(+1, C, L, X1, B2, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd_solve)(0, R, beta, L, X1, B2, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel_solve)(0, R, beta, L, X1, B2, cm) ; NOT (ok) ; - - CHOLMOD(free_dense)(&B2, cm) ; - CHOLMOD(free_dense)(&X1, cm) ; - ok = CHOLMOD(updown)(+1, Abad2, L, cm) ; NOT (ok) ; - - ok = CHOLMOD(updown)(+1, C, NULL, cm) ; NOT (ok) ; - - C->sorted = FALSE ; - ok = CHOLMOD(updown)(+1, C, L, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - ok = CHOLMOD(updown)(+1, NULL, L, cm) ; NOT (ok) ; - - if (nrow > 0) - { - C = CHOLMOD(speye)(nrow-1, 1, CHOLMOD_REAL, cm) ; OKP (C) ; - ok = CHOLMOD(updown)(+1, C, L, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - - C = CHOLMOD(speye)(nrow, 0, CHOLMOD_REAL, cm) ; OKP (C) ; - ok = CHOLMOD(updown)(+1, C, L, cm) ; OK (ok) ; - - ok = CHOLMOD(rowdel)(0, C, L, cm) ; NOT (ok) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* rowfac, rcond */ - /* ---------------------------------------------------------------------- */ - - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->postorder = FALSE ; - - cm->print = 5 ; - cm->final_ll = TRUE ; - for (xtype2 = CHOLMOD_REAL ; xtype2 <= CHOLMOD_ZOMPLEX ; xtype2++) - { - cm->supernodal = CHOLMOD_SIMPLICIAL ; - - /* factor a singular matrix (C=LL') */ - printf ("start singular LL'\n") ; - XX = CHOLMOD(ones)(4, 4, xtype2, cm) ; OKP (X) ; - C = CHOLMOD(dense_to_sparse)(XX, TRUE, cm) ; OKP (C) ; - CHOLMOD(free_dense)(&XX, cm) ; - C->stype = 1 ; - CHOLMOD(print_sparse)(C, "C ones", cm) ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - printf ("status %d\n", cm->status) ; - ok1 = (cm->status == CHOLMOD_NOT_POSDEF) ; - ok = CHOLMOD(print_factor)(L6, "L6 singular", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - - /* now make C positive definite */ - CHOLMOD(free_sparse)(&C, cm) ; - XX = CHOLMOD(ones)(4, 4, xtype2, cm) ; OKP (X) ; - x = XX->x ; - for (i = 0 ; i < 4 ; i++) - { - if (xtype2 == CHOLMOD_REAL || xtype2 == CHOLMOD_ZOMPLEX) - { - x [i + 4*i] = 42 ; - } - else /* complex */ - { - x [2*(i + 4*i)] = 42 ; - } - } - C = CHOLMOD(dense_to_sparse)(XX, TRUE, cm) ; OKP (C) ; - CHOLMOD(free_dense)(&XX, cm) ; - C->stype = 1 ; - CHOLMOD(print_sparse)(C, "C ok", cm) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - ok1 = (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(print_factor)(L6, "L6 ok", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond > 0) ; - -/* generate intentional nan's, to test the nan-handling of cholmod_rcond */ -if (do_nantests) -{ - - xnan = xnan/xnan ; - - /* C(2,2) = nan */ - x = C->x ; - i = 2 ; - if (xtype2 == CHOLMOD_REAL || xtype2 == CHOLMOD_ZOMPLEX) - { - x [i + 4*i] = xnan ; - } - else /* complex */ - { - x [2*(i + 4*i)] = xnan ; - } - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - ok1 = (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(print_factor)(L6, "L6 nan2", cm) ; OK (ok) ; - printf ("rcond %g\n", rcond) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - CHOLMOD(free_factor)(&L6, cm) ; - - /* C(2,2) = nan, LDL' */ - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_ll = TRUE ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - ok1 = (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(print_factor)(L6, "LDL6 nan2", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - CHOLMOD(free_factor)(&L6, cm) ; - - /* C(2,2) = nan, supernodal */ - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_ll = FALSE ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - /* sometimes LAPACK says NaN is not pos.def, sometimes it doesn't...*/ - ok1 = (cm->status == CHOLMOD_OK || cm->status == CHOLMOD_NOT_POSDEF) ; - ok = CHOLMOD(print_factor)(L6, "L6 supernan2", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - CHOLMOD(free_factor)(&L6, cm) ; - - /* C(0,0) = nan */ - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_ll = FALSE ; - x [0] = xnan ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - ok1 = (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(print_factor)(L6, "L6 nan0", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - CHOLMOD(free_factor)(&L6, cm) ; - - /* C(0,0) = nan, LDL' */ - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_ll = TRUE ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - ok1 = (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(print_factor)(L6, "LDL6 nan0", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; - CHOLMOD(free_factor)(&L6, cm) ; - - /* C(0,0) = nan, supernodal */ - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_ll = FALSE ; - L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; - ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; - /* sometimes LAPACK says NaN is not pos.def, sometimes it doesn't...*/ - ok1 = (cm->status == CHOLMOD_OK || cm->status == CHOLMOD_NOT_POSDEF) ; - ok = CHOLMOD(print_factor)(L6, "L6 supernan0", cm) ; OK (ok) ; - OK (ok1) ; - rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; -} - - CHOLMOD(free_factor)(&L6, cm) ; - CHOLMOD(free_sparse)(&C, cm) ; - } - cm->supernodal = CHOLMOD_AUTO ; - cm->final_ll = FALSE ; - cm->print = 1 ; - - /* ---------------------------------------------------------------------- */ - /* refactorize simplicial LDL' */ - /* ---------------------------------------------------------------------- */ - - if (nrow < NLARGE) - { - L7 = CHOLMOD(analyze) (A, cm) ; OKP (L7) ; - ok = CHOLMOD(factorize) (A, L7, cm) ; OK (ok) ; - ok = CHOLMOD(factorize) (A, L7, cm) ; OK (ok) ; - B7 = CHOLMOD(ones) (nrow, 1, xtype, cm) ; OKP (B7) ; - X7 = CHOLMOD(solve) (CHOLMOD_A, L7, B7, cm) ; OKP (X7) ; - ok = CHOLMOD(free_dense) (&X7, cm) ; OK (ok) ; - ok = CHOLMOD(free_dense) (&B7, cm) ; OK (ok) ; - if (A->stype > 0) - { - ok = CHOLMOD(rowfac) (A, NULL, zero, 0, nrow, L7, cm) ; OK (ok) ; - ok = CHOLMOD(rowfac) (A, NULL, zero, 0, nrow, L7, cm) ; OK (ok) ; - printf ("I7 :::\n") ; - I7 = CHOLMOD(speye) (nrow+1, 1, xtype, cm) ; OKP (I7) ; - I7->stype = 1 ; - ok = CHOLMOD(rowfac) (I7,NULL, zero, 0, nrow, L7, cm) ; NOT(ok) ; - printf ("I7 ::: done\n") ; - CHOLMOD(free_sparse) (&I7, cm) ; - } - ok = CHOLMOD(free_factor) (&L7, cm) ; OK (ok) ; - } - - cm->nmethods = 0 ; /* restore defaults */ - cm->method [0].ordering = CHOLMOD_GIVEN ; - cm->postorder = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* row subtree */ - /* ---------------------------------------------------------------------- */ - - i = nrow / 2 ; - - C = CHOLMOD(allocate_sparse)(nrow, 1, nrow, TRUE, TRUE, 0, - CHOLMOD_REAL, cm) ; OKP (C) ; - C2 = CHOLMOD(allocate_sparse)(nrow, 1, nrow, TRUE, TRUE, 0, - CHOLMOD_REAL, cm) ; OKP (C) ; - ok = CHOLMOD(row_subtree)(NULL, NULL, i, Parent, C, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(NULL, NULL, 0, i, L, C2, cm) ; NOT (ok) ; - - if (A->stype == 0 && nrow > 0 && AT != NULL) - { - ok = CHOLMOD(row_subtree)(A, AT, i, Parent, C, cm) ; OK (ok) ; - - ATp = AT->p ; - ATi = AT->i ; - fnz = ATp [i+1] - ATp [i] ; - ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, C2, cm) ; - /* - if (i < ncol) { OK (ok) ; } else { NOT (ok) ; } - */ - OK (ok) ; - - ok = CHOLMOD(row_lsubtree)(Abad2, ATi, fnz, i, L, C2, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, NULL, fnz, i, L, C2, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, Abad2, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, NULL, C2, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, nrow+1, L, C2, cm) ;NOT (ok) ; - - ok = CHOLMOD(row_subtree)(Abad2, AT, i, Parent, C, cm) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, Abad2, i, Parent, C, cm) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, AT, i, Parent, Abad2, cm) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, C, cm) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, AT, nrow+1, Parent, C, cm) ; NOT (ok) ; - } - else - { - ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, C, cm) ; - if (A->stype == 1 && nrow > 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - #if 0 - ok = CHOLMOD(row_lsubtree)(A, NULL, 0, i, L, C2, cm) ; - printf ("%g %g %g\n", (double) A->stype, (double) nrow, (double) ok) ; - if (A->stype == 1 && nrow > 0 || (A->stype == 0 && nrow == 0 && - A->ncol == 1)) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - #endif - } - - ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(row_subtree)(A, NULL, i, NULL, C, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree)(A, NULL, 0, i, L, NULL, cm) ; NOT (ok) ; - - if (A->stype == 1 && nrow > 0) - { - /* add extra entries in the (ignored) lower triangular part to AA */ - if (!(A->sorted)) - { - ok = CHOLMOD(sort)(A, cm) ; OK (ok) ; - } - AA = CHOLMOD(copy)(A, 0, 0, cm) ; - OK (AA->sorted) ; - AA->stype = 1 ; - ok = CHOLMOD(row_subtree)(AA, NULL, i, Parent, C, cm) ; OK (ok) ; - ok = CHOLMOD(row_lsubtree)(AA, NULL, 0, i, L, C2, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&AA, cm) ; OK (ok) ; - } - - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&C2, cm) ; OK (ok) ; - - C = CHOLMOD(speye)(nrow, 0, CHOLMOD_REAL, cm) ; OKP (C) ; - if (A->stype == 0 && AT != NULL && nrow > 0) - { - ok = CHOLMOD(row_subtree)(A, AT, i, Parent, C, cm) ; NOT (ok) ; - - ATp = AT->p ; - ATi = AT->i ; - fnz = ATp [i+1] - ATp [i] ; - ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, C, cm) ; NOT (ok) ; - } - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - L6 = CHOLMOD(allocate_factor)(nrow, cm) ; OKP (L6) ; - if (A->stype == 0 && nrow > 2) - { - ok = CHOLMOD(rowfac)(A, AT, beta, 0, 1, L6, cm) ; OK (ok) ; - OK (cm->status == CHOLMOD_OK) ; - ok = CHOLMOD(rowfac)(A, NULL, beta, 1, 2, L6, cm) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(A, AT, beta, 1, 2, L6, cm) ; OK (ok) ; - ok = CHOLMOD(rowfac)(Abad2, AT, beta, 1, 2, L6, cm) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(A, Abad2, beta, 1, 2, L6, cm) ; NOT (ok) ; - } - ok = CHOLMOD(free_factor)(&L6, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* horzcat, vertcat */ - /* ---------------------------------------------------------------------- */ - - if (A->nrow != A->ncol) - { - C = CHOLMOD(horzcat)(A, AT, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(vertcat)(A, AT, TRUE, cm) ; NOP (C) ; - } - - C = CHOLMOD(horzcat)(A, Axbad, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(vertcat)(A, Axbad, TRUE, cm) ; NOP (C) ; - - C = CHOLMOD(vertcat)(A, NULL, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(vertcat)(NULL, AT, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(horzcat)(A, NULL, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(horzcat)(NULL, AT, TRUE, cm) ; NOP (C) ; - - /* ---------------------------------------------------------------------- */ - /* print_triplet */ - /* ---------------------------------------------------------------------- */ - - cm->print = 4 ; - ok = CHOLMOD(print_triplet)(Tok, "T ok", cm) ; OK (ok) ; - T = CHOLMOD(copy_triplet)(Tok, cm) ; /* [ */ OKP (T) ; - - Tz = T->z ; - T->z = NULL ; - ok = CHOLMOD(print_triplet)(T, "T no z", cm) ; - if (T->xtype == CHOLMOD_ZOMPLEX) - { - NOT (ok) ; - } - else - { - OK (ok) ; - } - T->z = Tz ; - cm->print = 1 ; - - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - ok = CHOLMOD(print_triplet)(NULL, "null", cm) ; NOT (ok) ; - - p = T->nzmax ; - T->nzmax = T->nnz - 1 ; - ok = CHOLMOD(print_triplet)(T, "T nzmax too small", cm) ; NOT (ok) ; - T->nzmax = p ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - T->itype = -1 ; - ok = CHOLMOD(print_triplet)(T, "T itype bad", cm) ; NOT (ok) ; - T->itype = cm->itype ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - cm->print = 4 ; -#if defined ( CHOLMOD_INT64 ) - T->itype = CHOLMOD_INT ; -#else - T->itype = CHOLMOD_LONG ; -#endif - ok = CHOLMOD(print_triplet)(T, "T bad itype", cm) ; NOT (ok) ; - T->itype = cm->itype ; - cm->print = 1 ; - - Txtype = T->xtype ; - T->xtype = -1 ; - ok = CHOLMOD(print_triplet)(T, "T xtype bad", cm) ; NOT (ok) ; - - T->xtype = Txtype ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - T->dtype = -1 ; - ok = CHOLMOD(print_triplet)(T, "T dtype bad", cm) ; NOT (ok) ; - T->dtype = CHOLMOD_SINGLE ; - ok = CHOLMOD(print_triplet)(T, "T dtype float: OK", cm) ; OK (ok) ; - T->dtype = CHOLMOD_DOUBLE ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - Tj = T->j ; - Ti = T->i ; - Tx = T->x ; - - T->j = NULL ; - ok = CHOLMOD(print_triplet)(T, "Tj null", cm) ; NOT (ok) ; - T->j = Tj ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - T->i = NULL ; - ok = CHOLMOD(print_triplet)(T, "Ti null", cm) ; NOT (ok) ; - T->i = Ti ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - T->x = NULL ; - ok = CHOLMOD(print_triplet)(T, "Tx null", cm) ; NOT (ok) ; - T->x = Tx ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - if (T->nnz > 0) - { - p = Ti [0] ; - Ti [0] = -1 ; - ok = CHOLMOD(print_triplet)(T, "Ti bad", cm) ; NOT (ok) ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; - Ti [0] = p ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - p = Tj [0] ; - Tj [0] = -1 ; - ok = CHOLMOD(print_triplet)(T, "Tj bad", cm) ; NOT (ok) ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; - Tj [0] = p ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - } - - cm->print = 4 ; -// ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - CHOLMOD(triplet_xtype)(CHOLMOD_PATTERN, T, cm) ; - ok = CHOLMOD(print_triplet)(T, "T pattern ok", cm) ; OK (ok) ; - cm->print = 1 ; - - /* ---------------------------------------------------------------------- */ - /* triplet, realloc_multiple */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - OK (cm->status == CHOLMOD_OK) ; - - cm->print = 4 ; - if (T->nrow != T->ncol) - { - OK (T->stype == 0) ; - - CHOLMOD(print_triplet)(T, "T ok", cm) ; - - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; - CHOLMOD(print_sparse)(C, "C ok", cm) ; - OKP (C) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - Ti = T->i ; - T->i = NULL ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; - if (T->nnz == 0) - { - OKP (C) ; - ASSERT (CHOLMOD(nnz) (C, cm) == 0) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - else - { - NOP (C) ; - } - T->i = Ti ; - - Tj = T->j ; - T->j = NULL ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; - if (T->nnz == 0) - { - OKP (C) ; - ASSERT (CHOLMOD(nnz) (C, cm) == 0) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - else - { - NOP (C) ; - } - T->j = Tj ; - - T->stype = 1 ; - ok = CHOLMOD(print_triplet)(T, "T bad", cm) ; NOT (ok) ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; - T->stype = 0 ; - ok = CHOLMOD(print_triplet)(T, "T pattern ok", cm) ; OK (ok) ; - } - OK (cm->status == CHOLMOD_OK) ; - cm->print = 1 ; - - ok = CHOLMOD(reallocate_triplet)(1, NULL, cm) ; NOT (ok) ; - - CHOLMOD(print_triplet)(T, "T before realloc", cm) ; - ok = CHOLMOD(reallocate_triplet)(1+(T->nzmax), T, cm) ; OK (ok) ; - CHOLMOD(print_triplet)(T, "T after realloc", cm) ; - - nznew = 10 + T->nzmax ; - pp = NULL ; - - ok = CHOLMOD(realloc_multiple)(SIZE_MAX/2, 2, T->xtype, &(T->i), - &(T->j), &(T->x), &(T->z), &(T->nzmax), cm) ; NOT (ok) ; - - size = 0 ; - ii = NULL ; - jj = NULL ; - xx = NULL ; - ok = CHOLMOD(realloc_multiple)(SIZE_MAX, 2, CHOLMOD_REAL, &ii, &jj, &xx, - NULL, &size, cm) ; NOT (ok) ; - - ok = CHOLMOD(realloc_multiple)(0, 0, CHOLMOD_PATTERN, &ii, &jj, &xx, NULL, - &size, cm) ; OK (ok) ; - - ok = CHOLMOD(realloc_multiple)(0, 0, -1, &ii, &jj, &xx, NULL, - &size, cm) ; NOT (ok) ; - - /* change to pattern-only */ - CHOLMOD(triplet_xtype)(CHOLMOD_PATTERN, T, cm) ; - - ok = CHOLMOD(reallocate_triplet)(1+(T->nzmax), T, cm) ; OK (ok) ; - - ok = CHOLMOD(free_triplet)(&T, cm) ; /* ] */ OK (ok) ; - - T = CHOLMOD(allocate_triplet)(nrow, ncol, SIZE_MAX, 0, CHOLMOD_REAL, cm); - NOP (T) ; - - T2 = CHOLMOD(allocate_triplet)(4, 4, 8, 0, CHOLMOD_REAL, cm); OKP (T2) ; - ok = CHOLMOD(reallocate_triplet)(12, T2, cm) ; OK (ok) ; - T = CHOLMOD(copy_triplet)(T2, cm) ; OKP (T) ; - CHOLMOD(free_triplet)(&T, cm) ; - T = CHOLMOD(sparse_to_triplet)(A, cm) ; OKP (T) ; - C = CHOLMOD(triplet_to_sparse)(T, 100, cm) ; OKP (C) ; - CHOLMOD(free_sparse)(&C, cm) ; - CHOLMOD(free_triplet)(&T, cm) ; - - T2->xtype = -1 ; - ok = CHOLMOD(reallocate_triplet)(16, T2, cm) ; NOT (ok) ; - T = CHOLMOD(copy_triplet)(T2, cm) ; NOP (T) ; - C = CHOLMOD(triplet_to_sparse)(T2, 100, cm) ; NOP (C) ; - T2->xtype = CHOLMOD_REAL ; - CHOLMOD(free_triplet)(&T2, cm) ; - -// T = CHOLMOD(allocate_triplet)(4, 4, 16, 0, -1, cm); NOP (T) ; - - T = CHOLMOD(sparse_to_triplet)(Abad2, cm) ; NOP (T) ; - - for (stype = -1 ; stype <= 1 ; stype++) - { - T = CHOLMOD(allocate_triplet)(4, 4, 16, stype, CHOLMOD_PATTERN, cm) ; - OKP (T) ; - Ti = T->i ; - Tj = T->j ; - k = 0 ; - for (i = 0 ; i < 4 ; i++) - { - for (j = 0 ; j < 4 ; j++) - { - Ti [k] = i ; - Tj [k] = j ; - k++ ; - } - } - T->nnz = k ; - C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; - cm->print = 4 ; - printf ("stype "ID"\n", stype) ; - CHOLMOD(print_triplet)(T, "T from triplet", cm) ; - CHOLMOD(print_sparse)(C, "C from triplet", cm) ; - cm->print = 1 ; - OKP (C) ; - CHOLMOD(free_sparse)(&C, cm) ; - CHOLMOD(free_triplet)(&T, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* sparse_to_triplet */ - /* ---------------------------------------------------------------------- */ - - if (A->nrow != A->ncol) - { - OK (A->stype == 0) ; - T = CHOLMOD(sparse_to_triplet)(A, cm) ; OKP (T) ; - ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; - - T2 = CHOLMOD(copy_triplet)(NULL, cm) ; NOP (T2) ; - - Ti = T->i ; - T->i = NULL ; - T2 = CHOLMOD(copy_triplet)(T, cm) ; - - if (T->nnz == 0) - { - OKP (T2) ; - } - else - { - NOP (T2) ; - } - T->i = Ti ; - ok = CHOLMOD(free_triplet)(&T2, cm) ; OK (ok) ; - - Tj = T->j ; - T->j = NULL ; - T2 = CHOLMOD(copy_triplet)(T, cm) ; - if (T->nnz == 0) - { - OKP (T2) ; - } - else - { - NOP (T2) ; - } - T->j = Tj ; - ok = CHOLMOD(free_triplet)(&T2, cm) ; OK (ok) ; - - ok = CHOLMOD(free_triplet)(&T, cm) ; OK (ok) ; - A->stype = 1 ; - T = CHOLMOD(sparse_to_triplet)(A, cm) ; NOP (T) ; - A->stype = 0 ; - T = CHOLMOD(sparse_to_triplet)(NULL, cm) ; NOP (T) ; - } - - /* ---------------------------------------------------------------------- */ - /* colamd */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(colamd)(NULL, fsetok, fsizeok, TRUE, Pok, cm) ; NOT (ok) ; - - cm->current = 0 ; - - save1 = cm->method [0].prune_dense2 ; - save2 = cm->method [0].ordering ; - save4 = cm->nmethods ; - - cm->method [0].prune_dense2 = 0.5 ; - cm->method [0].ordering = CHOLMOD_COLAMD ; - cm->nmethods = 1 ; - - ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; - if (A->stype == 0) - { - save3 = cm->print ; - cm->print = 5 ; - ok = CHOLMOD(print_common) ("colamd dense2", cm) ; OK (ok) ; - cm->print = save3 ; - OK (ok) ; - } - else - { - NOT (ok) ; - } - - cm->method [0].prune_dense2 = save1 ; - cm->method [0].ordering = save2 ; - cm->nmethods = save4 ; - - cm->current = -1 ; - ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; - if (A->stype == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - cm->current = 0 ; - - ok = CHOLMOD(colamd)(Abad2, NULL, 0, TRUE, Pok, cm) ; NOT (ok) ; - - if (ncol > 0) - { - ok = CHOLMOD(colamd)(A, fsetbad, ncol, TRUE, Pok, cm) ; NOT (ok) ; - } - - /* mangle the matrix to test integer overflow in colamd */ - if (A->stype == 0) - { - nzmax = A->nzmax ; - A->nzmax = SIZE_MAX/2 ; - ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; NOT (ok) ; - A->nzmax = nzmax ; - } - - /* ---------------------------------------------------------------------- */ - /* ccolamd/csymamd */ - /* ---------------------------------------------------------------------- */ - -#ifndef NCAMD - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; - if (A->stype == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - ok = CHOLMOD(ccolamd)(Abad2, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; - - ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; - if (A->nrow == A->ncol) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - ok = CHOLMOD(csymamd)(Abad2, NULL, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(csymamd)(NULL, NULL, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(csymamd)(A, NULL, NULL, cm) ; NOT (ok) ; - - /* mangle the matrix to test integer overflow in colamd */ - if (A->stype == 0) - { - nzmax = A->nzmax ; - A->nzmax = SIZE_MAX/2 ; - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; - A->nzmax = nzmax ; - } -#endif - - /* ---------------------------------------------------------------------- */ - /* amd */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* metis */ - /* ---------------------------------------------------------------------- */ - -#ifndef NPARTITION - /* no METIS memory guard */ - cm->metis_memory = 0 ; - if (A->stype) - { - E = CHOLMOD(copy)(A, 0, -1, cm) ; - } - else - { - E = CHOLMOD(aat)(A, NULL, 0, -1, cm) ; - } - enz = CHOLMOD(nnz)(E, cm) ; - - CHOLMOD(print_sparse)(A, "A for metis", cm) ; - - if (A != NULL && Pok != NULL) - { - ok = CHOLMOD(metis)(A, NULL, 0, TRUE, Pok, cm) ; - - /* memory guard triggered */ - if (nrow > 0) - { - double density ; - - cm->metis_memory = SIZE_MAX ; - ok = CHOLMOD(metis)(A, NULL, 0, FALSE, Pok, cm) ; - OK (ok) ; - /* Pok should be identity */ - for (j = 0 ; j < nrow ; j++) - { - OK (Pok [j] == j) ; - } - - /* memory guard triggered */ - cm->metis_memory = 2 ; - cm->metis_nswitch = 10 ; - - - ok = CHOLMOD(metis)(A, NULL, 0, FALSE, Pok, cm) ; OK (ok) ; - /* Pok should be identity if the matrix is dense */ - density = ((double) enz) / (((double) nrow) * ((double) nrow)) ; - if (nrow > 10 && density > cm->metis_dswitch) - { - for (j = 0 ; j < nrow ; j++) - { - OK (Pok [j] == j) ; - } - } - } - } - - /* restore METIS default memory guard */ - cm->metis_memory = 2 ; - cm->metis_nswitch = 3000 ; - - /* check metis bisector error handling */ - if (E != NULL && enz > 0) - { - Int *Anw, *Aew ; - Anw = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; - Aew = CHOLMOD(malloc)(MAX (anz,enz), sizeof (Int), cm) ; - for (j = 0 ; j < nrow ; j++) - { - Anw [j] = 1 ; - } - for (j = 0 ; j < enz ; j++) - { - Aew [j] = 1 ; - } - lr = CHOLMOD(metis_bisector)(E, Anw, Aew, Pok, cm) ; - if (E->stype || E->nrow != E->ncol) - { - NOT (lr >= 0) ; - } - else - { - OK (lr >= 0) ; - } - lr = CHOLMOD(metis_bisector)(Abad2, Anw, Aew, Pok, cm) ;NOT (lr >= 0); - lr = CHOLMOD(metis_bisector)(NULL, Anw, Aew, Pok, cm) ; NOT (lr >= 0); - lr = CHOLMOD(metis_bisector)(A, Anw, Aew, NULL, cm) ; NOT (lr >= 0); - - if (A->stype) - { - lr = CHOLMOD(metis_bisector)(A, Anw, Aew, Pok, cm) ; NOT (lr>=0) ; - } - - CHOLMOD(free)(nrow, sizeof (Int), Anw, cm) ; - CHOLMOD(free)(MAX (anz,enz), sizeof (Int), Aew, cm) ; - } - - CHOLMOD(free_sparse)(&E, cm) ; - - CHOLMOD(print_sparse)(Abad, "Abad", cm) ; - lr = CHOLMOD(bisect)(Abad, NULL, 0, TRUE, Partition, cm) ; - if (Abad != NULL && Abad->nrow == 0) - { - OK (lr == 0) ; - } - else - { - NOT (lr >= 0) ; - } - - lr = CHOLMOD(bisect)(A, NULL, 0, TRUE, NULL, cm) ; NOT (lr >= 0); - lr = CHOLMOD(bisect)(NULL, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0); - - lr = CHOLMOD(nested_dissection)(NULL, NULL, 0, Pok, CParent, - Cmember, cm) ; NOT (lr>=0) ; - - lr = CHOLMOD(nested_dissection)(A, NULL, 0, NULL, CParent, - Cmember, cm) ; NOT (lr>=0) ; - - lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, NULL, - Cmember, cm) ; NOT (lr>=0) ; - - lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, CParent, - NULL, cm) ; NOT (lr>=0) ; - - ok = CHOLMOD(metis)(NULL, NULL, 0, TRUE, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(metis)(A, NULL, 0, TRUE, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(metis)(Abad2, NULL, 0, FALSE, Pok, cm) ; NOT (ok) ; - lr = CHOLMOD(bisect)(Abad2, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0); -#endif - - /* ---------------------------------------------------------------------- */ - /* etree */ - /* ---------------------------------------------------------------------- */ - - if (A->stype < 0) - { - ok = CHOLMOD(etree)(A, Parent, cm) ; NOT (ok) ; - } - ok = CHOLMOD(etree)(Abad2, Parent, cm) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* etree, postorder, rowcolcount */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0 && ncol > 0) - { - AFT = CHOLMOD(ptranspose)(A, 1, NULL, fsetok, fsizeok, cm) ; OKP(AFT); - AF = CHOLMOD(transpose)(AFT, 1, cm) ; OKP(AF); - - ok = CHOLMOD(etree)(NULL, Parent, cm) ; NOT(ok); - ok = CHOLMOD(etree)(AFT, NULL, cm) ; NOT(ok); - ok = CHOLMOD(etree)(AFT, Parent, cm) ; OK (ok); - - lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cm) ; OK (lr>=0) ; - lr = CHOLMOD(postorder)(NULL, nrow, NULL, Post, cm) ; NOT (lr>=0) ; - lr = CHOLMOD(postorder)(Parent, nrow, NULL, NULL, cm) ; NOT (lr>=0) ; - - - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - Post, NULL, ColCount, First, Level, cm) ; OK (ok); - - ok = CHOLMOD(rowcolcounts)(Abad2, fsetok, fsizeok, Parent, - Post, NULL, ColCount, First, Level, cm) ; NOT(ok); - - ok = CHOLMOD(rowcolcounts)(NULL, fsetok, fsizeok, Parent, - Post, NULL, ColCount, First, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, NULL, - Post, NULL, ColCount, First, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - NULL, NULL, ColCount, First, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - Post, NULL, NULL, First, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - Post, NULL, ColCount, NULL, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - Post, NULL, ColCount, First, NULL, cm) ; NOT(ok); - - ok = CHOLMOD(rowcolcounts)(A, fsetbad, ncol, Parent, - Post, NULL, ColCount, First, Level, cm) ; NOT(ok); - ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, - Post, NULL, ColCount, First, NULL, cm) ; NOT(ok); - - CHOLMOD(free_sparse)(&AF, cm) ; - CHOLMOD(free_sparse)(&AFT, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* norm */ - /* ---------------------------------------------------------------------- */ - - nm = CHOLMOD(norm_sparse)(A, 2, cm) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_sparse)(Abad, 0, cm) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_sparse)(Abad2, 2, cm) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_dense)(Bok, 3, cm) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_dense)(Bok, 2, cm) ; NOT (nm>=0) ; - nm = CHOLMOD(norm_dense)(Xbad2, 1, cm) ; NOT (nm>=0) ; - - /* ---------------------------------------------------------------------- */ - /* copy dense */ - /* ---------------------------------------------------------------------- */ - - ok = CHOLMOD(copy_dense2)(NULL, Bok, cm) ; NOT (ok) ; - ok = CHOLMOD(copy_dense2)(Bok, NULL, cm) ; NOT (ok) ; - - ok = CHOLMOD(copy_dense2)(Bok, Xbad2, cm) ; NOT (ok) ; - ok = CHOLMOD(copy_dense2)(Xbad2, Xbad2, cm) ; NOT (ok) ; - - if (nrow > 1) - { - - /* wrong dimensions */ - ok = CHOLMOD(copy_dense2)(Two, Bok, cm) ; NOT (ok) ; - - /* mangled matrix */ - Y = CHOLMOD(copy_dense)(Bok, cm) ; OKP (Y) ; - Y->d = 0 ; - ok = CHOLMOD(copy_dense2)(Bok, Y, cm) ; NOT (ok) ; - CHOLMOD(free_dense)(&Y, cm) ; - - Y = CHOLMOD(copy_dense)(Xbad2, cm) ; NOP (Y) ; - Y = CHOLMOD(copy_dense)(NULL, cm) ; NOP (Y) ; - } - - /* ---------------------------------------------------------------------- */ - /* complex */ - /* ---------------------------------------------------------------------- */ - - W = CHOLMOD(eye)(4, 4, CHOLMOD_COMPLEX, cm) ; OKP (W) ; - ok = CHOLMOD(dense_xtype)(0, W, cm) ; NOT (ok) ; - ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL, W, cm) ; OK (ok) ; - ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL, NULL, cm) ; NOT (ok) ; - k = W->xtype ; - W->xtype = -1 ; - ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL, W, cm) ; NOT (ok) ; - W->xtype = k ; - ok = CHOLMOD(free_dense)(&W, cm) ; OK (ok) ; - - C = CHOLMOD(speye)(4, 4, CHOLMOD_COMPLEX, cm) ; OKP (C) ; - ok = CHOLMOD(sparse_xtype)(-1, C, cm) ; OK (ok) ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX, C, cm) ; OK (ok) ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX, NULL, cm) ; NOT (ok) ; - T = CHOLMOD(sparse_to_triplet)(C, cm) ; OKP (T) ; - ok = CHOLMOD(triplet_xtype)(-1, T, cm) ; OK (ok) ; - ok = CHOLMOD(triplet_xtype)(CHOLMOD_ZOMPLEX, T, cm) ; OK (ok) ; - ok = CHOLMOD(triplet_xtype)(CHOLMOD_ZOMPLEX, NULL, cm) ; NOT (ok) ; - - k = T->xtype ; - T->xtype = -1 ; - ok = CHOLMOD(triplet_xtype)(CHOLMOD_REAL, T, cm) ; NOT (ok) ; - T->xtype = k ; - - k = C->xtype ; - C->xtype = -1 ; - ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL, C, cm) ; NOT (ok) ; - C->xtype = k ; - - ok = CHOLMOD(free_triplet)(&T, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL, Lbad, cm) ; NOT (ok) ; - - /* ---------------------------------------------------------------------- */ - /* rowadd */ - /* ---------------------------------------------------------------------- */ - - x = X->x ; - X->x = NULL ; - C = CHOLMOD(dense_to_sparse)(X, TRUE, cm) ; NOP (C) ; - - if (nrow > 3 && isreal) - { - ok = CHOLMOD(rowadd)(1, I1, L, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(nrow+1, R, L, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(nrow+1, R, L, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel)(nrow+1, NULL, L5, cm) ; NOT (ok) ; - - ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; - ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; - ok = CHOLMOD(rowdel)(nrow-2, Abad2, L5, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel)(nrow-1, R, L5, cm) ; NOT (ok) ; - - ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, FALSE, TRUE, TRUE, L5, - cm) ; - OK (ok) ; - - ok = CHOLMOD(rowadd)(nrow-2, NULL, L5, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(nrow-2, R, NULL, cm) ; NOT (ok) ; - - ok = CHOLMOD(rowadd)(nrow-2, R, L5, cm) ; OK (ok) ; - - ok = CHOLMOD(rowadd)(nrow-2, Abad2, L5, cm) ; NOT (ok) ; - -/* ok = CHOLMOD(rowadd)(nrow-2, R, L5, cm) ; NOT (ok) ; */ - ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; - ok = CHOLMOD(change_factor)(CHOLMOD_PATTERN, TRUE, - TRUE, TRUE, TRUE, L5, cm) ; NOT (ok) ; - ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, - TRUE, TRUE, TRUE, L5, cm) ; NOT (ok) ; - - ok = CHOLMOD(rowadd_solve)(nrow-2, R, beta, L5, X, X, cm) ; NOT (ok) ; - ok = CHOLMOD(rowdel_solve)(nrow-2, R, beta, L5, X, X, cm) ; NOT (ok) ; - ok = CHOLMOD(updown_solve)(TRUE, R, L5, X, X, cm) ; NOT (ok) ; - - if (nrow < 200 && L5 != NULL && R2 != NULL) - { - cholmod_factor *L8 ; - Int *L8p, *L8i, *L8nz, rnz ; - double *L8x ; - L8 = CHOLMOD(copy_factor) (L5, cm) ; - ok = TRUE ; - for (k = nrow-1 ; ok && L8 != NULL - && L8->xtype == CHOLMOD_REAL && k >= 0 ; k--) - { - for (rnz = 0 ; rnz < nrow ; rnz++) - { - /* first, ensure row i is zero */ - for (j = 0 ; j < nrow ; j++) - { - L8p = L8->p ; - L8i = L8->i ; - L8nz = L8->nz ; - L8x = L8->x ; - for (p = L8p [j] ; p < L8p [j] + L8nz [j] ; p++) - { - i = L8i [p] ; - if (i == k) L8x [p] = 0 ; - } - } - R2p [1] = rnz ; - ok = CHOLMOD(rowadd)(k, R2, L8, cm) ; OK (ok) ; - ok = CHOLMOD(rowdel)(k, NULL, L8, cm) ; OK (ok) ; - ok = CHOLMOD(rowadd)(k, R2, L8, cm) ; OK (ok) ; - } - } - CHOLMOD(free_factor) (&L8, cm) ; - } - } - - X->x = x ; - ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* ssmult */ - /* ---------------------------------------------------------------------- */ - - if (nrow < 100) - { - C = CHOLMOD(ssmult)(A, A, 0, TRUE, TRUE, cm) ; - if (A->nrow != A->ncol || !isreal) - { - NOP (C) ; - } - else - { - OKP (C) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - C = CHOLMOD(ssmult)(NULL, A, 0, TRUE, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(ssmult)(A, NULL, 0, TRUE, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(ssmult)(A, Axbad, 0, TRUE, TRUE, cm) ; NOP (C) ; - } - - /* ---------------------------------------------------------------------- */ - /* sdmult */ - /* ---------------------------------------------------------------------- */ - - if (nrow > 1) - { - ok = CHOLMOD(sdmult)(A, FALSE, one, one, Two, Two, cm) ; NOT (ok) ; - } - - YY = CHOLMOD(ones)(A->nrow, 1, xtype, cm) ; OKP (YY) ; - XX = CHOLMOD(ones)(A->ncol, 1, xtype, cm) ; OKP (XX) ; - cm->print = 4 ; - ok = CHOLMOD(print_dense)(XX, "XX", cm) ; OK (ok) ; - cm->print = 1 ; - ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; OK (ok) ; - ok = CHOLMOD(sdmult)(NULL, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; - ok = CHOLMOD(sdmult)(A, FALSE, one, one, NULL, YY, cm) ; NOT (ok) ; - ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, NULL, cm) ; NOT (ok) ; - - ok = CHOLMOD(sdmult)(Abad2, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; - - XX->xtype++ ; - ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; - XX->xtype-- ; - - YY->xtype++ ; - ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; - YY->xtype-- ; - - CHOLMOD(free_dense)(&YY, cm) ; - CHOLMOD(free_dense)(&XX, cm) ; - - /* ---------------------------------------------------------------------- */ - /* symmetry */ - /* ---------------------------------------------------------------------- */ - - for (option = 0 ; option <= 2 ; option++) - { - Int xmatched = 0, pmatched = 0, nzoffdiag = 0, nz_diag = 0 ; - int asym ; - printf ("test symmetry: option %d\n", option) ; - save1 = cm->print ; - cm->print = 5 ; - CHOLMOD(print_sparse) (A, "A", cm) ; - cm->print = save1 ; - asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - printf ("asym: %d\n", asym) ; - OK (A->stype != 0 || asym >= 0) ; - save1 = A->xtype ; - A->xtype = CHOLMOD_PATTERN ; - asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - printf ("asym: %d pattern\n", asym) ; - OK (A->stype != 0 || asym >= 0) ; - A->xtype = save1 ; - C = CHOLMOD(copy_sparse) (A, cm) ; - OKP (C) ; - ok = CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX, C, cm) ; - OK (ok) ; - asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - OK (A->stype != 0 || asym >= 0) ; - printf ("asym: %d zomplex\n", asym) ; - - asym = CHOLMOD(symmetry) (NULL, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - NOT (asym >= 0) ; - - C->xtype = 999 ; - asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - NOT (asym >= 0) ; - C->xtype = CHOLMOD_ZOMPLEX ; - - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - - C = CHOLMOD(copy) (A, 0, (A->xtype == CHOLMOD_REAL), cm) ; - OKP (C) ; - asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, - &nzoffdiag, &nz_diag, cm) ; - OK (asym >= 0) ; - ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* memory tests */ - /* ---------------------------------------------------------------------- */ - - R3 = CHOLMOD(speye)(nrow, 1, CHOLMOD_PATTERN, cm) ; /* [ */ - OKP (R3) ; - - test_memory_handler ( ) ; - - ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; - if (A->nrow == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - -#ifndef NCAMD - ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; - if (A->nrow == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } -#endif - - C = CHOLMOD(aat)(A, NULL, 0, 0, cm) ; NOP (C) ; - A->sorted = FALSE ; - ok = CHOLMOD(check_sparse)(A, cm) ; NOT (ok) ; - A->sorted = TRUE ; - - CHOLMOD(free_work)(cm) ; - if (A->stype == 0) - { - for (trial = 0 ; !ok && trial < 20 ; trial++) - { - my_tries = trial ; - printf ("--------------------- trial %"PRId64"\n", my_tries) ; - ok = CHOLMOD(colamd)(A, NULL, 0, TRUE, Pok, cm) ; - } - OK (ok) ; - } - - -#ifndef NCAMD - test_memory_handler ( ) ; - ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; - ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; - for (trial = 0 ; trial < 7 ; trial++) - { - test_memory_handler ( ) ; - my_tries = trial ; - ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; - } - - if (A->nrow == A->ncol && A->packed) - { - test_memory_handler ( ) ; - my_tries = 8 ; - ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; OK (ok) ; - test_memory_handler ( ) ; - ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; - OK (cm->status == CHOLMOD_OUT_OF_MEMORY) ; - } - - for (trial = 0 ; trial < 5 ; trial++) - { - test_memory_handler ( ) ; - my_tries = trial ; - ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; - if (A->nrow == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - } -#endif - - test_memory_handler ( ) ; - - ok = CHOLMOD(etree)(A, Parent, cm) ; NOT (ok) ; - ok = CHOLMOD(factorize)(A, L, cm) ; NOT (ok) ; - - pp = CHOLMOD(malloc)(4, 0, cm) ; NOP (pp) ; - pp = CHOLMOD(calloc)(4, 0, cm) ; NOP (pp) ; - pp = CHOLMOD(calloc)(SIZE_MAX, 1, cm) ; NOP (pp) ; - pp = NULL ; - size = 0 ; - pp = CHOLMOD(realloc)(4, 0, pp, &size, cm) ; NOP (pp) ; - pp = CHOLMOD(realloc)(SIZE_MAX, 1, pp, &size, cm) ; NOP (pp) ; - - normal_memory_handler ( ) ; - OK (CHOLMOD(print_sparse)(A, "A ok", cm)) ; - OK (CHOLMOD(print_factor)(L, "L ok", cm)) ; - - /* test no_workspace_reallocate flag */ - CHOLMOD (free_work) (cm) ; - CHOLMOD (allocate_work) (1, 1, 1, cm) ; - OK (cm->status == CHOLMOD_OK) ; - cm->no_workspace_reallocate = TRUE ; - ok = CHOLMOD (allocate_work) (2, 1, 1, cm) ; - NOT (ok) ; - ok = CHOLMOD (allocate_work) (1, 2, 1, cm) ; - NOT (ok) ; - ok = CHOLMOD (allocate_work) (1, 1, 8, cm) ; - NOT (ok) ; - cm->no_workspace_reallocate = FALSE ; - ok = CHOLMOD (allocate_work) (1, 1, 2, cm) ; - OK (ok) ; - - cm->print = 4 ; - ok = CHOLMOD(print_factor)(L, "L for copy", cm) ; - OK (ok) ; - ok = FALSE ; - test_memory_handler ( ) ; - for (trial = 0 ; !ok && trial < 100 ; trial++) - { - my_tries = trial ; - Lcopy = CHOLMOD(copy_factor)(L, cm) ; - ok = (Lcopy != NULL) ; - } - normal_memory_handler ( ) ; - ok = CHOLMOD(print_factor)(Lcopy, "Lcopy", cm) ; - OK (ok) ; - CHOLMOD(free_factor)(&Lcopy, cm) ; - cm->print = 1 ; - - test_memory_handler ( ) ; - ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - ok = CHOLMOD(resymbol_noperm)(A, NULL, 0, TRUE, L, cm) ; NOT (ok) ; - - lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cm) ; NOT (lr>=0) ; - - T = CHOLMOD(copy_triplet)(Tok, cm) ; NOT (ok) ; - -#ifndef NPARTITION - lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, CParent, - Cmember, cm) ; - if (nrow == 0) - { - OK (lr >= 0) ; - } - else - { - NOT (lr >= 0) ; - } - - lr = CHOLMOD(nested_dissection)(Abad2, NULL, 0, Pok, CParent, - Cmember, cm) ; - NOT (lr >= 0) ; - - ok = CHOLMOD(metis)(A, NULL, 0, TRUE, Pok, cm) ; - - if (nrow == 0) - { - OK (ok) ; - } - else - { - NOT (ok) ; - } - lr = CHOLMOD(bisect)(A, NULL, 0, TRUE, Partition, cm) ; - - if (nrow == 0) - { - OK (lr == 0) ; - } - else - { - NOT (lr >= 0) ; - } - - lr = CHOLMOD(bisect)(Abad2, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0) ; - -#endif - - if (nrow > 3) - { - ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; NOT (ok) ; - ok = CHOLMOD(rowadd)(nrow-2, R, L5, cm) ; NOT (ok) ; - ok = CHOLMOD(updown)(+1, A, L, cm) ; NOT (ok) ; - } - - C = CHOLMOD(add)(A, A, one, one, TRUE, TRUE, cm) ; NOP (C) ; - C = CHOLMOD(ssmult)(A, A, 0, TRUE, TRUE, cm) ; NOP (C) ; - - ok = CHOLMOD(rowcolcounts)(A, NULL, 0, Parent, Post, - NULL, ColCount, First, Level, cm) ; NOT (ok) ; - - ok = CHOLMOD(rowfac)(A, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_unsym)(A, 1, Pok, NULL, 0, R, cm) ; NOT (ok) ; - ok = CHOLMOD(transpose_sym)(A, 1, Pok, R, cm) ; NOT (ok) ; -// if (nrow > 1) -// { -// ok = CHOLMOD(sort)(A, cm) ; -// NOT (ok) ; -// } - - ok = CHOLMOD(row_subtree)(A, AT, 0, Parent, R3, cm) ; NOT (ok) ; - ATi = (AT == NULL) ? NULL : AT->i ; - ok = CHOLMOD(row_lsubtree)(A, ATi, 0, 0, L, R3, cm) ; NOT (ok) ; - - normal_memory_handler ( ) ; - - /* ---------------------------------------------------------------------- */ - /* free the valid objects */ - /* ---------------------------------------------------------------------- */ - - cm->status = CHOLMOD_OK ; - - CHOLMOD(free_triplet)(NULL, cm) ; - - CHOLMOD(free_sparse)(&R3, cm) ; /* ] */ - CHOLMOD(free_sparse)(&R, cm) ; /* ] */ - CHOLMOD(free_sparse)(&Acopy, cm) ; /* ] */ - CHOLMOD(free_factor)(&L5, cm) ; /* ] */ - CHOLMOD(free_factor)(&L2, cm) ; /* ] */ - - Lbad->xtype = Lxtype ; - CHOLMOD(free_factor)(&Lbad, cm) ; /* ] */ - - CHOLMOD(free_factor)(&L, cm) ; /* ] */ - - CHOLMOD(free_triplet)(&T, cm) ; - - Axbad->xtype = Axbad_type ; - CHOLMOD(free_sparse)(&Axbad, cm) ; /* ] */ - - cm->error_handler = my_handler ; - - Xbad2->xtype = CHOLMOD_REAL ; - CHOLMOD(free_dense)(&Xbad2, cm) ; /* ] */ - - Abad2->xtype = Abad2xtype ; - CHOLMOD(free_sparse)(&Abad2, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&Abad, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&R0, cm) ; - CHOLMOD(free_sparse)(&R1, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&Aboth, cm) ; /* ] */ - CHOLMOD(free_sparse)(&Sok, cm) ; - - - CHOLMOD(free)(nrow, sizeof (Int), Pinv, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), Parent, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), Post, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), Cmember, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), CParent, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), Partition, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), ColCount, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), First, cm) ; - CHOLMOD(free)(nrow, sizeof (Int), Level, cm) ; /* ] */ - - CHOLMOD(free_dense)(&Two, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&R2, cm) ; /* ] */ - CHOLMOD(free)(nrow, sizeof (Int), Pok, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&I1, cm) ; /* ] */ - - CHOLMOD(free)(nrow, sizeof (Int), Pbad, cm) ; /* ] */ - - CHOLMOD(free)(ncol, sizeof (Int), fsetbad, cm) ; /* ] */ - CHOLMOD(free)(ncol, sizeof (Int), fsetok, cm) ; /* ] */ - - CHOLMOD(free_dense)(&Bok, cm) ; /* ] */ - - CHOLMOD(free_dense)(&Xok, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&AT, cm) ; /* ] */ - - CHOLMOD(free_sparse)(&A, cm) ; /* ] */ - - OK (cm->status == CHOLMOD_OK) ; - printf ("\n------------------------null2 tests: All OK\n") ; -} diff --git a/CHOLMOD/Tcov/raw_factor.c b/CHOLMOD/Tcov/raw_factor.c deleted file mode 100644 index 6bc5aac2ec..0000000000 --- a/CHOLMOD/Tcov/raw_factor.c +++ /dev/null @@ -1,886 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/raw_factor: test CHOLMOD factorization and solvers -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Factorize A using cholmod_rowfac for the simplicial case, and the - * cholmod_super_* routines for the supernodal case, and test the solution to - * linear systems. */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === icomp ================================================================ */ -/* ========================================================================== */ - -/* for sorting by qsort */ -static int icomp (Int *i, Int *j) -{ - if (*i < *j) - { - return (-1) ; - } - else - { - return (1) ; - } -} - - -/* ========================================================================== */ -/* === add_gunk ============================================================= */ -/* ========================================================================== */ - -static cholmod_sparse *add_gunk (cholmod_sparse *A) -{ - cholmod_sparse *S ; - double *Sx, *Sz ; - Int *Sp, *Si, nz, p, save3, j, n ; - - if (A == NULL) return (NULL) ; - - /* save3 = cm->print ; cm->print = 5 ; */ - - A->nzmax++ ; - S = CHOLMOD(copy_sparse) (A, cm) ; - A->nzmax-- ; - - /* add a S(n,1)=1 entry to the matrix */ - if (S != NULL) - { - S->sorted = FALSE ; - Sx = S->x ; - Si = S->i ; - Sp = S->p ; - Sz = S->z ; - n = S->ncol ; - nz = Sp [n] ; - for (j = 1 ; j <= n ; j++) - { - Sp [j]++ ; - } - if (S->xtype == CHOLMOD_REAL) - { - for (p = nz-1 ; p >= 0 ; p--) - { - Si [p+1] = Si [p] ; - Sx [p+1] = Sx [p] ; - } - Si [0] = n-1 ; - Sx [0] = 99999 ; - } - else if (S->xtype == CHOLMOD_COMPLEX) - { - for (p = nz-1 ; p >= 0 ; p--) - { - Si [p+1] = Si [p] ; - Sx [2*p+2] = Sx [2*p] ; - Sx [2*p+3] = Sx [2*p+1] ; - } - Si [0] = n-1 ; - Sx [0] = 99999 ; - Sx [1] = 0 ; - } - else if (S->xtype == CHOLMOD_ZOMPLEX) - { - for (p = nz-1 ; p >= 0 ; p--) - { - Si [p+1] = Si [p] ; - Sx [p+1] = Sx [p] ; - Sz [p+1] = Sz [p] ; - } - Si [0] = n-1 ; - Sx [0] = 99999 ; - Sz [0] = 0 ; - } - } - - /* CHOLMOD(print_sparse) (A, "A for gunk", cm) ; */ - /* CHOLMOD(print_sparse) (S, "S with gunk", cm) ; */ - /* cm->print = save3 ; */ - - return (S) ; -} - - -/* ========================================================================== */ -/* === raw_factor =========================================================== */ -/* ========================================================================== */ - -/* Factor A, without using any fill-reducing permutation. This may fail due - * to catastrophic fill-in (which is the desired test result for a large - * arrowhead matrix). - */ - -double raw_factor (cholmod_sparse *A, Int check_errors) -{ - double maxerr = 0, r, anorm ; - cholmod_sparse *AT, *C, *LT, *Lsparse, *S, *ST, *R, *A1 ; - cholmod_factor *L, *Lcopy ; - cholmod_dense *X, *W, *B, *X2 ; - Int i, k, n, ok, ok1, ok2, trial, rnz, lnz, Lxtype, Axtype, posdef, - prefer_zomplex, Bxtype ; - Int *Parent, *Post, *First, *Level, *Ri, *Rp, *LTp = NULL, *LTi = NULL, *P, - *mask, *RLinkUp ; - int64_t lr ; - double beta [2] ; - uint64_t save ; - - /* ---------------------------------------------------------------------- */ - /* create the problem */ - /* ---------------------------------------------------------------------- */ - - if (A == NULL || A->stype != 1) - { - return (0) ; - } - - W = NULL ; - X2 = NULL ; - L = NULL ; - n = A->nrow ; - B = rhs (A, 1, n) ; - AT = CHOLMOD(transpose) (A, 2, cm) ; - Parent = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Post = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - First = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Level = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - beta [0] = 0 ; - beta [1] = 0 ; - anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; - - prefer_zomplex = (A->xtype == CHOLMOD_ZOMPLEX) ; - Bxtype = A->xtype ; - - /* ---------------------------------------------------------------------- */ - /* supernodal factorization */ - /* ---------------------------------------------------------------------- */ - - L = CHOLMOD(allocate_factor) (n, cm) ; - ok1 = CHOLMOD(etree) (A, Parent, cm) ; - lr = CHOLMOD(postorder) (Parent, n, NULL, Post, cm) ; - ok2 = CHOLMOD(rowcolcounts) (AT, NULL, 0, Parent, Post, - NULL, (L != NULL) ? (L->ColCount) : NULL, First, Level, cm) ; - - if (ok2) - { - printf ("raw_factor: cm->fl %g cm->lnz %g\n", cm->fl, cm->lnz) ; - } - - if (check_errors) - { - OKP (AT) ; - OKP (Parent) ; - OKP (Post) ; - OKP (First) ; - OKP (Level) ; - OK (AT->stype == -1) ; - OKP (L) ; - OK (ok1) ; - OK (ok2) ; - OK (lr >= 0) ; - - /* rowcolcounts requires A in symmetric lower form */ - ok = CHOLMOD(rowcolcounts) (A, NULL, 0, Parent, Post, - NULL, L->ColCount, First, Level, cm) ; NOT (ok) ; - } - - /* super_symbolic needs A in upper form, so this will succeed - * unless the problem is huge */ - ok = CHOLMOD(super_symbolic) (A, NULL, Parent, L, cm) ; - - /* super_symbolic should fail if lnz is too large */ - if (cm->lnz > SIZE_MAX / 2) - { - printf ("raw_factor: problem is huge\n") ; - NOT (ok) ; - OK (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ; - - /* try changing to LDL packed, which should also fail */ - ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, - L, cm) ; - NOT (ok) ; - - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free) (n, sizeof (Int), First, cm) ; - CHOLMOD(free) (n, sizeof (Int), Level, cm) ; - CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; - CHOLMOD(free) (n, sizeof (Int), Post, cm) ; - return (0) ; - } - - if (check_errors) - { - - if (cm->status == CHOLMOD_OUT_OF_MEMORY - || cm->status == CHOLMOD_TOO_LARGE) - { - /* no test case will reach here, but check just to be safe */ - printf ("raw_factor: out of memory for symbolic case %d\n", - cm->status) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free) (n, sizeof (Int), First, cm) ; - CHOLMOD(free) (n, sizeof (Int), Level, cm) ; - CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; - CHOLMOD(free) (n, sizeof (Int), Post, cm) ; - return (0) ; - } - - OK (ok) ; - ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_symbolic)(AT, NULL, Parent, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_symbolic)(NULL, NULL, Parent, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_symbolic)(A, NULL, NULL, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_symbolic)(A, NULL, Parent, NULL, cm) ; NOT (ok) ; - } - - /* super_numeric needs A in lower form, so this will succeed unless - * the problem is huge */ - ok = CHOLMOD(super_numeric) (AT, NULL, Zero, L, cm) ; - - if (check_errors) - { - - if (cm->status == CHOLMOD_OUT_OF_MEMORY) - { - /* For the 64-bit case, the Matrix/a1 problem will reach here */ - printf ("raw_factor: out of memory for numeric case\n") ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free) (n, sizeof (Int), First, cm) ; - CHOLMOD(free) (n, sizeof (Int), Level, cm) ; - CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; - CHOLMOD(free) (n, sizeof (Int), Post, cm) ; - return (0) ; - } - - OK (ok) ; - ok = CHOLMOD(super_numeric)(A, NULL, Zero, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(NULL, NULL, Zero, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric)(AT, NULL, Zero, NULL, cm) ; NOT (ok) ; - } - - /* solve */ - Lxtype = (L == NULL) ? CHOLMOD_REAL : L->xtype ; - W = CHOLMOD(zeros) (n, 1, Lxtype, cm) ; - X = CHOLMOD(copy_dense) (B, cm) ; - if (Bxtype == CHOLMOD_ZOMPLEX) - { - CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX, X, cm) ; - } - - CHOLMOD(print_factor) (L, "L for super l/ltsolve", cm) ; - CHOLMOD(print_dense) (W, "W", cm) ; - CHOLMOD(print_dense) (X, "X", cm) ; - - ok1 = CHOLMOD(super_lsolve) (L, X, W, cm) ; - CHOLMOD(print_dense) (X, "X", cm) ; - - ok2 = CHOLMOD(super_ltsolve) (L, X, W, cm) ; - CHOLMOD(print_dense) (X, "X", cm) ; - - if (Bxtype == CHOLMOD_ZOMPLEX) - { - CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX, X, cm) ; - } - - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - - if (Bxtype == CHOLMOD_ZOMPLEX) - { - CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX, X, cm) ; - } - - if (check_errors) - { - OKP (W) ; - OKP (X) ; - OK (ok1) ; - OK (ok2) ; - ok = CHOLMOD(super_lsolve) (NULL, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve) (NULL, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_lsolve) (L, NULL, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve) (L, NULL, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_lsolve) (L, X, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve) (L, X, NULL, cm) ; NOT (ok) ; - - if (L != NULL && L->maxesize > 1) - { - /* W is too small */ - ok = CHOLMOD(free_dense) (&W, cm) ; OK (ok) ; - W = CHOLMOD(zeros) (1, 1, Lxtype, cm) ; OKP (W) ; - ok = CHOLMOD(super_lsolve) (L, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve) (L, X, W, cm) ; NOT (ok) ; - ok = CHOLMOD(free_dense) (&W, cm) ; OK (ok) ; - W = CHOLMOD(zeros) (n, 1, Lxtype, cm) ; OKP (W) ; - } - - /* X2 has the wrong dimensions */ - X2 = CHOLMOD(zeros) (n+1, 1, Lxtype, cm) ; OKP (X2) ; - ok = CHOLMOD(super_lsolve) (L, X2, W, cm) ; NOT (ok) ; - ok = CHOLMOD(super_ltsolve) (L, X2, W, cm) ; NOT (ok) ; - CHOLMOD(free_dense) (&X2, cm) ; - } - - CHOLMOD(free_dense) (&X, cm) ; - - /* X2 is n-by-0, which is OK */ - X2 = CHOLMOD(zeros) (n, 0, Lxtype, cm) ; - ok1 = CHOLMOD(super_lsolve) (L, X2, W, cm) ; - ok2 = CHOLMOD(super_ltsolve) (L, X2, W, cm) ; - CHOLMOD(free_dense) (&W, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - - if (check_errors) - { - OK (ok1) ; - OK (ok2) ; - test_memory_handler ( ) ; - my_tries = 0 ; - ok = CHOLMOD(super_symbolic) (A, NULL, Parent, L, cm) ; NOT (ok) ; - ok = CHOLMOD(super_numeric) (AT, NULL, Zero, L, cm) ; NOT (ok) ; - normal_memory_handler ( ) ; - cm->error_handler = NULL ; - } - - /* R = space for result of row_subtree and row_lsubtree */ - R = CHOLMOD(allocate_sparse)(n, 1, n, FALSE, TRUE, 0, CHOLMOD_PATTERN, cm) ; - - /* ---------------------------------------------------------------------- */ - /* erroneous factorization */ - /* ---------------------------------------------------------------------- */ - - /* cannot use rowfac or row_lsubtree on a supernodal factorization */ - if (check_errors && n > 0) - { - ok = CHOLMOD(rowfac) (A, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; - ok = CHOLMOD(row_lsubtree) (A, &i, 0, n-1, L, R, cm) ; NOT (ok) ; - } - - /* ---------------------------------------------------------------------- */ - /* convert to simplicial LDL' */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(change_factor) (Lxtype, FALSE, FALSE, TRUE, TRUE, L, cm) ; - - /* remove entries due to relaxed supernodal amalgamation */ - CHOLMOD(resymbol) (A, NULL, 0, TRUE, L, cm) ; - - /* refactorize a numeric factor */ - posdef = 0 ; /* unknown */ - if (A != NULL && A->stype >= 0) - { - if (A->stype > 0 && A->packed) - { - S = add_gunk (A) ; - CHOLMOD(rowfac) (S, NULL, beta, 0, n, L, cm) ; - if (S && S->xtype == CHOLMOD_COMPLEX) - { - CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX, S, cm) ; - } - ok = CHOLMOD(free_sparse) (&S, cm) ; OK (ok) ; - } - else - { - CHOLMOD(rowfac) (A, NULL, beta, 0, n, L, cm) ; - } - posdef = (cm->status == CHOLMOD_OK) ; - } - - /* convert to a sparse matrix, and transpose L */ - Lcopy = CHOLMOD(copy_factor)(L, cm) ; - Lsparse = CHOLMOD(factor_to_sparse) (L, cm) ; - - LT = CHOLMOD(transpose) (Lsparse, 0, cm) ; - CHOLMOD(free_sparse) (&Lsparse, cm) ; - - if (LT != NULL) - { - LTp = LT->p ; - LTi = LT->i ; - OK (LT->packed) ; - } - - /* remove the unit diagonal of LT */ - CHOLMOD(band_inplace) (1, n, -1, LT, cm) ; - - /* ST = pattern of A(p,p)' */ - P = (L == NULL) ? NULL : L->Perm ; - ST = CHOLMOD(ptranspose) (A, 0, P, NULL, 0, cm) ; - - /* S = pattern of A(p,p) */ - S = CHOLMOD(transpose) (ST, 0, cm) ; - ok = CHOLMOD(free_sparse) (&ST, cm) ; - - if (R != NULL && LT != NULL && posdef && A != NULL && A->stype >= 0 - && S != NULL && Lcopy != NULL) - { - LTp = LT->p ; - LTi = LT->i ; - - Ri = R->i ; - Rp = R->p ; - - save = my_seed ( ) ; /* RAND */ - for (trial = 0 ; trial < 30 ; trial++) - { - /* pick a row at random */ - i = nrand (n) ; /* RAND */ - - /* compute R = pattern of L(i,0:i-1), using row subtrees */ - ok = CHOLMOD(row_subtree) (S, NULL, i, Parent, R, cm) ; - if (!ok) - { - break ; - } - rnz = Rp [1] ; - - /* sort R */ - qsort (Ri, rnz, sizeof (Int), - (int (*) (const void *, const void *)) icomp) ; - - /* compare with ith column of L transpose */ - lnz = LTp [i+1] - LTp [i] ; - ok = TRUE ; - for (k = 0 ; k < MIN (rnz,lnz) ; k++) - { - /* printf ("%d vs %d\n", Ri [k], LTi [LTp [i] + k]) ; */ - ok = ok && (Ri [k] == LTi [LTp [i] + k]) ; - } - OK (ok) ; - OK (rnz == lnz) ; - - /* compute R = pattern of L(i,0:i-1), using row lsubtrees */ - ok = CHOLMOD(row_lsubtree) (S, NULL, 0, i, Lcopy, R, cm) ; - if (!ok) - { - break ; - } - rnz = Rp [1] ; - - /* sort R */ - qsort (Ri, rnz, sizeof (Int), - (int (*) (const void *, const void *)) icomp) ; - - /* compare with ith column of L transpose */ - lnz = LTp [i+1] - LTp [i] ; - ok = TRUE ; - for (k = 0 ; k < MIN (rnz,lnz) ; k++) - { - /* printf ("%d vs %d\n", Ri [k], LTi [LTp [i] + k]) ; */ - ok = ok && (Ri [k] == LTi [LTp [i] + k]) ; - } - OK (ok) ; - OK (rnz == lnz) ; - - /* L is symbolic, so cholmod_lsubtree will fail */ - if (check_errors) - { - ok = CHOLMOD(row_lsubtree) (S, NULL, 0, i, L, R, cm) ; - NOT (ok) ; - } - - } - my_srand (save) ; /* RAND */ - } - - ok = CHOLMOD(free_factor) (&L, cm) ; OK (ok) ; - ok = CHOLMOD(free_factor) (&Lcopy, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse) (<, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse) (&R, cm) ; OK (ok) ; - ok = CHOLMOD(free_sparse) (&S, cm) ; OK (ok) ; - - /* ---------------------------------------------------------------------- */ - /* simplicial LDL' or LL' factorization with no analysis */ - /* ---------------------------------------------------------------------- */ - - for (trial = 0 ; trial <= check_errors ; trial++) - { - - /* create a simplicial symbolic factor */ - L = CHOLMOD(allocate_factor) (n, cm) ; - ok = TRUE ; - Axtype = (A == NULL) ? CHOLMOD_REAL : A->xtype ; - - if (check_errors) - { - OKP (L) ; - if (trial == 0) - { - /* convert to packed LDL' first, then unpacked */ - ok = CHOLMOD(change_factor) (Axtype, FALSE, FALSE, TRUE, - TRUE, L, cm) ; - OK (ok); - ok = CHOLMOD(change_factor) (Axtype, FALSE, FALSE, FALSE, - TRUE, L, cm) ; - OK (ok) ; - } - else if (trial == 1) - { - ok = CHOLMOD(rowfac)(NULL, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(A, NULL, beta, 0, 0, NULL, cm) ; NOT (ok) ; - ok = CHOLMOD(rowfac)(AT, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; - if (n > 1) - { - A1 = CHOLMOD(allocate_sparse)(1, 1, 1, TRUE, TRUE, 1, - CHOLMOD_PATTERN, cm) ; OKP (A1) ; - ok = CHOLMOD(rowfac)(A1, NULL, beta, 0, 0, L, cm); NOT (ok); - ok = CHOLMOD(free_sparse)(&A1, cm) ; OK (ok); - } - } - else - { - /* convert to symbolic LL' */ - ok = CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, FALSE, TRUE, - TRUE, L, cm) ; - OK (ok) ; - OK (L->is_ll) ; - } - } - - /* factor */ - CHOLMOD(print_factor) (L, "L for rowfac", cm) ; - CHOLMOD(print_sparse) (A, "A for rowfac", cm) ; - - cm->dbound = 1e-15 ; - for (k = 0 ; ok && k < n ; k++) - { - if (!CHOLMOD(rowfac) (A, NULL, beta, k, k+1, L, cm)) - { - ok = FALSE ; - } - if (cm->status == CHOLMOD_NOT_POSDEF) - { - /* LL' factorization failed; subsequent rowfac's should fail */ - k++ ; - ok = CHOLMOD(rowfac) (A, NULL, beta, k, k+1, L, cm) ; - NOT (ok) ; - ok = TRUE ; - } - } - cm->dbound = 0 ; - - if (check_errors) - { - OK (ok) ; - ok = CHOLMOD(rowfac) (A, NULL, beta, n, n+1, L, cm) ; NOT (ok) ; - ok = TRUE ; - } - - /* solve */ - if (ok) - { - -/* -int saveit = cm->print ; -int saveit2 = cm->precise ; -cm->print = 5 ; -cm->precise = TRUE ; - -CHOLMOD (print_sparse) (A, "A here", cm) ; -CHOLMOD (print_factor) (L, "L here", cm) ; -CHOLMOD (print_dense) (B, "B here", cm) ; -*/ - - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - -/* -CHOLMOD (print_dense) (X, "X here", cm) ; -*/ - - cm->prefer_zomplex = FALSE ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - -/* -cm->print = saveit ; -cm->precise = saveit2 ; -fprintf (stderr, "solve %8.2e\n", r) ; -*/ - } - - CHOLMOD(free_factor) (&L, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* factor again with entries in the (ignored) lower part A */ - /* ---------------------------------------------------------------------- */ - - if (A->packed) - { - L = CHOLMOD(allocate_factor) (n, cm) ; - C = add_gunk (A) ; - -/* - C = CHOLMOD(copy) (A, 0, 1, cm) ; - if (C != NULL) - { - C->stype = 1 ; - } -*/ - - CHOLMOD(rowfac) (C, NULL, beta, 0, n, L, cm) ; - - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&X, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* factor again using rowfac_mask (for LPDASA only) */ - /* ---------------------------------------------------------------------- */ - - r = raw_factor2 (A, 0., 0) ; - MAXERR (maxerr, r, 1) ; - - r = raw_factor2 (A, 1e-16, 0) ; - MAXERR (maxerr, r, 1) ; - - /* ---------------------------------------------------------------------- */ - /* free the problem */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free_sparse) (&AT, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free) (n, sizeof (Int), First, cm) ; - CHOLMOD(free) (n, sizeof (Int), Level, cm) ; - CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; - CHOLMOD(free) (n, sizeof (Int), Post, cm) ; - progress (0, '.') ; - return (maxerr) ; -} - - -/* ========================================================================== */ -/* === raw_factor2 ========================================================== */ -/* ========================================================================== */ - -/* A->stype can be 0 (lower), 1 (upper) or 0 (unsymmetric). In the first two - * cases, Ax=b is solved. In the third, A*A'x=b is solved. No analysis and no - * fill-reducing ordering is used. Both simplicial LL' and LDL' factorizations - * are used (testing rowfac_mask, for LPDASA only). */ - -double raw_factor2 (cholmod_sparse *A, double alpha, int domask) -{ - Int n, i, prefer_zomplex, is_ll, xtype, sorted, axtype, stype ; - Int *mask = NULL, *RLinkUp = NULL, nz = 0 ; - Int *Cp = NULL, added_gunk ; - double maxerr = 0, r = 0 ; - cholmod_sparse *AT = NULL, *C = NULL, *CT = NULL, *CC = NULL, *C2 = NULL ; - cholmod_factor *L = NULL ; - cholmod_dense *B = NULL, *X = NULL ; - double beta [2] ; - -/* -int saveit = cm->print ; -int saveit2 = cm->precise ; -cm->print = 5 ; -cm->precise = TRUE ; -*/ - - if (A == NULL) - { - return (0) ; - } - n = A->nrow ; - if (n > 1000) - { - printf ("\nSkipping rowfac, matrix too large\n") ; - return (0) ; - } - axtype = A->xtype ; - beta [0] = alpha ; - beta [1] = 0 ; - - prefer_zomplex = (A->xtype == CHOLMOD_ZOMPLEX) ; - AT = CHOLMOD(transpose) (A, 2, cm) ; - - /* ensure C has stype of 0 or 1. Do not prune any entries */ - stype = A->stype ; - if (stype >= 0) - { - A->stype = 0 ; - C = CHOLMOD(copy_sparse) (A, cm) ; - A->stype = stype ; - if (C) C->stype = stype ; - /* - C = CHOLMOD(copy) (A, 0, 1, cm) ; - if (C) C->stype = A->stype ; - */ - CT = AT ; - - } - else - { - C = AT ; - /* - CT = CHOLMOD(copy_sparse) (A, cm) ; - */ - /* - CT = CHOLMOD(copy) (A, 0, 1, cm) ; - if (CT) CT->stype = A->stype ; - */ - A->stype = 0 ; - CT = CHOLMOD(copy_sparse) (A, cm) ; - A->stype = stype ; - if (CT) CT->stype = stype ; - - /* only domask if C is symmetric and upper part stored */ - domask = FALSE ; - - } - - mask = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - RLinkUp = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - - if (C && cm->status == CHOLMOD_OK) - { - for (i = 0 ; i < n ; i++) - { - mask [i] = -1 ; - RLinkUp [i] = i+1 ; - } - } - else - { - domask = FALSE ; - } - - if (C && !(C->packed) && !(C->sorted)) - { - /* do not do the unpacked or unsorted cases */ - domask = FALSE ; - } - - /* make a copy of C and add some gunk if stype > 0 */ - added_gunk = (C && C->stype > 0) ; - if (added_gunk) - { - C2 = add_gunk (C) ; - } - else - { - C2 = CHOLMOD(copy_sparse) (C, cm) ; - } - - CC = CHOLMOD(copy_sparse) (C2, cm) ; - - if (CC && domask) - { - Int *Cp, *Ci, p ; - double *Cx, *Cz ; - - /* this implicitly sets the first row/col of C to zero, except diag. */ - mask [0] = 1 ; - - /* CC = C2, and then set the first row/col to zero, except diagonal */ - Cp = CC->p ; - Ci = CC->i ; - Cx = CC->x ; - Cz = CC->z ; - nz = Cp [n] ; - switch (C->xtype) - { - case CHOLMOD_REAL: - for (p = 1 ; p < nz ; p++) - { - if (Ci [p] == 0) Cx [p] = 0 ; - } - break ; - - case CHOLMOD_COMPLEX: - for (p = 1 ; p < nz ; p++) - { - if (Ci [p] == 0) - { - Cx [2*p ] = 0 ; - Cx [2*p+1] = 0 ; - } - } - break ; - - case CHOLMOD_ZOMPLEX: - for (p = 1 ; p < nz ; p++) - { - if (Ci [p] == 0) - { - Cx [p] = 0 ; - Cz [p] = 0 ; - } - } - break ; - } - } - - B = rhs (CC, 1, n) ; - - for (sorted = 1 ; sorted >= 0 ; sorted--) - { - - if (!sorted) - { - if (C2 && !added_gunk) C2->sorted = FALSE ; - if (C) C->sorted = FALSE ; - if (CT) CT->sorted = FALSE ; - } - - for (is_ll = 0 ; is_ll <= 1 ; is_ll++) - { - for (xtype = 0 ; xtype <= 1 ; xtype++) - { - - L = CHOLMOD(allocate_factor) (n, cm) ; - if (L) L->is_ll = is_ll ; - - if (xtype) - { - CHOLMOD (change_factor) (axtype, is_ll, 0, 0, 1, L, cm) ; - } - - CHOLMOD(rowfac_mask) (sorted ? C : C2, - CT, beta, 0, n, mask, RLinkUp, L, cm) ; - - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - cm->prefer_zomplex = FALSE ; - - r = resid (CC, X, B) ; - MAXERR (maxerr, r, 1) ; - - printf ("rowfac mask: resid is %g\n", r) ; - - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&X, cm) ; - } - } - } - - CHOLMOD(free) (n, sizeof (Int), mask, cm) ; - CHOLMOD(free) (n, sizeof (Int), RLinkUp, cm) ; - - CHOLMOD(free_sparse) (&C2, cm) ; - CHOLMOD(free_sparse) (&CC, cm) ; - CHOLMOD(free_sparse) (&CT, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - - return (maxerr) ; -} diff --git a/CHOLMOD/Tcov/si_amdtest.c b/CHOLMOD/Tcov/si_amdtest.c new file mode 100644 index 0000000000..208bd56a2a --- /dev/null +++ b/CHOLMOD/Tcov/si_amdtest.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/si_amdtest: single/int32_t version of amdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_SINGLE + +#include "t_amdtest.c" + diff --git a/CHOLMOD/Tcov/si_camdtest.c b/CHOLMOD/Tcov/si_camdtest.c new file mode 100644 index 0000000000..d89fd7e5f3 --- /dev/null +++ b/CHOLMOD/Tcov/si_camdtest.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/si_camdtest: single/int32_t version of camdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_SINGLE + +#include "t_camdtest.c" + diff --git a/CHOLMOD/Tcov/si_huge.c b/CHOLMOD/Tcov/si_huge.c new file mode 100644 index 0000000000..67cbbb195b --- /dev/null +++ b/CHOLMOD/Tcov/si_huge.c @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/si_huge: single/int32_t version of huge +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_SINGLE + +#include "t_huge.c" + diff --git a/CHOLMOD/Tcov/si_read.c b/CHOLMOD/Tcov/si_read.c new file mode 100644 index 0000000000..f4e35f4e6c --- /dev/null +++ b/CHOLMOD/Tcov/si_read.c @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/si_read: single/int32_t version of cmread +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_SINGLE + +#include "t_cmread.c" diff --git a/CHOLMOD/Tcov/si_test.c b/CHOLMOD/Tcov/si_test.c new file mode 100644 index 0000000000..5ddd25bba0 --- /dev/null +++ b/CHOLMOD/Tcov/si_test.c @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/si_test: single/int32_t version of Tcov/cm test program +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT32 +#define DTYPE CHOLMOD_SINGLE + +#include "t_cm.c" +#include "t_test_ops.c" +#include "t_test_ops2.c" +#include "t_null.c" +#include "t_null2.c" +#include "t_lpdemo.c" +#include "t_memory.c" +#include "t_solve.c" +#include "t_aug.c" +#include "t_unpack.c" +#include "t_raw_factor.c" +#include "t_cctest.c" +#include "t_ctest.c" +#include "t_basic.c" +#include "t_overflow_tests.c" +#include "t_dump.c" +#include "t_read_triplet.c" +#include "t_rhs.c" +#include "t_znorm_diag.c" +#include "t_prand.c" +#include "t_perm_matrix.c" +#include "t_ptest.c" +#include "t_rand_dense.c" +#include "t_cat_tests.c" +#include "t_dense_tests.c" +#include "t_dtype_tests.c" +#include "t_common_tests.c" +#include "t_error_tests.c" +#include "t_tofrom_tests.c" +#include "t_suitesparse.c" diff --git a/CHOLMOD/Tcov/sl_amdtest.c b/CHOLMOD/Tcov/sl_amdtest.c new file mode 100644 index 0000000000..423516b53d --- /dev/null +++ b/CHOLMOD/Tcov/sl_amdtest.c @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/sl_amdtest: single/int64_t version of amdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_SINGLE + +#define DLONG +#include "t_amdtest.c" + diff --git a/CHOLMOD/Tcov/sl_camdtest.c b/CHOLMOD/Tcov/sl_camdtest.c new file mode 100644 index 0000000000..0130d8d56d --- /dev/null +++ b/CHOLMOD/Tcov/sl_camdtest.c @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/sl_camdtest: single/int64_t version of camdtest +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_SINGLE + +#define DLONG +#include "t_camdtest.c" + diff --git a/CHOLMOD/Tcov/amdtest_l.c b/CHOLMOD/Tcov/sl_huge.c similarity index 64% rename from CHOLMOD/Tcov/amdtest_l.c rename to CHOLMOD/Tcov/sl_huge.c index b77e761588..e2928208b7 100644 --- a/CHOLMOD/Tcov/amdtest_l.c +++ b/CHOLMOD/Tcov/sl_huge.c @@ -1,14 +1,16 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Tcov/amdtest_l: int64_t version of amdtest +// CHOLMOD/Tcov/sl_huge: single/int64_t version of huge //------------------------------------------------------------------------------ -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ +#define SINGLE #define CHOLMOD_INT64 -#define DLONG -#include "amdtest.c" +#define DTYPE CHOLMOD_SINGLE + +#include "t_huge.c" diff --git a/CHOLMOD/Tcov/sl_read.c b/CHOLMOD/Tcov/sl_read.c new file mode 100644 index 0000000000..5bc7ff1cbd --- /dev/null +++ b/CHOLMOD/Tcov/sl_read.c @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/sl_read: single/int64_t version of cmread +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_SINGLE + +#include "t_cmread.c" diff --git a/CHOLMOD/Tcov/sl_test.c b/CHOLMOD/Tcov/sl_test.c new file mode 100644 index 0000000000..fef34f7fb1 --- /dev/null +++ b/CHOLMOD/Tcov/sl_test.c @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/sl_test: single/int64_t version of Tcov/cm test program +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#define SINGLE +#define CHOLMOD_INT64 +#define DTYPE CHOLMOD_SINGLE + +#include "t_cm.c" +#include "t_test_ops.c" +#include "t_test_ops2.c" +#include "t_null.c" +#include "t_null2.c" +#include "t_lpdemo.c" +#include "t_memory.c" +#include "t_solve.c" +#include "t_aug.c" +#include "t_unpack.c" +#include "t_raw_factor.c" +#include "t_cctest.c" +#include "t_ctest.c" +#include "t_basic.c" +#include "t_overflow_tests.c" +#include "t_dump.c" +#include "t_read_triplet.c" +#include "t_rhs.c" +#include "t_znorm_diag.c" +#include "t_prand.c" +#include "t_perm_matrix.c" +#include "t_ptest.c" +#include "t_rand_dense.c" +#include "t_cat_tests.c" +#include "t_dense_tests.c" +#include "t_dtype_tests.c" +#include "t_common_tests.c" +#include "t_error_tests.c" +#include "t_tofrom_tests.c" +#include "t_suitesparse.c" diff --git a/CHOLMOD/Tcov/solve.c b/CHOLMOD/Tcov/solve.c deleted file mode 100644 index 92060cd58e..0000000000 --- a/CHOLMOD/Tcov/solve.c +++ /dev/null @@ -1,1634 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/solve: test CHOLMOD solvers -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test CHOLMOD for solving various systems of linear equations. */ - -#include "cm.h" - -#define NFTYPES 17 -Int ll_types [NFTYPES] = { 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0 } ; -Int pk_types [NFTYPES] = { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0 } ; -Int mn_types [NFTYPES] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 } ; -Int co_types [NFTYPES] = { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 } ; - -#define NRHS 9 - -#ifndef NDEBUG -#ifndef EXTERN -#define EXTERN extern -#endif -EXTERN int cholmod_dump, cholmod_l_dump ; -#endif - -/* ========================================================================== */ -/* === test_solver ========================================================== */ -/* ========================================================================== */ - -/* Test solve(A) with various control parameters */ - -double test_solver (cholmod_sparse *A) -{ - double err, maxerr = 0 ; - int save ; - - for (cm->postorder = 0 ; cm->postorder <= 1 ; cm->postorder++) - { - - my_srand (42) ; /* RAND reset */ - - /* simplicial, no extra memory */ - printf ("test_solver: simplicial, no extra memory\n") ; - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->grow2 = 0 ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* simplicial, extra space in columns of L */ - printf ("test_solver: simplicial, extra space in columns of L\n") ; - cm->grow2 = 5 ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* supernodal */ - printf ("test_solver: supernodal\n") ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* supernodal, without final resymbol */ - printf ("test_solver: supernodal, without final resymbol\n") ; - cm->final_resymbol = FALSE ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* supernodal, with resymbol, final_super false */ - printf ("test_solver: supernodal, with resymbol\n") ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_asis = FALSE ; - cm->final_resymbol = TRUE ; - cm->final_super = FALSE ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* supernodal, with resymbol, final_super tree */ - printf ("test_solver: supernodal, with resymbol\n") ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_asis = FALSE ; - cm->final_resymbol = TRUE ; - cm->final_super = TRUE ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* simplicial LL' */ - printf ("test_solver: simplicial LL', try NESDIS instead of METIS\n") ; - cm->supernodal = CHOLMOD_SIMPLICIAL ; - cm->final_ll = TRUE ; -cm->default_nesdis = TRUE ; - err = solve (A) ; -cm->default_nesdis = FALSE ; - MAXERR (maxerr, err, 1) ; - cm->final_ll = FALSE ; - printf ("test_solver err: %6.2e\n", err) ; - - /* supernodal, without final resymbol, and no relaxed supernodes */ - printf ( -"test_solver: supernodal, without final resymbol, and no relaxed supernodes\n") ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - cm->final_asis = TRUE ; - cm->nrelax [0] = 0 ; - cm->nrelax [1] = 0 ; - cm->nrelax [2] = 0 ; - cm->zrelax [0] = 0 ; - cm->zrelax [1] = 0 ; - cm->zrelax [2] = 0 ; - cm->grow0 = 1 ; - cm->grow1 = 1 ; - cm->grow2 = 0 ; - err = solve (A) ; - MAXERR (maxerr, err, 1) ; - printf ("test_solver err: %6.2e\n", err) ; - - /* ------------------------------------------------------------------ */ - /* restore defaults */ - /* ------------------------------------------------------------------ */ - - cm->dbound = 0.0 ; - - cm->grow0 = 1.2 ; - cm->grow1 = 1.2 ; - cm->grow2 = 5 ; - - cm->final_asis = TRUE ; - cm->final_super = TRUE ; - cm->final_ll = FALSE ; - cm->final_pack = TRUE ; - cm->final_monotonic = TRUE ; - cm->final_resymbol = FALSE ; - - cm->supernodal = CHOLMOD_AUTO ; - cm->nrelax [0] = 4 ; - cm->nrelax [1] = 16 ; - cm->nrelax [2] = 48 ; - cm->zrelax [0] = 0.8 ; - cm->zrelax [1] = 0.1 ; - cm->zrelax [2] = 0.05 ; - - /* do not restore these defaults: */ - /* - cm->maxrank = ... - cm->metis_memory = 2.0 - cm->metis_nswitch = 3000 - cm->metis_dswitch = 0.66 - cm->print = 3 - cm->precise = FALSE - */ - } - - progress (1, '.') ; - return (maxerr) ; -} - - -/* ========================================================================== */ -/* === solve ================================================================ */ -/* ========================================================================== */ - -/* solve Ax=b or AA'x=b, systems involving just L, D, or L', and update/downdate - * the system. Returns the worst-case residual. This routine keeps going if - * it runs out of memory (unless the error handler terminates it), because - * it is used both normally and in the memory tests. - */ - -double solve (cholmod_sparse *A) -{ - double r, enorm, snorm, maxerr = 0, gnorm, anorm, bnorm, xnorm, norm, rcond; - cholmod_factor *L, *Lcopy, *L2 ; - cholmod_sparse *Lmat, *Lo, *D, *Up, *S, *LD, *LDL, *E, *I, *C, *CC, *Ct, - *Ssym, *Cperm, *C2, *S2, *H, *F, *Lo1, *Aboth, *Bset ; - cholmod_dense *X, *Cdense, *B, *Bcomplex, *Bzomplex, *Breal, *W, *R, - *A3, *C3, *E3 ; - cholmod_dense *B2, *B2complex, *B2zomplex, *B2real, *Ywork, *Ework ; - cholmod_sparse *AFt, *AF, *G, *RowK, *Bsparse, *Xsparse ; - double *Cx ; - double *B2x ; - Int *P, *cset, *fset, *Parent, *Post, *RowCount, *ColCount, - *First, *Level, *rcount, *ccount, *Lp, *Li ; - Int p, i, j, k, n, nrhs, save, save2, csize, rank, nrow, ncol, is_ll, - xtype, isreal, prefer_zomplex, Lxtype, xtype2, save3 ; - cm->blas_ok = TRUE ; - - Ywork = NULL ; - Ework = NULL ; - - if (cm->print > 1) - { - printf ("============================================== in solve:\n") ; - } - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "nothing to solve") ; - return (1) ; - } - - /* ---------------------------------------------------------------------- */ - /* construct right-hand-side (Ax=b if symmetric, AA'x=b otherwise) */ - /* ---------------------------------------------------------------------- */ - - n = A->nrow ; - nrow = A->nrow ; - ncol = A->ncol ; - xtype = A->xtype ; - isreal = (xtype == CHOLMOD_REAL) ; - B = rhs (A, NRHS, n) ; - anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; - save = cm->final_asis ; - cm->final_asis = TRUE ; - - /* contents of these will be revised later */ - Bzomplex = CHOLMOD(copy_dense) (B, cm) ; - Bcomplex = CHOLMOD(copy_dense) (Bzomplex, cm) ; - Breal = CHOLMOD(copy_dense) (Bzomplex, cm) ; - - /* create another right-hand-side, slightly different */ - B2 = CHOLMOD(copy_dense) (B, cm) ; - if (B2 != NULL) - { - B2x = (double *) B2->x ; - B2x [0] = 42 ; - } - - /* ---------------------------------------------------------------------- */ - /* analyze */ - /* ---------------------------------------------------------------------- */ - - if (n < 100 && cm->nmethods == 1 && cm->method[0].ordering == CHOLMOD_GIVEN) - { - Int *UserPerm = prand (nrow) ; /* RAND */ - L = CHOLMOD(analyze_p) (A, UserPerm, NULL, 0, cm) ; - OK (CHOLMOD(print_common) ("with UserPerm", cm)) ; - CHOLMOD(free) (nrow, sizeof (Int), UserPerm, cm) ; - } - else - { - L = CHOLMOD(analyze) (A, cm) ; - } - - /* test rowadd on a symbolic factor */ - if (isreal) - { - RowK = CHOLMOD(spzeros) (n, 1, 0, CHOLMOD_REAL, cm) ; - Lcopy = CHOLMOD(copy_factor) (L, cm) ; - if (n > 0) - { - CHOLMOD(rowadd) (0, RowK, Lcopy, cm) ; - CHOLMOD(check_factor) (Lcopy, cm) ; - CHOLMOD(print_factor) (Lcopy, "Lcopy, now numeric", cm) ; - } - CHOLMOD(free_sparse) (&RowK, cm) ; - CHOLMOD(free_factor) (&Lcopy, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* factorize */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(factorize) (A, L, cm) ; - - /* ---------------------------------------------------------------------- */ - /* various solves */ - /* ---------------------------------------------------------------------- */ - - if (B != NULL) - { - /* B->ncol = 1 ; */ - prefer_zomplex = (B->xtype == CHOLMOD_ZOMPLEX) ; - } - else - { - prefer_zomplex = FALSE ; - } - - for (k = 0 ; k <= 1 ; k++) - { - - cm->prefer_zomplex = k ; - - /* compute the residual, X complex if L or B not real */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* now test the same thing, but with cholmod_solve2 */ - CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B2, NULL, &X, NULL, &Ywork, &Ework, cm) ; - r = resid (A, X, B2) ; - MAXERR (maxerr, r, 1) ; - - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - - /* see what happens if X has the wrong size or type on input. This - * will free X on input, and reallocate it the right size and type */ - X = CHOLMOD(ones) (1, 1, CHOLMOD_REAL, cm) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - - /* now X is OK, and so is E, but Y is null */ - CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - - /* zomplex right-hand-side */ - CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX, Bzomplex, cm) ; - if (Bzomplex != NULL && B != NULL && B->xtype == CHOLMOD_REAL - && Bzomplex->xtype == CHOLMOD_ZOMPLEX) - { - /* add an arbitrary imaginary part */ - double *Bz = Bzomplex->z ; - for (j = 0 ; j < NRHS ; j++) - { - for (i = 0 ; i < n ; i++) - { - Bz [i+j*n] = (double) (i+j*n) ; - } - } - } - X = CHOLMOD(solve) (CHOLMOD_A, L, Bzomplex, cm) ; - r = resid (A, X, Bzomplex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - B2zomplex = CHOLMOD(copy_dense) (Bzomplex, cm) ; - if (B2zomplex != NULL) - { - B2x = (double *) B2zomplex->x ; - B2x [0] = 99 ; - } - - /* now test the same thing, but with cholmod_solve2 */ - CHOLMOD(solve2) (CHOLMOD_A, L, Bzomplex, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, Bzomplex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B2zomplex, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, B2zomplex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - - /* complex right-hand-side */ - CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX, Bcomplex, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L, Bcomplex, cm) ; - r = resid (A, X, Bcomplex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - B2complex = CHOLMOD(copy_dense) (Bcomplex, cm) ; - if (B2complex != NULL) - { - B2x = (double *) B2complex->x ; - B2x [0] = 777 ; - } - - /* now test the same thing, but with cholmod_solve2 */ - CHOLMOD(solve2) (CHOLMOD_A, L, Bcomplex, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, Bcomplex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B2complex, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, B2complex) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - - /* real right-hand-side */ - CHOLMOD(dense_xtype) (CHOLMOD_REAL, Breal, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L, Breal, cm) ; - r = resid (A, X, Breal) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - B2real = CHOLMOD(copy_dense) (Breal, cm) ; - if (B2real != NULL) - { - B2x = (double *) B2real->x ; - B2x [0] = 1234 ; - } - - /* now test the same thing, but with cholmod_solve2 */ - CHOLMOD(solve2) (CHOLMOD_A, L, Breal, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, Breal) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B2real, NULL, &X, NULL, - &Ywork, &Ework, cm) ; - r = resid (A, X, B2real) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - - /* sparse solve of Ax=b, b real */ - Bsparse = CHOLMOD(dense_to_sparse) (Breal, TRUE, cm) ; - Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; - r = resid_sparse (A, Xsparse, Bsparse) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_sparse) (&Bsparse, cm) ; - CHOLMOD(free_sparse) (&Xsparse, cm) ; - - /* sparse solve of Ax=b, b complex */ - Bsparse = CHOLMOD(dense_to_sparse) (Bcomplex, TRUE, cm) ; - Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; - r = resid_sparse (A, Xsparse, Bsparse) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_sparse) (&Bsparse, cm) ; - CHOLMOD(free_sparse) (&Xsparse, cm) ; - - /* sparse solve of Ax=b, b zomplex */ - Bsparse = CHOLMOD(dense_to_sparse) (Bzomplex, TRUE, cm) ; - Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; - r = resid_sparse (A, Xsparse, Bsparse) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_sparse) (&Bsparse, cm) ; - CHOLMOD(free_sparse) (&Xsparse, cm) ; - - CHOLMOD(free_dense) (&B2zomplex, cm) ; - CHOLMOD(free_dense) (&B2complex, cm) ; - CHOLMOD(free_dense) (&B2real, cm) ; - } - - cm->prefer_zomplex = FALSE ; - - /* ---------------------------------------------------------------------- */ - /* sparse solve to compute inv(A) */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(print_sparse) (A, "A", cm) ; - CHOLMOD(print_factor) (L, "L", cm) ; - rcond = CHOLMOD(rcond) (L, cm) ; - if (cm->print > 1) - { - printf ("rcond: %g\n", rcond) ; - } - - if (n < 100 && A->stype != 0) - { - /* solve A*C=I, so C should equal A inverse */ - I = CHOLMOD(speye) (n, n, CHOLMOD_REAL, cm) ; - C = CHOLMOD(spsolve) (CHOLMOD_A, L, I, cm) ; - /* compute norm of A*C-I */ - if (isreal && n > 10) - { - /* A and C are large and real */ - E = CHOLMOD(ssmult) (A, C, 0, TRUE, FALSE, cm) ; - F = CHOLMOD(add) (E, I, minusone, one, TRUE, FALSE, cm) ; - r = CHOLMOD(norm_sparse) (F, 1, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; - } - else - { - /* There is no complex ssmult or add, so use the BLAS. - * Also test sparse_to_dense for small symmetric matrices. */ - A3 = CHOLMOD(sparse_to_dense) (A, cm) ; - C3 = CHOLMOD(sparse_to_dense) (C, cm) ; - xtype2 = isreal ? CHOLMOD_REAL : CHOLMOD_COMPLEX ; - CHOLMOD(dense_xtype) (xtype2, A3, cm) ; - CHOLMOD(dense_xtype) (xtype2, C3, cm) ; - E3 = CHOLMOD(eye) (n, n, xtype2, cm) ; - if (A3 != NULL && C3 != NULL && E3 != NULL) - { - /* E3 = A3*C3-I */ - if (isreal) - { - SUITESPARSE_BLAS_dgemm ("N", "N", n, n, n, one, A3->x, n, - C3->x, n, minusone, E3->x, n, cm->blas_ok) ; - } - else - { - SUITESPARSE_BLAS_zgemm ("N", "N", n, n, n, one, A3->x, n, - C3->x, n, minusone, E3->x, n, cm->blas_ok) ; - } - OK (cm->blas_ok) ; - } - r = CHOLMOD(norm_dense) (E3, 1, cm) ; - CHOLMOD(free_dense) (&A3, cm) ; - CHOLMOD(free_dense) (&C3, cm) ; - CHOLMOD(free_dense) (&E3, cm) ; - } - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_sparse) (&I, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* change complexity of L and solve again; test copy/change routines */ - /* ---------------------------------------------------------------------- */ - - /* change to complex, otherwise leave as */ - Lcopy = CHOLMOD(copy_factor) (L, cm) ; - CHOLMOD(factor_xtype) (CHOLMOD_COMPLEX, Lcopy, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, Lcopy, B, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_factor) (&Lcopy, cm) ; - - /* change to zomplex LDL' */ - Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; - Lcopy = CHOLMOD(copy_factor) (L, cm) ; - CHOLMOD(check_factor) (L, cm) ; - CHOLMOD(print_factor) (Lcopy, "Lcopy", cm) ; - CHOLMOD(change_factor) (Lxtype, FALSE, FALSE, TRUE, TRUE, Lcopy, cm) ; - CHOLMOD(factor_xtype) (CHOLMOD_ZOMPLEX, Lcopy, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, Lcopy, B, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_factor) (&Lcopy, cm) ; - - Lcopy = CHOLMOD(copy_factor) (L, cm) ; - CHOLMOD(change_factor) (Lxtype, TRUE, FALSE, FALSE, FALSE, Lcopy, cm) ; - CHOLMOD(check_factor) (L, cm) ; - CHOLMOD(print_factor) (Lcopy, "Lcopy LL unpacked", cm) ; - CHOLMOD(free_factor) (&Lcopy, cm) ; - - CHOLMOD(free_factor) (&L, cm) ; - cm->final_asis = save ; - - /* ---------------------------------------------------------------------- */ - /* solve again, but use cm->final_asis as given */ - /* ---------------------------------------------------------------------- */ - - if (n < 100 && cm->nmethods == 1 && cm->method[0].ordering == CHOLMOD_GIVEN) - { - Int *UserPerm = prand (nrow) ; /* RAND */ - L = CHOLMOD(analyze_p) (A, UserPerm, NULL, 0, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), UserPerm, cm) ; - } - else - { - L = CHOLMOD(analyze) (A, cm) ; - } - - CHOLMOD(print_factor) (L, "Lsymbolic", cm) ; - CHOLMOD(factorize) (A, L, cm) ; - - /* turn off memory tests [ */ - save3 = my_tries ; - my_tries = -1 ; - - CHOLMOD(print_factor) (L, "Lnumeric for solver tests", cm) ; - CHOLMOD(print_dense) (B, "B for solver tests", cm) ; - CHOLMOD(print_dense) (Breal, "Breal for solver tests", cm) ; - CHOLMOD(print_dense) (Bcomplex, "Bcomplex for solver tests", cm) ; - CHOLMOD(print_dense) (Bzomplex, "Bzomplex for solver tests", cm) ; - - if (B != NULL && Breal != NULL && Bcomplex != NULL && Bzomplex != NULL) - { - for (nrhs = 1 ; nrhs <= NRHS ; nrhs++) - { - for (cm->prefer_zomplex = 0 ; cm->prefer_zomplex <= 1 ; - cm->prefer_zomplex++) - { - B->ncol = nrhs ; - Breal->ncol = nrhs ; - Bcomplex->ncol = nrhs ; - Bzomplex->ncol = nrhs ; - - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (A, X, B) ; - CHOLMOD(free_dense) (&X, cm) ; - MAXERR (maxerr, r, 1) ; - - X = CHOLMOD(solve) (CHOLMOD_A, L, Breal, cm) ; - r = resid (A, X, Breal) ; - CHOLMOD(free_dense) (&X, cm) ; - MAXERR (maxerr, r, 1) ; - - X = CHOLMOD(solve) (CHOLMOD_A, L, Bcomplex, cm) ; - r = resid (A, X, Bcomplex) ; - CHOLMOD(free_dense) (&X, cm) ; - MAXERR (maxerr, r, 1) ; - - X = CHOLMOD(solve) (CHOLMOD_A, L, Bzomplex, cm) ; - r = resid (A, X, Bzomplex) ; - CHOLMOD(free_dense) (&X, cm) ; - MAXERR (maxerr, r, 1) ; - } - } - } - cm->prefer_zomplex = FALSE ; - - /* turn memory tests back on, where we left off ] */ - my_tries = save3 ; - - Lcopy = CHOLMOD(copy_factor) (L, cm) ; - - /* ---------------------------------------------------------------------- */ - /* convert L to LDL' packed or LL packed */ - /* ---------------------------------------------------------------------- */ - - printf ("before change factor : %d\n", L ? L->is_super : -1) ; - is_ll = (L == NULL) ? FALSE : (L->is_ll) ; - Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; - CHOLMOD(change_factor) (Lxtype, is_ll, FALSE, TRUE, TRUE, Lcopy, cm) ; - printf ("after change factor : %d\n", L ? L->is_super : -1) ; - - /* ---------------------------------------------------------------------- */ - /* extract L, D, and L' as matrices from Lcopy */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(resymbol) (A, NULL, 0, TRUE, Lcopy, cm) ; - - Lmat = CHOLMOD(factor_to_sparse) (Lcopy, cm) ; - CHOLMOD(check_sparse) (Lmat, cm) ; - - I = CHOLMOD(speye) (n, n, CHOLMOD_REAL, cm) ; - - Lo = NULL ; - D = NULL ; - - Lxtype = (Lmat == NULL) ? CHOLMOD_REAL : (Lmat->xtype) ; - - if (isreal) - { - /* use band and add */ - if (!is_ll) - { - /* factorization is LDL' = Lo*D*Up */ - Lo1 = CHOLMOD(band) (Lmat, -n, -1, 1, cm) ; - Lo = CHOLMOD(add) (Lo1, I, one, one, TRUE, TRUE, cm) ; - CHOLMOD(free_sparse) (&Lo1, cm) ; - D = CHOLMOD(band) (Lmat, 0, 0, 1, cm) ; - } - else - { - /* factorization is LL' = Lo*D*Up */ - Lo = CHOLMOD(band) (Lmat, -n, 0, 1, cm) ; - D = CHOLMOD(speye) (n, n, Lxtype, cm) ; - } - } - else - { - /* band and add do not work for c/zomplex matrices*/ - D = CHOLMOD(speye) (n, n, Lxtype, cm) ; - Lo = CHOLMOD(copy_sparse) (Lmat, cm) ; - if (!is_ll && D != NULL && Lo != NULL) - { - /* factorization is LDL' = Lo*D*Up */ - double *Dx = D->x ; - double *Lx = Lo->x ; - Lp = Lo->p ; - for (k = 0 ; k < n ; k++) - { - p = Lp [k] ; - if (Lxtype == CHOLMOD_COMPLEX) - { - Dx [2*k] = Lx [2*p] ; - Lx [2*p] = 1 ; - } - else - { - Dx [k] = Lx [p] ; - Lx [p] = 1 ; - } - } - } - } - - Up = CHOLMOD(transpose) (Lo, 2, cm) ; - - /* ---------------------------------------------------------------------- */ - /* compute 1-norm of (Lo*D*Up - PAP') or (Lo*D*Up - PAA'P') */ - /* ---------------------------------------------------------------------- */ - - P = (L != NULL) ? (L->Perm) : NULL ; - S = NULL ; - G = NULL ; - - if (isreal) - { - - if (A->stype == 0) - { - /* G = A*A', try with fset = prand (ncol) */ - fset = prand (ncol) ; /* RAND */ - AFt = CHOLMOD(ptranspose) (A, 1, NULL, fset, ncol, cm) ; - AF = CHOLMOD(transpose) (AFt, 1, cm) ; - CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; - G = CHOLMOD(ssmult) (AF, AFt, 0, TRUE, TRUE, cm) ; - -// int save = cm->print ; -// cm->print = 5 ; -// CHOLMOD (print_sparse) (A, "HERE A", cm) ; -// CHOLMOD (print_sparse) (AFt, "HERE AFt", cm) ; -// CHOLMOD (print_sparse) (AF, "HERE AF", cm) ; -// CHOLMOD (print_sparse) (G, "HERE G", cm) ; - - /* also try aat */ - H = CHOLMOD(aat) (AF, NULL, 0, 1, cm) ; - -// CHOLMOD (print_sparse) (H, "HERE H", cm) ; -// printf ("status %d\n", cm->status) ; -// cm->print = save ; - - E = CHOLMOD(add) (G, H, one, minusone, TRUE, FALSE, cm) ; - - enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; - gnorm = CHOLMOD(norm_sparse) (G, 0, cm) ; - MAXERR (maxerr, enorm, gnorm) ; - if (1) // (cm->print > 1) - { - printf ("enorm %g gnorm %g hnorm %g\n", enorm, gnorm, - CHOLMOD(norm_sparse) (H, 0, cm)) ; - } - if (gnorm > 0) - { - enorm /= gnorm ; - } - OK (enorm < 1e-8) ; - CHOLMOD(free_sparse) (&AFt, cm) ; - CHOLMOD(free_sparse) (&AF, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&H, cm) ; - - } - else - { - /* G = A */ - G = CHOLMOD(copy) (A, 0, 1, cm) ; - } - - if (A->stype == 0) - { - /* S = PAA'P' */ - S = CHOLMOD(submatrix) (G, P, n, P, n, TRUE, FALSE, cm) ; - } - else - { - /* S = PAP' */ - Aboth = CHOLMOD(copy) (A, 0, 1, cm) ; - S = CHOLMOD(submatrix) (Aboth, P, n, P, n, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&Aboth, cm) ; - } - - if (n < NSMALL) - { - /* only do this for small test matrices, since L*D*L' can have many - * nonzero entries */ - - /* E = L*D*L' - S */ - LD = CHOLMOD(ssmult) (Lo, D, 0, TRUE, FALSE, cm) ; - LDL = CHOLMOD(ssmult) (LD, Up, 0, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&LD, cm) ; - E = CHOLMOD(add) (LDL, S, one, minusone, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&LDL, cm) ; - - /* e = norm (E) / norm (S) */ - enorm = CHOLMOD(norm_sparse) (E, 1, cm) ; - snorm = CHOLMOD(norm_sparse) (S, 0, cm) ; - MAXERR (maxerr, enorm, snorm) ; - CHOLMOD(free_sparse) (&E, cm) ; - } - - /* check the row/col counts */ - RowCount = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - ColCount = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Parent = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Post = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - First = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - Level = CHOLMOD(malloc) (n, sizeof (Int), cm) ; - rcount = CHOLMOD(calloc) (n, sizeof (Int), cm) ; - ccount = CHOLMOD(calloc) (n, sizeof (Int), cm) ; - - if (S != NULL && Lmat != NULL && RowCount != NULL && ColCount != NULL && - Parent != NULL && Post != NULL && First != NULL && Level != NULL && - rcount != NULL && ccount != NULL) - { - S->stype = 1 ; - - CHOLMOD(etree) (S, Parent, cm) ; - CHOLMOD(print_parent) (Parent, n, "Parent", cm) ; - CHOLMOD(postorder) (Parent, n, NULL, Post, cm) ; - CHOLMOD(print_perm) (Post, n, n, "Post", cm) ; - S->stype = -1 ; - CHOLMOD(rowcolcounts) (S, NULL, 0, Parent, Post, RowCount, ColCount, - First, Level, cm) ; - - Lp = Lmat->p ; - Li = Lmat->i ; - OK (Lmat->packed) ; - for (j = 0 ; j < n ; j++) - { - for (p = Lp [j] ; p < Lp [j+1] ; p++) - { - i = Li [p] ; - rcount [i]++ ; - ccount [j]++ ; - } - } - /* a singular matrix will only be partially factorized */ - if (L->minor == (size_t) n) - { - for (j = 0 ; j < n ; j++) - { - OK (ccount [j] == ColCount [j]) ; - } - } - for (i = 0 ; i < (Int) (L->minor) ; i++) - { - OK (rcount [i] == RowCount [i]) ; - } - } - - CHOLMOD(free) (n, sizeof (Int), RowCount, cm) ; - CHOLMOD(free) (n, sizeof (Int), ColCount, cm) ; - CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; - CHOLMOD(free) (n, sizeof (Int), Post, cm) ; - CHOLMOD(free) (n, sizeof (Int), First, cm) ; - CHOLMOD(free) (n, sizeof (Int), Level, cm) ; - CHOLMOD(free) (n, sizeof (Int), rcount, cm) ; - CHOLMOD(free) (n, sizeof (Int), ccount, cm) ; - - CHOLMOD(free_sparse) (&S, cm) ; - } - - CHOLMOD(free_factor) (&Lcopy, cm) ; - - /* ---------------------------------------------------------------------- */ - /* solve other systems */ - /* ---------------------------------------------------------------------- */ - - /* turn off memory tests [ */ - save3 = my_tries ; - my_tries = -1 ; - - for (nrhs = 1 ; nrhs <= 4 ; nrhs++) /* reduced here (6 to 4) */ - { - - if (B == NULL) - { - break ; - } - - B->ncol = nrhs ; - - /* solve Ax=b and compare with the sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve LDL'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; - /* printf ("LDL'x=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, D, Up, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve LDx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_LD, L, B, cm) ; - /* printf ("LDx=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, D, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve DL'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_DLt, L, B, cm) ; - /* printf ("DL'x=b %p %p %p\n", D, X, B) ; */ - r = resid3 (D, Up, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve Lx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; - /* printf ("Lx=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve L'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_Lt, L, B, cm) ; - /* printf ("L'x=b %p %p %p\n", Up, X, B) ; */ - r = resid3 (Up, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* solve Dx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_D, L, B, cm) ; - /* printf ("Dx=b %p %p %p\n", D, X, B) ; */ - r = resid3 (D, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - save2 = cm->prefer_zomplex ; - for (k = 0 ; k <= 1 ; k++) - { - cm->prefer_zomplex = k ; - - /* x=Pb and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_P, L, B, cm) ; - r = pnorm (X, P, B, FALSE) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* x=P'b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_Pt, L, B, cm) ; - r = pnorm (X, P, B, TRUE) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - } - cm->prefer_zomplex = save2 ; - } - - /* turn memory tests back on, where we left off ] */ - my_tries = save3 ; - - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free_dense) (&B2, cm) ; - - /* ---------------------------------------------------------------------- */ - /* test the sparse solve */ - /* ---------------------------------------------------------------------- */ - - /* turn off memory tests [ */ - save3 = my_tries ; - my_tries = -1 ; - - /* get ready for sparse solve */ - Bset = CHOLMOD(allocate_sparse) (n, 1, 1, FALSE, TRUE, 0, - CHOLMOD_PATTERN, cm) ; - B = CHOLMOD(zeros) (n, 1, Lxtype, cm) ; - - printf ("testing sparse solve, maxerr so far %g\n", maxerr) ; - - if (Bset != NULL && B != NULL && n > 0) - { - cholmod_sparse *Xset ; - cholmod_dense *X2 ; - Int *Bseti, *Bsetp, *Xseti ; - double *X2x, *X1x, *Bx, *Bz ; - - Xset = NULL ; - X2 = NULL ; - - Bseti = Bset->i ; - Bsetp = Bset->p ; - Bsetp [0] = 0 ; - Bsetp [1] = 1 ; - Bseti [0] = 0 ; /* first entry in b is nonzero, all others zero */ - Bx = B->x ; - Bz = B->z ; - - if (B->xtype == CHOLMOD_REAL) - { - Bx [0] = 42 ; - } - else if (B->xtype == CHOLMOD_COMPLEX) - { - Bx [0] = -2 ; - Bx [1] = 1 ; - } - else - { - Bx [0] = 77 ; - Bz [0] = -2 ; - } - - /* solve Ax=b and compare with the sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - if (X != NULL) - { - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_A, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 Ax=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve LDL'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; - if (X != NULL) - { - /* printf ("LDL'x=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, D, Up, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_LDLt, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 LDL'x=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve LDx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_LD, L, B, cm) ; - if (X != NULL) - { - /* printf ("LDx=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, D, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_LD, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 LDx=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve DL'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_DLt, L, B, cm) ; - if (X != NULL) - { - /* printf ("DL'x=b %p %p %p\n", D, X, B) ; */ - r = resid3 (D, Up, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_DLt, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 DL'x=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve Lx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; - if (X != NULL) - { - /* printf ("Lx=b %p %p %p\n", Lo, X, B) ; */ - r = resid3 (Lo, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_L, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 Lx=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve L'x=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_Lt, L, B, cm) ; - if (X != NULL) - { - /* printf ("L'x=b %p %p %p\n", Up, X, B) ; */ - r = resid3 (Up, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_Lt, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 Ltx=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* solve Dx=b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_D, L, B, cm) ; - if (X != NULL) - { - /* printf ("Dx=b %p %p %p\n", D, X, B) ; */ - r = resid3 (D, NULL, NULL, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_D, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL) - { - X2x = X2->x ; - X1x = X->x ; - r = fabs (X2x [0] - X1x [0]) ; - printf ("solve2 Dx=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - -#if 0 - save2 = cm->prefer_zomplex ; - for (k = 0 ; k <= 1 ; k++) - { - cm->prefer_zomplex = k ; - - /* x=Pb and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_P, L, B, cm) ; - if (X != NULL) - { - r = pnorm (X, P, B, FALSE) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_P, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL && Xset != NULL) - { - X2x = X2->x ; - X1x = X->x ; - Xseti = Xset->i ; - i = Xseti [0] ; - r = fabs (X2x [i] - X1x [i]) ; - printf ("solve2 Px=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - - /* x=P'b and compare with sparse solve */ - X = CHOLMOD(solve) (CHOLMOD_Pt, L, B, cm) ; - if (X != NULL) - { - r = pnorm (X, P, B, TRUE) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(solve2) (CHOLMOD_Pt, L, B, Bset, &X2, &Xset, - &Ywork, &Ework, cm) ; - if (X2 != NULL && Xset != NULL) - { - X2x = X2->x ; - X1x = X->x ; - Xseti = Xset->i ; - i = Xseti [0] ; - r = fabs (X2x [i] - X1x [i]) ; - printf ("solve2 P'x=b err %g\n", r) ; - MAXERR (maxerr, r, 1) ; - } - } - CHOLMOD(free_dense) (&X, cm) ; - } - cm->prefer_zomplex = save2 ; -#endif - - CHOLMOD(free_sparse) (&Xset, cm) ; - CHOLMOD(free_dense) (&X2, cm) ; - CHOLMOD(free_dense) (&Ywork, cm) ; - CHOLMOD(free_dense) (&Ework, cm) ; - } - - CHOLMOD(free_sparse) (&Bset, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - - /* turn memory tests back on, where we left off ] */ - my_tries = save3 ; - - CHOLMOD(free_sparse) (&I, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&Lo, cm) ; - CHOLMOD(free_sparse) (&Up, cm) ; - CHOLMOD(free_sparse) (&Lmat, cm) ; - - printf ("done testing sparse solve, maxerr so far %g\n", maxerr) ; - - /* ---------------------------------------------------------------------- */ - /* update the factorization */ - /* ---------------------------------------------------------------------- */ - - /* turn off memory tests [ */ - save3 = my_tries ; - my_tries = -1 ; - - B = rhs (A, 1, n) ; - - for (rank = 1 ; isreal && rank <= ((n < 100) ? 33 : 2) ; rank++) - { - - /* pick a random C */ - Cdense = CHOLMOD(zeros) (n, rank, CHOLMOD_REAL, cm) ; - - if (Cdense != NULL) - { - Cx = Cdense->x ; - for (k = 0 ; k < 10*rank ; k++) - { - i = nrand (n) ; /* RAND */ - j = nrand (rank) ; /* RAND */ - Cx [i+j*n] += xrand (1.) ; /* RAND */ - } - } - - C = CHOLMOD(dense_to_sparse) (Cdense, TRUE, cm) ; - CHOLMOD(free_dense) (&Cdense, cm) ; - - /* permute the rows according to L->Perm */ - Cperm = CHOLMOD(submatrix) (C, P, n, NULL, -1, TRUE, TRUE, cm) ; - - /* update */ - CHOLMOD(updown) (TRUE, Cperm, L, cm) ; - CHOLMOD(free_sparse) (&Cperm, cm) ; - - /* solve (G+C*C')x=b */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - - /* an alternative method would be to compute (G*x + C*(C'*x) - b) */ - - /* compute S = G+C*C', with no sort */ - Ct = CHOLMOD(transpose) (C, 1, cm) ; - CC = CHOLMOD(ssmult) (C, Ct, 0, TRUE, FALSE, cm) ; - S = CHOLMOD(add) (G, CC, one, one, TRUE, TRUE, cm) ; - Ssym = CHOLMOD(copy) (S, 1, 1, cm) ; - CHOLMOD(free_sparse) (&CC, cm) ; - CHOLMOD(free_sparse) (&Ct, cm) ; - - /* compute norm (S*x-b) */ - r = resid (Ssym, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* ------------------------------------------------------------------ */ - /* factor A+CC' from scratch, using same permutation */ - /* ------------------------------------------------------------------ */ - - if (rank == 1) - { - save = cm->nmethods ; - save2 = cm->method [0].ordering ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_GIVEN ; - L2 = CHOLMOD(analyze_p) (Ssym, P, NULL, 0, cm) ; - cm->nmethods = save ; - cm->method [0].ordering = save2 ; - CHOLMOD(factorize) (Ssym, L2, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L2, B, cm) ; - r = resid (Ssym, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_factor) (&L2, cm) ; - } - - CHOLMOD(free_sparse) (&Ssym, cm) ; - - /* ------------------------------------------------------------------ */ - /* downdate, with just the first half of C */ - /* ------------------------------------------------------------------ */ - - csize = MAX (1, rank / 2) ; - cset = CHOLMOD(malloc) (csize, sizeof (Int), cm) ; - if (cset != NULL) - { - for (i = 0 ; i < csize ; i++) - { - cset [i] = i ; - } - } - C2 = CHOLMOD(submatrix) (C, NULL, -1, cset, csize, TRUE, TRUE, cm) ; - Cperm = CHOLMOD(submatrix) (C2, P, n, NULL, -1, TRUE, TRUE, cm) ; - CHOLMOD(free) (csize, sizeof (Int), cset, cm) ; - - CHOLMOD(updown) (FALSE, Cperm, L, cm) ; - CHOLMOD(free_sparse) (&Cperm, cm) ; - - /* solve (G+C*C'-C2*C2')x=b */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - - /* This is an expensive way to compute the residual. A better - * method would be to compute (G*x + C*(C'*x) - C2*(C2'*x) - b), - * using sdmult. It is done just to test the ssmult - * routine. */ - - /* compute S2 = G+C*C'-C2*C2', with no sort */ - Ct = CHOLMOD(transpose) (C2, 1, cm) ; - CC = CHOLMOD(ssmult) (C2, Ct, 0, TRUE, FALSE, cm) ; - S2 = CHOLMOD(add) (S, CC, one, minusone, TRUE, FALSE, cm) ; - CHOLMOD(free_sparse) (&CC, cm) ; - CHOLMOD(free_sparse) (&Ct, cm) ; - CHOLMOD(free_sparse) (&C2, cm) ; - - /* Ssym is a symmetric/upper copy of S2 */ - Ssym = CHOLMOD(copy) (S2, 1, 1, cm) ; - CHOLMOD(free_sparse) (&S2, cm) ; - - /* compute norm (S2*x-b) */ - r = resid (Ssym, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* ------------------------------------------------------------------ */ - /* factor S2 scratch, using same permutation */ - /* ------------------------------------------------------------------ */ - - if (rank == 1) - { - save = cm->nmethods ; - save2 = cm->method [0].ordering ; - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_GIVEN ; - L2 = CHOLMOD(analyze_p) (Ssym, P, NULL, 0, cm) ; - cm->nmethods = save ; - cm->method [0].ordering = save2 ; - CHOLMOD(factorize) (Ssym, L2, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L2, B, cm) ; - r = resid (Ssym, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_factor) (&L2, cm) ; - } - - /* ------------------------------------------------------------------ */ - /* re-do the symbolic factorization on L */ - /* ------------------------------------------------------------------ */ - - CHOLMOD(resymbol) (Ssym, NULL, 0, TRUE, L, cm) ; - - /* solve (G+C*C'-C2*C2')x=b again */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - - /* compute norm (S2*x-b) */ - r = resid (Ssym, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - CHOLMOD(free_sparse) (&Ssym, cm) ; - - /* ------------------------------------------------------------------ */ - /* downdate, with the remaining part of C, to get original L */ - /* ------------------------------------------------------------------ */ - - if (rank > csize) - { - cset = CHOLMOD(malloc) (rank-csize, sizeof (Int), cm) ; - if (cset != NULL) - { - for (i = csize ; i < rank ; i++) - { - cset [i-csize] = i ; - } - } - if (rank - csize == 4) - { - /* test the subset print/check routine */ - CHOLMOD(print_subset) (cset, rank-csize, rank, "cset", cm) ; - } - C2 = CHOLMOD(submatrix) (C, NULL, -1, cset, rank-csize, TRUE, TRUE, - cm) ; - Cperm = CHOLMOD(submatrix) (C2, P, n, NULL, -1, TRUE, TRUE, cm) ; - - CHOLMOD(free) (rank-csize, sizeof (Int), cset, cm) ; - CHOLMOD(updown) (FALSE, Cperm, L, cm) ; - CHOLMOD(free_sparse) (&Cperm, cm) ; - CHOLMOD(free_sparse) (&C2, cm) ; - - /* solve the original system */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - - /* compute the residual */ - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - } - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&S, cm) ; - } - - /* turn memory tests back on, where we left off ] */ - my_tries = save3 ; - - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - - /* ---------------------------------------------------------------------- */ - /* factor again, then change the factor type many times */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(copy_sparse) (A, cm) ; - if (C != NULL) - { - C->sorted = FALSE ; - } - L = CHOLMOD(analyze) (C, cm) ; - CHOLMOD(factorize) (C, L, cm) ; - - if (L != NULL && !(L->is_super)) - { - CHOLMOD(resymbol) (C, NULL, 0, TRUE, L, cm) ; - } - - B = rhs (C, 1, n) ; - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - cm->prefer_zomplex = FALSE ; - r = resid (C, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - for (k = 0 ; k < NFTYPES ; k++) - { - - if (co_types [k] && n > 1) - { - /* reallocate column zero of L, to make it non-monotonic */ - CHOLMOD(reallocate_column) (0, n, L, cm) ; - } - Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; - - CHOLMOD(change_factor) (Lxtype, ll_types [k], FALSE, pk_types [k], - mn_types [k], L, cm) ; - - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - cm->prefer_zomplex = FALSE ; - r = resid (C, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - } - - /* reallocate a column and solve again */ - if (n > 3) - { - CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, L, cm) ; - CHOLMOD(reallocate_column) (0, n, L, cm) ; - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - cm->prefer_zomplex = FALSE ; - r = resid (C, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - } - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - CHOLMOD(free_dense) (&Breal, cm) ; - CHOLMOD(free_dense) (&Bcomplex, cm) ; - CHOLMOD(free_dense) (&Bzomplex, cm) ; - - /* ---------------------------------------------------------------------- */ - /* factorize and solve (A*A'+beta*I)x=b or A'x=b */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0) - { - double *Rx, *Rz, *Xx, *Xz ; - double beta [2] ; - beta [0] = 3.14159 ; - beta [1] = 0 ; - L = CHOLMOD(analyze) (A, cm) ; - CHOLMOD(factorize_p) (A, beta, NULL, 0, L, cm) ; - B = rhs (A, 1, n) ; - cm->prefer_zomplex = prefer_zomplex ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - cm->prefer_zomplex = FALSE ; - - /* compute the residual */ - - /* W = A'*X */ - W = CHOLMOD(zeros) (ncol, 1, xtype, cm) ; - CHOLMOD(sdmult) (A, 2, one, zero, X, W, cm) ; - - /* R = B */ - R = CHOLMOD(copy_dense) (B, cm) ; - - /* R = A*W - R */ - CHOLMOD(sdmult) (A, 0, one, minusone, W, R, cm) ; - - /* R = R + beta*X */ - if (R != NULL && X != NULL) - { - Rx = R->x ; - Rz = R->z ; - Xx = X->x ; - Xz = X->z ; - - for (i = 0 ; i < nrow ; i++) - { - switch (xtype) - { - case CHOLMOD_REAL: - Rx [i] += beta [0] * Xx [i] ; - break ; - - case CHOLMOD_COMPLEX: - Rx [2*i ] += beta [0] * Xx [2*i ] ; - Rx [2*i+1] += beta [0] * Xx [2*i+1] ; - break ; - - case CHOLMOD_ZOMPLEX: - Rx [i] += beta [0] * Xx [i] ; - Rz [i] += beta [0] * Xz [i] ; - break ; - } - } - } - - r = CHOLMOD(norm_dense) (R, 2, cm) ; - bnorm = CHOLMOD(norm_dense) (B, 2, cm) ; - xnorm = CHOLMOD(norm_dense) (X, 2, cm) ; - norm = MAX (r, xnorm) ; - if (norm > 0) - { - r /= norm ; - } - MAXERR (maxerr, r, 1) ; - - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&R, cm) ; - CHOLMOD(free_dense) (&W, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* test rowdel and updown */ - /* ---------------------------------------------------------------------- */ - - if (isreal && A->stype == 1 && n > 0 && n < NLARGE) - { - Int save4, save5, save6 ; - save4 = cm->nmethods ; - save5 = cm->method [0].ordering ; - save6 = cm->supernodal ; - - cm->nmethods = 1 ; - cm->method [0].ordering = CHOLMOD_NATURAL ; - cm->supernodal = CHOLMOD_SUPERNODAL ; - - B = rhs (A, 1, n) ; - L = CHOLMOD(analyze) (A, cm) ; - CHOLMOD(factorize) (A, L, cm) ; - - /* solve Ax=b */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (A, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* determine the new system with row/column k missing */ - k = n/2 ; - S = CHOLMOD(copy) (A, 0, 1, cm) ; - RowK = CHOLMOD(submatrix) (S, NULL, -1, &k, 1, TRUE, TRUE, cm) ; - CHOLMOD(print_sparse) (S, "S", cm) ; - CHOLMOD(print_sparse) (RowK, "RowK of S", cm) ; - CHOLMOD(free_sparse) (&RowK, cm) ; - prune_row (S, k) ; - if (S != NULL) - { - S->stype = 1 ; - } - - /* delete row k of L (converts to LDL') */ - /* printf ("rowdel here:\n") ; */ - CHOLMOD(rowdel) (k, NULL, L, cm) ; - CHOLMOD(resymbol) (S, NULL, 0, TRUE, L, cm) ; - - /* solve with row k missing */ - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (S, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_sparse) (&S, cm) ; - - /* factorize again */ - CHOLMOD(free_factor) (&L, cm) ; - L = CHOLMOD(analyze) (A, cm) ; - CHOLMOD(factorize) (A, L, cm) ; - - /* rank-3 update (converts to LDL') and solve */ - C = CHOLMOD(speye) (n, 3, CHOLMOD_REAL, cm) ; - CC = CHOLMOD(aat) (C, NULL, 0, 1, cm) ; - S = CHOLMOD(add) (A, CC, one, one, TRUE, TRUE, cm) ; - if (S != NULL) - { - S->stype = 1 ; - } - CHOLMOD(updown) (TRUE, C, L, cm) ; - X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; - r = resid (S, X, B) ; - MAXERR (maxerr, r, 1) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* free everything */ - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_sparse) (&CC, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&S, cm) ; - CHOLMOD(free_factor) (&L, cm) ; - CHOLMOD(free_dense) (&B, cm) ; - - cm->nmethods = save4 ; - cm->method [0].ordering = save5 ; - cm->supernodal = save6 ; - } - - /* ---------------------------------------------------------------------- */ - /* free remaining workspace */ - /* ---------------------------------------------------------------------- */ - - OK (CHOLMOD(print_common) ("cm", cm)) ; - progress (0, '.') ; - return (maxerr) ; -} diff --git a/CHOLMOD/Tcov/t_amdtest.c b/CHOLMOD/Tcov/t_amdtest.c new file mode 100644 index 0000000000..866b9d1d27 --- /dev/null +++ b/CHOLMOD/Tcov/t_amdtest.c @@ -0,0 +1,375 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/amdtest: test coverage of AMD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#undef ASSERT +#include "amd.h" +#include "amd_internal.h" + +#undef FLIP +#undef UNFLIP +#undef ASSERT +#include "cm.h" + +//------------------------------------------------------------------------------ +// amdtest +//------------------------------------------------------------------------------ + +void amdtest (cholmod_sparse *A) +{ + double Control [AMD_CONTROL], Info [AMD_INFO], alpha ; + Int *P, *Cp, *Ci, *Sp, *Si, *Bp, *Bi, *Ep, *Ei, *Fp, *Fi, + *Len, *Nv, *Next, *Head, *Elen, *Deg, *Wi, *W, *Flag ; + cholmod_sparse *C, *B, *S, *E, *F ; + Int i, j, n, nrow, ncol, ok, cnz, bnz, p, trial, sorted ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + printf ("\nAMD test\n") ; + + if (A == NULL) + { + return ; + } + + if (A->stype) + { + B = CHOLMOD(copy) (A, 0, 0, cm) ; + } + else + { + B = CHOLMOD(aat) (A, NULL, 0, 0, cm) ; + } + + if (A->nrow != A->ncol) + { + F = CHOLMOD(copy_sparse) (B, cm) ; + OK (F->nrow == F->ncol) ; + CHOLMOD(sort) (F, cm) ; + } + else + { + // A is square and unsymmetric, and may have entries in A+A' that + // are not in A + F = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sort) (F, cm) ; + } + + C = CHOLMOD(copy_sparse) (B, cm) ; + + nrow = C->nrow ; + ncol = C->ncol ; + n = nrow ; + OK (nrow == ncol) ; + + Cp = C->p ; + Ci = C->i ; + + Bp = B->p ; + Bi = B->i ; + + //-------------------------------------------------------------------------- + // S = sorted form of B, using AMD_preprocess + //-------------------------------------------------------------------------- + + cnz = CHOLMOD(nnz) (C, cm) ; + S = CHOLMOD(allocate_sparse) (n, n, cnz, TRUE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + Sp = S->p ; + Si = S->i ; + + W = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Flag = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + + //-------------------------------------------------------------------------- + // allocate workspace for amd + //-------------------------------------------------------------------------- + + P = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; + + Len = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Nv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Next = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Head = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; + Elen = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Deg = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Wi = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + + //-------------------------------------------------------------------------- + + for (sorted = 0 ; sorted <= 1 ; sorted++) + { + + if (sorted) CHOLMOD(sort) (C, cm) ; + + Cp = C->p ; + Ci = C->i ; + + //---------------------------------------------------------------------- + // order C with AMD_order + //---------------------------------------------------------------------- + + AMD_defaults (Control) ; + AMD_defaults (NULL) ; + AMD_control (Control) ; + AMD_control (NULL) ; + AMD_info (NULL) ; + + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; + + // no dense rows/cols + alpha = Control [AMD_DENSE] ; + Control [AMD_DENSE] = -1 ; + AMD_control (Control) ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=-1)", cm)) ; + + // many dense rows/cols + Control [AMD_DENSE] = 0 ; + AMD_control (Control) ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (alpha=0)", cm)) ; + Control [AMD_DENSE] = alpha ; + + // no aggressive absorption + Control [AMD_AGGRESSIVE] = FALSE ; + AMD_control (Control) ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation (no agg) ", cm)) ; + Control [AMD_AGGRESSIVE] = TRUE ; + + //---------------------------------------------------------------------- + // order F with AMD_order + //---------------------------------------------------------------------- + + Fp = F->p ; + Fi = F->i ; + ok = AMD_order (n, Fp, Fi, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "F: AMD permutation", cm)) ; + + //---------------------------------------------------------------------- + // order S with AMD_order + //---------------------------------------------------------------------- + + ok = AMD_order (n, Sp, Si, P, Control, Info) ; + printf ("amd return value: "ID"\n", ok) ; + AMD_info (Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD permutation", cm)) ; + + //---------------------------------------------------------------------- + // order E with AMD_2, which destroys its contents + //---------------------------------------------------------------------- + + E = CHOLMOD(copy) (B, 0, -1, cm) ; // remove diagonal entries + bnz = CHOLMOD(nnz) (E, cm) ; + + // add the bare minimum extra space to E + ok = CHOLMOD(reallocate_sparse) (bnz + n, E, cm) ; + OK (ok) ; + Ep = E->p ; + Ei = E->i ; + + for (j = 0 ; j < n ; j++) + { + Len [j] = Ep [j+1] - Ep [j] ; + } + + printf ("calling AMD_2:\n") ; + if (n > 0) + { + AMD_2 (n, Ep, Ei, Len, E->nzmax, Ep [n], Nv, Next, P, Head, Elen, + Deg, Wi, Control, Info) ; + AMD_info (Info) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; + } + + //---------------------------------------------------------------------- + // error tests + //---------------------------------------------------------------------- + + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + ok = AMD_order (-1, Cp, Ci, P, Control, Info) ; + OK (ok == AMD_INVALID); + ok = AMD_order (0, Cp, Ci, P, Control, Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + ok = AMD_order (n, NULL, Ci, P, Control, Info) ; + OK (ok == AMD_INVALID); + ok = AMD_order (n, Cp, NULL, P, Control, Info) ; + OK (ok == AMD_INVALID); + ok = AMD_order (n, Cp, Ci, NULL, Control, Info) ; + OK (ok == AMD_INVALID); + + if (n > 0) + { + printf ("AMD error tests:\n") ; + + p = Cp [n] ; + Cp [n] = -1 ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + OK (ok == AMD_INVALID) ; + + if (SIZE_MAX/2 == Int_max) + { + Cp [n] = Int_max ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + printf ("AMD status is "ID"\n", ok) ; + OK (ok == AMD_OUT_OF_MEMORY) ; + } + + Cp [n] = p ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + if (Cp [n] > 0) + { + printf ("Mangle column zero:\n") ; + i = Ci [0] ; + Ci [0] = -1 ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + AMD_info (Info) ; + OK (ok == AMD_INVALID) ; + Ci [0] = i ; + } + } + + ok = AMD_valid (n, n, Sp, Si) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + ok = AMD_valid (-1, n, Sp, Si) ; OK (ok == AMD_INVALID) ; + ok = AMD_valid (n, -1, Sp, Si) ; OK (ok == AMD_INVALID) ; + ok = AMD_valid (n, n, NULL, Si) ; OK (ok == AMD_INVALID) ; + ok = AMD_valid (n, n, Sp, NULL) ; OK (ok == AMD_INVALID) ; + + if (n > 0 && Sp [n] > 0) + { + + p = Sp [n] ; + Sp [n] = -1 ; + ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; + Sp [n] = p ; + + p = Sp [0] ; + Sp [0] = -1 ; + ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; + Sp [0] = p ; + + p = Sp [1] ; + Sp [1] = -1 ; + ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; + Sp [1] = p ; + + i = Si [0] ; + Si [0] = -1 ; + ok = AMD_valid (n, n, Sp, Si) ; OK (ok == AMD_INVALID) ; + Si [0] = i ; + + } + + ok = AMD_valid (n, n, Sp, Si) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + ok = AMD_valid (n, n, Sp, Si) ; + OK (ok == AMD_OK) ; + + if (n > 0 && Bp [n] > 0) + { + + p = Bp [n] ; + Bp [n] = -1 ; + ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; + Bp [n] = p ; + + + p = Bp [1] ; + Bp [1] = -1 ; + ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; + Bp [1] = p ; + + i = Bi [0] ; + Bi [0] = -1 ; + ok = AMD_valid (n, n, Bp, Bi) ; OK (ok == AMD_INVALID) ; + Bi [0] = i ; + } + + AMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + + Info [AMD_STATUS] = 777 ; + AMD_info (Info) ; + + //---------------------------------------------------------------------- + // memory tests + //---------------------------------------------------------------------- + + if (n > 0) + { + + normal_memory_handler ( ) ; + + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + OK (sorted ? (ok == AMD_OK) : (ok >= AMD_OK)) ; + + test_memory_handler ( ) ; + + for (trial = 0 ; trial < 6 ; trial++) + { + my_tries = trial ; + printf ("AMD memory trial "ID"\n", trial) ; + ok = AMD_order (n, Cp, Ci, P, Control, Info) ; + AMD_info (Info) ; + OK (ok == AMD_OUT_OF_MEMORY + || (sorted ? (ok == AMD_OK) : (ok >= AMD_OK))) ; + } + normal_memory_handler ( ) ; + OK (CHOLMOD(print_perm) (P, n, n, "AMD2 permutation", cm)) ; + + } + + CHOLMOD(free_sparse) (&E, cm) ; + } + + //-------------------------------------------------------------------------- + // free everything + //-------------------------------------------------------------------------- + + CHOLMOD(free) (n, sizeof (Int), Len, cm) ; + CHOLMOD(free) (n, sizeof (Int), Nv, cm) ; + CHOLMOD(free) (n, sizeof (Int), Next, cm) ; + CHOLMOD(free) (n+1, sizeof (Int), Head, cm) ; + CHOLMOD(free) (n, sizeof (Int), Elen, cm) ; + CHOLMOD(free) (n, sizeof (Int), Deg, cm) ; + CHOLMOD(free) (n, sizeof (Int), Wi, cm) ; + CHOLMOD(free) (n+1, sizeof (Int), P, cm) ; + CHOLMOD(free) (n, sizeof (Int), W, cm) ; + CHOLMOD(free) (n, sizeof (Int), Flag, cm) ; + + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; +} + diff --git a/CHOLMOD/Tcov/t_aug.c b/CHOLMOD/Tcov/t_aug.c new file mode 100644 index 0000000000..efe8e12452 --- /dev/null +++ b/CHOLMOD/Tcov/t_aug.c @@ -0,0 +1,264 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_aug: test with an augmented system +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Create the augmented system S = [-I A' ; A alpha*I], solve Sx=b, and return +// the residual. The system solved is (alpha*I + A*A')*x=b. +// +// r1 = norm (Sx-b) +// r2 = norm ((alpha*I+AA')x-b) +// alpha = norm(A) +// +// All matrices are real, not complex/zomplex. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// aug +//------------------------------------------------------------------------------ + +double aug (cholmod_sparse *A) +{ + double r, maxerr = 0, bnorm, anorm ; + cholmod_sparse *S, *Im, *In, *At, *A1, *A2, *Sup ; + cholmod_dense *Alpha, *B, *Baug, *X, *W1, *W2, *R, *X2, X2mat, *Minus1 ; + cholmod_factor *L ; + Real *b, *baug, *rx, *w, *x ; + Int nrow, ncol, nrhs, i, j, d, d2, save, save2, save3 ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "cm: no A for aug") ; + return (1) ; + } + + if (A->xtype != CHOLMOD_REAL) + { + return (0) ; + } + + //-------------------------------------------------------------------------- + // A is m-by-n, B must be m-by-nrhs + //-------------------------------------------------------------------------- + + nrow = A->nrow ; + ncol = A->ncol ; + B = rhs (A, 5, A->nrow + 7, 0) ; + + //-------------------------------------------------------------------------- + // create scalars + //-------------------------------------------------------------------------- + + bnorm = CHOLMOD(norm_dense) (B, 0, cm) ; + anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; + + Alpha = CHOLMOD(eye) (1, 1, A->xtype + DTYPE, cm) ; + if (Alpha != NULL) + { + ((Real *) (Alpha->x)) [0] = anorm ; + } + + Minus1 = CHOLMOD(zeros) (1, 1, A->xtype + DTYPE, cm) ; + if (Minus1 != NULL) + { + ((Real *) (Minus1->x)) [0] = -1 ; + } + + CHOLMOD(print_dense) (Minus1, "MinusOne", cm) ; + CHOLMOD(print_dense) (Alpha, "Alpha = norm(A)", cm) ; + + //-------------------------------------------------------------------------- + // create augmented system, S = [-I A' ; A anorm*I] + //-------------------------------------------------------------------------- + + Im = CHOLMOD(speye) (nrow, nrow, A->xtype + DTYPE, cm) ; + In = CHOLMOD(speye) (ncol, ncol, A->xtype + DTYPE, cm) ; + CHOLMOD(scale) (Alpha, CHOLMOD_SCALAR, Im, cm) ; + CHOLMOD(scale) (Minus1, CHOLMOD_SCALAR, In, cm) ; + At = CHOLMOD(transpose) (A, 2, cm) ; + + // use one of two equivalent methods + if (nrow % 2) + { + // S = [[-In A'] ; [A alpha*Im]] + A1 = CHOLMOD(horzcat) (In, At, TRUE, cm) ; + A2 = CHOLMOD(horzcat) (A, Im, TRUE, cm) ; + S = CHOLMOD(vertcat) (A1, A2, TRUE, cm) ; + } + else + { + // S = [[-In ; A] [A' ; alpha*Im]] + A1 = CHOLMOD(vertcat) (In, A, TRUE, cm) ; + A2 = CHOLMOD(vertcat) (At, Im, TRUE, cm) ; + S = CHOLMOD(horzcat) (A1, A2, TRUE, cm) ; + } + + CHOLMOD(free_sparse) (&Im, cm) ; + CHOLMOD(free_sparse) (&In, cm) ; + + CHOLMOD(print_sparse) (S, "S, augmented system", cm) ; + + // make a symmetric (upper) copy of S + Sup = CHOLMOD(copy) (S, 1, 1, cm) ; + + CHOLMOD(print_sparse) (S, "S, augmented system (upper)", cm) ; + CHOLMOD(print_sparse) (Sup, "Sup", cm) ; + + //-------------------------------------------------------------------------- + // create augmented right-hand-side, Baug = [ zeros(ncol,nrhs) ; B ] + //-------------------------------------------------------------------------- + + b = NULL ; + d = 0 ; + nrhs = 0 ; + d2 = 0 ; + if (B != NULL) + { + nrhs = B->ncol ; + d = B->d ; + b = B->x ; + Baug = CHOLMOD(zeros) (nrow+ncol, nrhs, A->xtype + DTYPE, cm) ; + if (Baug != NULL) + { + d2 = Baug->d ; + baug = Baug->x ; + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < nrow ; i++) + { + baug [(i+ncol)+j*d2] = b [i+j*d] ; + } + } + } + } + else + { + Baug = NULL ; + } + + //-------------------------------------------------------------------------- + // solve Sx=baug + //-------------------------------------------------------------------------- + + // S is symmetric indefinite, so do not use a supernodal LL' + save = cm->supernodal ; + save2 = cm->final_asis ; + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_asis = TRUE ; + save3 = cm->metis_memory ; + cm->metis_memory = 2.0 ; + L = CHOLMOD(analyze) (Sup, cm) ; + CHOLMOD(factorize) (Sup, L, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, L, Baug, cm) ; + cm->supernodal = save ; + cm->final_asis = save2 ; + cm->metis_memory = save3 ; + + //-------------------------------------------------------------------------- + // compute the residual + //-------------------------------------------------------------------------- + + r = resid (Sup, X, Baug) ; + MAXERR (maxerr, r, 1) ; + + //-------------------------------------------------------------------------- + // create a shallow submatrix of X, X2 = X (ncol:end, :) + //-------------------------------------------------------------------------- + + if (X == NULL) + { + X2 = NULL ; + } + else + { + X2 = &X2mat ; + X2->nrow = nrow ; + X2->ncol = nrhs ; + X2->nzmax = X->nzmax ; + X2->d = X->d ; + X2->x = ((Real *) X->x) + ncol ; + X2->z = NULL ; + X2->xtype = X->xtype ; + X2->dtype = X->dtype ; + } + + CHOLMOD(print_dense) (X, "X", cm) ; + CHOLMOD(print_dense) (X2, "X2 = X (ncol:end,:)", cm) ; + + //-------------------------------------------------------------------------- + // compute norm ((alpha*I + A*A')*x-b) + //-------------------------------------------------------------------------- + + // W1 = A'*X2 + W1 = CHOLMOD(zeros) (ncol, nrhs, A->xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A, TRUE, one, zero, X2, W1, cm) ; + + // W2 = A*W1 + W2 = CHOLMOD(zeros) (nrow, nrhs, A->xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A, FALSE, one, zero, W1, W2, cm) ; + + // R = alpha*x + w2 - b + R = CHOLMOD(zeros) (nrow, nrhs, A->xtype + DTYPE, cm) ; + + if (R != NULL && W2 != NULL && X != NULL) + { + w = W2->x ; + rx = R->x ; + x = X2->x ; + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < nrow ; i++) + { + rx [i+j*nrow] = anorm * x [i+j*d2] + w [i+j*nrow] - b [i+j*d] ; + } + } + } + + double xnorm = CHOLMOD(norm_dense) (X2, 1, cm) ; + r = CHOLMOD(norm_dense) (R, 1, cm) ; + + double rcond = CHOLMOD(rcond) (L, cm) ; + if (cm->print > 1) + { + printf ("rcond in aug.c: %g, r: %g\n", rcond, r) ; + } + #ifdef DOUBLE + bool rcond_ok = rcond > 1e-6 ; + #else + bool rcond_ok = rcond > 1e-3 ; + #endif + + if (rcond_ok) + { + MAXERR (maxerr, r, (anorm*anorm)*xnorm + bnorm) ; + } + + //-------------------------------------------------------------------------- + // free everything + //-------------------------------------------------------------------------- + + CHOLMOD(free_sparse) (&At, cm) ; + CHOLMOD(free_sparse) (&A1, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&Sup, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_dense) (&R, cm) ; + CHOLMOD(free_dense) (&W1, cm) ; + CHOLMOD(free_dense) (&W2, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free_dense) (&Baug, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Alpha, cm) ; + CHOLMOD(free_dense) (&Minus1, cm) ; + + progress (0, '.') ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_basic.c b/CHOLMOD/Tcov/t_basic.c new file mode 100644 index 0000000000..177a358e6d --- /dev/null +++ b/CHOLMOD/Tcov/t_basic.c @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_basic: basic tests +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cm.h" + +void basic1 (cholmod_common *cm) +{ + + //-------------------------------------------------------------------------- + // hypot and divcomplex + //-------------------------------------------------------------------------- + + double maxerr = 0 ; + double ax = 4.3 ; + double az = 9.2 ; + double bx, bz, cx, cz ; + int bzero ; + + for (Int i = 0 ; i <= 1 ; i++) + { + if (i == 0) + { + bx = 3.14159 ; + bz = -1.2 ; + } + else + { + bx = 0.9 ; + bz = -1.2 ; + } + + // c = a/b + bzero = CHOLMOD(divcomplex)(ax, az, bx, bz, &cx, &cz) ; + OK (!bzero) ; + // d = c*b + double dx = cx * bx - cz * bz ; + double dz = cz * bx + cx * bz ; + // e = d-a, which should be zero + double fx = dx - ax ; + double fz = dz - az ; + // r = hypot (fx,fz) + double r = CHOLMOD(hypot)(fx, fz) ; + MAXERR (maxerr, r, 1) ; + OK (r < 1e-14) ; + + // c = a/b using SuiteSparse_divcomplex + cx = 0 ; + cz = 0 ; + bzero = SuiteSparse_divcomplex (ax, az, bx, bz, &cx, &cz) ; + OK (!bzero) ; + // d = c*b + dx = cx * bx - cz * bz ; + dz = cz * bx + cx * bz ; + // e = d-a, which should be zero + fx = dx - ax ; + fz = dz - az ; + // r = hypot (fx,fz) + r = SuiteSparse_hypot (fx, fz) ; + MAXERR (maxerr, r, 1) ; + OK (r < 1e-14) ; + } + + printf ("basic1: %g\n", maxerr) ; + + // divide by zero + bx = 0 ; + bz = 0 ; + bzero = CHOLMOD(divcomplex)(ax, az, bx, bz, &cx, &cz) ; + OK (bzero) ; + printf ("c: %g %g\n", cx, cz) ; + OK (isinf (cx)) ; + OK (isinf (cz)) ; + + bzero = SuiteSparse_divcomplex (ax, az, bx, bz, &cx, &cz) ; + OK (bzero) ; + printf ("c: %g %g\n", cx, cz) ; + OK (isinf (cx)) ; + OK (isinf (cz)) ; + + // zero divided by zero + ax = 0 ; + az = 0 ; + + bzero = CHOLMOD(divcomplex)(ax, az, bx, bz, &cx, &cz) ; + OK (bzero) ; + printf ("c: %g %g\n", cx, cz) ; + OK (isnan (cx)) ; + + bzero = SuiteSparse_divcomplex (ax, az, bx, bz, &cx, &cz) ; + OK (bzero) ; + printf ("c: %g %g\n", cx, cz) ; + OK (isnan (cx)) ; + + //-------------------------------------------------------------------------- + // descendant score + //-------------------------------------------------------------------------- + + struct cholmod_descendant_score_t s1, s2 ; + s1.d = 0 ; + s2.d = 0 ; + for (int k1 = -4 ; k1 < 4 ; k1++) + { + s1.score = (double) k1 ; + for (int k2 = -4 ; k2 < 4 ; k2++) + { + s2.score = (double) k2 ; + int result = CHOLMOD(score_comp) (&s1, &s2) ; + OK (result == (k1 < k2) ? 1 : -1) ; + } + } +} + diff --git a/CHOLMOD/Tcov/t_camdtest.c b/CHOLMOD/Tcov/t_camdtest.c new file mode 100644 index 0000000000..9ed047651c --- /dev/null +++ b/CHOLMOD/Tcov/t_camdtest.c @@ -0,0 +1,412 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_camdtest: test of CAMD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#undef ASSERT +#include "cm.h" +#undef FLIP +#undef UNFLIP + +#undef ASSERT +#ifndef NCAMD +#include "camd.h" +#include "camd_internal.h" + +//------------------------------------------------------------------------------ +// camdtest +//------------------------------------------------------------------------------ + +void camdtest (cholmod_sparse *A) +{ + double Control [CAMD_CONTROL], Info [CAMD_INFO], alpha ; + Int *P, *Cp, *Ci, *Sp, *Si, *Bp, *Bi, *Ep, *Ei, *Fp, *Fi, + *Len, *Nv, *Next, *Head, *Elen, *Deg, *Wi, *W, *Flag, *BucketSet, + *Constraint ; + cholmod_sparse *C, *B, *S, *E, *F ; + Int i, j, n, nrow, ncol, ok, cnz, bnz, p, trial, sorted ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + printf ("\nCAMD test\n") ; + + if (A == NULL) + { + return ; + } + + if (A->stype) + { + B = CHOLMOD(copy) (A, 0, 0, cm) ; + } + else + { + B = CHOLMOD(aat) (A, NULL, 0, 0, cm) ; + } + + if (A->nrow != A->ncol) + { + F = CHOLMOD(copy_sparse) (B, cm) ; + OK (F->nrow == F->ncol) ; + CHOLMOD(sort) (F, cm) ; + } + else + { + // A is square and unsymmetric, and may have entries in A+A' that + // are not in A + F = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sort) (F, cm) ; + } + + C = CHOLMOD(copy_sparse) (B, cm) ; + + nrow = C->nrow ; + ncol = C->ncol ; + n = nrow ; + OK (nrow == ncol) ; + + Cp = C->p ; + Ci = C->i ; + + Bp = B->p ; + Bi = B->i ; + + //-------------------------------------------------------------------------- + // S = sorted form of B, using CAMD_preprocess + //-------------------------------------------------------------------------- + + cnz = CHOLMOD(nnz) (C, cm) ; + S = CHOLMOD(allocate_sparse) (n, n, cnz, TRUE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + Sp = S->p ; + Si = S->i ; + + W = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Flag = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + + //-------------------------------------------------------------------------- + // allocate workspace for camd + //-------------------------------------------------------------------------- + + P = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; + Constraint = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + for (i = 0 ; i < n ; i++) + { + Constraint [i] = my_rand () % (MIN (n,6)) ; + } + + ok = CAMD_cvalid (n, Constraint) ; OK (ok) ; + if (n > 0) + { + Constraint [0] = -1 ; + ok = CAMD_cvalid (n, Constraint) ; OK (!ok) ; + Constraint [0] = 0 ; + } + ok = CAMD_cvalid (n, Constraint) ; OK (ok) ; + ok = CAMD_cvalid (n, NULL) ; OK (ok) ; + + Len = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Nv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Next = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Head = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; + Elen = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Deg = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Wi = CHOLMOD(malloc) (n+1, sizeof (Int), cm) ; + BucketSet = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + + //-------------------------------------------------------------------------- + + for (sorted = 0 ; sorted <= 1 ; sorted++) + { + + if (sorted) CHOLMOD(sort) (C, cm) ; + + Cp = C->p ; + Ci = C->i ; + + //---------------------------------------------------------------------- + // order C with CAMD_order + //---------------------------------------------------------------------- + + CAMD_defaults (Control) ; + CAMD_defaults (NULL) ; + CAMD_control (Control) ; + CAMD_control (NULL) ; + CAMD_info (NULL) ; + + ok = CAMD_order (n, Cp, Ci, P, Control, Info, Constraint) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; + + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; + + // no dense rows/cols + alpha = Control [CAMD_DENSE] ; + Control [CAMD_DENSE] = -1 ; + CAMD_control (Control) ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (alpha=-1)", cm)) ; + + // many dense rows/cols + Control [CAMD_DENSE] = 0 ; + CAMD_control (Control) ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (alpha=0)", cm)) ; + Control [CAMD_DENSE] = alpha ; + + // no aggressive absorption + Control [CAMD_AGGRESSIVE] = FALSE ; + CAMD_control (Control) ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation (no agg) ", cm)) ; + Control [CAMD_AGGRESSIVE] = TRUE ; + + //---------------------------------------------------------------------- + // order F with CAMD_order + //---------------------------------------------------------------------- + + Fp = F->p ; + Fi = F->i ; + ok = CAMD_order (n, Fp, Fi, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "F: CAMD permutation", cm)) ; + + //---------------------------------------------------------------------- + // order S with CAMD_order + //---------------------------------------------------------------------- + + ok = CAMD_order (n, Sp, Si, P, Control, Info, NULL) ; + printf ("camd return value: "ID"\n", ok) ; + CAMD_info (Info) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD permutation", cm)) ; + + //---------------------------------------------------------------------- + // order E with CAMD_2, which destroys its contents + //---------------------------------------------------------------------- + + E = CHOLMOD(copy) (B, 0, -1, cm) ; // remove diagonal entries + bnz = CHOLMOD(nnz) (E, cm) ; + + // add the bare minimum extra space to E + ok = CHOLMOD(reallocate_sparse) (bnz + n, E, cm) ; + OK (ok) ; + Ep = E->p ; + Ei = E->i ; + + for (j = 0 ; j < n ; j++) + { + Len [j] = Ep [j+1] - Ep [j] ; + } + + printf ("calling CAMD_2:\n") ; + if (n > 0) + { + CAMD_2 (n, Ep, Ei, Len, E->nzmax, Ep [n], Nv, Next, P, Head, Elen, + Deg, Wi, NULL, Info, NULL, BucketSet) ; + CAMD_info (Info) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD2 permutation", cm)) ; + } + + //---------------------------------------------------------------------- + // error tests + //---------------------------------------------------------------------- + + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + ok = CAMD_order (-1, Cp, Ci, P, Control, Info, NULL) ; + OK (ok == CAMD_INVALID); + ok = CAMD_order (0, Cp, Ci, P, Control, Info, NULL) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + ok = CAMD_order (n, NULL, Ci, P, Control, Info, NULL) ; + OK (ok == CAMD_INVALID); + ok = CAMD_order (n, Cp, NULL, P, Control, Info, NULL) ; + OK (ok == CAMD_INVALID); + ok = CAMD_order (n, Cp, Ci, NULL, Control, Info, NULL) ; + OK (ok == CAMD_INVALID); + + if (n > 0) + { + printf ("CAMD error tests:\n") ; + + p = Cp [n] ; + Cp [n] = -1 ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + OK (ok == CAMD_INVALID) ; + + if (SIZE_MAX/2 == Int_max) + { + Cp [n] = Int_max ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + printf ("CAMD status is "ID"\n", ok) ; + OK (ok == CAMD_OUT_OF_MEMORY) ; + } + + Cp [n] = p ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + if (Cp [n] > 0) + { + printf ("Mangle column zero:\n") ; + i = Ci [0] ; + Ci [0] = -1 ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + CAMD_info (Info) ; + OK (ok == CAMD_INVALID) ; + Ci [0] = i ; + } + } + + ok = CAMD_valid (n, n, Sp, Si) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + ok = CAMD_valid (-1, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; + ok = CAMD_valid (n, -1, Sp, Si) ; OK (ok == CAMD_INVALID) ; + ok = CAMD_valid (n, n, NULL, Si) ; OK (ok == CAMD_INVALID) ; + ok = CAMD_valid (n, n, Sp, NULL) ; OK (ok == CAMD_INVALID) ; + + if (n > 0 && Sp [n] > 0) + { + + p = Sp [n] ; + Sp [n] = -1 ; + ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; + Sp [n] = p ; + + p = Sp [0] ; + Sp [0] = -1 ; + ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; + Sp [0] = p ; + + p = Sp [1] ; + Sp [1] = -1 ; + ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; + Sp [1] = p ; + + i = Si [0] ; + Si [0] = -1 ; + ok = CAMD_valid (n, n, Sp, Si) ; OK (ok == CAMD_INVALID) ; + Si [0] = i ; + + } + + ok = CAMD_valid (n, n, Sp, Si) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + ok = CAMD_valid (n, n, Sp, Si) ; + OK (ok == CAMD_OK) ; + + if (n > 0 && Bp [n] > 0) + { + + p = Bp [n] ; + Bp [n] = -1 ; + ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; + Bp [n] = p ; + + + p = Bp [1] ; + Bp [1] = -1 ; + ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; + Bp [1] = p ; + + i = Bi [0] ; + Bi [0] = -1 ; + ok = CAMD_valid (n, n, Bp, Bi) ; OK (ok == CAMD_INVALID) ; + Bi [0] = i ; + } + + CAMD_preprocess (n, Bp, Bi, Sp, Si, W, Flag) ; + + Info [CAMD_STATUS] = 777 ; + CAMD_info (Info) ; + + //---------------------------------------------------------------------- + // memory tests + //---------------------------------------------------------------------- + + if (n > 0) + { + + normal_memory_handler ( ) ; + + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + OK (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK)) ; + + test_memory_handler ( ) ; + + for (trial = 0 ; trial < 6 ; trial++) + { + my_tries = trial ; + printf ("CAMD memory trial "ID"\n", trial) ; + ok = CAMD_order (n, Cp, Ci, P, Control, Info, NULL) ; + CAMD_info (Info) ; + OK (ok == CAMD_OUT_OF_MEMORY + || (sorted ? (ok == CAMD_OK) : (ok >= CAMD_OK))) ; + } + normal_memory_handler ( ) ; + OK (CHOLMOD(print_perm) (P, n, n, "CAMD2 permutation", cm)) ; + + } + + CHOLMOD(free_sparse) (&E, cm) ; + } + + //-------------------------------------------------------------------------- + // free everything + //-------------------------------------------------------------------------- + + CHOLMOD(free) (n, sizeof (Int), Len, cm) ; + CHOLMOD(free) (n, sizeof (Int), Nv, cm) ; + CHOLMOD(free) (n, sizeof (Int), Next, cm) ; + CHOLMOD(free) (n+1, sizeof (Int), Head, cm) ; + CHOLMOD(free) (n, sizeof (Int), Elen, cm) ; + CHOLMOD(free) (n, sizeof (Int), Deg, cm) ; + CHOLMOD(free) (n+1, sizeof (Int), Wi, cm) ; + CHOLMOD(free) (n, sizeof (Int), BucketSet, cm) ; + CHOLMOD(free) (n+1, sizeof (Int), P, cm) ; + CHOLMOD(free) (n, sizeof (Int), Constraint, cm) ; + CHOLMOD(free) (n, sizeof (Int), W, cm) ; + CHOLMOD(free) (n, sizeof (Int), Flag, cm) ; + + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; +} + +#else + +void camdtest (cholmod_sparse *A) +{ + if (A == NULL) + { + return ; + } +} +#endif + diff --git a/CHOLMOD/Tcov/t_cat_tests.c b/CHOLMOD/Tcov/t_cat_tests.c new file mode 100644 index 0000000000..ace098cf95 --- /dev/null +++ b/CHOLMOD/Tcov/t_cat_tests.c @@ -0,0 +1,263 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_cat_tests: horzcat and vertcat tests +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +double cat_tests (cholmod_sparse *A_input, cholmod_common *cm) +{ + + if (!A_input) return (-1) ; + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + int xtype = A_input->xtype ; + double maxerr = 0 ; + double alpha [2] = {3.14158, 2.12345} ; + cholmod_sparse *C1, *C2, *C3, *C4, *T1, *T2, *E, *G = NULL ; + + //-------------------------------------------------------------------------- + // create test matrices + //-------------------------------------------------------------------------- + + cholmod_sparse *A = CHOLMOD(copy_sparse) (A_input, cm) ; + cholmod_sparse *S = CHOLMOD(copy) (A, 0, 0, cm) ; + double anorm = CHOLMOD(norm_sparse) (A, 0, cm) ; + cholmod_sparse *T = CHOLMOD(copy_sparse) (S, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, T, cm) ; + + Int *rset = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Int *cset = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + if (rset != NULL && cset != NULL) + { + // rset = 0:nrow-1 + for (Int k = 0 ; k < nrow ; k++) + { + rset [k] = k ; + } + // cset = 0:ncol-1 + for (Int k = 0 ; k < ncol ; k++) + { + cset [k] = k ; + } + } + + //-------------------------------------------------------------------------- + // basic horzcat tests: no scaling, no change of stype + //-------------------------------------------------------------------------- + + // C1 = [A A] + C1 = CHOLMOD(horzcat) (A, A, 2, cm) ; + + // C3 = [A' ; A']' + T1 = CHOLMOD(transpose) (A, 2, cm) ; + C2 = CHOLMOD(vertcat) (T1, T1, 2, cm) ; + C3 = CHOLMOD(transpose) (C2, 2, cm) ; + + // E = C1-C3 + E = CHOLMOD(add) (C1, C3, one, minusone, 2, true, cm) ; + double cnorm = CHOLMOD(norm_sparse) (C1, 0, cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, cnorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + // G = C1 (0:nrow-1, 0:ncol-1) + G = CHOLMOD(submatrix) (C1, rset, nrow, cset, ncol, 2, true, cm) ; + + // E = A-G + E = CHOLMOD(add) (A, G, one, minusone, 2, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + // G = C1 (:, 0:ncol-1) + G = CHOLMOD(submatrix) (C1, NULL, -1, cset, ncol, 2, true, cm) ; + + // E = A-G + E = CHOLMOD(add) (A, G, one, minusone, 2, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + //-------------------------------------------------------------------------- + // submatrix: pattern + //-------------------------------------------------------------------------- + + // S1 = [S A] + cholmod_sparse *S1 = CHOLMOD(horzcat) (S, A, 2, cm) ; + if (S1 != NULL) { OK (S1->stype == CHOLMOD_PATTERN) ; } ; + + // G = S1 (0:nrow-1, 0:ncol-1) + G = CHOLMOD(submatrix) (S1, rset, nrow, cset, ncol, 2, true, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, G, cm) ; + + // E = T-G + E = CHOLMOD(add) (T, G, one, minusone, 1, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + // G = S1 (:, 0:ncol-1) + G = CHOLMOD(submatrix) (S1, NULL, -1, cset, ncol, 2, true, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, G, cm) ; + + // E = T-G + E = CHOLMOD(add) (T, G, one, minusone, 1, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + CHOLMOD(free_sparse) (&S1, cm) ; + + // free matrices + + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + CHOLMOD(free_sparse) (&T1, cm) ; + + //-------------------------------------------------------------------------- + // basic vertcat tests: no scaling, no change of stype + //-------------------------------------------------------------------------- + + // C1 = [A ; A] + C1 = CHOLMOD(vertcat) (A, A, 2, cm) ; + + // C3 = [A' A']' + T1 = CHOLMOD(transpose) (A, 2, cm) ; + C2 = CHOLMOD(horzcat) (T1, T1, 2, cm) ; + C3 = CHOLMOD(transpose) (C2, 2, cm) ; + + // E = C1-C3 + E = CHOLMOD(add) (C1, C3, one, minusone, 2, true, cm) ; + cnorm = CHOLMOD(norm_sparse) (C1, 0, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, cnorm) ; + + // free matrices + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + CHOLMOD(free_sparse) (&T1, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + //-------------------------------------------------------------------------- + // scaled tests + //-------------------------------------------------------------------------- + + for (int values = 0 ; values <= 1 ; values++) + { + + // A1 = unsymmetric form of A + cholmod_sparse *A1 = CHOLMOD(copy) (A, 0, values, cm) ; + + // B = sparse (nrow,ncol) + cholmod_sparse *B = CHOLMOD(spzeros) (nrow, ncol, 1, xtype + DTYPE, + cm) ; + + // A2 = alpha*A1 + B + cholmod_sparse *A2 = CHOLMOD(add) (A1, B, alpha, zero, values, true, + cm) ; + + // C1 = [A1 A2] + C1 = CHOLMOD(horzcat) (A1, A2, values, cm) ; + + int mode = values ? 2 : 0 ; + + // C3 = [A1' ; A2']' + T1 = CHOLMOD(transpose) (A1, mode, cm) ; + T2 = CHOLMOD(transpose) (A2, mode, cm) ; + C2 = CHOLMOD(vertcat) (T1, T2, values, cm) ; + C3 = CHOLMOD(transpose) (C2, mode, cm) ; + + if (!values) + { + // convert C1 and C3 to binary + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, C1, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, C3, cm) ; + } + + // E = C1-C3 + E = CHOLMOD(add) (C1, C3, one, minusone, true, true, cm) ; + cnorm = CHOLMOD(norm_sparse) (C1, 0, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, cnorm) ; + + // free matrices + CHOLMOD(free_sparse) (&A1, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + CHOLMOD(free_sparse) (&T1, cm) ; + CHOLMOD(free_sparse) (&T2, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + } + + //-------------------------------------------------------------------------- + // submatrix: symmetric upper + //-------------------------------------------------------------------------- + + // C1 = [I1 A] + cholmod_sparse *I1 = CHOLMOD(speye) (nrow, nrow, xtype + DTYPE, cm) ; + C1 = CHOLMOD(horzcat) (I1, A, 2, cm) ; + CHOLMOD(free_sparse) (&I1, cm) ; + + // C2 = [0 I2] + cholmod_sparse *Z = CHOLMOD(spzeros) (ncol, nrow, 0, xtype + DTYPE, cm) ; + cholmod_sparse *I2 = CHOLMOD(speye) (ncol, ncol, xtype + DTYPE, cm) ; + C2 = CHOLMOD(horzcat) (Z, I2, 2, cm) ; + CHOLMOD(free_sparse) (&Z, cm) ; + CHOLMOD(free_sparse) (&I2, cm) ; + + // C3 = [C1 ; C2] + C3 = CHOLMOD(vertcat) (C1, C2, 2, cm) ; + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + + // C4 = symmetric upper copy of C3 + C4 = CHOLMOD(copy) (C3, 1, 2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + if (C4 != NULL) { OK (C4->stype == 1) ; } ; + + if (cset != NULL) + { + // cset = nrow:(nrow+ncol-1) + for (Int k = 0 ; k < ncol ; k++) + { + cset [k] = k + nrow ; + } + } + + // G = C4 (0:nrow-1, nrow:(nrow+ncol-1)) + G = CHOLMOD(submatrix) (C4, rset, nrow, cset, ncol, 2, true, cm) ; + CHOLMOD(free_sparse) (&C4, cm) ; + + // E = A-G + E = CHOLMOD(add) (A, G, one, minusone, 2, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and return result + //-------------------------------------------------------------------------- + + CHOLMOD(free) (nrow, sizeof (Int), rset, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), cset, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&T, cm) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_cctest.c b/CHOLMOD/Tcov/t_cctest.c new file mode 100644 index 0000000000..750dd6becb --- /dev/null +++ b/CHOLMOD/Tcov/t_cctest.c @@ -0,0 +1,400 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_cctest: test for CCOLAMD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cm.h" + +#ifndef NCAMD +#include "ccolamd.h" + +//------------------------------------------------------------------------------ +// check_constraints +//------------------------------------------------------------------------------ + +// Check to see if P obeys the constraints +Int check_constraints (Int *P, Int *Cmember, Int n) +{ + Int c, clast, k, i ; + if ((P == NULL) || !CHOLMOD(print_perm) (P, n, n, "ccolamd perm", cm)) + { + printf ("cctest: Perm is bad\n") ; + return (FALSE) ; + } + clast = EMPTY ; + for (k = 0 ; k < n ; k++) + { + i = P [k] ; + c = Cmember [i] ; + if (c < clast) + { + printf ("cctest: constraints are incorrect\n") ; + return (FALSE) ; + } + clast = c ; + } + return (TRUE) ; +} + +//------------------------------------------------------------------------------ +// cctest +//------------------------------------------------------------------------------ + +void cctest (cholmod_sparse *A) +{ + + double knobs [CCOLAMD_KNOBS], knobs2 [CCOLAMD_KNOBS] ; + Int *P, *Cmember, *Cp, *Ci, *Front_npivcol, *Front_nrows, *Front_ncols, + *Front_parent, *Front_cols, *InFront, *Si, *Sp ; + cholmod_sparse *C, *A2, *B, *S ; + Int nrow, ncol, alen, ok, stats [CCOLAMD_STATS], csets, i, nfr, c, p ; + size_t s ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + my_srand (42) ; // RAND reset + + printf ("\nCCOLAMD test\n") ; + + if (A == NULL) + { + return ; + } + + if (A->stype) + { + A2 = CHOLMOD(copy) (A, 0, 0, cm) ; + B = A2 ; + } + else + { + A2 = NULL ; + B = A ; + } + S = CHOLMOD(copy_sparse) (A, cm) ; + + nrow = B->nrow ; + ncol = B->ncol ; + Si = S->i ; + Sp = S->p ; + + //-------------------------------------------------------------------------- + // allocate workspace and Cmember for ccolamd + //-------------------------------------------------------------------------- + + P = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Front_npivcol = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + Front_nrows = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + Front_ncols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + Front_parent = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + Front_cols = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + InFront = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + + csets = MIN (6, nrow) ; + for (i = 0 ; i < nrow ; i++) + { + Cmember [i] = nrand (csets) ; + } + + CCOLAMD_set_defaults (knobs) ; + CCOLAMD_set_defaults (knobs2) ; + CCOLAMD_set_defaults (NULL) ; + CCOLAMD_report (NULL) ; + CSYMAMD_report (NULL) ; + + alen = CCOLAMD_recommended (B->nzmax, ncol, nrow) ; + C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + Cp = C->p ; + Ci = C->i ; + + //-------------------------------------------------------------------------- + // order with ccolamd + //-------------------------------------------------------------------------- + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; + CHOLMOD(print_sparse) (C, "C for ccolamd", cm) ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, NULL, stats, Cmember) ; + CCOLAMD_report (stats) ; + OK (ok) ; + ok = stats [CCOLAMD_STATUS] ; + ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ; + OK (ok) ; + + // permutation returned in C->p, if the ordering succeeded + // make sure P obeys the constraints + OK (check_constraints (Cp, Cmember, nrow)) ; + + //-------------------------------------------------------------------------- + // order with ccolamd2 + //-------------------------------------------------------------------------- + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; + ok = CCOLAMD_2 (ncol, nrow, alen, Ci, Cp, NULL, stats, + Front_npivcol, Front_nrows, Front_ncols, Front_parent, + Front_cols, &nfr, InFront, Cmember) ; + CCOLAMD_report (stats) ; + OK (check_constraints (Cp, Cmember, nrow)) ; + + //-------------------------------------------------------------------------- + // with a small dense-row threshold + //-------------------------------------------------------------------------- + + knobs2 [CCOLAMD_DENSE_ROW] = 0 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; + CCOLAMD_report (stats) ; + + knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; + knobs2 [CCOLAMD_DENSE_COL] = 0 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; + CCOLAMD_report (stats) ; + + knobs2 [CCOLAMD_DENSE_ROW] = 0.625 ; + knobs2 [CCOLAMD_DENSE_COL] = -1 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; OK (ok) ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; + CCOLAMD_report (stats) ; + + knobs2 [CCOLAMD_DENSE_COL] = 0 ; + + //-------------------------------------------------------------------------- + // duplicate entries + //-------------------------------------------------------------------------- + + if (ncol > 2 && nrow > 2) + { + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + if (Cp [1] - Cp [0] > 2) + { + Ci [0] = Ci [1] ; + } + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats, Cmember) ; + CCOLAMD_report (stats) ; + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "ccolamd perm", cm)) ; + } + + //-------------------------------------------------------------------------- + // csymamd + //-------------------------------------------------------------------------- + + if (nrow == ncol) + { + Int n = nrow ; + + void * (*calloc_func) (size_t, size_t) ; + void (*free_func) (void *) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; + OK (ok) ; + OK (check_constraints (P, Cmember, n)) ; + CSYMAMD_report (stats) ; + + //---------------------------------------------------------------------- + // csymamd errors + //---------------------------------------------------------------------- + + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, NULL, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + + ok = CSYMAMD_MAIN (n, NULL, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + + ok = CSYMAMD_MAIN (n, Si, NULL, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + + ok = CSYMAMD_MAIN (-1, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + + p = Sp [n] ; + Sp [n] = -1 ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + Sp [n] = p ; + + Sp [0] = -1 ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + Sp [0] = 0 ; + + if (n > 2 && Sp [n] > 3) + { + p = Sp [1] ; + Sp [1] = -1 ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + Sp [1] = p ; + + i = Si [0] ; + Si [0] = -1 ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; NOT (ok); + CSYMAMD_report (stats) ; + Si [0] = i ; + + // ok, but jumbled + i = Si [0] ; + Si [0] = Si [1] ; + Si [1] = i ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; OK (ok); + CSYMAMD_report (stats) ; + i = Si [0] ; + Si [0] = Si [1] ; + Si [1] = i ; + + test_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + ok = CSYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, + free_func, + Cmember, A->stype) ; + NOT (ok) ; + CSYMAMD_report (stats) ; + normal_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + } + } + + //-------------------------------------------------------------------------- + // error tests + //-------------------------------------------------------------------------- + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + ok = CCOLAMD_MAIN (ncol, nrow, 0, Ci, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CCOLAMD_MAIN (ncol, nrow, alen, NULL, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, NULL, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, NULL, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CCOLAMD_MAIN (-1, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CCOLAMD_MAIN (ncol, -1, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + Cp [nrow] = -1 ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + Cp [0] = 1 ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT (ok) ; + CCOLAMD_report (stats) ; + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + + if (nrow > 0 && alen > 0 && Cp [1] > 0) + { + c = Cmember [0] ; + Cmember [0] = -1 ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT(ok); + CCOLAMD_report (stats) ; + Cmember [0] = c ; + + p = Cp [1] ; + Cp [1] = -1 ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT(ok); + CCOLAMD_report (stats) ; + Cp [1] = p ; + + i = Ci [0] ; + Ci [0] = -1 ; + ok = CCOLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats, Cmember) ; + NOT(ok); + CCOLAMD_report (stats) ; + Ci [0] = i ; + } + + s = CCOLAMD_recommended (-1, 0, 0) ; + OK (s == 0) ; + + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + + CHOLMOD(free) (nrow+1, sizeof (Int), Front_npivcol, cm) ; + CHOLMOD(free) (nrow+1, sizeof (Int), Front_nrows, cm) ; + CHOLMOD(free) (nrow+1, sizeof (Int), Front_ncols, cm) ; + CHOLMOD(free) (nrow+1, sizeof (Int), Front_parent, cm) ; + CHOLMOD(free) (nrow+1, sizeof (Int), Front_cols, cm) ; + CHOLMOD(free) (nrow+1, sizeof (Int), P, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), InFront, cm) ; + + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; +} + +#else + +void cctest (cholmod_sparse *A) +{ + if (A == NULL) + { + return ; + } +} +#endif + diff --git a/CHOLMOD/Tcov/t_cm.c b/CHOLMOD/Tcov/t_cm.c new file mode 100644 index 0000000000..30ebeddbc3 --- /dev/null +++ b/CHOLMOD/Tcov/t_cm.c @@ -0,0 +1,1541 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_cm: CHOLMOD test program +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// A program for exhaustive statement-coverage for CHOLMOD, AMD, COLAMD, and +// CCOLAMD. It tests every line of code in all three packages. +// +// For a complete test, all CHOLMOD modules, AMD, COLAMD, CCOLAMD, METIS, +// LAPACK, and the BLAS are required. A partial test can be performed without +// the Supernodal and/or Partition modules. METIS is not required if the +// Partition module is not installed. LAPACK and the BLAS are not required +// if the Supernodal module is not installed. +// +// Usage: +// +// cm < input > output +// +// where "input" contains a sparse matrix in triplet form. The first line of +// the file contains four or five integers: +// +// nrow ncol nnz stype complex +// +// where the matrix is nrow-by-ncol. nnz is the number of (i,j,aij) triplets +// in the rest of the file, one triplet per line. stype is -1 (symmetric +// with entries in lower triangular part provided), 0 (unsymmetric), or 1 +// (symmetric upper). If the 5th entry is missing, or 0, then the matrix is +// real; if 1 the matrix is complex, if 2 the matrix is zomplex. Each +// subsequent line contains +// +// i j aij +// +// for the row index, column index, and value of A(i,j). Duplicate entries +// are summed. If stype is 2 or 3, the rest of the file is ignored, and a +// special test matrix is constructed (2: arrowhead, 3: tridiagonal plus a +// dense row). Test matrices are located in the Matrix/ subdirectory. +// +// For complex matrices, each line consists of +// +// i j xij zij +// +// where xij is the real part of A(i,j) and zij is the imaginary part. +// +// cm takes one optional parameter. If present (it does not matter what the +// argument is, actually) then extension memory-failure tests are performed. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// global variables +//------------------------------------------------------------------------------ + +double zero [2], one [2], minusone [2] ; +cholmod_common Common, *cm ; +double Zero [2] ; + +//------------------------------------------------------------------------------ +// my_rand +//------------------------------------------------------------------------------ + +// The POSIX example of rand, duplicated here so that the same sequence will +// be generated on different machines. + +static unsigned long next = 1 ; + +// see MY_RAND_MAX in cm.h +Int my_rand (void) +{ + next = next * 1103515245 + 12345 ; + return ((unsigned)(next/65536) % (MY_RAND_MAX + 1)) ; +} + +void my_srand (unsigned seed) +{ + next = seed ; +} + +unsigned long my_seed (void) +{ + return (next) ; +} + +//------------------------------------------------------------------------------ +// progress +//------------------------------------------------------------------------------ + +// print a "." on stderr to indicate progress + +#define COUNT 100 + +Int dot = 0 ; +void progress (Int force, char s) +{ + dot++ ; + if (force) + { + dot = 0 ; + } + if (dot % COUNT == 0) + { + fprintf (stderr, "%c", s) ; + } + fflush (stdout) ; + fflush (stderr) ; +} + +//------------------------------------------------------------------------------ +// my_handler +//------------------------------------------------------------------------------ + +// An error occurred that should not have occurred + +void my_handler (int status, const char *file, int line, const char *msg) +{ + printf ("Error handler: file %s line %d status %d: %s\n", + file, line, status, msg) ; + if (status < CHOLMOD_OK || status > CHOLMOD_DSMALL) + { + fprintf (stderr, "\n\n************************************************" + "********************************\n" + "*** Test failure: file: %s line: %d\n" + "*** status: %d message: %s\n" + "***********************************************************" + "*********************\n", file, line, status, msg); + fflush (stderr) ; + fflush (stdout) ; + abort ( ) ; + } +} + +//------------------------------------------------------------------------------ +// Assert +//------------------------------------------------------------------------------ + +void Assert (int truth, char *file, int line) +{ + if (!truth) + { + my_handler (-1, file, line, "") ; + } +} + +//------------------------------------------------------------------------------ +// nrand +//------------------------------------------------------------------------------ + +// return a random Int between 0 and n-1 + +Int nrand (Int n) +{ + return ((n <= 0) ? (0) : (rand ( ) % n)) ; +} + +//------------------------------------------------------------------------------ +// xrand +//------------------------------------------------------------------------------ + +// return a random double between 0 and x + +double xrand (double range) +{ + return ((range * (double) (my_rand ( ))) / MY_RAND_MAX) ; +} + +//------------------------------------------------------------------------------ +// rand_set +//------------------------------------------------------------------------------ + +// allocate and construct a random set of 0:n-1, possibly with duplicates + +Int *rand_set (Int len, Int n) +{ + Int *cset ; + Int k ; + cset = CHOLMOD(malloc) (len, sizeof (Int), cm) ; + if (cset == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot create random set") ; + return (NULL) ; + } + for (k = 0 ; k < len ; k++) + { + cset [k] = nrand (n) ; + } + CHOLMOD(print_subset) (cset, len, n, "random cset", cm) ; + return (cset) ; +} + +//------------------------------------------------------------------------------ +// zeros +//------------------------------------------------------------------------------ + +// Same as cholmod_zeros or cholmod_l_zeros, except it allows for a leading +// dimension that is different than nrow + +cholmod_dense *zeros (Int nrow, Int ncol, Int d, int xdtype) +{ + cholmod_dense *X ; + Real *Xx, *Xz ; + Int i, nz ; + X = CHOLMOD(allocate_dense) (nrow, ncol, d, xdtype, cm) ; + if (X == NULL) + { + return (NULL) ; + } + Xx = X->x ; + Xz = X->z ; + nz = MAX (1, X->nzmax) ; + switch (X->xtype) + { + case CHOLMOD_REAL: + for (i = 0 ; i < nz ; i++) + { + Xx [i] = 0 ; + } + break ; + case CHOLMOD_COMPLEX: + for (i = 0 ; i < 2*nz ; i++) + { + Xx [i] = 0 ; + } + break ; + case CHOLMOD_ZOMPLEX: + for (i = 0 ; i < nz ; i++) + { + Xx [i] = 0 ; + } + for (i = 0 ; i < nz ; i++) + { + Xz [i] = 0 ; + } + break ; + } + return (X) ; +} + +//------------------------------------------------------------------------------ +// xtrue +//------------------------------------------------------------------------------ + +// Allocate and construct a dense matrix, X(i,j) = i+j*d+1 + +// if tweak is nonzero, X(0,0) is revised. + +cholmod_dense *xtrue (Int nrow, Int ncol, Int d, int xdtype, int tweak) +{ + Real *x, *z ; + cholmod_dense *X ; + Int j, i ; + X = zeros (nrow, ncol, d, xdtype) ; + if (X == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot create dense matrix") ; + return (NULL) ; + } + x = X->x ; + z = X->z ; + + int xtype = xdtype & 3 ; + + if (xtype == CHOLMOD_REAL) + { + for (j = 0 ; j < ncol ; j++) + { + for (i = 0 ; i < nrow ; i++) + { + x [i+j*d] = i+j*d + 1 ; + } + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + for (j = 0 ; j < ncol ; j++) + { + for (i = 0 ; i < nrow ; i++) + { + x [2*(i+j*d) ] = i+j*d + 1 ; + x [2*(i+j*d)+1] = ((Real) (j+i*d + 1))/10 ; + } + } + } + else // xtype == CHOLMOD_ZOMPLEX + { + for (j = 0 ; j < ncol ; j++) + { + for (i = 0 ; i < nrow ; i++) + { + x [i+j*d] = i+j*d + 1 ; + z [i+j*d] = ((Real) (j+i*d + 1))/10 ; + } + } + } + + if (tweak != 0 && nrow > 0 && ncol > 0) + { + x [0] += ((double) tweak) / 10.0 ; + if (xtype == CHOLMOD_COMPLEX) + { + x [1] += ((double) tweak) / 20.0 ; + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + z [0] += ((double) tweak) / 20.0 ; + } + } + + return (X) ; +} + +//------------------------------------------------------------------------------ +// resid +//------------------------------------------------------------------------------ + +// compute r = norm (A*x-b)/norm(b) or r = norm (A*A'*x-b)/norm(b) + +double resid (cholmod_sparse *A, cholmod_dense *X, cholmod_dense *B) +{ + double r, bnorm ; + cholmod_dense *R, *X2, *B2 ; + cholmod_sparse *C, *A2 ; + Int d, n, nrhs, xtype ; + + if (A == NULL || X == NULL || B == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute resid") ; + return (1) ; + } + + cm->status = CHOLMOD_OK ; + n = B->nrow ; + + //-------------------------------------------------------------------------- + // convert all inputs to an identical xtype + //-------------------------------------------------------------------------- + + xtype = MAX (A->xtype, X->xtype) ; + xtype = MAX (xtype, B->xtype) ; + A2 = NULL ; + B2 = NULL ; + X2 = NULL ; + if (A->xtype != xtype) + { + A2 = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sparse_xtype) (xtype + DTYPE, A2, cm) ; + A = A2 ; + } + if (X->xtype != xtype) + { + X2 = CHOLMOD(copy_dense) (X, cm) ; + CHOLMOD(dense_xtype) (xtype + DTYPE, X2, cm) ; + X = X2 ; + } + if (B->xtype != xtype) + { + B2 = CHOLMOD(copy_dense) (B, cm) ; + CHOLMOD(dense_xtype) (xtype + DTYPE, B2, cm) ; + B = B2 ; + } + + if (cm->status < CHOLMOD_OK) + { + ERROR (CHOLMOD_INVALID, "cannot compute resid") ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + return (1) ; + } + + //-------------------------------------------------------------------------- + // get the right-hand-side, B, and its norm + //-------------------------------------------------------------------------- + + nrhs = B->ncol ; + d = B->d ; + if (nrhs == 1) + { + // inf-norm, 1-norm, or 2-norm (random choice) + bnorm = CHOLMOD(norm_dense) (B, nrand (2), cm) ; + } + else + { + // inf-norm or 1-norm (random choice) + bnorm = CHOLMOD(norm_dense) (B, nrand (1), cm) ; + } + + //-------------------------------------------------------------------------- + // compute the residual + //-------------------------------------------------------------------------- + + if (A->stype == 0) + { + if (n < 10 && A->xtype == CHOLMOD_REAL) + { + // test cholmod_aat, C = A*A' + C = CHOLMOD(aat) (A, NULL, 0, 1, cm) ; + + // R = B + R = CHOLMOD(copy_dense) (B, cm) ; + // R = C*X - R + CHOLMOD(sdmult) (C, FALSE, one, minusone, X, R, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + + } + else + { + // W = A'*X + cholmod_dense *W ; + W = CHOLMOD(zeros) (A->ncol, nrhs, A->xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A, TRUE, one, zero, X, W, cm) ; + // R = B + R = CHOLMOD(copy_dense) (B, cm) ; + // R = A*W - R + CHOLMOD(sdmult) (A, FALSE, one, minusone, W, R, cm) ; + CHOLMOD(free_dense) (&W, cm) ; + } + } + else + { + // R = B + R = CHOLMOD(copy_dense) (B, cm) ; + // R = A*X - R + CHOLMOD(sdmult) (A, FALSE, one, minusone, X, R, cm) ; + } + + //-------------------------------------------------------------------------- + // r = norm (R) / norm (B) + //-------------------------------------------------------------------------- + + r = CHOLMOD(norm_dense) (R, 1, cm) ; + + CHOLMOD(free_dense) (&R, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + + if (bnorm > 0) + { + r /= bnorm ; + } + return (r) ; +} + +//------------------------------------------------------------------------------ +// resid_sparse +//------------------------------------------------------------------------------ + +// compute r = norm (A*x-b)/norm(b) or r = norm (A*A'*x-b)/norm(b) + +double resid_sparse (cholmod_sparse *A, cholmod_sparse *X, cholmod_sparse *B) +{ + double r, bnorm ; + cholmod_sparse *R, *W, *AT, *W2 ; + cholmod_dense *X2, *B2 ; + Int n, nrhs, xtype ; + + if (A == NULL || X == NULL || B == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute resid") ; + return (1) ; + } + + //-------------------------------------------------------------------------- + // compute the residual + //-------------------------------------------------------------------------- + + xtype = MAX (A->xtype, X->xtype) ; + xtype = MAX (xtype, B->xtype) ; + + if (xtype > CHOLMOD_REAL) + { + + //---------------------------------------------------------------------- + // convert X and B to dense if any is complex or zomplex + //---------------------------------------------------------------------- + + X2 = CHOLMOD(sparse_to_dense) (X, cm) ; + B2 = CHOLMOD(sparse_to_dense) (B, cm) ; + r = resid (A, X2, B2) ; + CHOLMOD(free_dense) (&X2, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + + } + else + { + + //---------------------------------------------------------------------- + // all inputs are real + //---------------------------------------------------------------------- + + n = B->nrow ; + nrhs = B->ncol ; + // inf-norm or 1-norm (random choice) + bnorm = CHOLMOD(norm_sparse) (B, nrand (1), cm) ; + + if (A->stype == 0) + { + // W = A'*X + AT = CHOLMOD(transpose) (A, 1, cm) ; + W = CHOLMOD(ssmult) (AT, X, 0, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + // W2 = A*W + W2 = CHOLMOD(ssmult) (A, W, 0, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&W, cm) ; + // R = W2 - B + R = CHOLMOD(add) (W2, B, one, minusone, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&W2, cm) ; + } + else + { + // W = A*X + W = CHOLMOD(ssmult) (A, X, 0, TRUE, FALSE, cm) ; + // R = W - B + R = CHOLMOD(add) (W, B, one, minusone, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&W, cm) ; + } + + r = CHOLMOD(norm_sparse) (R, 1, cm) ; + CHOLMOD(free_sparse) (&R, cm) ; + if (bnorm > 0) + { + r /= bnorm ; + } + } + + return (r) ; +} + +//------------------------------------------------------------------------------ +// resid3 +//------------------------------------------------------------------------------ + +// r = norm (A1*A2*A3*x - b) / norm (b) + +double resid3 (cholmod_sparse *A1, cholmod_sparse *A2, cholmod_sparse *A3, + cholmod_dense *X, cholmod_dense *B) +{ + double r, bnorm ; + cholmod_dense *R, *W1, *W2, *X2, *B2 ; + cholmod_sparse *C1, *C2, *C3 ; + Int n, nrhs, d, xtype ; + + if (A1 == NULL || X == NULL || B == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute resid3") ; + return (1) ; + } + + cm->status = CHOLMOD_OK ; + + n = B->nrow ; + + //-------------------------------------------------------------------------- + // convert all inputs to an identical xtype + //-------------------------------------------------------------------------- + + xtype = MAX (A1->xtype, X->xtype) ; + xtype = MAX (xtype, B->xtype) ; + if (A2 != NULL) + { + xtype = MAX (xtype, A2->xtype) ; + } + if (A3 != NULL) + { + xtype = MAX (xtype, A3->xtype) ; + } + + C1 = NULL ; + C2 = NULL ; + C3 = NULL ; + B2 = NULL ; + X2 = NULL ; + + if (A1->xtype != xtype) + { + C1 = CHOLMOD(copy_sparse) (A1, cm) ; + CHOLMOD(sparse_xtype) (xtype + DTYPE, C1, cm) ; + A1 = C1 ; + } + + if (A2 != NULL && A2->xtype != xtype) + { + C2 = CHOLMOD(copy_sparse) (A2, cm) ; + CHOLMOD(sparse_xtype) (xtype + DTYPE, C2, cm) ; + A2 = C2 ; + } + + if (A3 != NULL && A3->xtype != xtype) + { + C3 = CHOLMOD(copy_sparse) (A3, cm) ; + CHOLMOD(sparse_xtype) (xtype + DTYPE, C3, cm) ; + A3 = C3 ; + } + + if (X->xtype != xtype) + { + X2 = CHOLMOD(copy_dense) (X, cm) ; + CHOLMOD(dense_xtype) (xtype + DTYPE, X2, cm) ; + X = X2 ; + } + + if (B->xtype != xtype) + { + B2 = CHOLMOD(copy_dense) (B, cm) ; + CHOLMOD(dense_xtype) (xtype + DTYPE, B2, cm) ; + B = B2 ; + } + + if (cm->status < CHOLMOD_OK) + { + ERROR (CHOLMOD_INVALID, "cannot compute resid3") ; + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + return (1) ; + } + + //-------------------------------------------------------------------------- + // get B and its norm + //-------------------------------------------------------------------------- + + nrhs = B->ncol ; + d = B->d ; + bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; + + //-------------------------------------------------------------------------- + // compute the residual + //-------------------------------------------------------------------------- + + if (A3 != NULL) + { + // W1 = A3*X + W1 = CHOLMOD(zeros) (n, nrhs, xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A3, FALSE, one, zero, X, W1, cm) ; + } + else + { + W1 = X ; + } + + if (A2 != NULL) + { + // W2 = A2*W1 + W2 = CHOLMOD(eye) (n, nrhs, xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A2, FALSE, one, zero, W1, W2, cm) ; + } + else + { + W2 = W1 ; + } + + // R = B + R = CHOLMOD(copy_dense) (B, cm) ; + + // R = A1*W2 - R + CHOLMOD(sdmult) (A1, FALSE, one, minusone, W2, R, cm) ; + + //-------------------------------------------------------------------------- + // r = norm (R) / norm (B) + //-------------------------------------------------------------------------- + + r = CHOLMOD(norm_dense) (R, 1, cm) ; + CHOLMOD(free_dense) (&R, cm) ; + + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + + if (A3 != NULL) + { + CHOLMOD(free_dense) (&W1, cm) ; + } + if (A2 != NULL) + { + CHOLMOD(free_dense) (&W2, cm) ; + } + if (bnorm > 0) + { + r /= bnorm ; + } + return (r) ; +} + +//------------------------------------------------------------------------------ +// pnorm +//------------------------------------------------------------------------------ + +// r = norm (x-Pb) or r = norm(x-P'b). This is lengthy because CHOLMOD does +// not provide any operations on dense matrices, and because it used to test +// the sparse-to-dense conversion routine. Multiple methods are used to +// compute the same thing. + +double pnorm (cholmod_dense *X, Int *P, cholmod_dense *B, Int inv) +{ + cholmod_dense *R, *X2, *B2 ; + cholmod_factor *L ; + Real *xx, *xz, *bx, *bz, *rx, *rz ; + Int *Pinv, *Perm ; + double rnorm, r ; + Int i, j, k, n, nrhs, xtype, ok, save, lxtype ; + + if (X == NULL || P == NULL || B == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute pnorm") ; + return (1) ; + } + + save = cm->prefer_zomplex ; + n = X->nrow ; + nrhs = X->ncol ; + rnorm = 0 ; + + Pinv = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + if (Pinv != NULL) + { + for (k = 0 ; k < n ; k++) + { + Pinv [P [k]] = k ; + } + } + + xtype = MAX (X->xtype, B->xtype) ; + + R = CHOLMOD(zeros) (n, nrhs, CHOLMOD_ZOMPLEX + DTYPE, cm) ; + B2 = CHOLMOD(copy_dense) (B, cm) ; + ok = R != NULL && B2 != NULL ; + ok = ok && CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX + DTYPE, B2, cm) ; + + for (lxtype = CHOLMOD_REAL ; ok && lxtype <= CHOLMOD_ZOMPLEX ; lxtype++) + { + // create a fake factor object +// L = CHOLMOD(allocate_factor) (n, cm) ; + L = CHOLMOD(alloc_factor) (n, DTYPE, cm) ; + CHOLMOD(change_factor) (lxtype, TRUE, FALSE, TRUE, TRUE, L, cm) ; + ok = ok && (L != NULL && L->Perm != NULL && Pinv != NULL) ; + if (ok) + { + L->ordering = CHOLMOD_GIVEN ; + Perm = L->Perm ; + for (k = 0 ; k < n ; k++) + { + Perm [k] = Pinv [k] ; + } + } + for (k = 0 ; k <= 1 ; k++) + { + // solve the inverse permutation system, X2 = P*X or X2 = P'*X + cm->prefer_zomplex = k ; + X2 = CHOLMOD(solve) (inv ? CHOLMOD_Pt : CHOLMOD_P, L, X, cm) ; + + ok = ok && CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX + DTYPE, X2, cm) ; + if (ok && X2 != NULL) + { + rx = R->x ; + rz = R->z ; + xx = X2->x ; + xz = X2->z ; + bx = B2->x ; + bz = B2->z ; + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < n ; i++) + { + rx [i+j*n] = xx [i+j*n] - bx [i+j*n] ; + rz [i+j*n] = xz [i+j*n] - bz [i+j*n] ; + } + } + } + r = CHOLMOD(norm_dense) (R, 0, cm) ; + rnorm = MAX (r, rnorm) ; + CHOLMOD(free_dense) (&X2, cm) ; + } + CHOLMOD(free_factor) (&L, cm) ; + } + + CHOLMOD(free_dense) (&B2, cm) ; + CHOLMOD(free_dense) (&R, cm) ; + + if (xtype == CHOLMOD_REAL) + { + // X and B are both real + cholmod_sparse *Bs, *Pb ; + Bs = CHOLMOD(dense_to_sparse) (B, TRUE, cm) ; + Pb = CHOLMOD(submatrix) (Bs, inv ? Pinv : P, n, NULL, -1, TRUE, TRUE, + cm) ; + X2 = CHOLMOD(sparse_to_dense) (Pb, cm) ; + R = CHOLMOD(zeros) (n, nrhs, CHOLMOD_REAL + DTYPE, cm) ; + if (R != NULL && X != NULL && X2 != NULL) + { + rx = R->x ; + xx = X->x ; + bx = X2->x ; + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < n ; i++) + { + rx [i+j*n] = xx [i+j*n] - bx [i+j*n] ; + } + } + } + CHOLMOD(free_sparse) (&Bs, cm) ; + CHOLMOD(free_sparse) (&Pb, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + r = CHOLMOD(norm_dense) (R, 1, cm) ; + rnorm = MAX (rnorm, r) ; + CHOLMOD(free_dense) (&R, cm) ; + } + + CHOLMOD(free) (n, sizeof (Int), Pinv, cm) ; + cm->prefer_zomplex = save ; + return (rnorm) ; +} + +//------------------------------------------------------------------------------ +// prune_row +//------------------------------------------------------------------------------ + +// Set row k and column k of a packed matrix A to zero. Set A(k,k) to 1 +// if space is available. + +void prune_row (cholmod_sparse *A, Int k) +{ + Real *Ax ; + Int *Ap, *Ai ; + Int ncol, p, i, j, nz ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "nothing to prune") ; + return ; + } + + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + nz = 0 ; + ncol = A->ncol ; + + for (j = 0 ; j < ncol ; j++) + { + p = Ap [j] ; + Ap [j] = nz ; + if (j == k && nz < Ap [j+1]) + { + Ai [nz] = k ; + Ax [nz] = 1 ; + nz++ ; + } + else + { + for ( ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + if (i != k) + { + Ai [nz] = i ; + Ax [nz] = Ax [p] ; + nz++ ; + } + } + } + } + Ap [ncol] = nz ; +} + +//------------------------------------------------------------------------------ +// do_matrix +//------------------------------------------------------------------------------ + +double do_matrix (cholmod_sparse *A) +{ + double err, maxerr = 0 ; + Int print, precise, maxprint, minprint, nmethods ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "no matrix") ; + return (1) ; + } + + //-------------------------------------------------------------------------- + // determine print level, based on matrix size + //-------------------------------------------------------------------------- + + if (A->nrow <= 4) + { + minprint = 5 ; + maxprint = 5 ; + } + else if (A->nrow <= 8) + { + minprint = 4 ; + maxprint = 4 ; + } + else + { + minprint = 1 ; + maxprint = 1 ; + } + + //-------------------------------------------------------------------------- + // for all print levels and precisions, do: + //-------------------------------------------------------------------------- + + int psave = cm->print ; + + for (print = minprint ; print <= maxprint ; print++) + { + for (precise = 0 ; precise <= (print >= 4) ? 1 : 0 ; precise++) + { + Int save1, save2 ; + + maxerr = 0 ; + my_srand (42) ; // RAND reset + cm->print = print ; + cm->precise = precise ; + printf ("\n----------Print level %d precise: %d\n", + cm->print, cm->precise) ; + + save1 = cm->final_asis ; + save2 = cm->final_super ; + cm->final_asis = FALSE ; + cm->final_super = TRUE ; + OK (CHOLMOD(print_common) ("1:cm", cm)) ; + cm->final_asis = save1 ; + cm->final_super = save2 ; + + //------------------------------------------------------------------ + // test various matrix operations + //------------------------------------------------------------------ + + err = test_ops (A) ; // RAND + MAXERR (maxerr, err, 1) ; + + //------------------------------------------------------------------ + // solve the augmented system + //------------------------------------------------------------------ + + err = aug (A) ; // no random number use + MAXERR (maxerr, err, 1) ; + + //------------------------------------------------------------------ + // solve using different methods + //------------------------------------------------------------------ + + printf ("test_solver (1)\n") ; + cm->nmethods = 9 ; + cm->final_asis = TRUE ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (2)\n") ; + cm->final_asis = TRUE ; + for (nmethods = 0 ; nmethods < 7 ; nmethods++) + { + cm->nmethods = nmethods ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + } + + printf ("test_solver (3)\n") ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NESDIS ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (3b)\n") ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NESDIS ; + cm->method [0].nd_camd = 2 ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (3c)\n") ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (4)\n") ; + cm->nmethods = 1 ; + cm->method[0].ordering = CHOLMOD_METIS ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (5)\n") ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_AMD ; + CHOLMOD(free_work) (cm) ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + printf ("test_solver (6)\n") ; + cm->nmethods = 1 ; + cm->method[0].ordering = CHOLMOD_COLAMD ; + err = test_solver (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + //------------------------------------------------------------------ + // restore default control parameters + //------------------------------------------------------------------ + + OK (CHOLMOD(print_common) ("2:cm", cm)) ; + CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; + } + } + + printf ("do_matrix max error %.1g\n", maxerr) ; + cm->print = psave ; + + return (maxerr) ; +} + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ + +// Usage: +// cm < matrix do not perform intensive memory-failure tests +// cm -m < matrix do perform memory tests +// cm -s < matrix matrix is singular, nan error expected +// +// (The memory tests are performed if any argument is given to cm). + +int main (int argc, char **argv) +{ + cholmod_triplet *T ; + cholmod_sparse *A, *C, *AT ; + double err = 0, maxerr = 0 ; + Int n = 0, nmin = 0, nrow = 0, ncol = 0, save ; + int singular, do_memory, i, do_nantests, ok ; + double v = CHOLMOD_VERSION, tic [2], t ; + int version [3] ; + char *p ; + const char* env_use_gpu; + + SuiteSparse_start ( ) ; + SuiteSparse_tic (tic) ; + printf ("Testing CHOLMOD (%g): %d ", v, CHOLMOD(version) (version)) ; + printf ("(%d.%d.%d)\n", version [0], version [1], version [2]) ; + OK (CHOLMOD_VERSION == CHOLMOD(version) (NULL)) ; + v = SUITESPARSE_VERSION ; + printf ("for SuiteSparse (%g): %d ", v, SuiteSparse_version (version)) ; + printf ("(%d.%d.%d)\n", version [0], version [1], version [2]) ; + printf ("%s: argc: %d\n", argv [0], argc) ; + my_srand (42) ; // RAND + + // Ignore floating point exceptions. Infs and NaNs are generated + // on purpose. + signal (SIGFPE, SIG_IGN) ; + + // query the CHOLMOD_USE_GPU environment variable + env_use_gpu = getenv ("CHOLMOD_USE_GPU") ; + if ( env_use_gpu ) + { + // CHOLMOD_USE_GPU environment variable is set to something + if ( atoi ( env_use_gpu ) == 0 ) + { + printf ("CHOLMOD_USE_GPU 0\n") ; + } + else + { + printf ("CHOLMOD_USE_GPU 1 (ignored for this test)\n") ; + } + } + else + { + printf ("CHOLMOD_USE_GPU not present\n") ; + } + + fflush (stdout) ; + + double maxerr_allowed = 0.1 ; + + singular = FALSE ; + do_memory = FALSE ; + do_nantests = FALSE ; + for (i = 1 ; i < argc ; i++) + { + char *s ; + s = argv [i] ; + if (s [0] == '-' && s [1] == 'm') + { + // -m do memory tests + do_memory = TRUE ; + } + if (s [0] == '-' && s [1] == 's') + { + // -s matrix is singular, maxerr not important (likely nan) + singular = TRUE ; + } + if (s [0] == '-' && s [1] == 'n') + { + // -n do tests with nans + do_nantests = TRUE ; + } + if (s [0] == '-' && s [1] == 'e') + { + // -e# maxerr must be < 1e-# + // for example, -e-10 means maxerr < 1e-10 must hold for the + // test to pass. + long int ee = strtol (s + 2, NULL, 10) ; + if (ee > 0) + { + maxerr_allowed = pow ((double) 10, (double) (-ee)) ; + printf ("maxerr allowed: %g\n", maxerr_allowed) ; + } + } + } + + printf ("do_memory: %d singular: %d\n", do_memory, singular) ; + + //-------------------------------------------------------------------------- + // test SuiteSparse_config + //-------------------------------------------------------------------------- + + suitesparse_tests ( ) ; + + p = SuiteSparse_malloc (0, 0) ; + OKP (p) ; + p [0] = 'a' ; + SuiteSparse_free (p) ; + p = SuiteSparse_calloc (0, 0) ; + OKP (p) ; + p [0] = 'a' ; + p = SuiteSparse_realloc (0, 0, 0, p, &ok) ; + OK (ok) ; + OKP (p) ; + p [0] = 'a' ; + SuiteSparse_free (p) ; + p = SuiteSparse_malloc (INT64_MAX, 1024) ; + NOP (p) ; + p = SuiteSparse_calloc (INT64_MAX, 1024) ; + NOP (p) ; + p = SuiteSparse_realloc (0, 0, 0, NULL, &ok) ; + OK (ok) ; + OKP (p) ; + p [0] = 'a' ; + SuiteSparse_free (p) ; + p = SuiteSparse_realloc (INT64_MAX, 0, 1024, NULL, &ok) ; + NOP (p) ; + NOT (ok) ; + + //-------------------------------------------------------------------------- + // initialize CHOLMOD + //-------------------------------------------------------------------------- + + cm = &Common ; + OK (CHOLMOD(start) (cm)) ; cm->useGPU = 0 ; + + //-------------------------------------------------------------------------- + // test all methods with NULL common + //-------------------------------------------------------------------------- + + // no user error handler, since lots of errors will be raised here + cm->error_handler = NULL ; + null_test (NULL) ; + save = cm->itype ; + cm->itype = -999 ; + null_test (cm) ; + cm->itype = save ; + null_test2 ( ) ; + CHOLMOD(finish) (cm) ; + OK (cm->malloc_count == 0) ; + OK (CHOLMOD(start) (cm)) ; cm->useGPU = 0 ; + + //-------------------------------------------------------------------------- + // create basic scalars + //-------------------------------------------------------------------------- + + Zero [0] = 0 ; + Zero [1] = 0 ; + + zero [0] = 0 ; + zero [1] = 0 ; + one [0] = 1 ; + one [1] = 0 ; + minusone [0] = -1 ; + minusone [1] = 0 ; + + //-------------------------------------------------------------------------- + // basic tests + //-------------------------------------------------------------------------- + + basic1 (cm) ; + printf ("basic1 tests OK\n") ; + + //-------------------------------------------------------------------------- + // integer overflow tests + //-------------------------------------------------------------------------- + + overflow_tests (cm) ; + printf ("overflow tests OK\n") ; + + //-------------------------------------------------------------------------- + // read in a triplet matrix + //-------------------------------------------------------------------------- + + T = read_triplet (stdin) ; // RAND + OKP (T) ; + int test_result = 0 ; + ok = true ; + + //-------------------------------------------------------------------------- + // test CHOLMOD with the triplet matrix T + //-------------------------------------------------------------------------- + + if (T->nrow > 1000000) + { + + //---------------------------------------------------------------------- + // do huge-problem tests only + //---------------------------------------------------------------------- + + huge ( ) ; // RAND + CHOLMOD(free_triplet) (&T, cm) ; + + } + else + { + + //---------------------------------------------------------------------- + // test CHOLMOD with this matrix T + //---------------------------------------------------------------------- + + maxerr = 0 ; + CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; + cm->error_handler = my_handler ; + cm->nmethods = 8 ; + + //---------------------------------------------------------------------- + // convert triplet to sparse matrix + //---------------------------------------------------------------------- + + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + AT = CHOLMOD(transpose) (A, 0, cm) ; + C = unpack (A) ; // RAND + + cm->print = 4 ; + cm->precise = FALSE ; + OK (CHOLMOD(print_sparse) (A, "Test matrix, A", cm)) ; + OK (CHOLMOD(print_sparse) (C, "Unpacked/unsorted version of A", cm)) ; + cm->print = 1 ; // default cm->print for all remaining tests + + if (T != NULL) + { + nrow = T->nrow ; + ncol = T->ncol ; + n = MAX (nrow, ncol) ; + nmin = MIN (nrow, ncol) ; + } + + //---------------------------------------------------------------------- + // basic error tests, possibily with nans + //---------------------------------------------------------------------- + + null2 (T, do_nantests) ; // RAND + + printf ("Null2 OK : no error\n") ; + maxerr = 0 ; + + //---------------------------------------------------------------------- + // remaining tests (skip if nantests were just done) + //---------------------------------------------------------------------- + + if (!do_nantests) + { + + //------------------------------------------------------------------ + // raw factorization tests + //------------------------------------------------------------------ + + cm->error_handler = NULL ; + err = raw_factor (A, 2) ; // RAND + cm->error_handler = my_handler ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error %.1g\n", err) ; + + err = raw_factor2 (A, 0., 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error2 %.1g\n", err) ; + + err = raw_factor2 (A, 1e-16, 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error3 %.1g\n", err) ; + + if (n < 1000 && A && T && A->stype == 1) + { + // factorize a symmetric matrix (upper part stored), possibly + // with ignored entries in lower triangular part. + cholmod_sparse *F ; + int save = T->stype ; + + printf ("triplet to sparse:\n") ; + T->stype = 0 ; + F = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + T->stype = save ; + + if (F) F->stype = 1 ; + + err = raw_factor2 (F, 0., 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error4 %.1g\n", err) ; + + err = raw_factor2 (F, 1e-16, 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error5 %.1g\n", err) ; + + cm->dbound = 1e-15 ; + cm->sbound = 1e-6 ; + + #ifdef DOUBLE + double alpha = 1e-16 ; + #else + double alpha = 1e-8 ; + #endif + + err = raw_factor2 (F, 0., 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error6 %.1g\n", err) ; + + err = raw_factor2 (F, alpha, 0) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error7 %.1g\n", err) ; + + err = raw_factor2 (F, alpha, 1) ; + MAXERR (maxerr, err, 1) ; + printf ("raw factorization error8 %.1g\n", err) ; + + cm->dbound = 0 ; + cm->sbound = 0 ; + + CHOLMOD(free_sparse) (&F, cm) ; + } + + //------------------------------------------------------------------ + // matrix ops + //------------------------------------------------------------------ + + err = test_ops (A) ; // RAND + MAXERR (maxerr, err, 1) ; + printf ("initial testops error %.1g\n", err) ; + + //------------------------------------------------------------------ + // analyze, factorize, solve + //------------------------------------------------------------------ + + err = solve (A) ; // RAND + MAXERR (maxerr, err, 1) ; + printf ("initial solve error %.1g\n", err) ; + + //------------------------------------------------------------------ + // CCOLAMD tests + //------------------------------------------------------------------ + + cctest (A) ; // RAND reset + cctest (AT) ; // RAND reset + + //------------------------------------------------------------------ + // COLAMD tests + //------------------------------------------------------------------ + + ctest (A) ; + ctest (AT) ; + + //------------------------------------------------------------------ + // AMD tests + //------------------------------------------------------------------ + + if (n < NLARGE || A->stype) + { + // for unsymmetric matrices, this forms A*A' and A'*A, which + // can fail if A has a dense row or column. So it is only done + // for modest-sized unsymmetric matrices. + amdtest (A) ; + amdtest (AT) ; + camdtest (A) ; // RAND + camdtest (AT) ; // RAND + } + + if (n < NSMALL) + { + + //-------------------------------------------------------------- + // do_matrix with an unpacked matrix + //-------------------------------------------------------------- + + // try with an unpacked matrix, and a non-default dbound + cm->dbound = 1e-15 ; + cm->sbound = 1e-6 ; + err = do_matrix (C) ; // RAND reset + MAXERR (maxerr, err, 1) ; + cm->dbound = 0 ; + cm->sbound = 0 ; + + //-------------------------------------------------------------- + // do_matrix: analyze, factorize, and solve, with many options + //-------------------------------------------------------------- + + err = do_matrix (A) ; // RAND reset + MAXERR (maxerr, err, 1) ; + + //-------------------------------------------------------------- + // pretend to solve an LP + //-------------------------------------------------------------- + + if (nrow != ncol) + { + int psave = cm->print ; + cm->print = 2 ; + err = lpdemo (T) ; // RAND + cm->print = psave ; + MAXERR (maxerr, err, 1) ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_COLAMD ; + err = lpdemo (T) ; // RAND + MAXERR (maxerr, err, 1) ; + #ifdef DOUBLE + printf ("initial lp error %.1g, dbound %g\n", + err, cm->dbound) ; + #else + printf ("initial lp error %.1g, sbound %g\n", + err, cm->sbound) ; + #endif + cm->nmethods = 0 ; + cm->method [0].ordering = CHOLMOD_GIVEN ; + } + } + + //------------------------------------------------------------------ + // test more ops + //------------------------------------------------------------------ + + my_srand (42) ; // RAND reset + double err = test_ops2 (A) ; + MAXERR (maxerr, err, 1) ; + + err = cat_tests (A, cm) ; + MAXERR (maxerr, err, 1) ; + + err = dense_tests (A, cm) ; + MAXERR (maxerr, err, 1) ; + + dtype_tests (A, cm) ; + + common_tests (cm) ; + + error_tests (A, cm) ; + + err = tofrom_tests (A, cm) ; + MAXERR (maxerr, err, 1) ; + + //------------------------------------------------------------------ + // exhaustive memory-error handling for small matrices + //------------------------------------------------------------------ + + progress (1, '|') ; + if (n < NSMALL && do_memory) + { + memory_tests (T) ; // RAND + } + } + + //---------------------------------------------------------------------- + // free matrices and print results + //---------------------------------------------------------------------- + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_triplet) (&T, cm) ; + + ok = true ; + if (nrow <= ncol && !singular) + { + ok = (maxerr <= maxerr_allowed) && !isnan (maxerr) ; + } + } + + //-------------------------------------------------------------------------- + // report results + //-------------------------------------------------------------------------- + + t = SuiteSparse_toc (tic) ; + fprintf (stderr, "\n%8.2f sec", t) ; + if (nrow <= ncol && !singular) + { + // maxerr should be NaN if nrow > ncol, so don't print it + fprintf (stderr, ", maxerr %.1e <= %.1e", maxerr, maxerr_allowed) ; + } + if (ok) + { + fprintf (stderr, ", Test OK\n") ; + test_result = 0 ; + } + else + { + fprintf (stderr, ", Test FAIL\n") ; + test_result = 1 ; + } + + //-------------------------------------------------------------------------- + // finalize CHOLMOD + //-------------------------------------------------------------------------- + + CHOLMOD(finish) (cm) ; + + int psave = cm->print ; + cm->print = 5 ; + OK (CHOLMOD(print_common) ("4:cm", cm)) ; + cm->print = psave ; + + printf ("FINAL::malloc count "ID" inuse "ID"\n", + (Int) cm->malloc_count, + (Int) cm->memory_inuse) ; + + OK (cm->malloc_count == 0) ; + OK (cm->memory_inuse == 0) ; + if (nrow > ncol) + { + // maxerr should be NaN, so don't print it + printf ("All tests passed: time %.1g\n", t) ; + } + else + { + printf ("All tests passed: max error %.1g time: %.1g\n", maxerr, t); + } + + SuiteSparse_finish ( ) ; + return (test_result) ; +} + diff --git a/CHOLMOD/Tcov/t_cmread.c b/CHOLMOD/Tcov/t_cmread.c new file mode 100644 index 0000000000..a2266fcfc1 --- /dev/null +++ b/CHOLMOD/Tcov/t_cmread.c @@ -0,0 +1,301 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_cmread: test program that reads in a sparse matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read in a matrix from a file and print it out. +// +// Usage: +// cmread matrixfile +// cmread < matrixfile +// +// With the option -x, the matrix is assumed to be mangled. + +#include "cholmod.h" + +#ifdef CHOLMOD_INT64 +#define CHOLMOD(routine) cholmod_l_ ## routine +#define Int int64_t +#define UInt uint64_t +#else +#define CHOLMOD(routine) cholmod_ ## routine +#define Int int32_t +#define UInt uint32_t +#endif + +#ifdef SINGLE +#define Real float +#define DTYPE CHOLMOD_SINGLE +#else +#define Real double +#define DTYPE CHOLMOD_DOUBLE +#endif + +#define OK(expr) \ +{ \ + if (!(expr)) \ + { \ + fprintf (stderr, "line %d Test FAIL\n", __LINE__) ; \ + printf ("line %d Test FAIL\n", __LINE__) ; \ + fflush (stdout) ; \ + fflush (stderr) ; \ + abort ( ) ; \ + } \ +} + +#include "t_znorm_diag.c" + +//------------------------------------------------------------------------------ +// test_sparse +//------------------------------------------------------------------------------ + +void test_sparse (cholmod_sparse *C, cholmod_common *cm) ; + +void test_sparse (cholmod_sparse *C, cholmod_common *cm) +{ + + //-------------------------------------------------------------------------- + // print C and create Z + //-------------------------------------------------------------------------- + + CHOLMOD(print_sparse) (C, "C", cm) ; + cholmod_sparse *Z = CHOLMOD(speye) (C->nrow, C->ncol, + CHOLMOD_PATTERN + DTYPE, cm) ; + Z->stype = C->stype ; + CHOLMOD(print_sparse) (Z, "Z", cm) ; + + //-------------------------------------------------------------------------- + // symmetry + //-------------------------------------------------------------------------- + + for (int option = 0 ; option <= 2 ; option++) + { + Int xmatch = 0, pmatch = 0, nzoff = 0, nzd = 0 ; + int asym = CHOLMOD(symmetry) (C, option, &xmatch, &pmatch, &nzoff, + &nzd, cm) ; + printf ("option: %d asym %d\n", option, asym) ; + } + + //-------------------------------------------------------------------------- + // write C as a sparse matrix and read it back in as A + //-------------------------------------------------------------------------- + + FILE *f = fopen ("temp5.mtx", "w") ; + CHOLMOD(write_sparse) (f, C, Z, NULL, cm) ; + fclose (f) ; + f = fopen ("temp5.mtx", "r") ; + cholmod_sparse *A = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; + fclose (f) ; + double anorm = CHOLMOD(norm_sparse) (A, 0, cm) ; + double dnorm = znorm_diag (A, cm) ; + + //-------------------------------------------------------------------------- + // test C and A + //-------------------------------------------------------------------------- + + // do the test only if norm(A) is finite, and if norm(imag(diag(A))) is + // zero or the matrix is unsymmetric. + + if (isfinite (anorm) && (dnorm == 0 || A->stype == 0)) + { + + //---------------------------------------------------------------------- + // compare C and A + //---------------------------------------------------------------------- + + double one [2] = {1,0} ; + double minusone [2] = {-1,0} ; + CHOLMOD(print_sparse) (C, "C", cm) ; + CHOLMOD(print_sparse) (A, "A", cm) ; + cholmod_sparse *E = CHOLMOD(add) (C, A, one, minusone, 2, true, cm) ; + CHOLMOD(print_sparse) (E, "E", cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + printf ("enorm %g\n", enorm) ; + OK (enorm == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + + //---------------------------------------------------------------------- + // test the pattern of C and A + //---------------------------------------------------------------------- + + CHOLMOD(sparse_xtype) (CHOLMOD_PATTERN, A, cm); + CHOLMOD(sparse_xtype) (CHOLMOD_REAL, A, cm) ; + cholmod_sparse *G = CHOLMOD(add) (C, Z, one, one, 2, false, cm); + CHOLMOD(sparse_xtype) (CHOLMOD_REAL, G, cm) ; + CHOLMOD(print_sparse) (G, "G", cm) ; + CHOLMOD(print_sparse) (A, "A", cm) ; + E = CHOLMOD(add) (G, A, one, minusone, 2, true, cm) ; + CHOLMOD(print_sparse) (E, "E", cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + printf ("pattern enorm %g\n", enorm) ; + OK (enorm == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + //---------------------------------------------------------------------- + // write C as a dense matrix and read it back in + //---------------------------------------------------------------------- + + cholmod_dense *X = CHOLMOD(sparse_to_dense) (C, cm) ; + f = fopen ("temp6.mtx", "w") ; + CHOLMOD(write_dense) (f, X, NULL, cm) ; + fclose (f) ; + f = fopen ("temp6.mtx", "r") ; + cholmod_dense *Y = CHOLMOD(read_dense2) (f, DTYPE, cm) ; + cholmod_sparse *X2 = CHOLMOD(dense_to_sparse) (X, true, cm) ; + cholmod_sparse *Y2 = CHOLMOD(dense_to_sparse) (Y, true, cm) ; + + CHOLMOD(print_sparse) (X2, "X2", cm) ; + CHOLMOD(print_sparse) (Y2, "Y2", cm) ; + E = CHOLMOD(add) (X2, Y2, one, minusone, 2, true, cm) ; + CHOLMOD(print_sparse) (E, "E", cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + printf ("dense enorm %g\n", enorm) ; + OK (enorm == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + + CHOLMOD(free_sparse) (&X2, cm) ; + CHOLMOD(free_sparse) (&Y2, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_sparse) (&Z, cm) ; +} + +//------------------------------------------------------------------------------ +// *_test: test read/write methods +//------------------------------------------------------------------------------ + +int main (int argc, char **argv) +{ + cholmod_sparse *C ; + cholmod_dense *X ; + cholmod_triplet *T ; + void *V ; + FILE *f ; + cholmod_common Common, *cm ; + int mtype, prefer ; + + //-------------------------------------------------------------------------- + // get the file containing the input matrix + //-------------------------------------------------------------------------- + + char *filename = NULL; + bool mangled = false ; + if (argc > 1) + { + char *arg = argv [1] ; + if (arg [0] == '-' && arg [1] == 'x') + { + mangled = true ; + filename = (argc > 2) ? argv [2] : NULL ; + } + else + { + filename = argv [1] ; + } + } + + if (filename == NULL) + { + f = stdin ; + } + else + { + if ((f = fopen (filename, "r")) == NULL) + { + printf ("cannot open file: %s\n", filename) ; + return (0) ; + } + } + + //-------------------------------------------------------------------------- + // start CHOLMOD, read the matrix, print it, and free it + //-------------------------------------------------------------------------- + + cm = &Common ; + CHOLMOD(start) (cm) ; + cm->print = 5 ; + + //-------------------------------------------------------------------------- + // read the matrix (assuming it's sparse), print it, and free it + //-------------------------------------------------------------------------- + + cholmod_sparse *A = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; + if (argc > 1) fclose (f) ; + if (A == NULL) + { + printf ("Matrix is mangled, or not sparse\n") ; + } + CHOLMOD(print_sparse) (A, "A", cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + + //-------------------------------------------------------------------------- + // read the matrix in different formats + //-------------------------------------------------------------------------- + + if (argc > 1) + { + for (prefer = 0 ; prefer <= 2 ; prefer++) + { + printf ("\n---------------------- Prefer: %d\n", prefer) ; + f = fopen (filename, "r") ; + V = CHOLMOD(read_matrix2) (f, prefer, DTYPE, &mtype, cm) ; + if (V == NULL) + { + printf ("Matrix is mangled\n") ; + OK (mangled) ; + } + else + { + printf ("Matrix is OK\n") ; + OK (!mangled) ; + switch (mtype) + { + case CHOLMOD_TRIPLET: + printf ("\n=========================TRIPLET:\n") ; + T = V ; + CHOLMOD(print_triplet) (T, "T", cm) ; + OK (T->dtype == DTYPE) ; + C = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + test_sparse (C, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_triplet) (&T, cm) ; + break ; + + case CHOLMOD_SPARSE: + printf ("\n=========================SPARSE:\n") ; + C = V ; + CHOLMOD(print_sparse) (C, "C", cm) ; + OK (C->dtype == DTYPE) ; + test_sparse (C, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + break ; + + case CHOLMOD_DENSE: + printf ("\n=========================DENSE:\n") ; + X = V ; + CHOLMOD(print_dense) (X, "X", cm) ; + OK (X->dtype == DTYPE) ; + C = CHOLMOD(dense_to_sparse) (X, true, cm) ; + test_sparse (C, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + break ; + } + } + fclose (f) ; + } + } + + CHOLMOD(finish) (cm) ; + return (0) ; +} + diff --git a/CHOLMOD/Tcov/t_common_tests.c b/CHOLMOD/Tcov/t_common_tests.c new file mode 100644 index 0000000000..945d59b0ae --- /dev/null +++ b/CHOLMOD/Tcov/t_common_tests.c @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_common_tests: tests for cholmod_common +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +void common_tests (cholmod_common *cm) +{ + int cm_print_save = cm->print ; + cm->print = 5 ; + + cm->status = CHOLMOD_GPU_PROBLEM ; + CHOLMOD(print_common) ("cm:gpu", cm) ; + cm->status = CHOLMOD_OK ; + + int save1 = cm->supernodal = -1 ; + cm->supernodal = -1 ; + CHOLMOD(print_common) ("cm:always_simplicial", cm) ; + cm->supernodal = save1 ; + + save1 = cm->default_nesdis ; + int save2 = cm->nmethods ; + cm->nmethods = 0 ; + cm->default_nesdis = true ; + CHOLMOD(print_common) ("cm:default_nesdis", cm) ; + cm->default_nesdis = save1 ; + cm->nmethods = save2 ; + + save1 = cm->nmethods ; + cm->nmethods = 2 ; + save2 = cm->method [0].ordering ; + int save3 = cm->method [1].ordering ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->method [1].ordering = CHOLMOD_METIS ; + cm->method [2].fl = 32 ; + cm->method [2].lnz = 8 ; + CHOLMOD(print_common) ("cm:amd_backup", cm) ; + cm->nmethods = save1 ; + cm->method [0].ordering = save2 ; + cm->method [1].ordering = save3 ; + cm->method [2].fl = EMPTY ; + cm->method [2].lnz = EMPTY ; + + save1 = cm->final_asis ; + cm->final_asis = false ; + save2 = cm->final_ll ; + cm->final_ll = true ; + CHOLMOD(print_common) ("cm:final_ll", cm) ; + cm->final_asis = save1 ; + cm->final_ll = save2 ; + + cm->print = cm_print_save ; +} + diff --git a/CHOLMOD/Tcov/t_ctest.c b/CHOLMOD/Tcov/t_ctest.c new file mode 100644 index 0000000000..e75a3f3ce8 --- /dev/null +++ b/CHOLMOD/Tcov/t_ctest.c @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_ctest: test for COLAMD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include "cm.h" +#include "colamd.h" + +//------------------------------------------------------------------------------ +// ctest +//------------------------------------------------------------------------------ + +void ctest (cholmod_sparse *A) +{ + double knobs [COLAMD_KNOBS], knobs2 [COLAMD_KNOBS] ; + Int *P, *Cp, *Ci, *Si, *Sp ; + cholmod_sparse *C, *A2, *B, *S, *BT ; + Int nrow, ncol, alen, ok, stats [COLAMD_STATS], i, p, trial ; + size_t s ; + + //-------------------------------------------------------------------------- + // get inputs + //-------------------------------------------------------------------------- + + printf ("\nCOLAMD test\n") ; + + if (A == NULL) + { + return ; + } + + if (A->stype) + { + A2 = CHOLMOD(copy) (A, 0, 0, cm) ; + B = A2 ; + } + else + { + A2 = NULL ; + B = A ; + } + + nrow = B->nrow ; + ncol = B->ncol ; + S = NULL ; + + //-------------------------------------------------------------------------- + // allocate workspace colamd + //-------------------------------------------------------------------------- + + P = CHOLMOD(malloc) (nrow+1, sizeof (Int), cm) ; + + COLAMD_set_defaults (knobs) ; + COLAMD_set_defaults (knobs2) ; + COLAMD_set_defaults (NULL) ; + COLAMD_report (NULL) ; + SYMAMD_report (NULL) ; + + alen = COLAMD_recommended (B->nzmax, ncol, nrow) ; + C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + Cp = C->p ; + Ci = C->i ; + + //-------------------------------------------------------------------------- + // order with colamd + //-------------------------------------------------------------------------- + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + CHOLMOD(print_sparse) (C, "C for colamd", cm) ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, NULL, stats) ; + COLAMD_report (stats) ; + OK (ok) ; + ok = stats [COLAMD_STATUS] ; + ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ; + OK (ok) ; + + // permutation returned in C->p, if the ordering succeeded + // make sure P obeys the constraints + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; + + //-------------------------------------------------------------------------- + // with different dense thresholds + //-------------------------------------------------------------------------- + + printf ("\nall dense rows:\n") ; + knobs2 [COLAMD_DENSE_ROW] = 0 ; + knobs2 [COLAMD_DENSE_COL] = 0.5 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; + COLAMD_report (stats) ; + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; + + printf ("\nall dense cols:\n") ; + knobs2 [COLAMD_DENSE_ROW] = 0.5 ; + knobs2 [COLAMD_DENSE_COL] = 0 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; + COLAMD_report (stats) ; + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; + + printf ("\nno dense rows/cols:\n") ; + knobs2 [COLAMD_DENSE_ROW] = -1 ; + knobs2 [COLAMD_DENSE_COL] = -1 ; + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; + COLAMD_report (stats) ; + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; + + knobs2 [COLAMD_DENSE_ROW] = 0.5 ; + knobs2 [COLAMD_DENSE_COL] = 0.5 ; + + //-------------------------------------------------------------------------- + // duplicate entries + //-------------------------------------------------------------------------- + + if (ncol > 2 && nrow > 2) + { + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + if (Cp [1] - Cp [0] > 2) + { + Ci [0] = Ci [1] ; + } + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs2, stats) ; + COLAMD_report (stats) ; + OK (CHOLMOD(print_perm) (Cp, nrow, nrow, "colamd perm", cm)) ; + } + + //-------------------------------------------------------------------------- + // symamd + //-------------------------------------------------------------------------- + + if (nrow == ncol) + { + Int n = nrow ; + + BT = CHOLMOD(transpose) (B, 0, cm) ; + OKP(BT); + S = CHOLMOD(add) (B, BT, one, one, FALSE, FALSE, cm) ; + CHOLMOD(free_sparse) (&BT, cm) ; + Si = S->i ; + Sp = S->p ; + + void * (*calloc_func) (size_t, size_t) ; + void (*free_func) (void *) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + OK (ok) ; + OK (CHOLMOD(print_perm) (P, n, n, "symamd perm", cm)) ; + SYMAMD_report (stats) ; + + //---------------------------------------------------------------------- + // symamd errors + //---------------------------------------------------------------------- + + test_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + for (trial = 0 ; trial < 3 ; trial++) + { + my_tries = trial ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok) ; + } + my_tries = 3 ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + OK (ok) ; + normal_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, NULL, + calloc_func, free_func) ; + NOT (ok); + + ok = SYMAMD_MAIN (n, NULL, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + + ok = SYMAMD_MAIN (n, Si, NULL, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + + ok = SYMAMD_MAIN (-1, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + + p = Sp [n] ; + Sp [n] = -1 ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + Sp [n] = p ; + + Sp [0] = -1 ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + Sp [0] = 0 ; + + if (n > 2 && Sp [n] > 3) + { + p = Sp [1] ; + Sp [1] = -1 ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + Sp [1] = p ; + + i = Si [0] ; + Si [0] = -1 ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + Si [0] = i ; + + // ok, but jumbled + i = Si [0] ; + Si [0] = Si [1] ; + Si [1] = i ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + OK (ok); + SYMAMD_report (stats) ; + OK (CHOLMOD(print_perm) (P, nrow, nrow, "symamd perm", cm)) ; + i = Si [0] ; + Si [0] = Si [1] ; + Si [1] = i ; + + test_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + ok = SYMAMD_MAIN (n, Si, Sp, P, NULL, stats, + calloc_func, free_func) ; + NOT (ok); + SYMAMD_report (stats) ; + normal_memory_handler ( ) ; + calloc_func = SuiteSparse_config_calloc_func_get ( ) ; + free_func = SuiteSparse_config_free_func_get ( ) ; + } + } + + //-------------------------------------------------------------------------- + // error tests + //-------------------------------------------------------------------------- + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + ok = COLAMD_MAIN (ncol, nrow, 0, Ci, Cp, knobs, stats) ; + NOT (ok) ; + COLAMD_report (stats) ; + + ok = COLAMD_MAIN (ncol, nrow, alen, NULL, Cp, knobs, stats); + NOT (ok) ; + COLAMD_report (stats) ; + + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, NULL, knobs, stats); + NOT (ok) ; + COLAMD_report (stats) ; + + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, NULL) ; + NOT (ok) ; + COLAMD_report (stats) ; + + ok = COLAMD_MAIN (-1, nrow, alen, Ci, Cp, knobs, stats) ; + NOT (ok) ; + COLAMD_report (stats) ; + + ok = COLAMD_MAIN (ncol, -1, alen, Ci, Cp, knobs, stats) ; + NOT (ok) ; + COLAMD_report (stats) ; + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + Cp [nrow] = -1 ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; + NOT (ok) ; + COLAMD_report (stats) ; + + Cp [0] = 1 ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; + NOT (ok) ; + COLAMD_report (stats) ; + + ok = CHOLMOD(transpose_unsym) (B, 0, NULL, NULL, 0, C, cm) ; + OK (ok) ; + + if (nrow > 0 && alen > 0 && Cp [1] > 0) + { + + p = Cp [1] ; + Cp [1] = -1 ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; + NOT(ok); + COLAMD_report (stats) ; + Cp [1] = p ; + + i = Ci [0] ; + Ci [0] = -1 ; + ok = COLAMD_MAIN (ncol, nrow, alen, Ci, Cp, knobs, stats) ; + NOT(ok); + COLAMD_report (stats) ; + Ci [0] = i ; + } + + s = COLAMD_recommended (-1, 0, 0) ; + OK (s == 0) ; + + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + + CHOLMOD(free) (nrow+1, sizeof (Int), P, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; +} + diff --git a/CHOLMOD/Tcov/t_dense_tests.c b/CHOLMOD/Tcov/t_dense_tests.c new file mode 100644 index 0000000000..1144898ff7 --- /dev/null +++ b/CHOLMOD/Tcov/t_dense_tests.c @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_dense_tests: dense matrix tests +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +double dense_tests (cholmod_sparse *A_input, cholmod_common *cm) +{ + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + int xtype = A_input->xtype ; + double maxerr = 0 ; + + if (nrow > 100000) + { + // test skipped + return (-1) ; + } + + cholmod_dense *X = rand_dense (nrow, 4, xtype + DTYPE, cm) ; + cholmod_dense *Y = CHOLMOD(allocate_dense) (nrow, 4, nrow + 7, + xtype + DTYPE, cm) ; + cholmod_dense *Z = CHOLMOD(allocate_dense) (nrow, 4, nrow + 4, + xtype + DTYPE, cm) ; + + // Y = X (with change of leading dimension) + CHOLMOD(copy_dense2) (X, Y, cm) ; + + // Z = Y (with another change of leading dimension) + CHOLMOD(copy_dense2) (Y, Z, cm) ; + + // SX = sparse (X) + cholmod_sparse *SX = CHOLMOD(dense_to_sparse) (X, true, cm) ; + + // SZ = sparse (Z) + cholmod_sparse *SZ = CHOLMOD(dense_to_sparse) (Z, true, cm) ; + + // E = SX-SZ + cholmod_sparse *E = CHOLMOD(add) (SX, SZ, one, minusone, true, true, cm) ; + double cnorm = CHOLMOD(norm_sparse) (SX, 0, cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, cnorm) ; + + // free matrices and return results + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&SX, cm) ; + CHOLMOD(free_sparse) (&SZ, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + CHOLMOD(free_dense) (&Z, cm) ; + + printf ("dense maxerr %g\n", maxerr) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_dtype_tests.c b/CHOLMOD/Tcov/t_dtype_tests.c new file mode 100644 index 0000000000..5017546ef3 --- /dev/null +++ b/CHOLMOD/Tcov/t_dtype_tests.c @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_dtype_tests: tests with changing dtype +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +double dtype_tests (cholmod_sparse *A_input, cholmod_common *cm) +{ + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + int xtype = A_input->xtype ; + double maxerr = 0 ; + + // A = double(single(A_input)) or A = single(double(A_input)) + int other = (DTYPE == CHOLMOD_SINGLE) ? CHOLMOD_DOUBLE : CHOLMOD_SINGLE ; + cholmod_sparse *A = CHOLMOD(copy_sparse) (A_input, cm) ; + CHOLMOD(sparse_xtype) (xtype + other, A, cm) ; + CHOLMOD(sparse_xtype) (xtype + DTYPE, A, cm) ; + + // E = A_input - A + cholmod_sparse *E = CHOLMOD(add) (A_input, A, one, minusone, + true, true, cm) ; + double anorm = CHOLMOD(norm_sparse) (A_input, 0, cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + + printf ("dtype maxerr %g\n", maxerr) ; + OK (maxerr < 1e-5) ; + + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_dump.c b/CHOLMOD/Tcov/t_dump.c new file mode 100644 index 0000000000..a789bd7590 --- /dev/null +++ b/CHOLMOD/Tcov/t_dump.c @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_dump: debug routines for CHOLMOD test programs +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// sparse_dump +//------------------------------------------------------------------------------ + +// dump a sparse matrix in triplet form. The up, lo, up/lo format is ignored. + +void sparse_dump (cholmod_sparse *A, char *filename, cholmod_common *cm) +{ + if (!A) return ; + FILE *ff = fopen (filename, "w") ; + if (!ff) return ; + Int *Ap = A->p ; + Int *Ai = A->i ; + Real *Ax = A->x ; + Real *Az = A->z ; + Int *Anz = A->nz ; + bool packed = A->packed ; + for (Int j = 0 ; j < A->ncol ; j++) + { + Int p = Ap [j] ; + Int pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + Int i = Ai [p] ; + if (A->xtype == CHOLMOD_PATTERN) + { + fprintf (ff, ID " " ID "\n", i, j) ; + } + else if (A->xtype == CHOLMOD_REAL) + { + fprintf (ff, ID " " ID " %30.16g\n", i, j, Ax [p]) ; + } + else if (A->xtype == CHOLMOD_COMPLEX) + { + fprintf (ff, ID " " ID " %30.16g %30.16g\n", i, j, + Ax [2*p], Ax [2*p+1]) ; + } + else // zomplex + { + fprintf (ff, ID " " ID " %30.16g %30.16g\n", i, j, + Ax [p], Az [p]) ; + } + } + } + fclose (ff) ; +} + +//------------------------------------------------------------------------------ +// Int_dump +//------------------------------------------------------------------------------ + +void Int_dump (Int *P, Int n, char *filename, cholmod_common *cm) +{ + if (!P) return ; + FILE *ff = fopen (filename, "w") ; + if (!ff) return ; + for (Int k = 0 ; k < n ; k++) + { + fprintf (ff, ID "\n", P [k]) ; + } + fclose (ff) ; +} + +//------------------------------------------------------------------------------ +// factor_dump +//------------------------------------------------------------------------------ + +// dump a sparse factorization matrix in triplet form, as an LL' factorization + +void factor_dump (cholmod_factor *L, char *L_filename, char *P_filename, + cholmod_common *cm) +{ + if (!L) return ; + Int_dump (L->Perm, L->n, P_filename, cm) ; + cholmod_factor *L2 = CHOLMOD(copy_factor) (L, cm) ; + cholmod_sparse *A = CHOLMOD(factor_to_sparse) (L2, cm) ; + sparse_dump (A, L_filename, cm) ; + CHOLMOD(free_factor) (&L2, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; +} + +//------------------------------------------------------------------------------ +// dense_dump +//------------------------------------------------------------------------------ + +// dump a dense matrix in triplet form + +void dense_dump (cholmod_dense *X, char *filename, cholmod_common *cm) +{ + if (!X) return ; + cholmod_sparse *A = CHOLMOD(dense_to_sparse) (X, 1, cm) ; + sparse_dump (A, filename, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; +} + diff --git a/CHOLMOD/Tcov/t_error_tests.c b/CHOLMOD/Tcov/t_error_tests.c new file mode 100644 index 0000000000..b960e93c9d --- /dev/null +++ b/CHOLMOD/Tcov/t_error_tests.c @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_error_tests: misc error tests +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +void error_tests (cholmod_sparse *A_input, cholmod_common *cm) +{ + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + OK (DTYPE == A_input->dtype) ; + int xtype = A_input->xtype ; + int stype = A_input->stype ; + double maxerr = 0 ; + int save ; + int cm_print_save = cm->print ; + cm->print = 4 ; + cm->error_handler = NULL ; + int ok ; + + //-------------------------------------------------------------------------- + // make a copy of the input matrix + //-------------------------------------------------------------------------- + + cholmod_sparse *A = CHOLMOD(copy_sparse) (A_input, cm) ; + + int other_xtype ; + switch (xtype) + { + case CHOLMOD_REAL: other_xtype = CHOLMOD_COMPLEX ; break ; + case CHOLMOD_COMPLEX: other_xtype = CHOLMOD_REAL ; break ; + case CHOLMOD_ZOMPLEX: other_xtype = CHOLMOD_REAL ; break ; + default: other_xtype = xtype ; break ; + } + + int other_dtype ; + switch (DTYPE) + { + case CHOLMOD_DOUBLE: other_dtype = CHOLMOD_SINGLE; break ; + case CHOLMOD_SINGLE: other_dtype = CHOLMOD_DOUBLE; break ; + } + + //-------------------------------------------------------------------------- + // matrices with invalid dtypes + //-------------------------------------------------------------------------- + + { + + //---------------------------------------------------------------------- + // cholmod_sparse + //---------------------------------------------------------------------- + + cholmod_sparse *S = CHOLMOD(speye) (2, 2, xtype + DTYPE, cm) ; + if (S != NULL) + { + save = S->dtype ; + S->dtype = 99 ; + ok = CHOLMOD(print_sparse) (S, "S:dtype mangled", cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + S->dtype = save ; + } + CHOLMOD(free_sparse) (&S, cm) ; + + //---------------------------------------------------------------------- + // cholmod_triplet + //---------------------------------------------------------------------- + + cholmod_triplet *T = CHOLMOD(allocate_triplet) (nrow, ncol, 10, stype, + xtype + DTYPE, cm) ; + if (T != NULL) + { + save = T->dtype ; + T->dtype = 911 ; + ok = CHOLMOD(print_triplet) (T, "T:dtype mangled", cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + T->dtype = save ; + } + CHOLMOD(free_triplet) (&T, cm) ; + + //---------------------------------------------------------------------- + // cholmod_dense + //---------------------------------------------------------------------- + + cholmod_dense *X = CHOLMOD(allocate_dense) (5, 5, 5, xtype + DTYPE, + cm) ; + if (X != NULL) + { + save = X->dtype ; + X->dtype = 911 ; + ok = CHOLMOD(print_dense) (X, "X:dtype mangled", cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + X->dtype = save ; + } + CHOLMOD(free_dense) (&X, cm) ; + + //---------------------------------------------------------------------- + // cholmod_ensure_dense + //---------------------------------------------------------------------- + + CHOLMOD(ensure_dense) (&X, 5, 5, 5, CHOLMOD_PATTERN + DTYPE, cm) ; + OK (X == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + } + + //-------------------------------------------------------------------------- + // matrices with different xtypes + //-------------------------------------------------------------------------- + + if (other_xtype != xtype) + { + + cholmod_sparse *B = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sparse_xtype) (other_xtype + DTYPE, B, cm) ; + + //---------------------------------------------------------------------- + // horzcat + //---------------------------------------------------------------------- + + cholmod_sparse *C = CHOLMOD(horzcat) (A, B, true, cm) ; + OK (C == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // vertcat + //---------------------------------------------------------------------- + + C = CHOLMOD(vertcat) (A, B, true, cm) ; + OK (C == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // scale + //---------------------------------------------------------------------- + + cholmod_dense *X = CHOLMOD(ones) (1, 1, other_xtype + DTYPE, cm) ; + ok = CHOLMOD(scale) (X, CHOLMOD_SCALAR, A, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + CHOLMOD(free_dense) (&X, cm) ; + + CHOLMOD(free_sparse) (&B, cm) ; + } + + //-------------------------------------------------------------------------- + // matrices with different dtypes + //-------------------------------------------------------------------------- + + if (xtype == CHOLMOD_REAL) + { + cholmod_sparse *R = CHOLMOD(speye) (nrow, 1, xtype + other_dtype, cm) ; + cholmod_factor *L = CHOLMOD(analyze) (A, cm) ; + CHOLMOD(factorize) (A, L, cm) ; + + cholmod_sparse *B = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sparse_xtype) (xtype + other_dtype, B, cm) ; + + if (cm->status == CHOLMOD_OK) + { + + //------------------------------------------------------------------ + // super_numeric + //------------------------------------------------------------------ + + int is_super = L->is_super ; + L->is_super = true ; + CHOLMOD(super_numeric) (B, B, one, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + L->is_super = is_super ; + + //------------------------------------------------------------------ + // rowadd + //------------------------------------------------------------------ + + ok = CHOLMOD(rowadd) (0, R, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //------------------------------------------------------------------ + // updown + //------------------------------------------------------------------ + + ok = CHOLMOD(updown) (1, R, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //------------------------------------------------------------------ + // spsolve + //------------------------------------------------------------------ + + cholmod_sparse *C = CHOLMOD(spsolve) (CHOLMOD_A, L, R, cm) ; + OK (C == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //------------------------------------------------------------------ + // add + //------------------------------------------------------------------ + + C = CHOLMOD(add) (A, B, one, one, true, true, cm) ; + OK (C == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + } + + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_sparse) (&R, cm) ; + } + + //-------------------------------------------------------------------------- + // matrices with different dimensions + //-------------------------------------------------------------------------- + + cholmod_sparse *S = CHOLMOD(speye) (nrow+1, ncol+1, xtype + DTYPE, cm) ; + + if (S != NULL) + { + + //--------------------------------------------------------------------- + // add + //--------------------------------------------------------------------- + + cholmod_sparse *C = CHOLMOD(add) (A, S, one, one, true, true, cm) ; + OK (C == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + } + + CHOLMOD(free_sparse) (&S, cm) ; + + //-------------------------------------------------------------------------- + // invalid stype + //-------------------------------------------------------------------------- + + if (nrow != ncol) + { + + //---------------------------------------------------------------------- + // allocate_triplet + //---------------------------------------------------------------------- + + cholmod_triplet *T = CHOLMOD(allocate_triplet) (nrow, ncol, 10, 1, + xtype + DTYPE, cm) ; + OK (T == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // copy + //---------------------------------------------------------------------- + + cholmod_sparse *S = CHOLMOD(copy) (A, 1, 0, cm) ; + OK (S == NULL) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + } + + //-------------------------------------------------------------------------- + // realloc_multiple + //-------------------------------------------------------------------------- + + size_t siz = 0 ; + ok = CHOLMOD(realloc_multiple) (2, 2, CHOLMOD_PATTERN + DTYPE, + NULL, NULL, NULL, NULL, &siz, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + + //-------------------------------------------------------------------------- + // solve2 + //-------------------------------------------------------------------------- + + cholmod_factor *L = CHOLMOD(analyze) (A, cm) ; + ok = CHOLMOD(factorize) (A, L, cm) ; + OK (ok) ; + cholmod_dense *B = CHOLMOD(ones) (nrow, 1, xtype + other_dtype, cm) ; + cholmod_dense *X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + NOP (X) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + CHOLMOD(free_dense) (&B, cm) ; + + cholmod_sparse *Xset = NULL ; + cholmod_dense *Y = NULL, *E = NULL ; + cholmod_sparse *Bset = CHOLMOD(speye) (nrow, 1, xtype + DTYPE, cm) ; + B = CHOLMOD(ones) (nrow, 2, xtype + DTYPE, cm) ; + X = CHOLMOD(ones) (nrow, 1, xtype + DTYPE, cm) ; + ok = CHOLMOD(solve2) (CHOLMOD_A, L, B, Bset, &X, &Xset, &Y, &E, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + CHOLMOD(free_dense) (&B, cm) ; + + B = CHOLMOD(ones) (nrow, 1, other_xtype + DTYPE, cm) ; + ok = CHOLMOD(solve2) (CHOLMOD_A, L, B, Bset, &X, &Xset, &Y, &E, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_INVALID) ; + cm->status = CHOLMOD_OK ; + CHOLMOD(free_dense) (&B, cm) ; + + CHOLMOD(free_sparse) (&Xset, cm) ; + CHOLMOD(free_sparse) (&Bset, cm) ; + CHOLMOD(free_dense) (&E, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and restore error handling + //-------------------------------------------------------------------------- + + CHOLMOD(free_sparse) (&A, cm) ; + cm->print = cm_print_save ; + cm->error_handler = my_handler ; +} + diff --git a/CHOLMOD/Tcov/t_huge.c b/CHOLMOD/Tcov/t_huge.c new file mode 100644 index 0000000000..12a43ff58b --- /dev/null +++ b/CHOLMOD/Tcov/t_huge.c @@ -0,0 +1,383 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_huge: test program for CHOLMOD on huge matrices +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Tests on huge matrices + +#include "cm.h" +#include "amd.h" +#ifndef NCAMD +#include "camd.h" +#endif + +#undef ERROR +#define ERROR(status,message) \ + CHOLMOD(error) (status, __FILE__, __LINE__, message, cm) + +//------------------------------------------------------------------------------ +// huge +//------------------------------------------------------------------------------ + +void huge ( ) +{ + + printf ("=================================\ntests with huge matrices:\n") ; + cholmod_sparse *A, *C ; + cholmod_triplet *T ; + cholmod_factor *L ; + cholmod_dense *X ; + size_t n ; + int ok = TRUE, save ; + Int junk = 0 ; + double beta [2] ; + + //-------------------------------------------------------------------------- + // allocate_work + //-------------------------------------------------------------------------- + + n = SIZE_MAX ; + CHOLMOD (free_work) (cm) ; + CHOLMOD (allocate_work) (n, 0, 0, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // add_size_t + //-------------------------------------------------------------------------- + + n = CHOLMOD(add_size_t) (n, 1, &ok) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // create a fake zero sparse matrix, with huge dimensions + //-------------------------------------------------------------------------- + + A = CHOLMOD (spzeros) (1, 1, 0, CHOLMOD_REAL + DTYPE, cm) ; + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + A->stype = 0 ; + + //-------------------------------------------------------------------------- + // factorize + //-------------------------------------------------------------------------- + +// L = CHOLMOD (allocate_factor) (1, cm) ; + L = CHOLMOD (alloc_factor) (1, DTYPE, cm) ; + OKP (L) ; + L->n = SIZE_MAX ; + CHOLMOD (factorize) (A, L, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + // free the fake factor + L->n = 1 ; + CHOLMOD (free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // resymbol, rowfac, rowadd, rowdel, and updown + //-------------------------------------------------------------------------- + + C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + C->stype = 1 ; + L = CHOLMOD (analyze) (C, cm) ; + OKP (L) ; + OKP (L) ; + CHOLMOD (factorize) (C, L, cm) ; + ok = CHOLMOD (resymbol) (C, NULL, 0, 0, L, cm) ; + OK (ok) ; + C->nrow = SIZE_MAX ; + C->ncol = SIZE_MAX ; + L->n = SIZE_MAX ; + + ok = CHOLMOD (resymbol) (C, NULL, 0, 0, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + printf ("rowfac:\n") ; + beta [0] = 1 ; + beta [1] = 0 ; + C->xtype = CHOLMOD_COMPLEX ; + L->xtype = CHOLMOD_COMPLEX ; + ok = CHOLMOD (rowfac) (C, NULL, beta, 0, 0, L, cm) ; + printf ("rowfac %d\n", cm->status) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + C->xtype = CHOLMOD_REAL ; + L->xtype = CHOLMOD_REAL ; + printf ("rowfac done:\n") ; + + C->stype = -1 ; + ok = CHOLMOD (resymbol_noperm) (C, NULL, 0, 0, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + C->ncol = 1 ; + CHOLMOD (rowadd) (0, C, L, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + CHOLMOD (rowdel) (0, C, L, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + C->ncol = 4 ; + CHOLMOD (updown) (1, C, L, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + C->nrow = 1 ; + C->ncol = 1 ; + L->n = 1 ; + CHOLMOD (free_sparse) (&C, cm) ; + CHOLMOD (free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // allocate_sparse + //-------------------------------------------------------------------------- + + C = CHOLMOD (allocate_sparse) (SIZE_MAX, SIZE_MAX, SIZE_MAX, + 0, 0, 0, CHOLMOD_PATTERN + DTYPE, cm) ; + NOP (C) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // rowcolcounts + //-------------------------------------------------------------------------- + + CHOLMOD (rowcolcounts) (A, NULL, 0, + &junk, &junk, &junk, &junk, &junk, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // submatrix + //-------------------------------------------------------------------------- + + C = CHOLMOD (submatrix) (A, &junk, SIZE_MAX/4, &junk, SIZE_MAX/4, + 0, 0, cm) ; + NOP (C) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // transpose and variants + //-------------------------------------------------------------------------- + + ok = CHOLMOD (transpose_unsym) (A, 0, &junk, &junk, SIZE_MAX, A, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE || + cm->status == CHOLMOD_OUT_OF_MEMORY || + cm->status == CHOLMOD_INVALID); + + A->stype = 1 ; + ok = CHOLMOD (transpose_sym) (A, 0, &junk, A, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE || + cm->status == CHOLMOD_OUT_OF_MEMORY || + cm->status == CHOLMOD_INVALID); + + C = CHOLMOD (ptranspose) (A, 0, &junk, NULL, 0, cm) ; + NOP (C) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + A->stype = 0 ; + + //-------------------------------------------------------------------------- + // amd + //-------------------------------------------------------------------------- + + CHOLMOD (amd) (A, NULL, 0, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // analyze + //-------------------------------------------------------------------------- + + L = CHOLMOD (analyze) (A, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + NOP (L) ; + + //-------------------------------------------------------------------------- + // camd + //-------------------------------------------------------------------------- + + #ifndef NCAMD + CHOLMOD (camd) (A, NULL, 0, &junk, NULL, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + #endif + + //-------------------------------------------------------------------------- + // colamd + //-------------------------------------------------------------------------- + + printf ("calling colamd\n") ; + CHOLMOD (colamd) (A, NULL, 0, 0, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // ccolamd + //-------------------------------------------------------------------------- + + #ifndef NCAMD + printf ("calling ccolamd\n") ; + CHOLMOD (ccolamd) (A, NULL, 0, NULL, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + #endif + + //-------------------------------------------------------------------------- + // etree + //-------------------------------------------------------------------------- + + CHOLMOD (etree) (A, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // allocate factor + //-------------------------------------------------------------------------- + + L = CHOLMOD (allocate_factor) (SIZE_MAX, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + NOP (L) ; + + //-------------------------------------------------------------------------- + // alloc factor + //-------------------------------------------------------------------------- + + L = CHOLMOD (alloc_factor) (SIZE_MAX, DTYPE, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + NOP (L) ; + + //-------------------------------------------------------------------------- + // metis, bisect, and nested dissection + //-------------------------------------------------------------------------- + + #ifndef NPARTITION + CHOLMOD (metis) (A, NULL, 0, 0, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + CHOLMOD (bisect) (A, NULL, 0, 0, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + CHOLMOD (nested_dissection) (A, NULL, 0, &junk, &junk, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + #endif + + //-------------------------------------------------------------------------- + // postorder + //-------------------------------------------------------------------------- + + CHOLMOD (postorder) (&junk, SIZE_MAX, &junk, &junk, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + + //-------------------------------------------------------------------------- + // read_triplet + //-------------------------------------------------------------------------- + + // causes overflow in 32-bit version, but not 64-bit + FILE *f = fopen ("Matrix/mega.tri", "r") ; + OK (f != NULL) ; + T = CHOLMOD (read_triplet) (f, cm) ; + if (sizeof (Int) == sizeof (int)) + { + NOP (T) ; + OK (cm->status != CHOLMOD_OK) ; + } + CHOLMOD (free_triplet) (&T, cm) ; + fclose (f) ; + + //-------------------------------------------------------------------------- + // allocate_dense + //-------------------------------------------------------------------------- + + n = SIZE_MAX ; + X = CHOLMOD (allocate_dense) (n, 1, n, CHOLMOD_REAL + DTYPE, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + NOP (X) ; + + //-------------------------------------------------------------------------- + // supernodal symbolic + //-------------------------------------------------------------------------- + + C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + C->stype = 1 ; + save = cm->supernodal ; + cm->supernodal = CHOLMOD_SIMPLICIAL ; + L = CHOLMOD (analyze) (C, cm) ; + OKP (L) ; + junk = 0 ; + C->nrow = SIZE_MAX ; + C->ncol = SIZE_MAX ; + L->n = SIZE_MAX ; + CHOLMOD (super_symbolic) (C, C, &junk, L, cm) ; + OK (cm->status == CHOLMOD_TOO_LARGE || cm->status == CHOLMOD_OUT_OF_MEMORY); + cm->supernodal = save ; + C->nrow = 1 ; + C->ncol = 1 ; + L->n = 1 ; + CHOLMOD (free_sparse) (&C, cm) ; + CHOLMOD (free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // supernodal numeric + //-------------------------------------------------------------------------- + + C = CHOLMOD (speye) (1, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + C->stype = -1 ; + save = cm->supernodal ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + L = CHOLMOD (analyze) (C, cm) ; + OKP (L) ; + OK (cm->status == CHOLMOD_OK) ; + C->nrow = SIZE_MAX ; + C->ncol = SIZE_MAX ; + L->n = SIZE_MAX ; + CHOLMOD (super_numeric) (C, C, beta, L, cm) ; + cm->supernodal = save ; + C->nrow = 1 ; + C->ncol = 1 ; + L->n = 1 ; + CHOLMOD (free_sparse) (&C, cm) ; + CHOLMOD (free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // sort + //-------------------------------------------------------------------------- + + n = 100000 ; + X = CHOLMOD(ones) (n, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (X) ; + C = CHOLMOD(dense_to_sparse) (X, true, cm) ; + OKP (C) ; + Int *P = prand ((Int) n) ; // RAND + OKP (P) ; + + Int *Ci = C->i ; + Real *Cx = C->x ; + for (Int k = 0 ; k < n ; k++) + { + Ci [k] = P [k] ; + Cx [k] = P [k] ; + } + + C->sorted = false ; + CHOLMOD(sort) (C, cm) ; + OK (C->sorted) ; + + for (Int k = 0 ; k < n ; k++) + { + OK (Ci [k] == k) ; + OK (Cx [k] == k) ; + } + + CHOLMOD (free_sparse) (&C, cm) ; + CHOLMOD (free_dense) (&X, cm) ; + CHOLMOD (free) (n, sizeof (Int), P, cm) ; + + //-------------------------------------------------------------------------- + // free the fake matrix + //-------------------------------------------------------------------------- + + A->nrow = 1 ; + A->ncol = 1 ; + CHOLMOD (free_sparse) (&A, cm) ; +} + diff --git a/CHOLMOD/Tcov/t_lpdemo.c b/CHOLMOD/Tcov/t_lpdemo.c new file mode 100644 index 0000000000..a1325f3e24 --- /dev/null +++ b/CHOLMOD/Tcov/t_lpdemo.c @@ -0,0 +1,939 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_lpdemo: test program with an LP-style operations in CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// A rectangular matrix is being tested (# nrows < # cols). This is a +// linear programming problem. Process the system using the same kind of +// operations that occur in an LP solver (the LP Dual Active Set Algorithm). +// This routine does not actually solve the LP. It simply mimics the kind +// of matrix operations that occur in LPDASA. +// +// The active set f is held in fset [0..fsize-1]. It is a subset of the columns +// of A. Columns not in the fset are in the list fnot [0..ncol-fsize-1]. +// +// Rows can be added and deleted from A as well. A "dead" row is one that has +// been (temporarily) set to zero in A. If row i is dead, rflag [i] is 0, +// and 1 otherwise. +// +// The list r of "live" rows is kept in rset [0..rsize-1]. The list of "dead" +// rows is kept in rnot [0..nrow-rsize-1]. +// +// The system to solve as r and/or f change is (beta*I + A(r,f)*A(r,f)') x = b. +// If a row i is deleted from A, it is set to zero. Row i of L and D are set +// to the ith row of the identity matrix. + +#include "cm.h" +#define MAXCOLS 8 + +//------------------------------------------------------------------------------ +// Lcheck +//------------------------------------------------------------------------------ + +// Testing only: make sure there are no dead rows in L (excluding diagonal) + +static void Lcheck (cholmod_factor *L, Int *rflag) +{ + Int *Lp, *Li, *Lnz ; + Int i, n, j, p, pend ; + Real *Lx ; + + if (L == NULL) + { + return ; + } + + Lp = L->p ; + Li = L->i ; + Lx = L->x ; + Lnz = L->nz ; + n = L->n ; + + for (j = 0 ; j < n ; j++) + { + p = Lp [j] ; + pend = p + Lnz [j] ; + for (p++ ; p < pend ; p++) + { + i = Li [p] ; + OK (IMPLIES (!rflag [i], Lx [p] == 0)) ; + } + } +} + +//------------------------------------------------------------------------------ +// lp_prune +//------------------------------------------------------------------------------ + +// C = A (r,f), except that C and A have the same row dimension. Row i of C +// and A(:,f) are equal if row i is in the rset. Row i of C is zero +// otherwise. C has as many columns as the size of f. + +cholmod_sparse *lp_prune +( + cholmod_sparse *A, + Int *rflag, + Int *fset, + Int fsize +) +{ + cholmod_sparse *C ; + Real *Ax, *Cx ; + Int *Ai, *Ap, *Ci, *Cp ; + Int i, kk, j, p, nz, nf, ncol ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "nothing to prune") ; + return (NULL) ; + } + + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + ncol = A->ncol ; + nf = (fset == NULL) ? ncol : fsize ; + + OK (fsize >= 0) ; + + C = CHOLMOD(allocate_sparse) (A->nrow, nf, A->nzmax, A->sorted, + TRUE, 0, CHOLMOD_REAL + DTYPE, cm) ; + + if (C == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot create pruned C") ; + return (NULL) ; + } + + Cp = C->p ; + Ci = C->i ; + Cx = C->x ; + + nz = 0 ; + + for (kk = 0 ; kk < nf ; kk++) + { + j = (fset == NULL) ? (kk) : (fset [kk]) ; + Cp [kk] = nz ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + if (rflag [i]) + { + Ci [nz] = i ; + Cx [nz] = Ax [p] ; + nz++ ; + } + } + } + Cp [nf] = nz ; + return (C) ; +} + +//------------------------------------------------------------------------------ +// lp_resid +//------------------------------------------------------------------------------ + +// Compute the 2-norm of the residual. +// norm ((beta*I + C*C')y(r) - b(r)), where C = A (r,f). + +double lp_resid +( + cholmod_sparse *A, + Int *rflag, + Int *fset, + Int fsize, + double beta [2], + cholmod_dense *Y, + cholmod_dense *B +) +{ + cholmod_dense *R ; + Real *Rx, *Yx ; + double rnorm, bnorm, ynorm, norm ; + cholmod_sparse *C ; + cholmod_dense *W ; + Int i, nrow ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute LP resid") ; + return (1) ; + } + + nrow = A->nrow ; + R = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + + // C = A(r,f). In LPDASA, we do this in place, without making a copy. + C = lp_prune (A, rflag, fset, fsize) ; + + // W = C'*Y + OK (fsize >= 0) ; + W = CHOLMOD(zeros) (fsize, 1, CHOLMOD_REAL + DTYPE, cm) ; + CHOLMOD(sdmult) (C, TRUE, one, zero, Y, W, cm) ; + + // R = B + CHOLMOD(copy_dense2) (B, R, cm) ; + + // R = C*W - R + CHOLMOD(sdmult) (C, FALSE, one, minusone, W, R, cm) ; + + // R = R + beta*Y, (beta = 1 for dropped rows) + if (R != NULL && Y != NULL) + { + Rx = R->x ; + Yx = Y->x ; + for (i = 0 ; i < nrow ; i++) + { + if (rflag [i]) + { + Rx [i] += beta [0] * Yx [i] ; + } + else + { + Rx [i] += Yx [i] ; + } + } + } + + // rnorm = norm (R) + rnorm = CHOLMOD(norm_dense) (R, 2, cm) ; + bnorm = CHOLMOD(norm_dense) (B, 2, cm) ; + ynorm = CHOLMOD(norm_dense) (Y, 2, cm) ; + norm = MAX (bnorm, ynorm) ; + if (norm > 0) + { + rnorm /= norm ; + } + + CHOLMOD(print_dense) (R, "R, resid", cm) ; + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_dense) (&W, cm) ; + CHOLMOD(free_dense) (&R, cm) ; + + return (rnorm) ; +} + +//------------------------------------------------------------------------------ +// get_row +//------------------------------------------------------------------------------ + +// S = column i of beta*I + A(r,f)*A(r,f)' + +cholmod_sparse *get_row +( + cholmod_sparse *A, + Int i, + Int *rflag, + Int *fset, + Int fsize, + double beta [2] +) +{ + cholmod_sparse *Ri, *R, *C, *S ; + Real *Sx ; + Int *Sp, *Si ; + Int p, ii, found ; + + if (rflag [i] == 0) + { + S = CHOLMOD(speye) (A->nrow, A->nrow, CHOLMOD_REAL + DTYPE, cm) ; + CHOLMOD(print_sparse) (S, "S identity", cm) ; + return (S) ; + } + OK (fsize >= 0) ; + + // Getting row i of A is expensive. In LPDASA, we maintain + // a copy of A(r,f)', and extact row i as column i of that + // matrix. We compute S = A(r,f)*A(i,f)' and S(i) += beta + // in a single pass. This is a simpler but slower method. + + // R = A (i,f)' + Ri = CHOLMOD(submatrix) (A, &i, 1, fset, fsize, TRUE, FALSE, cm) ; + R = CHOLMOD(transpose) (Ri, 1, cm) ; + CHOLMOD(free_sparse) (&Ri, cm) ; + + // C = A (r,f) + C = lp_prune (A, rflag, fset, fsize) ; + + // S = C*R + S = CHOLMOD(ssmult) (C, R, 0, TRUE, TRUE, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&R, cm) ; + + if (S == NULL) + { + return (NULL) ; + } + + // S (i) += beta + found = FALSE ; + Sp = S->p ; + Si = S->i ; + Sx = S->x ; + for (p = Sp [0] ; p < Sp [1] ; p++) + { + ii = Si [p] ; + if (ii == i) + { + found = TRUE ; + Sx [p] += beta [0] ; + break ; + } + } + if (!found) + { + // oops, row index i is not present in S. Add it. + CHOLMOD(reallocate_sparse) (S->nzmax+1, S, cm) ; + OK (Sp [1] < (Int) (S->nzmax)) ; + Si = S->i ; + Sx = S->x ; + Si [Sp [1]] = i ; + Sx [Sp [1]] = beta [0] ; + Sp [1]++ ; + S->sorted = FALSE ; + } + + CHOLMOD(print_sparse) (S, "S", cm) ; + + return (S) ; +} + +//------------------------------------------------------------------------------ +// lpdemo +//------------------------------------------------------------------------------ + +double lpdemo (cholmod_triplet *T) +{ + double r, maxerr = 0, anorm, bnorm, norm, xnorm, ynorm ; + Real *b = NULL, *Yx = NULL, *Xx = NULL, *Sx ; + cholmod_sparse *A, *AT, *Apermuted, *C, *S, *Row ; + cholmod_dense *X, *B, *Y, *DeltaB, *R ; + cholmod_factor *L ; + Int *init, *rset, *rnot, *fset, *fnot, *rflag, *P, *Pinv, *Lperm, *fflag, + *Sp, *Si, *StaticParent ; + Int i, j, k, nrow, ncol, fsize, cols [MAXCOLS+1], trial, rank, kk, rsize, + p, op, ok ; + double beta [2], bk [2], yk [2] ; + + //-------------------------------------------------------------------------- + // convert T into a sparse matrix A + //-------------------------------------------------------------------------- + + if (T == NULL || T->ncol == 0) + { + // nothing to do + return (0) ; + } + + if (T->xtype != CHOLMOD_REAL) + { + return (0) ; + } + + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot continue LP demo") ; + return (1) ; + } + + nrow = A->nrow ; + ncol = A->ncol ; + + anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; + + // switch for afiro, but not galenet + cm->supernodal_switch = 5 ; + + //-------------------------------------------------------------------------- + // select a random initial row and column basis + //-------------------------------------------------------------------------- + + // select an initial fset of size nrow + init = prand (ncol) ; // RAND + CHOLMOD(print_perm) (init, ncol, ncol, "init", cm) ; + fset = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + fnot = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + fflag = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + fsize = MIN (nrow, ncol) ; + + if (init != NULL && fset != NULL && fflag != NULL) + { + for (k = 0 ; k < fsize ; k++) + { + j = init [k] ; + fset [k] = j ; + fflag [j] = 1 ; + } + for ( ; k < ncol ; k++) + { + j = init [k] ; + fnot [k-fsize] = j ; + fflag [j] = 0 ; + } + } + + CHOLMOD(free) (ncol, sizeof (Int), init, cm) ; + + // all rows are live + rsize = nrow ; + rflag = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + rset = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + rnot = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + + if (rset != NULL && rflag != NULL) + { + for (i = 0 ; i < nrow ; i++) + { + rflag [i] = 1 ; + rset [i] = i ; + } + } + + //-------------------------------------------------------------------------- + // factorize the first matrix, beta*I + A(p,f)*A(p,f)' + //-------------------------------------------------------------------------- + + #ifdef DOUBLE + beta [0] = 1e-6 ; + #else + beta [0] = 0.1 ; + #endif + beta [1] = 0 ; + + // Need to prune entries due to relaxed amalgamation, or else + // cholmod_row_subtree will not be able to find all the entries in row + // k of L. + cm->final_resymbol = TRUE ; + + cm->final_asis = FALSE ; + cm->final_super = FALSE ; + cm->final_ll = FALSE ; + cm->final_pack = FALSE ; + cm->final_monotonic = FALSE ; + + L = CHOLMOD(analyze_p) (A, NULL, fset, fsize, cm) ; + CHOLMOD(factorize_p) (A, beta, fset, fsize, L, cm) ; + + // get a copy of the fill-reducing permutation P and compute its inverse + Lperm = (L != NULL) ? (L->Perm) : NULL ; + P = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + + if (P != NULL && Pinv != NULL && Lperm != NULL) + { + for (k = 0 ; k < nrow ; k++) + { + P [k] = Lperm [k] ; + Pinv [P [k]] = k ; + } + } + else + { + P = CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; + Pinv = CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; + } + + if (cm->print > 1) + { + k = cm->print ; + cm->print = 5 ; + CHOLMOD(print_common) ("5:cm for lpdemo", cm) ; + cm->print = k ; + } + + //-------------------------------------------------------------------------- + // A=P*A: permute the rows of A according to P + //-------------------------------------------------------------------------- + + // This is done just once, since the system will be solved and modified + // many times. It's faster, and easier, to work in the permuted ordering + // rather than the original ordering. + + // A will become unsorted later on; don't bother to sort it here + Apermuted = CHOLMOD(submatrix) (A, P, nrow, NULL, -1, TRUE, TRUE, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + A = Apermuted ; + + //-------------------------------------------------------------------------- + // find the etree of A*A' + //-------------------------------------------------------------------------- + + // Since the fset is a subset of 0:ncol-1, and rset is a subset of 0:nrow-1, + // the nonzero pattern of the Cholesky factorization of A(r,f)*A(r,f)' is a + // subset of the Cholesky factorization of A*A'. After many updates/ + // downdates/rowadds/rowdels, any given row i of L may have entries that + // are not in the factorization of A (r,f)*A(r,f)'. To drop a row using + // cholmod_rowdel, we either need to know the pattern of the ith row of L, + // we can pass NULL and have cholmod_rowdel look at each column 0 to i-1. + // The StaticParent array is the etree of A*A', and it suffices to compute + // the pattern of the ith row of L based on that etree, and A and A' + // (ignoring the fset and rset). This gives us an upper bound on the + // nonzero pattern of the ith row of the current L (the factorization + // of A(r,f)*A(r,f)'. + + // AT = nonzero pattern of A', used for row-subtree computations + AT = CHOLMOD(transpose) (A, 0, cm) ; + + // Row = cholmod_row_subtree workspace (unsorted, packed, unsym, pattern) + Row = CHOLMOD(allocate_sparse) (nrow, 1, nrow, FALSE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + + // Compute the "static" etree; the etree of A*A' + StaticParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + CHOLMOD(etree) (AT, StaticParent, cm) ; + + //-------------------------------------------------------------------------- + // compute initial right-hand-side + //-------------------------------------------------------------------------- + + // If row i of the original A and B is row k of the permuted P*A and P*B, + // then P [k] = i and Pinv [i] = k. Row indices of A now refer to the + // permuted form of A, not the original A. Likewise, row k of B will + // refer to the permuted row k = Pinv [i], not the original row i. In a + // real program, this would affect how B is computed. This program just + // creates a random B anyway, so the order of B does not matter. It does + // use Pinv [i], just to show you how you would do it. + + B = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + + if (B != NULL && Pinv != NULL) + { + b = B->x ; + for (i = 0 ; i < nrow ; i++) + { + // row i of the original B is row k of the permuted B + k = Pinv [i] ; + b [k] = xrand (1.) ; // RAND + } + } + + //-------------------------------------------------------------------------- + // solve the system + //-------------------------------------------------------------------------- + + // Solve the system (beta*I + A(:,f)*A(:,f)')y=b without using L->Perm, + // since A and B have already been permuted according to L->Perm. + + DeltaB = CHOLMOD(zeros) (nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + + // solve Lx=b + X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; + + // solve DL'y=x + Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; + + r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; + MAXERR (maxerr, r, 1) ; + + bk [0] = 0 ; + bk [1] = 0 ; + + yk [0] = 0 ; + yk [1] = 0 ; + + bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; + + //-------------------------------------------------------------------------- + // modify the system + //-------------------------------------------------------------------------- + + ok = (fset != NULL && fnot != NULL && fflag != NULL && + rset != NULL && rnot != NULL && rflag != NULL && + B != NULL && Y != NULL && X != NULL && Row != NULL && A != NULL && + AT != NULL && StaticParent != NULL && DeltaB != NULL && L != NULL && + L->xtype != CHOLMOD_PATTERN && !(L->is_ll) && !(L->is_super)) ; + + for (trial = 1 ; ok && trial < MAX (64, 2*ncol) ; trial++) + { + // select an operation at random + op = nrand (6) ; // RAND + + Xx = X->x ; + Yx = Y->x ; + + switch (op) + { + + //------------------------------------------------------------------ + case 0: // update + //------------------------------------------------------------------ + + // pick some columns at random, but not all columns + rank = 1 + nrand (MAXCOLS+4) ; // RAND + rank = MIN (rank, MAXCOLS) ; + + rank = MIN (rank, ncol-fsize-1) ; + if (rank <= 0) + { + continue ; + } + + // remove the columns from fnot and add them to fset + for (k = 0 ; k < rank ; k++) + { + kk = nrand (ncol-fsize) ; // RAND + j = fnot [kk] ; + fnot [kk] = fnot [ncol-fsize-1] ; + fset [fsize++] = j ; + OK (fsize < ncol) ; + cols [k] = j ; + fflag [j] = 1 ; + } + + // update L, and the solution to Lx=b+deltaB + C = lp_prune (A, rflag, cols, rank) ; + ok = CHOLMOD(updown_solve) (TRUE, C, L, X, DeltaB, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + break ; + + //------------------------------------------------------------------ + case 1: // downdate + //------------------------------------------------------------------ + + // pick some columns at random, but not all columns + rank = 1 + nrand (MAXCOLS+4) ; // RAND + rank = MIN (rank, MAXCOLS) ; + + rank = MIN (rank, fsize-1) ; + if (rank <= 0) + { + continue ; + } + + // remove the columns from fset and add them to fnot + for (k = 0 ; k < rank ; k++) + { + kk = nrand (fsize) ; // RAND + j = fset [kk] ; + fset [kk] = fset [fsize-1] ; + fnot [ncol-fsize] = j ; + fsize-- ; + OK (fsize > 0) ; + cols [k] = j ; + fflag [j] = 0 ; + } + + // downdate L, and the solution to Lx=b+deltaB + C = lp_prune (A, rflag, cols, rank) ; + ok = CHOLMOD(updown_solve) (FALSE, C, L, X, DeltaB, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + break ; + + //------------------------------------------------------------------ + case 2: // resymbol (no change to numerical values) + //------------------------------------------------------------------ + + // let resymbol handle the fset + C = lp_prune (A, rflag, NULL, 0) ; + ok = CHOLMOD(resymbol_noperm) (C, fset, fsize, TRUE, L, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + break; + + //------------------------------------------------------------------ + case 3: // add row + //------------------------------------------------------------------ + + // remove a row from rnot and add to rset + if (nrow == rsize) + { + continue ; + } + kk = nrand (nrow-rsize) ; // RAND + i = rnot [kk] ; + + OK (rflag [i] == 0) ; + + rnot [kk] = rnot [nrow-rsize-1] ; + rset [rsize++] = i ; + rflag [i] = 1 ; + + // S = column i of beta*I + A(r,f)*A(r,f)' + S = get_row (A, i, rflag, fset, fsize, beta) ; + ok = (S != NULL) ; + + if (ok) + { + // pick a random right-hand-side for this new row + b [i] = 1 ; // xrand (1) + bk [0] = b [i] ; + bk [1] = 0 ; + ok = CHOLMOD(rowadd_solve) (i, S, bk, L, X, DeltaB, cm) ; + } + + CHOLMOD(free_sparse) (&S, cm) ; + break ; + + //------------------------------------------------------------------ + case 4: // delete row + //------------------------------------------------------------------ + + // remove a row from rset and add to rnot + if (rsize == 0) + { + continue ; + } + kk = nrand (rsize) ; // RAND + i = rset [kk] ; + + OK (rflag [i] == 1) ; + rset [kk] = rset [rsize-1] ; + rnot [nrow-rsize] = i ; + rsize-- ; + + // S = column i of beta*I + A(r,f)*A(r,f)' + S = get_row (A, i, rflag, fset, fsize, beta) ; + ok = (S != NULL) ; + + if (ok) + { + // B = B - S * y(i) + Sp = S->p ; + Si = S->i ; + Sx = S->x ; + for (p = 0 ; p < Sp [1] ; p++) + { + b [Si [p]] -= Sx [p] * Yx [i] ; + } + // B(i) = y(i) + b [i] = Yx [i] ; + + yk [0] = Yx [i] ; + yk [1] = 0 ; + + // pick a method arbitrarily + if (trial % 2) + { + // get upper bound nonzero pattern of L(i,0:i-1) + CHOLMOD(row_subtree) (A, AT, i, StaticParent, Row, cm) ; + ok = CHOLMOD(rowdel_solve) (i, Row, yk, L, X, DeltaB, + cm) ; + } + else + { + // Look in all cols 0 to i-1 for entries in L(i,0:i-1). + // This is more costly, but requires no knowledge of + // an upper bound on the pattern of L. + ok = CHOLMOD(rowdel_solve) (i, NULL, yk, L, X, DeltaB, + cm) ; + } + + // for testing only, to ensure cholmod_row_subtree worked + if (ok) + { + rflag [i] = 0 ; + Lcheck (L, rflag) ; + } + } + + if (ok) + { + // let resymbol handle the fset + C = lp_prune (A, rflag, NULL, 0) ; + ok = CHOLMOD(resymbol_noperm) (C, fset, fsize, TRUE, L, cm); + CHOLMOD(free_sparse) (&C, cm) ; + } + + CHOLMOD(free_sparse) (&S, cm) ; + break ; + + //------------------------------------------------------------------ + case 5: // convert, just for testing + //------------------------------------------------------------------ + + // convert to LDL', optionally packed + if (trial % 2) + { + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, + TRUE, TRUE, L, cm) ; + } + else + { + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, + FALSE, TRUE, L, cm) ; + } + break ; + + } + + if (ok) + { + + // scale B and X if their norm is getting large + ynorm = CHOLMOD(norm_dense) (Y, 1, cm) ; + bnorm = CHOLMOD(norm_dense) (B, 1, cm) ; + xnorm = CHOLMOD(norm_dense) (X, 1, cm) ; + norm = MAX (bnorm, xnorm) ; + norm = MAX (norm, ynorm) ; + if (norm > 1e10) + { + for (i = 0 ; i < nrow ; i++) + { + Xx [i] /= norm ; + b [i] /= norm ; + } + } + + CHOLMOD(free_dense) (&Y, cm) ; + Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; + + r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; + OK (!ISNAN (r)) ; + MAXERR (maxerr, r, 1) ; + if (r > 1e-6 && cm->print > 1) + { + printf ("lp err %.1g operation: "ID" ok "ID"\n", r, op, ok) ; + } + ok = (Y != NULL) ; + } + } + + CHOLMOD(free_dense) (&Y, cm) ; + OK (CHOLMOD(print_common) ("6:cm in lpdemo", cm)) ; + + //-------------------------------------------------------------------------- + // convert to LDL packed, LDL unpacked or LL packed and solve again + //-------------------------------------------------------------------------- + + // solve the new system and check the residual + + CHOLMOD(print_factor) (L, "L final, for convert", cm) ; + if (ok) + { + switch (nrand (3)) // RAND + { + // pick one at random + case 0: + { + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, + TRUE, L, cm) ; + Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; + break ; + } + case 1: + { + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, + TRUE, L, cm) ; + Y = CHOLMOD(solve) (CHOLMOD_DLt, L, X, cm) ; + break ; + } + case 2: + { + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, TRUE, FALSE, TRUE, + TRUE, L, cm) ; + Y = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; + break ; + } + } + r = lp_resid (A, rflag, fset, fsize, beta, Y, B) ; + OK (!ISNAN (r)) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(print_factor) (L, "L after convert", cm) ; + } + + //-------------------------------------------------------------------------- + // rank-1 update, but only partial Lx=b update + //-------------------------------------------------------------------------- + + int whatever = 0 ; + + if (ok && fsize < ncol && nrow > 3) + { + Int colmark [1] ; + + j = fnot [0] ; + fnot [0] = fnot [ncol-fsize-1] ; + fset [fsize++] = j ; + OK (fsize <= ncol) ; + cols [0] = j ; + fflag [j] = 1 ; + + for (colmark [0] = 0 ; ok && colmark [0] <= nrow ; colmark [0]++) + { + cholmod_factor *L2 ; + cholmod_dense *X2 ; + Real *X2x ; + L2 = CHOLMOD(copy_factor) (L, cm) ; + X2 = CHOLMOD(copy_dense) (X, cm) ; + if (X2 != NULL) { OK (X2->dtype == DTYPE) ; } + X2x = (X2 == NULL) ? NULL : X2->x ; + + // update L, and the solution to Lx=b+deltaB, + // but only update solution in rows 0 to colmark[0] + C = lp_prune (A, rflag, cols, 1) ; + if ((whatever++) % 2 == 0) + { + ok = CHOLMOD(updown_mark) (TRUE, C, colmark, + L2, X2, DeltaB, cm) ; + } + else + { + // does the same thing as updown_mark, with different API + ok = CHOLMOD(updown_mask) (TRUE, C, colmark, NULL, + L2, X2, DeltaB, cm) ; + } + CHOLMOD(free_sparse) (&C, cm) ; + + // compare with Lr=b+deltaB + R = CHOLMOD(solve) (CHOLMOD_L, L2, B, cm) ; + ok = ok && (R != NULL) ; + r = -1 ; + if (ok) + { + Real *Rx ; + OK (R->dtype == DTYPE) ; + Rx = R->x ; + OK (X2x != NULL) ; + r = 0 ; + for (i = 0 ; i < colmark [0] ; i++) + { + r = MAX (r, fabs (X2x [i] - Rx [i])) ; + } + MAXERR (maxerr, r, 1) ; + } + CHOLMOD(free_dense) (&R, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + CHOLMOD(free_factor) (&L2, cm) ; + } + } + + //-------------------------------------------------------------------------- + // free everything + //-------------------------------------------------------------------------- + + // restore defaults + cm->final_resymbol = FALSE ; + cm->final_asis = TRUE ; + cm->supernodal_switch = 40 ; + + CHOLMOD(free) (nrow, sizeof (Int), StaticParent, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), rflag, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), rset, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), rnot, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), fnot, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), fflag, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_sparse) (&Row, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + CHOLMOD(free_dense) (&DeltaB, cm) ; + + progress (0, '.') ; + printf ("maxerr %g at %d: %s\n", maxerr, __LINE__, __FILE__) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_memory.c b/CHOLMOD/Tcov/t_memory.c new file mode 100644 index 0000000000..6d4f178ef8 --- /dev/null +++ b/CHOLMOD/Tcov/t_memory.c @@ -0,0 +1,376 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_memory: memory-failure testing in CHOLMOD +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Extensive memory-failure testing for CHOLMOD. +// +// my_malloc2, my_calloc2, and my_realloc2 pretend to fail if my_tries goes to +// zero, to test CHOLMOD's memory error handling. No failure occurs if +// my_tries is negative. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// my_tries +//------------------------------------------------------------------------------ + +int64_t my_tries = -1 ; // a global variable + +//------------------------------------------------------------------------------ +// my_malloc2 +//------------------------------------------------------------------------------ + +void *my_malloc2 (size_t size) +{ + void *p ; + if (my_tries == 0) + { + // pretend to fail + return (NULL) ; + } + if (my_tries > 0) + { + my_tries-- ; + } + p = malloc (size) ; + return (p) ; +} + +//------------------------------------------------------------------------------ +// my_calloc2 +//------------------------------------------------------------------------------ + +void *my_calloc2 (size_t n, size_t size) +{ + void *p ; + if (my_tries == 0) + { + // pretend to fail + return (NULL) ; + } + if (my_tries > 0) + { + my_tries-- ; + } + p = calloc (n, size) ; + return (p) ; +} + +//------------------------------------------------------------------------------ +// my_realloc2 +//------------------------------------------------------------------------------ + +void *my_realloc2 (void *p, size_t size) +{ + void *p2 ; + if (my_tries == 0) + { + // pretend to fail + return (NULL) ; + } + if (my_tries > 0) + { + my_tries-- ; + } + p2 = realloc (p, size) ; + return (p2) ; +} + +//------------------------------------------------------------------------------ +// my_free2 +//------------------------------------------------------------------------------ + +void my_free2 (void *p) +{ + free (p) ; +} + +//------------------------------------------------------------------------------ +// normal_memory_handler +//------------------------------------------------------------------------------ + +void normal_memory_handler ( void ) +{ + SuiteSparse_config_malloc_func_set (malloc) ; + SuiteSparse_config_calloc_func_set (calloc) ; + SuiteSparse_config_realloc_func_set (realloc) ; + SuiteSparse_config_free_func_set (free) ; + + cm->error_handler = my_handler ; + CHOLMOD(free_work) (cm) ; +} + +//------------------------------------------------------------------------------ +// test_memory_handler +//------------------------------------------------------------------------------ + +void test_memory_handler ( void ) +{ + SuiteSparse_config_malloc_func_set (my_malloc2) ; + SuiteSparse_config_calloc_func_set (my_calloc2) ; + SuiteSparse_config_realloc_func_set (my_realloc2) ; + SuiteSparse_config_free_func_set (my_free2) ; + + cm->error_handler = NULL ; + CHOLMOD(free_work) (cm) ; + my_tries = 0 ; +} + +//------------------------------------------------------------------------------ +// memory tests +//------------------------------------------------------------------------------ + +void memory_tests (cholmod_triplet *T) +{ + double err ; + cholmod_sparse *A ; + Int trial ; + size_t count, inuse ; + const int psave = cm->print ; + + test_memory_handler ( ) ; + inuse = cm->memory_inuse ; + + cm->nmethods = 8 ; + cm->print = 0 ; + cm->final_resymbol = TRUE ; + + cm->final_asis = FALSE ; + cm->final_super = FALSE ; + cm->final_ll = FALSE ; + cm->final_pack = FALSE ; + cm->final_monotonic = FALSE ; + + //-------------------------------------------------------------------------- + // test raw factorizations + //-------------------------------------------------------------------------- + + printf ("==================================== fac memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + my_srand (trial+1) ; // RAND reset + err = raw_factor (A, FALSE) ; // RAND + CHOLMOD(free_sparse) (&A, cm) ; + OK (CHOLMOD(print_common) ("7:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + CHOLMOD(free_work) (cm) ; + printf ("memory test: fac error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + + //-------------------------------------------------------------------------- + // test raw factorizations (rowfac_mask) + //-------------------------------------------------------------------------- + + printf ("==================================== fac memory test2\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + my_srand (trial+1) ; // RAND reset + err = raw_factor2 (A, 0., 0) ; // RAND + CHOLMOD(free_sparse) (&A, cm) ; + OK (CHOLMOD(print_common) ("8:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + CHOLMOD(free_work) (cm) ; + printf ("memory test: fac error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + + //-------------------------------------------------------------------------- + // test augmented system solver + //-------------------------------------------------------------------------- + + printf ("==================================== aug memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + err = aug (A) ; // no random number use + CHOLMOD(free_sparse) (&A, cm) ; + OK (CHOLMOD(print_common) ("9:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + CHOLMOD(free_work) (cm) ; + printf ("memory test: aug error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + + //-------------------------------------------------------------------------- + // test ops + //-------------------------------------------------------------------------- + + printf ("==================================== test_ops memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + my_srand (trial+1) ; // RAND reset + err = test_ops (A) ; // RAND + CHOLMOD(free_sparse) (&A, cm) ; + OK (CHOLMOD(print_common) ("10:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + printf ("inuse "ID" "ID"\n", (Int) inuse, (Int) (cm->memory_inuse)) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + printf ("memory test: testops error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + + //-------------------------------------------------------------------------- + // test lpdemo + //-------------------------------------------------------------------------- + + if (T == NULL || T->nrow != T->ncol) + { + printf ("==================================== lpdemo memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + my_srand (trial+1) ; // RAND reset + err = lpdemo (T) ; // RAND + OK (CHOLMOD(print_common) ("11:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + CHOLMOD(free_work) (cm) ; + printf ("memory test: lpdemo error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + + //-------------------------------------------------------------------------- + // test solver + //-------------------------------------------------------------------------- + + printf ("==================================== solve memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->metis_memory = 2.0 ; + cm->nmethods = 4 ; + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + my_srand (trial+1) ; // RAND reset + err = solve (A) ; // RAND + CHOLMOD(free_sparse) (&A, cm) ; + OK (CHOLMOD(print_common) ("12:cm", cm)) ; + CHOLMOD(free_work) (cm) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + CHOLMOD(free_work) (cm) ; + printf ("memory test: solve error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + cm->supernodal = CHOLMOD_AUTO ; + + //-------------------------------------------------------------------------- + // cat tests + //-------------------------------------------------------------------------- + + CHOLMOD(defaults) (cm) ; cm->useGPU = 0 ; + test_memory_handler ( ) ; + + printf ("==================================== cat_tests memory test\n") ; + count = cm->malloc_count ; + my_tries = -1 ; + for (trial = 0 ; my_tries <= 0 ; trial++) + { + cm->print = 0 ; + fflush (stdout) ; + my_tries = trial ; + A = CHOLMOD(triplet_to_sparse) (T, 0, cm) ; + err = cat_tests (A, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_work) (cm) ; + printf ("inuse "ID" "ID"\n", (Int) inuse, (Int) (cm->memory_inuse)) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + } + printf ("memory test: cat_test error %.1g trials "ID"\n", err, trial) ; + printf ("initial count: "ID" final count "ID"\n", + (Int) count, (Int) cm->malloc_count) ; + printf ("initial inuse: "ID" final inuse "ID"\n", + (Int) inuse, (Int) cm->memory_inuse) ; + OK (count == cm->malloc_count) ; + OK (inuse == cm->memory_inuse) ; + + //-------------------------------------------------------------------------- + // restore original memory handler + //-------------------------------------------------------------------------- + + progress (1, '|') ; + normal_memory_handler ( ) ; + cm->print = psave ; + + printf ("All memory tests OK, no error\n") ; +} + diff --git a/CHOLMOD/Tcov/t_null.c b/CHOLMOD/Tcov/t_null.c new file mode 100644 index 0000000000..5ffb19e80d --- /dev/null +++ b/CHOLMOD/Tcov/t_null.c @@ -0,0 +1,391 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_null: test CHOLMOD with NULL and erroneous inputs +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Test CHOLMOD with NULL pointers, and other error cases. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// my_hander2 +//------------------------------------------------------------------------------ + +void my_handler2 (int status, const char *file, int line, const char *msg) +{ + printf ("This ERROR is expected: file %s line %d\n%d: %s\n", + file, line, status, msg) ; +} + +//------------------------------------------------------------------------------ +// null_test +//------------------------------------------------------------------------------ + +// This routine is not called during memory testing + +void null_test (cholmod_common *cn) +{ + cholmod_sparse *A = NULL, *F = NULL, *C = NULL, *R = NULL, *B = NULL ; + cholmod_factor *L = NULL ; + cholmod_triplet *T = NULL ; + cholmod_dense *X = NULL, *DeltaB = NULL, *S = NULL, *Y = NULL, *E = NULL ; + void *p = NULL, *ii = NULL, *jj = NULL, *xx = NULL, *zz = NULL ; + Int *Perm = NULL, *fset = NULL, *Parent = NULL, *Post = NULL, + *RowCount = NULL, *ColCount = NULL, *First = NULL, *Level = NULL, + *UserPerm = NULL, *colmark = NULL, *Constraints = NULL, + *r = NULL, *c = NULL, *Set = NULL ; + char *name = NULL ; + double alpha [2], beta [2], bk [2], yk [2], rcond ; + double dj = 1, nm = 0, tol = 0 ; + int ok, stype = 0, xtype = 0, sorted = 0, packed = 0, nint = 0, update = 0, + postorder = 0, pack = 0, values = 0, mode = 0, sys = 0, norm = 0, + to_xtype = 0, to_ll = 0, to_super = 0, to_packed = 0, to_monotonic = 0, + scale = 0, transpose = 0, option = 0, ordering = 0, prefer = 0, + mtype = 0, asym = 0 ; + int64_t lr = 0, k1 = 0, k2 = 0 ; + size_t j = 0, need = 0, n = 0, mr = 0, nrow = 0, ncol = 0, iworksize = 0, + newsize = 0, fsize = 0, d = 0, nzmax = 0, nnew = 0, size = 0, + nold = 0, xwork = 0, kstart = 0, kend = 0, nr = 0, nc = 0, len = 0, + krow = 0, k = 0 ; + + #ifndef NPARTITION + Int *Anw = NULL, *Aew = NULL, *Partition = NULL, *CParent = NULL, + *Cmember = NULL ; + Int compress = 0 ; + #endif + + #ifndef NCAMD + Int *Cmem2 = NULL ; + #endif + + //-------------------------------------------------------------------------- + // Utility + //-------------------------------------------------------------------------- + + if (cn == NULL) + { + ok = CHOLMOD(start)(cn) ; NOT (ok) ; + } + ok = CHOLMOD(finish)(cn) ; NOT (ok) ; + ok = CHOLMOD(defaults)(cn) ; NOT (ok) ; + mr = CHOLMOD(maxrank)(n, cn) ; NOT (mr>0) ; + ok = CHOLMOD(allocate_work)(nrow, iworksize, xwork, cn) ; + NOT (ok) ; + ok = CHOLMOD(alloc_work)(nrow, iworksize, xwork, DTYPE, cn) ; + NOT (ok) ; + ok = CHOLMOD(free_work)(cn) ; NOT (ok) ; + lr = CHOLMOD(clear_flag)(cn) ; NOT (lr>=0) ; + + dj = CHOLMOD(dbound)(dj, cn) ; OK (dj==0) ; + ok = CHOLMOD(error)(CHOLMOD_INVALID, __FILE__, __LINE__, "oops", cn) ; + NOT (ok) ; + A = CHOLMOD(allocate_sparse)(nrow, ncol, nzmax, sorted, + packed, stype, xtype + DTYPE, cn) ; + NOP (A) ; + ok = CHOLMOD(free_sparse)(&A, cn) ; NOT (ok) ; + ok = CHOLMOD(reallocate_sparse)(newsize, A, cn) ; NOT (ok) ; + lr = CHOLMOD(nnz)(A, cn) ; NOT (lr>=0) ; + A = CHOLMOD(speye)(nrow, ncol, xtype + DTYPE, cn) ; + NOP (A) ; + A = CHOLMOD(spzeros)(nrow, ncol, 0, xtype + DTYPE, cn) ; + NOP (A) ; + A = CHOLMOD(ptranspose)(A, values, Perm, fset, fsize, cn); NOP (A) ; + A = CHOLMOD(transpose)(A, values, cn) ; NOP (A) ; + ok = CHOLMOD(transpose_unsym)(A, values, Perm, fset, fsize, F, cn) ; + NOT (ok) ; + ok = CHOLMOD(transpose_sym)(A, values, Perm, F, cn) ; NOT (ok) ; + ok = CHOLMOD(sort)(A, cn) ; NOT (ok) ; + A = CHOLMOD(copy_sparse)(A, cn) ; NOP (A) ; + C = CHOLMOD(aat)(A, fset, fsize, mode, cn) ; NOP (C) ; + + L = CHOLMOD(allocate_factor)(n, cn) ; + NOP (L) ; + L = CHOLMOD(alloc_factor)(n, DTYPE, cn) ; + NOP (L) ; + ok = CHOLMOD(free_factor)(&L, cn) ; NOT (ok) ; + ok = CHOLMOD(reallocate_factor)(newsize, L, cn) ; NOT (ok) ; + ok = CHOLMOD(change_factor)(0, 0, 0, 0, 0, L, cn) ; NOT (ok) ; + ok = CHOLMOD(pack_factor)(L, cn) ; NOT (ok) ; + ok = CHOLMOD(change_factor)(to_xtype, to_ll, to_super, + to_packed, to_monotonic, L, cn) ; NOT (ok) ; + ok = CHOLMOD(reallocate_column)(j, need, L, cn) ; NOT (ok) ; + A = CHOLMOD(factor_to_sparse)(L, cn) ; NOP (A) ; + L = CHOLMOD(copy_factor)(L, cn) ; NOP (L) ; + + X = CHOLMOD(allocate_dense)(nrow, ncol, d, xtype + DTYPE, cn) ; + NOP (X) ; + X = CHOLMOD(zeros)(nrow, ncol, xtype + DTYPE, cn) ; + NOP (X) ; + X = CHOLMOD(ones)(nrow, ncol, xtype + DTYPE, cn) ; + NOP (X) ; + X = CHOLMOD(eye)(nrow, ncol, xtype, cn) ; NOP (X) ; + ok = CHOLMOD(free_dense)(&X, cn) ; NOT (ok) ; + X = CHOLMOD(sparse_to_dense)(A, cn) ; NOP (X) ; + A = CHOLMOD(dense_to_sparse)(X, values, cn) ; NOP (A) ; + Y = CHOLMOD(copy_dense)(X, cn) ; NOP (X) ; + ok = CHOLMOD(copy_dense2)(X, Y, cn) ; NOT (ok) ; + + T = CHOLMOD(allocate_triplet)(nrow, ncol, nzmax, + stype, xtype + DTYPE, cn) ; + NOP (T) ; + ok = CHOLMOD(free_triplet)(&T, cn) ; NOT (ok) ; + T = CHOLMOD(sparse_to_triplet)(A, cn) ; NOP (T) ; + A = CHOLMOD(triplet_to_sparse)(T, 0, cn) ; NOP (A) ; + T = CHOLMOD(copy_triplet)(T, cn) ; NOP (T) ; + ok = CHOLMOD(reallocate_triplet)(nzmax, T, cn) ; NOT (ok) ; + + lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cn) ; NOT (lr>=0) ; + p = CHOLMOD(malloc)(n, size, cn) ; NOP (p) ; + p = CHOLMOD(calloc)(n, size, cn) ; NOP (p) ; + p = CHOLMOD(free)(n, size, p, cn) ; NOP (p) ; + p = CHOLMOD(realloc)(nnew, size, p, &n, cn) ; NOP (p) ; + ok = CHOLMOD(realloc_multiple)(nnew, nint, xtype, + &ii, &jj, &xx, &zz, &nold, cn) ; NOT (ok) ; + + C = CHOLMOD(band)(A, k1, k2, mode, cn) ; NOP (C) ; + ok = CHOLMOD(band_inplace)(k1, k2, mode, A, cn) ; NOT (ok) ; + + ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL + DTYPE, L, cn) ; + NOT (ok) ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL + DTYPE, A, cn) ; + NOT (ok) ; + ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL + DTYPE, X, cn) ; + NOT (ok) ; + ok = CHOLMOD(triplet_xtype)(CHOLMOD_REAL + DTYPE, T, cn) ; + NOT (ok) ; + + //-------------------------------------------------------------------------- + // Cholesky + //-------------------------------------------------------------------------- + + L = CHOLMOD(analyze)(A, cn) ; NOP (L) ; + L = CHOLMOD(analyze_p)(A, UserPerm, fset, fsize, cn) ; NOP (L) ; + ok = CHOLMOD(factorize)(A, L, cn) ; NOT (ok) ; + ok = CHOLMOD(factorize_p)(A, beta, fset, fsize, L, cn) ; NOT (ok) ; + rcond = CHOLMOD(rcond)(L, cn) ; NOT (rcond>=0) ; + X = CHOLMOD(solve)(sys, L, Y, cn) ; NOP (X) ; + C = CHOLMOD(spsolve)(sys, L, B, cn) ; NOP (C) ; + ok = CHOLMOD(etree)(A, Parent, cn) ; NOT (ok) ; + ok = CHOLMOD(rowcolcounts)(A, fset, fsize, Parent, Post, + RowCount, ColCount, First, Level, cn) ; NOT (ok) ; + ok = CHOLMOD(amd)(A, fset, fsize, Perm, cn) ; NOT (ok) ; + ok = CHOLMOD(camd)(A, fset, fsize, Constraints, Perm, cn) ; NOT (ok) ; + ok = CHOLMOD(colamd)(A, fset, fsize, postorder, Perm, cn) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(A, F, beta, kstart, kend, L, cn) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, F, krow, Parent, R, cn) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, c, 0, krow, L, R, cn) ; NOT (ok) ; + ok = CHOLMOD(resymbol)(A, fset, fsize, pack, L, cn) ; NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(A, fset, fsize, pack, L, cn) ;NOT (ok) ; + ok = CHOLMOD(analyze_ordering)(A, ordering, Perm, fset, + fsize, Parent, Post, ColCount, First, Level, cn) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // Modify + //-------------------------------------------------------------------------- + + ok = CHOLMOD(updown)(update, C, L, cn) ; NOT (ok) ; + ok = CHOLMOD(updown_solve)(update, C, L, X, DeltaB, cn) ; NOT (ok) ; + ok = CHOLMOD(updown_mark)(update, C, colmark, L, X, DeltaB, + cn) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(k, R, L, cn) ; NOT (ok) ; + ok = CHOLMOD(rowadd_solve)(k, R, bk, L, X, DeltaB, cn) ; NOT (ok) ; + ok = CHOLMOD(rowadd_mark)(k, R, bk, colmark, L, X, DeltaB, + cn) ; NOT (ok) ; + ok = CHOLMOD(rowdel)(k, R, L, cn) ; NOT (ok) ; + ok = CHOLMOD(rowdel_solve)(k, R, yk, L, X, DeltaB, cn) ; NOT (ok) ; + ok = CHOLMOD(rowdel_mark)(k, R, yk, colmark, L, X, DeltaB, + cn) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // MatrixOps + //-------------------------------------------------------------------------- + + C = CHOLMOD(add)(A, B, alpha, beta, values, sorted, cn) ; NOP (C) ; + + C = CHOLMOD(copy)(A, stype, mode, cn) ; NOP (C) ; + ok = CHOLMOD(drop)(tol, A, cn) ; NOT (ok) ; + nm = CHOLMOD(norm_dense)(X, norm, cn) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_sparse)(A, norm, cn) ; NOT (nm>=0) ; + C = CHOLMOD(horzcat)(A, B, values, cn) ; NOP (C) ; + ok = CHOLMOD(scale)(S, scale, A, cn) ; NOT (ok) ; + ok = CHOLMOD(sdmult)(A, transpose, alpha, beta, X, Y, cn) ; NOT (ok) ; + C = CHOLMOD(ssmult)(A, B, stype, values, sorted, cn) ; NOP (C) ; + C = CHOLMOD(submatrix)(A, r, nr, c, nc, values, sorted, + cn) ; NOP (C) ; + C = CHOLMOD(vertcat)(A, B, values, cn) ; NOP (C) ; + asym = CHOLMOD(symmetry)(A, option, NULL, NULL, NULL, NULL, + cn) ; NOT(asym>=0) ; + + //-------------------------------------------------------------------------- + // Supernodal + //-------------------------------------------------------------------------- + + ok = CHOLMOD(super_symbolic)(A, F, Parent, L, cn) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(A, F, beta, L, cn) ; NOT (ok) ; + ok = CHOLMOD(super_lsolve)(L, X, E, cn) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, E, cn) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // Check + //-------------------------------------------------------------------------- + + ok = CHOLMOD(check_common)(cn) ; NOT (ok) ; + ok = CHOLMOD(print_common)(name, cn) ; NOT (ok) ; + + ok = CHOLMOD(check_sparse)(A, cn) ; NOT (ok) ; + ok = CHOLMOD(print_sparse)(A, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_dense)(X, cn) ; NOT (ok) ; + ok = CHOLMOD(print_dense)(X, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_factor)(L, cn) ; NOT (ok) ; + ok = CHOLMOD(print_factor)(L, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_triplet)(T, cn) ; NOT (ok) ; + ok = CHOLMOD(print_triplet)(T, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_subset)(Set, len, n, cn) ; NOT (ok) ; + ok = CHOLMOD(print_subset)(Set, len, n, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_perm)(Perm, n, n, cn) ; NOT (ok) ; + ok = CHOLMOD(print_perm)(Perm, n, n, name, cn) ; NOT (ok) ; + ok = CHOLMOD(check_parent)(Parent, n, cn) ; NOT (ok) ; + ok = CHOLMOD(print_parent)(Parent, n, name, cn) ; NOT (ok) ; + + A = CHOLMOD(read_sparse)(NULL, cn) ; NOP (A) ; + p = CHOLMOD(read_matrix)(NULL, prefer, &mtype, cn) ; NOP (p) ; + X = CHOLMOD(read_dense)(NULL, cn) ; NOP (X) ; + T = CHOLMOD(read_triplet)(NULL, cn) ; NOP (T) ; + + A = CHOLMOD(read_sparse2)(NULL, DTYPE, cn) ; + NOP (A) ; + p = CHOLMOD(read_matrix2)(NULL, prefer, DTYPE, &mtype, cn) ; + NOP (p) ; + X = CHOLMOD(read_dense2)(NULL, DTYPE, cn) ; + NOP (X) ; + T = CHOLMOD(read_triplet2)(NULL, DTYPE, cn) ; + NOP (T) ; + + asym = CHOLMOD(write_dense) (NULL, NULL, NULL, cn) ; NOT (asym>=0) ; + asym = CHOLMOD(write_dense) ((FILE *) 1, NULL, NULL, cn) ; NOT (asym>=0) ; + + asym = CHOLMOD(write_sparse)(NULL, NULL, NULL, NULL, cn) ; NOT (asym>=0) ; + asym = CHOLMOD(write_sparse)((FILE *) 1, NULL, NULL, NULL, + cn) ; NOT (asym>=0) ; + + //-------------------------------------------------------------------------- + // Partition + //-------------------------------------------------------------------------- + + #ifndef NPARTITION + lr = CHOLMOD(nested_dissection)(A, fset, fsize, Perm, + CParent, Cmember, cn) ; NOT (lr >= 0) ; + lr = CHOLMOD(collapse_septree) (n, n, 1., 4, + CParent, Cmember, cn) ; NOT (lr >= 0) ; + ok = CHOLMOD(metis)(A, fset, fsize, postorder, Perm, cn) ; NOT (ok) ; + lr = CHOLMOD(bisect)(A, fset, fsize, compress, + Partition, cn) ; NOT (lr >= 0) ; + lr = CHOLMOD(metis_bisector)(A, Anw, Aew, Partition, cn) ; NOT (lr >= 0) ; + #endif + + #ifndef NCAMD + ok = CHOLMOD(ccolamd)(A, fset, fsize, Cmem2, Perm, cn) ; NOT (ok) ; + ok = CHOLMOD(csymamd)(A, Cmem2, Perm, cn) ; NOT (ok) ; + #endif + +} + +//------------------------------------------------------------------------------ +// null_test2 +//------------------------------------------------------------------------------ + +void null_test2 (void) +{ + cholmod_dense *X, *Xbad = NULL ; + cholmod_sparse *Sbad = NULL, *A ; + int ok ; + + //-------------------------------------------------------------------------- + // Test Common + //-------------------------------------------------------------------------- + + ok = CHOLMOD(allocate_work)(SIZE_MAX, 1, 1, cm) ; NOT (ok) ; + ok = CHOLMOD(allocate_work)(1, SIZE_MAX, 1, cm) ; NOT (ok) ; + ok = CHOLMOD(allocate_work)(1, 1, SIZE_MAX, cm) ; NOT (ok) ; + + // free a NULL pointer + CHOLMOD(free)(42, sizeof (char), NULL, cm) ; + int psave = cm->print ; + cm->print = 5 ; + CHOLMOD(print_common)("34:cm", cm) ; + cm->print = psave ; + + cm->maxrank = 3 ; + cm->maxrank = CHOLMOD(maxrank)(5, cm) ; OK (cm->maxrank == 4) ; + cm->maxrank = 1 ; + cm->maxrank = CHOLMOD(maxrank)(5, cm) ; OK (cm->maxrank == 2) ; + cm->maxrank = 8 ; + + // test the error handler + cm->error_handler = my_handler2 ; + CHOLMOD(drop)(0., NULL, cm) ; + cm->error_handler = NULL ; + + //-------------------------------------------------------------------------- + // dense + //-------------------------------------------------------------------------- + + X = CHOLMOD(allocate_dense)(5, 4, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (X) ; + OK (X->d == 5) ; + CHOLMOD(free_dense)(&X, cm) ; + + X = CHOLMOD(allocate_dense)(1, Int_max, 1, CHOLMOD_REAL + DTYPE, cm) ; + NOP (X) ; + X = CHOLMOD(allocate_dense)(1, 1, 1, CHOLMOD_PATTERN + DTYPE, cm) ; + NOP (X) ; + CHOLMOD(free_dense)(&X, cm) ; + + // free a NULL dense matrix + ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; + ok = CHOLMOD(free_dense)(NULL, cm) ; OK (ok) ; + + // make an invalid sparse matrix + printf ("\nspeye:\n") ; + Sbad = CHOLMOD(speye)(2, 3, CHOLMOD_REAL + DTYPE, cm) ; + OKP (Sbad) ; + + Sbad->stype = 1 ; + ok = CHOLMOD(check_sparse)(Sbad, cm) ; NOT (ok) ; + printf ("\nSparse to dense:\n") ; + X = CHOLMOD(sparse_to_dense)(Sbad, cm) ; NOP (X) ; + ok = CHOLMOD(free_sparse)(&Sbad, cm) ; OK (ok) ; + + // make an invalid dense matrix + Xbad = CHOLMOD(eye)(4, 4, CHOLMOD_REAL, cm) ; OKP (Xbad) ; + Xbad->d = 1 ; + ok = CHOLMOD(check_dense)(Xbad, cm) ; NOT (ok) ; + A = CHOLMOD(dense_to_sparse)(Xbad, TRUE, cm) ; + ok = CHOLMOD(free_dense)(&Xbad, cm) ; OK (ok) ; + CHOLMOD(print_common)("35:cm", cm) ; + cm->print = 5 ; + CHOLMOD(print_sparse)(A, "Bad A", cm) ; + cm->print = psave ; + NOP (A) ; + + //-------------------------------------------------------------------------- + // sparse + //-------------------------------------------------------------------------- + + // free a NULL sparse matrix + ok = CHOLMOD(free_sparse)(&A, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(NULL, cm) ; OK (ok) ; + A = CHOLMOD(copy_sparse)(NULL, cm) ; NOP (A) ; + + //-------------------------------------------------------------------------- + // error tests done + //-------------------------------------------------------------------------- + + printf ("------------------ null tests done\n") ; +} + diff --git a/CHOLMOD/Tcov/t_null2.c b/CHOLMOD/Tcov/t_null2.c new file mode 100644 index 0000000000..1e4bc629a6 --- /dev/null +++ b/CHOLMOD/Tcov/t_null2.c @@ -0,0 +1,3632 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_null2: test CHOLMOD with NULL and erroneous inputs +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Null and error tests, continued. + +#include "cm.h" +#include "amd.h" +#ifndef NCAMD +#include "camd.h" +#endif + +#define CSETSIZE 5 + +//------------------------------------------------------------------------------ +// null2 +//------------------------------------------------------------------------------ + +void null2 (cholmod_triplet *Tok, int do_nantests) +{ + double nm, gsave0, gsave1, r, anorm, beta [2], xnan, rcond ; + cholmod_sparse *A, *C, *AT, *E, *F, *G, *Sok, *R0, *R1, *Aboth, *Axbad, *I1, + *Abad, *R, *Acopy, *R3, *Abad2, *I, *I3, *Abad3, *AA, *AF, *AFT, + *I7, *C2, *R2, *Z ; + cholmod_dense *Xok, *Bok, *Two, *X, *W, *XX, *YY, *Xbad2, *B, + *Y, *X1, *B1, *B2, *X7, *B7 ; + cholmod_factor *L, *L2, *L3, *L4, *L5, *L6, *Lcopy, *Lbad, *L7 ; + cholmod_triplet *T, *T2, *Tz, *T3 ; + Int *fsetok, *Pok, *Flag, *Head, *Cp, *Ci, *P2, *Parent, *Lperm, + *Lp, *Li, *Lnz, *Lprev, *Lnext, *Ls, *Lpi, *Lpx, *Super, *Tj, *Ti, + *Enz, *Ep, *Post, *Cmember, *CParent, *Partition, *Pinv, *ATi, *ATp, + *LColCount, *ColCount, *First, *Level, *fsetbad, *Pbad, *Lz, + *R2p, *R2i ; + Real *Xwork, *Cx, *x, *Lx, *Tx, *Az, *R2x ; + size_t size, nznew, gsave2 ; + int64_t lr ; + void *pp, *ii, *jj, *xx ; + Int p, i, j, d, nrhs, nrow, ncol, stype, fsizeok, nz, ok, n2, trial, anz, + nzmax, cset [CSETSIZE], Axbad_type, isreal, xtype, enz, Lxtype, Cxtype, + Xxtype, Txtype, Abad2xtype, k, xtype2, Abad3xtype, save1, save2, save3, + save4, ok1, fnz ; + int option, asym ; + FILE *f ; + + beta [0] = 1e-6 ; + beta [1] = 0 ; + xnan = 0 ; + + xtype = Tok->xtype ; + printf ("Tok xtype is %d\n", (int) xtype) ; + isreal = (xtype == CHOLMOD_REAL) ; + + double maxerr = 0 ; + const int psave = cm->print ; + + //-------------------------------------------------------------------------- + // create objects to test + //-------------------------------------------------------------------------- + + printf ("\n------------------------null2 tests:\n") ; + + cm->error_handler = my_handler ; + + CHOLMOD(check_triplet) (Tok, cm) ; + nrhs = 5 ; + nrow = Tok->nrow ; + ncol = Tok->ncol ; + d = nrow + 2 ; + + A = CHOLMOD(triplet_to_sparse) (Tok, 0, cm) ; // [ + + anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; + anz = A->nzmax ; + + AT = CHOLMOD(transpose) (A, 2, cm) ; // [ + + printf ("xtrue:\n") ; + Xok = xtrue (nrow, nrhs, d, xtype + DTYPE, false) ; // [ + + printf ("rhs:\n") ; + Bok = rhs (A, nrhs, d, 0) ; // [ + printf ("fset:\n") ; + + fsetok = prand (ncol) ; // RAND [ + CHOLMOD(print_perm) (fsetok, ncol, ncol, "fsetok", cm) ; + + fsetbad = prand (ncol) ; // RAND [ + CHOLMOD(print_perm) (fsetbad, ncol, ncol, "fsetbad (befor mangling)", cm) ; + + if (ncol > 0) + { + fsetbad [0] = -1 ; + } + Pbad = prand (nrow) ; // RAND [ + CHOLMOD(print_perm) (Pbad, nrow, nrow, "Pbad", cm) ; + + if (nrow > 0) + { + Pbad [0] = -1 ; + } + I1 = CHOLMOD(speye) (nrow+1, nrow+1, xtype + DTYPE, cm) ; // [ + + fsizeok = (ncol < 2) ? ncol : (ncol/2) ; + Pok = prand (nrow) ; // RAND [ + CHOLMOD(print_perm) (Pok, nrow, nrow, "Pok", cm) ; + + R2 = CHOLMOD(allocate_sparse) (nrow, 1, nrow, FALSE, TRUE, 0, // [ + CHOLMOD_REAL + DTYPE, cm) ; + OKP (R2) ; + + R2p = R2->p ; + R2i = R2->i ; + R2x = R2->x ; + for (i = 0 ; i < nrow ; i++) + { + R2i [i] = Pok [i] ; + R2x [i] = 1 ; + } + R2p [0] = 0 ; + R2p [1] = nrow ; + + stype = A->stype ; + Two = CHOLMOD(zeros) (1, 1, xtype + DTYPE, cm) ; // [ + *((Real *) (Two->x)) = 2 ; + + Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; // [ + Parent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Post = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + CParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Partition = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + ColCount = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + First = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Level = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + + printf ("etree:\n") ; + + if (AT->stype >= 0) + { + // AT is unsymmetric, or symmetric/upper + CHOLMOD(etree) (AT, Parent, cm) ; + } + else + { + // A is symmetric/upper + CHOLMOD(etree) (A, Parent, cm) ; + } + CHOLMOD(check_parent) (Parent, nrow, cm) ; + for (cm->print = 0 ; cm->print <= ((nrow <= 30) ? 5 : 4) ; cm->print++) + { + CHOLMOD(print_parent) (Parent, nrow, "Parent", cm) ; + } + cm->print = psave ; + + // get row 0 and row 1 of A + R0 = NULL ; + R1 = NULL ; + Aboth = NULL ; + Sok = NULL ; + + Aboth = CHOLMOD(copy) (A, 0, 2, cm) ; // [ + Sok = CHOLMOD(copy) (A, 0, 0, cm) ; + Aboth->sorted = FALSE ; + + if (nrow > 1) + { + cm->print = 4 ; + if (nrow < 10) + { + ok = CHOLMOD(print_sparse) (Aboth, "Aboth", cm) ; + OK (ok) ; + } + i = 0 ; + R0 = CHOLMOD(submatrix) (Aboth, &i, 1, NULL, -1, TRUE, TRUE, cm) ; + ok = CHOLMOD(print_sparse) (R0, "Row zero", cm) ; + OK (ok) ; + i = 1 ; + R1 = CHOLMOD(submatrix) (Aboth, &i, 1, NULL, -1, TRUE, TRUE, cm) ; + ok = CHOLMOD(print_sparse) (R1, "Row one", cm) ; + OK (ok) ; + cholmod_sparse *Rt = CHOLMOD(transpose) (R1, 2, cm) ; + + C = CHOLMOD(ssmult) (R0, Rt, 0, TRUE, TRUE, cm) ; OKP (C) ; + ok = CHOLMOD(print_sparse) (C, "(Row 0)*(Row 1)'", cm) ; + OK (ok) ; + ok = CHOLMOD(free_sparse) (&C, cm) ; + OK (ok) ; + ok = CHOLMOD(free_sparse) (&Rt, cm) ; + OK (ok) ; + cm->print = psave ; + } + + // Abad: symmetric but not square, or null if A is square + if (A->nrow != A->ncol) + { + Abad = CHOLMOD(copy_sparse)(A, cm) ; // [ + Abad->stype = 1 ; + } + else + { + Abad = NULL ; + } + + // Abad2: sparse matrix with invalid xtype + Abad2 = CHOLMOD(copy_sparse)(A, cm) ; // [ + cm->print = 4 ; + CHOLMOD(print_sparse)(Abad2, "Abad2", cm) ; + cm->print = psave ; + Abad2xtype = Abad2->xtype ; + Abad2->xtype = -999 ; + + // Xbad2: dense matrix with invalid xtype + Xbad2 = CHOLMOD(zeros)(2, 2, CHOLMOD_REAL + DTYPE, cm) ; // [ + Xbad2->xtype = -911 ; + + //-------------------------------------------------------------------------- + // expect lots of errors + //-------------------------------------------------------------------------- + + printf ("\n------------------------null2 tests: ERRORs will occur\n") ; + cm->error_handler = NULL ; + + //-------------------------------------------------------------------------- + // transpose + //-------------------------------------------------------------------------- + + C = CHOLMOD(transpose)(Abad2, 1, cm) ; NOP (C) ; + ok = CHOLMOD(sort)(Abad2, cm) ; NOT (ok) ; + ok = CHOLMOD(sort)(NULL, cm) ; NOT (ok) ; + + if (nrow > 0) + { + C = CHOLMOD(ptranspose)(A, 1, Pbad, NULL, 0, cm) ; NOP (C) ; + } + + if (A->stype == 0) + { + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, TRUE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, + C, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, + C, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, Pok, NULL, 0, + C, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, Pok, fsetok, fsizeok, + C, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, NULL, fsetok, fsizeok, + C, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, FALSE, + -(A->stype), CHOLMOD_PATTERN + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, NULL, fsetok, fsizeok, + C, cm) ; OK (ok); + + E = CHOLMOD(allocate_sparse)(nrow, ncol, anz, TRUE, FALSE, + (A->stype), CHOLMOD_PATTERN + DTYPE, cm) ; + OKP (C) ; + enz = CHOLMOD(nnz)(E, cm) ; + OK (enz == 0) ; + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, Pok, nrow, + E, cm) ; OK (ok); + ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; + + } + else + { + // A is symmetric so transpose_unsym will fail + C = CHOLMOD(allocate_sparse)(ncol, nrow, anz, TRUE, TRUE, + -(A->stype), xtype + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(transpose_unsym)(A, 1, NULL, NULL, 0, + C, cm) ; NOT (ok); + OK (cm->status == CHOLMOD_INVALID) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + + if (A->nrow != A->ncol) + { + ok = CHOLMOD(transpose_sym)(A, 1, NULL, C, cm) ; NOT (ok) ; + } + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + // Abad3: sparse matrix with invalid xtype [ + C = CHOLMOD(copy_sparse)(A, cm) ; + Abad3 = CHOLMOD(transpose)(A, 1, cm) ; OKP (Abad3) ; + E = CHOLMOD(transpose)(A, 1, cm) ; OKP (E) ; + Abad3xtype = Abad3->xtype ; + Abad3->xtype = -999 ; + + ok = CHOLMOD(transpose_sym)(C, 1, NULL, Abad3, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(Abad3, 1, NULL, C, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, Abad3, cm) ;NOT (ok); + ok = CHOLMOD(transpose_unsym)(Abad3, 1, NULL, NULL, 0, C, cm) ;NOT (ok); + + switch (xtype) + { + case CHOLMOD_REAL: + printf ("make E complex:1\n") ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_COMPLEX + DTYPE, E, cm) ; + OK (ok) ; + break ; + case CHOLMOD_COMPLEX: + printf ("make E zomplex\n") ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX + DTYPE, E, cm) ; + OK (ok) ; + break ; + case CHOLMOD_ZOMPLEX: + printf ("make E complex\n") ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_COMPLEX + DTYPE, E, cm) ; + OK (ok) ; + break ; + } + + printf ("xtypes %d %d %d now\n", C->xtype, E->xtype, (int) xtype) ; + printf ("dtypes %d %d\n", C->dtype, E->dtype) ; + OK (C->dtype == DTYPE) ; + OK (E->dtype == DTYPE) ; + + printf ("mismatch start [:\n") ; + ok = CHOLMOD(transpose_sym)(C, 1, NULL, E, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(E, 1, NULL, C, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(C, 2, NULL, E, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(E, 2, NULL, C, cm) ; NOT (ok) ; + + printf ("unsym transpose:\n") ; + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, E, cm) ; + NOT (ok); + + ok = CHOLMOD(transpose_unsym)(E, 1, NULL, NULL, 0, C, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(C, 2, NULL, NULL, 0, E, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(E, 2, NULL, NULL, 0, C, cm) ; NOT (ok); + printf ("mismatch done ]\n") ; + + printf ("wrong dim [:\n") ; + ok = CHOLMOD(transpose_sym)(C, 1, NULL, I1, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(I1, 1, NULL, C, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, I1, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(I1, 1, NULL, NULL, 0, C, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(C, 2, NULL, NULL, 0, I1, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(I1, 2, NULL, NULL, 0, C, cm) ; NOT (ok); + printf ("wrong dim ]\n") ; + + nz = CHOLMOD(nnz)(C, cm) ; + if (nz > 10) + { + printf ("F too small [:\n") ; + F = CHOLMOD(allocate_sparse)(C->ncol, C->nrow, C->nzmax-5, TRUE, TRUE, + -(C->stype), C->xtype + DTYPE, cm) ; + OKP (F) ; + ok = CHOLMOD(transpose_sym)(C, 1, NULL, F, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, F, cm) ; NOT (ok); + CHOLMOD(free_sparse)(&F, cm) ; + printf ("F too small ]\n") ; + } + + ok = CHOLMOD(transpose_unsym)(C, 1, NULL, NULL, 0, NULL, cm) ; NOT (ok); + ok = CHOLMOD(transpose_unsym)(NULL, 1, NULL, NULL, 0, C, cm) ; NOT (ok); + + ok = CHOLMOD(transpose_sym)(C, 1, NULL, NULL, cm) ; NOT (ok); + ok = CHOLMOD(transpose_sym)(NULL, 1, NULL, C, cm) ; NOT (ok); + + CHOLMOD(free_sparse)(&C, cm) ; + CHOLMOD(free_sparse)(&E, cm) ; + + Abad3->xtype = Abad3xtype ; + CHOLMOD(free_sparse)(&Abad3, cm) ; // ] + + cm->status = CHOLMOD_OK ; + + //-------------------------------------------------------------------------- + // aat + //-------------------------------------------------------------------------- + + C = CHOLMOD(aat)(NULL, NULL, 0, 0, cm) ; NOP (C) ; + if (stype) + { + C = CHOLMOD(aat)(A, fsetok, fsizeok, 0, cm) ; + NOP (C) ; + } + else + { + C = CHOLMOD(aat)(A, fsetok, fsizeok, 0, cm) ; OKP (C) ; + CHOLMOD(free_sparse)(&C, cm) ; + C = CHOLMOD(aat)(Abad2, fsetok, fsizeok, 0, cm) ; NOP (C) ; + } + + //-------------------------------------------------------------------------- + // add + //-------------------------------------------------------------------------- + + C = CHOLMOD(add) (A, NULL, one, one, 1, true, cm) ; NOP (C) ; + C = CHOLMOD(add) (NULL, AT, one, one, 1, true, cm) ; NOP (C) ; + + if (A->nrow == A->ncol) + { + // C = A+AT + C = CHOLMOD(add) (A, AT, one, one, 2, true, cm) ; + OKP (C) ; + + // r = norm (imag (diag (A))) + r = znorm_diag (A, cm) ; + + // C should equal 2*A if A=A' + if (stype != 0 && r == 0) + { + // this test requires diag(A) to be real + // E = 2*A + E = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(scale) (Two, CHOLMOD_SCALAR, E, cm) ; + + // F = C-E + F = CHOLMOD(add) (C, E, one, minusone, 2, true, cm) ; + CHOLMOD(drop) (0., F, cm) ; + nz = CHOLMOD(nnz) (F, cm) ; + + OK (nz == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + + // Scale = 2 * ones(n,1) + cholmod_dense *Scale = CHOLMOD(zeros) (nrow, 1, xtype + DTYPE, cm) ; + Real *Scalex = Scale->x ; + Real *Scalez = Scale->z ; + if (xtype == CHOLMOD_REAL || xtype == CHOLMOD_ZOMPLEX) + { + for (int j = 0 ; j < nrow ; j++) + { + Scalex [j] = 2 ; + } + } + else // CHOLMOD_COMPLEX + { + for (int j = 0 ; j < nrow ; j++) + { + Scalex [2*j] = 2 ; + } + } + + // E = diag(2)*A + E = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(scale) (Scale, CHOLMOD_ROW, E, cm) ; + + // F = C-E + F = CHOLMOD(add) (C, E, one, minusone, 2, true, cm) ; + CHOLMOD(drop) (0., F, cm) ; + nz = CHOLMOD(nnz) (F, cm) ; + r = CHOLMOD(norm_sparse) (F, 0, cm) ; + OK (nz == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + + // E = A*diag(2) + E = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(scale) (Scale, CHOLMOD_COL, E, cm) ; + + // F = C-E + F = CHOLMOD(add) (C, E, one, minusone, 2, true, cm) ; + CHOLMOD(drop) (0., F, cm) ; + nz = CHOLMOD(nnz) (F, cm) ; + r = CHOLMOD(norm_sparse) (F, 0, cm) ; + OK (nz == 0) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + + // Scale = sqrt(2) * ones(n,1) + if (xtype == CHOLMOD_REAL || xtype == CHOLMOD_ZOMPLEX) + { + for (int j = 0 ; j < nrow ; j++) + { + Scalex [j] = sqrt (2) ; + } + } + else // CHOLMOD_COMPLEX + { + for (int j = 0 ; j < nrow ; j++) + { + Scalex [2*j] = sqrt (2) ; + } + } + + // E = diag(sqrt(2)) * A * diag(sqrt(2)) + E = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(scale) (Scale, CHOLMOD_SYM, E, cm) ; + F = CHOLMOD(add) (C, E, one, minusone, 2, true, cm) ; + CHOLMOD(drop) (0., F, cm) ; + nz = CHOLMOD(nnz) (F, cm) ; + r = CHOLMOD(norm_sparse) (F, 0, cm) ; + #ifdef DOUBLE + OK (r < 1e-12*anorm) ; + #else + OK (r < 1e-5*anorm) ; + #endif + + // error tests + Real *s = Scale->x ; + Scale->x = NULL ; + ok = CHOLMOD(scale) (Scale, CHOLMOD_SYM, E, cm) ; + NOT (ok) ; + Scale->x = s ; + + OKP (E) ; + OKP (cm) ; + ok = CHOLMOD(scale) (NULL, CHOLMOD_ROW, E, cm) ; NOT (ok) ; + ok = CHOLMOD(scale) (Scale, CHOLMOD_SYM, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(scale) (NULL, CHOLMOD_SYM, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(scale) (Scale, -1, E, cm) ; NOT (ok) ; + + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + CHOLMOD(free_dense) (&Scale, cm) ; + } + CHOLMOD(free_sparse) (&C, cm) ; + } + + Axbad = CHOLMOD(copy_sparse) (A, cm) ; // [ + Axbad_type = Axbad->xtype ; + Axbad->xtype = CHOLMOD_COMPLEX ; + C = CHOLMOD(add) (A, Axbad, one, one, 1, true, cm) ; + bool Axbad_is_ok = (Axbad_type == CHOLMOD_COMPLEX) ; + if (Axbad_is_ok) + { + OKP (C) ; + ok = CHOLMOD(free_sparse) (&C, cm) ; OK (ok) ; + } + else + { + NOP (C) ; + } + + if (nrow > 1 && xtype == CHOLMOD_REAL) + { + // C = A (0,:) + A (1,:) + C = CHOLMOD(add) (R0, R1, one, one, 1, true, cm) ; OKP (C) ; + OK (CHOLMOD(check_sparse) (C, cm)) ; + ok = CHOLMOD(free_sparse) (&C, cm) ; OK (ok) ; + } + ok = CHOLMOD(free_sparse) (&C, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse) (NULL, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // sparse + //-------------------------------------------------------------------------- + + cm->print = 4 ; + + ok = CHOLMOD(reallocate_sparse)(10, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(reallocate_sparse)(2 * Abad2->nzmax, Abad2, cm) ; NOT (ok) ; + + C = CHOLMOD(copy_sparse)(Abad2, cm) ; NOP (C) ; + C = CHOLMOD(allocate_sparse)(2, 3, 6, TRUE, TRUE, 1, + CHOLMOD_PATTERN + DTYPE, cm) ; + NOP (C) ; + + C = CHOLMOD(copy)(A, 0, -1, cm) ; OKP (C) ; + E = unpack (C) ; OKP (E) ; + F = CHOLMOD(copy_sparse)(E, cm) ; OKP (F) ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL + DTYPE, C, cm) ; + OK (ok) ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL + DTYPE, F, cm) ; + OK (ok) ; + // G = C-F + G = CHOLMOD(add)(C, F, one, minusone, 2, false, cm) ; OKP (G) ; + CHOLMOD(print_sparse)(G, "G predrop", cm) ; + ok = CHOLMOD(drop)(0., G, cm) ; OK (ok) ; + nz = CHOLMOD(nnz)(G, cm) ; + CHOLMOD(print_sparse)(C, "C", cm) ; + CHOLMOD(print_sparse)(E, "E", cm) ; + CHOLMOD(print_sparse)(F, "F", cm) ; + CHOLMOD(print_sparse)(G, "G", cm) ; + + OK (nz == 0) ; + CHOLMOD(free_sparse)(&C, cm) ; + CHOLMOD(free_sparse)(&E, cm) ; + CHOLMOD(free_sparse)(&F, cm) ; + CHOLMOD(free_sparse)(&G, cm) ; + + cm->print = psave ; + + //-------------------------------------------------------------------------- + // scale + //-------------------------------------------------------------------------- + + ok = CHOLMOD(scale)(Two, -1, C, cm) ; NOT (ok) ; + if (nrow > 1) + { + E = CHOLMOD(copy_sparse)(A, cm) ; OKP (E) ; + CHOLMOD(scale)(Two, CHOLMOD_ROW, E, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // amd + //-------------------------------------------------------------------------- + + ok = CHOLMOD(amd)(NULL, NULL, 0, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(amd)(A, NULL, 0, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(amd)(NULL, NULL, 0, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; + cm->current = -1 ; + ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; + cm->current = 0 ; + ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "AMD perm", cm) ; OK (ok) ; + cm->print = 4 ; + if (A->nrow < 1000) + { + CHOLMOD(print_sparse)(Aboth, "Aboth", cm) ; + ok = CHOLMOD(amd)(Aboth, NULL, 0, Pok, cm) ; OK (ok) ; + } + cm->print = psave ; + ok = CHOLMOD(amd)(Abad2, NULL, 0, Pok, cm) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // camd + //-------------------------------------------------------------------------- + + #ifndef NCAMD + ok = CHOLMOD(camd)(NULL, NULL, 0, NULL, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(camd)(A, NULL, 0, NULL, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(camd)(NULL, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; OK (ok) ; + cm->current = -1 ; + ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; OK (ok) ; + cm->current = 0 ; + ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "CAMD perm", cm) ; OK (ok) ; + cm->print = 4 ; + if (A->nrow < 1000) + { + CHOLMOD(print_sparse)(Aboth, "Aboth", cm) ; + ok = CHOLMOD(camd)(Aboth, NULL, 0, NULL, Pok, cm) ; OK (ok) ; + } + cm->print = psave ; + ok = CHOLMOD(camd)(Abad2, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; + #endif + + //-------------------------------------------------------------------------- + // analyze + //-------------------------------------------------------------------------- + + cm->print = 4 ; + ok = CHOLMOD(print_common)("13:cm", cm) ; + OK (ok) ; + cm->print = psave ; + + cm->nmethods = 1 ; + cm->method [0].ordering = -1 ; + ok = CHOLMOD(print_common)("14:cm Bad", cm) ; + NOT (ok) ; + ok = CHOLMOD(analyze_ordering)(NULL, 0, NULL, NULL, 0, + NULL, NULL, NULL, NULL, NULL, cm) ; NOT (ok) ; + L = CHOLMOD(analyze)(NULL, cm) ; NOP (L) ; + L = CHOLMOD(analyze)(Abad2, cm) ; NOP (L) ; + L = CHOLMOD(analyze)(A, cm) ; NOP (L) ; + + // test AMD backup strategy + cm->nmethods = 2 ; + cm->method [0].ordering = -1 ; + cm->method [1].ordering = -1 ; + L = CHOLMOD(analyze)(A, cm) ; OKP (L) ; + + cm->nmethods = 0 ; // restore defaults + cm->method [0].ordering = CHOLMOD_GIVEN ; + cm->method [1].ordering = CHOLMOD_AMD ; + cm->print = 4 ; + ok = CHOLMOD(print_common)("15:cm", cm) ; + OK (ok) ; + ok = CHOLMOD(print_factor)(L, "L symbolic", cm) ; OK (ok) ; + cm->print = psave ; + ok = CHOLMOD(free_factor)(&L, cm) ; OK (ok) ; + ok = CHOLMOD(free_factor)(&L, cm) ; OK (ok) ; + ok = CHOLMOD(free_factor)(NULL, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // band + //-------------------------------------------------------------------------- + + C = CHOLMOD(band)(NULL, 0, 0, 0, cm) ; NOP (C) ; + C = CHOLMOD(band)(Abad2, 0, 0, 0, cm) ; NOP (C) ; + + //-------------------------------------------------------------------------- + // ccolamd + //-------------------------------------------------------------------------- + + #ifndef NCAMD + ok = CHOLMOD(ccolamd)(NULL, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, NULL, cm) ; NOT (ok) ; + + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; + if (stype) + { + NOT (ok) ; + } + else + { + OK (ok) ; + } + + cm->current = -1 ; + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; + cm->current = 0 ; + if (stype) + { + NOT (ok) ; + } + else + { + OK (ok) ; + } + #endif + + //-------------------------------------------------------------------------- + // copy + //-------------------------------------------------------------------------- + + CHOLMOD(print_sparse)(Abad, "Abad", cm) ; + + C = CHOLMOD(copy)(Abad, 0, 1, cm) ; + CHOLMOD(print_sparse)(C, "copy of Abad", cm) ; + NOP (C) ; + + C = CHOLMOD(copy_sparse)(Abad, cm) ; + CHOLMOD(print_sparse)(C, "another copy of Abad", cm) ; + NOP (C) ; + + C = CHOLMOD(copy)(A, 0, -1, cm) ; OKP (C) ; + OK (nzdiag (C) == 0) ; + + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // submatrix + //-------------------------------------------------------------------------- + + E = CHOLMOD(submatrix) (Abad2, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; + NOP (E) ; + + if (A->stype == 0) + { + // E = A(:,:) + E = CHOLMOD(submatrix) (NULL, NULL,-1, NULL,-1, TRUE, TRUE, cm) ; + NOP (E) ; + E = CHOLMOD(submatrix) (A, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; + OKP (E) ; + + // C = A-E + C = CHOLMOD(add) (A, E, one, minusone, 1, true, cm) ; + OKP (C) ; + ok = CHOLMOD(drop) (0., C, cm) ; + OK (ok) ; + ok = CHOLMOD(drop) (0., Abad2, cm) ; + NOT (ok) ; + nz = CHOLMOD(nnz) (C, cm) ; + OK (nz == 0) ; + ok = CHOLMOD(free_sparse) (&C, cm) ; + OK (ok) ; + ok = CHOLMOD(free_sparse) (&E, cm) ; + OK (ok) ; + + i = -1 ; + E = CHOLMOD(submatrix) (A, &i, 1, NULL, -1, TRUE, TRUE, cm) ; + NOP (E) ; + E = CHOLMOD(submatrix) (A, NULL, -1, &i, 1, TRUE, TRUE, cm) ; + NOP (E) ; + E = CHOLMOD(submatrix) (A, &i, 1, &i, 1, TRUE, TRUE, cm) ; + NOP (E) ; + i = 0 ; + j = -1 ; + E = CHOLMOD(submatrix) (A, &i, 1, &j, 1, TRUE, TRUE, cm) ; + NOP (E) ; + } + + //-------------------------------------------------------------------------- + // read + //-------------------------------------------------------------------------- + + C = CHOLMOD(read_sparse)(NULL, cm) ; NOP (C) ; + X = CHOLMOD(read_dense)(NULL, cm) ; NOP (X) ; + pp = CHOLMOD(read_matrix)(NULL, 1, NULL, cm) ; NOP (pp) ; + pp = CHOLMOD(read_matrix)((FILE *) 1, 1, NULL, cm) ; NOP (pp) ; + T3 = CHOLMOD(read_triplet)(NULL, cm) ; NOP (T3) ; + + C = CHOLMOD(read_sparse2)(NULL, DTYPE, cm) ; NOP (C) ; + X = CHOLMOD(read_dense2)(NULL, DTYPE, cm) ; NOP (X) ; + pp = CHOLMOD(read_matrix2)(NULL, 1, DTYPE, NULL, cm) ; NOP (pp) ; + pp = CHOLMOD(read_matrix2)((FILE *) 1, DTYPE, 1, NULL, cm) ; NOP (pp) ; + T3 = CHOLMOD(read_triplet2)(NULL, DTYPE, cm) ; NOP (T3) ; + + //-------------------------------------------------------------------------- + // write + //-------------------------------------------------------------------------- + + asym = CHOLMOD(write_sparse) (NULL, NULL, NULL, NULL, cm) ; NOT (asym>=0); + asym = CHOLMOD(write_sparse) ((FILE *) 1, NULL, NULL, NULL, cm) ; + NOT (asym>=0); + + asym = CHOLMOD(write_dense) (NULL, NULL, NULL, cm) ; NOT (asym>=0); + asym = CHOLMOD(write_dense) ((FILE *) 1, NULL, NULL, cm) ; NOT (asym>=0); + + f = fopen ("temp4.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, NULL, "garbage.txt", cm) ; + fclose (f) ; + printf ("write_sparse, asym: %d\n", asym) ; + OK (asym == EMPTY) ; + + if (A != NULL) + { + save1 = A->xtype ; + A->xtype = 999 ; + f = fopen ("temp4.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, NULL, NULL, cm) ; + fclose (f) ; + printf ("write_sparse, asym: %d\n", asym) ; + OK (asym == EMPTY) ; + A->xtype = save1 ; + } + + Z = CHOLMOD(speye) (nrow+1, ncol+1, CHOLMOD_PATTERN + DTYPE, cm) ; + f = fopen ("temp4.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; + fclose (f) ; + printf ("write_sparse, asym: %d with Z\n", asym) ; + OK (asym == EMPTY) ; + + Z->xtype = 999 ; + f = fopen ("temp4.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; + fclose (f) ; + printf ("write_sparse, asym: %d with Z2\n", asym) ; + OK (asym == EMPTY) ; + Z->xtype = CHOLMOD_PATTERN ; + + CHOLMOD(free_sparse) (&Z, cm) ; + + Z = CHOLMOD(speye) (0, ncol+1, CHOLMOD_PATTERN + DTYPE, cm) ; + if (ncol == 7 && nrow == 7) + { + f = fopen ("temp4_write7.mtx", "w") ; + } + else + { + f = fopen ("temp4.mtx", "w") ; + } + asym = CHOLMOD(write_sparse) (f, A, Z, NULL, cm) ; + fclose (f) ; + printf ("write_sparse, asym: %d with Z\n", asym) ; + if (A == NULL) + { + OK (asym == EMPTY) ; + } + else + { + OK (asym > EMPTY) ; + } + CHOLMOD(free_sparse) (&Z, cm) ; + + X = CHOLMOD(ones) (4, 4, CHOLMOD_REAL + DTYPE, cm) ; + f = fopen ("temp6.mtx", "w") ; + asym = CHOLMOD(write_dense) (f, X, "garbage.txt", cm) ; + fclose (f) ; + OK (asym == EMPTY) ; + + X->xtype = 999 ; + f = fopen ("temp6.mtx", "w") ; + asym = CHOLMOD(write_dense) (f, X, NULL, cm) ; + fclose (f) ; + OK (asym == EMPTY) ; + X->xtype = CHOLMOD_REAL ; + CHOLMOD(free_dense) (&X, cm) ; + + //-------------------------------------------------------------------------- + // print_common + //-------------------------------------------------------------------------- + + cm->print = 4 ; + ok = CHOLMOD(print_common)("16:cm Null", NULL) ; + cm->print = psave ; + NOT (ok) ; + for (cm->status = CHOLMOD_INVALID ; cm->status <= CHOLMOD_DSMALL ; + cm->status++) + { + ok = CHOLMOD(print_common)("17:cm status", cm) ; + OK (ok) ; + } + cm->status = 999 ; + ok = CHOLMOD(print_common)("18:cm bad status", cm) ; + NOT (ok) ; + cm->status = CHOLMOD_OK ; + + Flag = cm->Flag ; + cm->Flag = NULL ; + ok = CHOLMOD(print_common)("19:cm bad Flag", cm) ; + NOT (ok) ; + cm->Flag = Flag ; + ok = CHOLMOD(print_common)("20:cm ok Flag", cm) ; + OK (ok) ; + + Flag [0] = Int_max ; + ok = CHOLMOD(print_common)("21:cm bad Flag", cm) ; + NOT (ok) ; + Flag [0] = -1 ; + ok = CHOLMOD(print_common)("22:cm ok Flag", cm) ; + OK (ok) ; + + Head = cm->Head ; + cm->Head = NULL ; + ok = CHOLMOD(print_common)("23:cm bad Head", cm) ; + NOT (ok) ; + cm->Head = Head ; + ok = CHOLMOD(print_common)("24:cm ok Head", cm) ; + OK (ok) ; + + Head [0] = Int_max ; + ok = CHOLMOD(print_common)("25:cm bad Head", cm) ; + NOT (ok) ; + Head [0] = -1 ; + ok = CHOLMOD(print_common)("26:cm ok Head", cm) ; + OK (ok) ; + + cm->status = CHOLMOD_OK ; + printf ("\nbad Xwork:\n") ; + Xwork = cm->Xwork ; + cm->Xwork = NULL ; + ok = CHOLMOD(print_common)("27:cm bad Xwork", cm) ; + NOT (ok) ; + cm->Xwork = Xwork ; + ok = CHOLMOD(print_common)("28:cm ok Xwork", cm) ; + OK (ok) ; + + Xwork [0] = 1 ; + ok = CHOLMOD(print_common)("29:cm bad Xwork", cm) ; + NOT (ok) ; + Xwork [0] = 0 ; + ok = CHOLMOD(print_common)("30:cm ok Xwork", cm) ; + OK (ok) ; + + p = cm->nmethods ; + i = cm->method [0].ordering ; + cm->nmethods = 1 ; + cm->method [0].ordering = 999 ; + ok = CHOLMOD(print_common)("31:cm bad method", cm) ; + NOT (ok) ; + cm->nmethods = p ; + cm->method [0].ordering = i ; + + //-------------------------------------------------------------------------- + // print_sparse + //-------------------------------------------------------------------------- + + C = CHOLMOD(copy_sparse)(A, cm) ; OKP (C) ; + + cm->print = 3 ; + C->itype = EMPTY ; + ok = CHOLMOD(print_sparse)(C, "CIbad", cm) ; NOT (ok) ; + C->itype = cm->itype ; + cm->print = psave ; + + cm->print = 4 ; + #if defined ( CHOLMOD_INT64 ) + C->itype = CHOLMOD_INT ; + #else + C->itype = CHOLMOD_LONG ; + #endif + ok = CHOLMOD(print_sparse)(C, "Cibad2", cm) ; NOT (ok) ; + C->itype = cm->itype ; + cm->print = psave ; + + OK (C->dtype == DTYPE) ; + + Cxtype = C->xtype ; + C->xtype = EMPTY ; + ok = CHOLMOD(print_sparse)(C, "CXbad", cm) ; NOT (ok) ; + C->xtype = Cxtype ; + + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + Cp = C->p ; + Ci = C->i ; + Cx = C->x ; + + C->p = NULL ; + ok = CHOLMOD(print_sparse)(C, "Cp bad", cm) ; NOT (ok) ; + C->p = Cp ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + C->i = NULL ; + ok = CHOLMOD(print_sparse)(C, "Ci bad", cm) ; NOT (ok) ; + C->i = Ci ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + C->x = NULL ; + ok = CHOLMOD(print_sparse)(C, "Cx bad", cm) ; NOT (ok) ; + C->x = Cx ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + Cp [0] = 42 ; + ok = CHOLMOD(print_sparse)(C, "Cp [0] bad", cm) ; NOT (ok) ; + Cp [0] = 0 ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + p = Cp [ncol] ; + Cp [ncol] = C->nzmax + 10 ; + ok = CHOLMOD(print_sparse)(C, "Cp [ncol] bad", cm) ; NOT (ok) ; + Cp [ncol] = p ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + p = Cp [ncol] ; + Cp [ncol] = -1 ; + ok = CHOLMOD(print_sparse)(C, "Cp [ncol] neg", cm) ; NOT (ok) ; + Cp [ncol] = p ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + + if (ncol > 0) + { + p = Cp [1] ; + Cp [1] = 2*nrow + 1 ; + ok = CHOLMOD(print_sparse)(C, "Cp [1] bad", cm) ; NOT (ok) ; + Cp [1] = p ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + } + + if (ncol > 2) + { + p = Cp [2] ; + Cp [2] = Cp [1] - 1 ; + ok = CHOLMOD(print_sparse)(C, "Cp [2] bad", cm) ; NOT (ok) ; + Cp [2] = p ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + } + + if (Cp [ncol] > 0) + { + i = Ci [0] ; + Ci [0] = -1 ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] neg", cm) ; NOT (ok) ; + Ci [0] = i ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + } + + if (ncol > 0 && C->sorted && Cp [1] - Cp [0] > 2) + { + i = Ci [0] ; + Ci [0] = nrow-1 ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; NOT (ok) ; + Ci [0] = i ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + } + + if (ncol > 0 && C->sorted && ncol > 2 && Cp [1] - Cp [0] > 2) + { + // swap the first two entries + p = Ci [0] ; + Ci [0] = Ci [1] ; + Ci [1] = p ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; NOT (ok) ; + C->sorted = FALSE ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; OK (ok) ; + Ci [1] = Ci [0] ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] duplicate", cm) ; NOT (ok) ; + Ci [1] = p ; + ok = CHOLMOD(print_sparse)(C, "Ci [0] unsorted", cm) ; OK (ok) ; + p = Ci [0] ; + Ci [0] = Ci [1] ; + Ci [1] = p ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + C->sorted = TRUE ; + ok = CHOLMOD(print_sparse)(C, "C ok", cm) ; OK (ok) ; + } + + E = CHOLMOD(copy_sparse)(C, cm) ; OKP (E) ; + Enz = CHOLMOD(malloc)(ncol, sizeof (Int), cm) ; OKP (Enz) ; + E->nz = Enz ; + Ep = E->p ; + for (j = 0 ; j < ncol ; j++) + { + Enz [j] = Ep [j+1] - Ep [j] ; + } + E->packed = FALSE ; + + ok = CHOLMOD(print_sparse)(E, "E unpacked ok", cm) ; OK (ok) ; + + ok = CHOLMOD(band_inplace)(0, 0, 0, E, cm) ; NOT (ok) ; + + E->nz = NULL ; + ok = CHOLMOD(print_sparse)(E, "E unpacked bad", cm) ; NOT (ok) ; + E->nz = Enz ; + ok = CHOLMOD(print_sparse)(E, "E unpacked ok", cm) ; OK (ok) ; + + F = CHOLMOD(copy)(E, 0, 0, cm) ; + cm->print = 4 ; + ok = CHOLMOD(print_sparse)(F, "F pattern ok", cm) ; OK (ok) ; + cm->print = 1 ; + + CHOLMOD(free_sparse)(&F, cm) ; + CHOLMOD(free_sparse)(&E, cm) ; + CHOLMOD(free_sparse)(&C, cm) ; + + //-------------------------------------------------------------------------- + // print_dense + //-------------------------------------------------------------------------- + + X = CHOLMOD(sparse_to_dense)(NULL, cm) ; NOP (X) ; + X = CHOLMOD(sparse_to_dense)(Abad2, cm) ; NOP (X) ; + C = CHOLMOD(dense_to_sparse)(NULL, TRUE, cm) ; NOP (C) ; + + X = CHOLMOD(copy_dense)(Xok, cm) ; + + ok = CHOLMOD(print_dense)(NULL, "null", cm) ; NOT (ok) ; + + x = X->x ; + X->x = NULL ; + ok = CHOLMOD(print_dense)(X, "Xnull", cm) ; NOT (ok) ; + X->x = x ; + ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; + + X->nzmax = 1 ; + ok = CHOLMOD(print_dense)(X, "X nzmax too small", cm) ; NOT (ok) ; + X->nzmax = Xok->nzmax ; + ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; + + X->d = -1 ; + ok = CHOLMOD(print_dense)(X, "X d too small", cm) ; NOT (ok) ; + X->d = Xok->d ; + ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; + + Xxtype = X->xtype ; + X->xtype = CHOLMOD_PATTERN ; + ok = CHOLMOD(print_dense)(X, "X pattern", cm) ; NOT (ok) ; + + X->xtype = -1 ; + ok = CHOLMOD(print_dense)(X, "X unknown", cm) ; NOT (ok) ; + X->xtype = Xxtype ; + ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; + + ok = CHOLMOD(print_dense)(X, "X OK", cm) ; OK (ok) ; + OK (X->dtype == DTYPE) ; + + CHOLMOD(free_dense)(&X, cm) ; + + //-------------------------------------------------------------------------- + // print_subset + //-------------------------------------------------------------------------- + + ok = CHOLMOD(check_subset)(NULL, 0, 0, cm) ; OK (ok) ; + ok = CHOLMOD(print_subset)(NULL, 0, 0, "null", cm) ; OK (ok) ; + + for (i = 0 ; i < CSETSIZE ; i++) + { + cset [i] = i ; + } + + for (cm->print = 0 ; cm->print <= 5 ; cm->print++) + { + ok = CHOLMOD(print_subset)(NULL, -1, 10, "[0:9]", cm) ; + OK (ok) ; + ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset OK", cm) ; + OK (ok) ; + cset [0] = -1 ; + ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset bad", cm) ; + NOT (ok) ; + cset [0] = CSETSIZE-1 ; + ok = CHOLMOD(print_subset)(cset, CSETSIZE, CSETSIZE, "cset OK", cm) ; + OK (ok) ; + } + + cm->print = psave ; + + //-------------------------------------------------------------------------- + // print_perm + //-------------------------------------------------------------------------- + + ok = CHOLMOD(check_perm)(NULL, 0, 0, cm) ; OK (ok) ; + + for (cm->print = 3 ; cm->print <= 4 ; cm->print++) + { + ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P OK", cm) ; + OK (ok) ; + if (nrow > 0) + { + p = Pok [0] ; + Pok [0] = 2*ncol + 1 ; + ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P bad", cm) ; + NOT (ok) ; + Pok [0] = p ; + ok = CHOLMOD(print_perm)(Pok, nrow, nrow, "P OK", cm) ; + } + OK (ok) ; + } + cm->print = psave ; + + n2 = 2 * cm->nrow ; + P2 = prand (n2) ; // RAND + CHOLMOD(print_perm) (P2, n2, n2, "P2", cm) ; + + for (cm->print = 3 ; cm->print <= 4 ; cm->print++) + { + ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 OK", cm) ; + OK (ok) ; + p = P2 [0] ; + P2 [0] = -1 ; + ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 bad", cm) ; + NOT (ok) ; + P2 [0] = p ; + ok = CHOLMOD(print_perm)(P2, n2, n2, "P2 OK", cm) ; + OK (ok) ; + } + cm->print = psave ; + + CHOLMOD(free)(2 * (cm->nrow), sizeof (Int), P2, cm) ; + + //-------------------------------------------------------------------------- + // print_parent + //-------------------------------------------------------------------------- + + ok = CHOLMOD(print_parent)(NULL, 0, "null", cm) ; NOT (ok) ; + if (nrow > 0) + { + i = Parent [0] ; + Parent [0] = -2 ; + ok = CHOLMOD(print_parent)(Parent, nrow, "bad Parent", cm) ; NOT (ok) ; + Parent [0] = i ; + ok = CHOLMOD(print_parent)(Parent, nrow, "OK Parent", cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // print_factor + //-------------------------------------------------------------------------- + + if (A->stype == 0) + { + L = CHOLMOD(alloc_factor)(nrow, DTYPE, cm) ; + OKP (L) ; + ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; + NOT (ok) ; + CHOLMOD(free_factor)(&L, cm) ; + } + + ok = CHOLMOD(print_factor)(NULL, "L null", cm) ; NOT (ok) ; + + // create a valid symbolic supernodal L + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_asis = TRUE ; + L = CHOLMOD(analyze)(A, cm) ; // [ + OKP (L) ; + ok = CHOLMOD(print_factor)(L, "L ok", cm) ; OK (ok) ; + + ok = CHOLMOD(change_factor)(CHOLMOD_ZOMPLEX, TRUE, TRUE, TRUE, TRUE, L, cm); + NOT (ok) ; + + OK (L->xtype == CHOLMOD_PATTERN) ; + OK (L->is_super) ; + + L->itype = -1 ; + ok = CHOLMOD(print_factor)(L, "L int unknown", cm) ; NOT (ok) ; + L->itype = cm->itype ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + cm->print = 4 ; + #if defined ( CHOLMOD_INT64 ) + L->itype = CHOLMOD_INT ; + #else + L->itype = CHOLMOD_LONG ; + #endif + ok = CHOLMOD(print_factor)(L, "L bad itype", cm) ; + NOT (ok) ; + L->itype = cm->itype ; + cm->print = psave ; + + cm->print = 4 ; + + i = L->ordering ; + L->ordering = -1 ; + ok = CHOLMOD(print_factor)(L, "L bad ordering", cm) ; NOT (ok) ; + L->ordering = CHOLMOD_GIVEN ; + ok = CHOLMOD(print_factor)(L, "L given ordering", cm) ; OK (ok) ; + L->ordering = i ; + + Lxtype = L->xtype ; + L->xtype = CHOLMOD_REAL ; + ok = CHOLMOD(print_factor)(L, "L real", cm) ; NOT (ok) ; + L->xtype = CHOLMOD_COMPLEX ; + ok = CHOLMOD(print_factor)(L, "L complex", cm) ; NOT (ok) ; + L->xtype = CHOLMOD_ZOMPLEX ; + ok = CHOLMOD(print_factor)(L, "L zomplex", cm) ; NOT (ok) ; + L->xtype = -1 ; + ok = CHOLMOD(print_factor)(L, "L unknown", cm) ; NOT (ok) ; + L->xtype = CHOLMOD_PATTERN ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + L->xtype = Lxtype ; + + //-------------------------------------------------------------------------- + // supernodal factor + //-------------------------------------------------------------------------- + + // create a valid supernodal numeric L (simplicial if Supernodal + // module not installed) + ok = CHOLMOD(factorize)(A, L, cm) ; + + OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; + + if (L->is_super) + { + // there is no supernodal zomplex L + ok = CHOLMOD(factor_xtype)(CHOLMOD_ZOMPLEX + DTYPE, L, cm) ; + NOT (ok) ; + } + + // pack the simplicial factor, or return silently if supernodal + ok = CHOLMOD(pack_factor)(L, cm) ; OK (ok) ; + + Lbad = CHOLMOD(copy_factor)(L, cm) ; // [ + Lxtype = L->xtype ; + Lbad->xtype = -1 ; + + OK (L->is_super && L->xtype != CHOLMOD_PATTERN && L->is_ll) ; + + if (A->stype == 0) + { + ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; NOT (ok) ; + } + ok = CHOLMOD(super_symbolic)(A, Abad2, Parent, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_symbolic)(Abad2, A, Parent, L, cm) ; NOT (ok) ; + + W = CHOLMOD(zeros)(L->maxesize, 1, L->xtype + DTYPE, cm) ; + OKP (W) ; + X = CHOLMOD(ones)(nrow, 1, L->xtype + DTYPE, cm) ; + OKP (X) ; + ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; OK (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; OK (ok) ; + + ok = CHOLMOD(super_lsolve)(Lbad, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(Lbad, X, W, cm) ; NOT (ok) ; + + XX = CHOLMOD(zeros)(nrow, 1, + ((L->xtype == CHOLMOD_REAL) ? CHOLMOD_COMPLEX : CHOLMOD_REAL) + DTYPE, + cm) ; + ok = CHOLMOD(super_lsolve)(L, X, XX, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, XX, cm) ; NOT (ok) ; + CHOLMOD(free_dense)(&XX, cm) ; + + ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; OK (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; OK (ok) ; + + x = X->x ; + X->x = NULL ; + ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; NOT (ok) ; + X->x = x ; + + x = W->x ; + W->x = NULL ; + ok = CHOLMOD(super_lsolve)(L, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(L, X, W, cm) ; NOT (ok) ; + W->x = x ; + CHOLMOD(free_dense)(&X, cm) ; + CHOLMOD(free_dense)(&W, cm) ; + + cm->precise = TRUE ; + ok = CHOLMOD(print_factor)(L, "L supernodal (precise)", cm) ; OK (ok) ; + cm->precise = FALSE ; + ok = CHOLMOD(print_factor)(L, "L supernodal", cm) ; OK (ok) ; + cm->print = psave ; + + // cannot realloc a supernodal L + ok = CHOLMOD(reallocate_factor)(10000, L, cm) ; NOT (ok) ; + ok = CHOLMOD(reallocate_factor)(10000, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(pack_factor)(NULL, cm) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // print factor + //-------------------------------------------------------------------------- + + Lxtype = L->xtype ; + OK (L->dtype == DTYPE) ; + + cm->print = 4 ; + L->xtype = CHOLMOD_PATTERN ; + ok = CHOLMOD(print_factor)(L, "L pattern", cm) ; OK (ok) ; + C = CHOLMOD(factor_to_sparse)(L, cm) ; NOP (C) ; + L->xtype = Lxtype ; + cm->print = psave ; + + // check with bad L factor + ok = CHOLMOD(print_factor)(Lbad, "L unknown", cm) ; NOT (ok) ; + ok = CHOLMOD(reallocate_factor)(999, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(pack_factor)(Lbad, cm) ; NOT (ok) ; + C = CHOLMOD(factor_to_sparse)(Lbad, cm) ; NOP (C) ; + L2 = CHOLMOD(copy_factor)(Lbad, cm) ; NOP (L2) ; + ok = CHOLMOD(factorize)(A, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(A, NULL, 0, TRUE, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(nrow-2, A, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel)(nrow-2, NULL, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(A, AT, beta, 1, 2, Lbad, cm) ; NOT (ok) ; + ok = CHOLMOD(updown)(+1, A, Lbad, cm) ; NOT (ok) ; + + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + L->dtype = -1 ; + ok = CHOLMOD(print_factor)(L, "L unknown", cm) ; NOT (ok) ; + L->dtype = DTYPE ; + + if (nrow > 0) + { + Lperm = L->Perm ; + p = Lperm [0] ; + Lperm [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L perm invalid", cm) ; NOT (ok) ; + Lperm [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + } + + LColCount = L->ColCount ; + L->ColCount = NULL ; + ok = CHOLMOD(print_factor)(L, "L no colcount", cm) ; NOT (ok) ; + L->ColCount = LColCount ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + OK (L->dtype == DTYPE) ; + + if (nrow > 0) + { + LColCount = L->ColCount ; + p = LColCount [0] ; + LColCount [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L colcount vad", cm) ; NOT (ok) ; + LColCount [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // print simplicial factor + //-------------------------------------------------------------------------- + + // check LDL' unpacked + ok = CHOLMOD(print_factor)(L, "L OK for L2 copy", cm) ; OK (ok) ; + OK (L->dtype == DTYPE) ; + L2 = CHOLMOD(copy_factor)(L, cm) ; // [ + + OK (L2->dtype == DTYPE) ; + OKP (L2) ; + ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, + TRUE, L2, cm) ; + OK (L->dtype == DTYPE) ; + + // check LDL' packed + L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; + OK (L3->dtype == DTYPE) ; + ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, TRUE, + TRUE, L3, cm) ; + ok = CHOLMOD(print_factor)(L3, "L3 OK", cm) ; OK (ok) ; + OK (L3->dtype == DTYPE) ; + CHOLMOD(free_factor)(&L3, cm) ; OK (ok) ; + ok = CHOLMOD(print_factor)(L2, "L2 OK", cm) ; OK (ok) ; + ok = CHOLMOD(pack_factor)(L2, cm) ; OK (ok) ; + ok = CHOLMOD(print_factor)(L2, "L2 OK packed", cm) ; OK (ok) ; + + OK (L->dtype == DTYPE) ; + OK (L2->dtype == DTYPE) ; + + // create a simplicial factor from scratch + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_asis = TRUE ; + L6 = CHOLMOD(analyze)(A, cm) ; // [ + OKP (L6) ; + ok = CHOLMOD(factorize)(A, L6, cm) ; + OK (cm->status >= CHOLMOD_OK) ; + cm->supernodal = CHOLMOD_AUTO ; + + ok = CHOLMOD(print_sparse)(A, "A OK", cm) ; OK (ok) ; + ok = CHOLMOD(print_factor)(L6, "L6 OK", cm) ; OK (ok) ; + + Lz = L6->z ; + L6->z = NULL ; + ok = CHOLMOD(print_factor)(L6, "L6 no z", cm) ; + if (L6->xtype == CHOLMOD_ZOMPLEX) + { + NOT (ok) ; + } + else + { + OK (ok) ; + } + L6->z = Lz ; + CHOLMOD(free_factor)(&L6, cm) ; // ] + + Az = A->z ; + A->z = NULL ; + ok = CHOLMOD(print_sparse)(A, "A no z", cm) ; + if (A->xtype == CHOLMOD_ZOMPLEX) + { + NOT (ok) ; + } + else + { + OK (ok) ; + } + A->z = Az ; + + Lp = L2->p ; + Li = L2->i ; + Lx = L2->x ; + Lnz = L2->nz ; + Lnext = L2->next ; + Lprev = L2->prev ; + + OK (Lp [0] == 0) ; + + L2->p = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no p", cm) ; NOT (ok) ; + L2->p = Lp ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + L2->i = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no i", cm) ; NOT (ok) ; + L2->i = Li ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + L2->x = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no x", cm) ; NOT (ok) ; + L2->x = Lx ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + L2->nz = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no nz", cm) ; NOT (ok) ; + L2->nz = Lnz ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + L2->next = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no next", cm) ; NOT (ok) ; + L2->next = Lnext ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + L2->prev = NULL ; + ok = CHOLMOD(print_factor)(L2, "L no prev", cm) ; NOT (ok) ; + L2->prev = Lprev ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + if (nrow > 0) + { + p = Lp [0] ; + Lp [0] = -1 ; + ok = CHOLMOD(print_factor)(L2, "Lp bad", cm) ; NOT (ok) ; + Lp [0] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Li [0] ; + Li [0] = -1 ; + ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; + Li [0] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Lnz [0] ; + Lnz [0] = -1 ; + ok = CHOLMOD(print_factor)(L2, "Lnz bad", cm) ; NOT (ok) ; + Lnz [0] = p ; + } + + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + OK (Lnz != NULL) ; + + if (nrow > 0 && Lnz [0] > 3) + { + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + p = Li [1] ; + Li [1] = nrow ; + ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; + Li [1] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK again", cm) ; OK (ok) ; + + p = Li [2] ; + Li [2] = Li [1] ; + ok = CHOLMOD(print_factor)(L2, "Li bad", cm) ; NOT (ok) ; + Li [2] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + } + + // check LDL' dynamic link list + ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, + FALSE, L2, cm) ; + OK (ok) ; + + ok = CHOLMOD(print_factor)(L2, "L2 OK", cm) ; OK (ok) ; + OK (L2->xtype != CHOLMOD_PATTERN && !(L2->is_ll) && !(L2->is_super)) ; + + // cannot do a supernodal factorization on a dynamic LDL' factor + ok = CHOLMOD(super_numeric)(AT, NULL, Zero, L2, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(I1, NULL, Zero, L2, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(I1, I1, Zero, L2, cm) ; NOT (ok) ; + + G = CHOLMOD(copy)(I1, 1, 0, cm) ; OKP (G) ; + ok = CHOLMOD(super_numeric)(G, NULL, Zero, L2, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&G, cm) ; OK (ok) ; + + G = CHOLMOD(copy)(I1, -1, 0, cm) ; OKP (G) ; + ok = CHOLMOD(super_numeric)(G, NULL, Zero, L2, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&G, cm) ; OK (ok) ; + + ok = CHOLMOD(super_numeric)(AT, I1, Zero, L2, cm) ; NOT (ok) ; + W = CHOLMOD(zeros)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (W) ; + X = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (X) ; + ok = CHOLMOD(super_lsolve)(L2, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve)(L2, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(free_dense)(&W, cm) ; OK (ok) ; + ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; + + Lnext = L2->next ; + Lprev = L2->prev ; + + if (nrow > 3) + { + + p = Lnext [nrow+1] ; + Lnext [nrow+1] = -1 ; + ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; + Lnext [nrow+1] = -p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Lnext [2] ; + Lnext [2] = 2 ; + ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; + Lnext [2] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Lnext [2] ; + Lnext [2] = -1 ; + ok = CHOLMOD(print_factor)(L2, "Lnext bad", cm) ; NOT (ok) ; + Lnext [2] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Lprev [2] ; + Lprev [2] = -9 ; + ok = CHOLMOD(print_factor)(L2, "Lprev bad", cm) ; NOT (ok) ; + Lprev [2] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + p = Lnext [nrow] ; + Lnext [nrow] = 0 ; + ok = CHOLMOD(print_factor)(L2, "Lnext/prev bad", cm) ; NOT (ok) ; + Lnext [nrow] = p ; + ok = CHOLMOD(print_factor)(L2, "L OK", cm) ; OK (ok) ; + + // make a non-monotonic copy of L2 and then mangle it + L6 = CHOLMOD(copy_factor)(L2, cm) ; + ok = CHOLMOD(reallocate_column)(0, nrow, L6, cm) ; + if (ok && !(L6->is_monotonic)) + { + ok = CHOLMOD(print_factor)(L6, "L6 monotonic OK ", cm) ; OK (ok) ; + L6->is_monotonic = TRUE ; + ok = CHOLMOD(print_factor)(L6, "L6 monotonic bad", cm) ; NOT (ok) ; + } + CHOLMOD(free_factor)(&L6, cm) ; + } + + + L6 = CHOLMOD(copy_factor)(L, cm) ; OKP (L6) ; + I = CHOLMOD(speye)(nrow, nrow, L->xtype + DTYPE, cm) ; + OKP (I) ; + int i3_xtype = (I->xtype == CHOLMOD_REAL) ? CHOLMOD_COMPLEX : CHOLMOD_REAL ; + I3 = CHOLMOD(speye)(nrow, nrow, i3_xtype + DTYPE, cm) ; + OKP (I3) ; + + ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; OK (ok) ; + ok = CHOLMOD(super_numeric)(I, I3, beta, L6, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(I, Abad2, beta, L6, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(I, I, beta, Lbad, cm) ; NOT (ok) ; + I->stype = -1 ; + ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; OK (ok) ; + ok = CHOLMOD(super_numeric)(I, NULL, beta, L6, cm) ; OK (ok) ; + I3->stype = -1 ; + + cm->print = 4 ; + CHOLMOD(print_sparse)(I3, "I3", cm) ; + CHOLMOD(print_factor)(L6, "L6", cm) ; + cm->print = psave ; + + ok = CHOLMOD(super_numeric)(I3, NULL, beta, L6, cm) ; NOT (ok) ; + CHOLMOD(free_sparse)(&I, cm) ; + I = CHOLMOD(speye)(nrow+1, nrow+1, L->xtype + DTYPE, cm) ; + OKP (I) ; + I->stype = -1 ; + ok = CHOLMOD(super_numeric)(I, I, beta, L6, cm) ; NOT (ok) ; + + + CHOLMOD(free_sparse)(&I, cm) ; + CHOLMOD(free_sparse)(&I3, cm) ; + ok = CHOLMOD(free_factor)(&L6, cm) ; OK (ok) ; + + // check the supernodal L + Ls = L->s ; + Lpi = L->pi ; + Lpx = L->px ; + Super = L->super ; + Lx = L->x ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + L->s = NULL ; + ok = CHOLMOD(print_factor)(L, "L no s", cm) ; NOT (ok) ; + L->s = Ls ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + L->pi = NULL ; + ok = CHOLMOD(print_factor)(L, "L no pi", cm) ; NOT (ok) ; + L->pi = Lpi ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + L->px = NULL ; + ok = CHOLMOD(print_factor)(L, "L no px", cm) ; NOT (ok) ; + L->px = Lpx ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + L->super = NULL ; + ok = CHOLMOD(print_factor)(L, "L no super", cm) ; NOT (ok) ; + L->super = Super ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + + L->x = NULL ; + ok = CHOLMOD(print_factor)(L, "L no x", cm) ; NOT (ok) ; + L->x = Lx ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + p = Ls [0] ; + Ls [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L bad s", cm) ; NOT (ok) ; + Ls [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + p = Lpi [0] ; + Lpi [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L bad pi", cm) ; NOT (ok) ; + Lpi [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + p = Lpx [0] ; + Lpx [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L bad px", cm) ; NOT (ok) ; + Lpx [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + if (nrow > 0) + { + p = Super [0] ; + Super [0] = -1 ; + ok = CHOLMOD(print_factor)(L, "L bad super", cm) ; NOT (ok) ; + Super [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + + p = Ls [0] ; + Ls [0] = 42 ; + ok = CHOLMOD(print_factor)(L, "L bad s", cm) ; NOT (ok) ; + Ls [0] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + } + + if (nrow > 0 && Lpi [1] - Lpi [0] > 3) + { + p = Ls [2] ; + Ls [2] = Ls [1] ; + ok = CHOLMOD(print_factor)(L, "L unsorted s", cm) ; NOT (ok) ; + Ls [2] = p ; + ok = CHOLMOD(print_factor)(L, "L OK", cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // Cholesky + //-------------------------------------------------------------------------- + + // test the supernodal symbolic L + L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; + ok = CHOLMOD(change_factor)(CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, + L3, cm) ; + OK (ok) ; + + Ls = L3->s ; + Lpi = L3->pi ; + Super = L3->super ; + + if (nrow > 0) + { + p = Ls [0] ; + Ls [0] = 42 ; + ok = CHOLMOD(print_factor)(L3, "Lsym bad s", cm) ; NOT (ok) ; + Ls [0] = p ; + ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; + } + + if (nrow > 0 && Lpi [1] - Lpi [0] > 3) + { + p = Ls [2] ; + Ls [2] = Ls [1] ; + ok = CHOLMOD(print_factor)(L3, "Lsym unsorted s", cm) ; NOT (ok) ; + Ls [2] = p ; + ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; + } + + if (nrow > 0 && L->nsuper > 0) + { + Int nscol = Super [1] ; + Int nsrow = Lpi [1] - Lpi [0] ; + if (nsrow > nscol + 1) + { + p = Ls [nscol] ; + Ls [nscol] = Ls [nscol+1] ; + ok = CHOLMOD(print_factor)(L3, "Lsym unsorted s2", cm) ; NOT (ok) ; + Ls [nscol] = p ; + ok = CHOLMOD(print_factor)(L3, "Lsym OK", cm) ; OK (ok) ; + } + } + CHOLMOD(free_factor)(&L3, cm) ; + + // (re)factorize as LL' + L5 = CHOLMOD(copy_factor)(L, cm) ; // [ + OKP (L5) ; + + ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL + DTYPE, NULL, cm) ; + NOT (ok) ; + + L3 = CHOLMOD(copy_factor)(L, cm) ; OKP (L3) ; + CHOLMOD(print_factor)(L3, "L3 before factorize", cm) ; + ok = CHOLMOD(change_factor)(L3->xtype, TRUE, FALSE, TRUE, TRUE, L3, cm) ; + OK (ok) ; + + Acopy = CHOLMOD(copy_sparse)(A, cm) ; // [ + CHOLMOD(sparse_xtype)(L3->xtype + DTYPE, Acopy, cm) ; + + CHOLMOD(print_sparse)(Acopy, "Acopy for factorize", cm) ; + + ok = CHOLMOD(factorize)(Acopy, L3, cm) ; + OK (ok || cm->status >= CHOLMOD_OK) ; + ok = CHOLMOD(free_factor)(&L3, cm) ; OK (ok) ; + + CHOLMOD(print_sparse)(A, "A for factorize", cm) ; + CHOLMOD(print_factor)(L3, "L3 for factorize", cm) ; + + // refactor, but with wrong-sized A + ok = CHOLMOD(print_sparse)(I1, "I1", cm) ; OK (ok) ; + ok = CHOLMOD(factorize)(I1, L, cm) ; NOT (ok) ; + ok = CHOLMOD(factorize)(Abad2, L, cm) ; NOT (ok) ; + C = CHOLMOD(transpose)(I1, 0, cm) ; OKP (C) ; + ok = CHOLMOD(print_sparse)(C, "C = I1'", cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + ok = CHOLMOD(print_factor)(L, "L OK ", cm) ; OK (ok) ; + + // refactor, with invalid A (NULL, or symmetric but not square) + ok = CHOLMOD(print_sparse)(Abad, "Abad", cm) ; NOT (ok) ; + ok = CHOLMOD(factorize)(Abad, L, cm) ; NOT (ok) ; + + // refactorize supernodal LL' + printf ("refactorize here\n") ; + ok = CHOLMOD(print_sparse)(Acopy, "Acopy refactorize", cm) ; OK (ok) ; + ok = CHOLMOD(print_factor)(L, "L for refactorize", cm) ; OK (ok) ; + + printf ("L->xtype for refactorize %d\n", L->xtype) ; + ok = CHOLMOD(factorize)(Acopy, L, cm) ; + OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; + ok = CHOLMOD(print_factor)(L, "L ok, here", cm) ; OK (ok) ; + + ok = CHOLMOD(print_sparse)(Acopy, "Acopy ok, here2::", cm) ; OK (ok) ; + ok = CHOLMOD(factorize)(Acopy, L, cm) ; + OK (ok || cm->status == CHOLMOD_NOT_POSDEF) ; + ok = CHOLMOD(print_factor)(L, "L ok, here2", cm) ; OK (ok) ; + + // solve + B = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (B) ; + X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; OKP (X) ; + ok = CHOLMOD(print_dense)(X, "X :: good", cm) ; OK (ok) ; + ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; + + X = CHOLMOD(solve)(-1, L, B, cm) ; NOP (X) ; + ok = CHOLMOD(free_dense)(&B, cm) ; OK (ok) ; + + B = CHOLMOD(zeros)(nrow+1, 0, CHOLMOD_REAL + DTYPE, cm) ; + OKP (B) ; + X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; NOP (X) ; + + B->xtype = 0 ; + X = CHOLMOD(solve)(CHOLMOD_A, L, B, cm) ; NOP (X) ; + B->xtype = CHOLMOD_REAL ; + ok = CHOLMOD(free_dense)(&B, cm) ; OK (ok) ; + + rcond = CHOLMOD(rcond) (L, cm) ; + printf ("rcond for sparse solve is %g\n", rcond) ; + #ifdef DOUBLE + bool rcond_ok = rcond > 1e-6 ; + #else + bool rcond_ok = rcond > 1e-3 ; + #endif + + // sparse solve + if (nrow < 100 && A->stype != 0 && rcond_ok) + { + // solve A*C=I, so C should equal A inverse + I = CHOLMOD(speye)(nrow, nrow, CHOLMOD_REAL + DTYPE, cm) ; + OKP (I) ; + C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; OKP (C) ; + // compute norm of A*C-I + if (xtype == CHOLMOD_REAL) + { + E = CHOLMOD(ssmult)(A, C, 0, TRUE, FALSE, cm) ; OKP (E) ; + F = CHOLMOD(add)(E, I, minusone, one, 1, false, cm) ; OKP (F) ; + ok = CHOLMOD(print_sparse)(F, "A*inv(A)-I", cm) ; OK (ok) ; + r = CHOLMOD(norm_sparse)(F, 1, cm) ; + OK (! (r < 0)) ; + MAXERR (maxerr, r, 1) ; + ok = CHOLMOD(free_sparse)(&E, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(&F, cm) ; OK (ok) ; + } + CHOLMOD(free_sparse)(&C, cm) ; + + // check error cases for sparse solve + C = CHOLMOD(spsolve)(CHOLMOD_A, NULL, I, cm) ; NOP (C) ; + C = CHOLMOD(spsolve)(CHOLMOD_A, Lbad, I, cm) ; NOP (C) ; + C = CHOLMOD(spsolve)(CHOLMOD_A, L, NULL, cm) ; NOP (C) ; + I->xtype = 0 ; + C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; + I->xtype = CHOLMOD_REAL ; + I->stype = -1 ; + C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; + ok = CHOLMOD(free_sparse)(&I, cm) ; OK (ok) ; + I = CHOLMOD(speye)(nrow+1, nrow+1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (I) ; + C = CHOLMOD(spsolve)(CHOLMOD_A, L, I, cm) ; NOP (C) ; + ok = CHOLMOD(free_sparse)(&I, cm) ; OK (ok) ; + } + + // resymbol + ok = CHOLMOD(resymbol)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, FALSE, L, cm) ; + OK (ok) ; + ok = CHOLMOD(resymbol)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(I1, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + + ok = CHOLMOD(change_factor)(L->xtype, FALSE, FALSE, FALSE, FALSE, Lbad, cm); + NOT (ok) ; + + ok = CHOLMOD(resymbol_noperm)(Acopy, NULL, 0, TRUE, L2, cm) ; + if (Acopy->stype <= 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + + ok = CHOLMOD(resymbol_noperm)(Abad2, NULL, 0, TRUE, L2, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol)(Abad2, NULL, 0, TRUE, L2, cm) ; NOT (ok) ; + + ok = CHOLMOD(resymbol_noperm)(Acopy, NULL, 0, TRUE, NULL, cm) ; NOT (ok) ; + + printf ("resymbol, no pack:\n") ; + if (L2 != NULL && L2->xtype == CHOLMOD_COMPLEX) + { + L3 = CHOLMOD(copy_factor)(L2, cm) ; + OKP (L3) ; + ok = CHOLMOD(factor_xtype)(CHOLMOD_ZOMPLEX + L2->dtype, L3, cm) ; + OK (ok) ; + ok = CHOLMOD(print_factor) (L3, "L3 before zomplex resymbol", cm) ; + OK (ok) ; + ok = CHOLMOD(resymbol)(Acopy, NULL, 0, false, L3, cm) ; + OK (ok) ; + ok = CHOLMOD(print_factor) (L3, "L3: zomplex resymbol, no pack", cm) ; + OK (ok) ; + ok = CHOLMOD(free_factor) (&L3, cm) ; + OK (ok) ; + } + ok = CHOLMOD(resymbol)(Acopy, NULL, 0, false, L2, cm) ; + OK (ok) ; + + if (ncol > 0) + { + ok = CHOLMOD(print_perm)(fsetbad, ncol, ncol, "bad fset", cm) ; + NOT (ok) ; + } + + if (ncol > 1) + { + ok = CHOLMOD(resymbol)(Acopy, fsetok, ncol/2, TRUE, L2, cm) ; OK (ok) ; + ok = CHOLMOD(resymbol)(Acopy, fsetbad, ncol/2, TRUE, L2, cm) ; + if (Acopy->stype) + { + // fset is ignored + OK (ok) ; + } + else + { + NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(Acopy, fsetbad, ncol/2, TRUE, L2, cm); + NOT (ok) ; + } + Acopy->sorted = FALSE ; + ok = CHOLMOD(resymbol)(Acopy, fsetok, ncol/2, TRUE, L2, cm) ; + OK (ok) ; + Acopy->sorted = TRUE ; + } + + cm->print = 4 ; + gsave0 = cm->grow0 ; + gsave1 = cm->grow1 ; + gsave2 = cm->grow2 ; + + // reallocate column + L4 = NULL ; + if (nrow > 0) + { + ok = CHOLMOD(print_factor)(L, "L ok, for colrealloc", cm) ; OK (ok) ; + L4 = CHOLMOD(copy_factor)(L, cm) ; + ok = CHOLMOD(print_factor)(L4, "L4 ok, for colrealloc", cm) ; OK (ok) ; + OK (nrow == (Int)(L->n)) ; + ok = CHOLMOD(reallocate_column)(nrow, 1, L4, cm) ; NOT (ok) ; + ok = CHOLMOD(reallocate_column)(nrow-1, 10, L4, cm) ; OK (ok) ; + + cm->grow0 = 2e10 ; + cm->grow1 = 2 ; + + // this may or may not fail + ok = CHOLMOD(reallocate_column)(0, 10, L4, cm) ; + CHOLMOD(print_common)("32:cm OK or too large", cm) ; + ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; + } + + cm->grow0 = gsave0 ; + cm->grow1 = gsave1 ; + cm->grow2 = gsave2 ; + + if (ok && nrow > 2) + { + L4 = CHOLMOD(copy_factor)(L, cm) ; + ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L4, cm) ; OK (ok) ; + + // make it non-monotonic and then monotonic (LDL' unpacked) + ok = CHOLMOD(reallocate_column)(0, nrow-1, L4, cm) ; OK (ok) ; + + // this should be OK for small matrices, but fail for large ones + cm->grow0 = nrow ; + cm->grow1 = nrow ; + cm->grow2 = nrow ; + ok = CHOLMOD(change_factor)(CHOLMOD_REAL, FALSE, FALSE, FALSE, TRUE, + L4, cm) ; + + ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; + L4 = CHOLMOD(copy_factor)(L, cm) ; + ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L4, cm) ; OK (ok) ; + ok = CHOLMOD(pack_factor)(L4, cm) ; OK (ok) ; + + // now try to make L4 really huge + + if (ok && !(L->is_super) && L->xtype != CHOLMOD_PATTERN) + { + + cm->grow0 = gsave0 ; + cm->grow1 = gsave1 ; + cm->grow2 = gsave2 ; + + ok = CHOLMOD(reallocate_column)(0, nrow-1, L4, cm) ; OK (ok) ; + + cm->grow0 = nrow ; + cm->grow1 = nrow ; + cm->grow2 = nrow ; + + // CHOLMOD(print_factor) (L4, "L4 for huge, realloced", cm) ; + // printf ("L4 for huge is monotonic: %d\n", L4->is_monotonic) ; + + if (!(L4->is_monotonic)) + { + // printf ("Make L4 really huge: ") ; + ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, FALSE, FALSE, + TRUE, L4, cm) ; + printf ("L4 huge ok: "ID"\n", ok) ; + } + } + ok = CHOLMOD(free_factor)(&L4, cm) ; OK (ok) ; + } + + cm->grow0 = gsave0 ; + cm->grow1 = gsave1 ; + cm->grow2 = gsave2 ; + + cm->print = psave ; + + //-------------------------------------------------------------------------- + // more error tests + //-------------------------------------------------------------------------- + + cm->error_handler = NULL ; + + //-------------------------------------------------------------------------- + // modify (real matrices only) + //-------------------------------------------------------------------------- + + X = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (X) ; + R = CHOLMOD(dense_to_sparse)(X, TRUE, cm) ; // [ + OKP (R) ; + + if (isreal) + { + C = CHOLMOD(speye)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(updown)(+1, C, L, cm) ; OK (ok) ; + X1 = CHOLMOD(ones)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + B1 = CHOLMOD(eye)(nrow, 1, CHOLMOD_REAL + DTYPE, cm) ; + ok = CHOLMOD(updown_solve)(+1, C, L, X1, B1, cm) ; OK (ok) ; + B1->xtype = -999 ; + ok = CHOLMOD(updown_solve)(+1, C, L, X1, B1, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd_solve)(0, R, beta, L, X1, B1, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel_solve)(0, R, beta, L, X1, B1, cm) ; NOT (ok) ; + B1->xtype = CHOLMOD_REAL ; + CHOLMOD(free_dense)(&B1, cm) ; + B2 = CHOLMOD(ones)(nrow, 2, CHOLMOD_REAL + DTYPE, cm) ; + ok = CHOLMOD(updown_solve)(+1, C, L, X1, B2, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd_solve)(0, R, beta, L, X1, B2, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel_solve)(0, R, beta, L, X1, B2, cm) ; NOT (ok) ; + + CHOLMOD(free_dense)(&B2, cm) ; + CHOLMOD(free_dense)(&X1, cm) ; + ok = CHOLMOD(updown)(+1, Abad2, L, cm) ; NOT (ok) ; + + ok = CHOLMOD(updown)(+1, C, NULL, cm) ; NOT (ok) ; + + C->sorted = FALSE ; + ok = CHOLMOD(updown)(+1, C, L, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + ok = CHOLMOD(updown)(+1, NULL, L, cm) ; NOT (ok) ; + + if (nrow > 0) + { + C = CHOLMOD(speye)(nrow-1, 1, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(updown)(+1, C, L, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + + C = CHOLMOD(speye)(nrow, 0, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(updown)(+1, C, L, cm) ; OK (ok) ; + + ok = CHOLMOD(rowdel)(0, C, L, cm) ; NOT (ok) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // rowfac, rcond + //-------------------------------------------------------------------------- + + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->postorder = FALSE ; + + cm->print = 5 ; + cm->final_ll = TRUE ; + for (xtype2 = CHOLMOD_REAL ; xtype2 <= CHOLMOD_ZOMPLEX ; xtype2++) + { + cm->supernodal = CHOLMOD_SIMPLICIAL ; + + // factor a singular matrix (C=LL') + printf ("start singular LL'\n") ; + XX = CHOLMOD(ones)(4, 4, xtype2 + DTYPE, cm) ; + OKP (X) ; + C = CHOLMOD(dense_to_sparse)(XX, TRUE, cm) ; OKP (C) ; + CHOLMOD(free_dense)(&XX, cm) ; + C->stype = 1 ; + CHOLMOD(print_sparse)(C, "C ones", cm) ; + L6 = CHOLMOD(analyze)(C, cm) ; OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; + printf ("status %d\n", cm->status) ; + ok1 = (cm->status == CHOLMOD_NOT_POSDEF) ; + ok = CHOLMOD(print_factor)(L6, "L6 singular", cm) ; OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond == 0) ; + + // now make C positive definite + CHOLMOD(free_sparse)(&C, cm) ; + XX = CHOLMOD(ones)(4, 4, xtype2 + DTYPE, cm) ; + OKP (X) ; + x = XX->x ; + for (i = 0 ; i < 4 ; i++) + { + if (xtype2 == CHOLMOD_REAL || xtype2 == CHOLMOD_ZOMPLEX) + { + x [i + 4*i] = 42 ; + } + else // complex + { + x [2*(i + 4*i)] = 42 ; + } + } + C = CHOLMOD(dense_to_sparse)(XX, TRUE, cm) ; OKP (C) ; + CHOLMOD(free_dense)(&XX, cm) ; + C->stype = 1 ; + CHOLMOD(print_sparse)(C, "C ok", cm) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; OK (ok) ; + ok1 = (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(print_factor)(L6, "L6 ok", cm) ; OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; OK (rcond > 0) ; + + //---------------------------------------------------------------------- + // generate intentional nan's, to test the nan-handling of cholmod_rcond + //---------------------------------------------------------------------- + + if (do_nantests) + { + xnan = xnan/xnan ; + + // C(2,2) = nan + x = C->x ; + i = 2 ; + if (xtype2 == CHOLMOD_REAL || xtype2 == CHOLMOD_ZOMPLEX) + { + x [i + 4*i] = xnan ; + } + else // complex + { + x [2*(i + 4*i)] = xnan ; + } + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + ok1 = (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(print_factor)(L6, "L6 nan2", cm) ; + OK (ok) ; + printf ("rcond %g\n", rcond) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + CHOLMOD(free_factor)(&L6, cm) ; + + // C(2,2) = nan, LDL' + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_ll = TRUE ; + L6 = CHOLMOD(analyze)(C, cm) ; + OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + ok1 = (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(print_factor)(L6, "LDL6 nan2", cm) ; + OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + CHOLMOD(free_factor)(&L6, cm) ; + + // C(2,2) = nan, supernodal + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_ll = FALSE ; + L6 = CHOLMOD(analyze)(C, cm) ; + OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + + // sometimes LAPACK says NaN is not pos.def, sometimes it doesn't + ok1 = (cm->status == CHOLMOD_OK || + cm->status == CHOLMOD_NOT_POSDEF) ; + ok = CHOLMOD(print_factor)(L6, "L6 supernan2", cm) ; + OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + CHOLMOD(free_factor)(&L6, cm) ; + + // C(0,0) = nan + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_ll = FALSE ; + x [0] = xnan ; + L6 = CHOLMOD(analyze)(C, cm) ; + OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + ok1 = (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(print_factor)(L6, "L6 nan0", cm) ; + OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + CHOLMOD(free_factor)(&L6, cm) ; + + // C(0,0) = nan, LDL' + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_ll = TRUE ; + L6 = CHOLMOD(analyze)(C, cm) ; + OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + ok1 = (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(print_factor)(L6, "LDL6 nan0", cm) ; + OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + CHOLMOD(free_factor)(&L6, cm) ; + + // C(0,0) = nan, supernodal + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_ll = FALSE ; + L6 = CHOLMOD(analyze)(C, cm) ; + OKP (L6) ; + ok = CHOLMOD(factorize)(C, L6, cm) ; + OK (ok) ; + // sometimes LAPACK says NaN is not pos.def, sometimes it doesn't... + ok1 = (cm->status == CHOLMOD_OK || + cm->status == CHOLMOD_NOT_POSDEF) ; + ok = CHOLMOD(print_factor)(L6, "L6 supernan0", cm) ; + OK (ok) ; + OK (ok1) ; + rcond = CHOLMOD(rcond) (L6, cm) ; + OK (rcond == 0) ; + } + + CHOLMOD(free_factor)(&L6, cm) ; + CHOLMOD(free_sparse)(&C, cm) ; + } + cm->supernodal = CHOLMOD_AUTO ; + cm->final_ll = FALSE ; + cm->print = psave ; + + //-------------------------------------------------------------------------- + // refactorize simplicial LDL' + //-------------------------------------------------------------------------- + + if (nrow < NLARGE) + { + L7 = CHOLMOD(analyze) (A, cm) ; OKP (L7) ; + ok = CHOLMOD(factorize) (A, L7, cm) ; OK (ok) ; + ok = CHOLMOD(factorize) (A, L7, cm) ; OK (ok) ; + B7 = CHOLMOD(ones) (nrow, 1, xtype + DTYPE, cm) ; + OKP (B7) ; + X7 = CHOLMOD(solve) (CHOLMOD_A, L7, B7, cm) ; OKP (X7) ; + ok = CHOLMOD(free_dense) (&X7, cm) ; OK (ok) ; + ok = CHOLMOD(free_dense) (&B7, cm) ; OK (ok) ; + if (A->stype > 0) + { + ok = CHOLMOD(rowfac) (A, NULL, zero, 0, nrow, L7, cm) ; OK (ok) ; + ok = CHOLMOD(rowfac) (A, NULL, zero, 0, nrow, L7, cm) ; OK (ok) ; + // printf ("I7 :::\n") ; + I7 = CHOLMOD(speye) (nrow+1, 1, xtype + DTYPE, cm) ; + OKP (I7) ; + I7->stype = 1 ; + ok = CHOLMOD(rowfac) (I7,NULL, zero, 0, nrow, L7, cm) ; NOT(ok) ; + // printf ("I7 ::: done\n") ; + CHOLMOD(free_sparse) (&I7, cm) ; + } + ok = CHOLMOD(free_factor) (&L7, cm) ; OK (ok) ; + } + + cm->nmethods = 0 ; // restore defaults + cm->method [0].ordering = CHOLMOD_GIVEN ; + cm->postorder = TRUE ; + + //-------------------------------------------------------------------------- + // row subtree + //-------------------------------------------------------------------------- + + i = nrow / 2 ; + + C = CHOLMOD(allocate_sparse)(nrow, 1, nrow, TRUE, TRUE, 0, + CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + C2 = CHOLMOD(allocate_sparse)(nrow, 1, nrow, TRUE, TRUE, 0, + CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(row_subtree)(NULL, NULL, i, Parent, C, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(NULL, NULL, 0, i, L, C2, cm) ; NOT (ok) ; + + if (A->stype == 0 && nrow > 0 && AT != NULL) + { + ok = CHOLMOD(row_subtree)(A, AT, i, Parent, C, cm) ; OK (ok) ; + + ATp = AT->p ; + ATi = AT->i ; + fnz = ATp [i+1] - ATp [i] ; + ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, C2, cm) ; + // if (i < ncol) { OK (ok) ; } else { NOT (ok) ; } + OK (ok) ; + + ok = CHOLMOD(row_lsubtree)(Abad2, ATi, fnz, i, L, C2, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, NULL, fnz, i, L, C2, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, Abad2, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, NULL, C2, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, nrow+1, L, C2, cm) ;NOT (ok) ; + + ok = CHOLMOD(row_subtree)(Abad2, AT, i, Parent, C, cm) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, Abad2, i, Parent, C, cm) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, AT, i, Parent, Abad2, cm) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, C, cm) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, AT, nrow+1, Parent, C, cm) ; NOT (ok) ; + } + else + { + ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, C, cm) ; + if (A->stype == 1 && nrow > 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + } + + ok = CHOLMOD(row_subtree)(A, NULL, i, Parent, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(row_subtree)(A, NULL, i, NULL, C, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree)(A, NULL, 0, i, L, NULL, cm) ; NOT (ok) ; + + if (A->stype == 1 && nrow > 0) + { + // add extra entries in the (ignored) lower triangular part to AA + if (!(A->sorted)) + { + ok = CHOLMOD(sort)(A, cm) ; OK (ok) ; + } + AA = CHOLMOD(copy)(A, 0, 0, cm) ; + OK (AA->sorted) ; + AA->stype = 1 ; + ok = CHOLMOD(row_subtree)(AA, NULL, i, Parent, C, cm) ; OK (ok) ; + ok = CHOLMOD(row_lsubtree)(AA, NULL, 0, i, L, C2, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(&AA, cm) ; OK (ok) ; + } + + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(&C2, cm) ; OK (ok) ; + + C = CHOLMOD(speye)(nrow, 0, CHOLMOD_REAL + DTYPE, cm) ; + OKP (C) ; + if (A->stype == 0 && AT != NULL && nrow > 0) + { + ok = CHOLMOD(row_subtree)(A, AT, i, Parent, C, cm) ; NOT (ok) ; + + ATp = AT->p ; + ATi = AT->i ; + fnz = ATp [i+1] - ATp [i] ; + ok = CHOLMOD(row_lsubtree)(A, ATi, fnz, i, L, C, cm) ; NOT (ok) ; + } + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + L6 = CHOLMOD(alloc_factor)(nrow, DTYPE, cm) ; + OKP (L6) ; + if (A->stype == 0 && nrow > 2) + { + ok = CHOLMOD(rowfac)(A, AT, beta, 0, 1, L6, cm) ; OK (ok) ; + OK (cm->status == CHOLMOD_OK) ; + ok = CHOLMOD(rowfac)(A, NULL, beta, 1, 2, L6, cm) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(A, AT, beta, 1, 2, L6, cm) ; OK (ok) ; + ok = CHOLMOD(rowfac)(Abad2, AT, beta, 1, 2, L6, cm) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(A, Abad2, beta, 1, 2, L6, cm) ; NOT (ok) ; + } + ok = CHOLMOD(free_factor)(&L6, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // horzcat, vertcat + //-------------------------------------------------------------------------- + + if (A->nrow != A->ncol) + { + C = CHOLMOD(horzcat)(A, AT, TRUE, cm) ; NOP (C) ; + C = CHOLMOD(vertcat)(A, AT, TRUE, cm) ; NOP (C) ; + } + + C = CHOLMOD(vertcat)(A, NULL, TRUE, cm) ; NOP (C) ; + C = CHOLMOD(vertcat)(NULL, AT, TRUE, cm) ; NOP (C) ; + C = CHOLMOD(horzcat)(A, NULL, TRUE, cm) ; NOP (C) ; + C = CHOLMOD(horzcat)(NULL, AT, TRUE, cm) ; NOP (C) ; + + //-------------------------------------------------------------------------- + // print_triplet + //-------------------------------------------------------------------------- + + cm->print = 4 ; + ok = CHOLMOD(print_triplet)(Tok, "T ok", cm) ; OK (ok) ; + T = CHOLMOD(copy_triplet)(Tok, cm) ; // [ + OKP (T) ; + + Tz = T->z ; + T->z = NULL ; + ok = CHOLMOD(print_triplet)(T, "T no z", cm) ; + if (T->xtype == CHOLMOD_ZOMPLEX) + { + NOT (ok) ; + } + else + { + OK (ok) ; + } + T->z = Tz ; + cm->print = psave ; + + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + ok = CHOLMOD(print_triplet)(NULL, "null", cm) ; NOT (ok) ; + + p = T->nzmax ; + T->nzmax = T->nnz - 1 ; + ok = CHOLMOD(print_triplet)(T, "T nzmax too small", cm) ; NOT (ok) ; + T->nzmax = p ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + T->itype = -1 ; + ok = CHOLMOD(print_triplet)(T, "T itype bad", cm) ; NOT (ok) ; + T->itype = cm->itype ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + cm->print = 4 ; + #if defined ( CHOLMOD_INT64 ) + T->itype = CHOLMOD_INT ; + #else + T->itype = CHOLMOD_LONG ; + #endif + ok = CHOLMOD(print_triplet)(T, "T bad itype", cm) ; NOT (ok) ; + T->itype = cm->itype ; + cm->print = psave ; + + Txtype = T->xtype ; + T->xtype = -1 ; + ok = CHOLMOD(print_triplet)(T, "T xtype bad", cm) ; NOT (ok) ; + + T->xtype = Txtype ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + Tj = T->j ; + Ti = T->i ; + Tx = T->x ; + + T->j = NULL ; + ok = CHOLMOD(print_triplet)(T, "Tj null", cm) ; NOT (ok) ; + T->j = Tj ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + T->i = NULL ; + ok = CHOLMOD(print_triplet)(T, "Ti null", cm) ; NOT (ok) ; + T->i = Ti ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + T->x = NULL ; + ok = CHOLMOD(print_triplet)(T, "Tx null", cm) ; NOT (ok) ; + T->x = Tx ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + if (T->nnz > 0) + { + p = Ti [0] ; + Ti [0] = -1 ; + ok = CHOLMOD(print_triplet)(T, "Ti bad", cm) ; NOT (ok) ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; + Ti [0] = p ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + p = Tj [0] ; + Tj [0] = -1 ; + ok = CHOLMOD(print_triplet)(T, "Tj bad", cm) ; NOT (ok) ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; + Tj [0] = p ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + } + + cm->print = 4 ; + CHOLMOD(triplet_xtype)(CHOLMOD_PATTERN + DTYPE, T, cm) ; + ok = CHOLMOD(print_triplet)(T, "T pattern ok", cm) ; OK (ok) ; + cm->print = psave ; + + //-------------------------------------------------------------------------- + // triplet, realloc_multiple + //-------------------------------------------------------------------------- + + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + OK (cm->status == CHOLMOD_OK) ; + + cm->print = 4 ; + if (T->nrow != T->ncol) + { + OK (T->stype == 0) ; + + CHOLMOD(print_triplet)(T, "T ok", cm) ; + + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; + CHOLMOD(print_sparse)(C, "C ok", cm) ; + OKP (C) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + Ti = T->i ; + T->i = NULL ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; + if (T->nnz == 0) + { + OKP (C) ; + ASSERT (CHOLMOD(nnz) (C, cm) == 0) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + else + { + NOP (C) ; + } + T->i = Ti ; + + Tj = T->j ; + T->j = NULL ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; + if (T->nnz == 0) + { + OKP (C) ; + ASSERT (CHOLMOD(nnz) (C, cm) == 0) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + else + { + NOP (C) ; + } + T->j = Tj ; + + T->stype = 1 ; + ok = CHOLMOD(print_triplet)(T, "T bad", cm) ; NOT (ok) ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; NOP (C) ; + T->stype = 0 ; + ok = CHOLMOD(print_triplet)(T, "T pattern ok", cm) ; OK (ok) ; + } + OK (cm->status == CHOLMOD_OK) ; + cm->print = psave ; + + ok = CHOLMOD(reallocate_triplet)(1, NULL, cm) ; NOT (ok) ; + + CHOLMOD(print_triplet)(T, "T before realloc", cm) ; + ok = CHOLMOD(reallocate_triplet)(1+(T->nzmax), T, cm) ; OK (ok) ; + CHOLMOD(print_triplet)(T, "T after realloc", cm) ; + + nznew = 10 + T->nzmax ; + pp = NULL ; + + ok = CHOLMOD(realloc_multiple)(SIZE_MAX/2, 2, T->xtype, &(T->i), + &(T->j), &(T->x), &(T->z), &(T->nzmax), cm) ; NOT (ok) ; + + size = 0 ; + ii = NULL ; + jj = NULL ; + xx = NULL ; + ok = CHOLMOD(realloc_multiple)(SIZE_MAX, 2, CHOLMOD_REAL, &ii, &jj, &xx, + NULL, &size, cm) ; NOT (ok) ; + + ok = CHOLMOD(realloc_multiple)(0, 0, CHOLMOD_PATTERN, &ii, &jj, &xx, NULL, + &size, cm) ; OK (ok) ; + + ok = CHOLMOD(realloc_multiple)(0, 0, -1, &ii, &jj, &xx, NULL, + &size, cm) ; NOT (ok) ; + + // change to pattern-only + CHOLMOD(triplet_xtype)(CHOLMOD_PATTERN + DTYPE, T, cm) ; + + ok = CHOLMOD(reallocate_triplet)(1+(T->nzmax), T, cm) ; OK (ok) ; + + ok = CHOLMOD(free_triplet)(&T, cm) ; // ] + OK (ok) ; + + T = CHOLMOD(allocate_triplet)(nrow, ncol, SIZE_MAX, 0, + CHOLMOD_REAL + DTYPE, cm) ; + NOP (T) ; + + T2 = CHOLMOD(allocate_triplet)(4, 4, 8, 0, + CHOLMOD_REAL + DTYPE, cm) ; + OKP (T2) ; + ok = CHOLMOD(reallocate_triplet)(12, T2, cm) ; OK (ok) ; + T = CHOLMOD(copy_triplet)(T2, cm) ; OKP (T) ; + CHOLMOD(free_triplet)(&T, cm) ; + T = CHOLMOD(sparse_to_triplet)(A, cm) ; OKP (T) ; + C = CHOLMOD(triplet_to_sparse)(T, 100, cm) ; OKP (C) ; + CHOLMOD(free_sparse)(&C, cm) ; + CHOLMOD(free_triplet)(&T, cm) ; + + T2->xtype = -1 ; + ok = CHOLMOD(reallocate_triplet)(16, T2, cm) ; NOT (ok) ; + T = CHOLMOD(copy_triplet)(T2, cm) ; NOP (T) ; + C = CHOLMOD(triplet_to_sparse)(T2, 100, cm) ; NOP (C) ; + T2->xtype = CHOLMOD_REAL ; + CHOLMOD(free_triplet)(&T2, cm) ; + + T = CHOLMOD(sparse_to_triplet)(Abad2, cm) ; NOP (T) ; + + for (stype = -1 ; stype <= 1 ; stype++) + { + T = CHOLMOD(allocate_triplet)(4, 4, 16, stype, + CHOLMOD_PATTERN + DTYPE, cm) ; + OKP (T) ; + Ti = T->i ; + Tj = T->j ; + k = 0 ; + for (i = 0 ; i < 4 ; i++) + { + for (j = 0 ; j < 4 ; j++) + { + Ti [k] = i ; + Tj [k] = j ; + k++ ; + } + } + T->nnz = k ; + C = CHOLMOD(triplet_to_sparse)(T, 0, cm) ; + cm->print = 4 ; + printf ("stype "ID"\n", stype) ; + CHOLMOD(print_triplet)(T, "T from triplet", cm) ; + CHOLMOD(print_sparse)(C, "C from triplet", cm) ; + cm->print = psave ; + OKP (C) ; + CHOLMOD(free_sparse)(&C, cm) ; + CHOLMOD(free_triplet)(&T, cm) ; + } + + //-------------------------------------------------------------------------- + // sparse_to_triplet + //-------------------------------------------------------------------------- + + if (A->nrow != A->ncol) + { + OK (A->stype == 0) ; + T = CHOLMOD(sparse_to_triplet)(A, cm) ; OKP (T) ; + ok = CHOLMOD(print_triplet)(T, "T ok", cm) ; OK (ok) ; + + T2 = CHOLMOD(copy_triplet)(NULL, cm) ; NOP (T2) ; + + Ti = T->i ; + T->i = NULL ; + T2 = CHOLMOD(copy_triplet)(T, cm) ; + + if (T->nnz == 0) + { + OKP (T2) ; + } + else + { + NOP (T2) ; + } + T->i = Ti ; + ok = CHOLMOD(free_triplet)(&T2, cm) ; OK (ok) ; + + Tj = T->j ; + T->j = NULL ; + T2 = CHOLMOD(copy_triplet)(T, cm) ; + if (T->nnz == 0) + { + OKP (T2) ; + } + else + { + NOP (T2) ; + } + T->j = Tj ; + ok = CHOLMOD(free_triplet)(&T2, cm) ; OK (ok) ; + + ok = CHOLMOD(free_triplet)(&T, cm) ; OK (ok) ; + A->stype = 1 ; + T = CHOLMOD(sparse_to_triplet)(A, cm) ; NOP (T) ; + A->stype = 0 ; + T = CHOLMOD(sparse_to_triplet)(NULL, cm) ; NOP (T) ; + } + + //-------------------------------------------------------------------------- + // colamd + //-------------------------------------------------------------------------- + + ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(colamd)(NULL, fsetok, fsizeok, TRUE, Pok, cm) ; NOT (ok) ; + + cm->current = 0 ; + + save1 = cm->method [0].prune_dense2 ; + save2 = cm->method [0].ordering ; + save4 = cm->nmethods ; + + cm->method [0].prune_dense2 = 0.5 ; + cm->method [0].ordering = CHOLMOD_COLAMD ; + cm->nmethods = 1 ; + + ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; + if (A->stype == 0) + { + cm->print = 5 ; + ok = CHOLMOD(print_common) ("33:cm colamd dense2", cm) ; + OK (ok) ; + cm->print = psave ; + OK (ok) ; + } + else + { + NOT (ok) ; + } + + cm->method [0].prune_dense2 = save1 ; + cm->method [0].ordering = save2 ; + cm->nmethods = save4 ; + + cm->current = -1 ; + ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; + if (A->stype == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + cm->current = 0 ; + + ok = CHOLMOD(colamd)(Abad2, NULL, 0, TRUE, Pok, cm) ; NOT (ok) ; + + if (ncol > 0) + { + ok = CHOLMOD(colamd)(A, fsetbad, ncol, TRUE, Pok, cm) ; NOT (ok) ; + } + + // mangle the matrix to test integer overflow in colamd + if (A->stype == 0) + { + nzmax = A->nzmax ; + A->nzmax = SIZE_MAX/2 ; + ok = CHOLMOD(colamd)(A, fsetok, fsizeok, TRUE, Pok, cm) ; NOT (ok) ; + A->nzmax = nzmax ; + } + + //-------------------------------------------------------------------------- + // ccolamd/csymamd + //-------------------------------------------------------------------------- + + #ifndef NCAMD + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; + if (A->stype == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + ok = CHOLMOD(ccolamd)(Abad2, NULL, 0, NULL, Pok, cm) ; NOT (ok) ; + + ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; + if (A->nrow == A->ncol) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + ok = CHOLMOD(csymamd)(Abad2, NULL, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(csymamd)(NULL, NULL, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(csymamd)(A, NULL, NULL, cm) ; NOT (ok) ; + + // mangle the matrix to test integer overflow in colamd + if (A->stype == 0) + { + nzmax = A->nzmax ; + A->nzmax = SIZE_MAX/2 ; + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; + A->nzmax = nzmax ; + } + #endif + + //-------------------------------------------------------------------------- + // amd + //-------------------------------------------------------------------------- + + ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // metis + //-------------------------------------------------------------------------- + + #ifndef NPARTITION + // no METIS memory guard + cm->metis_memory = 0 ; + if (A->stype) + { + E = CHOLMOD(copy)(A, 0, -1, cm) ; + } + else + { + E = CHOLMOD(aat)(A, NULL, 0, -1, cm) ; + } + enz = CHOLMOD(nnz)(E, cm) ; + + CHOLMOD(print_sparse)(A, "A for metis", cm) ; + + if (A != NULL && Pok != NULL) + { + ok = CHOLMOD(metis)(A, NULL, 0, TRUE, Pok, cm) ; + + // memory guard triggered + if (nrow > 0) + { + double density ; + + cm->metis_memory = SIZE_MAX ; + ok = CHOLMOD(metis)(A, NULL, 0, FALSE, Pok, cm) ; + OK (ok) ; + // Pok should be identity + for (j = 0 ; j < nrow ; j++) + { + OK (Pok [j] == j) ; + } + + // memory guard triggered + cm->metis_memory = 2 ; + cm->metis_nswitch = 10 ; + + + ok = CHOLMOD(metis)(A, NULL, 0, FALSE, Pok, cm) ; OK (ok) ; + // Pok should be identity if the matrix is dense + density = ((double) enz) / (((double) nrow) * ((double) nrow)) ; + if (nrow > 10 && density > cm->metis_dswitch) + { + for (j = 0 ; j < nrow ; j++) + { + OK (Pok [j] == j) ; + } + } + } + } + + // restore METIS default memory guard + cm->metis_memory = 2 ; + cm->metis_nswitch = 3000 ; + + // check metis bisector error handling + if (E != NULL && enz > 0) + { + Int *Anw, *Aew ; + Anw = CHOLMOD(malloc)(nrow, sizeof (Int), cm) ; + Aew = CHOLMOD(malloc)(MAX (anz,enz), sizeof (Int), cm) ; + for (j = 0 ; j < nrow ; j++) + { + Anw [j] = 1 ; + } + for (j = 0 ; j < enz ; j++) + { + Aew [j] = 1 ; + } + lr = CHOLMOD(metis_bisector)(E, Anw, Aew, Pok, cm) ; + if (E->stype || E->nrow != E->ncol) + { + NOT (lr >= 0) ; + } + else + { + OK (lr >= 0) ; + } + lr = CHOLMOD(metis_bisector)(Abad2, Anw, Aew, Pok, cm) ;NOT (lr >= 0); + lr = CHOLMOD(metis_bisector)(NULL, Anw, Aew, Pok, cm) ; NOT (lr >= 0); + lr = CHOLMOD(metis_bisector)(A, Anw, Aew, NULL, cm) ; NOT (lr >= 0); + + if (A->stype) + { + lr = CHOLMOD(metis_bisector)(A, Anw, Aew, Pok, cm) ; NOT (lr>=0) ; + } + + CHOLMOD(free)(nrow, sizeof (Int), Anw, cm) ; + CHOLMOD(free)(MAX (anz,enz), sizeof (Int), Aew, cm) ; + } + + CHOLMOD(free_sparse)(&E, cm) ; + + CHOLMOD(print_sparse)(Abad, "Abad", cm) ; + lr = CHOLMOD(bisect)(Abad, NULL, 0, TRUE, Partition, cm) ; + if (Abad != NULL && Abad->nrow == 0) + { + OK (lr == 0) ; + } + else + { + NOT (lr >= 0) ; + } + + lr = CHOLMOD(bisect)(A, NULL, 0, TRUE, NULL, cm) ; NOT (lr >= 0); + lr = CHOLMOD(bisect)(NULL, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0); + + lr = CHOLMOD(nested_dissection)(NULL, NULL, 0, Pok, CParent, + Cmember, cm) ; NOT (lr>=0) ; + + lr = CHOLMOD(nested_dissection)(A, NULL, 0, NULL, CParent, + Cmember, cm) ; NOT (lr>=0) ; + + lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, NULL, + Cmember, cm) ; NOT (lr>=0) ; + + lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, CParent, + NULL, cm) ; NOT (lr>=0) ; + + ok = CHOLMOD(metis)(NULL, NULL, 0, TRUE, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(metis)(A, NULL, 0, TRUE, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(metis)(Abad2, NULL, 0, FALSE, Pok, cm) ; NOT (ok) ; + lr = CHOLMOD(bisect)(Abad2, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0); + #endif + + //-------------------------------------------------------------------------- + // etree + //-------------------------------------------------------------------------- + + if (A->stype < 0) + { + ok = CHOLMOD(etree)(A, Parent, cm) ; NOT (ok) ; + } + ok = CHOLMOD(etree)(Abad2, Parent, cm) ; NOT (ok) ; + + //-------------------------------------------------------------------------- + // etree, postorder, rowcolcount + //-------------------------------------------------------------------------- + + if (A->stype == 0 && ncol > 0) + { + AFT = CHOLMOD(ptranspose)(A, 1, NULL, fsetok, fsizeok, cm) ; OKP(AFT); + AF = CHOLMOD(transpose)(AFT, 1, cm) ; OKP(AF); + + ok = CHOLMOD(etree)(NULL, Parent, cm) ; NOT(ok); + ok = CHOLMOD(etree)(AFT, NULL, cm) ; NOT(ok); + ok = CHOLMOD(etree)(AFT, Parent, cm) ; OK (ok); + + lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cm) ; OK (lr>=0) ; + lr = CHOLMOD(postorder)(NULL, nrow, NULL, Post, cm) ; NOT (lr>=0) ; + lr = CHOLMOD(postorder)(Parent, nrow, NULL, NULL, cm) ; NOT (lr>=0) ; + + + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + Post, NULL, ColCount, First, Level, cm) ; OK (ok); + + ok = CHOLMOD(rowcolcounts)(Abad2, fsetok, fsizeok, Parent, + Post, NULL, ColCount, First, Level, cm) ; NOT(ok); + + ok = CHOLMOD(rowcolcounts)(NULL, fsetok, fsizeok, Parent, + Post, NULL, ColCount, First, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, NULL, + Post, NULL, ColCount, First, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + NULL, NULL, ColCount, First, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + Post, NULL, NULL, First, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + Post, NULL, ColCount, NULL, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + Post, NULL, ColCount, First, NULL, cm) ; NOT(ok); + + ok = CHOLMOD(rowcolcounts)(A, fsetbad, ncol, Parent, + Post, NULL, ColCount, First, Level, cm) ; NOT(ok); + ok = CHOLMOD(rowcolcounts)(A, fsetok, fsizeok, Parent, + Post, NULL, ColCount, First, NULL, cm) ; NOT(ok); + + CHOLMOD(free_sparse)(&AF, cm) ; + CHOLMOD(free_sparse)(&AFT, cm) ; + } + + //-------------------------------------------------------------------------- + // norm + //-------------------------------------------------------------------------- + + nm = CHOLMOD(norm_sparse)(A, 2, cm) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_sparse)(Abad, 0, cm) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_sparse)(Abad2, 2, cm) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_dense)(Bok, 3, cm) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_dense)(Bok, 2, cm) ; NOT (nm>=0) ; + nm = CHOLMOD(norm_dense)(Xbad2, 1, cm) ; NOT (nm>=0) ; + + //-------------------------------------------------------------------------- + // copy dense + //-------------------------------------------------------------------------- + + ok = CHOLMOD(copy_dense2)(NULL, Bok, cm) ; NOT (ok) ; + ok = CHOLMOD(copy_dense2)(Bok, NULL, cm) ; NOT (ok) ; + + ok = CHOLMOD(copy_dense2)(Bok, Xbad2, cm) ; NOT (ok) ; + ok = CHOLMOD(copy_dense2)(Xbad2, Xbad2, cm) ; NOT (ok) ; + + if (nrow > 1) + { + + // wrong dimensions + ok = CHOLMOD(copy_dense2)(Two, Bok, cm) ; NOT (ok) ; + + // mangled matrix + Y = CHOLMOD(copy_dense)(Bok, cm) ; OKP (Y) ; + Y->d = 0 ; + ok = CHOLMOD(copy_dense2)(Bok, Y, cm) ; NOT (ok) ; + CHOLMOD(free_dense)(&Y, cm) ; + + Y = CHOLMOD(copy_dense)(Xbad2, cm) ; NOP (Y) ; + Y = CHOLMOD(copy_dense)(NULL, cm) ; NOP (Y) ; + } + + //-------------------------------------------------------------------------- + // complex + //-------------------------------------------------------------------------- + + W = CHOLMOD(eye)(4, 4, CHOLMOD_COMPLEX + DTYPE, cm) ; + OKP (W) ; + ok = CHOLMOD(dense_xtype)(CHOLMOD_PATTERN + DTYPE, W, cm) ; + NOT (ok) ; + ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL + DTYPE, W, cm) ; + OK (ok) ; + ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL + DTYPE, NULL, cm) ; + NOT (ok) ; + k = W->xtype ; + W->xtype = -1 ; + ok = CHOLMOD(dense_xtype)(CHOLMOD_REAL + DTYPE, W, cm) ; + NOT (ok) ; + W->xtype = k ; + ok = CHOLMOD(free_dense)(&W, cm) ; + OK (ok) ; + + C = CHOLMOD(speye)(4, 4, CHOLMOD_COMPLEX + DTYPE, cm) ; + OKP (C) ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX + DTYPE, C, cm) ; + OK (ok) ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_ZOMPLEX + DTYPE, NULL, cm) ; + NOT (ok) ; + T = CHOLMOD(sparse_to_triplet)(C, cm) ; + OKP (T) ; + ok = CHOLMOD(triplet_xtype)(CHOLMOD_ZOMPLEX + DTYPE, T, cm) ; + OK (ok) ; + ok = CHOLMOD(triplet_xtype)(CHOLMOD_ZOMPLEX + DTYPE, NULL, cm) ; + NOT (ok) ; + + k = T->xtype ; + T->xtype = -1 ; + ok = CHOLMOD(triplet_xtype)(CHOLMOD_REAL + DTYPE, T, cm) ; + NOT (ok) ; + T->xtype = k ; + + k = C->xtype ; + C->xtype = -1 ; + ok = CHOLMOD(sparse_xtype)(CHOLMOD_REAL + DTYPE, C, cm) ; + NOT (ok) ; + C->xtype = k ; + + ok = CHOLMOD(free_triplet)(&T, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + ok = CHOLMOD(factor_xtype)(CHOLMOD_REAL + DTYPE, Lbad, cm) ; + NOT (ok) ; + + //-------------------------------------------------------------------------- + // rowadd (real matrices only) + //-------------------------------------------------------------------------- + + x = X->x ; + X->x = NULL ; + C = CHOLMOD(dense_to_sparse)(X, TRUE, cm) ; NOP (C) ; + + if (nrow > 3 && isreal) + { + ok = CHOLMOD(rowadd)(1, I1, L, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(nrow+1, R, L, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(nrow+1, R, L, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel)(nrow+1, NULL, L5, cm) ; NOT (ok) ; + + ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; + ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; + ok = CHOLMOD(rowdel)(nrow-2, Abad2, L5, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel)(nrow-1, R, L5, cm) ; NOT (ok) ; + + ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, FALSE, TRUE, TRUE, L5, + cm) ; + OK (ok) ; + + ok = CHOLMOD(rowadd)(nrow-2, NULL, L5, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(nrow-2, R, NULL, cm) ; NOT (ok) ; + + ok = CHOLMOD(rowadd)(nrow-2, R, L5, cm) ; OK (ok) ; + + ok = CHOLMOD(rowadd)(nrow-2, Abad2, L5, cm) ; NOT (ok) ; + + ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; OK (ok) ; + ok = CHOLMOD(change_factor)(CHOLMOD_PATTERN, TRUE, + TRUE, TRUE, TRUE, L5, cm) ; NOT (ok) ; + ok = CHOLMOD(change_factor)(CHOLMOD_REAL, TRUE, + TRUE, TRUE, TRUE, L5, cm) ; NOT (ok) ; + + ok = CHOLMOD(rowadd_solve)(nrow-2, R, beta, L5, X, X, cm) ; NOT (ok) ; + ok = CHOLMOD(rowdel_solve)(nrow-2, R, beta, L5, X, X, cm) ; NOT (ok) ; + ok = CHOLMOD(updown_solve)(TRUE, R, L5, X, X, cm) ; NOT (ok) ; + + if (nrow < 200 && L5 != NULL && R2 != NULL) + { + cholmod_factor *L8 ; + Int *L8p, *L8i, *L8nz, rnz ; + Real *L8x ; + L8 = CHOLMOD(copy_factor) (L5, cm) ; + ok = TRUE ; + for (k = nrow-1 ; ok && L8 != NULL + && L8->xtype == CHOLMOD_REAL && k >= 0 ; k--) + { + for (rnz = 0 ; rnz < nrow ; rnz++) + { + // first, ensure row i is zero + for (j = 0 ; j < nrow ; j++) + { + L8p = L8->p ; + L8i = L8->i ; + L8nz = L8->nz ; + L8x = L8->x ; + for (p = L8p [j] ; p < L8p [j] + L8nz [j] ; p++) + { + i = L8i [p] ; + if (i == k) L8x [p] = 0 ; + } + } + R2p [1] = rnz ; + ok = CHOLMOD(rowadd)(k, R2, L8, cm) ; OK (ok) ; + ok = CHOLMOD(rowdel)(k, NULL, L8, cm) ; OK (ok) ; + ok = CHOLMOD(rowadd)(k, R2, L8, cm) ; OK (ok) ; + } + } + CHOLMOD(free_factor) (&L8, cm) ; + } + } + + X->x = x ; + ok = CHOLMOD(free_dense)(&X, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // ssmult + //-------------------------------------------------------------------------- + + if (nrow < 100) + { + C = CHOLMOD(ssmult)(A, A, 0, TRUE, TRUE, cm) ; + if (A->nrow != A->ncol) + { + NOP (C) ; + } + else + { + OKP (C) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + C = CHOLMOD(ssmult)(NULL, A, 0, TRUE, TRUE, cm) ; NOP (C) ; + C = CHOLMOD(ssmult)(A, NULL, 0, TRUE, TRUE, cm) ; NOP (C) ; + } + + //-------------------------------------------------------------------------- + // sdmult + //-------------------------------------------------------------------------- + + if (nrow > 1) + { + ok = CHOLMOD(sdmult)(A, FALSE, one, one, Two, Two, cm) ; NOT (ok) ; + } + + YY = CHOLMOD(ones)(A->nrow, 1, xtype + DTYPE, cm) ; + OKP (YY) ; + XX = CHOLMOD(ones)(A->ncol, 1, xtype + DTYPE, cm) ; + OKP (XX) ; + cm->print = 4 ; + ok = CHOLMOD(print_dense)(XX, "XX", cm) ; OK (ok) ; + cm->print = psave ; + ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; OK (ok) ; + ok = CHOLMOD(sdmult)(NULL, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; + ok = CHOLMOD(sdmult)(A, FALSE, one, one, NULL, YY, cm) ; NOT (ok) ; + ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, NULL, cm) ; NOT (ok) ; + + ok = CHOLMOD(sdmult)(Abad2, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; + + XX->xtype++ ; + ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; + XX->xtype-- ; + + YY->xtype++ ; + ok = CHOLMOD(sdmult)(A, FALSE, one, one, XX, YY, cm) ; NOT (ok) ; + YY->xtype-- ; + + CHOLMOD(free_dense)(&YY, cm) ; + CHOLMOD(free_dense)(&XX, cm) ; + + //-------------------------------------------------------------------------- + // symmetry + //-------------------------------------------------------------------------- + + for (option = 0 ; option <= 2 ; option++) + { + Int xmatched = 0, pmatched = 0, nzoffdiag = 0, nz_diag = 0 ; + int asym ; + printf ("test symmetry: option %d\n", option) ; + cm->print = 3 ; // 5 ; + CHOLMOD(print_sparse) (A, "A", cm) ; + cm->print = psave ; + asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + printf ("asym: %d\n", asym) ; + OK (A->stype != 0 || asym >= 0) ; + save1 = A->xtype ; + A->xtype = CHOLMOD_PATTERN ; + asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + printf ("asym: %d pattern\n", asym) ; + OK (A->stype != 0 || asym >= 0) ; + A->xtype = save1 ; + C = CHOLMOD(copy_sparse) (A, cm) ; + OKP (C) ; + ok = CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX + DTYPE, C, cm) ; + OK (ok) ; + asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + OK (A->stype != 0 || asym >= 0) ; + printf ("asym: %d zomplex\n", asym) ; + + asym = CHOLMOD(symmetry) (NULL, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + NOT (asym >= 0) ; + + C->xtype = 999 ; + asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + NOT (asym >= 0) ; + C->xtype = CHOLMOD_ZOMPLEX ; + + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + + C = CHOLMOD(copy) (A, 0, (A->xtype == CHOLMOD_REAL), cm) ; + OKP (C) ; + asym = CHOLMOD(symmetry) (C, option, &xmatched, &pmatched, + &nzoffdiag, &nz_diag, cm) ; + OK (asym >= 0) ; + ok = CHOLMOD(free_sparse)(&C, cm) ; OK (ok) ; + } + + //-------------------------------------------------------------------------- + // memory tests + //-------------------------------------------------------------------------- + + R3 = CHOLMOD(speye)(nrow, 1, CHOLMOD_PATTERN + DTYPE, cm) ; // [ + OKP (R3) ; + + test_memory_handler ( ) ; + + ok = CHOLMOD(amd)(A, NULL, 0, Pok, cm) ; + if (A->nrow == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + + #ifndef NCAMD + ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; + if (A->nrow == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + #endif + + C = CHOLMOD(aat)(A, NULL, 0, 0, cm) ; NOP (C) ; + A->sorted = FALSE ; + ok = CHOLMOD(check_sparse)(A, cm) ; NOT (ok) ; + A->sorted = TRUE ; + + CHOLMOD(free_work)(cm) ; + if (A->stype == 0) + { + for (trial = 0 ; !ok && trial < 20 ; trial++) + { + my_tries = trial ; + printf ("--------------------- trial %"PRId64"\n", my_tries) ; + ok = CHOLMOD(colamd)(A, NULL, 0, TRUE, Pok, cm) ; + } + OK (ok) ; + } + + + #ifndef NCAMD + test_memory_handler ( ) ; + ok = CHOLMOD(ccolamd)(A, fsetok, fsizeok, NULL, Pok, cm) ; NOT (ok) ; + ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; + for (trial = 0 ; trial < 7 ; trial++) + { + test_memory_handler ( ) ; + my_tries = trial ; + ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; + } + + if (A->nrow == A->ncol && A->packed) + { + test_memory_handler ( ) ; + my_tries = 8 ; + ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; OK (ok) ; + test_memory_handler ( ) ; + ok = CHOLMOD(csymamd)(A, NULL, Pok, cm) ; NOT (ok) ; + OK (cm->status == CHOLMOD_OUT_OF_MEMORY) ; + } + + for (trial = 0 ; trial < 5 ; trial++) + { + test_memory_handler ( ) ; + my_tries = trial ; + ok = CHOLMOD(camd)(A, NULL, 0, NULL, Pok, cm) ; + if (A->nrow == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + } + #endif + + test_memory_handler ( ) ; + + ok = CHOLMOD(etree)(A, Parent, cm) ; NOT (ok) ; + ok = CHOLMOD(factorize)(A, L, cm) ; NOT (ok) ; + + pp = CHOLMOD(malloc)(4, 0, cm) ; NOP (pp) ; + pp = CHOLMOD(calloc)(4, 0, cm) ; NOP (pp) ; + pp = CHOLMOD(calloc)(SIZE_MAX, 1, cm) ; NOP (pp) ; + pp = NULL ; + size = 0 ; + pp = CHOLMOD(realloc)(4, 0, pp, &size, cm) ; NOP (pp) ; + pp = CHOLMOD(realloc)(SIZE_MAX, 1, pp, &size, cm) ; NOP (pp) ; + + normal_memory_handler ( ) ; + OK (CHOLMOD(print_sparse)(A, "A ok", cm)) ; + OK (CHOLMOD(print_factor)(L, "L ok", cm)) ; + + // test no_workspace_reallocate flag + CHOLMOD (free_work) (cm) ; + CHOLMOD (allocate_work) (1, 1, 1, cm) ; + OK (cm->status == CHOLMOD_OK) ; + cm->no_workspace_reallocate = TRUE ; + ok = CHOLMOD (allocate_work) (2, 1, 1, cm) ; + NOT (ok) ; + ok = CHOLMOD (allocate_work) (1, 2, 1, cm) ; + NOT (ok) ; + ok = CHOLMOD (allocate_work) (1, 1, 8, cm) ; + NOT (ok) ; + cm->no_workspace_reallocate = FALSE ; + ok = CHOLMOD (allocate_work) (1, 1, 2, cm) ; + OK (ok) ; + + cm->print = 4 ; + ok = CHOLMOD(print_factor)(L, "L for copy", cm) ; + OK (ok) ; + ok = FALSE ; + test_memory_handler ( ) ; + for (trial = 0 ; !ok && trial < 100 ; trial++) + { + my_tries = trial ; + Lcopy = CHOLMOD(copy_factor)(L, cm) ; + ok = (Lcopy != NULL) ; + } + normal_memory_handler ( ) ; + ok = CHOLMOD(print_factor)(Lcopy, "Lcopy", cm) ; + OK (ok) ; + CHOLMOD(free_factor)(&Lcopy, cm) ; + cm->print = psave ; + + test_memory_handler ( ) ; + ok = CHOLMOD(resymbol)(A, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + ok = CHOLMOD(resymbol_noperm)(A, NULL, 0, TRUE, L, cm) ; NOT (ok) ; + + lr = CHOLMOD(postorder)(Parent, nrow, NULL, Post, cm) ; NOT (lr>=0) ; + + T = CHOLMOD(copy_triplet)(Tok, cm) ; NOT (ok) ; + + #ifndef NPARTITION + lr = CHOLMOD(nested_dissection)(A, NULL, 0, Pok, CParent, + Cmember, cm) ; + if (nrow == 0) + { + OK (lr >= 0) ; + } + else + { + NOT (lr >= 0) ; + } + + lr = CHOLMOD(nested_dissection)(Abad2, NULL, 0, Pok, CParent, + Cmember, cm) ; + NOT (lr >= 0) ; + + ok = CHOLMOD(metis)(A, NULL, 0, TRUE, Pok, cm) ; + + if (nrow == 0) + { + OK (ok) ; + } + else + { + NOT (ok) ; + } + lr = CHOLMOD(bisect)(A, NULL, 0, TRUE, Partition, cm) ; + + if (nrow == 0) + { + OK (lr == 0) ; + } + else + { + NOT (lr >= 0) ; + } + + lr = CHOLMOD(bisect)(Abad2, NULL, 0, TRUE, Partition, cm) ; NOT (lr >= 0) ; + #endif + + if (nrow > 3) + { + ok = CHOLMOD(rowdel)(nrow-2, NULL, L5, cm) ; NOT (ok) ; + ok = CHOLMOD(rowadd)(nrow-2, R, L5, cm) ; NOT (ok) ; + ok = CHOLMOD(updown)(+1, A, L, cm) ; NOT (ok) ; + } + + C = CHOLMOD(add)(A, A, one, one, 1, true, cm) ; NOP (C) ; + C = CHOLMOD(ssmult)(A, A, 0, TRUE, TRUE, cm) ; NOP (C) ; + + ok = CHOLMOD(rowcolcounts)(A, NULL, 0, Parent, Post, + NULL, ColCount, First, Level, cm) ; NOT (ok) ; + + ok = CHOLMOD(rowfac)(A, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_unsym)(A, 1, Pok, NULL, 0, R, cm) ; NOT (ok) ; + ok = CHOLMOD(transpose_sym)(A, 1, Pok, R, cm) ; NOT (ok) ; + + ok = CHOLMOD(row_subtree)(A, AT, 0, Parent, R3, cm) ; NOT (ok) ; + ATi = (AT == NULL) ? NULL : AT->i ; + ok = CHOLMOD(row_lsubtree)(A, ATi, 0, 0, L, R3, cm) ; NOT (ok) ; + + normal_memory_handler ( ) ; + + //-------------------------------------------------------------------------- + // free the valid objects + //-------------------------------------------------------------------------- + + cm->status = CHOLMOD_OK ; + + CHOLMOD(free_triplet)(NULL, cm) ; + + CHOLMOD(free_sparse)(&R3, cm) ; // ] + CHOLMOD(free_sparse)(&R, cm) ; // ] + CHOLMOD(free_sparse)(&Acopy, cm) ; // ] + CHOLMOD(free_factor)(&L5, cm) ; // ] + CHOLMOD(free_factor)(&L2, cm) ; // ] + + Lbad->xtype = Lxtype ; + CHOLMOD(free_factor)(&Lbad, cm) ; // ] + + CHOLMOD(free_factor)(&L, cm) ; // ] + + CHOLMOD(free_triplet)(&T, cm) ; + + Axbad->xtype = Axbad_type ; + CHOLMOD(free_sparse)(&Axbad, cm) ; // ] + + cm->error_handler = my_handler ; + + Xbad2->xtype = CHOLMOD_REAL ; + CHOLMOD(free_dense)(&Xbad2, cm) ; // ] + + Abad2->xtype = Abad2xtype ; + CHOLMOD(free_sparse)(&Abad2, cm) ; // ] + + CHOLMOD(free_sparse)(&Abad, cm) ; // ] + + CHOLMOD(free_sparse)(&R0, cm) ; + CHOLMOD(free_sparse)(&R1, cm) ; // ] + + CHOLMOD(free_sparse)(&Aboth, cm) ; // ] + CHOLMOD(free_sparse)(&Sok, cm) ; + + + CHOLMOD(free)(nrow, sizeof (Int), Pinv, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), Parent, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), Post, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), Cmember, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), CParent, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), Partition, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), ColCount, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), First, cm) ; + CHOLMOD(free)(nrow, sizeof (Int), Level, cm) ; // ] + + CHOLMOD(free_dense)(&Two, cm) ; // ] + + CHOLMOD(free_sparse)(&R2, cm) ; // ] + CHOLMOD(free)(nrow, sizeof (Int), Pok, cm) ; // ] + + CHOLMOD(free_sparse)(&I1, cm) ; // ] + + CHOLMOD(free)(nrow, sizeof (Int), Pbad, cm) ; // ] + + CHOLMOD(free)(ncol, sizeof (Int), fsetbad, cm) ; // ] + CHOLMOD(free)(ncol, sizeof (Int), fsetok, cm) ; // ] + + CHOLMOD(free_dense)(&Bok, cm) ; // ] + + CHOLMOD(free_dense)(&Xok, cm) ; // ] + + CHOLMOD(free_sparse)(&AT, cm) ; // ] + + CHOLMOD(free_sparse)(&A, cm) ; // ] + + OK (cm->status == CHOLMOD_OK) ; + printf ("\n------------------------null2 tests: All OK\n") ; +} + diff --git a/CHOLMOD/Tcov/t_overflow_tests.c b/CHOLMOD/Tcov/t_overflow_tests.c new file mode 100644 index 0000000000..b5e53885e3 --- /dev/null +++ b/CHOLMOD/Tcov/t_overflow_tests.c @@ -0,0 +1,446 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_overflow_tests: integer overflow tests +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +void overflow_tests (cholmod_common *cm) +{ + + //-------------------------------------------------------------------------- + // cholmod_read_triplet + //-------------------------------------------------------------------------- + + FILE *f = fopen ("Matrix/int_overflow.tri", "r") ; + if (f != NULL) + { + cholmod_triplet *T = CHOLMOD(read_triplet) (f, cm) ; + OK (cm->status = CHOLMOD_TOO_LARGE) ; + OK (T == NULL) ; + } + + //-------------------------------------------------------------------------- + // AMD and CAMD + //-------------------------------------------------------------------------- + + #ifdef CHOLMOD_INT64 + { + int64_t n = 1 ; + int64_t Ap [2] = { 0, INT64_MAX } ; + int64_t Ai [1] = { 0 } ; + int64_t P [1] = { 0 } ; + int result = amd_l_order (n, Ap, Ai, P, NULL, NULL) ; + OK (result == AMD_OUT_OF_MEMORY) ; + result = camd_l_order (n, Ap, Ai, P, NULL, NULL, NULL) ; + OK (result == AMD_OUT_OF_MEMORY) ; + } + #else + { + int32_t n = 1 ; + int32_t Ap [2] = { 0, INT32_MAX/2 } ; + int32_t Ai [1] = { 0 } ; + int32_t P [1] = { 0 } ; + int result = amd_order (n, Ap, Ai, P, NULL, NULL) ; + OK (result == AMD_OUT_OF_MEMORY) ; + result = camd_order (n, Ap, Ai, P, NULL, NULL, NULL) ; + OK (result == AMD_OUT_OF_MEMORY) ; + } + #endif + + //-------------------------------------------------------------------------- + // cholmod_amd, cholmod_camd, ... + //-------------------------------------------------------------------------- + + cholmod_sparse *A = CHOLMOD(spzeros) (1, 1, 1, CHOLMOD_REAL + DTYPE, cm) ; + cholmod_sparse *R = CHOLMOD(spzeros) (1, 1, 1, CHOLMOD_REAL + DTYPE, cm); + cholmod_sparse *C = CHOLMOD(spzeros) (1, 8, 1, CHOLMOD_REAL + DTYPE, cm); + cholmod_factor *L = CHOLMOD(alloc_factor) (1, DTYPE, cm) ; + cm->print = 5 ; + CHOLMOD(print_sparse) (C, "C", cm) ; + + if (A != NULL && R != NULL && L != NULL) + { + Int P [1] ; + + size_t n_save = L->n ; + bool is_super_save = L->is_super ; + size_t ncol_save = A->ncol ; + size_t nrow_save = A->nrow ; + size_t R_nrow_save = R->nrow ; + size_t C_nrow_save = C->nrow ; + int stype_save = A->stype ; + int L_xtype_save = L->xtype ; + int A_xtype_save = A->xtype ; + + A->nrow = INT64_MAX ; + + //---------------------------------------------------------------------- + // cholmod_amd + //---------------------------------------------------------------------- + + int ok = CHOLMOD(amd) (A, NULL, 0, P, cm) ; + printf ("cholmod_amd result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_camd + //---------------------------------------------------------------------- + + ok = CHOLMOD(camd) (A, NULL, 0, NULL, P, cm) ; + printf ("cholmod_camd result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_metis + //---------------------------------------------------------------------- + + ok = CHOLMOD(metis) (A, NULL, 0, false, P, cm) ; + printf ("cholmod_metis result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_bisect + //---------------------------------------------------------------------- + + A->ncol = SIZE_MAX ; + + int64_t nsep = CHOLMOD(bisect) (A, NULL, 0, false, P, cm) ; + printf ("cholmod_bisect result: %ld\n", nsep) ; + OK (nsep == EMPTY) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->ncol = ncol_save ; + + //---------------------------------------------------------------------- + // cholmod_nested_dissection + //---------------------------------------------------------------------- + + nsep = CHOLMOD(nested_dissection) (A, NULL, 0, P, P, P, cm) ; + printf ("cholmod_nested_dissection result: %ld\n", nsep) ; + OK (nsep == EMPTY) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_analyze + //---------------------------------------------------------------------- + + cholmod_factor *Lbad = CHOLMOD(analyze) (A, cm) ; + printf ("cholmod_analyze result: %d\n", ok) ; + OK (Lbad == NULL) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_postorder + //---------------------------------------------------------------------- + + Int npost = CHOLMOD(postorder) (P, SIZE_MAX, P, P, cm) ; + printf ("cholmod_postorder result: "ID"\n", npost) ; + OK (npost == EMPTY) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_super_symbolic + //---------------------------------------------------------------------- + + A->ncol = SIZE_MAX ; + A->nrow = SIZE_MAX ; + A->stype = 1 ; + L->n = SIZE_MAX ; + + ok = CHOLMOD(super_symbolic) (A, NULL, P, L, cm) ; + NOT (ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + L->n = n_save ; + A->ncol = ncol_save ; + A->nrow = nrow_save ; + A->stype = stype_save ; + + //---------------------------------------------------------------------- + // cholmod_cumsum + //---------------------------------------------------------------------- + + Int Result [5] ; + Int Set [4] = { 0, Int_max/2, Int_max/2, Int_max } ; + int64_t sum = CHOLMOD(cumsum) (Result, Set, 5) ; + OK (sum == EMPTY) ; + + //---------------------------------------------------------------------- + // cholmod_ensure_dense + //---------------------------------------------------------------------- + + cholmod_dense *Y = NULL ; + cholmod_dense *Z = CHOLMOD(ensure_dense) (&Y, SIZE_MAX, SIZE_MAX, + SIZE_MAX, CHOLMOD_REAL + DTYPE, cm) ; + printf ("status %d\n", cm->status) ; + OK (Z == NULL) ; + OK (Y == NULL) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_alloc_factor + //---------------------------------------------------------------------- + + Lbad = CHOLMOD(alloc_factor) (Int_max, DTYPE, cm) ; + OK (Lbad == NULL) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + //---------------------------------------------------------------------- + // cholmod_factorize + //---------------------------------------------------------------------- + + Real X [2] ; + + A->ncol = SIZE_MAX ; + A->nrow = SIZE_MAX ; + A->stype = 0 ; + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + + ok = CHOLMOD(factorize) (A, L, cm) ; + printf ("cholmod_factorize result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->nrow = nrow_save ; + A->ncol = ncol_save ; + A->stype = stype_save ; + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + + //---------------------------------------------------------------------- + // cholmod_resymbol + //---------------------------------------------------------------------- + + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + A->stype = 0 ; + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + + ok = CHOLMOD(resymbol) (A, NULL, 0, true, L, cm) ; + printf ("cholmod_resymbol result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->nrow = nrow_save ; + A->ncol = ncol_save ; + A->stype = stype_save ; + + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + + //---------------------------------------------------------------------- + // cholmod_resymbol_noperm + //---------------------------------------------------------------------- + + A->ncol = SIZE_MAX ; + A->nrow = SIZE_MAX ; + A->stype = -1 ; + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + + ok = CHOLMOD(resymbol_noperm) (A, NULL, 0, true, L, cm) ; + printf ("cholmod_resymbol_noperm result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->ncol = ncol_save ; + A->nrow = nrow_save ; + A->stype = stype_save ; + + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + + //---------------------------------------------------------------------- + // cholmod_etree + //---------------------------------------------------------------------- + + A->stype = 0 ; + A->ncol = SIZE_MAX ; + + ok = CHOLMOD(etree) (A, P, cm) ; + printf ("cholmod_etree result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->ncol = ncol_save ; + A->stype = stype_save ; + + //---------------------------------------------------------------------- + // cholmod_rowadd + //---------------------------------------------------------------------- + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + R->nrow = SIZE_MAX ; + + ok = CHOLMOD(rowadd) (0, R, L, cm) ; + printf ("cholmod_rowadd result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + R->nrow = R_nrow_save ; + + //---------------------------------------------------------------------- + // cholmod_rowdel + //---------------------------------------------------------------------- + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + + ok = CHOLMOD(rowdel) (0, NULL, L, cm) ; + printf ("cholmod_rowdel result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + + //---------------------------------------------------------------------- + // cholmod_rowcolcounts + //---------------------------------------------------------------------- + + A->stype = 0 ; + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + + ok = CHOLMOD(rowcolcounts) (A, NULL, 0, P, P, P, P, P, P, cm) ; + printf ("cholmod_rowadd result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->stype = stype_save ; + A->nrow = nrow_save ; + A->ncol = ncol_save ; + + //---------------------------------------------------------------------- + // cholmod_rowfac + //---------------------------------------------------------------------- + + A->stype = 0 ; + A->xtype = CHOLMOD_COMPLEX ; + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + + L->n = SIZE_MAX ; + + ok = CHOLMOD(rowfac) (A, A, one, 0, 0, L, cm) ; + printf ("cholmod_rowfac result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->stype = stype_save ; + A->xtype = A_xtype_save ; + A->nrow = nrow_save ; + A->ncol = ncol_save ; + + L->n = n_save ; + + //---------------------------------------------------------------------- + // cholmod_submatrix + //---------------------------------------------------------------------- + + A->stype = 0 ; + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + + cholmod_sparse *S = CHOLMOD(submatrix) (A, P, 1, P, 1, false, true, cm); + printf ("cholmod_submatrix result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + A->stype = stype_save ; + A->nrow = nrow_save ; + A->ncol = ncol_save ; + + //---------------------------------------------------------------------- + // cholmod_updown + //---------------------------------------------------------------------- + + L->n = SIZE_MAX ; + L->xtype = CHOLMOD_REAL ; + L->x = X ; + C->nrow = SIZE_MAX ; + + ok = CHOLMOD(updown) (1, C, L, cm) ; + printf ("cholmod_updown result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + L->n = n_save ; + L->xtype = L_xtype_save ; + L->x = NULL ; + C->nrow = C_nrow_save ; + + //---------------------------------------------------------------------- + // cholmod_super_numeric + //---------------------------------------------------------------------- + + L->n = SIZE_MAX ; + L->is_super = true ; + A->stype = -1 ; + A->nrow = SIZE_MAX ; + A->ncol = SIZE_MAX ; + + ok = CHOLMOD(super_numeric) (A, NULL, one, L, cm) ; + printf ("cholmod_super_numeric result: %d\n", ok) ; + OK (!ok) ; + OK (cm->status == CHOLMOD_TOO_LARGE) ; + cm->status = CHOLMOD_OK ; + + L->is_super = is_super_save ; + L->n = n_save ; + A->stype = stype_save ; + A->nrow = nrow_save ; + A->ncol = ncol_save ; + } + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&R, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_factor) (&L, cm) ; +} + diff --git a/CHOLMOD/Tcov/t_perm_matrix.c b/CHOLMOD/Tcov/t_perm_matrix.c new file mode 100644 index 0000000000..db7cf2b3ed --- /dev/null +++ b/CHOLMOD/Tcov/t_perm_matrix.c @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_perm_matrix: create a permutation matrix from perm vector +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// if perm is NULL, the identity permutation matrix is returned + +cholmod_sparse *perm_matrix (Int *perm, Int n, int xdtype, + cholmod_common *Common) +{ + + // P = I + cholmod_sparse *P = CHOLMOD(speye) (n, n, xdtype, Common) ; + + // copy perm [0..n-1] as the row indices of P + if (P != NULL && perm != NULL) + { + Int *Pi = P->i ; + for (Int j = 0 ; j < n ; j++) + { + Pi [j] = perm [j] ; + } + } + + return (P) ; +} + diff --git a/CHOLMOD/Tcov/t_prand.c b/CHOLMOD/Tcov/t_prand.c new file mode 100644 index 0000000000..4781d3a939 --- /dev/null +++ b/CHOLMOD/Tcov/t_prand.c @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_prand: random permutation vector +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// allocate and construct a random permutation of 0:n-1 + +Int *prand (Int n) +{ + Int *P ; + + P = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + if (P == NULL) + { + return (NULL) ; + } + + for (Int k = 0 ; k < n ; k++) + { + P [k] = k ; + } + + for (Int k = 0 ; k < n-1 ; k++) + { + Int j = k + nrand (n-k) ; + Int t = P [j] ; + P [j] = P [k] ; + P [k] = t ; + } + return (P) ; +} + diff --git a/CHOLMOD/Tcov/t_ptest.c b/CHOLMOD/Tcov/t_ptest.c new file mode 100644 index 0000000000..326b9fd36b --- /dev/null +++ b/CHOLMOD/Tcov/t_ptest.c @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_ptest: test ssmult, sort, using permutations +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// returns r = norm (P*A - P*B), where P is a permutation matrix created from +// perm, of size n (which must equal A->nrow and B->nrow). If perm is NULL on +// input, P = I is used. + +double ptest (cholmod_sparse *A, cholmod_sparse *B, Int *perm, Int n) +{ + + // P = permutation matrix from perm + int xtype = (A == NULL) ? CHOLMOD_PATTERN : A->xtype ; + cholmod_sparse *P = perm_matrix (perm, n, xtype + DTYPE, cm) ; + + // PA = P*A + cholmod_sparse *PA = CHOLMOD(ssmult) (P, A, 0, true, false, cm) ; + CHOLMOD(sort) (PA, cm) ; + + // PB = P*B + cholmod_sparse *PB = CHOLMOD(ssmult) (P, B, 0, true, false, cm) ; + CHOLMOD(sort) (PB, cm) ; + + // E = PA-PB + cholmod_sparse *E = CHOLMOD(add) (PA, PB, one, minusone, true, false, cm) ; + + // rnorm = norm (A) + double rnorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + + CHOLMOD(free_sparse) (&P, cm) ; + CHOLMOD(free_sparse) (&PA, cm) ; + CHOLMOD(free_sparse) (&PB, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + return (rnorm) ; +} + diff --git a/CHOLMOD/Tcov/t_rand_dense.c b/CHOLMOD/Tcov/t_rand_dense.c new file mode 100644 index 0000000000..859b8b6539 --- /dev/null +++ b/CHOLMOD/Tcov/t_rand_dense.c @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_rand_dense: random dense matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +cholmod_dense *rand_dense +( + Int nrow, + Int ncol, + int xdtype, + cholmod_common *Common +) +{ + + cholmod_dense *X = CHOLMOD(zeros) (nrow, ncol, xdtype, Common) ; + if (!X) return (NULL) ; + Int nz = nrow*ncol ; + + switch (xdtype % 8) + { + case CHOLMOD_REAL + CHOLMOD_SINGLE: + { + float *Xx = X->x ; + for (Int p = 0 ; p < nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + } + } + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + { + float *Xx = X->x ; + for (Int p = 0 ; p < 2*nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + } + } + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + { + float *Xx = X->x ; + float *Xz = X->z ; + for (Int p = 0 ; p < nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + Xz [p] = xrand (1) ; // RAND + } + } + break ; + + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + { + double *Xx = X->x ; + for (Int p = 0 ; p < nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + } + } + break ; + + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + { + double *Xx = X->x ; + for (Int p = 0 ; p < 2*nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + } + } + break ; + + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + { + double *Xx = X->x ; + double *Xz = X->z ; + for (Int p = 0 ; p < nz ; p++) + { + Xx [p] = xrand (1) ; // RAND + Xz [p] = xrand (1) ; // RAND + } + } + break ; + } + + return (X) ; +} + diff --git a/CHOLMOD/Tcov/t_raw_factor.c b/CHOLMOD/Tcov/t_raw_factor.c new file mode 100644 index 0000000000..2fb5998439 --- /dev/null +++ b/CHOLMOD/Tcov/t_raw_factor.c @@ -0,0 +1,834 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_raw_factor: test CHOLMOD factorization and solvers +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Factorize A using cholmod_rowfac for the simplicial case, and the +// cholmod_super_* routines for the supernodal case, and test the solution to +// linear systems. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// icomp +//------------------------------------------------------------------------------ + +// for sorting by qsort +static int icomp (Int *i, Int *j) +{ + if (*i < *j) + { + return (-1) ; + } + else + { + return (1) ; + } +} + +//------------------------------------------------------------------------------ +// add_gunk +//------------------------------------------------------------------------------ + +static cholmod_sparse *add_gunk (cholmod_sparse *A) +{ + cholmod_sparse *S ; + Real *Sx, *Sz ; + Int *Sp, *Si, nz, p, save3, j, n ; + + if (A == NULL) return (NULL) ; + + A->nzmax++ ; + S = CHOLMOD(copy_sparse) (A, cm) ; + A->nzmax-- ; + + // add a S(n,1)=1 entry to the matrix + if (S != NULL) + { + S->sorted = FALSE ; + Sx = S->x ; + Si = S->i ; + Sp = S->p ; + Sz = S->z ; + n = S->ncol ; + nz = Sp [n] ; + for (j = 1 ; j <= n ; j++) + { + Sp [j]++ ; + } + if (S->xtype == CHOLMOD_REAL) + { + for (p = nz-1 ; p >= 0 ; p--) + { + Si [p+1] = Si [p] ; + Sx [p+1] = Sx [p] ; + } + Si [0] = n-1 ; + Sx [0] = 99999 ; + } + else if (S->xtype == CHOLMOD_COMPLEX) + { + for (p = nz-1 ; p >= 0 ; p--) + { + Si [p+1] = Si [p] ; + Sx [2*p+2] = Sx [2*p] ; + Sx [2*p+3] = Sx [2*p+1] ; + } + Si [0] = n-1 ; + Sx [0] = 99999 ; + Sx [1] = 0 ; + } + else if (S->xtype == CHOLMOD_ZOMPLEX) + { + for (p = nz-1 ; p >= 0 ; p--) + { + Si [p+1] = Si [p] ; + Sx [p+1] = Sx [p] ; + Sz [p+1] = Sz [p] ; + } + Si [0] = n-1 ; + Sx [0] = 99999 ; + Sz [0] = 0 ; + } + } + + return (S) ; +} + +//------------------------------------------------------------------------------ +// raw_factor +//------------------------------------------------------------------------------ + +// Factor A, without using any fill-reducing permutation. This may fail due +// to catastrophic fill-in (which is the desired test result for a large +// arrowhead matrix). + +double raw_factor (cholmod_sparse *A, Int check_errors) +{ + double maxerr = 0, r, anorm ; + cholmod_sparse *AT, *C, *LT, *Lsparse, *S, *ST, *R, *A1 ; + cholmod_factor *L, *Lcopy ; + cholmod_dense *X, *W, *B, *X2 ; + Int i, k, n, ok, ok1, ok2, trial, rnz, lnz, Lxtype, Axtype, posdef, + prefer_zomplex, Bxtype ; + Int *Parent, *Post, *First, *Level, *Ri, *Rp, *LTp = NULL, *LTi = NULL, *P, + *mask, *RLinkUp ; + int64_t lr ; + double beta [2] ; + uint64_t save ; + + //-------------------------------------------------------------------------- + // create the problem + //-------------------------------------------------------------------------- + + if (A == NULL || A->stype != 1) + { + return (0) ; + } + + W = NULL ; + X2 = NULL ; + L = NULL ; + n = A->nrow ; + B = rhs (A, 1, n, 0) ; + AT = CHOLMOD(transpose) (A, 2, cm) ; + Parent = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Post = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + First = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Level = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + beta [0] = 0 ; + beta [1] = 0 ; + anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; + + prefer_zomplex = (A->xtype == CHOLMOD_ZOMPLEX) ; + Bxtype = A->xtype ; + + //-------------------------------------------------------------------------- + // supernodal factorization + //-------------------------------------------------------------------------- + + L = CHOLMOD(alloc_factor) (n, DTYPE, cm) ; + ok1 = CHOLMOD(etree) (A, Parent, cm) ; + lr = CHOLMOD(postorder) (Parent, n, NULL, Post, cm) ; + ok2 = CHOLMOD(rowcolcounts) (AT, NULL, 0, Parent, Post, + NULL, (L != NULL) ? (L->ColCount) : NULL, First, Level, cm) ; + + if (ok2) + { + printf ("raw_factor: cm->fl %g cm->lnz %g\n", cm->fl, cm->lnz) ; + } + + if (check_errors) + { + OKP (AT) ; + OKP (Parent) ; + OKP (Post) ; + OKP (First) ; + OKP (Level) ; + OK (AT->stype == -1) ; + OKP (L) ; + OK (ok1) ; + OK (ok2) ; + OK (lr >= 0) ; + + // rowcolcounts requires A in symmetric lower form + ok = CHOLMOD(rowcolcounts) (A, NULL, 0, Parent, Post, + NULL, L->ColCount, First, Level, cm) ; NOT (ok) ; + } + + // super_symbolic needs A in upper form, so this will succeed + // unless the problem is huge + ok = CHOLMOD(super_symbolic) (A, NULL, Parent, L, cm) ; + + // super_symbolic should fail if lnz is too large + if (cm->lnz > SIZE_MAX / 2) + { + printf ("raw_factor: problem is huge\n") ; + NOT (ok) ; + OK (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ; + + // try changing to LDL packed, which should also fail + ok = CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, + L, cm) ; + NOT (ok) ; + + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free) (n, sizeof (Int), First, cm) ; + CHOLMOD(free) (n, sizeof (Int), Level, cm) ; + CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; + CHOLMOD(free) (n, sizeof (Int), Post, cm) ; + return (0) ; + } + + if (check_errors) + { + + if (cm->status == CHOLMOD_OUT_OF_MEMORY + || cm->status == CHOLMOD_TOO_LARGE) + { + // no test case will reach here, but check just to be safe + printf ("raw_factor: out of memory for symbolic case %d\n", + cm->status) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free) (n, sizeof (Int), First, cm) ; + CHOLMOD(free) (n, sizeof (Int), Level, cm) ; + CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; + CHOLMOD(free) (n, sizeof (Int), Post, cm) ; + return (0) ; + } + + OK (ok) ; + ok = CHOLMOD(super_symbolic)(A, NULL, Parent, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_symbolic)(AT, NULL, Parent, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_symbolic)(NULL, NULL, Parent, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_symbolic)(A, NULL, NULL, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_symbolic)(A, NULL, Parent, NULL, cm) ; NOT (ok) ; + } + + // super_numeric needs A in lower form, so this will succeed unless + // the problem is huge + ok = CHOLMOD(super_numeric) (AT, NULL, Zero, L, cm) ; + + if (check_errors) + { + + if (cm->status == CHOLMOD_OUT_OF_MEMORY) + { + // For the 64-bit case, the Matrix/a1 problem will reach here + printf ("raw_factor: out of memory for numeric case\n") ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free) (n, sizeof (Int), First, cm) ; + CHOLMOD(free) (n, sizeof (Int), Level, cm) ; + CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; + CHOLMOD(free) (n, sizeof (Int), Post, cm) ; + return (0) ; + } + + OK (ok) ; + ok = CHOLMOD(super_numeric)(A, NULL, Zero, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(NULL, NULL, Zero, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric)(AT, NULL, Zero, NULL, cm) ; NOT (ok) ; + } + + // solve + Lxtype = (L == NULL) ? CHOLMOD_REAL : L->xtype ; + W = CHOLMOD(zeros) (n, 1, Lxtype + DTYPE, cm) ; + X = CHOLMOD(copy_dense) (B, cm) ; + if (Bxtype == CHOLMOD_ZOMPLEX) + { + CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX + DTYPE, X, cm) ; + } + + CHOLMOD(print_factor) (L, "L for super l/ltsolve", cm) ; + CHOLMOD(print_dense) (W, "W", cm) ; + CHOLMOD(print_dense) (X, "X", cm) ; + + ok1 = CHOLMOD(super_lsolve) (L, X, W, cm) ; + CHOLMOD(print_dense) (X, "X", cm) ; + + ok2 = CHOLMOD(super_ltsolve) (L, X, W, cm) ; + CHOLMOD(print_dense) (X, "X", cm) ; + + if (Bxtype == CHOLMOD_ZOMPLEX) + { + CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX + DTYPE, X, cm) ; + } + + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + + if (Bxtype == CHOLMOD_ZOMPLEX) + { + CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX + DTYPE, X, cm) ; + } + + if (check_errors) + { + OKP (W) ; + OKP (X) ; + OK (ok1) ; + OK (ok2) ; + ok = CHOLMOD(super_lsolve) (NULL, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve) (NULL, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_lsolve) (L, NULL, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve) (L, NULL, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_lsolve) (L, X, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve) (L, X, NULL, cm) ; NOT (ok) ; + + if (L != NULL && L->maxesize > 1) + { + // W is too small + ok = CHOLMOD(free_dense) (&W, cm) ; OK (ok) ; + W = CHOLMOD(zeros) (1, 1, Lxtype + DTYPE, cm) ; + OKP (W) ; + ok = CHOLMOD(super_lsolve) (L, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve) (L, X, W, cm) ; NOT (ok) ; + ok = CHOLMOD(free_dense) (&W, cm) ; OK (ok) ; + W = CHOLMOD(zeros) (n, 1, Lxtype + DTYPE, cm) ; + OKP (W) ; + } + + // X2 has the wrong dimensions + X2 = CHOLMOD(zeros) (n+1, 1, Lxtype + DTYPE, cm) ; + OKP (X2) ; + ok = CHOLMOD(super_lsolve) (L, X2, W, cm) ; NOT (ok) ; + ok = CHOLMOD(super_ltsolve) (L, X2, W, cm) ; NOT (ok) ; + CHOLMOD(free_dense) (&X2, cm) ; + } + + CHOLMOD(free_dense) (&X, cm) ; + + // X2 is n-by-0, which is OK + X2 = CHOLMOD(zeros) (n, 0, Lxtype + DTYPE, cm) ; + ok1 = CHOLMOD(super_lsolve) (L, X2, W, cm) ; + ok2 = CHOLMOD(super_ltsolve) (L, X2, W, cm) ; + CHOLMOD(free_dense) (&W, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + + if (check_errors) + { + OK (ok1) ; + OK (ok2) ; + test_memory_handler ( ) ; + my_tries = 0 ; + ok = CHOLMOD(super_symbolic) (A, NULL, Parent, L, cm) ; NOT (ok) ; + ok = CHOLMOD(super_numeric) (AT, NULL, Zero, L, cm) ; NOT (ok) ; + normal_memory_handler ( ) ; + cm->error_handler = NULL ; + } + + // R = space for result of row_subtree and row_lsubtree + R = CHOLMOD(allocate_sparse)(n, 1, n, FALSE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + + //-------------------------------------------------------------------------- + // erroneous factorization + //-------------------------------------------------------------------------- + + // cannot use rowfac or row_lsubtree on a supernodal factorization + if (check_errors && n > 0) + { + ok = CHOLMOD(rowfac) (A, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; + ok = CHOLMOD(row_lsubtree) (A, &i, 0, n-1, L, R, cm) ; NOT (ok) ; + } + + //-------------------------------------------------------------------------- + // convert to simplicial LDL' + //-------------------------------------------------------------------------- + + CHOLMOD(change_factor) (Lxtype, FALSE, FALSE, TRUE, TRUE, L, cm) ; + + // remove entries due to relaxed supernodal amalgamation + CHOLMOD(resymbol) (A, NULL, 0, TRUE, L, cm) ; + + // refactorize a numeric factor + posdef = 0 ; // unknown + if (A != NULL && A->stype >= 0) + { + if (A->stype > 0 && A->packed) + { + S = add_gunk (A) ; + CHOLMOD(rowfac) (S, NULL, beta, 0, n, L, cm) ; + if (S && S->xtype == CHOLMOD_COMPLEX) + { + CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX + DTYPE, S, cm) ; + } + ok = CHOLMOD(free_sparse) (&S, cm) ; + OK (ok) ; + } + else + { + CHOLMOD(rowfac) (A, NULL, beta, 0, n, L, cm) ; + } + posdef = (cm->status == CHOLMOD_OK) ; + } + + // convert to a sparse matrix, and transpose L + Lcopy = CHOLMOD(copy_factor)(L, cm) ; + Lsparse = CHOLMOD(factor_to_sparse) (L, cm) ; + + LT = CHOLMOD(transpose) (Lsparse, 0, cm) ; + CHOLMOD(free_sparse) (&Lsparse, cm) ; + + if (LT != NULL) + { + LTp = LT->p ; + LTi = LT->i ; + OK (LT->packed) ; + } + + // remove the unit diagonal of LT + CHOLMOD(band_inplace) (1, n, -1, LT, cm) ; + + // ST = pattern of A(p,p)' + P = (L == NULL) ? NULL : L->Perm ; + ST = CHOLMOD(ptranspose) (A, 0, P, NULL, 0, cm) ; + + // S = pattern of A(p,p) + S = CHOLMOD(transpose) (ST, 0, cm) ; + ok = CHOLMOD(free_sparse) (&ST, cm) ; + + if (R != NULL && LT != NULL && posdef && A != NULL && A->stype >= 0 + && S != NULL && Lcopy != NULL) + { + LTp = LT->p ; + LTi = LT->i ; + + Ri = R->i ; + Rp = R->p ; + + save = my_seed ( ) ; // RAND + for (trial = 0 ; trial < 30 ; trial++) + { + // pick a row at random + i = nrand (n) ; // RAND + + // compute R = pattern of L(i,0:i-1), using row subtrees + ok = CHOLMOD(row_subtree) (S, NULL, i, Parent, R, cm) ; + if (!ok) + { + break ; + } + rnz = Rp [1] ; + + // sort R + qsort (Ri, rnz, sizeof (Int), + (int (*) (const void *, const void *)) icomp) ; + + // compare with ith column of L transpose + lnz = LTp [i+1] - LTp [i] ; + ok = TRUE ; + for (k = 0 ; k < MIN (rnz,lnz) ; k++) + { + ok = ok && (Ri [k] == LTi [LTp [i] + k]) ; + } + OK (ok) ; + OK (rnz == lnz) ; + + // compute R = pattern of L(i,0:i-1), using row lsubtrees + ok = CHOLMOD(row_lsubtree) (S, NULL, 0, i, Lcopy, R, cm) ; + if (!ok) + { + break ; + } + rnz = Rp [1] ; + + // sort R + qsort (Ri, rnz, sizeof (Int), + (int (*) (const void *, const void *)) icomp) ; + + // compare with ith column of L transpose + lnz = LTp [i+1] - LTp [i] ; + ok = TRUE ; + for (k = 0 ; k < MIN (rnz,lnz) ; k++) + { + // printf ("%d vs %d\n", Ri [k], LTi [LTp [i] + k]) ; + ok = ok && (Ri [k] == LTi [LTp [i] + k]) ; + } + OK (ok) ; + OK (rnz == lnz) ; + + // L is symbolic, so cholmod_lsubtree will fail + if (check_errors) + { + ok = CHOLMOD(row_lsubtree) (S, NULL, 0, i, L, R, cm) ; + NOT (ok) ; + } + + } + my_srand (save) ; // RAND + } + + ok = CHOLMOD(free_factor) (&L, cm) ; OK (ok) ; + ok = CHOLMOD(free_factor) (&Lcopy, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse) (<, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse) (&R, cm) ; OK (ok) ; + ok = CHOLMOD(free_sparse) (&S, cm) ; OK (ok) ; + + //-------------------------------------------------------------------------- + // simplicial LDL' or LL' factorization with no analysis + //-------------------------------------------------------------------------- + + for (trial = 0 ; trial <= check_errors ; trial++) + { + + // create a simplicial symbolic factor + L = CHOLMOD(alloc_factor) (n, DTYPE, cm) ; + ok = TRUE ; + Axtype = (A == NULL) ? CHOLMOD_REAL : A->xtype ; + + if (check_errors) + { + OKP (L) ; + if (trial == 0) + { + // convert to packed LDL' first, then unpacked + ok = CHOLMOD(change_factor) (Axtype, FALSE, FALSE, TRUE, + TRUE, L, cm) ; + OK (ok); + ok = CHOLMOD(change_factor) (Axtype, FALSE, FALSE, FALSE, + TRUE, L, cm) ; + OK (ok) ; + } + else if (trial == 1) + { + ok = CHOLMOD(rowfac)(NULL, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(A, NULL, beta, 0, 0, NULL, cm) ; NOT (ok) ; + ok = CHOLMOD(rowfac)(AT, NULL, beta, 0, 0, L, cm) ; NOT (ok) ; + if (n > 1) + { + A1 = CHOLMOD(allocate_sparse)(1, 1, 1, TRUE, TRUE, 1, + CHOLMOD_PATTERN + DTYPE, cm) ; + OKP (A1) ; + ok = CHOLMOD(rowfac)(A1, NULL, beta, 0, 0, L, cm); NOT (ok); + ok = CHOLMOD(free_sparse)(&A1, cm) ; OK (ok); + } + } + else + { + // convert to symbolic LL' + ok = CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, FALSE, TRUE, + TRUE, L, cm) ; + OK (ok) ; + OK (L->is_ll) ; + } + } + + // factor + CHOLMOD(print_factor) (L, "L for rowfac", cm) ; + CHOLMOD(print_sparse) (A, "A for rowfac", cm) ; + + cm->dbound = 1e-15 ; + cm->sbound = 1e-6 ; + for (k = 0 ; ok && k < n ; k++) + { + if (!CHOLMOD(rowfac) (A, NULL, beta, k, k+1, L, cm)) + { + ok = FALSE ; + } + if (cm->status == CHOLMOD_NOT_POSDEF) + { + // LL' factorization failed; subsequent rowfac's should fail + k++ ; + ok = CHOLMOD(rowfac) (A, NULL, beta, k, k+1, L, cm) ; + NOT (ok) ; + ok = TRUE ; + } + } + cm->dbound = 0 ; + cm->sbound = 0 ; + + if (check_errors) + { + OK (ok) ; + ok = CHOLMOD(rowfac) (A, NULL, beta, n, n+1, L, cm) ; NOT (ok) ; + ok = TRUE ; + } + + // solve + if (ok) + { + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + cm->prefer_zomplex = FALSE ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + CHOLMOD(free_factor) (&L, cm) ; + } + + //-------------------------------------------------------------------------- + // factor again with entries in the (ignored) lower part A + //-------------------------------------------------------------------------- + + if (A->packed) + { + L = CHOLMOD(alloc_factor) (n, DTYPE, cm) ; + C = add_gunk (A) ; + + CHOLMOD(rowfac) (C, NULL, beta, 0, n, L, cm) ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + //-------------------------------------------------------------------------- + // factor again using rowfac_mask (for LPDASA only) + //-------------------------------------------------------------------------- + + r = raw_factor2 (A, 0., 0) ; + MAXERR (maxerr, r, 1) ; + + r = raw_factor2 (A, 1e-16, 0) ; + MAXERR (maxerr, r, 1) ; + + //-------------------------------------------------------------------------- + // free the problem + //-------------------------------------------------------------------------- + + CHOLMOD(free_sparse) (&AT, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free) (n, sizeof (Int), First, cm) ; + CHOLMOD(free) (n, sizeof (Int), Level, cm) ; + CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; + CHOLMOD(free) (n, sizeof (Int), Post, cm) ; + progress (0, '.') ; + return (maxerr) ; +} + +//------------------------------------------------------------------------------ +// raw_factor2 +//------------------------------------------------------------------------------ + +// A->stype can be 0 (lower), 1 (upper) or 0 (unsymmetric). In the first two +// cases, Ax=b is solved. In the third, A*A'x=b is solved. No analysis and no +// fill-reducing ordering is used. Both simplicial LL' and LDL' factorizations +// are used (testing rowfac_mask, for LPDASA only). + +double raw_factor2 (cholmod_sparse *A, double alpha, int domask) +{ + Int n, i, prefer_zomplex, is_ll, xtype, sorted, axtype, stype ; + Int *mask = NULL, *RLinkUp = NULL, nz = 0 ; + Int *Cp = NULL, added_gunk ; + double maxerr = 0, r = 0 ; + cholmod_sparse *AT = NULL, *C = NULL, *CT = NULL, *CC = NULL, *C2 = NULL ; + cholmod_factor *L = NULL ; + cholmod_dense *B = NULL, *X = NULL ; + double beta [2] ; + + if (A == NULL) + { + return (0) ; + } + n = A->nrow ; + if (n > 1000) + { + printf ("\nSkipping rowfac, matrix too large\n") ; + return (0) ; + } + axtype = A->xtype ; + beta [0] = alpha ; + beta [1] = 0 ; + + prefer_zomplex = (A->xtype == CHOLMOD_ZOMPLEX) ; + AT = CHOLMOD(transpose) (A, 2, cm) ; + + // ensure C has stype of 0 or 1. Do not prune any entries + stype = A->stype ; + if (stype >= 0) + { + A->stype = 0 ; + C = CHOLMOD(copy_sparse) (A, cm) ; + A->stype = stype ; + if (C) C->stype = stype ; + CT = AT ; + + } + else + { + C = AT ; + A->stype = 0 ; + CT = CHOLMOD(copy_sparse) (A, cm) ; + A->stype = stype ; + if (CT) CT->stype = stype ; + + // only domask if C is symmetric and upper part stored + domask = FALSE ; + + } + + mask = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + RLinkUp = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + + if (C && cm->status == CHOLMOD_OK) + { + for (i = 0 ; i < n ; i++) + { + mask [i] = -1 ; + RLinkUp [i] = i+1 ; + } + } + else + { + domask = FALSE ; + } + + if (C && !(C->packed) && !(C->sorted)) + { + // do not do the unpacked or unsorted cases + domask = FALSE ; + } + + // make a copy of C and add some gunk if stype > 0 + added_gunk = (C && C->stype > 0) ; + if (added_gunk) + { + C2 = add_gunk (C) ; + } + else + { + C2 = CHOLMOD(copy_sparse) (C, cm) ; + } + + CC = CHOLMOD(copy_sparse) (C2, cm) ; + + if (CC && domask) + { + Int *Cp, *Ci, p ; + Real *Cx, *Cz ; + + // this implicitly sets the first row/col of C to zero, except diag. + mask [0] = 1 ; + + // CC = C2, and then set the first row/col to zero, except diagonal + Cp = CC->p ; + Ci = CC->i ; + Cx = CC->x ; + Cz = CC->z ; + nz = Cp [n] ; + switch (C->xtype) + { + case CHOLMOD_REAL: + for (p = 1 ; p < nz ; p++) + { + if (Ci [p] == 0) Cx [p] = 0 ; + } + break ; + + case CHOLMOD_COMPLEX: + for (p = 1 ; p < nz ; p++) + { + if (Ci [p] == 0) + { + Cx [2*p ] = 0 ; + Cx [2*p+1] = 0 ; + } + } + break ; + + case CHOLMOD_ZOMPLEX: + for (p = 1 ; p < nz ; p++) + { + if (Ci [p] == 0) + { + Cx [p] = 0 ; + Cz [p] = 0 ; + } + } + break ; + } + } + + B = rhs (CC, 1, n, 0) ; + + for (sorted = 1 ; sorted >= 0 ; sorted--) + { + + if (!sorted) + { + if (C2 && !added_gunk) C2->sorted = FALSE ; + if (C) C->sorted = FALSE ; + if (CT) CT->sorted = FALSE ; + } + + for (is_ll = 0 ; is_ll <= 1 ; is_ll++) + { + for (xtype = 0 ; xtype <= 1 ; xtype++) + { + + L = CHOLMOD(alloc_factor) (n, DTYPE, cm) ; + if (L) L->is_ll = is_ll ; + + if (xtype) + { + CHOLMOD (change_factor) (axtype, is_ll, 0, 0, 1, L, cm) ; + } + + CHOLMOD(rowfac_mask) (sorted ? C : C2, + CT, beta, 0, n, mask, RLinkUp, L, cm) ; + + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + cm->prefer_zomplex = FALSE ; + + r = resid (CC, X, B) ; + MAXERR (maxerr, r, 1) ; + + printf ("rowfac mask: resid is %g\n", r) ; + + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + } + } + } + + CHOLMOD(free) (n, sizeof (Int), mask, cm) ; + CHOLMOD(free) (n, sizeof (Int), RLinkUp, cm) ; + + CHOLMOD(free_sparse) (&C2, cm) ; + CHOLMOD(free_sparse) (&CC, cm) ; + CHOLMOD(free_sparse) (&CT, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + + return (maxerr) ; +} diff --git a/CHOLMOD/Tcov/t_read_triplet.c b/CHOLMOD/Tcov/t_read_triplet.c new file mode 100644 index 0000000000..87b878a370 --- /dev/null +++ b/CHOLMOD/Tcov/t_read_triplet.c @@ -0,0 +1,249 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_read_triplet: read a triplet matrix +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Read a triplet matrix from a file. + +cholmod_triplet *read_triplet +( + FILE *f +) +{ + cholmod_triplet *T ; + Real *Tx, *Tz ; + long long x1, x2, x3, x4, x5 ; + Int *Ti, *Tj ; + Int n, j, k, nrow, ncol, nz, stype, arrowhead, tridiag_plus_denserow, + xtype, is_complex ; + char s [MAXLINE] ; + + //-------------------------------------------------------------------------- + // read in a triplet matrix from a file + //-------------------------------------------------------------------------- + + dot = 0 ; + xtype = 0 ; + if (fgets (s, MAXLINE, f) == NULL) + { + return (NULL) ; + } + + // header line: nrow ncol nz stype (xtype-1) + + x1 = 0 ; + x2 = 0 ; + x3 = 0 ; + x4 = 0 ; + x5 = 0 ; + k = sscanf (s, "%lld %lld %lld %lld %lld\n", &x1, &x2, &x3, &x4, &x5) ; + nrow = x1 ; + ncol = x2 ; + nz = x3 ; + stype = x4 ; + xtype = x5 ; + + xtype++ ; + is_complex = (xtype != CHOLMOD_REAL) ; + + printf ("read_triplet: nrow "ID" ncol "ID" nz "ID" stype "ID" xtype "ID"\n", + nrow, ncol, nz, stype, xtype) ; + + arrowhead = FALSE ; + tridiag_plus_denserow = FALSE ; + + n = MAX (nrow, ncol) ; + if (stype == 2) + { + // ignore nz and the rest of the file, and create an arrowhead matrix + arrowhead = TRUE ; + nz = nrow + ncol + 1 ; + stype = (nrow == ncol) ? (1) : (0) ; + } + else if (stype == 3) + { + tridiag_plus_denserow = TRUE ; + nrow = n ; + ncol = n ; + nz = 4*n + 4 ; + stype = 0 ; + } + + T = CHOLMOD(allocate_triplet) (nrow, ncol, nz, stype, + (is_complex ? CHOLMOD_ZOMPLEX : CHOLMOD_REAL) + DTYPE, cm) ; + if (T == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot create triplet matrix") ; + return (NULL) ; + } + Ti = T->i ; + Tj = T->j ; + Tx = T->x ; + Tz = T->z ; + + if (arrowhead) + { + for (k = 0 ; k < MIN (nrow,ncol) ; k++) + { + Ti [k] = k ; + Tj [k] = k ; + Tx [k] = nrow + xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = nrow + xrand (1) ; // RAND + } + } + for (j = 0 ; j < ncol ; j++) + { + Ti [k] = 0 ; + Tj [k] = j ; + Tx [k] = - xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = - xrand (1) ; // RAND + } + k++ ; + } + T->nnz = k ; + } + else if (tridiag_plus_denserow) + { + // dense row, except for the last column + for (k = 0 ; k < n-1 ; k++) + { + Ti [k] = 0 ; + Tj [k] = k ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + } + + // diagonal + for (j = 0 ; j < n ; j++) + { + Ti [k] = j ; + Tj [k] = j ; + Tx [k] = nrow + xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = nrow + xrand (1) ; // RAND + } + k++ ; + } + + // superdiagonal + for (j = 1 ; j < n ; j++) + { + Ti [k] = j-1 ; + Tj [k] = j ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + k++ ; + } + + // subdiagonal + for (j = 0 ; j < n-1 ; j++) + { + Ti [k] = j+1 ; + Tj [k] = j ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + k++ ; + } + + // a few extra terms in the last column + Ti [k] = MAX (0, n-3) ; + Tj [k] = n-1 ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + k++ ; + + Ti [k] = MAX (0, n-4) ; + Tj [k] = n-1 ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + k++ ; + + Ti [k] = MAX (0, n-5) ; + Tj [k] = n-1 ; + Tx [k] = xrand (1) ; // RAND + if (is_complex) + { + Tz [k] = xrand (1) ; // RAND + } + k++ ; + + T->nnz = k ; + } + else + { + if (is_complex) + { + for (k = 0 ; k < nz ; k++) + { + int64_t i, j ; + double x, z ; + if (fscanf (f, "%ld %ld %lg %lg\n", &i, &j, &x, &z) + == EOF) + { + ERROR (CHOLMOD_INVALID, "Error reading triplet matrix\n") ; + } + Ti [k] = i ; + Tj [k] = j ; + Tx [k] = x ; + Tz [k] = z ; + } + } + else + { + for (k = 0 ; k < nz ; k++) + { + int64_t i, j ; + double x ; + if (fscanf (f, "%ld %ld %lg\n", &i, &j, &x) == EOF) + { + ERROR (CHOLMOD_INVALID, "Error reading triplet matrix\n") ; + } + Ti [k] = i ; + Tj [k] = j ; + Tx [k] = x ; + } + } + T->nnz = nz ; + } + + CHOLMOD(triplet_xtype) (xtype + DTYPE, T, cm) ; + + //-------------------------------------------------------------------------- + // print the triplet matrix + //-------------------------------------------------------------------------- + + const int psave = cm->print ; + cm->print = 4 ; + CHOLMOD(print_triplet) (T, "T input", cm) ; + cm->print = psave ; + printf ("\n\n======================================================\n" + "Test matrix: "ID"-by-"ID" with "ID" entries, stype: "ID"\n", + (Int) T->nrow, (Int) T->ncol, (Int) T->nnz, (Int) T->stype) ; + return (T) ; +} + diff --git a/CHOLMOD/Tcov/t_rhs.c b/CHOLMOD/Tcov/t_rhs.c new file mode 100644 index 0000000000..1cde427a8d --- /dev/null +++ b/CHOLMOD/Tcov/t_rhs.c @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_rhs: create a right-hand side +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Create a right-hand-side, b = A*x, where x is a known solution + +cholmod_dense *rhs (cholmod_sparse *A, Int nrhs, Int d, int tweak) +{ + Int n ; + cholmod_dense *W, *Z, *B ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "cannot compute rhs") ; + return (NULL) ; + } + + n = A->nrow ; + + // B = zeros (n,rhs) but with leading dimension d + B = zeros (n, nrhs, d, A->xtype + DTYPE) ; + + //-------------------------------------------------------------------------- + // create a known solution + //-------------------------------------------------------------------------- + + Z = xtrue (n, nrhs, d, A->xtype + DTYPE, tweak) ; + + //-------------------------------------------------------------------------- + // compute B = A*Z or A*A'*Z + //-------------------------------------------------------------------------- + + if (A->stype == 0) + { + // W = A'*Z + W = CHOLMOD(zeros) (A->ncol, nrhs, A->xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A, TRUE, one, zero, Z, W, cm) ; + // B = A*W + CHOLMOD(sdmult) (A, FALSE, one, zero, W, B, cm) ; + CHOLMOD(free_dense) (&W, cm) ; + } + else + { + // B = A*Z + CHOLMOD(sdmult) (A, FALSE, one, zero, Z, B, cm) ; + } + CHOLMOD(free_dense) (&Z, cm) ; + return (B) ; +} + diff --git a/CHOLMOD/Tcov/t_solve.c b/CHOLMOD/Tcov/t_solve.c new file mode 100644 index 0000000000..c7d8f16170 --- /dev/null +++ b/CHOLMOD/Tcov/t_solve.c @@ -0,0 +1,1595 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_solve: test CHOLMOD solvers +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Test CHOLMOD for solving various systems of linear equations. + +#include "cm.h" + +#define NFTYPES 17 +Int ll_types [NFTYPES] = { 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0 } ; +Int pk_types [NFTYPES] = { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0 } ; +Int mn_types [NFTYPES] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 } ; +Int co_types [NFTYPES] = { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 } ; + +#define NRHS 9 + +#ifndef NDEBUG +#ifndef EXTERN +#define EXTERN extern +#endif +EXTERN int cholmod_dump, cholmod_l_dump ; +#endif + +//------------------------------------------------------------------------------ +// test_solver +//------------------------------------------------------------------------------ + +// Test solve(A) with various control parameters + +double test_solver (cholmod_sparse *A) +{ + double err, maxerr = 0 ; + int save ; + + for (cm->postorder = 0 ; cm->postorder <= 1 ; cm->postorder++) + { + + my_srand (42) ; // RAND reset + + // simplicial, no extra memory + printf ("test_solver: simplicial, no extra memory\n") ; + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->grow2 = 0 ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // simplicial, extra space in columns of L + printf ("test_solver: simplicial, extra space in columns of L\n") ; + cm->grow2 = 5 ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // supernodal + printf ("test_solver: supernodal\n") ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + save = cm->nthreads_max ; + cm->nthreads_max = -1 ; + err = solve (A) ; + cm->nthreads_max = save ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // supernodal, without final resymbol + printf ("test_solver: supernodal, without final resymbol\n") ; + cm->final_resymbol = FALSE ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // supernodal, with resymbol, final_super false + printf ("test_solver: supernodal, with resymbol\n") ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_asis = FALSE ; + cm->final_resymbol = TRUE ; + cm->final_super = FALSE ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // supernodal, with resymbol, final_super tree + printf ("test_solver: supernodal, with resymbol\n") ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_asis = FALSE ; + cm->final_resymbol = TRUE ; + cm->final_super = TRUE ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + // simplicial LL' + printf ("test_solver: simplicial LL', try NESDIS instead of METIS\n") ; + cm->supernodal = CHOLMOD_SIMPLICIAL ; + cm->final_ll = TRUE ; + cm->default_nesdis = TRUE ; + err = solve (A) ; + cm->default_nesdis = FALSE ; + MAXERR (maxerr, err, 1) ; + cm->final_ll = FALSE ; + printf ("test_solver err: %6.2e\n", err) ; + + // supernodal, without final resymbol, and no relaxed supernodes + printf ( "test_solver: supernodal, without final resymbol, " + "and no relaxed supernodes\n") ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + cm->final_asis = TRUE ; + cm->nrelax [0] = 0 ; + cm->nrelax [1] = 0 ; + cm->nrelax [2] = 0 ; + cm->zrelax [0] = 0 ; + cm->zrelax [1] = 0 ; + cm->zrelax [2] = 0 ; + cm->grow0 = 1 ; + cm->grow1 = 1 ; + cm->grow2 = 0 ; + err = solve (A) ; + MAXERR (maxerr, err, 1) ; + printf ("test_solver err: %6.2e\n", err) ; + + //---------------------------------------------------------------------- + // restore defaults + //---------------------------------------------------------------------- + + cm->dbound = 0.0 ; + cm->sbound = 0.0 ; + + cm->grow0 = 1.2 ; + cm->grow1 = 1.2 ; + cm->grow2 = 5 ; + + cm->final_asis = TRUE ; + cm->final_super = TRUE ; + cm->final_ll = FALSE ; + cm->final_pack = TRUE ; + cm->final_monotonic = TRUE ; + cm->final_resymbol = FALSE ; + + cm->supernodal = CHOLMOD_AUTO ; + cm->nrelax [0] = 4 ; + cm->nrelax [1] = 16 ; + cm->nrelax [2] = 48 ; + cm->zrelax [0] = 0.8 ; + cm->zrelax [1] = 0.1 ; + cm->zrelax [2] = 0.05 ; + + // do not restore these defaults: + // cm->maxrank = ... + // cm->metis_memory = 2.0 + // cm->metis_nswitch = 3000 + // cm->metis_dswitch = 0.66 + // cm->print = 3 + // cm->precise = FALSE + } + + progress (1, '.') ; + return (maxerr) ; +} + +//------------------------------------------------------------------------------ +// solve +//------------------------------------------------------------------------------ + +// solve Ax=b or AA'x=b, systems involving just L, D, or L', and update/downdate +// the system. Returns the worst-case residual. This routine keeps going if +// it runs out of memory (unless the error handler terminates it), because +// it is used both normally and in the memory tests. + +double solve (cholmod_sparse *A) +{ + double r, enorm, snorm, maxerr = 0, gnorm, anorm, bnorm, xnorm, norm, rcond; + cholmod_factor *L, *Lcopy, *L2 ; + cholmod_sparse *Lmat, *Lo, *D, *Up, *S, *LD, *LDL, *E, *I, *C, *CC, *Ct, + *Ssym, *Cperm, *C2, *S2, *H, *F, *Lo1, *Aboth, *Bset ; + cholmod_dense *X, *Cdense, *B, *Bcomplex, *Bzomplex, *Breal, *W, *R, + *A3, *C3, *E3 ; + cholmod_dense *B2, *B2complex, *B2zomplex, *B2real, *Ywork, *Ework ; + cholmod_sparse *AFt, *AF, *G, *RowK, *Bsparse, *Xsparse ; + Real *Cx ; + Int *P, *cset, *fset, *Parent, *Post, *RowCount, *ColCount, + *First, *Level, *rcount, *ccount, *Lp, *Li ; + Int p, i, j, k, n, nrhs, save, save2, csize, rank, nrow, ncol, is_ll, + xtype, isreal, prefer_zomplex, xtype2, save3 ; + cm->blas_ok = TRUE ; + int Lxtype ; + + Ywork = NULL ; + Ework = NULL ; + + if (cm->print > 1) + { + printf ("============================================== in solve:\n") ; + } + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "nothing to solve") ; + return (1) ; + } + + //-------------------------------------------------------------------------- + // construct right-hand-side (Ax=b if symmetric, AA'x=b otherwise) + //-------------------------------------------------------------------------- + + n = A->nrow ; + nrow = A->nrow ; + ncol = A->ncol ; + xtype = A->xtype ; + isreal = (xtype == CHOLMOD_REAL) ; + anorm = CHOLMOD(norm_sparse) (A, 1, cm) ; + save = cm->final_asis ; + cm->final_asis = TRUE ; + + B = rhs (A, NRHS, n, 0) ; + + Bcomplex = CHOLMOD(copy_dense) (B, cm) ; + CHOLMOD(dense_xtype) (CHOLMOD_COMPLEX + DTYPE, Bcomplex, cm) ; + + B2 = rhs (A, NRHS, n, 1) ; + + Breal = CHOLMOD(copy_dense) (B, cm) ; + CHOLMOD(dense_xtype) (CHOLMOD_REAL + DTYPE, Breal, cm) ; + + Bzomplex = rhs (A, NRHS, n, 2) ; + CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX + DTYPE, Bzomplex, cm) ; + + B2complex = rhs (A, NRHS, n, 3) ; + + B2real = rhs (A, NRHS, n, 4) ; + CHOLMOD(dense_xtype) (CHOLMOD_REAL + DTYPE, B2real, cm) ; + + B2zomplex = rhs (A, NRHS, n, 5) ; + CHOLMOD(dense_xtype) (CHOLMOD_ZOMPLEX + DTYPE, B2zomplex, cm) ; + + //-------------------------------------------------------------------------- + // analyze + //-------------------------------------------------------------------------- + + if (n < 100 && cm->nmethods == 1 && cm->method[0].ordering == CHOLMOD_GIVEN) + { + Int *UserPerm = prand (nrow) ; // RAND + CHOLMOD(print_perm) (UserPerm, nrow, nrow, "UserPerm", cm) ; + L = CHOLMOD(analyze_p) (A, UserPerm, NULL, 0, cm) ; + OK (CHOLMOD(print_common) ("36:cm with UserPerm", cm)) ; + CHOLMOD(free) (nrow, sizeof (Int), UserPerm, cm) ; + } + else + { + L = CHOLMOD(analyze) (A, cm) ; + } + + //-------------------------------------------------------------------------- + // test rowadd on a symbolic factor (real matrices only) + //-------------------------------------------------------------------------- + + if (isreal) + { + RowK = CHOLMOD(spzeros) (n, 1, 0, CHOLMOD_REAL, cm) ; + Lcopy = CHOLMOD(copy_factor) (L, cm) ; + if (n > 0) + { + // rowadd does not work on complex/zomplex matrices + CHOLMOD(rowadd) (0, RowK, Lcopy, cm) ; + CHOLMOD(check_factor) (Lcopy, cm) ; + } + CHOLMOD(free_sparse) (&RowK, cm) ; + CHOLMOD(free_factor) (&Lcopy, cm) ; + } + + //-------------------------------------------------------------------------- + // factorize + //-------------------------------------------------------------------------- + + CHOLMOD(factorize) (A, L, cm) ; + +// CHOLMOD(print_sparse) (A, "A here::", cm) ; +// CHOLMOD(print_factor) (L, "L here::", cm) ; + + // make a of copy of L->Perm, just for testing + Int *PP = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + if (PP != NULL && L != NULL && L->Perm != NULL) + { + memcpy (PP, L->Perm, nrow * sizeof (Int)) ; + } + + //-------------------------------------------------------------------------- + // various solves + //-------------------------------------------------------------------------- + + if (B != NULL) + { + // B->ncol = 1 ; + prefer_zomplex = (B->xtype == CHOLMOD_ZOMPLEX) ; + } + else + { + prefer_zomplex = FALSE ; + } + + for (k = 0 ; k <= 1 ; k++) + { + + cm->prefer_zomplex = k ; + + // compute the residual, X complex if L or B not real + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + rcond = CHOLMOD(rcond) (L, cm) ; + if (cm->print > 1) + { + printf ("rcond for solv2: %g k %d\n", rcond, (int) k) ; + } + + // now test the same thing, but with cholmod_solve2 + + CHOLMOD(solve2) (CHOLMOD_A, L, B2, NULL, &X, NULL, &Ywork, &Ework, cm) ; + r = resid (A, X, B2) ; + MAXERR (maxerr, r, 1) ; + + CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + // see what happens if X has the wrong size or type on input. This + // will free X on input, and reallocate it the right size and type + X = CHOLMOD(ones) (1, 1, CHOLMOD_REAL + DTYPE, cm) ; + CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + + // now X is OK, and so is E, but Y is null + CHOLMOD(solve2) (CHOLMOD_A, L, B, NULL, &X, NULL, &Ywork, &Ework, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, Bzomplex, cm) ; + r = resid (A, X, Bzomplex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // now test the same thing, but with cholmod_solve2 + CHOLMOD(solve2) (CHOLMOD_A, L, Bzomplex, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, Bzomplex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_A, L, B2zomplex, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, B2zomplex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + // complex right-hand-side + X = CHOLMOD(solve) (CHOLMOD_A, L, Bcomplex, cm) ; + r = resid (A, X, Bcomplex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // now test the same thing, but with cholmod_solve2 + CHOLMOD(solve2) (CHOLMOD_A, L, Bcomplex, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, Bcomplex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_A, L, B2complex, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, B2complex) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + // real right-hand-side + + X = CHOLMOD(solve) (CHOLMOD_A, L, Breal, cm) ; + r = resid (A, X, Breal) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // now test the same thing, but with cholmod_solve2 + CHOLMOD(solve2) (CHOLMOD_A, L, Breal, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, Breal) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_A, L, B2real, NULL, &X, NULL, + &Ywork, &Ework, cm) ; + r = resid (A, X, B2real) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + // sparse solve of Ax=b, b real + Bsparse = CHOLMOD(dense_to_sparse) (Breal, TRUE, cm) ; + Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; + r = resid_sparse (A, Xsparse, Bsparse) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_sparse) (&Bsparse, cm) ; + CHOLMOD(free_sparse) (&Xsparse, cm) ; + + // sparse solve of Ax=b, b complex + Bsparse = CHOLMOD(dense_to_sparse) (Bcomplex, TRUE, cm) ; + Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; + r = resid_sparse (A, Xsparse, Bsparse) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_sparse) (&Bsparse, cm) ; + CHOLMOD(free_sparse) (&Xsparse, cm) ; + + // sparse solve of Ax=b, b zomplex + Bsparse = CHOLMOD(dense_to_sparse) (Bzomplex, TRUE, cm) ; + Xsparse = CHOLMOD(spsolve) (CHOLMOD_A, L, Bsparse, cm) ; + r = resid_sparse (A, Xsparse, Bsparse) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_sparse) (&Bsparse, cm) ; + CHOLMOD(free_sparse) (&Xsparse, cm) ; + + } + + cm->prefer_zomplex = FALSE ; + + //-------------------------------------------------------------------------- + // sparse solve to compute inv(A) + //-------------------------------------------------------------------------- + + rcond = CHOLMOD(rcond) (L, cm) ; + if (cm->print > 1) + { + printf ("rcond: %g\n", rcond) ; + } + + #ifdef DOUBLE + bool rcond_ok = rcond > 1e-6 ; + #else + bool rcond_ok = rcond > 1e-3 ; + #endif + + if (n < 100 && A->stype != 0 && rcond_ok) + { + // solve A*C=I, so C should equal A inverse + I = CHOLMOD(speye) (n, n, A->xtype + DTYPE, cm) ; + C = CHOLMOD(spsolve) (CHOLMOD_A, L, I, cm) ; + CHOLMOD(sparse_xtype) (A->xtype + DTYPE, C, cm) ; + + // compute norm of A*C-I + + // E = A*C + E = CHOLMOD(ssmult) (A, C, 0, 2, false, cm) ; + + // r = norm (E-I) + F = CHOLMOD(add) (E, I, minusone, one, 2, false, cm) ; + r = CHOLMOD(norm_sparse) (F, 1, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + + // also use ptest to compute norm (E-I) + double r2 = ptest (E, I, PP, n) ; + + CHOLMOD(free_sparse) (&E, cm) ; + if (cm->print > 1) + { + printf ("norm (A*C-I): %g %g\n", r, r2) ; + } + MAXERR (maxerr, r, 1) ; + MAXERR (maxerr, r2, 1) ; + CHOLMOD(free_sparse) (&I, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + } + + //-------------------------------------------------------------------------- + // change complexity of L and solve again; test copy/change routines + //-------------------------------------------------------------------------- + + // change to complex, otherwise leave as + Lcopy = CHOLMOD(copy_factor) (L, cm) ; + CHOLMOD(factor_xtype) (CHOLMOD_COMPLEX + DTYPE, Lcopy, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, Lcopy, B, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_factor) (&Lcopy, cm) ; + + // change to zomplex LDL' + Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; + Lcopy = CHOLMOD(copy_factor) (L, cm) ; + CHOLMOD(check_factor) (L, cm) ; + CHOLMOD(change_factor) (Lxtype, FALSE, FALSE, TRUE, TRUE, Lcopy, cm) ; + CHOLMOD(factor_xtype) (CHOLMOD_ZOMPLEX + DTYPE, Lcopy, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, Lcopy, B, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_factor) (&Lcopy, cm) ; + + Lcopy = CHOLMOD(copy_factor) (L, cm) ; + CHOLMOD(change_factor) (Lxtype, TRUE, FALSE, FALSE, FALSE, Lcopy, cm) ; + CHOLMOD(check_factor) (L, cm) ; + CHOLMOD(free_factor) (&Lcopy, cm) ; + + CHOLMOD(free_factor) (&L, cm) ; + cm->final_asis = save ; + + //-------------------------------------------------------------------------- + // solve again, but use cm->final_asis as given + //-------------------------------------------------------------------------- + + if (n < 100 && cm->nmethods == 1 && cm->method[0].ordering == CHOLMOD_GIVEN) + { + Int *UserPerm = prand (nrow) ; // RAND + CHOLMOD(print_perm) (UserPerm, nrow, nrow, "UserPerm", cm) ; + L = CHOLMOD(analyze_p) (A, UserPerm, NULL, 0, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), UserPerm, cm) ; + } + else + { + L = CHOLMOD(analyze) (A, cm) ; + } + + CHOLMOD(factorize) (A, L, cm) ; + + // turn off memory tests [ + save3 = my_tries ; + my_tries = -1 ; + + if (B != NULL && Breal != NULL && Bcomplex != NULL && Bzomplex != NULL) + { + for (nrhs = 1 ; nrhs <= NRHS ; nrhs++) + { + for (cm->prefer_zomplex = 0 ; cm->prefer_zomplex <= 1 ; + cm->prefer_zomplex++) + { + B->ncol = nrhs ; + Breal->ncol = nrhs ; + Bcomplex->ncol = nrhs ; + Bzomplex->ncol = nrhs ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (A, X, B) ; + CHOLMOD(free_dense) (&X, cm) ; + MAXERR (maxerr, r, 1) ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, Breal, cm) ; + r = resid (A, X, Breal) ; + CHOLMOD(free_dense) (&X, cm) ; + MAXERR (maxerr, r, 1) ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, Bcomplex, cm) ; + r = resid (A, X, Bcomplex) ; + CHOLMOD(free_dense) (&X, cm) ; + MAXERR (maxerr, r, 1) ; + + X = CHOLMOD(solve) (CHOLMOD_A, L, Bzomplex, cm) ; + r = resid (A, X, Bzomplex) ; + CHOLMOD(free_dense) (&X, cm) ; + MAXERR (maxerr, r, 1) ; + } + } + } + cm->prefer_zomplex = FALSE ; + + my_tries = save3 ; + // turn memory tests back on, where we left off ] + + //-------------------------------------------------------------------------- + // convert L to LDL' packed or LL packed + //-------------------------------------------------------------------------- + + if (cm->print > 1) + { + printf ("before change factor : %d\n", L ? L->is_super : -1) ; + } + is_ll = (L == NULL) ? FALSE : (L->is_ll) ; + Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; + Lcopy = CHOLMOD(copy_factor) (L, cm) ; + CHOLMOD(change_factor) (Lxtype, is_ll, FALSE, TRUE, TRUE, Lcopy, cm) ; + if (cm->print > 1) + { + printf ("after change factor : %d\n", L ? L->is_super : -1) ; + } + + //-------------------------------------------------------------------------- + // extract L, D, and L' as matrices from Lcopy + //-------------------------------------------------------------------------- + + CHOLMOD(resymbol) (A, NULL, 0, TRUE, Lcopy, cm) ; + + Lmat = CHOLMOD(factor_to_sparse) (Lcopy, cm) ; + CHOLMOD(free_factor) (&Lcopy, cm) ; + if (Lmat != NULL && A != NULL && Lmat->xtype != A->xtype) + { + if (cm->print > 1) + { + printf ("change Lmat from xtype %d to %d\n", + Lmat->xtype, A->xtype) ; + } + CHOLMOD(sparse_xtype) (A->xtype + DTYPE, Lmat, cm) ; + } + CHOLMOD(check_sparse) (Lmat, cm) ; + + Lo = NULL ; + D = NULL ; + + Lxtype = (Lmat == NULL) ? CHOLMOD_REAL : (Lmat->xtype) ; + I = CHOLMOD(speye) (n, n, Lxtype + DTYPE, cm) ; + + if (!is_ll) + { + // factorization is LDL' = Lo*D*Up + Lo1 = CHOLMOD(band) (Lmat, -n, -1, 1, cm) ; + Lo = CHOLMOD(add) (Lo1, I, one, one, TRUE, TRUE, cm) ; + CHOLMOD(free_sparse) (&Lo1, cm) ; + D = CHOLMOD(band) (Lmat, 0, 0, 1, cm) ; + } + else + { + // factorization is LL' = Lo*D*Up + Lo = CHOLMOD(band) (Lmat, -n, 0, 1, cm) ; + D = CHOLMOD(speye) (n, n, Lxtype + DTYPE, cm) ; + } + + Up = CHOLMOD(transpose) (Lo, 2, cm) ; + + //-------------------------------------------------------------------------- + // compute 1-norm of (Lo*D*Up - PAP') or (Lo*D*Up - PAA'P') + //-------------------------------------------------------------------------- + + P = (L != NULL) ? (L->Perm) : NULL ; + S = NULL ; + G = NULL ; + + if (A->stype == 0) + { + // G = A*A', try with fset = prand (ncol) + fset = prand (ncol) ; // RAND + CHOLMOD(print_perm) (fset, ncol, ncol, "fset", cm) ; + AFt = CHOLMOD(ptranspose) (A, 2, NULL, fset, ncol, cm) ; + AF = CHOLMOD(transpose) (AFt, 2, cm) ; + + CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; + G = CHOLMOD(ssmult) (AF, AFt, 0, TRUE, TRUE, cm) ; + + // H = A*A' using aat + H = CHOLMOD(aat) (AF, NULL, 0, 2, cm) ; + + // enorm = norm (G-H) + E = CHOLMOD(add) (G, H, one, minusone, TRUE, FALSE, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + // also use ptest to compute enorm (G-H) + double enorm2 = ptest (G, H, PP, nrow) ; + + gnorm = CHOLMOD(norm_sparse) (G, 0, cm) ; + MAXERR (maxerr, enorm, gnorm) ; + MAXERR (maxerr, enorm2, gnorm) ; + if (cm->print > 1) + { + printf ("enorm %g %g gnorm %g hnorm %g\n", enorm, enorm2, gnorm, + CHOLMOD(norm_sparse) (H, 0, cm)) ; + } + if (gnorm > 0) + { + enorm /= gnorm ; + } + + #ifdef DOUBLE + OK (enorm < 1e-8) ; + #else + OK (enorm < 1e-4) ; + #endif + CHOLMOD(free_sparse) (&AFt, cm) ; + CHOLMOD(free_sparse) (&AF, cm) ; + CHOLMOD(free_sparse) (&H, cm) ; + } + else + { + // G = A + G = CHOLMOD(copy) (A, 0, 2, cm) ; + } + + if (A->stype == 0) + { + // S = PAA'P' + S = CHOLMOD(submatrix) (G, P, n, P, n, TRUE, FALSE, cm) ; + } + else + { + // S = PAP' + Aboth = CHOLMOD(copy) (A, 0, 2, cm) ; + S = CHOLMOD(submatrix) (Aboth, P, n, P, n, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&Aboth, cm) ; + } + + if (n < NSMALL) + { + // only do this for small test matrices, since L*D*L' can have many + // nonzero entries + // E = L*D*L' - S + + LD = CHOLMOD(ssmult) (Lo, D, 0, TRUE, FALSE, cm) ; + LDL = CHOLMOD(ssmult) (LD, Up, 0, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&LD, cm) ; + E = CHOLMOD(add) (LDL, S, one, minusone, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&LDL, cm) ; + + // e = norm (E) / norm (S) + enorm = CHOLMOD(norm_sparse) (E, 1, cm) ; + snorm = CHOLMOD(norm_sparse) (S, 0, cm) ; + MAXERR (maxerr, enorm, snorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + } + + // check the row/col counts + RowCount = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + ColCount = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Parent = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Post = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + First = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + Level = CHOLMOD(malloc) (n, sizeof (Int), cm) ; + rcount = CHOLMOD(calloc) (n, sizeof (Int), cm) ; + ccount = CHOLMOD(calloc) (n, sizeof (Int), cm) ; + + if (S != NULL && Lmat != NULL && RowCount != NULL && ColCount != NULL && + Parent != NULL && Post != NULL && First != NULL && Level != NULL && + rcount != NULL && ccount != NULL) + { + S->stype = 1 ; + + CHOLMOD(etree) (S, Parent, cm) ; + CHOLMOD(postorder) (Parent, n, NULL, Post, cm) ; + S->stype = -1 ; + CHOLMOD(rowcolcounts) (S, NULL, 0, Parent, Post, RowCount, ColCount, + First, Level, cm) ; + + Lp = Lmat->p ; + Li = Lmat->i ; + OK (Lmat->packed) ; + for (j = 0 ; j < n ; j++) + { + for (p = Lp [j] ; p < Lp [j+1] ; p++) + { + i = Li [p] ; + rcount [i]++ ; + ccount [j]++ ; + } + } + // a singular matrix will only be partially factorized + if (L->minor == (size_t) n) + { + for (j = 0 ; j < n ; j++) + { + OK (ccount [j] == ColCount [j]) ; + } + } + for (i = 0 ; i < (Int) (L->minor) ; i++) + { + OK (rcount [i] == RowCount [i]) ; + } + } + + CHOLMOD(free) (n, sizeof (Int), RowCount, cm) ; + CHOLMOD(free) (n, sizeof (Int), ColCount, cm) ; + CHOLMOD(free) (n, sizeof (Int), Parent, cm) ; + CHOLMOD(free) (n, sizeof (Int), Post, cm) ; + CHOLMOD(free) (n, sizeof (Int), First, cm) ; + CHOLMOD(free) (n, sizeof (Int), Level, cm) ; + CHOLMOD(free) (n, sizeof (Int), rcount, cm) ; + CHOLMOD(free) (n, sizeof (Int), ccount, cm) ; + + CHOLMOD(free_sparse) (&S, cm) ; + + //-------------------------------------------------------------------------- + // solve other systems + //-------------------------------------------------------------------------- + + // turn off memory tests [ + save3 = my_tries ; + my_tries = -1 ; + rcond = CHOLMOD(rcond) (L, cm) ; + + #ifdef DOUBLE + rcond_ok = rcond > 1e-6 ; + #else + rcond_ok = rcond > 1e-3 ; + #endif + + for (nrhs = 1 ; nrhs <= 4 ; nrhs++) // reduced here (6 to 4) + { + if (B == NULL) + { + break ; + } + + B->ncol = nrhs ; + + // solve Ax=b and compare with the sparse solve + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve LDL'x=b and compare with sparse solve + if (rcond_ok) + { + X = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; + // printf ("LDL'x=b %p %p %p\n", Lo, X, B) ; + r = resid3 (Lo, D, Up, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve DL'x=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_DLt, L, B, cm) ; + // printf ("DL'x=b %p %p %p\n", D, X, B) ; + r = resid3 (D, Up, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve LDx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_LD, L, B, cm) ; + // printf ("LDx=b %p %p %p\n", Lo, X, B) ; + r = resid3 (Lo, D, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve Lx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; + // printf ("Lx=b %p %p %p\n", Lo, X, B) ; + r = resid3 (Lo, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve L'x=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_Lt, L, B, cm) ; + // printf ("L'x=b %p %p %p\n", Up, X, B) ; + r = resid3 (Up, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // solve Dx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_D, L, B, cm) ; + // printf ("Dx=b %p %p %p\n", D, X, B) ; + r = resid3 (D, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + save2 = cm->prefer_zomplex ; + for (k = 0 ; k <= 1 ; k++) + { + cm->prefer_zomplex = k ; + + // x=Pb and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_P, L, B, cm) ; + r = pnorm (X, P, B, FALSE) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // x=P'b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_Pt, L, B, cm) ; + r = pnorm (X, P, B, TRUE) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + } + cm->prefer_zomplex = save2 ; + } + } + + // turn memory tests back on, where we left off ] + my_tries = save3 ; + + Real bx = 0 ; + Real bz = 0 ; + + if (n > 0 && B != NULL) + { + Real *Bx = B->x ; + Real *Bz = B->z ; + if (B->xtype == CHOLMOD_REAL) + { + bx = Bx [0] ; + } + else if (B->xtype == CHOLMOD_COMPLEX) + { + bx = Bx [0] ; + bz = Bx [1] ; + } + else + { + bx = Bx [0] ; + bz = Bz [0] ; + } + } + + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free_dense) (&B2, cm) ; + + //-------------------------------------------------------------------------- + // test the sparse solve + //-------------------------------------------------------------------------- + + // turn off memory tests for large matrices [ + if (n > 10) + { + save3 = my_tries ; + my_tries = -1 ; + } + + // get ready for sparse solve + Bset = CHOLMOD(allocate_sparse) (n, 1, 1, FALSE, TRUE, 0, + CHOLMOD_PATTERN + DTYPE, cm) ; + Lxtype = (L == NULL) ? CHOLMOD_REAL : L->xtype ; + B = CHOLMOD(zeros) (n, 1, Lxtype + DTYPE, cm) ; + + if (Bset != NULL && B != NULL && n > 0 && rcond_ok) + { + cholmod_sparse *Xset ; + cholmod_dense *X2 ; + Int *Bseti, *Bsetp, *Xseti ; + Real *X2x, *X1x ; + + Xset = NULL ; + X2 = NULL ; + + Bseti = Bset->i ; + Bsetp = Bset->p ; + Bsetp [0] = 0 ; + Bsetp [1] = 1 ; + Bseti [0] = 0 ; // first entry in b is nonzero, all others zero + Real *Bx = B->x ; + Real *Bz = B->z ; + + if (B->xtype == CHOLMOD_REAL) + { + Bx [0] = bx ; + } + else if (B->xtype == CHOLMOD_COMPLEX) + { + Bx [0] = bx ; + Bx [1] = bz ; + } + else + { + Bx [0] = bx ; + Bz [0] = bz ; + } + + // solve Ax=b and compare with the sparse solve + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + if (X != NULL) + { + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_work) (cm) ; + CHOLMOD(solve2) (CHOLMOD_A, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 Ax=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve LDL'x=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_LDLt, L, B, cm) ; + if (X != NULL) + { + r = resid3 (Lo, D, Up, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_LDLt, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 LDL'x=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve LDx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_LD, L, B, cm) ; + if (X != NULL) + { + r = resid3 (Lo, D, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_LD, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 LDx=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve DL'x=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_DLt, L, B, cm) ; + if (X != NULL) + { + r = resid3 (D, Up, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_DLt, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 DL'x=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve Lx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_L, L, B, cm) ; + if (X != NULL) + { + r = resid3 (Lo, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_L, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 Lx=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve L'x=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_Lt, L, B, cm) ; + if (X != NULL) + { + r = resid3 (Up, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_Lt, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 Ltx=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + + // solve Dx=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_D, L, B, cm) ; + if (X != NULL) + { + r = resid3 (D, NULL, NULL, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(solve2) (CHOLMOD_D, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 Dx=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; + +#if 0 +int sav = cm->print ; +cm->print = 5 ; +CHOLMOD(print_factor) (L, "L for with Px=b", cm) ; +CHOLMOD(print_sparse) (Bset, "Bset for with Px=b", cm) ; +CHOLMOD(print_dense) (B, "B for with Px=b", cm) ; + // solve Px=b and compare with sparse solve + X = CHOLMOD(solve) (CHOLMOD_P, L, B, cm) ; + if (X != NULL) + { + CHOLMOD(solve2) (CHOLMOD_P, L, B, Bset, &X2, &Xset, + &Ywork, &Ework, cm) ; + if (X2 != NULL) + { +CHOLMOD(print_dense) (X2, "X2 with Px=b", cm) ; +CHOLMOD(print_dense) (X, "X with Px=b", cm) ; + X2x = X2->x ; + X1x = X->x ; + r = fabs (X2x [0] - X1x [0]) ; + if (cm->print > 1) printf ("solve2 Px=b err %g\n", r) ; + MAXERR (maxerr, r, 1) ; + OK (r < 0.1) ; + } + } + CHOLMOD(free_dense) (&X, cm) ; +cm->print = sav ; +#endif + + CHOLMOD(free_sparse) (&Xset, cm) ; + CHOLMOD(free_dense) (&X2, cm) ; + CHOLMOD(free_dense) (&Ywork, cm) ; + CHOLMOD(free_dense) (&Ework, cm) ; + + } + + CHOLMOD(free_sparse) (&Bset, cm) ; + + // turn memory tests back on, where we left off ] + if (n > 10) + { + my_tries = save3 ; + } + + CHOLMOD(free_sparse) (&I, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&Lo, cm) ; + CHOLMOD(free_sparse) (&Up, cm) ; + CHOLMOD(free_sparse) (&Lmat, cm) ; + + //-------------------------------------------------------------------------- + // update the factorization (real matrices only) + //-------------------------------------------------------------------------- + + // turn off memory tests [ + save3 = my_tries ; + my_tries = -1 ; + + CHOLMOD(free_dense) (&B, cm) ; + B = rhs (A, 1, n, 0) ; + + Int rank_max = ((n < 100) ? 33 : 2) ; + + for (rank = 1 ; rcond_ok && isreal && rank <= rank_max ; rank++) + { + + // pick a random C + Cdense = CHOLMOD(zeros) (n, rank, CHOLMOD_REAL + DTYPE, cm) ; + + if (Cdense != NULL) + { + Cx = Cdense->x ; + for (k = 0 ; k < 10*rank ; k++) + { + i = nrand (n) ; // RAND + j = nrand (rank) ; // RAND + Cx [i+j*n] += xrand (1.) ; // RAND + } + } + + C = CHOLMOD(dense_to_sparse) (Cdense, TRUE, cm) ; + CHOLMOD(free_dense) (&Cdense, cm) ; + + // permute the rows according to L->Perm + Cperm = CHOLMOD(submatrix) (C, P, n, NULL, -1, TRUE, TRUE, cm) ; + + // update + CHOLMOD(updown) (TRUE, Cperm, L, cm) ; + CHOLMOD(free_sparse) (&Cperm, cm) ; + + // solve (G+C*C')x=b + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + // an alternative method would be to compute (G*x + C*(C'*x) - b) + + // compute S = G+C*C', with no sort + Ct = CHOLMOD(transpose) (C, 1, cm) ; + CC = CHOLMOD(ssmult) (C, Ct, 0, TRUE, FALSE, cm) ; + S = CHOLMOD(add) (G, CC, one, one, TRUE, TRUE, cm) ; + Ssym = CHOLMOD(copy) (S, 1, 1, cm) ; + CHOLMOD(free_sparse) (&CC, cm) ; + CHOLMOD(free_sparse) (&Ct, cm) ; + + // compute norm (S*x-b) + r = resid (Ssym, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + //---------------------------------------------------------------------- + // factor A+CC' from scratch, using same permutation + //---------------------------------------------------------------------- + + if (rank == 1) + { + save = cm->nmethods ; + save2 = cm->method [0].ordering ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_GIVEN ; + L2 = CHOLMOD(analyze_p) (Ssym, P, NULL, 0, cm) ; + cm->nmethods = save ; + cm->method [0].ordering = save2 ; + CHOLMOD(factorize) (Ssym, L2, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, L2, B, cm) ; + r = resid (Ssym, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_factor) (&L2, cm) ; + } + + CHOLMOD(free_sparse) (&Ssym, cm) ; + + //---------------------------------------------------------------------- + // downdate, with just the first half of C + //---------------------------------------------------------------------- + + csize = MAX (1, rank / 2) ; + cset = CHOLMOD(malloc) (csize, sizeof (Int), cm) ; + if (cset != NULL) + { + for (i = 0 ; i < csize ; i++) + { + cset [i] = i ; + } + } + C2 = CHOLMOD(submatrix) (C, NULL, -1, cset, csize, TRUE, TRUE, cm) ; + Cperm = CHOLMOD(submatrix) (C2, P, n, NULL, -1, TRUE, TRUE, cm) ; + CHOLMOD(free) (csize, sizeof (Int), cset, cm) ; + + CHOLMOD(updown) (FALSE, Cperm, L, cm) ; + CHOLMOD(free_sparse) (&Cperm, cm) ; + + // solve (G+C*C'-C2*C2')x=b + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + // This is an expensive way to compute the residual. A better method + // would be to compute (G*x + C*(C'*x) - C2*(C2'*x) - b), using sdmult. + // It is done just to test the ssmult routine. + + // compute S2 = G+C*C'-C2*C2', with no sort + Ct = CHOLMOD(transpose) (C2, 1, cm) ; + CC = CHOLMOD(ssmult) (C2, Ct, 0, TRUE, FALSE, cm) ; + S2 = CHOLMOD(add) (S, CC, one, minusone, TRUE, FALSE, cm) ; + CHOLMOD(free_sparse) (&CC, cm) ; + CHOLMOD(free_sparse) (&Ct, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + + // Ssym is a symmetric/upper copy of S2 + Ssym = CHOLMOD(copy) (S2, 1, 1, cm) ; + CHOLMOD(free_sparse) (&S2, cm) ; + + // compute norm (S2*x-b) + r = resid (Ssym, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + //---------------------------------------------------------------------- + // factor S2 scratch, using same permutation + //---------------------------------------------------------------------- + + if (rank == 1) + { + save = cm->nmethods ; + save2 = cm->method [0].ordering ; + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_GIVEN ; + L2 = CHOLMOD(analyze_p) (Ssym, P, NULL, 0, cm) ; + cm->nmethods = save ; + cm->method [0].ordering = save2 ; + CHOLMOD(factorize) (Ssym, L2, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, L2, B, cm) ; + r = resid (Ssym, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_factor) (&L2, cm) ; + } + + //---------------------------------------------------------------------- + // re-do the symbolic factorization on L + //---------------------------------------------------------------------- + + CHOLMOD(resymbol) (Ssym, NULL, 0, TRUE, L, cm) ; + + // solve (G+C*C'-C2*C2')x=b again + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + // compute norm (S2*x-b) + r = resid (Ssym, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + CHOLMOD(free_sparse) (&Ssym, cm) ; + + //---------------------------------------------------------------------- + // downdate, with the remaining part of C, to get original L + //---------------------------------------------------------------------- + + if (rank > csize) + { + cset = CHOLMOD(malloc) (rank-csize, sizeof (Int), cm) ; + if (cset != NULL) + { + for (i = csize ; i < rank ; i++) + { + cset [i-csize] = i ; + } + } + if (rank - csize == 4) + { + // test the subset print/check routine + CHOLMOD(print_subset) (cset, rank-csize, rank, "cset", cm) ; + } + C2 = CHOLMOD(submatrix) (C, NULL, -1, cset, rank-csize, TRUE, TRUE, + cm) ; + Cperm = CHOLMOD(submatrix) (C2, P, n, NULL, -1, TRUE, TRUE, cm) ; + + CHOLMOD(free) (rank-csize, sizeof (Int), cset, cm) ; + CHOLMOD(updown) (FALSE, Cperm, L, cm) ; + CHOLMOD(free_sparse) (&Cperm, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + + // solve the original system + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + + // compute the residual + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + } + + // turn memory tests back on, where we left off ] + my_tries = save3 ; + + CHOLMOD(free_sparse) (&G, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + + //-------------------------------------------------------------------------- + // factor again, then change the factor type many times + //-------------------------------------------------------------------------- + + C = CHOLMOD(copy_sparse) (A, cm) ; + if (C != NULL) + { + C->sorted = FALSE ; + } + L = CHOLMOD(analyze) (C, cm) ; + CHOLMOD(factorize) (C, L, cm) ; + + if (L != NULL && !(L->is_super)) + { + CHOLMOD(resymbol) (C, NULL, 0, TRUE, L, cm) ; + } + + CHOLMOD(free_dense) (&B, cm) ; + B = rhs (C, 1, n, 0) ; + + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + cm->prefer_zomplex = FALSE ; + r = resid (C, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + for (k = 0 ; k < NFTYPES ; k++) + { + + if (co_types [k] && n > 1) + { + // reallocate column zero of L, to make it non-monotonic + CHOLMOD(reallocate_column) (0, n, L, cm) ; + } + Lxtype = (L == NULL) ? CHOLMOD_REAL : (L->xtype) ; + + CHOLMOD(change_factor) (Lxtype, ll_types [k], FALSE, pk_types [k], + mn_types [k], L, cm) ; + + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + cm->prefer_zomplex = FALSE ; + r = resid (C, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + // reallocate a column and solve again + if (n > 3) + { + CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, TRUE, TRUE, L, cm) ; + CHOLMOD(reallocate_column) (0, n, L, cm) ; + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + cm->prefer_zomplex = FALSE ; + r = resid (C, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + + CHOLMOD(free_dense) (&B, cm) ; + CHOLMOD(free_dense) (&Breal, cm) ; + CHOLMOD(free_dense) (&Bcomplex, cm) ; + CHOLMOD(free_dense) (&Bzomplex, cm) ; + + CHOLMOD(free_dense) (&B2zomplex, cm) ; + CHOLMOD(free_dense) (&B2complex, cm) ; + CHOLMOD(free_dense) (&B2real, cm) ; + + //-------------------------------------------------------------------------- + // factorize and solve (A*A'+beta*I)x=b or A'x=b + //-------------------------------------------------------------------------- + + if (A->stype == 0) + { + Real *Rx, *Rz, *Xx, *Xz ; + double beta [2] ; + beta [0] = 3.14159 ; + beta [1] = 0 ; + L = CHOLMOD(analyze) (A, cm) ; + CHOLMOD(factorize_p) (A, beta, NULL, 0, L, cm) ; + + CHOLMOD(free_dense) (&B, cm) ; + B = rhs (A, 1, n, 0) ; + + cm->prefer_zomplex = prefer_zomplex ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + cm->prefer_zomplex = FALSE ; + + // compute the residual + + // W = A'*X + W = CHOLMOD(zeros) (ncol, 1, xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (A, 2, one, zero, X, W, cm) ; + + // R = B + R = CHOLMOD(copy_dense) (B, cm) ; + + // R = A*W - R + CHOLMOD(sdmult) (A, 0, one, minusone, W, R, cm) ; + + // R = R + beta*X + if (R != NULL && X != NULL) + { + Rx = R->x ; + Rz = R->z ; + Xx = X->x ; + Xz = X->z ; + + for (i = 0 ; i < nrow ; i++) + { + switch (xtype) + { + case CHOLMOD_REAL: + Rx [i] += beta [0] * Xx [i] ; + break ; + + case CHOLMOD_COMPLEX: + Rx [2*i ] += beta [0] * Xx [2*i ] ; + Rx [2*i+1] += beta [0] * Xx [2*i+1] ; + break ; + + case CHOLMOD_ZOMPLEX: + Rx [i] += beta [0] * Xx [i] ; + Rz [i] += beta [0] * Xz [i] ; + break ; + } + } + } + + r = CHOLMOD(norm_dense) (R, 2, cm) ; + bnorm = CHOLMOD(norm_dense) (B, 2, cm) ; + xnorm = CHOLMOD(norm_dense) (X, 2, cm) ; + norm = MAX (r, xnorm) ; + if (norm > 0) + { + r /= norm ; + } + MAXERR (maxerr, r, 1) ; + + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&R, cm) ; + CHOLMOD(free_dense) (&W, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + } + + //-------------------------------------------------------------------------- + // test rowdel and updown (real matrices only) + //-------------------------------------------------------------------------- + + if (isreal && A->stype == 1 && n > 0 && n < NLARGE) + { + Int save4, save5, save6 ; + save4 = cm->nmethods ; + save5 = cm->method [0].ordering ; + save6 = cm->supernodal ; + + cm->nmethods = 1 ; + cm->method [0].ordering = CHOLMOD_NATURAL ; + cm->supernodal = CHOLMOD_SUPERNODAL ; + + CHOLMOD(free_dense) (&B, cm) ; + B = rhs (A, 1, n, 0) ; + + L = CHOLMOD(analyze) (A, cm) ; + CHOLMOD(factorize) (A, L, cm) ; + + // solve Ax=b + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (A, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // determine the new system with row/column k missing + k = n/2 ; + S = CHOLMOD(copy) (A, 0, 1, cm) ; + RowK = CHOLMOD(submatrix) (S, NULL, -1, &k, 1, TRUE, TRUE, cm) ; +// CHOLMOD(print_sparse) (S, "S", cm) ; +// CHOLMOD(print_sparse) (RowK, "RowK of S", cm) ; + CHOLMOD(free_sparse) (&RowK, cm) ; + prune_row (S, k) ; + if (S != NULL) + { + S->stype = 1 ; + } + + // delete row k of L (converts to LDL') + CHOLMOD(rowdel) (k, NULL, L, cm) ; + CHOLMOD(resymbol) (S, NULL, 0, TRUE, L, cm) ; + + // solve with row k missing + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (S, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + + // factorize again + CHOLMOD(free_factor) (&L, cm) ; + L = CHOLMOD(analyze) (A, cm) ; + CHOLMOD(factorize) (A, L, cm) ; + + // rank-3 update (converts to LDL') and solve + C = CHOLMOD(speye) (n, 3, CHOLMOD_REAL + DTYPE, cm) ; + CC = CHOLMOD(aat) (C, NULL, 0, 1, cm) ; + S = CHOLMOD(add) (A, CC, one, one, TRUE, TRUE, cm) ; + if (S != NULL) + { + S->stype = 1 ; + } + CHOLMOD(updown) (TRUE, C, L, cm) ; + X = CHOLMOD(solve) (CHOLMOD_A, L, B, cm) ; + r = resid (S, X, B) ; + MAXERR (maxerr, r, 1) ; + CHOLMOD(free_dense) (&X, cm) ; + + // free everything + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_sparse) (&CC, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&S, cm) ; + CHOLMOD(free_factor) (&L, cm) ; + CHOLMOD(free_dense) (&B, cm) ; + + cm->nmethods = save4 ; + cm->method [0].ordering = save5 ; + cm->supernodal = save6 ; + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + CHOLMOD(free) (nrow, sizeof (Int), PP, cm) ; + progress (0, '.') ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_suitesparse.c b/CHOLMOD/Tcov/t_suitesparse.c new file mode 100644 index 0000000000..0987ffcfef --- /dev/null +++ b/CHOLMOD/Tcov/t_suitesparse.c @@ -0,0 +1,261 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_suitesparse: tests for SuiteSparse_config +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +#include + +typedef double (*hfunc_t) (double, double) ; +typedef int (*dfunc_t) (double, double, double, double, double *, double *) ; +typedef int (*printf_t) (const char *, ...) ; + +//------------------------------------------------------------------------------ +// my_printf +//------------------------------------------------------------------------------ + +int my_printf (const char *, ...) ; + +int my_printf (const char *fmt, ...) +{ + return (printf ("my_printf [%s]\n", fmt)) ; +} + +//------------------------------------------------------------------------------ +// my_hypot +//------------------------------------------------------------------------------ + +double my_hypot (double x, double z) ; + +double my_hypot (double x, double y) +{ + printf ("my_hypot\n") ; + return (sqrt (x*x + y*y)) ; +} + +//------------------------------------------------------------------------------ +// hypot_test +//------------------------------------------------------------------------------ + +static double hypot_test (double x, double y, double maxerr) +{ + hfunc_t hfunc = SuiteSparse_config_hypot_func_get ( ) ; + OKP (hfunc) ; + + double z1 = hfunc (x, y) ; + double z2 = hypot (x, y) ; + double err = fabs (z1-z2) ; + MAXERR (maxerr, err, 1) ; + + double z3 = SuiteSparse_hypot (x, y) ; + err = fabs (z1-z3) ; + MAXERR (maxerr, err, 1) ; + + double complex a = CMPLX (x, y) ; + double z4 = cabs (a) ; + err = fabs (z1-z4) ; + MAXERR (maxerr, err, 1) ; + + SuiteSparse_config_hypot_func_set (my_hypot) ; + double z5 = SuiteSparse_config_hypot (x, y) ; + err = fabs (z1-z5) ; + MAXERR (maxerr, err, 1) ; + + hfunc_t hfunc2 = SuiteSparse_config_hypot_func_get ( ) ; + OK (hfunc2 == my_hypot) ; + + SuiteSparse_config_hypot_func_set (hfunc) ; + + printf ("hypot: %g\n", maxerr) ; + return (maxerr) ; +} + +//------------------------------------------------------------------------------ +// my_div +//------------------------------------------------------------------------------ + +int my_div +( + double xr, double xi, // real and imaginary parts of x + double yr, double yi, // real and imaginary parts of y + double *zr, double *zi // real and imaginary parts of z +) ; + +int my_div +( + double xr, double xi, // real and imaginary parts of x + double yr, double yi, // real and imaginary parts of y + double *zr, double *zi // real and imaginary parts of z +) +{ + printf ("my_div\n") ; + double complex z = CMPLX (xr, xi) / CMPLX (yr, yi) ; + (*zr) = creal (z) ; + (*zi) = cimag (z) ; + return (yr == 0 && yi == 0) ; +} + +//------------------------------------------------------------------------------ +// div_test +//------------------------------------------------------------------------------ + +static double div_test (double xr, double xi, double yr, double yi, + double maxerr) +{ + dfunc_t dfunc = SuiteSparse_config_divcomplex_func_get ( ) ; + OKP (dfunc) ; + printf ("\n---------------------div_test:\ndfunc %p\n", dfunc) ; + printf ("SuiteSparse_divcomplex %p\n", SuiteSparse_divcomplex) ; + OKP (SuiteSparse_divcomplex) ; + + SuiteSparse_config_divcomplex_func_set (NULL) ; + dfunc = SuiteSparse_config_divcomplex_func_get ( ) ; + NOP (dfunc) ; + + SuiteSparse_config_divcomplex_func_set (SuiteSparse_divcomplex) ; + dfunc = SuiteSparse_config_divcomplex_func_get ( ) ; + OKP (dfunc) ; + + double zr1 = 0 ; + double zi1 = 0 ; + + double zr2 = 0 ; + double zi2 = 0 ; + + double zr3 = 0 ; + double zi3 = 0 ; + + double zr4 = 0 ; + double zi4 = 0 ; + + double complex x = CMPLX (xr, xi) ; + double complex y = CMPLX (yr, yi) ; + + bool ok1 = dfunc (xr, xi, yr, yi, &zr1, &zi1) ; + bool ok2 = SuiteSparse_divcomplex (xr, xi, yr, yi, &zr2, &zi2) ; + OK (ok1 == ok2) ; + double err1 = hypot (zr1-zr2, zi1-zi2) ; + MAXERR (maxerr, err1, 1) ; + + double complex z4 = x / y ; + double complex t = CMPLX (zr1, zi1) ; + double err2 = cabs (t-z4) ; + MAXERR (maxerr, err2, 1) ; + + bool ok3 = SuiteSparse_config_divcomplex (xr, xi, yr, yi, &zr3, &zi3) ; + OK (ok1 == ok3) ; + double err3 = hypot (zr1-zr3, zi1-zi3) ; + MAXERR (maxerr, err3, 1) ; + + SuiteSparse_config_divcomplex_func_set (my_div) ; + bool ok4 = SuiteSparse_config_divcomplex (xr, xi, yr, yi, &zr4, &zi4) ; + OK (ok1 == ok4) ; + double err4 = hypot (zr1-zr4, zi1-zi4) ; + MAXERR (maxerr, err4, 1) ; + + printf ("dfunc: (%g,%g)/(%g,%g) = (%g,%g)\n", xr, xi, yr, yi, zr1, zi1) ; + printf ("suite: (%g,%g)/(%g,%g) = (%g,%g)\n", xr, xi, yr, yi, zr2, zi2) ; + printf ("config1: (%g,%g)/(%g,%g) = (%g,%g)\n", xr, xi, yr, yi, zr3, zi3) ; + printf ("my_div: (%g,%g)/(%g,%g) = (%g,%g)\n", xr, xi, yr, yi, zr4, zi4) ; + printf ("clib: (%g,%g)/(%g,%g) = (%g,%g)\n", + creal (x), cimag (x), creal (y), cimag (y), creal (z4), cimag (z4)) ; + + printf ("errs: %g %g %g %g\n", err1, err2, err3, err4) ; + + SuiteSparse_config_divcomplex_func_set (dfunc) ; + + dfunc_t dfunc2 = SuiteSparse_config_divcomplex_func_get ( ) ; + OK (dfunc == dfunc2) ; + + return (maxerr) ; +} + +//------------------------------------------------------------------------------ +// suitesparse_tests +//------------------------------------------------------------------------------ + +double suitesparse_tests (void) +{ + + double maxerr = 0 ; + + //-------------------------------------------------------------------------- + // hypot + //-------------------------------------------------------------------------- + + hypot_test (3.4 , 2.3 , maxerr) ; + hypot_test (2.3 , 3.4 , maxerr) ; + hypot_test (3.4 , 1e-40, maxerr) ; + hypot_test (1e-40, 3.4 , maxerr) ; + + //-------------------------------------------------------------------------- + // divcomplex + //-------------------------------------------------------------------------- + + double xr = 1.2 ; + double xi = -1.2 ; + + double yr = 4.3 ; + double yi = 3.1 ; + + maxerr = div_test (xr, xi, yr, yi, maxerr) ; + maxerr = div_test ( 0, xi, yr, 0, maxerr) ; + maxerr = div_test (xr, xi, 0, yi, maxerr) ; + maxerr = div_test ( 0, xi, 0, yi, maxerr) ; + maxerr = div_test (xr, 0, 0, yi, maxerr) ; + + double w = INFINITY ; + maxerr = div_test (xr, xi, -w, w, maxerr) ; + maxerr = div_test (xr, xi, w, -w, maxerr) ; + maxerr = div_test (xr, xi, -w, -w, maxerr) ; + maxerr = div_test (xr, xi, w, w, maxerr) ; + + //-------------------------------------------------------------------------- + // BLAS + //-------------------------------------------------------------------------- + + const char *blas_library = SuiteSparse_BLAS_library ( ) ; + printf ("BLAS library: %s\n", blas_library) ; + int s = (int) SuiteSparse_BLAS_integer_size ( ) ; + printf ("BLAS integer size: %d\n", s) ; + + //-------------------------------------------------------------------------- + // printf + //-------------------------------------------------------------------------- + + printf_t pfunc = SuiteSparse_config_printf_func_get ( ) ; + printf ("printf: %p %p\n", pfunc, printf) ; + SuiteSparse_config_printf_func_set (NULL) ; + printf_t pfunc2 = SuiteSparse_config_printf_func_get ( ) ; + NOP (pfunc2) ; + + SuiteSparse_config_printf_func_set (my_printf) ; + pfunc2 = SuiteSparse_config_printf_func_get ( ) ; + OK (pfunc2 == my_printf) ; + + SuiteSparse_config_printf_func_set (pfunc) ; + + //-------------------------------------------------------------------------- + // calloc + //-------------------------------------------------------------------------- + + int *p = SuiteSparse_config_calloc (10, sizeof (int)) ; + OKP (p) ; + for (int k = 0 ; k < 10 ; k++) + { + OK (p [k] == 0) ; + } + SuiteSparse_config_free (p) ; + + //-------------------------------------------------------------------------- + // return results + //-------------------------------------------------------------------------- + + printf ("suitesparse maxerr %g\n", maxerr) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_test_ops.c b/CHOLMOD/Tcov/t_test_ops.c new file mode 100644 index 0000000000..85ff85f891 --- /dev/null +++ b/CHOLMOD/Tcov/t_test_ops.c @@ -0,0 +1,1151 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_test_ops: test CHOLMOD matrix operators +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Test CHOLMOD matrix operators. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// nzdiag +//------------------------------------------------------------------------------ + +// Count the entries on the diagonal + +Int nzdiag (cholmod_sparse *A) +{ + Int *Ap, *Ai, *Anz ; + Int nnzdiag, packed, j, p, i, pend, ncol ; + if (A == NULL) + { + return (EMPTY) ; + } + nnzdiag = 0 ; + ncol = A->ncol ; + Ap = A->p ; + Ai = A->i ; + Anz = A->nz ; + packed = A->packed ; + for (j = 0 ; j < ncol ; j++) + { + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + if (i == j) + { + nnzdiag++ ; + } + } + } + return (nnzdiag) ; +} + +//------------------------------------------------------------------------------ +// check_partition +//------------------------------------------------------------------------------ + +// Check a node separator, and return the # of nodes in the node separator or +// -1 if the separater is invalid. A node j is in the left part if +// Part [j] = 0, in the right part if Part [j] = 1, and in the separator if +// Part [j] = 2. + +Int check_partition (cholmod_sparse *A, Int *Part) +{ + Int *Ap, *Ai, *Anz ; + Int chek [3], which, i, j, p, n, pend, packed ; + + if (A == NULL || Part == NULL || A->nrow != A->ncol) + { + // printf ("A NULL, no Partition, or rectangular\n") ; + return (EMPTY) ; + } + n = A->nrow ; + Ap = A->p ; + Ai = A->i ; + Anz = A->nz ; + packed = A->packed ; + + chek [0] = 0 ; + chek [1] = 0 ; + chek [2] = 0 ; + + // printf ("\ncheck partition:\n") ; + for (j = 0 ; j < n ; j++) + { + which = Part [j] ; + // printf ("node "ID" in Part "ID"\n", j, which) ; + p = Ap [j] ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + for ( ; p < pend ; p++) + { + i = Ai [p] ; + // printf (" neighbor "ID" in part "ID"\n", i, Part [i]) ; + if (which == 0) + { + if (Part [i] == 1) + { + // printf (" broken!\n") ; + return (EMPTY) ; + } + } + else if (which == 1) + { + if (Part [i] == 0) + { + // printf (" broken!\n") ; + return (EMPTY) ; + } + } + } + if (which < 0 || which > 2) + { + // printf (" node j, invalid partition, broken!\n") ; + return (EMPTY) ; + } + chek [which]++ ; + } + // printf ("nodes in left: "ID" right: "ID" separator: "ID"\n", + // chek [0], chek [1], chek [2]) ; + return (chek [2]) ; +} + +//------------------------------------------------------------------------------ +// check_equality +//------------------------------------------------------------------------------ + +// Ensure two sparse matrices are identical. + +static void check_equality (cholmod_sparse *E, cholmod_sparse *D, Int xtype) +{ + Real *Ex, *Ez, *Dx, *Dz ; + Int *Ep, *Ei, *Dp, *Di ; + Int j, nz, p, ncol ; + + if (E == NULL || D == NULL || D->xtype != xtype || E->xtype != xtype) + { + return ; + } + + Ep = E->p ; + Ei = E->i ; + Ex = E->x ; + Ez = E->z ; + + Dp = D->p ; + Di = D->i ; + Dx = D->x ; + Dz = D->z ; + + OK (E->ncol == D->ncol) ; + OK (E->nrow == D->nrow) ; + OK (E->packed == D->packed) ; + + ncol = E->ncol ; + + for (j = 0 ; j <= ncol ; j++) + { + OK (Ep [j] == Dp [j]) ; + } + nz = Ep [ncol] ; + + for (p = 0 ; p < nz ; p++) + { + OK (Ei [p] == Di [p]) ; + } + + if (xtype == CHOLMOD_REAL) + { + for (p = 0 ; p < nz ; p++) + { + OK (Ex [p] == Dx [p]) ; + } + } + else if (xtype == CHOLMOD_COMPLEX) + { + for (p = 0 ; p < 2*nz ; p++) + { + OK (Ex [p] == Dx [p]) ; + } + } + else if (xtype == CHOLMOD_ZOMPLEX) + { + for (p = 0 ; p < nz ; p++) + { + OK (Ex [p] == Dx [p]) ; + OK (Ez [p] == Dz [p]) ; + } + } +} + +//------------------------------------------------------------------------------ +// test_ops +//------------------------------------------------------------------------------ + +// Test various matrix operations. + +double test_ops (cholmod_sparse *A) +{ + double maxerr = 0, r, x, anorm, r1, rinf ; + Real *Sx, *Sz ; + Int *Pinv, *P, *Si, *Sj, *Q, *Qinv, *fset, *Partition ; + cholmod_triplet *S ; + cholmod_sparse *C, *D, *E, *F, *G, *H, *AT, *Zs ; + cholmod_dense *X, *Y ; + Int n, kk, k, nrow, ncol, len, nz, ok, i, j, stype, nmin, mode, + xtype, xtype2, mtype, asym, xmatched, pmatched, nzoffdiag, nz_diag ; + size_t nz1, nz2 ; + void (*save) (int, const char *, int, const char *) ; + double alpha [2], beta [2] ; + Real *Xx ; + FILE *f ; + int option, save3 ; + + if (A == NULL) + { + ERROR (CHOLMOD_INVALID, "nothing for test_ops") ; + return (1) ; + } + + nrow = A->nrow ; + ncol = A->ncol ; + H = NULL ; + n = MAX (nrow, ncol) ; + nmin = MIN (nrow, ncol) ; + xtype = A->xtype ; + + //-------------------------------------------------------------------------- + // norm + //-------------------------------------------------------------------------- + + CHOLMOD(print_sparse) (A, "A for testops", cm) ; + r1 = CHOLMOD(norm_sparse) (A, 1, cm) ; + rinf = CHOLMOD(norm_sparse) (A, 0, cm) ; + + anorm = r1 ; + + // E = pattern of A + E = CHOLMOD(copy) (A, 0, 0, cm) ; +// CHOLMOD(print_sparse) (E, "E = pattern of A", cm) ; +// int64_t enz = CHOLMOD (nnz) (E, cm) ; +// int64_t anz = CHOLMOD (nnz) (A, cm) ; +// if (E->stype == A->stype) { OK (enz == anz) ; } + r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; + rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; + OK (r1 <= nrow) ; + OK (rinf <= ncol) ; + CHOLMOD(free_sparse) (&E, cm) ; + + // E = pattern of A, but exclude the diagonal + E = CHOLMOD(copy) (A, 0, -1, cm) ; +// CHOLMOD(print_sparse) (E, "E = spones (A), excl diag", cm) ; + r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; + rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; + if (nrow < ncol) + { + OK (r1 <= nrow) ; + OK (rinf < MAX (1,ncol)) ; + } + else + { + OK (r1 < MAX (1,nrow)) ; + OK (rinf <= ncol) ; + } + CHOLMOD(free_sparse) (&E, cm) ; + + //-------------------------------------------------------------------------- + // copy + //-------------------------------------------------------------------------- + + if (A->stype) + { + // E = tril (A), no diagonal + E = CHOLMOD(copy) (A, -1, -1, cm) ; + CHOLMOD(band_inplace) (0, n, 0, E, cm) ; + nz = CHOLMOD(nnz) (E, cm) ; + if (E != NULL) + { + OK (nz == 0) ; + } + CHOLMOD(free_sparse) (&E, cm) ; + } + + // E = -2:2 bands of A + nz2 = CHOLMOD(band_nnz) (A, -2, 2, false, cm) ; + E = CHOLMOD(band) (A, -2, 2, 0, cm) ; + nz = CHOLMOD(nnz) (E, cm) ; + if (E != NULL) + { + OK (nz == nz2) ; + } + CHOLMOD(free_sparse) (&E, cm) ; + + //-------------------------------------------------------------------------- + // read/write + //-------------------------------------------------------------------------- + + // delete the contents of the temp1.mtx and temp2.mtx file + f = fopen ("temp1.mtx", "w") ; + fprintf (f, "temp1\n") ; + fclose (f) ; + + f = fopen ("temp3.mtx", "w") ; + fprintf (f, "temp3\n") ; + fclose (f) ; + + CHOLMOD(free_work) (cm) ; + + f = fopen ("temp1.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; + fclose (f) ; +// printf ("write_sparse, asym: "ID"\n", asym) ; + OK (IMPLIES (A != NULL, asym > EMPTY)) ; + + f = fopen ("temp1.mtx", "r") ; + C = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; + fclose (f) ; +// printf ("got_sparse\n") ; + CHOLMOD(free_sparse) (&C, cm) ; + + save3 = A->xtype ; + A->xtype = CHOLMOD_PATTERN ; + f = fopen ("temp3.mtx", "w") ; + asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; + A->xtype = save3 ; + fclose (f) ; +// printf ("write_sparse3, asym: "ID"\n", asym) ; + + f = fopen ("temp3.mtx", "r") ; + C = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; + fclose (f) ; +// printf ("got_sparse3\n") ; + CHOLMOD(free_sparse) (&C, cm) ; + + for (i = 0 ; i <= 1 ; i++) + { + + f = fopen ("temp2.mtx", "w") ; + fprintf (f, "temp2\n") ; + fclose (f) ; + + X = CHOLMOD(ones) (4, 4, CHOLMOD_REAL + DTYPE, cm) ; + if (X != NULL) + { + Xx = X->x ; + Xx [0] = (i == 0) ? 1.1e308 : -1.1e308 ; + } + f = fopen ("temp2.mtx", "w") ; + ok = CHOLMOD(write_dense) (f, X, "comments.txt", cm) ; + fclose (f) ; + + f = fopen ("temp2.mtx", "r") ; + Y = CHOLMOD(read_dense2) (f, DTYPE, cm) ; + fclose (f) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + } + + //-------------------------------------------------------------------------- + // symmetry + //-------------------------------------------------------------------------- + + CHOLMOD(free_work) (cm) ; + xmatched = 0 ; + pmatched = 0 ; + nzoffdiag = 0 ; + nz_diag = 0 ; + for (option = 0 ; option <= 2 ; option++) + { + asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, &nzoffdiag, + &nz_diag, cm); + printf + ("symmetry, asym: "ID" matched "ID" "ID" offdiag "ID" diag "ID"\n", + asym, xmatched, pmatched, nzoffdiag, nz_diag) ; + } + + //-------------------------------------------------------------------------- + // transpose + //-------------------------------------------------------------------------- + + C = CHOLMOD(allocate_sparse) (A->ncol, A->nrow, A->nzmax, TRUE, TRUE, + -(A->stype), A->xtype + DTYPE, cm) ; + D = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, TRUE, TRUE, + A->stype, A->xtype + DTYPE, cm) ; + CHOLMOD(free_work) (cm) ; + ok = (C != NULL && D != NULL) ; + + // C = A' + if (ok) + { + if (A->stype) + { + ok = CHOLMOD(transpose_sym) (A, 2, NULL, C, cm) ; + } + else + { + ok = CHOLMOD(transpose_unsym) (A, 2, NULL, NULL, 0, C, cm) ; + } + OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; + } + + // D = C' + if (ok) + { + if (A->stype) + { + ok = CHOLMOD(transpose_sym) (C, 2, NULL, D, cm) ; + } + else + { + ok = CHOLMOD(transpose_unsym) (C, 2, NULL, NULL, 0, D, cm) ; + } + OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; + } + + if (ok) + { + ok = CHOLMOD(check_sparse) (D, cm) ; + OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; + } + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + + //-------------------------------------------------------------------------- + // C = A with jumbled triplets + //-------------------------------------------------------------------------- + + S = CHOLMOD(sparse_to_triplet) (A, cm) ; // [ + + if (S != NULL && nmin > 0 && S->nnz > 0) + { + + // double the number of entries in S + nz1 = S->nzmax ; + nz2 = 2*nz1 ; + ok = CHOLMOD(reallocate_triplet) (nz2, S, cm) ; + + if (ok) + { + // add duplicate entries, but keep the matrix the same + OK (S->nzmax == nz2) ; + Si = S->i ; + Sj = S->j ; + Sx = S->x ; + Sz = S->z ; + + for (k = nz1 ; k < ((Int) nz2) ; k++) + { + kk = nrand (k) ; // RAND + Si [k] = Si [kk] ; + Sj [k] = Sj [kk] ; + + if (S->xtype == CHOLMOD_REAL) + { + x = Sx [kk] * (xrand (4.) - 2) ; // RAND + Sx [k] = x ; + Sx [kk] -= x ; + } + else if (S->xtype == CHOLMOD_COMPLEX) + { + x = Sx [2*kk] * (xrand (4.) - 2) ; // RAND + Sx [2*k] = x ; + Sx [2*kk] -= x ; + + x = Sx [2*kk+1] * (xrand (4.) - 2) ; // RAND + Sx [2*k+1] = x ; + Sx [2*kk+1] -= x ; + } + else + { + x = Sx [kk] * (xrand (4.) - 2) ; // RAND + Sx [k] = x ; + Sx [kk] -= x ; + + x = Sz [kk] * (xrand (4.) - 2) ; // RAND + Sz [k] = x ; + Sz [kk] -= x ; + } + } + + // randomly jumble the entries + for (k = 0 ; k < ((Int) (nz2-1)) ; k++) + { + kk = k + nrand (nz2-k) ; // RAND + i = Si [k] ; + Si [k] = Si [kk] ; + Si [kk] = i ; + j = Sj [k] ; + Sj [k] = Sj [kk] ; + Sj [kk] = j ; + + if (S->xtype == CHOLMOD_REAL) + { + x = Sx [k] ; + Sx [k] = Sx [kk] ; + Sx [kk] = x ; + } + else if (S->xtype == CHOLMOD_COMPLEX) + { + x = Sx [2*k] ; + Sx [2*k] = Sx [2*kk] ; + Sx [2*kk] = x ; + x = Sx [2*k+1] ; + Sx [2*k+1] = Sx [2*kk+1] ; + Sx [2*kk+1] = x ; + } + else + { + x = Sx [k] ; + Sx [k] = Sx [kk] ; + Sx [kk] = x ; + x = Sz [k] ; + Sz [k] = Sz [kk] ; + Sz [kk] = x ; + } + } + S->nnz = nz2 ; + } + else + { + OK (S->nzmax == nz1) ; + OK (S->nnz == nz1) ; + } + } + + C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; // [ + Zs = CHOLMOD(spzeros) (nrow, ncol, 1, xtype + DTYPE, cm) ; // [ + G = NULL ; + F = NULL ; + + // G=A+0 + G = CHOLMOD(add) (A, Zs, one, one, TRUE, TRUE, cm) ; // [ + + // F = G-C + F = CHOLMOD(add) (G, C, one, minusone, TRUE, TRUE, cm) ; // [ + + r = CHOLMOD(norm_sparse) (F, 1, cm) ; + MAXERR (maxerr, r, anorm) ; + r = CHOLMOD(norm_sparse) (F, 0, cm) ; + CHOLMOD(drop) (0, F, cm) ; + rinf = CHOLMOD(norm_sparse) (F, 0, cm) ; + if (F != NULL) + { + printf ("r %g rinf %g\n", r, rinf) ; + OK (r == rinf) ; + } + MAXERR (maxerr, r, anorm) ; + MAXERR (maxerr, rinf, anorm) ; + + // E = F, with change of type and dropping small entries + for (stype = -1 ; stype <= 1 ; stype++) + { + if (stype != 0 && (F != NULL && F->nrow != F->ncol)) + { + continue ; + } + for (mode = 0 ; mode <= 1 ; mode++) + { + E = CHOLMOD(copy) (F, stype, mode, cm) ; // [ + CHOLMOD(drop) (1e-16, E, cm) ; + r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; + rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; + if (E != NULL) + { + if (mode == 0) + { + // pattern only + OK (r1 <= nrow) ; + OK (rinf <= ncol) ; + } + else + { + MAXERR (maxerr, r1, anorm) ; + MAXERR (maxerr, rinf, anorm) ; + } + } + CHOLMOD(free_sparse) (&E, cm) ; // ] + } + } + + CHOLMOD(free_sparse) (&F, cm) ; // ] + CHOLMOD(free_sparse) (&G, cm) ; // ] + + Y = CHOLMOD(ones) (nrow, 1, xtype + DTYPE, cm) ; // [ + X = CHOLMOD(ones) (ncol, 1, xtype + DTYPE, cm) ; // [ + alpha [0] = 0 ; + alpha [1] = 0 ; + beta [0] = 2 ; + beta [1] = 0 ; + // Y = 0*A*X + 2*Y + CHOLMOD(sdmult) (A, FALSE, alpha, beta, X, Y, cm) ; + r = CHOLMOD(norm_dense) (Y, 0, cm) ; + if (Y != NULL && X != NULL && A != NULL) + { + OK ((nrow == 0) ? (r == 0) : (r == 2)) ; + } + + alpha [0] = 1 ; + // Y = 1*(0)*X + 2*Y + CHOLMOD(sdmult) (Zs, FALSE, alpha, beta, X, Y, cm) ; + r = CHOLMOD(norm_dense) (Y, 0, cm) ; + if (Y != NULL && X != NULL && A != NULL) + { + OK ((nrow == 0) ? (r == 0) : (r == 4)) ; + } + + CHOLMOD(free_dense) (&X, cm) ; // ] + CHOLMOD(free_dense) (&Y, cm) ; // ] + + CHOLMOD(free_sparse) (&Zs, cm) ; // ] + CHOLMOD(free_sparse) (&C, cm) ; // ] + CHOLMOD(free_triplet) (&S, cm) ; // ] + + //-------------------------------------------------------------------------- + // C = P*A*Q in triplet form + //-------------------------------------------------------------------------- + + S = CHOLMOD(sparse_to_triplet) (A, cm) ; + P = prand (nrow) ; // RAND + CHOLMOD(print_perm) (P, nrow, nrow, "P", cm) ; + if (A->stype == 0) + { + Q = prand (ncol) ; // RAND + CHOLMOD(print_perm) (Q, ncol, ncol, "Q", cm) ; + } + else + { + // if A is symmetric, and stored in either upper or lower form, then + // the following code only works if P = Q + Q = P ; + } + Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Qinv = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; + Partition = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + + if (Pinv != NULL && Qinv != NULL && P != NULL && Q != NULL && S != NULL) + { + Si = S->i ; + Sj = S->j ; + nz = S->nnz ; + for (k = 0 ; k < nrow ; k++) + { + Pinv [P [k]] = k ; + } + for (k = 0 ; k < ncol ; k++) + { + Qinv [Q [k]] = k ; + } + for (k = 0 ; k < nz ; k++) + { + Si [k] = Pinv [Si [k]] ; + } + for (k = 0 ; k < nz ; k++) + { + Sj [k] = Qinv [Sj [k]] ; + } + } + + C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; + D = NULL ; + E = NULL ; + F = NULL ; + G = NULL ; + + //-------------------------------------------------------------------------- + // E = P*A*Q in sparse form + //-------------------------------------------------------------------------- + + D = CHOLMOD(copy) (A, 0, 1, cm) ; + E = CHOLMOD(submatrix) (D, P, nrow, Q, ncol, TRUE, FALSE, cm) ; + CHOLMOD(sort) (E, cm) ; + + //-------------------------------------------------------------------------- + // F = E-G + //-------------------------------------------------------------------------- + + G = CHOLMOD(copy) (C, 0, 1, cm) ; + F = CHOLMOD(add) (E, G, one, minusone, TRUE, TRUE, cm) ; + CHOLMOD(drop) (0, F, cm) ; + nz = CHOLMOD(nnz) (F, cm) ; + if (F != NULL) + { + OK (nz == 0) ; + } + + CHOLMOD(free_sparse) (&F, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&H, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_triplet) (&S, cm) ; + + //-------------------------------------------------------------------------- + // submatrix + //-------------------------------------------------------------------------- + + if (A->stype == 0) + { + // E = A(:,:) + E = CHOLMOD(submatrix) (A, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; + // C = A-E + C = CHOLMOD(add) (A, E, one, minusone, TRUE, TRUE, cm) ; + ok = CHOLMOD(drop) (0., C, cm) ; + nz = CHOLMOD(nnz) (C, cm) ; + if (C != NULL) + { + OK (nz == 0) ; + } + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + } + + //-------------------------------------------------------------------------- + // test band and add, unsymmetric + //-------------------------------------------------------------------------- + + // E = A + E = CHOLMOD(copy) (A, 0, 2, cm) ; + + // E = triu (E) + CHOLMOD(band_inplace) (0, ncol, 1, E, cm) ; + + // F = A + F = CHOLMOD(copy) (A, 0, 2, cm) ; + + // F = tril(F,-1) + CHOLMOD(band_inplace) (-nrow, -1, 1, F, cm) ; + + // G = E+F + G = CHOLMOD(add) (E, F, one, one, 2, true, cm) ; + + // D = A-G, which should be empty + D = CHOLMOD(add) (G, A, one, minusone, 2, true, cm) ; + + CHOLMOD(drop) (0, D, cm) ; + nz = CHOLMOD(nnz) (D, cm) ; + if (D != NULL) + { + OK (nz == 0) ; + } + + CHOLMOD(free_sparse) (&F, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + D = CHOLMOD(band) (A, 1, -1, 0, cm) ; + nz = CHOLMOD(nnz) (D, cm) ; + if (D != NULL) + { + OK (nz == 0) ; + } + CHOLMOD(free_sparse) (&D, cm) ; + + D = CHOLMOD(band) (A, 0, 0, 0, cm) ; + nz = CHOLMOD(nnz) (D, cm) ; + if (D != NULL) + { + OK (nz == nzdiag (D)) ; + } + + CHOLMOD(free_sparse) (&D, cm) ; + + //-------------------------------------------------------------------------- + // test band, add and copy_sparse (symmetric) + //-------------------------------------------------------------------------- + + if (A->stype != 0) + { + // r = norm (imag (diag (A))) + r = znorm_diag (A, cm) ; + if (r == 0) + { + // this test requires diag(A) to be real + + // E = A, in symmetric/upper form + E = CHOLMOD(copy) (A, 1, 2, cm) ; + + // Minus1 = -1 + cholmod_dense *Minus1 = CHOLMOD(zeros) (1, 1, A->xtype + DTYPE, cm); + if (Minus1 != NULL) + { + ((Real *) (Minus1->x)) [0] = -1 ; + } + + // E = -E + CHOLMOD(scale) (Minus1, CHOLMOD_SCALAR, E, cm) ; + + // F = A, in symmetric/lower form + F = CHOLMOD(copy) (A, -1, 2, cm) ; + + // C = F (exact copy) + C = CHOLMOD(copy_sparse) (F, cm) ; + + // G = E+C + G = CHOLMOD(add) (E, C, one, one, 2, false, cm) ; + CHOLMOD(sort) (G, cm) ; + + CHOLMOD(drop) (0, G, cm) ; + nz = CHOLMOD(nnz) (G, cm) ; + if (G != NULL) + { + OK (nz == 0) ; + } + + CHOLMOD(free_dense) (&Minus1, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + } + } + + //-------------------------------------------------------------------------- + // try a dense identity matrix + //-------------------------------------------------------------------------- + + X = CHOLMOD(eye) (3, 4, CHOLMOD_REAL + DTYPE, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + + //-------------------------------------------------------------------------- + // bisector and nested_dissection + //-------------------------------------------------------------------------- + +#ifndef NPARTITION + if (A != NULL && A->nrow == A->ncol) + { + int64_t nc, nc_new ; + Int cnz, csep, save2 ; + Int *Cnw, *Cew, *Cmember, *CParent, *Perm ; + double save1 ; + + // try CHOLMOD's interface to METIS_ComputeVertexSeparator + cm->metis_memory = 2.0 ; +// CHOLMOD(print_sparse) (A, "A for bisect", cm) ; + csep = CHOLMOD(bisect) (A, NULL, 0, TRUE, Partition, cm) ; + if (csep != EMPTY) + { + Int csep2 ; + // printf ("csep %g\n", (double) csep) ; + csep2 = check_partition (A, Partition) ; + // printf ("csep2 %g\n", (double) csep2) ; + OK (csep == csep2) ; + } + + // try the raw interface to METIS_ComputeVertexSeparator +// CHOLMOD(print_sparse) (A, "A for metis bisect", cm) ; + + // C = A+A', remove the diagonal + AT = CHOLMOD(transpose) (A, 0, cm) ; + E = CHOLMOD(add) (A, AT, one, one, FALSE, TRUE, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + C = CHOLMOD(copy) (E, 0, -1, cm) ; +// CHOLMOD(print_sparse) (C, "C for metis bisect", cm) ; + + cnz = (C != NULL) ? (C->nzmax) : 0 ; + Cew = CHOLMOD(malloc) (cnz, sizeof (Int), cm) ; + Cnw = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + if (Cnw != NULL) + { + for (j = 0 ; j < (Int) (A->nrow) ; j++) + { + Cnw [j] = 1 ; + } + } + if (Cew != NULL) + { + for (j = 0 ; j < cnz ; j++) + { + Cew [j] = 1 ; + } + } + csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Partition, cm) ; + if (csep != EMPTY) + { + OK (csep == check_partition (C, Partition)) ; + } + CHOLMOD(free) (nrow, sizeof (Int), Cnw, cm) ; + CHOLMOD(free) (cnz, sizeof (Int), Cew, cm) ; + + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + CParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + Perm = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; + + save1 = cm->method [cm->current].nd_small ; + save2 = cm->method [cm->current].nd_oksep ; + cm->method [cm->current].nd_small = 1 ; + cm->method [cm->current].nd_oksep = 1.0 ; + + nc = CHOLMOD(nested_dissection) (A, NULL, 0, Perm, CParent, Cmember, + cm); + if (nc > 0) + { + OK (CHOLMOD(check_perm) (Perm, n, n, cm)) ; + } + + CHOLMOD(free_work) (cm) ; + + // collapse the septree + if (nc > 0 && n > 0) + { + nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, + CParent, Cmember, cm) ; + + // error checks + save = cm->error_handler ; + cm->error_handler = NULL ; + nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, + CParent, Cmember, NULL) ; + OK (nc_new == EMPTY) ; + nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, + NULL, Cmember, cm) ; + OK (nc_new == EMPTY) ; + nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, + CParent, NULL, cm) ; + OK (nc_new == EMPTY) ; + nc_new = CHOLMOD(collapse_septree) (0, 1, 0.1, 400, + CParent, Cmember, cm) ; + OK (nc_new == EMPTY) ; + nc_new = CHOLMOD(collapse_septree) (1, 1, 0.1, 400, + CParent, Cmember, cm) ; + OK (nc_new == 1 || nc_new == EMPTY) ; + nc_new = CHOLMOD(collapse_septree) (SIZE_MAX, SIZE_MAX, + 0.1, 400, CParent, Cmember, cm) ; + OK (nc_new == EMPTY) ; + + cm->error_handler = save ; + } + + CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), CParent, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), Perm, cm) ; + + cm->method [cm->current].nd_small = save1 ; + cm->method [cm->current].nd_oksep = save2 ; + + } +#endif + + //-------------------------------------------------------------------------- + // dense to/from sparse conversions + //-------------------------------------------------------------------------- + + // convert A to real, remove zero entries, and then convert to pattern + if (MAX (nrow, ncol) < 1000) + { + + C = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, C, cm) ; + CHOLMOD(drop) (0., C, cm) ; + D = CHOLMOD(copy) (C, 0, 0, cm) ; + CHOLMOD(sort) (D, cm) ; + + // X = dense copy of C + CHOLMOD(sparse_xtype) (CHOLMOD_PATTERN + DTYPE, C, cm) ; + X = CHOLMOD(sparse_to_dense) (C, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + + // change X to sparse pattern and then real/complex/zomplex, it should + // equal D + for (xtype2 = CHOLMOD_REAL ; xtype2 <= CHOLMOD_ZOMPLEX ; xtype2++) + { + E = CHOLMOD(dense_to_sparse) (X, FALSE, cm) ; + ok = CHOLMOD(sparse_xtype) (xtype2 + DTYPE, E, cm) ; + ok = CHOLMOD(sparse_xtype) (xtype2 + DTYPE, D, cm) ; + if (xtype2 == CHOLMOD_REAL) + { + F = CHOLMOD(add) (E, D, one, minusone, TRUE, TRUE, cm) ; + r = CHOLMOD(norm_sparse) (F, 0, cm) ; + if (F != NULL && cm->status == CHOLMOD_OK) + { + if (r != 0) + { + printf ("r %g at %d:%s\n", r, __LINE__, __FILE__) ; + } + OK (r == 0) ; + } + CHOLMOD(free_sparse) (&F, cm) ; + } + else + { + check_equality (E, D, xtype2) ; + } + CHOLMOD(free_sparse) (&E, cm) ; + } + + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + } + + //-------------------------------------------------------------------------- + // unsymmetric transpose + //-------------------------------------------------------------------------- + + len = ncol/2 ; + fset = prand (ncol) ; // RAND + CHOLMOD(print_perm) (fset, ncol, ncol, "fset", cm) ; + + C = CHOLMOD(copy) (A, 0, 2, cm) ; + D = CHOLMOD(ptranspose) (C, 2, P, fset, len, cm) ; + E = CHOLMOD(transpose) (D, 1, cm) ; + F = CHOLMOD(transpose) (E, 1, cm) ; + G = CHOLMOD(add) (D, F, one, minusone, TRUE, FALSE, cm) ; + r = CHOLMOD(norm_sparse) (G, 0, cm) ; + if (G != NULL && cm->status == CHOLMOD_OK) + { + OK (r == 0) ; + } + CHOLMOD(drop) (0, G, cm) ; + r = CHOLMOD(norm_sparse) (G, 0, cm) ; + if (G != NULL && cm->status == CHOLMOD_OK) + { + OK (r == 0) ; + } + nz = CHOLMOD(nnz) (G, cm) ; + if (G != NULL && cm->status == CHOLMOD_OK) + { + OK (nz == 0) ; + } + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + + //-------------------------------------------------------------------------- + // symmetric array transpose + //-------------------------------------------------------------------------- + + if (A->stype != 0) + { + + // C = A(p,p).' + C = CHOLMOD(ptranspose) (A, 1, P, NULL, 0, cm) ; + + // D = C(pinv,pinv).' + D = CHOLMOD(ptranspose) (C, 1, Pinv, NULL, 0, cm) ; + CHOLMOD(sort) (D, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + + // C = A, sorted + C = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sort) (C, cm) ; + + int cstype = (C == NULL) ? 0 : C->stype ; + E = CHOLMOD(copy) (C, cstype, 1, cm) ; + F = CHOLMOD(copy) (D, cstype, 1, cm) ; + + // C and D should be equal + check_equality (E, F, xtype) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + + // C = A.' + C = CHOLMOD(transpose) (A, 1, cm) ; + + // D = C.' + D = CHOLMOD(transpose) (C, 1, cm) ; + CHOLMOD(sort) (D, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + + // C = A, sorted + C = CHOLMOD(copy_sparse) (A, cm) ; + CHOLMOD(sort) (C, cm) ; + + cstype = (C == NULL) ? 0 : C->stype ; + E = CHOLMOD(copy) (C, cstype, 1, cm) ; + F = CHOLMOD(copy) (D, cstype, 1, cm) ; + + // C and D should be equal + check_equality (E, F, xtype) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&F, cm) ; + } + + //-------------------------------------------------------------------------- + // matrix multiply + //-------------------------------------------------------------------------- + + // this fails for a large arrowhead matrix, so turn off error hanlder + save = cm->error_handler ; + cm->error_handler = NULL ; + AT = CHOLMOD(transpose) (A, 2, cm) ; + D = CHOLMOD(copy) (A, 0, 2, cm) ; + if (n > NLARGE) progress (1, '.') ; + C = CHOLMOD(aat) (D, NULL, 0, 2, cm) ; + if (n > NLARGE) progress (1, '.') ; + + for (stype = -1 ; stype <= 1 ; stype++) + { + if (n > NLARGE) progress (1, '.') ; + E = CHOLMOD(ssmult) (A, AT, stype, 2, false, cm) ; + if (n > NLARGE) progress (1, '.') ; + G = CHOLMOD(add) (C, E, one, minusone, 2, false, cm) ; + if (n > NLARGE) progress (1, '.') ; + r = CHOLMOD(norm_sparse) (G, 0, cm) ; + if (G != NULL) + { + MAXERR (maxerr, r, anorm) ; + } + CHOLMOD(drop) (0, G, cm) ; + r = CHOLMOD(norm_sparse) (G, 0, cm) ; + if (G != NULL) + { + MAXERR (maxerr, r, anorm) ; + } + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + } + + if (nrow == ncol) + { + // E = pattern of A + E = CHOLMOD(copy) (A, 0, 0, cm) ; + // G = E*E + if (n > NLARGE) progress (1, '.') ; + G = CHOLMOD(ssmult) (E, E, 0, FALSE, FALSE, cm) ; + if (n > NLARGE) progress (1, '.') ; + CHOLMOD(free_sparse) (&E, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + } + + cm->error_handler = save ; + + CHOLMOD(free_sparse) (&D, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&AT, cm) ; + + //-------------------------------------------------------------------------- + // free P, Q, and their inverses + //-------------------------------------------------------------------------- + + CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; + if (A->stype == 0) + { + CHOLMOD(free) (ncol, sizeof (Int), Q, cm) ; + } + CHOLMOD(free) (ncol, sizeof (Int), Qinv, cm) ; + CHOLMOD(free) (nrow, sizeof (Int), Partition, cm) ; + + progress (0, '.') ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_test_ops2.c b/CHOLMOD/Tcov/t_test_ops2.c new file mode 100644 index 0000000000..aeeba4c9fb --- /dev/null +++ b/CHOLMOD/Tcov/t_test_ops2.c @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_test_ops2: test more ops +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +double test_ops2 (cholmod_sparse *A_input) +{ + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + int xtype = A_input->xtype ; + double maxerr = 0 ; + + //-------------------------------------------------------------------------- + // create test matrices + //-------------------------------------------------------------------------- + + // X = random ncol-by-6 matrix + cholmod_dense *X = rand_dense (ncol, 6, xtype + DTYPE, cm) ; + + // B = sparse (X) + cholmod_sparse *B = CHOLMOD(dense_to_sparse) (X, true, cm) ; + + // A = sparse (A_input), change stype to 0 + cholmod_sparse *A = CHOLMOD(copy) (A_input, 0, 2, cm) ; + + // P = random nrow-by-nrow permutation + Int *P_perm = prand (nrow) ; // RAND + cholmod_sparse *P = perm_matrix (P_perm, nrow, xtype + DTYPE, cm) ; + + // Q = random ncol-by-ncol permutation + Int *Q_perm = prand (ncol) ; // RAND + cholmod_sparse *Q = perm_matrix (Q_perm, ncol, xtype + DTYPE, cm) ; + + //-------------------------------------------------------------------------- + // C1 = (P*A)*(Q*B) + //-------------------------------------------------------------------------- + + cholmod_sparse *PA = CHOLMOD(ssmult) (P, A, 0, true, true, cm) ; + cholmod_sparse *QB = CHOLMOD(ssmult) (Q, B, 0, true, false, cm) ; + cholmod_sparse *C1 = CHOLMOD(ssmult) (PA, QB, 0, true, true, cm) ; + CHOLMOD(free_sparse) (&PA, cm) ; + CHOLMOD(free_sparse) (&QB, cm) ; + + //-------------------------------------------------------------------------- + // C2 = P*((A*Q)*B) + //-------------------------------------------------------------------------- + + cholmod_sparse *AQ = CHOLMOD(ssmult) (A, Q, 0, true, true, cm) ; + cholmod_sparse *AQB = CHOLMOD(ssmult) (AQ, B, 0, true, true, cm) ; + cholmod_sparse *C2 = CHOLMOD(ssmult) (P, AQB, 0, true, true, cm) ; + CHOLMOD(free_sparse) (&AQB, cm) ; + + //-------------------------------------------------------------------------- + // E = C1-C2 + //-------------------------------------------------------------------------- + + cholmod_sparse *E = CHOLMOD(add) (C1, C2, one, minusone, true, false, cm) ; + CHOLMOD(free_sparse) (&C2, cm) ; + + double anorm = CHOLMOD(norm_sparse) (A, 0, cm) ; + double bnorm = CHOLMOD(norm_sparse) (B, 0, cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm + bnorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + //-------------------------------------------------------------------------- + // C3 = (P*A*Q)*X + //-------------------------------------------------------------------------- + + // PAQ = P*AQ = P*(A*Q) + cholmod_sparse *PAQ = CHOLMOD(ssmult) (P, AQ, 0, true, true, cm) ; + CHOLMOD(free_sparse) (&AQ, cm) ; + + // Y = PAQ*X + cholmod_dense *Y = CHOLMOD(zeros) (nrow, 6, xtype + DTYPE, cm) ; + CHOLMOD(sdmult) (PAQ, false, one, zero, X, Y, cm) ; + CHOLMOD(free_sparse) (&PAQ, cm) ; + + // C3 = sparse (Y) + cholmod_sparse *C3 = CHOLMOD(dense_to_sparse) (Y, true, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + + //-------------------------------------------------------------------------- + // E = C1-C3 + //-------------------------------------------------------------------------- + + E = CHOLMOD(add) (C1, C3, one, minusone, true, false, cm) ; + CHOLMOD(free_sparse) (&C1, cm) ; + CHOLMOD(free_sparse) (&C3, cm) ; + + double fnorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, fnorm, anorm + bnorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + //-------------------------------------------------------------------------- + // free matrices and return result + //-------------------------------------------------------------------------- + + CHOLMOD(free) (nrow, sizeof (Int), P_perm, cm) ; + CHOLMOD(free) (ncol, sizeof (Int), Q_perm, cm) ; + CHOLMOD(free_sparse) (&P, cm) ; + CHOLMOD(free_sparse) (&Q, cm) ; + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + + printf ("test_ops2 maxerr %g\n", maxerr) ; + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_tofrom_tests.c b/CHOLMOD/Tcov/t_tofrom_tests.c new file mode 100644 index 0000000000..dbe0227ef1 --- /dev/null +++ b/CHOLMOD/Tcov/t_tofrom_tests.c @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_tofrom_tests: convert to/from sparse/dense/triplet +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +double tofrom_tests (cholmod_sparse *A_input, cholmod_common *cm) +{ + + Int nrow = A_input->nrow ; + Int ncol = A_input->ncol ; + int xtype = A_input->xtype ; + double maxerr = 0 ; + int64_t anz = CHOLMOD(nnz) (A_input, cm) ; + + if (nrow > 1000 || ncol > 1000) + { + // test skipped + return (-1) ; + } + + //-------------------------------------------------------------------------- + // test many conversions + //-------------------------------------------------------------------------- + + for (int to_xtype = 0 ; to_xtype <= 3 ; to_xtype++) + { + + // create the test matrix. Explicit zeros are dropped because + // otherwise the pattern-only tests will fail (the pattern-only + // conversions will keep explicit zeros, but converting to/from dense + // will drop them). + cholmod_sparse *A2 = CHOLMOD(copy_sparse) (A_input, cm) ; + CHOLMOD(drop) (0, A2, cm) ; + cholmod_sparse *A = CHOLMOD(copy_sparse) (A2, cm) ; + CHOLMOD(sparse_xtype) (to_xtype + DTYPE, A, cm) ; + + // C = sparse (dense (sparse (triplet (A)))) + cholmod_triplet *T = CHOLMOD(sparse_to_triplet) (A, cm) ; + cholmod_sparse *B = CHOLMOD(triplet_to_sparse) (T, anz, cm) ; + cholmod_dense *X = CHOLMOD(sparse_to_dense) (B, cm) ; + cholmod_sparse *C = CHOLMOD(dense_to_sparse) (X, true, cm) ; + + // G = sparse (dense (A)) + cholmod_dense *Y = CHOLMOD(sparse_to_dense) (A, cm) ; + cholmod_sparse *G = CHOLMOD(dense_to_sparse) (Y, true, cm) ; + + if (to_xtype == CHOLMOD_PATTERN) + { + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, A, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, C, cm) ; + } + + // E = A-C + cholmod_sparse *E = CHOLMOD(add) (A, C, one, minusone, 2, true, cm) ; + double anorm = CHOLMOD(norm_sparse) (A, 0, cm) ; + double enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + // E = A-G + E = CHOLMOD(add) (A, G, one, minusone, 2, true, cm) ; + enorm = CHOLMOD(norm_sparse) (E, 0, cm) ; + MAXERR (maxerr, enorm, anorm) ; + CHOLMOD(free_sparse) (&E, cm) ; + + // S1 = real (pattern (X)) + cholmod_sparse *S1 = CHOLMOD(dense_to_sparse) (X, false, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, S1, cm) ; + + // S2 = real (pattern (A)) + cholmod_sparse *S2 = CHOLMOD(copy_sparse) (A2, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_PATTERN + DTYPE, S2, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, S2, cm) ; + + // E = S1-S2 + E = CHOLMOD(add) (S1, S2, one, minusone, 1, true, cm) ; + CHOLMOD(drop) (0, E, cm) ; + int64_t enz = CHOLMOD(nnz) (E, cm) ; + CHOLMOD(free_sparse) (&E, cm) ; + OK (enz == 0) ; + + CHOLMOD(free_sparse) (&A, cm) ; + CHOLMOD(free_sparse) (&A2, cm) ; + CHOLMOD(free_sparse) (&B, cm) ; + CHOLMOD(free_sparse) (&C, cm) ; + CHOLMOD(free_sparse) (&G, cm) ; + CHOLMOD(free_sparse) (&S1, cm) ; + CHOLMOD(free_sparse) (&S2, cm) ; + CHOLMOD(free_triplet) (&T, cm) ; + CHOLMOD(free_dense) (&X, cm) ; + CHOLMOD(free_dense) (&Y, cm) ; + } + + return (maxerr) ; +} + diff --git a/CHOLMOD/Tcov/t_unpack.c b/CHOLMOD/Tcov/t_unpack.c new file mode 100644 index 0000000000..28c481fa36 --- /dev/null +++ b/CHOLMOD/Tcov/t_unpack.c @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_unpack: test CHOLMOD unpacked matrices +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// Create an unpacked, unsorted version of a matrix, with random-sized gaps in +// each column. + +#include "cm.h" + +//------------------------------------------------------------------------------ +// unpack +//------------------------------------------------------------------------------ + +cholmod_sparse *unpack (cholmod_sparse *A) +{ + Real *Ax, *Cx, *Az, *Cz ; + Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ; + cholmod_sparse *C ; + Int i, j, p, q, pdest, pend, nrow, ncol, nzmax, sorted, packed, stype, + extra ; + + if (A == NULL) + { + return (NULL) ; + } + + extra = 10 ; + + nrow = A->nrow ; + ncol = A->ncol ; + nzmax = A->nzmax ; + sorted = A->sorted ; + packed = A->packed ; + stype = A->stype ; + + C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax + extra*ncol, FALSE, + FALSE, stype, A->xtype + A->dtype, cm) ; + + if (C == NULL) + { + return (NULL) ; + } + + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + Az = A->z ; + Anz = A->nz ; + + Cp = C->p ; + Ci = C->i ; + Cx = C->x ; + Cz = C->z ; + Cnz = C->nz ; + nzmax = C->nzmax ; + nzmax = MAX (1, nzmax) ; + + for (p = 0 ; p < nzmax ; p++) + { + Ci [p] = 0 ; + } + if (A->xtype == CHOLMOD_REAL) + { + for (p = 0 ; p < nzmax ; p++) + { + Cx [p] = 0 ; + } + } + else if (A->xtype == CHOLMOD_COMPLEX) + { + for (p = 0 ; p < 2*nzmax ; p++) + { + Cx [p] = 0 ; + } + } + else if (A->xtype == CHOLMOD_ZOMPLEX) + { + for (p = 0 ; p < nzmax ; p++) + { + Cx [p] = 0 ; + Cz [p] = 0 ; + } + } + + pdest = 0 ; + for (j = 0 ; j < ncol ; j++) + { + // copy the column into C + p = Ap [j] ; + Cp [j] = pdest ; + pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; + Cnz [j] = pend - p ; + for ( ; p < pend ; p++) + { + Ci [pdest] = Ai [p] ; + if (A->xtype == CHOLMOD_REAL) + { + Cx [pdest] = Ax [p] ; + } + else if (A->xtype == CHOLMOD_COMPLEX) + { + Cx [2*pdest ] = Ax [2*p] ; + Cx [2*pdest+1] = Ax [2*p+1] ; + } + else if (A->xtype == CHOLMOD_ZOMPLEX) + { + Cx [pdest] = Ax [p] ; + Cz [pdest] = Az [p] ; + } + pdest++ ; + } + + // jumble the column + p = Cp [j] ; + pend = p + Cnz [j] ; + for ( ; p < pend-1 ; p++) + { + q = p + nrand (pend-p) ; // RAND + i = Ci [p] ; + Ci [p] = Ci [q] ; + Ci [q] = i ; + + if (A->xtype == CHOLMOD_REAL) + { + Real x = Cx [p] ; + Cx [p] = Cx [q] ; + Cx [q] = x ; + } + else if (A->xtype == CHOLMOD_COMPLEX) + { + Real x = Cx [2*p] ; + Cx [2*p] = Cx [2*q] ; + Cx [2*q] = x ; + + x = Cx [2*p+1] ; + Cx [2*p+1] = Cx [2*q+1] ; + Cx [2*q+1] = x ; + } + else if (A->xtype == CHOLMOD_ZOMPLEX) + { + Real x = Cx [p] ; + Cx [p] = Cx [q] ; + Cx [q] = x ; + + x = Cz [p] ; + Cz [p] = Cz [q] ; + Cz [q] = x ; + } + } + + // add some random blank space + pdest += nrand (extra) ; // RAND + for (p = pend ; p < pdest ; p++) + { + Ci [p] = 0 ; + if (A->xtype == CHOLMOD_REAL) + { + Cx [p] = 0 ; + } + else if (A->xtype == CHOLMOD_COMPLEX) + { + Cx [2*p] = 0 ; + Cx [2*p+1] = 0 ; + } + else if (A->xtype == CHOLMOD_ZOMPLEX) + { + Cx [p] = 0 ; + Cz [p] = 0 ; + } + } + } + Cp [ncol] = pdest ; + + return (C) ; +} + diff --git a/CHOLMOD/Tcov/t_znorm_diag.c b/CHOLMOD/Tcov/t_znorm_diag.c new file mode 100644 index 0000000000..b1fd9b743c --- /dev/null +++ b/CHOLMOD/Tcov/t_znorm_diag.c @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// CHOLMOD/Tcov/t_znorm_diag: compute norm (imag (diag (A))) +//------------------------------------------------------------------------------ + +// CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0+ + +//------------------------------------------------------------------------------ + +// r = norm (imag (diag (A))) + +double znorm_diag (cholmod_sparse *A, cholmod_common *cm) ; + +double znorm_diag (cholmod_sparse *A, cholmod_common *cm) +{ + double one [2] = {1,0} ; + double minusone [2] = {-1,0} ; + + // D1 = diag (A), converted to zomplex + cholmod_sparse *D1 = CHOLMOD(band) (A, 0, 0, true, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX + DTYPE, D1, cm) ; + + // D2 = zomplex (real (D1)) + cholmod_sparse *D2 = CHOLMOD(copy_sparse) (D1, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, D2, cm) ; + CHOLMOD(sparse_xtype) (CHOLMOD_ZOMPLEX + DTYPE, D2, cm) ; + + // G = D1-D2 = imaginary part of the diagonal of A + cholmod_sparse *G = CHOLMOD(add) (D1, D2, one, minusone, true, false, cm) ; + + // r is zero if the diagonal of A is all real + double r = CHOLMOD(norm_sparse) (G, 0, cm) ; + printf ("norm(G) (G = imag(diag(A))) : %g\n", r) ; + + CHOLMOD(free_sparse) (&G, cm) ; + CHOLMOD(free_sparse) (&D2, cm) ; + CHOLMOD(free_sparse) (&D1, cm) ; + return (r) ; +} + diff --git a/CHOLMOD/Tcov/test_ops.c b/CHOLMOD/Tcov/test_ops.c deleted file mode 100644 index 50ad63ba98..0000000000 --- a/CHOLMOD/Tcov/test_ops.c +++ /dev/null @@ -1,1172 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/test_ops: test CHOLMOD matrix operators -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Test CHOLMOD matrix operators. */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === nzdiag =============================================================== */ -/* ========================================================================== */ - -/* Count the entries on the diagonal */ - -Int nzdiag (cholmod_sparse *A) -{ - Int *Ap, *Ai, *Anz ; - Int nnzdiag, packed, j, p, i, pend, ncol ; - if (A == NULL) - { - return (EMPTY) ; - } - nnzdiag = 0 ; - ncol = A->ncol ; - Ap = A->p ; - Ai = A->i ; - Anz = A->nz ; - packed = A->packed ; - for (j = 0 ; j < ncol ; j++) - { - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - if (i == j) - { - nnzdiag++ ; - } - } - } - return (nnzdiag) ; -} - - -/* ========================================================================== */ -/* === check_partition ====================================================== */ -/* ========================================================================== */ - -/* Check a node separator, and return the # of nodes in the node separator or - * -1 if the separater is invalid. A node j is in the left part if - * Part [j] = 0, in the right part if Part [j] = 1, and in the separator if - * Part [j] = 2. - */ - -Int check_partition (cholmod_sparse *A, Int *Part) -{ - Int *Ap, *Ai, *Anz ; - Int chek [3], which, i, j, p, n, pend, packed ; - - if (A == NULL || Part == NULL || A->nrow != A->ncol) - { - /* printf ("A NULL, no Partition, or rectangular\n") ; */ - return (EMPTY) ; - } - n = A->nrow ; - Ap = A->p ; - Ai = A->i ; - Anz = A->nz ; - packed = A->packed ; - - chek [0] = 0 ; - chek [1] = 0 ; - chek [2] = 0 ; - - /* printf ("\ncheck partition:\n") ; */ - for (j = 0 ; j < n ; j++) - { - which = Part [j] ; - /* printf ("node "ID" in Part "ID"\n", j, which) ; */ - p = Ap [j] ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - for ( ; p < pend ; p++) - { - i = Ai [p] ; - /* printf (" neighbor "ID" in part "ID"\n", i, Part [i]) ; */ - if (which == 0) - { - if (Part [i] == 1) - { - /* printf (" broken!\n") ; */ - return (EMPTY) ; - } - } - else if (which == 1) - { - if (Part [i] == 0) - { - /* printf (" broken!\n") ; */ - return (EMPTY) ; - } - } - } - if (which < 0 || which > 2) - { - /* printf (" node j, invalid partition, broken!\n") ; */ - return (EMPTY) ; - } - chek [which]++ ; - } - /* - printf ("nodes in left: "ID" right: "ID" separator: "ID"\n", - chek [0], chek [1], chek [2]) ; - */ - return (chek [2]) ; -} - - -/* ========================================================================== */ -/* === check_equality ======================================================= */ -/* ========================================================================== */ - -/* Ensure two sparse matrices are identical. */ - -static void check_equality (cholmod_sparse *E, cholmod_sparse *D, Int xtype) -{ - double *Ex, *Ez, *Dx, *Dz ; - Int *Ep, *Ei, *Dp, *Di ; - Int j, nz, p, ncol ; - - if (E == NULL || D == NULL || D->xtype != xtype || E->xtype != xtype) - { - return ; - } - - Ep = E->p ; - Ei = E->i ; - Ex = E->x ; - Ez = E->z ; - - Dp = D->p ; - Di = D->i ; - Dx = D->x ; - Dz = D->z ; - - OK (E->ncol == D->ncol) ; - OK (E->nrow == D->nrow) ; - OK (E->packed == D->packed) ; - - ncol = E->ncol ; - - for (j = 0 ; j <= ncol ; j++) - { - OK (Ep [j] == Dp [j]) ; - } - nz = Ep [ncol] ; - - for (p = 0 ; p < nz ; p++) - { - OK (Ei [p] == Di [p]) ; - } - - if (xtype == CHOLMOD_REAL) - { - for (p = 0 ; p < nz ; p++) - { - OK (Ex [p] == Dx [p]) ; - } - } - else if (xtype == CHOLMOD_COMPLEX) - { - for (p = 0 ; p < 2*nz ; p++) - { - OK (Ex [p] == Dx [p]) ; - } - } - else if (xtype == CHOLMOD_ZOMPLEX) - { - for (p = 0 ; p < nz ; p++) - { - OK (Ex [p] == Dx [p]) ; - OK (Ez [p] == Dz [p]) ; - } - } -} - - -/* ========================================================================== */ -/* === test_ops ============================================================= */ -/* ========================================================================== */ - -/* Test various matrix operations. */ - -double test_ops (cholmod_sparse *A) -{ - double maxerr = 0, r, x, anorm, r1, rinf ; - double *Sx, *Sz ; - Int *Pinv, *P, *Si, *Sj, *Q, *Qinv, *fset, *Partition ; - cholmod_triplet *S ; - cholmod_sparse *C, *D, *E, *F, *G, *H, *AT, *Zs ; - cholmod_dense *X, *Y ; - Int n, kk, k, nrow, ncol, len, nz, ok, i, j, stype, nmin, mode, isreal, - xtype, xtype2, mtype, asym, xmatched, pmatched, nzoffdiag, nz_diag ; - size_t nz1, nz2 ; - void (*save) (int, const char *, int, const char *) ; - double alpha [2], beta [2], *Xx ; - FILE *f ; - int option, save3 ; - - if (A == NULL) - { - ERROR (CHOLMOD_INVALID, "nothing for test_ops") ; - return (1) ; - } - - nrow = A->nrow ; - ncol = A->ncol ; - H = NULL ; - n = MAX (nrow, ncol) ; - nmin = MIN (nrow, ncol) ; - xtype = A->xtype ; - isreal = (A->xtype == CHOLMOD_REAL) ; - - /* ---------------------------------------------------------------------- */ - /* norm */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(print_sparse) (A, "A for testops", cm) ; - r1 = CHOLMOD(norm_sparse) (A, 1, cm) ; - rinf = CHOLMOD(norm_sparse) (A, 0, cm) ; - - anorm = r1 ; - - /* E = pattern of A */ - E = CHOLMOD(copy) (A, 0, 0, cm) ; - CHOLMOD(print_sparse) (E, "E = pattern of A", cm) ; -// int64_t enz = CHOLMOD (nnz) (E, cm) ; -// int64_t anz = CHOLMOD (nnz) (A, cm) ; -// if (E->stype == A->stype) { OK (enz == anz) ; } - r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; - rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; - OK (r1 <= nrow) ; - OK (rinf <= ncol) ; - CHOLMOD(free_sparse) (&E, cm) ; - - /* E = pattern of A, but exclude the diagonal */ - E = CHOLMOD(copy) (A, 0, -1, cm) ; - CHOLMOD(print_sparse) (E, "E = spones (A), excl diag", cm) ; - r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; - rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; - if (nrow < ncol) - { - OK (r1 <= nrow) ; - OK (rinf < MAX (1,ncol)) ; - } - else - { - OK (r1 < MAX (1,nrow)) ; - OK (rinf <= ncol) ; - } - CHOLMOD(free_sparse) (&E, cm) ; - - /* ---------------------------------------------------------------------- */ - /* copy */ - /* ---------------------------------------------------------------------- */ - - if (A->stype) - { - /* E = tril (A), no diagonal */ - E = CHOLMOD(copy) (A, -1, -1, cm) ; - CHOLMOD(print_sparse) (E, "E, lower and no diagonal", cm) ; - CHOLMOD(band_inplace) (0, n, 0, E, cm) ; - CHOLMOD(print_sparse) (E, "E Empty", cm) ; - nz = CHOLMOD(nnz) (E, cm) ; - if (E != NULL) - { - OK (nz == 0) ; - } - CHOLMOD(free_sparse) (&E, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* read/write */ - /* ---------------------------------------------------------------------- */ - - /* delete the contents of the temp1.mtx and temp2.mtx file */ - f = fopen ("temp1.mtx", "w") ; - fprintf (f, "temp1\n") ; - fclose (f) ; - - f = fopen ("temp3.mtx", "w") ; - fprintf (f, "temp3\n") ; - fclose (f) ; - - CHOLMOD(free_work) (cm) ; - - f = fopen ("temp1.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; - fclose (f) ; - printf ("write_sparse, asym: "ID"\n", asym) ; - OK (IMPLIES (A != NULL, asym > EMPTY)) ; - - f = fopen ("temp1.mtx", "r") ; - C = CHOLMOD(read_sparse) (f, cm) ; - fclose (f) ; - printf ("got_sparse\n") ; - CHOLMOD(free_sparse) (&C, cm) ; - - save3 = A->xtype ; - A->xtype = CHOLMOD_PATTERN ; - f = fopen ("temp3.mtx", "w") ; - asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; - A->xtype = save3 ; - fclose (f) ; - printf ("write_sparse3, asym: "ID"\n", asym) ; - - f = fopen ("temp3.mtx", "r") ; - C = CHOLMOD(read_sparse) (f, cm) ; - fclose (f) ; - printf ("got_sparse3\n") ; - CHOLMOD(free_sparse) (&C, cm) ; - - for (i = 0 ; i <= 1 ; i++) - { - - f = fopen ("temp2.mtx", "w") ; - fprintf (f, "temp2\n") ; - fclose (f) ; - - X = CHOLMOD(ones) (4, 4, CHOLMOD_REAL, cm) ; - if (X != NULL) - { - Xx = X->x ; - Xx [0] = (i == 0) ? 1.1e308 : -1.1e308 ; - } - f = fopen ("temp2.mtx", "w") ; - ok = CHOLMOD(write_dense) (f, X, "comments.txt", cm) ; - fclose (f) ; - printf ("wrote dense\n") ; - - f = fopen ("temp2.mtx", "r") ; - Y = CHOLMOD(read_dense) (f, cm) ; - fclose (f) ; - printf ("got dense\n") ; - CHOLMOD(free_dense) (&X, cm) ; - CHOLMOD(free_dense) (&Y, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* symmetry */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free_work) (cm) ; - xmatched = 0 ; - pmatched = 0 ; - nzoffdiag = 0 ; - nz_diag = 0 ; - for (option = 0 ; option <= 2 ; option++) - { - asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, &nzoffdiag, - &nz_diag, cm); - printf - ("symmetry, asym: "ID" matched "ID" "ID" offdiag "ID" diag "ID"\n", - asym, xmatched, pmatched, nzoffdiag, nz_diag) ; - } - - /* ---------------------------------------------------------------------- */ - /* transpose */ - /* ---------------------------------------------------------------------- */ - - C = CHOLMOD(allocate_sparse) (A->ncol, A->nrow, A->nzmax, TRUE, TRUE, - -(A->stype), A->xtype, cm) ; - D = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, TRUE, TRUE, - A->stype, A->xtype, cm) ; - CHOLMOD(free_work) (cm) ; - ok = (C != NULL && D != NULL) ; - - /* C = A' */ - if (ok) - { - if (A->stype) - { - ok = CHOLMOD(transpose_sym) (A, 2, NULL, C, cm) ; - } - else - { - ok = CHOLMOD(transpose_unsym) (A, 2, NULL, NULL, 0, C, cm) ; - } - OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; - } - - /* D = C' */ - if (ok) - { - if (A->stype) - { - ok = CHOLMOD(transpose_sym) (C, 2, NULL, D, cm) ; - } - else - { - ok = CHOLMOD(transpose_unsym) (C, 2, NULL, NULL, 0, D, cm) ; - } - OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; - } - - if (ok) - { - ok = CHOLMOD(check_sparse) (D, cm) ; - OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; - } - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - - /* ---------------------------------------------------------------------- */ - /* C = A with jumbled triplets */ - /* ---------------------------------------------------------------------- */ - - S = CHOLMOD(sparse_to_triplet) (A, cm) ; /* [ */ - - if (S != NULL && nmin > 0 && S->nnz > 0) - { - - /* double the number of entries in S */ - nz1 = S->nzmax ; - nz2 = 2*nz1 ; - ok = CHOLMOD(reallocate_triplet) (nz2, S, cm) ; - - if (ok) - { - /* add duplicate entries, but keep the matrix the same */ - OK (S->nzmax == nz2) ; - Si = S->i ; - Sj = S->j ; - Sx = S->x ; - Sz = S->z ; - - for (k = nz1 ; k < ((Int) nz2) ; k++) - { - kk = nrand (k) ; /* RAND */ - Si [k] = Si [kk] ; - Sj [k] = Sj [kk] ; - - if (S->xtype == CHOLMOD_REAL) - { - x = Sx [kk] * (xrand (4.) - 2) ; /* RAND */ - Sx [k] = x ; - Sx [kk] -= x ; - } - else if (S->xtype == CHOLMOD_COMPLEX) - { - x = Sx [2*kk] * (xrand (4.) - 2) ; /* RAND */ - Sx [2*k] = x ; - Sx [2*kk] -= x ; - - x = Sx [2*kk+1] * (xrand (4.) - 2) ; /* RAND */ - Sx [2*k+1] = x ; - Sx [2*kk+1] -= x ; - } - else - { - x = Sx [kk] * (xrand (4.) - 2) ; /* RAND */ - Sx [k] = x ; - Sx [kk] -= x ; - - x = Sz [kk] * (xrand (4.) - 2) ; /* RAND */ - Sz [k] = x ; - Sz [kk] -= x ; - } - } - - /* randomly jumble the entries */ - for (k = 0 ; k < ((Int) (nz2-1)) ; k++) - { - kk = k + nrand (nz2-k) ; /* RAND */ - i = Si [k] ; - Si [k] = Si [kk] ; - Si [kk] = i ; - j = Sj [k] ; - Sj [k] = Sj [kk] ; - Sj [kk] = j ; - - if (S->xtype == CHOLMOD_REAL) - { - x = Sx [k] ; - Sx [k] = Sx [kk] ; - Sx [kk] = x ; - } - else if (S->xtype == CHOLMOD_COMPLEX) - { - x = Sx [2*k] ; - Sx [2*k] = Sx [2*kk] ; - Sx [2*kk] = x ; - x = Sx [2*k+1] ; - Sx [2*k+1] = Sx [2*kk+1] ; - Sx [2*kk+1] = x ; - } - else - { - x = Sx [k] ; - Sx [k] = Sx [kk] ; - Sx [kk] = x ; - x = Sz [k] ; - Sz [k] = Sz [kk] ; - Sz [kk] = x ; - } - } - S->nnz = nz2 ; - } - else - { - OK (S->nzmax == nz1) ; - OK (S->nnz == nz1) ; - } - } - - CHOLMOD(print_triplet) (S, "S jumbled", cm) ; - - C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; /* [ */ - CHOLMOD(print_sparse) (A, "A", cm) ; - CHOLMOD(print_sparse) (C, "C", cm) ; - - Zs = CHOLMOD(spzeros) (nrow, ncol, 1, xtype, cm) ; /* [ */ - - G = NULL ; - F = NULL ; - - if (isreal) - { - - /* G=A+0 */ - G = CHOLMOD(add) (A, Zs, one, one, TRUE, TRUE, cm) ; /* [ */ - - /* F = G-C */ - F = CHOLMOD(add) (G, C, one, minusone, TRUE, TRUE, cm) ; /* [ */ - - CHOLMOD(print_sparse) (F, "F", cm) ; - r = CHOLMOD(norm_sparse) (F, 1, cm) ; - MAXERR (maxerr, r, anorm) ; - r = CHOLMOD(norm_sparse) (F, 0, cm) ; - CHOLMOD(drop) (0, F, cm) ; - rinf = CHOLMOD(norm_sparse) (F, 0, cm) ; - if (F != NULL) - { - OK (r == rinf) ; - } - MAXERR (maxerr, r, anorm) ; - MAXERR (maxerr, rinf, anorm) ; - - /* E = F, with change of type and dropping small entries */ - for (stype = -1 ; stype <= 1 ; stype++) - { - if (stype != 0 && (F != NULL && F->nrow != F->ncol)) - { - continue ; - } - for (mode = 0 ; mode <= 1 ; mode++) - { - E = CHOLMOD(copy) (F, stype, mode, cm) ; /* [ */ - CHOLMOD(drop) (1e-16, E, cm) ; - r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; - rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; - if (E != NULL) - { - if (mode == 0) - { - /* pattern only */ - OK (r1 <= nrow) ; - OK (rinf <= ncol) ; - } - else - { - MAXERR (maxerr, r1, anorm) ; - MAXERR (maxerr, rinf, anorm) ; - } - } - CHOLMOD(free_sparse) (&E, cm) ; /* ] */ - } - } - - CHOLMOD(free_sparse) (&F, cm) ; /* ] */ - CHOLMOD(free_sparse) (&G, cm) ; /* ] */ - } - - Y = CHOLMOD(ones) (nrow, 1, xtype, cm) ; /* [ */ - X = CHOLMOD(ones) (ncol, 1, xtype, cm) ; /* [ */ - alpha [0] = 0 ; - alpha [1] = 0 ; - beta [0] = 2 ; - beta [1] = 0 ; - /* Y = 0*A*X + 2*Y */ - CHOLMOD(sdmult) (A, FALSE, alpha, beta, X, Y, cm) ; - r = CHOLMOD(norm_dense) (Y, 0, cm) ; - if (Y != NULL && X != NULL && A != NULL) - { - OK ((nrow == 0) ? (r == 0) : (r == 2)) ; - } - - alpha [0] = 1 ; - /* Y = 1*(0)*X + 2*Y */ - CHOLMOD(sdmult) (Zs, FALSE, alpha, beta, X, Y, cm) ; - r = CHOLMOD(norm_dense) (Y, 0, cm) ; - if (Y != NULL && X != NULL && A != NULL) - { - OK ((nrow == 0) ? (r == 0) : (r == 4)) ; - } - - CHOLMOD(free_dense) (&X, cm) ; /* ] */ - CHOLMOD(free_dense) (&Y, cm) ; /* ] */ - - CHOLMOD(free_sparse) (&Zs, cm) ; /* ] */ - CHOLMOD(free_sparse) (&C, cm) ; /* ] */ - CHOLMOD(free_triplet) (&S, cm) ; /* ] */ - - /* ---------------------------------------------------------------------- */ - /* C = P*A*Q in triplet form */ - /* ---------------------------------------------------------------------- */ - - S = CHOLMOD(sparse_to_triplet) (A, cm) ; - P = prand (nrow) ; /* RAND */ - if (A->stype == 0) - { - Q = prand (ncol) ; /* RAND */ - } - else - { - /* if A is symmetric, and stored in either upper or lower form, then - * the following code only works if P = Q */ - Q = P ; - } - Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - Qinv = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; - Partition = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - - if (Pinv != NULL && Qinv != NULL && P != NULL && Q != NULL && S != NULL) - { - Si = S->i ; - Sj = S->j ; - nz = S->nnz ; - for (k = 0 ; k < nrow ; k++) - { - Pinv [P [k]] = k ; - } - for (k = 0 ; k < ncol ; k++) - { - Qinv [Q [k]] = k ; - } - for (k = 0 ; k < nz ; k++) - { - Si [k] = Pinv [Si [k]] ; - } - for (k = 0 ; k < nz ; k++) - { - Sj [k] = Qinv [Sj [k]] ; - } - } - - C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; - D = NULL ; - E = NULL ; - F = NULL ; - G = NULL ; - - if (isreal) - { - - /* ------------------------------------------------------------------ */ - /* E = P*A*Q in sparse form */ - /* ------------------------------------------------------------------ */ - - D = CHOLMOD(copy) (A, 0, 1, cm) ; - E = CHOLMOD(submatrix) (D, P, nrow, Q, ncol, TRUE, FALSE, cm) ; - CHOLMOD(sort) (E, cm) ; - - /* ------------------------------------------------------------------ */ - /* F = E-G */ - /* ------------------------------------------------------------------ */ - - G = CHOLMOD(copy) (C, 0, 1, cm) ; - F = CHOLMOD(add) (E, G, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(drop) (0, F, cm) ; - nz = CHOLMOD(nnz) (F, cm) ; - if (F != NULL) - { - OK (nz == 0) ; - } - } - - CHOLMOD(free_sparse) (&F, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&H, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_triplet) (&S, cm) ; - - /* ---------------------------------------------------------------------- */ - /* submatrix */ - /* ---------------------------------------------------------------------- */ - - if (A->stype == 0 && isreal) - { - /* E = A(:,:) */ - E = CHOLMOD(submatrix) (A, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; - /* C = A-E */ - C = CHOLMOD(add) (A, E, one, minusone, TRUE, TRUE, cm) ; - ok = CHOLMOD(drop) (0., C, cm) ; - nz = CHOLMOD(nnz) (C, cm) ; - if (C != NULL) - { - OK (nz == 0) ; - } - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* test band and add, unsymmetric */ - /* ---------------------------------------------------------------------- */ - - if (isreal) - { - CHOLMOD(print_sparse) (A, "A for do triplet", cm) ; - - /* E = A */ - E = CHOLMOD(copy) (A, 0, 1, cm) ; - CHOLMOD(print_sparse) (E, "E=triu(A)", cm) ; - - /* E = triu (E) */ - CHOLMOD(band_inplace) (0, ncol, 1, E, cm) ; - - /* F = A */ - F = CHOLMOD(copy) (A, 0, 1, cm) ; - CHOLMOD(print_sparse) (F, "F=tril(A)", cm) ; - - /* F = tril(F,-1) */ - CHOLMOD(band_inplace) (-nrow, -1, 1, F, cm) ; - CHOLMOD(print_sparse) (F, "Ftril", cm) ; - - /* G = E+F */ - G = CHOLMOD(add) (E, F, one, one, TRUE, TRUE, cm) ; - CHOLMOD(print_sparse) (G, "G=E+F (1)", cm) ; - - /* D = A-G, which should be empty */ - D = CHOLMOD(add) (G, A, one, minusone, TRUE, TRUE, cm) ; - CHOLMOD(print_sparse) (D, "D=A-G", cm) ; - - CHOLMOD(drop) (0, D, cm) ; - CHOLMOD(print_sparse) (D, "D drop", cm) ; - nz = CHOLMOD(nnz) (D, cm) ; - if (D != NULL) - { - OK (nz == 0) ; - } - - CHOLMOD(free_sparse) (&F, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - - D = CHOLMOD(band) (A, 1, -1, 0, cm) ; - nz = CHOLMOD(nnz) (D, cm) ; - if (D != NULL) - { - OK (nz == 0) ; - } - CHOLMOD(free_sparse) (&D, cm) ; - D = CHOLMOD(band) (A, 0, 0, 0, cm) ; - nz = CHOLMOD(nnz) (D, cm) ; - if (D != NULL) - { - OK (nz == nzdiag (D)) ; - } - CHOLMOD(free_sparse) (&D, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* test band, add and copy_sparse (symmetric) */ - /* ---------------------------------------------------------------------- */ - - if (A->stype && isreal) - { - - /* E = A, in symmetric/upper form */ - E = CHOLMOD(copy) (A, 1, 1, cm) ; - CHOLMOD(print_sparse) (E, "E=A in sym/upper form", cm) ; - - /* E = -E */ - CHOLMOD(scale) (M1, CHOLMOD_SCALAR, E, cm) ; - - /* F = A, in symmetric/lower form */ - F = CHOLMOD(copy) (A, -1, 1, cm) ; - CHOLMOD(print_sparse) (F, "F=A in sym/lower form", cm) ; - - /* C = F (exact copy) */ - C = CHOLMOD(copy_sparse) (F, cm) ; - - /* G = E+C */ - G = CHOLMOD(add) (E, C, one, one, TRUE, FALSE, cm) ; - CHOLMOD(print_sparse) (G, "G = E+F", cm) ; - CHOLMOD(sort) (G, cm) ; - - CHOLMOD(drop) (0, G, cm) ; - CHOLMOD(print_sparse) (G, "G drop", cm) ; - nz = CHOLMOD(nnz) (G, cm) ; - if (G != NULL) - { - OK (nz == 0) ; - } - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - - } - - /* ---------------------------------------------------------------------- */ - /* try a dense identity matrix */ - /* ---------------------------------------------------------------------- */ - - X = CHOLMOD(eye) (3, 4, CHOLMOD_REAL, cm) ; - CHOLMOD(print_dense) (X, "Dense identity", cm) ; - CHOLMOD(free_dense) (&X, cm) ; - - /* ---------------------------------------------------------------------- */ - /* bisector and nested_dissection */ - /* ---------------------------------------------------------------------- */ - -#ifndef NPARTITION - if (A != NULL && A->nrow == A->ncol) - { - int64_t nc, nc_new ; - Int cnz, csep, save2 ; - Int *Cnw, *Cew, *Cmember, *CParent, *Perm ; - double save1 ; - - /* try CHOLMOD's interface to METIS_ComputeVertexSeparator */ - cm->metis_memory = 2.0 ; - CHOLMOD(print_sparse) (A, "A for bisect", cm) ; - csep = CHOLMOD(bisect) (A, NULL, 0, TRUE, Partition, cm) ; - if (csep != EMPTY) - { - Int csep2 ; - /* printf ("csep %g\n", (double) csep) ; */ - csep2 = check_partition (A, Partition) ; - /* printf ("csep2 %g\n", (double) csep2) ; */ - OK (csep == csep2) ; - } - - /* try the raw interface to METIS_ComputeVertexSeparator */ - CHOLMOD(print_sparse) (A, "A for metis bisect", cm) ; - - /* C = A+A', remove the diagonal */ - AT = CHOLMOD(transpose) (A, 0, cm) ; - E = CHOLMOD(add) (A, AT, one, one, FALSE, TRUE, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - C = CHOLMOD(copy) (E, 0, -1, cm) ; - CHOLMOD(print_sparse) (C, "C for metis bisect", cm) ; - - cnz = (C != NULL) ? (C->nzmax) : 0 ; - Cew = CHOLMOD(malloc) (cnz, sizeof (Int), cm) ; - Cnw = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - if (Cnw != NULL) - { - for (j = 0 ; j < (Int) (A->nrow) ; j++) - { - Cnw [j] = 1 ; - } - } - if (Cew != NULL) - { - for (j = 0 ; j < cnz ; j++) - { - Cew [j] = 1 ; - } - } - csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Partition, cm) ; - if (csep != EMPTY) - { - OK (csep == check_partition (C, Partition)) ; - } - CHOLMOD(free) (nrow, sizeof (Int), Cnw, cm) ; - CHOLMOD(free) (cnz, sizeof (Int), Cew, cm) ; - - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - - Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - CParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - Perm = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; - - save1 = cm->method [cm->current].nd_small ; - save2 = cm->method [cm->current].nd_oksep ; - cm->method [cm->current].nd_small = 1 ; - cm->method [cm->current].nd_oksep = 1.0 ; - - nc = CHOLMOD(nested_dissection) (A, NULL, 0, Perm, CParent, Cmember, - cm); - if (nc > 0) - { - OK (CHOLMOD(check_perm) (Perm, n, n, cm)) ; - } - - CHOLMOD(free_work) (cm) ; - - /* collapse the septree */ - if (nc > 0 && n > 0) - { - nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, - CParent, Cmember, cm) ; - - /* error checks */ - save = cm->error_handler ; - cm->error_handler = NULL ; - nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, - CParent, Cmember, NULL) ; - OK (nc_new == EMPTY) ; - nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, - NULL, Cmember, cm) ; - OK (nc_new == EMPTY) ; - nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, - CParent, NULL, cm) ; - OK (nc_new == EMPTY) ; - nc_new = CHOLMOD(collapse_septree) (0, 1, 0.1, 400, - CParent, Cmember, cm) ; - OK (nc_new == EMPTY) ; - nc_new = CHOLMOD(collapse_septree) (1, 1, 0.1, 400, - CParent, Cmember, cm) ; - OK (nc_new == 1 || nc_new == EMPTY) ; - nc_new = CHOLMOD(collapse_septree) (SIZE_MAX, SIZE_MAX, - 0.1, 400, CParent, Cmember, cm) ; - OK (nc_new == EMPTY) ; - - cm->error_handler = save ; - } - - CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), CParent, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), Perm, cm) ; - - cm->method [cm->current].nd_small = save1 ; - cm->method [cm->current].nd_oksep = save2 ; - - } -#endif - - /* ---------------------------------------------------------------------- */ - /* dense to/from sparse conversions */ - /* ---------------------------------------------------------------------- */ - - /* convert A to real, remove zero entries, and then convert to pattern */ - if (MAX (nrow, ncol) < 1000) - { - - C = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sparse_xtype) (CHOLMOD_REAL, C, cm) ; - CHOLMOD(drop) (0., C, cm) ; - D = CHOLMOD(copy) (C, 0, 0, cm) ; - CHOLMOD(sort) (D, cm) ; - - /* X = dense copy of C */ - CHOLMOD(sparse_xtype) (CHOLMOD_PATTERN, C, cm) ; - X = CHOLMOD(sparse_to_dense) (C, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - - /* change X to sparse pattern and then real/complex/zomplex, it should - * equal D */ - for (xtype2 = CHOLMOD_REAL ; xtype2 <= CHOLMOD_ZOMPLEX ; xtype2++) - { - E = CHOLMOD(dense_to_sparse) (X, FALSE, cm) ; - ok = CHOLMOD(sparse_xtype) (xtype2, E, cm) ; - ok = CHOLMOD(sparse_xtype) (xtype2, D, cm) ; - if (xtype2 == CHOLMOD_REAL) - { - F = CHOLMOD(add) (E, D, one, minusone, TRUE, TRUE, cm) ; - r = CHOLMOD(norm_sparse) (F, 0, cm) ; - if (F != NULL && cm->status == CHOLMOD_OK) - { - if (r != 0) - { - printf ("r %g at %d:%s\n", r, __LINE__, __FILE__) ; - } - OK (r == 0) ; - } - CHOLMOD(free_sparse) (&F, cm) ; - } - else - { - check_equality (E, D, xtype2) ; - } - CHOLMOD(free_sparse) (&E, cm) ; - } - - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_dense) (&X, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* unsymmetric transpose */ - /* ---------------------------------------------------------------------- */ - - len = ncol/2 ; - fset = prand (ncol) ; /* RAND */ - CHOLMOD(print_perm) (P, nrow, nrow, "P", cm) ; - CHOLMOD(print_subset) (fset, ncol, ncol, "fset", cm) ; - - if (isreal) - { - C = CHOLMOD(copy) (A, 0, 1, cm) ; - D = CHOLMOD(ptranspose) (C, 1, P, fset, len, cm) ; - E = CHOLMOD(transpose) (D, 1, cm) ; - F = CHOLMOD(transpose) (E, 1, cm) ; - G = CHOLMOD(add) (D, F, one, minusone, TRUE, FALSE, cm) ; - r = CHOLMOD(norm_sparse) (G, 0, cm) ; - if (G != NULL && cm->status == CHOLMOD_OK) - { - OK (r == 0) ; - } - CHOLMOD(drop) (0, G, cm) ; - r = CHOLMOD(norm_sparse) (G, 0, cm) ; - if (G != NULL && cm->status == CHOLMOD_OK) - { - OK (r == 0) ; - } - nz = CHOLMOD(nnz) (G, cm) ; - if (G != NULL && cm->status == CHOLMOD_OK) - { - OK (nz == 0) ; - } - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* symmetric array transpose */ - /* ---------------------------------------------------------------------- */ - - if (A->stype != 0) - { - - /* C = A(p,p).' */ - C = CHOLMOD(ptranspose) (A, 1, P, NULL, 0, cm) ; - - /* D = C(pinv,pinv).' */ - D = CHOLMOD(ptranspose) (C, 1, Pinv, NULL, 0, cm) ; - CHOLMOD(sort) (D, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - - /* C = A, sorted */ - C = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sort) (C, cm) ; - - int cstype = (C == NULL) ? 0 : C->stype ; - E = CHOLMOD(copy) (C, cstype, 1, cm) ; - F = CHOLMOD(copy) (D, cstype, 1, cm) ; - - /* C and D should be equal */ - check_equality (E, F, xtype) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; - - /* C = A.' */ - C = CHOLMOD(transpose) (A, 1, cm) ; - - /* D = C.' */ - D = CHOLMOD(transpose) (C, 1, cm) ; - CHOLMOD(sort) (D, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - - /* C = A, sorted */ - C = CHOLMOD(copy_sparse) (A, cm) ; - CHOLMOD(sort) (C, cm) ; - - cstype = (C == NULL) ? 0 : C->stype ; - E = CHOLMOD(copy) (C, cstype, 1, cm) ; - F = CHOLMOD(copy) (D, cstype, 1, cm) ; - - /* C and D should be equal */ - check_equality (E, F, xtype) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&F, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* matrix multiply */ - /* ---------------------------------------------------------------------- */ - - if (isreal) - { - /* this fails for a large arrowhead matrix, so turn off error hanlder */ - save = cm->error_handler ; - cm->error_handler = NULL ; - AT = CHOLMOD(transpose) (A, 1, cm) ; - D = CHOLMOD(copy) (A, 0, 1, cm) ; - if (n > NLARGE) progress (1, '.') ; - C = CHOLMOD(aat) (D, NULL, 0, 1, cm) ; - if (n > NLARGE) progress (1, '.') ; - CHOLMOD(print_common) ("After A*A'", cm) ; - - for (stype = -1 ; stype <= 1 ; stype++) - { - if (n > NLARGE) progress (1, '.') ; - E = CHOLMOD(ssmult) (A, AT, stype, TRUE, TRUE, cm) ; - if (n > NLARGE) progress (1, '.') ; - G = CHOLMOD(add) (C, E, one, minusone, TRUE, FALSE, cm) ; - if (n > NLARGE) progress (1, '.') ; - r = CHOLMOD(norm_sparse) (G, 0, cm) ; - if (G != NULL) - { - MAXERR (maxerr, r, anorm) ; - } - CHOLMOD(drop) (0, G, cm) ; - r = CHOLMOD(norm_sparse) (G, 0, cm) ; - if (G != NULL) - { - MAXERR (maxerr, r, anorm) ; - } - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - } - - if (nrow == ncol) - { - /* E = pattern of A */ - E = CHOLMOD(copy) (A, 0, 0, cm) ; - /* G = E*E */ - if (n > NLARGE) progress (1, '.') ; - G = CHOLMOD(ssmult) (E, E, 0, FALSE, FALSE, cm) ; - if (n > NLARGE) progress (1, '.') ; - CHOLMOD(free_sparse) (&E, cm) ; - CHOLMOD(free_sparse) (&G, cm) ; - } - - cm->error_handler = save ; - - CHOLMOD(free_sparse) (&D, cm) ; - CHOLMOD(free_sparse) (&C, cm) ; - CHOLMOD(free_sparse) (&AT, cm) ; - } - - /* ---------------------------------------------------------------------- */ - /* free P, Q, and their inverses */ - /* ---------------------------------------------------------------------- */ - - CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; - if (A->stype == 0) - { - CHOLMOD(free) (ncol, sizeof (Int), Q, cm) ; - } - CHOLMOD(free) (ncol, sizeof (Int), Qinv, cm) ; - CHOLMOD(free) (nrow, sizeof (Int), Partition, cm) ; - - progress (0, '.') ; - return (maxerr) ; -} diff --git a/CHOLMOD/Tcov/unpack.c b/CHOLMOD/Tcov/unpack.c deleted file mode 100644 index ea5471288f..0000000000 --- a/CHOLMOD/Tcov/unpack.c +++ /dev/null @@ -1,183 +0,0 @@ -//------------------------------------------------------------------------------ -// CHOLMOD/Tcov/unpack: test CHOLMOD unpacked matrices -//------------------------------------------------------------------------------ - -// CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis. -// All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0+ - -//------------------------------------------------------------------------------ - -/* Create an unpacked, unsorted version of a matrix, with random-sized gaps in - * each column. */ - -#include "cm.h" - - -/* ========================================================================== */ -/* === unpack =============================================================== */ -/* ========================================================================== */ - -cholmod_sparse *unpack (cholmod_sparse *A) -{ - double x ; - double *Ax, *Cx, *Az, *Cz ; - Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ; - cholmod_sparse *C ; - Int i, j, p, q, pdest, pend, nrow, ncol, nzmax, sorted, packed, stype, - extra ; - - if (A == NULL) - { - return (NULL) ; - } - - extra = 10 ; - - nrow = A->nrow ; - ncol = A->ncol ; - nzmax = A->nzmax ; - sorted = A->sorted ; - packed = A->packed ; - stype = A->stype ; - - C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax + extra*ncol, FALSE, - FALSE, stype, A->xtype, cm) ; - - if (C == NULL) - { - return (NULL) ; - } - - Ap = A->p ; - Ai = A->i ; - Ax = A->x ; - Az = A->z ; - Anz = A->nz ; - - Cp = C->p ; - Ci = C->i ; - Cx = C->x ; - Cz = C->z ; - Cnz = C->nz ; - nzmax = C->nzmax ; - nzmax = MAX (1, nzmax) ; - - for (p = 0 ; p < nzmax ; p++) - { - Ci [p] = 0 ; - } - if (A->xtype == CHOLMOD_REAL) - { - for (p = 0 ; p < nzmax ; p++) - { - Cx [p] = 0 ; - } - } - else if (A->xtype == CHOLMOD_COMPLEX) - { - for (p = 0 ; p < 2*nzmax ; p++) - { - Cx [p] = 0 ; - } - } - else if (A->xtype == CHOLMOD_ZOMPLEX) - { - for (p = 0 ; p < nzmax ; p++) - { - Cx [p] = 0 ; - Cz [p] = 0 ; - } - } - - pdest = 0 ; - for (j = 0 ; j < ncol ; j++) - { - /* copy the column into C */ - p = Ap [j] ; - Cp [j] = pdest ; - pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; - Cnz [j] = pend - p ; - for ( ; p < pend ; p++) - { - Ci [pdest] = Ai [p] ; - if (A->xtype == CHOLMOD_REAL) - { - Cx [pdest] = Ax [p] ; - } - else if (A->xtype == CHOLMOD_COMPLEX) - { - Cx [2*pdest ] = Ax [2*p] ; - Cx [2*pdest+1] = Ax [2*p+1] ; - } - else if (A->xtype == CHOLMOD_ZOMPLEX) - { - Cx [pdest] = Ax [p] ; - Cz [pdest] = Az [p] ; - } - pdest++ ; - } - - /* jumble the column */ - p = Cp [j] ; - pend = p + Cnz [j] ; - for ( ; p < pend-1 ; p++) - { - q = p + nrand (pend-p) ; /* RAND */ - i = Ci [p] ; - Ci [p] = Ci [q] ; - Ci [q] = i ; - - if (A->xtype == CHOLMOD_REAL) - { - x = Cx [p] ; - Cx [p] = Cx [q] ; - Cx [q] = x ; - } - else if (A->xtype == CHOLMOD_COMPLEX) - { - x = Cx [2*p] ; - Cx [2*p] = Cx [2*q] ; - Cx [2*q] = x ; - - x = Cx [2*p+1] ; - Cx [2*p+1] = Cx [2*q+1] ; - Cx [2*q+1] = x ; - } - else if (A->xtype == CHOLMOD_ZOMPLEX) - { - x = Cx [p] ; - Cx [p] = Cx [q] ; - Cx [q] = x ; - - x = Cz [p] ; - Cz [p] = Cz [q] ; - Cz [q] = x ; - } - } - - /* add some random blank space */ - pdest += nrand (extra) ; /* RAND */ - for (p = pend ; p < pdest ; p++) - { - Ci [p] = 0 ; - if (A->xtype == CHOLMOD_REAL) - { - Cx [p] = 0 ; - } - else if (A->xtype == CHOLMOD_COMPLEX) - { - Cx [2*p] = 0 ; - Cx [2*p+1] = 0 ; - } - else if (A->xtype == CHOLMOD_ZOMPLEX) - { - Cx [p] = 0 ; - Cz [p] = 0 ; - } - } - } - Cp [ncol] = pdest ; - - return (C) ; -} diff --git a/CHOLMOD/Utility/cholmod_allocate_factor.c b/CHOLMOD/Utility/cholmod_allocate_factor.c index 5ac43cae7c..30c0be0018 100644 --- a/CHOLMOD/Utility/cholmod_allocate_factor.c +++ b/CHOLMOD/Utility/cholmod_allocate_factor.c @@ -16,6 +16,7 @@ cholmod_factor *cholmod_allocate_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix cholmod_common *Common ) diff --git a/CHOLMOD/Utility/cholmod_allocate_work.c b/CHOLMOD/Utility/cholmod_allocate_work.c index 61e4996a3b..dc96918fda 100644 --- a/CHOLMOD/Utility/cholmod_allocate_work.c +++ b/CHOLMOD/Utility/cholmod_allocate_work.c @@ -12,6 +12,7 @@ int cholmod_allocate_work ( + // input: size_t nrow, size_t iworksize, size_t xworksize, diff --git a/CHOLMOD/Utility/cholmod_change_factor.c b/CHOLMOD/Utility/cholmod_change_factor.c index 3f9b0492e1..ffb0bc0ea7 100644 --- a/CHOLMOD/Utility/cholmod_change_factor.c +++ b/CHOLMOD/Utility/cholmod_change_factor.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Utility/cholmod_change_factor: change format of a factor object +// CHOLMOD/Utility/cholmod_change_factor: change format of a factor object //------------------------------------------------------------------------------ // CHOLMOD/Utility Module. Copyright (C) 2023, Timothy A. Davis, All Rights diff --git a/CHOLMOD/Utility/cholmod_divcomplex.c b/CHOLMOD/Utility/cholmod_divcomplex.c index cc3edb6e9e..c040ad6e64 100644 --- a/CHOLMOD/Utility/cholmod_divcomplex.c +++ b/CHOLMOD/Utility/cholmod_divcomplex.c @@ -14,6 +14,7 @@ int cholmod_divcomplex ( + // input: double ar, double ai, // a (real, imaginary) double br, double bi, // b (real, imaginary) double *cr, double *ci // c (real, imaginary) diff --git a/CHOLMOD/Utility/cholmod_l_allocate_factor.c b/CHOLMOD/Utility/cholmod_l_allocate_factor.c index cf81b411f0..dd6b6f3126 100644 --- a/CHOLMOD/Utility/cholmod_l_allocate_factor.c +++ b/CHOLMOD/Utility/cholmod_l_allocate_factor.c @@ -16,6 +16,7 @@ cholmod_factor *cholmod_l_allocate_factor // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix cholmod_common *Common ) diff --git a/CHOLMOD/Utility/cholmod_l_allocate_work.c b/CHOLMOD/Utility/cholmod_l_allocate_work.c index ee167e3548..5662b322f8 100644 --- a/CHOLMOD/Utility/cholmod_l_allocate_work.c +++ b/CHOLMOD/Utility/cholmod_l_allocate_work.c @@ -12,6 +12,7 @@ int cholmod_l_allocate_work ( + // input: size_t nrow, size_t iworksize, size_t xworksize, diff --git a/CHOLMOD/Utility/cholmod_l_change_factor.c b/CHOLMOD/Utility/cholmod_l_change_factor.c index f80779e70e..72faf2a01b 100644 --- a/CHOLMOD/Utility/cholmod_l_change_factor.c +++ b/CHOLMOD/Utility/cholmod_l_change_factor.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// CHOLMOD/Utility/cholmod_l_change_factor: change format of a factor object +// CHOLMOD/Utility/cholmod_l_change_factor: change format of a factor object //------------------------------------------------------------------------------ // CHOLMOD/Utility Module. Copyright (C) 2023, Timothy A. Davis, All Rights diff --git a/CHOLMOD/Utility/cholmod_l_divcomplex.c b/CHOLMOD/Utility/cholmod_l_divcomplex.c index 1a8901a0b5..1f18705961 100644 --- a/CHOLMOD/Utility/cholmod_l_divcomplex.c +++ b/CHOLMOD/Utility/cholmod_l_divcomplex.c @@ -12,6 +12,7 @@ int cholmod_l_divcomplex ( + // input: double ar, double ai, // a (real, imaginary) double br, double bi, // b (real, imaginary) double *cr, double *ci // c (real, imaginary) diff --git a/CHOLMOD/Utility/cholmod_memdebug.c b/CHOLMOD/Utility/cholmod_memdebug.c index eda9d86340..f2e738ab37 100644 --- a/CHOLMOD/Utility/cholmod_memdebug.c +++ b/CHOLMOD/Utility/cholmod_memdebug.c @@ -2,8 +2,8 @@ // CHOLMOD/Utility/cholmod_memdebug: memory debugging //------------------------------------------------------------------------------ -// CHOLMOD/Utility Module. Copyright (C) 2023, Timothy A. Davis -// All Rights Reserved. +// CHOLMOD/Utility Module. Copyright (C) 2023, Timothy A. Davis, All Rights +// Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ diff --git a/CHOLMOD/Utility/cholmod_mult_uint64_t.c b/CHOLMOD/Utility/cholmod_mult_uint64_t.c index 42a3a46530..78d7f85a72 100644 --- a/CHOLMOD/Utility/cholmod_mult_uint64_t.c +++ b/CHOLMOD/Utility/cholmod_mult_uint64_t.c @@ -29,7 +29,7 @@ bool cholmod_mult_uint64_t // c = a*b, return true if ok { if (a <= 1 || b <= 1) - { + { (*c) = a*b ; return (true) ; } @@ -37,7 +37,7 @@ bool cholmod_mult_uint64_t // c = a*b, return true if ok uint64_t a1 = a >> 30 ; // a1 = a / 2^30 uint64_t b1 = b >> 30 ; // b1 = b / 2^30 if (a1 > 0 && b1 > 0) - { + { // c = a*b will likely overflow, since both a and b are >= 2^30 and // thus c >= 2^60. This is slightly pessimistic. (*c) = UINT64_MAX ; @@ -73,7 +73,7 @@ bool cholmod_mult_uint64_t // c = a*b, return true if ok // a*b = (t0 + t1) * 2^30 + a0*b0 if (t0 >= 0x40000000L || t1 >= 0x40000000L) - { + { // t >= 2^31, so t * 2^30 might overflow. This is also slightly // pessimistic, but good enough for the usage of this function. (*c) = UINT64_MAX ; diff --git a/CHOLMOD/Utility/t_cholmod_aat.c b/CHOLMOD/Utility/t_cholmod_aat.c index 4147879c84..0ce23b419f 100644 --- a/CHOLMOD/Utility/t_cholmod_aat.c +++ b/CHOLMOD/Utility/t_cholmod_aat.c @@ -22,19 +22,21 @@ // 1 numerical, with non-conjugate transpose // 0 pattern, keeping the diagonal // -1 pattern, remove the diagonal -// -2 pattern, and add 50% + n extra space to C +// -2 pattern, and add 50% + n extra space to C // as elbow room for AMD and CAMD, when converting // a symmetric matrix A to an unsymmetric matrix C #include "cholmod_internal.h" #define RETURN_IF_ERROR \ +{ \ if (Common->status < CHOLMOD_OK) \ { \ CHOLMOD(free_sparse) (&C, Common) ; \ CHOLMOD(free_sparse) (&F, Common) ; \ return (NULL) ; \ - } + } \ +} //------------------------------------------------------------------------------ // t_cholmod_aat_worker template @@ -66,11 +68,14 @@ cholmod_sparse *CHOLMOD(aat) ( + // input: cholmod_sparse *A, // input matrix Int *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) + // -1: pattern (remove diag), // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) @@ -84,14 +89,16 @@ cholmod_sparse *CHOLMOD(aat) RETURN_IF_SPARSE_MATRIX_INVALID (A, NULL) ; Common->status = CHOLMOD_OK ; cholmod_sparse *C = NULL, *F = NULL ; - ASSERT (CHOLMOD(dump_sparse) (A, "aat:A", Common) >= 0) ; - if (A->stype != 0) { ERROR (CHOLMOD_INVALID, "input matrix must be unsymmetric") ; return (NULL) ; } + mode = RANGE (mode, -2, 2) ; + + ASSERT (CHOLMOD(dump_sparse) (A, "aat:A", Common) >= 0) ; + //-------------------------------------------------------------------------- // get inputs //-------------------------------------------------------------------------- @@ -147,8 +154,10 @@ cholmod_sparse *CHOLMOD(aat) // cnz = nnz (C) //-------------------------------------------------------------------------- - int64_t cnz = 0 ; - for (Int j = 0 ; j < n ; j++) + int ok = TRUE ; + size_t cnz = 0 ; + size_t cnzmax = SIZE_MAX - A->nrow ; + for (Int j = 0 ; ok && (j < n) ; j++) { //---------------------------------------------------------------------- @@ -190,24 +199,23 @@ cholmod_sparse *CHOLMOD(aat) } //---------------------------------------------------------------------- - // check for integer overflow + // check if nearing integer overflow //---------------------------------------------------------------------- - if (cnz < 0 || cnz >= Int_max / sizeof (Int)) - { - Common->status = CHOLMOD_TOO_LARGE ; - break ; - } + ok = (cnz < cnzmax) ; } - RETURN_IF_ERROR ; - //-------------------------------------------------------------------------- // allocate C //-------------------------------------------------------------------------- - size_t cnzmax = cnz + ((mode == -2) ? (cnz/2 + n) : 0) ; - C = CHOLMOD(allocate_sparse) (n, n, cnzmax, + if (mode == -2 && ok) + { + // add some extra space + cnz = CHOLMOD(add_size_t) (cnz, cnz/2, &ok) ; + cnz = CHOLMOD(add_size_t) (cnz, A->nrow, &ok) ; + } + C = CHOLMOD(allocate_sparse) (n, n, ok ? cnz : SIZE_MAX, /* C is not sorted: */ FALSE, /* C is packed: */ TRUE, /* C stype: */ 0, axtype + A->dtype, Common) ; RETURN_IF_ERROR ; @@ -218,33 +226,32 @@ cholmod_sparse *CHOLMOD(aat) switch ((C->xtype + C->dtype) % 8) { - default: p_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_aat_worker (C, A, F, ignore_diag, Common) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_add.c b/CHOLMOD/Utility/t_cholmod_add.c index e618998e76..7bbddd6f24 100644 --- a/CHOLMOD/Utility/t_cholmod_add.c +++ b/CHOLMOD/Utility/t_cholmod_add.c @@ -55,11 +55,14 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B ( + // input: cholmod_sparse *A, // input matrix cholmod_sparse *B, // input matrix - double alpha [2], // scale factor for A (two entires used if complex) + double alpha [2], // scale factor for A (two entries used if complex) double beta [2], // scale factor for B (two entries used if complex) - int values, // if TRUE compute the numerical values of C + int mode, // 2: numerical (conj) if A and/or B are symmetric, + // 1: numerical (non-conj.) if A and/or B are symmetric. + // 0: pattern int sorted, // ignored; C is now always returned as sorted cholmod_common *Common ) @@ -72,8 +75,6 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_SPARSE_MATRIX_INVALID (A, NULL) ; RETURN_IF_SPARSE_MATRIX_INVALID (B, NULL) ; - ASSERT (CHOLMOD(dump_sparse) (A, "add:A", Common) >= 0) ; - ASSERT (CHOLMOD(dump_sparse) (B, "add:B", Common) >= 0) ; Common->status = CHOLMOD_OK ; cholmod_sparse *A2 = NULL, *B2 = NULL, *C = NULL ; @@ -83,12 +84,14 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B return (NULL) ; } + mode = RANGE (mode, 0, 2) ; + int axtype = A->xtype ; int bxtype = B->xtype ; - if (!values || axtype == CHOLMOD_PATTERN || bxtype == CHOLMOD_PATTERN) + if (mode == 0 || axtype == CHOLMOD_PATTERN || bxtype == CHOLMOD_PATTERN) { // treat A and B as if they are pattern-only matrices; C is pattern - values = FALSE ; + mode = 0 ; axtype = CHOLMOD_PATTERN ; bxtype = CHOLMOD_PATTERN ; } @@ -99,7 +102,7 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B return (NULL) ; } - if (values && A->dtype != B->dtype) + if (mode != 0 && A->dtype != B->dtype) { ERROR (CHOLMOD_INVALID, "A and B dtypes do not match") ; return (NULL) ; @@ -108,6 +111,9 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B int xtype = axtype ; int dtype = A->dtype ; + ASSERT (CHOLMOD(dump_sparse) (A, "add:A", Common) >= 0) ; + ASSERT (CHOLMOD(dump_sparse) (B, "add:B", Common) >= 0) ; + //-------------------------------------------------------------------------- // get the sizes of the entries of C, A, and B //-------------------------------------------------------------------------- @@ -122,8 +128,6 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B // convert/sort A and/or B, if needed //-------------------------------------------------------------------------- - int mode = values ? 1 : 0 ; - if (A->stype == B->stype) { @@ -211,28 +215,28 @@ cholmod_sparse *CHOLMOD(add) // return C = alpha*A + beta*B p_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_add_worker (C, A, B, alpha, beta, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_add_worker.c b/CHOLMOD/Utility/t_cholmod_add_worker.c index f73557aa6c..dc39270fb6 100644 --- a/CHOLMOD/Utility/t_cholmod_add_worker.c +++ b/CHOLMOD/Utility/t_cholmod_add_worker.c @@ -60,6 +60,8 @@ static void TEMPLATE (cholmod_add_worker) Real alphax [2], betax [2] ; alphax [0] = (Real) alpha [0] ; betax [0] = (Real) beta [0] ; + alphax [1] = 0 ; + betax [1] = 0 ; #endif #ifdef COMPLEX diff --git a/CHOLMOD/Utility/t_cholmod_alloc_factor.c b/CHOLMOD/Utility/t_cholmod_alloc_factor.c index 58a68e52d1..8166c0f247 100644 --- a/CHOLMOD/Utility/t_cholmod_alloc_factor.c +++ b/CHOLMOD/Utility/t_cholmod_alloc_factor.c @@ -25,6 +25,7 @@ cholmod_factor *CHOLMOD(alloc_factor) // return the new factor L ( + // input: size_t n, // L is factorization of an n-by-n matrix int dtype, // CHOLMOD_SINGLE or CHOLMOD_DOUBLE cholmod_common *Common diff --git a/CHOLMOD/Utility/t_cholmod_alloc_work.c b/CHOLMOD/Utility/t_cholmod_alloc_work.c index d45e3549d2..3150fe48af 100644 --- a/CHOLMOD/Utility/t_cholmod_alloc_work.c +++ b/CHOLMOD/Utility/t_cholmod_alloc_work.c @@ -30,6 +30,7 @@ int CHOLMOD(alloc_work) ( + // input: size_t nrow, // # of rows in the matrix A size_t iworksize, // size of Iwork (# of integers, int32 or int64) size_t xworksize, // size of Xwork (in # of entries, double or single) diff --git a/CHOLMOD/Utility/t_cholmod_allocate_dense.c b/CHOLMOD/Utility/t_cholmod_allocate_dense.c index b0da190f27..64ff028c7e 100644 --- a/CHOLMOD/Utility/t_cholmod_allocate_dense.c +++ b/CHOLMOD/Utility/t_cholmod_allocate_dense.c @@ -21,6 +21,7 @@ cholmod_dense *CHOLMOD(allocate_dense) ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension diff --git a/CHOLMOD/Utility/t_cholmod_allocate_sparse.c b/CHOLMOD/Utility/t_cholmod_allocate_sparse.c index ca38c9f72b..fbc51d0a59 100644 --- a/CHOLMOD/Utility/t_cholmod_allocate_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_allocate_sparse.c @@ -23,6 +23,7 @@ cholmod_sparse *CHOLMOD(allocate_sparse) ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold diff --git a/CHOLMOD/Utility/t_cholmod_allocate_triplet.c b/CHOLMOD/Utility/t_cholmod_allocate_triplet.c index 55572ff7c8..d1314e76b7 100644 --- a/CHOLMOD/Utility/t_cholmod_allocate_triplet.c +++ b/CHOLMOD/Utility/t_cholmod_allocate_triplet.c @@ -22,6 +22,7 @@ cholmod_triplet *CHOLMOD(allocate_triplet) // return triplet matrix T ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -42,8 +43,8 @@ cholmod_triplet *CHOLMOD(allocate_triplet) // return triplet matrix T if (stype != 0 && nrow != ncol) { - ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; - return (NULL) ; + ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; + return (NULL) ; } //-------------------------------------------------------------------------- diff --git a/CHOLMOD/Utility/t_cholmod_band.c b/CHOLMOD/Utility/t_cholmod_band.c index 1fd981c261..88abe6e7dc 100644 --- a/CHOLMOD/Utility/t_cholmod_band.c +++ b/CHOLMOD/Utility/t_cholmod_band.c @@ -16,6 +16,10 @@ // The diagonal can be ignored, if the ignore_diag flag is true. // C can optionally be constructed as a pattern matrix. +// The stype is not changed, and no transpose takes place, so a mode of 1 and 2 +// have the same effect (unlike cholmod_tranpose, cholmod_copy, cholmod_aat, +// cholmod_vertcat, cholmod_horzcat, ... + #include "cholmod_internal.h" #define RETURN_IF_ERROR \ @@ -58,7 +62,7 @@ static cholmod_sparse *band_helper cholmod_sparse *A, int64_t k1, // count entries in k1:k2 diagonals int64_t k2, - bool values, // if true and A numerical, C is numerical + bool values, // if true and A numerical, C is numerical bool inplace, // if true, convert A in place (A cannot be packed) bool ignore_diag, // if true, ignore diagonal cholmod_common *Common @@ -131,30 +135,30 @@ static cholmod_sparse *band_helper { default: p_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; - break ; + break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_band_worker (C, A, k1, k2, ignore_diag) ; break ; } @@ -185,6 +189,7 @@ static cholmod_sparse *band_helper cholmod_sparse *CHOLMOD(band) // return a new matrix C ( + // input: cholmod_sparse *A, // input matrix int64_t k1, // count entries in k1:k2 diagonals int64_t k2, @@ -192,6 +197,7 @@ cholmod_sparse *CHOLMOD(band) // return a new matrix C cholmod_common *Common ) { + mode = RANGE (mode, -1, 1) ; bool values = (mode > 0) ; bool inplace = FALSE ; bool ignore_diag = (mode < 0) ; @@ -204,13 +210,16 @@ cholmod_sparse *CHOLMOD(band) // return a new matrix C int CHOLMOD(band_inplace) ( + // input: int64_t k1, // count entries in k1:k2 diagonals int64_t k2, int mode, // >0: numerical, 0: pattern, <0: pattern (no diag) + // input/output: cholmod_sparse *A, // input/output matrix cholmod_common *Common ) { + mode = RANGE (mode, -1, 1) ; bool values = (mode > 0) ; bool inplace = TRUE ; bool ignore_diag = (mode < 0) ; diff --git a/CHOLMOD/Utility/t_cholmod_band_nnz.c b/CHOLMOD/Utility/t_cholmod_band_nnz.c index 0f3d0d3e31..286b3643da 100644 --- a/CHOLMOD/Utility/t_cholmod_band_nnz.c +++ b/CHOLMOD/Utility/t_cholmod_band_nnz.c @@ -17,6 +17,7 @@ int64_t CHOLMOD(band_nnz) // return # of entries in a band (-1 if error) ( + // input: cholmod_sparse *A, // matrix to examine int64_t k1, // count entries in k1:k2 diagonals int64_t k2, diff --git a/CHOLMOD/Utility/t_cholmod_band_worker.c b/CHOLMOD/Utility/t_cholmod_band_worker.c index 2729ed5f75..4df3cc329a 100644 --- a/CHOLMOD/Utility/t_cholmod_band_worker.c +++ b/CHOLMOD/Utility/t_cholmod_band_worker.c @@ -31,7 +31,7 @@ static void TEMPLATE (cholmod_band_worker) Int *Anz = (Int *) A->nz ; Int *Ai = (Int *) A->i ; Real *Ax = (Real *) A->x ; - Real *Az = (Real *) A->x ; + Real *Az = (Real *) A->z ; bool packed = A->packed ; Int *Cp = (Int *) C->p ; diff --git a/CHOLMOD/Utility/t_cholmod_bound.c b/CHOLMOD/Utility/t_cholmod_bound.c index 7045068e4d..ea1878946a 100644 --- a/CHOLMOD/Utility/t_cholmod_bound.c +++ b/CHOLMOD/Utility/t_cholmod_bound.c @@ -22,6 +22,7 @@ Real CHOLMOD_BOUND_FUNCTION // returns modified diagonal entry D(j,j) ( + // input: Real djj, // input diagonal entry D(j,j) cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_change_factor.c b/CHOLMOD/Utility/t_cholmod_change_factor.c index 2d88b417bb..2f456f1a70 100644 --- a/CHOLMOD/Utility/t_cholmod_change_factor.c +++ b/CHOLMOD/Utility/t_cholmod_change_factor.c @@ -132,12 +132,12 @@ static Int grow_L (Int lnz, double grow0, Int n) { double xlnz = (double) lnz ; xlnz *= grow0 ; - xlnz = MIN (xlnz, (double) SIZE_MAX) ; + xlnz = MIN (xlnz, (double) Int_max) ; double d = (double) n ; d = (d*d + d) / 2 ; xlnz = MIN (xlnz, d) ; - lnz = (Int) xlnz ; - return (lnz) ; + Int newlnz = MAX (lnz, (Int) xlnz) ; + return (newlnz) ; } //------------------------------------------------------------------------------ @@ -513,7 +513,7 @@ static void simplicial_sym_to_simplicial_num // initialize the packed LL' or LDL' case (L is identity) //---------------------------------------------------------------------- - for (Int j = 0 ; j < n ; j++) + for (Int j = 0 ; ok && (j < n) ; j++) { // ensure ColCount [j] is in the range 1 to n-j Int len = ColCount [j] ; @@ -521,7 +521,6 @@ static void simplicial_sym_to_simplicial_num len = MIN (len, n-j) ; lnz += len ; ok = (lnz >= 0) ; - if (!ok) break ; } // each column L(:,j) holds a single diagonal entry for (Int j = 0 ; j <= n ; j++) @@ -549,7 +548,7 @@ static void simplicial_sym_to_simplicial_num grow1 = isnan (grow1) ? 1 : grow1 ; Int grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ; - for (Int j = 0 ; j < n ; j++) + for (Int j = 0 ; ok && (j < n) ; j++) { //------------------------------------------------------------------ @@ -577,7 +576,6 @@ static void simplicial_sym_to_simplicial_num } lnz += len ; ok = (lnz >= 0) ; - if (!ok) break ; } //---------------------------------------------------------------------- @@ -601,6 +599,7 @@ static void simplicial_sym_to_simplicial_num ASSERT (L->nzmax == 0) ; lnz = MAX (1, lnz) ; int nint = 1 ; + Common->status = (ok) ? CHOLMOD_OK : CHOLMOD_TOO_LARGE ; if (!ok || !CHOLMOD(realloc_multiple) (lnz, nint, to_xtype + L->dtype, &(L->i), NULL, &(L->x), &(L->z), &(L->nzmax), Common)) { @@ -618,31 +617,30 @@ static void simplicial_sym_to_simplicial_num if (packed >= 0) { - switch ((L->xtype + L->dtype) % 8) { - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_change_factor_1_worker (L) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_change_factor_1_worker (L) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_change_factor_1_worker (L) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_change_factor_1_worker (L) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_change_factor_1_worker (L) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_change_factor_1_worker (L) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_change_factor_1_worker (L) ; break ; } } @@ -750,7 +748,8 @@ static void change_simplicial_num // compute the new space for each column of L //---------------------------------------------------------------------- - for (Int j = 0 ; j < n ; j++) + bool ok = true ; + for (Int j = 0 ; ok && (j < n) ; j++) { Int len = Lnz [j] ; ASSERT (len >= 1 && len <= n-j) ; @@ -760,31 +759,37 @@ static void change_simplicial_num } ASSERT (len >= Lnz [j] && len <= n-j) ; lnz += len ; - if (lnz <= 0) + ok = (lnz >= 0) ; + } + + Common->status = (ok) ? CHOLMOD_OK : CHOLMOD_TOO_LARGE ; + if (ok) + { + + //------------------------------------------------------------------ + // add additional space at the end of L, if requested + //------------------------------------------------------------------ + + if (grow) { - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - return ; + lnz = grow_L (lnz, grow0, n) ; } - } - //---------------------------------------------------------------------- - // add additional space at the end of L, if requested - //---------------------------------------------------------------------- + //------------------------------------------------------------------ + // allocate Li2, Lx2, and Lz2 (as newly allocated space) + //------------------------------------------------------------------ - if (grow) - { - lnz = grow_L (lnz, grow0, n) ; + lnz = MAX (1, lnz) ; + int nint = 1 ; + size_t nzmax0 = 0 ; + CHOLMOD(realloc_multiple) (lnz, nint, L->xtype + L->dtype, &Li2, + NULL, &Lx2, &Lz2, &nzmax0, Common) ; } //---------------------------------------------------------------------- - // allocate Li2, Lx2, and Lz2 (as newly allocated space) + // return if out of memory or problem too large //---------------------------------------------------------------------- - lnz = MAX (1, lnz) ; - int nint = 1 ; - size_t nzmax0 = 0 ; - CHOLMOD(realloc_multiple) (lnz, nint, L->xtype + L->dtype, &Li2, - NULL, &Lx2, &Lz2, &nzmax0, Common) ; RETURN_IF_ERROR () ; } @@ -794,38 +799,38 @@ static void change_simplicial_num switch ((L->xtype + L->dtype) % 8) { - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_change_factor_2_worker (L, to_packed, Li2, Lx2, Lz2, lnz, grow, grow1, grow2, make_ll, out_of_place, make_ldl, Common) ; break ; @@ -1014,19 +1019,19 @@ static void super_num_to_simplicial_num switch ((L->xtype + L->dtype) % 8) { case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; + rs_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; break ; case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; + cs_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; break ; case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; + rd_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; break ; case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; + cd_cholmod_change_factor_3_worker (L, to_packed, to_ll, Common) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_change_factor_2_template.c b/CHOLMOD/Utility/t_cholmod_change_factor_2_template.c index 1e5988eb7f..d3ed73dbaa 100644 --- a/CHOLMOD/Utility/t_cholmod_change_factor_2_template.c +++ b/CHOLMOD/Utility/t_cholmod_change_factor_2_template.c @@ -15,7 +15,7 @@ // the new L is created in new space: Li2, Lx2, Lz2 #define Li_NEW Li2 #define Lx_NEW Lx2 - #define Lz_NEW Lx2 + #define Lz_NEW Lz2 #else // L is modified in its existing space: Li, Lx, and Lz #define Li_NEW Li diff --git a/CHOLMOD/Utility/t_cholmod_change_xdtype.c b/CHOLMOD/Utility/t_cholmod_change_xdtype.c index 8aaf8d23de..aa74c6f339 100644 --- a/CHOLMOD/Utility/t_cholmod_change_xdtype.c +++ b/CHOLMOD/Utility/t_cholmod_change_xdtype.c @@ -88,7 +88,9 @@ static int change_xdtype int CHOLMOD(sparse_xtype) ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_sparse *A, // sparse matrix to change cholmod_common *Common ) @@ -118,7 +120,9 @@ int CHOLMOD(sparse_xtype) int CHOLMOD(triplet_xtype) ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_triplet *T, // triplet matrix to change cholmod_common *Common ) @@ -148,7 +152,9 @@ int CHOLMOD(triplet_xtype) int CHOLMOD(dense_xtype) ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_dense *X, // dense matrix to change cholmod_common *Common ) @@ -172,7 +178,7 @@ int CHOLMOD(dense_xtype) { // output_xtype not supported ERROR (CHOLMOD_INVALID, "invalid xtype") ; - return (FALSE) ; + return (FALSE) ; } return (change_xdtype (X->nzmax, &(X->xtype), output_xtype, @@ -185,7 +191,9 @@ int CHOLMOD(dense_xtype) int CHOLMOD(factor_xtype) ( + // input: int to_xdtype, // requested xtype and dtype + // input/output: cholmod_factor *L, // factor to change cholmod_common *Common ) @@ -205,12 +213,12 @@ int CHOLMOD(factor_xtype) int output_xtype = to_xdtype & 3 ; // real, complex, or zomplex int output_dtype = to_xdtype & 4 ; // double or single - if (output_xtype <= CHOLMOD_PATTERN || + if (output_xtype <= CHOLMOD_PATTERN || L->is_super && output_xtype == CHOLMOD_ZOMPLEX) { // output_xtype not supported ERROR (CHOLMOD_INVALID, "invalid xtype") ; - return (FALSE) ; + return (FALSE) ; } Int nzmax = L->is_super ? L->xsize : L->nzmax ; diff --git a/CHOLMOD/Utility/t_cholmod_copy.c b/CHOLMOD/Utility/t_cholmod_copy.c index d8b3784499..775a6d5a3d 100644 --- a/CHOLMOD/Utility/t_cholmod_copy.c +++ b/CHOLMOD/Utility/t_cholmod_copy.c @@ -42,7 +42,7 @@ // 1 numerical, with non-conjugate transpose // 0 pattern, keeping the diagonal // -1 pattern, remove the diagonal -// -2 pattern, and add 50% + n extra space to C +// -2 pattern, and add 50% + n extra space to C // as elbow room for AMD and CAMD, when converting // a symmetric matrix A to an unsymmetric matrix C @@ -101,10 +101,13 @@ cholmod_sparse *CHOLMOD(copy) ( + // input: cholmod_sparse *A, // input matrix, not modified int stype, // stype of C - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // 0: pattern (with diag), -1: pattern (remove diag), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) + // -1: pattern (remove diag) // -2: pattern (remove diag; add ~50% extra space in C) cholmod_common *Common ) @@ -133,11 +136,12 @@ cholmod_sparse *CHOLMOD(copy) // get inputs //-------------------------------------------------------------------------- + mode = RANGE (mode, -2, 2) ; bool ignore_diag = (mode < 0) ; bool up = (astype > 0) ; bool lo = (astype < 0) ; bool values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; - bool conj = (mode >= 2) ; + bool conj = (mode == 2) ; //-------------------------------------------------------------------------- // copy the matrix @@ -161,8 +165,8 @@ cholmod_sparse *CHOLMOD(copy) // A is unsymmetric; C is symmetric upper or lower //---------------------------------------------------------------------- - size_t nlo = (stype > 0) ? 0 : (-nrow) ; - size_t nup = (stype > 0) ? ncol : 0 ; + size_t nlo = (stype > 0) ? 0 : (-nrow) ; + size_t nup = (stype > 0) ? ncol : 0 ; C = CHOLMOD(band) (A, nlo, nup, mode, Common) ; RETURN_IF_ERROR ; C->stype = stype ; @@ -267,55 +271,55 @@ cholmod_sparse *CHOLMOD(copy) p_cholmod_copy_worker (C, A, ignore_diag, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_copy_worker (C, A, ignore_diag, Common) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_copy_worker (C, A, ignore_diag, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: if (conj) { - c_s_cholmod_copy_worker (C, A, ignore_diag, Common) ; + cs_cholmod_copy_worker (C, A, ignore_diag, Common) ; } else { - ct_s_cholmod_copy_worker (C, A, ignore_diag, Common) ; + cs_t_cholmod_copy_worker (C, A, ignore_diag, Common) ; } break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: if (conj) { - z_s_cholmod_copy_worker (C, A, ignore_diag, Common) ; + zs_cholmod_copy_worker (C, A, ignore_diag, Common) ; } else { - zt_s_cholmod_copy_worker (C, A, ignore_diag, Common) ; + zs_t_cholmod_copy_worker (C, A, ignore_diag, Common) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_copy_worker (C, A, ignore_diag, Common) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_copy_worker (C, A, ignore_diag, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: if (conj) { - c_cholmod_copy_worker (C, A, ignore_diag, Common) ; + cd_cholmod_copy_worker (C, A, ignore_diag, Common) ; } else { - ct_cholmod_copy_worker (C, A, ignore_diag, Common) ; + cd_t_cholmod_copy_worker (C, A, ignore_diag, Common) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: if (conj) { - z_cholmod_copy_worker (C, A, ignore_diag, Common) ; + zd_cholmod_copy_worker (C, A, ignore_diag, Common) ; } else { - zt_cholmod_copy_worker (C, A, ignore_diag, Common) ; + zd_t_cholmod_copy_worker (C, A, ignore_diag, Common) ; } break ; } diff --git a/CHOLMOD/Utility/t_cholmod_copy_dense.c b/CHOLMOD/Utility/t_cholmod_copy_dense.c index 137a1b2c12..ea6cdcea50 100644 --- a/CHOLMOD/Utility/t_cholmod_copy_dense.c +++ b/CHOLMOD/Utility/t_cholmod_copy_dense.c @@ -22,6 +22,7 @@ cholmod_dense *CHOLMOD(copy_dense) // returns new dense matrix ( + // input: cholmod_dense *X, // input dense matrix cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_copy_dense2.c b/CHOLMOD/Utility/t_cholmod_copy_dense2.c index c19b4f531a..220c238167 100644 --- a/CHOLMOD/Utility/t_cholmod_copy_dense2.c +++ b/CHOLMOD/Utility/t_cholmod_copy_dense2.c @@ -39,7 +39,9 @@ int CHOLMOD(copy_dense2) ( + // input: cholmod_dense *X, // input dense matrix + // input/output: cholmod_dense *Y, // output dense matrix (already allocated on input) cholmod_common *Common ) @@ -96,28 +98,28 @@ int CHOLMOD(copy_dense2) switch ((X->xtype + X->dtype) % 8) { - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_copy_dense2_worker (X, Y) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_copy_dense2_worker (X, Y) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_copy_dense2_worker (X, Y) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_copy_dense2_worker (X, Y) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_copy_dense2_worker (X, Y) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_copy_dense2_worker (X, Y) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_copy_dense2_worker (X, Y) ; break ; } } diff --git a/CHOLMOD/Utility/t_cholmod_copy_factor.c b/CHOLMOD/Utility/t_cholmod_copy_factor.c index 9f4102fd0d..d770a73df6 100644 --- a/CHOLMOD/Utility/t_cholmod_copy_factor.c +++ b/CHOLMOD/Utility/t_cholmod_copy_factor.c @@ -44,6 +44,7 @@ cholmod_factor *CHOLMOD(copy_factor) // return a copy of the factor ( + // input: cholmod_factor *L, // factor to copy (not modified) cholmod_common *Common ) @@ -74,7 +75,7 @@ cholmod_factor *CHOLMOD(copy_factor) // return a copy of the factor // allocate the new factor H, H->Perm, and H->ColCount //-------------------------------------------------------------------------- - cholmod_factor *H = CHOLMOD(allocate_factor) (n, Common) ; + cholmod_factor *H = CHOLMOD(alloc_factor) (n, L->dtype, Common) ; RETURN_IF_ERROR ; //-------------------------------------------------------------------------- @@ -152,29 +153,28 @@ cholmod_factor *CHOLMOD(copy_factor) // return a copy of the factor switch ((L->xtype + L->dtype) % 8) { - - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_copy_factor_worker (L, H) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_copy_factor_worker (L, H) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_copy_factor_worker (L, H) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_copy_factor_worker (L, H) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_copy_factor_worker (L, H) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_copy_factor_worker (L, H) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_copy_factor_worker (L, H) ; break ; } } diff --git a/CHOLMOD/Utility/t_cholmod_copy_sparse.c b/CHOLMOD/Utility/t_cholmod_copy_sparse.c index 042bd2bbd8..0a59f316fd 100644 --- a/CHOLMOD/Utility/t_cholmod_copy_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_copy_sparse.c @@ -47,6 +47,7 @@ cholmod_sparse *CHOLMOD(copy_sparse) // return new sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to copy cholmod_common *Common ) @@ -108,28 +109,28 @@ cholmod_sparse *CHOLMOD(copy_sparse) // return new sparse matrix p_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_copy_sparse_worker (C, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_copy_sparse_worker (C, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_copy_sparse_worker (C, A) ; break ; } } diff --git a/CHOLMOD/Utility/t_cholmod_copy_triplet.c b/CHOLMOD/Utility/t_cholmod_copy_triplet.c index 9acab33a86..276084c278 100644 --- a/CHOLMOD/Utility/t_cholmod_copy_triplet.c +++ b/CHOLMOD/Utility/t_cholmod_copy_triplet.c @@ -19,6 +19,7 @@ cholmod_triplet *CHOLMOD(copy_triplet) // return new triplet matrix ( + // input: cholmod_triplet *T, // triplet matrix to copy cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_defaults.c b/CHOLMOD/Utility/t_cholmod_defaults.c index a6525a5686..ae4460472f 100644 --- a/CHOLMOD/Utility/t_cholmod_defaults.c +++ b/CHOLMOD/Utility/t_cholmod_defaults.c @@ -113,7 +113,7 @@ int CHOLMOD(defaults) (cholmod_common *Common) Common->method [8].ordering = CHOLMOD_COLAMD ; //-------------------------------------------------------------------------- - // GPU + // GPU //-------------------------------------------------------------------------- #if defined ( CHOLMOD_INT64 ) diff --git a/CHOLMOD/Utility/t_cholmod_dense_nnz.c b/CHOLMOD/Utility/t_cholmod_dense_nnz.c index cc48defd74..e1419bee91 100644 --- a/CHOLMOD/Utility/t_cholmod_dense_nnz.c +++ b/CHOLMOD/Utility/t_cholmod_dense_nnz.c @@ -39,6 +39,7 @@ int64_t CHOLMOD(dense_nnz) // return # of entries in the dense matrix ( + // input: cholmod_dense *X, // input matrix cholmod_common *Common ) @@ -60,29 +61,28 @@ int64_t CHOLMOD(dense_nnz) // return # of entries in the dense matrix int xnz = 0 ; switch ((X->xtype + X->dtype) % 8) { - - case CHOLMOD_SINGLE + CHOLMOD_REAL: - xnz = r_s_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + xnz = rs_cholmod_dense_nnz_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - xnz = c_s_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + xnz = cs_cholmod_dense_nnz_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - xnz = z_s_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + xnz = zs_cholmod_dense_nnz_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - xnz = r_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + xnz = rd_cholmod_dense_nnz_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - xnz = c_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + xnz = cd_cholmod_dense_nnz_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - xnz = z_cholmod_dense_nnz_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + xnz = zd_cholmod_dense_nnz_worker (X) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_dense_to_sparse.c b/CHOLMOD/Utility/t_cholmod_dense_to_sparse.c index 03267f3841..be164ddedd 100644 --- a/CHOLMOD/Utility/t_cholmod_dense_to_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_dense_to_sparse.c @@ -9,8 +9,8 @@ //------------------------------------------------------------------------------ // Converts a dense matrix X (as input) to a new sparse matrix C (as output). -// The xtype and dtype are preserved, except if values is false in which case -// C is returned as a pattern sparse matrix. +// The xtype and dtype are preserved, except if mode is 0 in which case C is +// returned as a pattern sparse matrix. #include "cholmod_internal.h" @@ -48,8 +48,10 @@ cholmod_sparse *CHOLMOD(dense_to_sparse) // return a sparse matrix C ( + // input: cholmod_dense *X, // input matrix - int values, // if true, copy the values; if false, C is pattern + int mode, // 1: copy the values + // 0: C is pattern cholmod_common *Common ) { @@ -67,8 +69,9 @@ cholmod_sparse *CHOLMOD(dense_to_sparse) // return a sparse matrix C // allocate the sparse matrix result C //-------------------------------------------------------------------------- + mode = RANGE (mode, 0, 1) ; int cnz = CHOLMOD(dense_nnz) (X, Common) ; - int cxtype = values ? X->xtype : CHOLMOD_PATTERN ; + int cxtype = (mode == 0) ? CHOLMOD_PATTERN : X->xtype ; cholmod_sparse *C = CHOLMOD(allocate_sparse) (X->nrow, X->ncol, cnz, /* C is sorted: */ TRUE, /* C is packed: */ TRUE, /* C->stype: */ 0, cxtype + X->dtype, Common) ; @@ -80,29 +83,28 @@ cholmod_sparse *CHOLMOD(dense_to_sparse) // return a sparse matrix C switch ((X->xtype + X->dtype) % 8) { - - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_dense_to_sparse_worker (C, X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_dense_to_sparse_worker (C, X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_dense_to_sparse_worker (C, X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_dense_to_sparse_worker (C, X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_dense_to_sparse_worker (C, X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_dense_to_sparse_worker (C, X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_dense_to_sparse_worker (C, X) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_ensure_dense.c b/CHOLMOD/Utility/t_cholmod_ensure_dense.c index e375e8f297..0b6cb6480e 100644 --- a/CHOLMOD/Utility/t_cholmod_ensure_dense.c +++ b/CHOLMOD/Utility/t_cholmod_ensure_dense.c @@ -22,7 +22,9 @@ cholmod_dense *CHOLMOD(ensure_dense) ( + // input/output: cholmod_dense **X, // matrix to resize as needed (*X may be NULL) + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t d, // leading dimension @@ -63,7 +65,7 @@ cholmod_dense *CHOLMOD(ensure_dense) size_t nzmax_required = CHOLMOD(mult_size_t) (d, ncol, &ok) ; if (!ok) { - ERROR (CHOLMOD_INVALID, "problem too large") ; + ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } @@ -89,6 +91,7 @@ cholmod_dense *CHOLMOD(ensure_dense) // free the matrix and reallocate it with the right properties CHOLMOD(free_dense) (X, Common) ; (*X) = CHOLMOD(allocate_dense) (nrow, ncol, d, xdtype, Common) ; + } //-------------------------------------------------------------------------- diff --git a/CHOLMOD/Utility/t_cholmod_error.c b/CHOLMOD/Utility/t_cholmod_error.c index 4d27b980cc..fc10ae1a3b 100644 --- a/CHOLMOD/Utility/t_cholmod_error.c +++ b/CHOLMOD/Utility/t_cholmod_error.c @@ -31,6 +31,7 @@ int CHOLMOD(error) ( + // input: int status, // Common->status const char *file, // source file where error occurred int line, // line number where error occurred @@ -70,12 +71,12 @@ int CHOLMOD(error) if (status > 0 && Common->print > 1) { // print a warning message - MESSAGE ("warning") ; + MESSAGE ("warning") ; } else if (Common->print > 0) { // print an error message - MESSAGE ("error") ; + MESSAGE ("error") ; } } #endif diff --git a/CHOLMOD/Utility/t_cholmod_eye.c b/CHOLMOD/Utility/t_cholmod_eye.c index 9886a4866f..cb522da912 100644 --- a/CHOLMOD/Utility/t_cholmod_eye.c +++ b/CHOLMOD/Utility/t_cholmod_eye.c @@ -47,6 +47,7 @@ cholmod_dense *CHOLMOD(eye) // return a dense identity matrix ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -76,28 +77,28 @@ cholmod_dense *CHOLMOD(eye) // return a dense identity matrix switch (xdtype % 8) { - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_eye_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_eye_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_eye_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_eye_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_eye_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_eye_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_eye_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_eye_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_eye_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_eye_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_eye_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_eye_worker (X) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_factor_to_sparse.c b/CHOLMOD/Utility/t_cholmod_factor_to_sparse.c index df786af4dc..9431eb69f2 100644 --- a/CHOLMOD/Utility/t_cholmod_factor_to_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_factor_to_sparse.c @@ -22,7 +22,8 @@ cholmod_sparse *CHOLMOD(factor_to_sparse) ( - cholmod_factor *L, // input: factor to convert; output: L is converted + // input/output: + cholmod_factor *L, // input: factor to convert; output: L is converted // to a simplicial symbolic factor cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_finish.c b/CHOLMOD/Utility/t_cholmod_finish.c index 596f566830..d38c23e734 100644 --- a/CHOLMOD/Utility/t_cholmod_finish.c +++ b/CHOLMOD/Utility/t_cholmod_finish.c @@ -17,6 +17,15 @@ int CHOLMOD(finish) (cholmod_common *Common) { + + #ifdef BLAS_DUMP + if (Common->blas_dump != NULL) + { + fclose (Common->blas_dump) ; + Common->blas_dump = NULL ; + } + #endif + return (CHOLMOD(free_work) (Common)) ; } diff --git a/CHOLMOD/Utility/t_cholmod_free.c b/CHOLMOD/Utility/t_cholmod_free.c index df473ee85b..7ea9627796 100644 --- a/CHOLMOD/Utility/t_cholmod_free.c +++ b/CHOLMOD/Utility/t_cholmod_free.c @@ -12,8 +12,10 @@ void *CHOLMOD(free) // returns NULL to simplify its usage ( + // input: size_t n, // number of items size_t size, // size of each item + // input/output: void *p, // memory to free cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_free_dense.c b/CHOLMOD/Utility/t_cholmod_free_dense.c index f682f47b49..ee31d44b37 100644 --- a/CHOLMOD/Utility/t_cholmod_free_dense.c +++ b/CHOLMOD/Utility/t_cholmod_free_dense.c @@ -12,6 +12,7 @@ int CHOLMOD(free_dense) ( + // input/output: cholmod_dense **X, // handle of dense matrix to free cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_free_factor.c b/CHOLMOD/Utility/t_cholmod_free_factor.c index f085b4d8b9..2c3a2cb7e5 100644 --- a/CHOLMOD/Utility/t_cholmod_free_factor.c +++ b/CHOLMOD/Utility/t_cholmod_free_factor.c @@ -21,7 +21,7 @@ void CHOLMOD(to_simplicial_sym) ( - cholmod_factor *L, // sparse factorization to modify + cholmod_factor *L, // sparse factorization to modify int to_ll, // change L to hold a LL' or LDL' factorization cholmod_common *Common ) @@ -96,6 +96,7 @@ void CHOLMOD(to_simplicial_sym) int CHOLMOD(free_factor) ( + // input/output: cholmod_factor **L, // handle of sparse factorization to free cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_free_sparse.c b/CHOLMOD/Utility/t_cholmod_free_sparse.c index 2fa15b6244..a51cb63e05 100644 --- a/CHOLMOD/Utility/t_cholmod_free_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_free_sparse.c @@ -12,6 +12,7 @@ int CHOLMOD(free_sparse) ( + // input/output: cholmod_sparse **A, // handle of sparse matrix to free cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_free_triplet.c b/CHOLMOD/Utility/t_cholmod_free_triplet.c index 3783bbd167..a30cf2f867 100644 --- a/CHOLMOD/Utility/t_cholmod_free_triplet.c +++ b/CHOLMOD/Utility/t_cholmod_free_triplet.c @@ -12,6 +12,7 @@ int CHOLMOD(free_triplet) ( + // input/output: cholmod_triplet **T, // handle of triplet matrix to free cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_free_work.c b/CHOLMOD/Utility/t_cholmod_free_work.c index cda854bc29..f3c13e9fda 100644 --- a/CHOLMOD/Utility/t_cholmod_free_work.c +++ b/CHOLMOD/Utility/t_cholmod_free_work.c @@ -37,7 +37,7 @@ int CHOLMOD(free_work) (cholmod_common *Common) Common->iworksize = 0 ; //-------------------------------------------------------------------------- - // free Xwork, of size xworksize bytes + // free Xwork, of size xworkbytes //-------------------------------------------------------------------------- Common->Xwork = CHOLMOD(free) (Common->xworkbytes, sizeof (uint8_t), diff --git a/CHOLMOD/Utility/t_cholmod_malloc.c b/CHOLMOD/Utility/t_cholmod_malloc.c index 8c1b7b33f0..465206d487 100644 --- a/CHOLMOD/Utility/t_cholmod_malloc.c +++ b/CHOLMOD/Utility/t_cholmod_malloc.c @@ -18,6 +18,7 @@ void *CHOLMOD_ALLOC_FUNCTION // return pointer to newly allocated memory ( + // input: size_t n, // number of items size_t size, // size of each item cholmod_common *Common diff --git a/CHOLMOD/Utility/t_cholmod_maxrank.c b/CHOLMOD/Utility/t_cholmod_maxrank.c index 508232ffe6..2a97397ee4 100644 --- a/CHOLMOD/Utility/t_cholmod_maxrank.c +++ b/CHOLMOD/Utility/t_cholmod_maxrank.c @@ -14,6 +14,7 @@ size_t CHOLMOD(maxrank) // return validated Common->maxrank ( + // input: size_t n, // # of rows of L and A cholmod_common *Common ) @@ -26,15 +27,17 @@ size_t CHOLMOD(maxrank) // return validated Common->maxrank RETURN_IF_NULL_COMMON (0) ; //-------------------------------------------------------------------------- - // determine a valid value of maxrank + // determine a valid value of maxrank //-------------------------------------------------------------------------- size_t maxrank = Common->maxrank ; - if (n == 0) return (2) ; - // guard against size_t overflow (very unlikely) - size_t max_maxrank = SIZE_MAX / (n * sizeof (float)) ; - maxrank = MIN (maxrank, max_maxrank) ; + if (n > 0) + { + // guard against size_t overflow (very unlikely) + size_t max_maxrank = SIZE_MAX / (n * sizeof (float)) ; + maxrank = MIN (maxrank, max_maxrank) ; + } // maxrank of 2 or less: use 2 // maxrank of 3 or 4: use 4 diff --git a/CHOLMOD/Utility/t_cholmod_mult_size_t.c b/CHOLMOD/Utility/t_cholmod_mult_size_t.c index 7bf6c70fda..35599c0004 100644 --- a/CHOLMOD/Utility/t_cholmod_mult_size_t.c +++ b/CHOLMOD/Utility/t_cholmod_mult_size_t.c @@ -15,7 +15,7 @@ size_t CHOLMOD(mult_size_t) (size_t a, size_t b, int *ok) { uint64_t x ; - (*ok) = cholmod_mult_uint64_t (&x, (uint64_t) a, (uint64_t) b) ; + (*ok) = (*ok) && cholmod_mult_uint64_t (&x, (uint64_t) a, (uint64_t) b) ; return (((*ok) && x <= SIZE_MAX) ? ((size_t) x) : 0) ; } diff --git a/CHOLMOD/Utility/t_cholmod_nnz.c b/CHOLMOD/Utility/t_cholmod_nnz.c index d24931dca7..9ac1ad9940 100644 --- a/CHOLMOD/Utility/t_cholmod_nnz.c +++ b/CHOLMOD/Utility/t_cholmod_nnz.c @@ -16,6 +16,7 @@ int64_t CHOLMOD(nnz) // return # of entries in the sparse matrix ( + // input: cholmod_sparse *A, // sparse matrix to query cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_ones.c b/CHOLMOD/Utility/t_cholmod_ones.c index d81f4b12b0..3aef95abae 100644 --- a/CHOLMOD/Utility/t_cholmod_ones.c +++ b/CHOLMOD/Utility/t_cholmod_ones.c @@ -46,6 +46,7 @@ cholmod_dense *CHOLMOD(ones) ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -76,28 +77,28 @@ cholmod_dense *CHOLMOD(ones) switch (xdtype % 8) { - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_ones_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_ones_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_ones_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_ones_worker (X) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_ones_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_ones_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_ones_worker (X) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_ones_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_ones_worker (X) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_ones_worker (X) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_ones_worker (X) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_ones_worker (X) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_pack_factor.c b/CHOLMOD/Utility/t_cholmod_pack_factor.c index 244d57c119..a19d71302a 100644 --- a/CHOLMOD/Utility/t_cholmod_pack_factor.c +++ b/CHOLMOD/Utility/t_cholmod_pack_factor.c @@ -53,6 +53,7 @@ int CHOLMOD(pack_factor) ( + // input/output: cholmod_factor *L, // factor to pack cholmod_common *Common ) @@ -70,8 +71,8 @@ int CHOLMOD(pack_factor) if (L->xtype == CHOLMOD_PATTERN || L->is_super) { - // nothing to do - return (TRUE) ; + // nothing to do + return (TRUE) ; } //-------------------------------------------------------------------------- @@ -80,31 +81,28 @@ int CHOLMOD(pack_factor) switch ((L->xtype + L->dtype) % 8) { - default: + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_pack_factor_worker (L, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_pack_factor_worker (L, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_pack_factor_worker (L, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_pack_factor_worker (L, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_pack_factor_worker (L, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_pack_factor_worker (L, Common) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_pack_factor_worker (L, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_pack_factor_worker (L, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_pack_factor_worker (L, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_pack_factor_worker (L, Common) ; - break ; - - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_pack_factor_worker (L, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_pack_factor_worker (L, Common) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_pack_factor_worker.c b/CHOLMOD/Utility/t_cholmod_pack_factor_worker.c index f4d5420bcb..b4a25a03da 100644 --- a/CHOLMOD/Utility/t_cholmod_pack_factor_worker.c +++ b/CHOLMOD/Utility/t_cholmod_pack_factor_worker.c @@ -40,30 +40,30 @@ static void TEMPLATE (cholmod_pack_factor_worker) //-------------------------------------------------------------------------- Int j = Lnext [n+1] ; // first column in the list is Lnext [n+1] - Int pnew = 0 ; // next column can move to pnew + Int pnew = 0 ; // next column can move to pnew while (j != n) // j=n is the fictious placeholder at end of list { //---------------------------------------------------------------------- - // get column j, entries currently in Li and Lx [pold...pold+lnzj-1] + // get column j, entries currently in Li and Lx [pold...pold+lnzj-1] //---------------------------------------------------------------------- - Int pold = Lp [j] ; // start of column j in L->i and L->j - Int lnzj = Lnz [j] ; // # of entries in column j - ASSERT (lnzj > 0) ; + Int pold = Lp [j] ; // start of column j in L->i and L->j + Int lnzj = Lnz [j] ; // # of entries in column j + ASSERT (lnzj > 0) ; //---------------------------------------------------------------------- // pack column j, if possible //---------------------------------------------------------------------- - if (pnew < pold) - { + if (pnew < pold) + { // Li,Lx [pnew...pnew+lnz-1] = Li,Lx [pold...pold+lnz-1] - for (Int k = 0 ; k < lnzj ; k++) - { + for (Int k = 0 ; k < lnzj ; k++) + { // move L(i,j) from position pold+k to position pnew+k - Li [pnew + k] = Li [pold + k] ; + Li [pnew + k] = Li [pold + k] ; ASSIGN (Lx, Lz, pnew + k, Lx, Lz, pold + k) ; } // log the new position of the first entry of L(:,j) @@ -71,7 +71,7 @@ static void TEMPLATE (cholmod_pack_factor_worker) } //---------------------------------------------------------------------- - // add some empty space at the end of column j + // add some empty space at the end of column j //---------------------------------------------------------------------- Int desired_space = lnzj + slack ; // add slack space to column j @@ -85,7 +85,7 @@ static void TEMPLATE (cholmod_pack_factor_worker) Int jnext = Lnext [j] ; // jnext = next column in the list Int pnext = Lp [jnext] ; // next column jnext starts here Int pthis = Lp [j] + total_space ; // one past the end of column j - pnew = MIN (pthis, pnext) ; // next column can move to pnew + pnew = MIN (pthis, pnext) ; // next column can move to pnew j = jnext ; // move to the next column } } diff --git a/CHOLMOD/Utility/t_cholmod_ptranspose.c b/CHOLMOD/Utility/t_cholmod_ptranspose.c index d81663cc0c..9291d41482 100644 --- a/CHOLMOD/Utility/t_cholmod_ptranspose.c +++ b/CHOLMOD/Utility/t_cholmod_ptranspose.c @@ -24,8 +24,10 @@ cholmod_sparse *CHOLMOD(ptranspose) ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) // <= 0: pattern (with diag) Int *Perm, // permutation for C=A(p,f)' or C=A(p,p)', or NULL Int *fset, // a list of column indices in range 0:A->ncol-1 @@ -41,6 +43,7 @@ cholmod_sparse *CHOLMOD(ptranspose) RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_SPARSE_MATRIX_INVALID (A, NULL) ; Common->status = CHOLMOD_OK ; + mode = RANGE (mode, -1, 2) ; //-------------------------------------------------------------------------- // count # of entries in C diff --git a/CHOLMOD/Utility/t_cholmod_realloc.c b/CHOLMOD/Utility/t_cholmod_realloc.c index e2cbe55920..9c9417c8fc 100644 --- a/CHOLMOD/Utility/t_cholmod_realloc.c +++ b/CHOLMOD/Utility/t_cholmod_realloc.c @@ -12,8 +12,10 @@ void *CHOLMOD(realloc) // return newly reallocated block of memory ( + // input: size_t nnew, // # of items in newly reallocate memory size_t size, // size of each item + // input/output: void *p, // pointer to memory to reallocate (may be NULL) size_t *n, // # of items in p on input; nnew on output if success cholmod_common *Common @@ -47,8 +49,8 @@ void *CHOLMOD(realloc) // return newly reallocated block of memory if (!newly_allocated) { - PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n", - pold, (double) nold*size, (double) Common->malloc_count-1, + PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n", + pold, (double) nold*size, (double) Common->malloc_count-1, (double) (Common->memory_inuse - nold*size))) ; #ifndef NDEBUG size_t size2 = CM_memtable_size (pold) ; diff --git a/CHOLMOD/Utility/t_cholmod_realloc_multiple.c b/CHOLMOD/Utility/t_cholmod_realloc_multiple.c index 49f84710d4..f6ea3afc27 100644 --- a/CHOLMOD/Utility/t_cholmod_realloc_multiple.c +++ b/CHOLMOD/Utility/t_cholmod_realloc_multiple.c @@ -12,6 +12,7 @@ int CHOLMOD(realloc_multiple) // returns true if successful, false otherwise ( + // input: size_t nnew, // # of items in newly reallocate memory int nint, // 0: do not allocate I or J, 1: just I, 2: both I and J int xdtype, // xtype + dtype of the matrix: @@ -66,6 +67,7 @@ int CHOLMOD(realloc_multiple) // returns true if successful, false otherwise (ex > 0 && X == NULL) || (ez > 0 && Z == NULL)) { + // input argument missing if (Common->status != CHOLMOD_OUT_OF_MEMORY) { ERROR (CHOLMOD_INVALID, "argument missing") ; diff --git a/CHOLMOD/Utility/t_cholmod_reallocate_column.c b/CHOLMOD/Utility/t_cholmod_reallocate_column.c index fcbba8cee3..0970ba7986 100644 --- a/CHOLMOD/Utility/t_cholmod_reallocate_column.c +++ b/CHOLMOD/Utility/t_cholmod_reallocate_column.c @@ -51,8 +51,10 @@ int CHOLMOD(reallocate_column) ( + // input: size_t j, // reallocate L(:,j) size_t need, // space in L(:,j) for this # of entries + // input/output: cholmod_factor *L, // L factor modified, L(:,j) resized cholmod_common *Common ) @@ -163,31 +165,28 @@ int CHOLMOD(reallocate_column) switch ((L->xtype + L->dtype) % 8) { - default: + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; - break ; - - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_reallocate_column_worker (L, j, pdest, psrc) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_reallocate_factor.c b/CHOLMOD/Utility/t_cholmod_reallocate_factor.c index aa1ffd4583..e8a921e295 100644 --- a/CHOLMOD/Utility/t_cholmod_reallocate_factor.c +++ b/CHOLMOD/Utility/t_cholmod_reallocate_factor.c @@ -15,7 +15,9 @@ int CHOLMOD(reallocate_factor) ( + // input: size_t nznew, // new max # of nonzeros the factor matrix can hold + // input/output: cholmod_factor *L, // factor to reallocate cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_reallocate_sparse.c b/CHOLMOD/Utility/t_cholmod_reallocate_sparse.c index df74814515..cabc1d9ca2 100644 --- a/CHOLMOD/Utility/t_cholmod_reallocate_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_reallocate_sparse.c @@ -14,7 +14,9 @@ int CHOLMOD(reallocate_sparse) ( + // input: size_t nznew, // new max # of nonzeros the sparse matrix can hold + // input/output: cholmod_sparse *A, // sparse matrix to reallocate cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_reallocate_triplet.c b/CHOLMOD/Utility/t_cholmod_reallocate_triplet.c index 5ffff9edf5..224030a169 100644 --- a/CHOLMOD/Utility/t_cholmod_reallocate_triplet.c +++ b/CHOLMOD/Utility/t_cholmod_reallocate_triplet.c @@ -14,7 +14,9 @@ int CHOLMOD(reallocate_triplet) ( + // input: size_t nznew, // new max # of nonzeros the triplet matrix can hold + // input/output: cholmod_triplet *T, // triplet matrix to reallocate cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_score_comp.c b/CHOLMOD/Utility/t_cholmod_score_comp.c index 8f2aaa8758..5a8b270fc6 100644 --- a/CHOLMOD/Utility/t_cholmod_score_comp.c +++ b/CHOLMOD/Utility/t_cholmod_score_comp.c @@ -11,8 +11,8 @@ #include "cholmod_internal.h" int CHOLMOD(score_comp) -( - struct cholmod_descendant_score_t *i, +( + struct cholmod_descendant_score_t *i, struct cholmod_descendant_score_t *j ) { diff --git a/CHOLMOD/Utility/t_cholmod_sort.c b/CHOLMOD/Utility/t_cholmod_sort.c index 9fe34a914d..083e522334 100644 --- a/CHOLMOD/Utility/t_cholmod_sort.c +++ b/CHOLMOD/Utility/t_cholmod_sort.c @@ -74,6 +74,7 @@ static inline uint64_t cm_rand (uint64_t *seed) int CHOLMOD(sort) ( + // input/output: cholmod_sparse *A, // input/output matrix to sort cholmod_common *Common ) @@ -97,28 +98,28 @@ int CHOLMOD(sort) p_cholmod_sort_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_sort_worker (A) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_sort_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_sort_worker (A) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_sort_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_sort_worker (A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_sort_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_sort_worker (A) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_sort_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_sort_worker (A) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_sort_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_sort_worker (A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_sort_worker (A) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_sort_worker.c b/CHOLMOD/Utility/t_cholmod_sort_worker.c index add2200a7b..fb685d52b7 100644 --- a/CHOLMOD/Utility/t_cholmod_sort_worker.c +++ b/CHOLMOD/Utility/t_cholmod_sort_worker.c @@ -163,7 +163,7 @@ static void TEMPLATE (cm_qsrt) // sort A [0:n-1] Int k = CM_PART (Ai, Ax, Az, n, seed) ; // sort each partition - CM_QSRT (Ai, Ax, Ax, 0, k, seed) ; // sort A [0:k-1] + CM_QSRT (Ai, Ax, Az, 0, k, seed) ; // sort A [0:k-1] CM_QSRT (Ai, Ax, Az, k, n-k, seed) ; // sort A [k+1:n-1] } } diff --git a/CHOLMOD/Utility/t_cholmod_sparse_to_dense.c b/CHOLMOD/Utility/t_cholmod_sparse_to_dense.c index 5f05bc88b5..9fc64b127a 100644 --- a/CHOLMOD/Utility/t_cholmod_sparse_to_dense.c +++ b/CHOLMOD/Utility/t_cholmod_sparse_to_dense.c @@ -52,6 +52,7 @@ cholmod_dense *CHOLMOD(sparse_to_dense) // return a dense matrix ( + // input: cholmod_sparse *A, // input matrix cholmod_common *Common ) @@ -81,37 +82,38 @@ cholmod_dense *CHOLMOD(sparse_to_dense) // return a dense matrix switch ((A->xtype + A->dtype) % 8) { - - case CHOLMOD_SINGLE + CHOLMOD_PATTERN: - p_s_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_PATTERN + CHOLMOD_SINGLE: + // input A is pattern but output X is single + ps_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_PATTERN: + case CHOLMOD_PATTERN + CHOLMOD_DOUBLE: + // input A is pattern but output X is double p_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_sparse_to_dense_worker (X, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_sparse_to_dense_worker (X, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_sparse_to_dense_worker (X, A) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_sparse_to_triplet.c b/CHOLMOD/Utility/t_cholmod_sparse_to_triplet.c index 1ce6dc7d23..733385a041 100644 --- a/CHOLMOD/Utility/t_cholmod_sparse_to_triplet.c +++ b/CHOLMOD/Utility/t_cholmod_sparse_to_triplet.c @@ -40,6 +40,7 @@ cholmod_triplet *CHOLMOD(sparse_to_triplet) ( + // input: cholmod_sparse *A, // matrix to copy into triplet form T cholmod_common *Common ) @@ -76,28 +77,28 @@ cholmod_triplet *CHOLMOD(sparse_to_triplet) p_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_sparse_to_triplet_worker (T, A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_sparse_to_triplet_worker (T, A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_sparse_to_triplet_worker (T, A) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_speye.c b/CHOLMOD/Utility/t_cholmod_speye.c index 0c08e9a23d..1591186344 100644 --- a/CHOLMOD/Utility/t_cholmod_speye.c +++ b/CHOLMOD/Utility/t_cholmod_speye.c @@ -51,6 +51,7 @@ cholmod_sparse *CHOLMOD(speye) ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: @@ -86,28 +87,28 @@ cholmod_sparse *CHOLMOD(speye) p_cholmod_speye_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_speye_worker (A) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_speye_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - c_s_cholmod_speye_worker (A) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + cs_cholmod_speye_worker (A) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - z_s_cholmod_speye_worker (A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + zs_cholmod_speye_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_speye_worker (A) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_speye_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - c_cholmod_speye_worker (A) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + cd_cholmod_speye_worker (A) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - z_cholmod_speye_worker (A) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + zd_cholmod_speye_worker (A) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_speye_worker.c b/CHOLMOD/Utility/t_cholmod_speye_worker.c index 06a86ac77c..7bb4f0683d 100644 --- a/CHOLMOD/Utility/t_cholmod_speye_worker.c +++ b/CHOLMOD/Utility/t_cholmod_speye_worker.c @@ -46,7 +46,7 @@ static void TEMPLATE (cholmod_speye_worker) for (Int k = n ; k <= ncol ; k++) { - Ap [k] = n ; + Ap [k] = n ; } } diff --git a/CHOLMOD/Utility/t_cholmod_spzeros.c b/CHOLMOD/Utility/t_cholmod_spzeros.c index 44353cb17d..07fdaf8d07 100644 --- a/CHOLMOD/Utility/t_cholmod_spzeros.c +++ b/CHOLMOD/Utility/t_cholmod_spzeros.c @@ -16,6 +16,7 @@ cholmod_sparse *CHOLMOD(spzeros) // return a sparse matrix with no entries ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns size_t nzmax, // max # of entries the matrix can hold @@ -27,7 +28,7 @@ cholmod_sparse *CHOLMOD(spzeros) // return a sparse matrix with no entries { return (CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, /* A is sorted: */ TRUE, - /* A is packed: */ TRUE, + /* A is packed: */ TRUE, /* A is unsymmetric: */ 0, xdtype, Common)) ; } diff --git a/CHOLMOD/Utility/t_cholmod_start.c b/CHOLMOD/Utility/t_cholmod_start.c index 02478cc0b9..e11e34d257 100644 --- a/CHOLMOD/Utility/t_cholmod_start.c +++ b/CHOLMOD/Utility/t_cholmod_start.c @@ -56,6 +56,10 @@ int CHOLMOD(start) (cholmod_common *Common) Common->fl = EMPTY ; Common->lnz = EMPTY ; + #ifdef BLAS_DUMP + Common->blas_dump = fopen ("blas_dump.txt", "a") ; + #endif + return (TRUE) ; } diff --git a/CHOLMOD/Utility/t_cholmod_transpose.c b/CHOLMOD/Utility/t_cholmod_transpose.c index 3579c67dc5..a8053209e8 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose.c +++ b/CHOLMOD/Utility/t_cholmod_transpose.c @@ -12,8 +12,10 @@ cholmod_sparse *CHOLMOD(transpose) ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) // <= 0: pattern (with diag) cholmod_common *Common ) diff --git a/CHOLMOD/Utility/t_cholmod_transpose_sym.c b/CHOLMOD/Utility/t_cholmod_transpose_sym.c index 789963897c..2985bcd2c4 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_sym.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_sym.c @@ -70,10 +70,13 @@ int CHOLMOD(transpose_sym) ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) // <= 0: pattern (with diag) Int *Perm, // permutation for C=A(p,p)', or NULL + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) @@ -88,6 +91,8 @@ int CHOLMOD(transpose_sym) RETURN_IF_NULL (C, FALSE) ; Common->status = CHOLMOD_OK ; + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN || C->xtype == CHOLMOD_PATTERN) { // A or C is pattern: C must be pattern, so mode can only be zero @@ -167,64 +172,63 @@ int CHOLMOD(transpose_sym) // compute the pattern and values of C //-------------------------------------------------------------------------- - bool conj = (mode >= 2) ; + bool conj = (mode == 2) ; switch ((C->xtype + C->dtype) % 8) { - default: p_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: if (conj) { - c_s_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + cs_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } else { - ct_s_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + cs_t_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: if (conj) { - z_s_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + zs_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } else { - zt_s_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + zs_t_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: if (conj) { - c_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + cd_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } else { - ct_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + cd_t_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: if (conj) { - z_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + zd_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } else { - zt_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; + zd_t_cholmod_transpose_sym_worker (C, A, Pinv, Wi) ; } break ; } diff --git a/CHOLMOD/Utility/t_cholmod_transpose_sym_permuted.c b/CHOLMOD/Utility/t_cholmod_transpose_sym_permuted.c index 26299b10c8..1959c1c1a6 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_sym_permuted.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_sym_permuted.c @@ -13,7 +13,7 @@ // The including file must define or undef PACKED, NUMERIC, and LO. // define PACKED: if A->packed is true, undefine if A->packed is false // define LO: if A is symmetric lower, undefine it if A is upper -// define NUMERIC: if computing values and pattern of C, undefine it if +// define NUMERIC: if computing values and pattern of C, undefine it if // computing just the column counts of C. //------------------------------------------------------------------------------ @@ -46,7 +46,7 @@ // C(jnew,inew) = conj (A(iold,jold)) Int pc = Wi [inew]++ ; #ifdef NUMERIC - ASSIGN_CONJ_OR_NCONJ (Cx, Cz, pc, Ax, Az, pa) ; + ASSIGN_CONJ_OR_NCONJ (Cx, Cz, pc, Ax, Az, pa) ; Ci [pc] = jnew ; #endif } @@ -55,7 +55,7 @@ // C(inew,jnew) = A(iold,jold) Int pc = Wi [jnew]++ ; #ifdef NUMERIC - ASSIGN (Cx, Cz, pc, Ax, Az, pa) ; + ASSIGN (Cx, Cz, pc, Ax, Az, pa) ; Ci [pc] = inew ; #endif } diff --git a/CHOLMOD/Utility/t_cholmod_transpose_sym_template.c b/CHOLMOD/Utility/t_cholmod_transpose_sym_template.c index 82f5cafa0d..482c75145e 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_sym_template.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_sym_template.c @@ -11,7 +11,7 @@ //------------------------------------------------------------------------------ // The including file must define or undef NUMERIC. -// define NUMERIC: if computing values and pattern of C, undefine it if +// define NUMERIC: if computing values and pattern of C, undefine it if // computing just the column counts of C. //------------------------------------------------------------------------------ diff --git a/CHOLMOD/Utility/t_cholmod_transpose_sym_unpermuted.c b/CHOLMOD/Utility/t_cholmod_transpose_sym_unpermuted.c index 17811443e8..a0d7b49198 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_sym_unpermuted.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_sym_unpermuted.c @@ -13,7 +13,7 @@ // The including file must define or undef PACKED, NUMERIC, and LO. // define PACKED: if A->packed is true, undefine if A->packed is false // define LO: if A is symmetric lower, undefine it if A is upper -// define NUMERIC: if computing values and pattern of C, undefine it if +// define NUMERIC: if computing values and pattern of C, undefine it if // computing just the column counts of C. //------------------------------------------------------------------------------ diff --git a/CHOLMOD/Utility/t_cholmod_transpose_unsym.c b/CHOLMOD/Utility/t_cholmod_transpose_unsym.c index 8bc9967ef1..a3def81706 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_unsym.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_unsym.c @@ -93,16 +93,20 @@ static void cm_copy_Cnz (Int *Cnz, Int *Wi, Int *Perm, Int nrow) } //------------------------------------------------------------------------------ +// cholmod_transpose_unsym //------------------------------------------------------------------------------ int CHOLMOD(transpose_unsym) ( + // input: cholmod_sparse *A, // input matrix - int mode, // 2: numerical (conj), 1: numerical (non-conj.), - // <= 0: pattern (with diag) + int mode, // 2: numerical (conj) + // 1: numerical (non-conj.) + // 0: pattern (with diag) Int *Perm, // permutation for C=A(p,f)', or NULL Int *fset, // a list of column indices in range 0:A->ncol-1 size_t fsize, // # of entries in fset + // input/output: cholmod_sparse *C, // output matrix, must be allocated on input cholmod_common *Common ) @@ -117,6 +121,8 @@ int CHOLMOD(transpose_unsym) RETURN_IF_NULL (C, FALSE) ; Common->status = CHOLMOD_OK ; + mode = RANGE (mode, 0, 2) ; + if (A->xtype == CHOLMOD_PATTERN || C->xtype == CHOLMOD_PATTERN) { // A or C is pattern: C must be pattern, so mode can only be zero @@ -132,7 +138,7 @@ int CHOLMOD(transpose_unsym) return (FALSE) ; } - if ((C->xtype != ((mode <= 0) ? CHOLMOD_PATTERN : A->xtype)) || + if ((C->xtype != ((mode == 0) ? CHOLMOD_PATTERN : A->xtype)) || (C->dtype != A->dtype) || (nrow != C->ncol) || (ncol != C->nrow) || (C->stype != 0)) { @@ -169,16 +175,16 @@ int CHOLMOD(transpose_unsym) if (Perm != NULL) { memset (Wi, 0, nrow * sizeof (Int)) ; - for (Int k = 0 ; k < nrow ; k++) - { - Int i = Perm [k] ; - if (i < 0 || i > nrow || Wi [i] == 1) - { - ERROR (CHOLMOD_INVALID, "invalid permutation") ; - return (FALSE) ; - } - Wi [i] = 1 ; - } + for (Int k = 0 ; k < nrow ; k++) + { + Int i = Perm [k] ; + if (i < 0 || i > nrow || Wi [i] == 1) + { + ERROR (CHOLMOD_INVALID, "invalid permutation") ; + return (FALSE) ; + } + Wi [i] = 1 ; + } } ASSERT (CHOLMOD(dump_perm) (Perm, nrow, nrow, "Perm", Common)) ; @@ -193,17 +199,17 @@ int CHOLMOD(transpose_unsym) { Int jlast = EMPTY ; memset (Wi, 0, ncol * sizeof (Int)) ; - for (Int k = 0 ; k < nf ; k++) + for (Int k = 0 ; k < nf ; k++) { - Int j = fset [k] ; - if (j < 0 || j > ncol || Wi [j] == 1) - { - ERROR (CHOLMOD_INVALID, "invalid fset") ; - return (FALSE) ; - } - Wi [j] = 1 ; + Int j = fset [k] ; + if (j < 0 || j > ncol || Wi [j] == 1) + { + ERROR (CHOLMOD_INVALID, "invalid fset") ; + return (FALSE) ; + } + Wi [j] = 1 ; fsorted = fsorted && (j > jlast) ; - jlast = j ; + jlast = j ; } } @@ -238,8 +244,8 @@ int CHOLMOD(transpose_unsym) // save the nz counts if C is unpacked, and recount all of A //---------------------------------------------------------------------- - if (!(C->packed)) - { + if (!(C->packed)) + { cm_copy_Cnz (Cnz, Wi, Perm, nrow) ; @@ -257,7 +263,7 @@ int CHOLMOD(transpose_unsym) { #include "t_cholmod_transpose_unsym_template.c" } - } + } } else @@ -281,10 +287,10 @@ int CHOLMOD(transpose_unsym) // save the nz counts if C is unpacked, and recount all of A //---------------------------------------------------------------------- - if (!(C->packed)) - { + if (!(C->packed)) + { cm_copy_Cnz (Cnz, Wi, Perm, nrow) ; - } + } } //-------------------------------------------------------------------------- @@ -302,87 +308,86 @@ int CHOLMOD(transpose_unsym) else { // Cp = cumsum (Wi [Perm]) - for (Int i = 0 ; i < nrow ; i++) - { - Cp [i] = p ; - p += Wi [Perm [i]] ; - } + for (Int i = 0 ; i < nrow ; i++) + { + Cp [i] = p ; + p += Wi [Perm [i]] ; + } Cp [nrow] = p ; // Wi [Perm [0..nrow-1]] = Cp [0..nrow-1] - for (Int i = 0 ; i < nrow ; i++) - { - Wi [Perm [i]] = Cp [i] ; - } + for (Int i = 0 ; i < nrow ; i++) + { + Wi [Perm [i]] = Cp [i] ; + } } if (p > (Int) C->nzmax) { - ERROR (CHOLMOD_INVALID, "C is too small") ; - return (FALSE) ; + ERROR (CHOLMOD_INVALID, "C is too small") ; + return (FALSE) ; } //-------------------------------------------------------------------------- // compute the pattern and values of C //-------------------------------------------------------------------------- - bool conj = (mode >= 2) ; + bool conj = (mode == 2) ; switch ((C->xtype + C->dtype) % 8) { - default: p_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - r_s_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + rs_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: if (conj) { - c_s_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + cs_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } else { - ct_s_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + cs_t_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: if (conj) { - z_s_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + zs_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } else { - zt_s_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + zs_t_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - r_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + rd_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: if (conj) { - c_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + cd_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } else { - ct_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + cd_t_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: if (conj) { - z_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + zd_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } else { - zt_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; + zd_t_cholmod_transpose_unsym_worker (A, fset, nf, C, Wi) ; } break ; } diff --git a/CHOLMOD/Utility/t_cholmod_transpose_unsym_template.c b/CHOLMOD/Utility/t_cholmod_transpose_unsym_template.c index 3a78d0fd2c..5460a8a688 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_unsym_template.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_unsym_template.c @@ -14,7 +14,7 @@ // define PACKED: if A->packed is true, undefine if A->packed is false -// define NUMERIC: if computing values and pattern of C, undefine it if +// define NUMERIC: if computing values and pattern of C, undefine it if // computing just the column counts of C. //------------------------------------------------------------------------------ @@ -36,7 +36,7 @@ //---------------------------------------------------------------------- #ifdef FSET - Int j = fset [k] ; + Int j = fset [k] ; #else Int j = k ; #endif @@ -45,27 +45,27 @@ // get A(:,k) //---------------------------------------------------------------------- - Int p = Ap [j] ; + Int p = Ap [j] ; #ifdef PACKED - Int pend = Ap [j+1] ; + Int pend = Ap [j+1] ; #else - Int pend = p + Anz [j] ; + Int pend = p + Anz [j] ; #endif //---------------------------------------------------------------------- // scan entries in A(:,k) //---------------------------------------------------------------------- - for ( ; p < pend ; p++) - { + for ( ; p < pend ; p++) + { // get A(i,j) and count it or get its place in C - Int pc = Wi [Ai [p]]++ ; + Int pc = Wi [Ai [p]]++ ; #ifdef NUMERIC // C(j,i) = conj (A(i,j)) - ASSIGN_CONJ_OR_NCONJ (Cx, Cz, pc, Ax, Az, p) ; - Ci [pc] = j ; + ASSIGN_CONJ_OR_NCONJ (Cx, Cz, pc, Ax, Az, p) ; + Ci [pc] = j ; #endif - } + } } } diff --git a/CHOLMOD/Utility/t_cholmod_transpose_unsym_worker.c b/CHOLMOD/Utility/t_cholmod_transpose_unsym_worker.c index f87b9a94b4..e717813abe 100644 --- a/CHOLMOD/Utility/t_cholmod_transpose_unsym_worker.c +++ b/CHOLMOD/Utility/t_cholmod_transpose_unsym_worker.c @@ -48,12 +48,14 @@ static void TEMPLATE (cholmod_transpose_unsym_worker) #define PACKED #define FSET #include "t_cholmod_transpose_unsym_template.c" + return ; } else { // C = A (p,f)' or A(:,f)' where A is unpacked #define FSET #include "t_cholmod_transpose_unsym_template.c" + return ; } } else @@ -63,11 +65,13 @@ static void TEMPLATE (cholmod_transpose_unsym_worker) // C = A (p,:)' or A' where A is packed #define PACKED #include "t_cholmod_transpose_unsym_template.c" + return ; } else { // C = A (p,:)' or A' where A is unpacked #include "t_cholmod_transpose_unsym_template.c" + return ; } } } diff --git a/CHOLMOD/Utility/t_cholmod_triplet_to_sparse.c b/CHOLMOD/Utility/t_cholmod_triplet_to_sparse.c index 4b777a244c..eb763debc9 100644 --- a/CHOLMOD/Utility/t_cholmod_triplet_to_sparse.c +++ b/CHOLMOD/Utility/t_cholmod_triplet_to_sparse.c @@ -55,6 +55,7 @@ cholmod_sparse *CHOLMOD(triplet_to_sparse) // return sparse matrix A ( + // input: cholmod_triplet *T, // input triplet matrix size_t nzmax, // allocate space for max(nzmax,nnz(A)) entries cholmod_common *Common @@ -160,28 +161,28 @@ cholmod_sparse *CHOLMOD(triplet_to_sparse) // return sparse matrix A anz = p_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_REAL: - anz = r_s_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_REAL + CHOLMOD_SINGLE: + anz = rs_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_COMPLEX: - anz = c_s_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: + anz = cs_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_SINGLE + CHOLMOD_ZOMPLEX: - anz = z_s_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: + anz = zs_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_REAL: - anz = r_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_REAL + CHOLMOD_DOUBLE: + anz = rd_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_COMPLEX: - anz = c_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: + anz = cd_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; - case CHOLMOD_DOUBLE + CHOLMOD_ZOMPLEX: - anz = z_cholmod_triplet_to_sparse_worker (T, R, Common) ; + case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: + anz = zd_cholmod_triplet_to_sparse_worker (T, R, Common) ; break ; } diff --git a/CHOLMOD/Utility/t_cholmod_zeros.c b/CHOLMOD/Utility/t_cholmod_zeros.c index eff8dad7b8..f5dbea93ab 100644 --- a/CHOLMOD/Utility/t_cholmod_zeros.c +++ b/CHOLMOD/Utility/t_cholmod_zeros.c @@ -21,6 +21,7 @@ cholmod_dense *CHOLMOD(zeros) ( + // input: size_t nrow, // # of rows size_t ncol, // # of columns int xdtype, // xtype + dtype of the matrix: diff --git a/SuiteSparse_config/Config/SuiteSparse_config.h.in b/SuiteSparse_config/Config/SuiteSparse_config.h.in index 09d05c9222..3af054cef6 100644 --- a/SuiteSparse_config/Config/SuiteSparse_config.h.in +++ b/SuiteSparse_config/Config/SuiteSparse_config.h.in @@ -469,7 +469,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #elif defined ( BLAS_UNDERSCORE ) - // append an undescore, use lower case + // append an underscore, use lower case #define SUITESPARSE_FORTRAN(name,NAME) name ## _ #define SUITESPARSE__FORTRAN(name,NAME) name ## _ @@ -572,6 +572,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // C names of Fortan BLAS and LAPACK functions used by SuiteSparse //------------------------------------------------------------------------------ +// double #define SUITESPARSE_BLAS_DTRSV SUITESPARSE_BLAS ( dtrsv , DTRSV ) #define SUITESPARSE_BLAS_DGEMV SUITESPARSE_BLAS ( dgemv , DGEMV ) #define SUITESPARSE_BLAS_DTRSM SUITESPARSE_BLAS ( dtrsm , DTRSM ) @@ -579,8 +580,15 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_DSYRK SUITESPARSE_BLAS ( dsyrk , DSYRK ) #define SUITESPARSE_BLAS_DGER SUITESPARSE_BLAS ( dger , DGER ) #define SUITESPARSE_BLAS_DSCAL SUITESPARSE_BLAS ( dscal , DSCAL ) +#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) + #define SUITESPARSE_LAPACK_DPOTRF SUITESPARSE_BLAS ( dpotrf , DPOTRF ) +#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) +#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) +#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) +#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) +// double complex #define SUITESPARSE_BLAS_ZTRSV SUITESPARSE_BLAS ( ztrsv , ZTRSV ) #define SUITESPARSE_BLAS_ZGEMV SUITESPARSE_BLAS ( zgemv , ZGEMV ) #define SUITESPARSE_BLAS_ZTRSM SUITESPARSE_BLAS ( ztrsm , ZTRSM ) @@ -588,20 +596,46 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_ZHERK SUITESPARSE_BLAS ( zherk , ZHERK ) #define SUITESPARSE_BLAS_ZGERU SUITESPARSE_BLAS ( zgeru , ZGERU ) #define SUITESPARSE_BLAS_ZSCAL SUITESPARSE_BLAS ( zscal , ZSCAL ) -#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) - -#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) -#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) -#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) -#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) -#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) - #define SUITESPARSE_BLAS_DZNRM2 SUITESPARSE_BLAS ( dznrm2 , DZNRM2 ) + +#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) #define SUITESPARSE_LAPACK_ZLARF SUITESPARSE_BLAS ( zlarf , ZLARF ) #define SUITESPARSE_LAPACK_ZLARFG SUITESPARSE_BLAS ( zlarfg , ZLARFG ) #define SUITESPARSE_LAPACK_ZLARFT SUITESPARSE_BLAS ( zlarft , ZLARFT ) #define SUITESPARSE_LAPACK_ZLARFB SUITESPARSE_BLAS ( zlarfb , ZLARFB ) +// single +#define SUITESPARSE_BLAS_STRSV SUITESPARSE_BLAS ( strsv , STRSV ) +#define SUITESPARSE_BLAS_SGEMV SUITESPARSE_BLAS ( sgemv , SGEMV ) +#define SUITESPARSE_BLAS_STRSM SUITESPARSE_BLAS ( strsm , STRSM ) +#define SUITESPARSE_BLAS_SGEMM SUITESPARSE_BLAS ( sgemm , SGEMM ) +#define SUITESPARSE_BLAS_SSYRK SUITESPARSE_BLAS ( ssyrk , SSYRK ) +#define SUITESPARSE_BLAS_SGER SUITESPARSE_BLAS ( sger , SGER ) +#define SUITESPARSE_BLAS_SSCAL SUITESPARSE_BLAS ( sscal , SSCAL ) +#define SUITESPARSE_BLAS_SNRM2 SUITESPARSE_BLAS ( snrm2 , SNRM2 ) + +#define SUITESPARSE_LAPACK_SPOTRF SUITESPARSE_BLAS ( spotrf , SPOTRF ) +#define SUITESPARSE_LAPACK_SLARF SUITESPARSE_BLAS ( slarf , SLARF ) +#define SUITESPARSE_LAPACK_SLARFG SUITESPARSE_BLAS ( slarfg , SLARFG ) +#define SUITESPARSE_LAPACK_SLARFT SUITESPARSE_BLAS ( slarft , SLARFT ) +#define SUITESPARSE_LAPACK_SLARFB SUITESPARSE_BLAS ( slarfb , SLARFB ) + +// single complex +#define SUITESPARSE_BLAS_CTRSV SUITESPARSE_BLAS ( ctrsv , CTRSV ) +#define SUITESPARSE_BLAS_CGEMV SUITESPARSE_BLAS ( cgemv , CGEMV ) +#define SUITESPARSE_BLAS_CTRSM SUITESPARSE_BLAS ( ctrsm , CTRSM ) +#define SUITESPARSE_BLAS_CGEMM SUITESPARSE_BLAS ( cgemm , CGEMM ) +#define SUITESPARSE_BLAS_CHERK SUITESPARSE_BLAS ( cherk , CHERK ) +#define SUITESPARSE_BLAS_CGERU SUITESPARSE_BLAS ( cgeru , CGERU ) +#define SUITESPARSE_BLAS_CSCAL SUITESPARSE_BLAS ( cscal , CSCAL ) +#define SUITESPARSE_BLAS_SCNRM2 SUITESPARSE_BLAS ( scnrm2 , SCNRM2 ) + +#define SUITESPARSE_LAPACK_CPOTRF SUITESPARSE_BLAS ( cpotrf , CPOTRF ) +#define SUITESPARSE_LAPACK_CLARF SUITESPARSE_BLAS ( clarf , CLARF ) +#define SUITESPARSE_LAPACK_CLARFG SUITESPARSE_BLAS ( clarfg , CLARFG ) +#define SUITESPARSE_LAPACK_CLARFT SUITESPARSE_BLAS ( clarft , CLARFT ) +#define SUITESPARSE_LAPACK_CLARFB SUITESPARSE_BLAS ( clarfb , CLARFB ) + //------------------------------------------------------------------------------ // prototypes of BLAS and SUITESPARSE_LAPACK functions //------------------------------------------------------------------------------ @@ -627,7 +661,11 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #if defined ( SUITESPARSE_BLAS_DEFINITIONS ) -void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ +// gemv: Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMV ( // input: const char *trans, @@ -659,7 +697,39 @@ void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y } \ } -void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y +void SUITESPARSE_BLAS_SGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *beta, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGEMV ( // input: const char *trans, @@ -691,7 +761,43 @@ void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y } \ } -void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b +void SUITESPARSE_BLAS_CGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *beta, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsv: solve Lx=b, Ux=b, L'x=b, or U'x=b +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSV ( // input: const char *uplo, @@ -718,7 +824,34 @@ void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b } \ } -void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b +void SUITESPARSE_BLAS_STRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_strsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSV ( // input: const char *uplo, @@ -745,7 +878,38 @@ void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b } \ } -void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B +void SUITESPARSE_BLAS_CTRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_ctrsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsm: solve LX=B, UX=B, L'X=B, or U'X=B +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSM ( // input: const char *side, @@ -776,7 +940,38 @@ void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B } \ } -void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B +void SUITESPARSE_BLAS_STRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_strsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSM ( // input: const char *side, @@ -807,7 +1002,42 @@ void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B } \ } -void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_CTRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_ctrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// gemm: C = alpha*A*B + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMM ( // input: const char *transa, @@ -844,7 +1074,7 @@ void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C } \ } -void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_SGEMM ( // input: const char *transa, @@ -852,19 +1082,19 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const void *alpha, - const void *A, + const float *alpha, + const float *A, const SUITESPARSE_BLAS_INT *lda, - const void *B, + const float *B, const SUITESPARSE_BLAS_INT *ldb, - const void *beta, + const float *beta, // input/output: - void *C, + float *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ +#define SUITESPARSE_BLAS_sgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ @@ -875,52 +1105,62 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + SUITESPARSE_BLAS_SGEMM (transa, transb, &M_blas_int, &N_blas_int, \ &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_DSYRK // C = alpha*A*A' + beta*C, or A'A +void SUITESPARSE_BLAS_ZGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const double *alpha, - const double *A, + const void *alpha, + const void *A, const SUITESPARSE_BLAS_INT *lda, - const double *beta, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, + const void *beta, // input/output: - double *C, + void *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A +void SUITESPARSE_BLAS_CGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, const void *alpha, const void *A, const SUITESPARSE_BLAS_INT *lda, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, const void *beta, // input/output: void *C, @@ -928,52 +1168,211 @@ void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_cgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_CGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_DPOTRF // Cholesky factorization +//------------------------------------------------------------------------------ +// syrk/herk: C = alpha*A*A' + beta*C ; or C = alpha*A'*A + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSYRK ( // input: const char *uplo, + const char *trans, const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const double *alpha, + const double *A, + const SUITESPARSE_BLAS_INT *lda, + const double *beta, // input/output: - double *A, + double *C, // input: - const SUITESPARSE_BLAS_INT *lda, - // output: - SUITESPARSE_BLAS_INT *info + const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ - info = 1 ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ - SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ - &LAPACK_Info) ; \ - info = (Int) LAPACK_Info ; \ + SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization +void SUITESPARSE_BLAS_SSYRK ( // input: const char *uplo, + const char *trans, const SUITESPARSE_BLAS_INT *n, - // input/output: + const SUITESPARSE_BLAS_INT *k, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *beta, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_ssyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_CHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_cherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// potrf: Cholesky factorization +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + double *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_SPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_spotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_SPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: void *A, // input: const SUITESPARSE_BLAS_INT *lda, @@ -995,7 +1394,38 @@ void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization } \ } -void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y +void SUITESPARSE_LAPACK_CPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_cpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_CPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = LAPACK_Info ; \ + } \ +} + +//------------------------------------------------------------------------------ +// scal: Y = alpha*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1016,7 +1446,28 @@ void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y +void SUITESPARSE_BLAS_SSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1037,7 +1488,32 @@ void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A +void SUITESPARSE_BLAS_CSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// ger/geru: A = alpha*x*y' + A +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGER ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1067,7 +1543,37 @@ void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A } \ } -void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A +void SUITESPARSE_BLAS_SGER +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_sger(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGER (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGERU ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1097,7 +1603,41 @@ void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A } \ } -void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor +void SUITESPARSE_BLAS_CGERU +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_cgeru(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGERU (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larft: T = block Householder factor +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFT ( // input: const char *direct, @@ -1126,7 +1666,36 @@ void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor +void SUITESPARSE_LAPACK_SLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *Tau, + // output: + float *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_slarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFT ( // input: const char *direct, @@ -1155,7 +1724,40 @@ void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_CLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *Tau, + // output: + void *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_clarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfb: apply block Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFB ( // input: const char *side, @@ -1197,7 +1799,49 @@ void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_SLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_slarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFB ( // input: const char *side, @@ -1239,7 +1883,53 @@ void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector } \ } -double SUITESPARSE_BLAS_DNRM2 // vector 2-norm +void SUITESPARSE_LAPACK_CLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_clarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// nrm2: vector 2-norm +//------------------------------------------------------------------------------ + +double SUITESPARSE_BLAS_DNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1258,7 +1948,26 @@ double SUITESPARSE_BLAS_DNRM2 // vector 2-norm } \ } -double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm +float SUITESPARSE_BLAS_SNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_snrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +double SUITESPARSE_BLAS_DZNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1277,7 +1986,30 @@ double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm } \ } -void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector +float SUITESPARSE_BLAS_SCNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_scnrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SCNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfg: generate Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1301,7 +2033,31 @@ void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector +void SUITESPARSE_LAPACK_SLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *alpha, + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + float *tau +) ; + +#define SUITESPARSE_LAPACK_slarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1325,7 +2081,35 @@ void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_DLARF // apply Householder reflector +void SUITESPARSE_LAPACK_CLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *alpha, + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + void *tau +) ; + +#define SUITESPARSE_LAPACK_clarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larf: apply Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARF ( // input: const char *side, @@ -1355,7 +2139,37 @@ void SUITESPARSE_LAPACK_DLARF // apply Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector +void SUITESPARSE_LAPACK_SLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *V, + const SUITESPARSE_BLAS_INT *incv, + const float *tau, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work +) ; + +#define SUITESPARSE_LAPACK_slarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARF ( // input: const char *side, @@ -1385,6 +2199,36 @@ void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector } \ } +void SUITESPARSE_LAPACK_CLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *V, + const SUITESPARSE_BLAS_INT *incv, + const void *tau, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work +) ; + +#define SUITESPARSE_LAPACK_clarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + #endif //------------------------------------------------------------------------------ diff --git a/SuiteSparse_config/SuiteSparse_config.c b/SuiteSparse_config/SuiteSparse_config.c index 079093716a..acdacc2af4 100644 --- a/SuiteSparse_config/SuiteSparse_config.c +++ b/SuiteSparse_config/SuiteSparse_config.c @@ -760,6 +760,10 @@ const char *SuiteSparse_BLAS_library ( void ) return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? "OpenBLAS (64-bit integers)" : "OpenBLAS (32-bit integers)") ; + #elif defined ( BLAS_FLAME ) + return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? + "FLAME (64-bit integers)" : + "FLAME (32-bit integers)") ; #elif defined ( BLAS_Generic ) return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? "Reference BLAS (64-bit integers)" : diff --git a/SuiteSparse_config/SuiteSparse_config.h b/SuiteSparse_config/SuiteSparse_config.h index 03f10a3b45..3f0223f804 100644 --- a/SuiteSparse_config/SuiteSparse_config.h +++ b/SuiteSparse_config/SuiteSparse_config.h @@ -469,7 +469,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #elif defined ( BLAS_UNDERSCORE ) - // append an undescore, use lower case + // append an underscore, use lower case #define SUITESPARSE_FORTRAN(name,NAME) name ## _ #define SUITESPARSE__FORTRAN(name,NAME) name ## _ @@ -507,7 +507,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #else // let CMake determine the size of the integer in the Fortran BLAS - #define SUITESPARSE_BLAS_INT int32_t + #define SUITESPARSE_BLAS_INT int64_t #endif @@ -572,6 +572,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // C names of Fortan BLAS and LAPACK functions used by SuiteSparse //------------------------------------------------------------------------------ +// double #define SUITESPARSE_BLAS_DTRSV SUITESPARSE_BLAS ( dtrsv , DTRSV ) #define SUITESPARSE_BLAS_DGEMV SUITESPARSE_BLAS ( dgemv , DGEMV ) #define SUITESPARSE_BLAS_DTRSM SUITESPARSE_BLAS ( dtrsm , DTRSM ) @@ -579,8 +580,15 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_DSYRK SUITESPARSE_BLAS ( dsyrk , DSYRK ) #define SUITESPARSE_BLAS_DGER SUITESPARSE_BLAS ( dger , DGER ) #define SUITESPARSE_BLAS_DSCAL SUITESPARSE_BLAS ( dscal , DSCAL ) +#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) + #define SUITESPARSE_LAPACK_DPOTRF SUITESPARSE_BLAS ( dpotrf , DPOTRF ) +#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) +#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) +#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) +#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) +// double complex #define SUITESPARSE_BLAS_ZTRSV SUITESPARSE_BLAS ( ztrsv , ZTRSV ) #define SUITESPARSE_BLAS_ZGEMV SUITESPARSE_BLAS ( zgemv , ZGEMV ) #define SUITESPARSE_BLAS_ZTRSM SUITESPARSE_BLAS ( ztrsm , ZTRSM ) @@ -588,20 +596,46 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_ZHERK SUITESPARSE_BLAS ( zherk , ZHERK ) #define SUITESPARSE_BLAS_ZGERU SUITESPARSE_BLAS ( zgeru , ZGERU ) #define SUITESPARSE_BLAS_ZSCAL SUITESPARSE_BLAS ( zscal , ZSCAL ) -#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) - -#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) -#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) -#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) -#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) -#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) - #define SUITESPARSE_BLAS_DZNRM2 SUITESPARSE_BLAS ( dznrm2 , DZNRM2 ) + +#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) #define SUITESPARSE_LAPACK_ZLARF SUITESPARSE_BLAS ( zlarf , ZLARF ) #define SUITESPARSE_LAPACK_ZLARFG SUITESPARSE_BLAS ( zlarfg , ZLARFG ) #define SUITESPARSE_LAPACK_ZLARFT SUITESPARSE_BLAS ( zlarft , ZLARFT ) #define SUITESPARSE_LAPACK_ZLARFB SUITESPARSE_BLAS ( zlarfb , ZLARFB ) +// single +#define SUITESPARSE_BLAS_STRSV SUITESPARSE_BLAS ( strsv , STRSV ) +#define SUITESPARSE_BLAS_SGEMV SUITESPARSE_BLAS ( sgemv , SGEMV ) +#define SUITESPARSE_BLAS_STRSM SUITESPARSE_BLAS ( strsm , STRSM ) +#define SUITESPARSE_BLAS_SGEMM SUITESPARSE_BLAS ( sgemm , SGEMM ) +#define SUITESPARSE_BLAS_SSYRK SUITESPARSE_BLAS ( ssyrk , SSYRK ) +#define SUITESPARSE_BLAS_SGER SUITESPARSE_BLAS ( sger , SGER ) +#define SUITESPARSE_BLAS_SSCAL SUITESPARSE_BLAS ( sscal , SSCAL ) +#define SUITESPARSE_BLAS_SNRM2 SUITESPARSE_BLAS ( snrm2 , SNRM2 ) + +#define SUITESPARSE_LAPACK_SPOTRF SUITESPARSE_BLAS ( spotrf , SPOTRF ) +#define SUITESPARSE_LAPACK_SLARF SUITESPARSE_BLAS ( slarf , SLARF ) +#define SUITESPARSE_LAPACK_SLARFG SUITESPARSE_BLAS ( slarfg , SLARFG ) +#define SUITESPARSE_LAPACK_SLARFT SUITESPARSE_BLAS ( slarft , SLARFT ) +#define SUITESPARSE_LAPACK_SLARFB SUITESPARSE_BLAS ( slarfb , SLARFB ) + +// single complex +#define SUITESPARSE_BLAS_CTRSV SUITESPARSE_BLAS ( ctrsv , CTRSV ) +#define SUITESPARSE_BLAS_CGEMV SUITESPARSE_BLAS ( cgemv , CGEMV ) +#define SUITESPARSE_BLAS_CTRSM SUITESPARSE_BLAS ( ctrsm , CTRSM ) +#define SUITESPARSE_BLAS_CGEMM SUITESPARSE_BLAS ( cgemm , CGEMM ) +#define SUITESPARSE_BLAS_CHERK SUITESPARSE_BLAS ( cherk , CHERK ) +#define SUITESPARSE_BLAS_CGERU SUITESPARSE_BLAS ( cgeru , CGERU ) +#define SUITESPARSE_BLAS_CSCAL SUITESPARSE_BLAS ( cscal , CSCAL ) +#define SUITESPARSE_BLAS_SCNRM2 SUITESPARSE_BLAS ( scnrm2 , SCNRM2 ) + +#define SUITESPARSE_LAPACK_CPOTRF SUITESPARSE_BLAS ( cpotrf , CPOTRF ) +#define SUITESPARSE_LAPACK_CLARF SUITESPARSE_BLAS ( clarf , CLARF ) +#define SUITESPARSE_LAPACK_CLARFG SUITESPARSE_BLAS ( clarfg , CLARFG ) +#define SUITESPARSE_LAPACK_CLARFT SUITESPARSE_BLAS ( clarft , CLARFT ) +#define SUITESPARSE_LAPACK_CLARFB SUITESPARSE_BLAS ( clarfb , CLARFB ) + //------------------------------------------------------------------------------ // prototypes of BLAS and SUITESPARSE_LAPACK functions //------------------------------------------------------------------------------ @@ -627,7 +661,11 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #if defined ( SUITESPARSE_BLAS_DEFINITIONS ) -void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ +// gemv: Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMV ( // input: const char *trans, @@ -659,7 +697,39 @@ void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y } \ } -void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y +void SUITESPARSE_BLAS_SGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *beta, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGEMV ( // input: const char *trans, @@ -691,7 +761,43 @@ void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y } \ } -void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b +void SUITESPARSE_BLAS_CGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *beta, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsv: solve Lx=b, Ux=b, L'x=b, or U'x=b +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSV ( // input: const char *uplo, @@ -718,7 +824,34 @@ void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b } \ } -void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b +void SUITESPARSE_BLAS_STRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_strsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSV ( // input: const char *uplo, @@ -745,7 +878,38 @@ void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b } \ } -void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B +void SUITESPARSE_BLAS_CTRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_ctrsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsm: solve LX=B, UX=B, L'X=B, or U'X=B +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSM ( // input: const char *side, @@ -776,7 +940,38 @@ void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B } \ } -void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B +void SUITESPARSE_BLAS_STRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_strsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSM ( // input: const char *side, @@ -807,7 +1002,42 @@ void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B } \ } -void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_CTRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_ctrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// gemm: C = alpha*A*B + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMM ( // input: const char *transa, @@ -844,7 +1074,7 @@ void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C } \ } -void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_SGEMM ( // input: const char *transa, @@ -852,19 +1082,19 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const void *alpha, - const void *A, + const float *alpha, + const float *A, const SUITESPARSE_BLAS_INT *lda, - const void *B, + const float *B, const SUITESPARSE_BLAS_INT *ldb, - const void *beta, + const float *beta, // input/output: - void *C, + float *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ +#define SUITESPARSE_BLAS_sgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ @@ -875,52 +1105,62 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + SUITESPARSE_BLAS_SGEMM (transa, transb, &M_blas_int, &N_blas_int, \ &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_DSYRK // C = alpha*A*A' + beta*C, or A'A +void SUITESPARSE_BLAS_ZGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const double *alpha, - const double *A, + const void *alpha, + const void *A, const SUITESPARSE_BLAS_INT *lda, - const double *beta, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, + const void *beta, // input/output: - double *C, + void *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A +void SUITESPARSE_BLAS_CGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, const void *alpha, const void *A, const SUITESPARSE_BLAS_INT *lda, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, const void *beta, // input/output: void *C, @@ -928,47 +1168,206 @@ void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_cgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_CGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_DPOTRF // Cholesky factorization +//------------------------------------------------------------------------------ +// syrk/herk: C = alpha*A*A' + beta*C ; or C = alpha*A'*A + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSYRK ( // input: const char *uplo, + const char *trans, const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const double *alpha, + const double *A, + const SUITESPARSE_BLAS_INT *lda, + const double *beta, // input/output: - double *A, + double *C, // input: - const SUITESPARSE_BLAS_INT *lda, - // output: - SUITESPARSE_BLAS_INT *info + const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ - info = 1 ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ - SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ - &LAPACK_Info) ; \ - info = (Int) LAPACK_Info ; \ + SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization +void SUITESPARSE_BLAS_SSYRK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *beta, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_ssyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_CHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_cherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// potrf: Cholesky factorization +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + double *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_SPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_spotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_SPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZPOTRF ( // input: const char *uplo, @@ -995,7 +1394,38 @@ void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization } \ } -void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y +void SUITESPARSE_LAPACK_CPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_cpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_CPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = LAPACK_Info ; \ + } \ +} + +//------------------------------------------------------------------------------ +// scal: Y = alpha*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1016,7 +1446,28 @@ void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y +void SUITESPARSE_BLAS_SSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1037,7 +1488,32 @@ void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A +void SUITESPARSE_BLAS_CSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// ger/geru: A = alpha*x*y' + A +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGER ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1067,7 +1543,37 @@ void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A } \ } -void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A +void SUITESPARSE_BLAS_SGER +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_sger(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGER (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGERU ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1097,7 +1603,41 @@ void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A } \ } -void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor +void SUITESPARSE_BLAS_CGERU +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_cgeru(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGERU (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larft: T = block Householder factor +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFT ( // input: const char *direct, @@ -1126,7 +1666,36 @@ void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor +void SUITESPARSE_LAPACK_SLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *Tau, + // output: + float *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_slarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFT ( // input: const char *direct, @@ -1155,7 +1724,40 @@ void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_CLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *Tau, + // output: + void *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_clarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfb: apply block Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFB ( // input: const char *side, @@ -1197,7 +1799,49 @@ void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_SLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_slarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFB ( // input: const char *side, @@ -1239,7 +1883,53 @@ void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector } \ } -double SUITESPARSE_BLAS_DNRM2 // vector 2-norm +void SUITESPARSE_LAPACK_CLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_clarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// nrm2: vector 2-norm +//------------------------------------------------------------------------------ + +double SUITESPARSE_BLAS_DNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1258,7 +1948,26 @@ double SUITESPARSE_BLAS_DNRM2 // vector 2-norm } \ } -double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm +float SUITESPARSE_BLAS_SNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_snrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +double SUITESPARSE_BLAS_DZNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1277,7 +1986,30 @@ double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm } \ } -void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector +float SUITESPARSE_BLAS_SCNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_scnrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SCNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfg: generate Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1301,7 +2033,31 @@ void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector +void SUITESPARSE_LAPACK_SLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *alpha, + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + float *tau +) ; + +#define SUITESPARSE_LAPACK_slarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1325,7 +2081,35 @@ void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_DLARF // apply Householder reflector +void SUITESPARSE_LAPACK_CLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *alpha, + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + void *tau +) ; + +#define SUITESPARSE_LAPACK_clarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larf: apply Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARF ( // input: const char *side, @@ -1355,7 +2139,37 @@ void SUITESPARSE_LAPACK_DLARF // apply Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector +void SUITESPARSE_LAPACK_SLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *V, + const SUITESPARSE_BLAS_INT *incv, + const float *tau, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work +) ; + +#define SUITESPARSE_LAPACK_slarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARF ( // input: const char *side, @@ -1385,6 +2199,36 @@ void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector } \ } +void SUITESPARSE_LAPACK_CLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *V, + const SUITESPARSE_BLAS_INT *incv, + const void *tau, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work +) ; + +#define SUITESPARSE_LAPACK_clarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + #endif //------------------------------------------------------------------------------