//------------------------------------------------------------------------------ // SuiteSparse/Example/Source/my_cxx.cc //------------------------------------------------------------------------------ // Copyright (c) 2022-2023, Timothy A. Davis, All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause //------------------------------------------------------------------------------ // Example C++ library that relies on SuiteSparse packages #include #include #include #include "my_internal.h" //------------------------------------------------------------------------------ // OK: check a result and return an error if it fails //------------------------------------------------------------------------------ #define OK(result) \ if (!(result)) \ { \ std::cout << "FAIL file: " << __FILE__ \ " line: " << __LINE__ << std::endl ;\ return (-1) ; \ } //------------------------------------------------------------------------------ // my_version: version of MY library //------------------------------------------------------------------------------ void my_version (int version [3], char date [128]) { // get the version of this library strncpy (date, MY_DATE, 127) ; version [0] = MY_MAJOR_VERSION ; version [1] = MY_MINOR_VERSION ; version [2] = MY_PATCH_VERSION ; } //------------------------------------------------------------------------------ // my_check_version: check library version //------------------------------------------------------------------------------ int my_check_version (const char *package, int major, int minor, int patch, const char *date, int version [3], long long unsigned int vercode) { // version and date in package header file: std::cout << "\n------------------------------------------------------------\n" << package << ": v" << major << "." << minor << "." << patch << " " << "(" << date << ")" << std::endl ; // version in library itself: std::cout << package << ": v" << version [0] << "." << version [1] << "." << version [2] << " " << "(in library)" << std::endl ; // make sure the versions match int ok = (major == version [0]) && (minor == version [1]) && (patch == version [2]) ; if (!ok) { std::cout << "Versions do not match" << std::endl ; } std::cout << package << " version code: " << vercode << std::endl ; ok = ok && (vercode == SUITESPARSE__VERCODE (major, minor, patch)) ; if (!ok) { std::cout << "version code mismatch: " << vercode << SUITESPARSE__VERCODE (major, minor, patch) << std::endl ; } return (ok) ; } //------------------------------------------------------------------------------ // my_function: try each library in SuiteSparse //------------------------------------------------------------------------------ int my_function (void) // returns 0 on success, -1 on failure { int version [3] ; //-------------------------------------------------------------------------- // My package //-------------------------------------------------------------------------- char my_date [128] ; my_version (version, my_date) ; OK (my_check_version ("MY", MY_MAJOR_VERSION, MY_MINOR_VERSION, MY_PATCH_VERSION, MY_DATE, version, SUITESPARSE__VERCODE (MY_MAJOR_VERSION, MY_MINOR_VERSION, MY_PATCH_VERSION))) ; std::cout << "MY date: " << my_date << std::endl ; OK (strcmp (my_date, MY_DATE) == 0) ; //-------------------------------------------------------------------------- // SuiteSparse_config //-------------------------------------------------------------------------- int v = SuiteSparse_version (version) ; OK (my_check_version ("SuiteSparse_config", SUITESPARSE_MAIN_VERSION, SUITESPARSE_SUB_VERSION, SUITESPARSE_SUBSUB_VERSION, SUITESPARSE_DATE, version, SUITESPARSE__VERSION)) ; //-------------------------------------------------------------------------- // CXSparse //-------------------------------------------------------------------------- cxsparse_version (version) ; OK (my_check_version ("CXSparse", CS_VER, CS_SUBVER, CS_SUBSUB, CS_DATE, version, CXSPARSE__VERSION)) ; cs_dl *A = nullptr ; // create a dense 2-by-2 matrix #define N 2 #define NNZ 4 int64_t n = N, nzmax = NNZ ; A = cs_dl_spalloc (n, n, nzmax, true, false) ; OK (A != nullptr) ; int64_t *Ap = A->p ; int64_t *Ai = A->i ; double *Ax = A->x ; Ap [0] = 0 ; Ap [1] = 2 ; Ap [2] = 4 ; Ai [0] = 0 ; Ax [0] = 11.0 ; // A(0,0) = 11 Ai [1] = 1 ; Ax [1] = 21.0 ; // A(1,0) = 21 Ai [2] = 0 ; Ax [2] = 12.0 ; // A(0,1) = 12 Ai [3] = 1 ; Ax [3] = 22.0 ; // A(1,1) = 22 OK (cs_dl_print (A, false)) ; //-------------------------------------------------------------------------- // AMD //-------------------------------------------------------------------------- amd_version (version) ; OK (my_check_version ("AMD", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE, version, AMD__VERSION)) ; int64_t P [N] ; OK (amd_l_order (n, Ap, Ai, P, nullptr, nullptr) == AMD_OK) ; for (int k = 0 ; k < n ; k++) { std::cout << "P [" << k << "] = " << P [k] << std::endl; } //-------------------------------------------------------------------------- // BTF //-------------------------------------------------------------------------- btf_version (version) ; OK (my_check_version ("BTF", BTF_MAIN_VERSION, BTF_SUB_VERSION, BTF_SUBSUB_VERSION, BTF_DATE, version, BTF__VERSION)) ; double work ; int64_t nmatch ; int64_t Q [N], R [N+1], Work [5*N] ; int64_t nblocks = btf_l_order (n, Ap, Ai, -1, &work, P, Q, R, &nmatch, Work) ; OK (nblocks > 0) ; for (int k = 0 ; k < n ; k++) { std::cout << "P [" << k << "] = " << P [k] << std::endl; } for (int k = 0 ; k < n ; k++) { std::cout << "Q [" << k << "] = " << Q [k] << std::endl; } std::cout << "nblocks " << nblocks << std::endl; //-------------------------------------------------------------------------- // CAMD //-------------------------------------------------------------------------- camd_version (version) ; OK (my_check_version ("CAMD", CAMD_MAIN_VERSION, CAMD_SUB_VERSION, CAMD_SUBSUB_VERSION, CAMD_DATE, version, CAMD__VERSION)) ; int64_t Cmem [N] ; for (int k = 0 ; k < n ; k++) { Cmem [k] = 0 ; } OK (camd_l_order (n, Ap, Ai, P, nullptr, nullptr, Cmem) == CAMD_OK) ; for (int k = 0 ; k < n ; k++) { std::cout << "P [" << k << "] = " << P [k] << std::endl; } //-------------------------------------------------------------------------- // CCOLAMD //-------------------------------------------------------------------------- ccolamd_version (version) ; OK (my_check_version ("CCOLAMD", CCOLAMD_MAIN_VERSION, CCOLAMD_SUB_VERSION, CCOLAMD_SUBSUB_VERSION, CCOLAMD_DATE, version, CCOLAMD__VERSION)) ; int64_t Alen = ccolamd_l_recommended (NNZ, n, n) ; int64_t *Awork = (int64_t *) malloc (Alen * sizeof (int64_t)) ; OK (Awork != nullptr) ; memcpy (Awork, Ai, NNZ * sizeof (int64_t)) ; OK (ccolamd_l (n, n, Alen, Awork, P, nullptr, nullptr, Cmem) == CCOLAMD_OK); for (int k = 0 ; k < n ; k++) { std::cout << "P [" << k << "] = " << P [k] << std::endl; } free (Awork) ; //-------------------------------------------------------------------------- // COLAMD //-------------------------------------------------------------------------- colamd_version (version) ; OK (my_check_version ("COLAMD", COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_SUBSUB_VERSION, COLAMD_DATE, version, COLAMD__VERSION)) ; Alen = ccolamd_l_recommended (NNZ, n, n) ; Awork = (int64_t *) malloc (Alen * sizeof (int64_t)) ; OK (Awork != nullptr) ; memcpy (Awork, Ai, NNZ * sizeof (int64_t)) ; OK (colamd_l (n, n, Alen, Awork, P, nullptr, nullptr) == COLAMD_OK) ; for (int k = 0 ; k < n ; k++) { std::cout << "P [" << k << "] = " << P [k] << std::endl; } free (Awork) ; //-------------------------------------------------------------------------- // CHOLMOD //-------------------------------------------------------------------------- v = cholmod_l_version (version) ; OK (my_check_version ("CHOLMOD", CHOLMOD_MAIN_VERSION, CHOLMOD_SUB_VERSION, CHOLMOD_SUBSUB_VERSION, CHOLMOD_DATE, version, CHOLMOD__VERSION)) ; cholmod_common cc ; OK (cholmod_l_start (&cc)) ; //-------------------------------------------------------------------------- // GraphBLAS //-------------------------------------------------------------------------- #if ! defined (NO_GRAPHBLAS) OK (GrB_init (GrB_NONBLOCKING) == GrB_SUCCESS) ; OK (GxB_Global_Option_get (GxB_LIBRARY_VERSION, version) == GrB_SUCCESS) ; OK (my_check_version ("GraphBLAS", GxB_IMPLEMENTATION_MAJOR, GxB_IMPLEMENTATION_MINOR, GxB_IMPLEMENTATION_SUB, GxB_IMPLEMENTATION_DATE, version, GxB_IMPLEMENTATION)) ; OK (GrB_finalize ( ) == GrB_SUCCESS) ; #endif //-------------------------------------------------------------------------- // LAGraph //-------------------------------------------------------------------------- #if ! defined (NO_LAGRAPH) char msg [LAGRAPH_MSG_LEN], verstring [LAGRAPH_MSG_LEN] ; OK (LAGraph_Init (msg) == GrB_SUCCESS) ; OK (LAGraph_Version (version, verstring, msg) == GrB_SUCCESS) ; OK (my_check_version ("LAGraph", LAGRAPH_VERSION_MAJOR, LAGRAPH_VERSION_MINOR, LAGRAPH_VERSION_UPDATE, LAGRAPH_DATE, version, SUITESPARSE__VERCODE (LAGRAPH_VERSION_MAJOR, LAGRAPH_VERSION_MINOR, LAGRAPH_VERSION_UPDATE))) ; OK (LAGraph_Finalize (msg) == GrB_SUCCESS) ; #endif //-------------------------------------------------------------------------- // KLU //-------------------------------------------------------------------------- klu_version (version) ; OK (my_check_version ("KLU", KLU_MAIN_VERSION, KLU_SUB_VERSION, KLU_SUBSUB_VERSION, KLU_DATE, version, KLU__VERSION)) ; double b [N] = {8., 45.} ; double xgood [N] = {36.4, -32.7} ; double x [N] ; klu_l_symbolic *Symbolic ; klu_l_numeric *Numeric ; klu_l_common Common ; OK (klu_l_defaults (&Common)) ; Symbolic = klu_l_analyze (n, Ap, Ai, &Common) ; OK (Symbolic != nullptr) ; Numeric = klu_l_factor (Ap, Ai, Ax, Symbolic, &Common) ; OK (Numeric != nullptr) ; memcpy (x, b, N * sizeof (double)) ; OK (klu_l_solve (Symbolic, Numeric, 5, 1, x, &Common)) ; klu_l_free_symbolic (&Symbolic, &Common) ; klu_l_free_numeric (&Numeric, &Common) ; double err = 0 ; for (int i = 0 ; i < n ; i++) { std::cout << "x [" << i << "] = " << x [i] << std::endl; err = fmax (err, fabs (x [i] - xgood [i])) ; } std::cout << "error: " << err << std::endl; OK (err < 1e-12) ; //-------------------------------------------------------------------------- // LDL //-------------------------------------------------------------------------- ldl_version (version) ; OK (my_check_version ("LDL", LDL_MAIN_VERSION, LDL_SUB_VERSION, LDL_SUBSUB_VERSION, LDL_DATE, version, LDL__VERSION)) ; double x2 [N] ; P [0] = 0 ; P [1] = 1 ; ldl_l_perm (n, x2, xgood, P) ; err = 0 ; for (int i = 0 ; i < n ; i++) { std::cout << "x2 [" << i << "] = " << x2 [i] << std::endl; err = fmax (err, fabs (x2 [i] - xgood [i])) ; } std::cout << "error: " << err << std::endl; OK (err == 0) ; //-------------------------------------------------------------------------- // RBio //-------------------------------------------------------------------------- RBio_version (version) ; OK (my_check_version ("RBio", RBIO_MAIN_VERSION, RBIO_SUB_VERSION, RBIO_SUBSUB_VERSION, RBIO_DATE, version, RBIO__VERSION)) ; char mtype [4]; std::string key {"simple"}; std::string title {"2-by-2 matrix"}; mtype [0] = '\0' ; int64_t njumbled, nzeros ; int result = RBok (n, n, NNZ, Ap, Ai, Ax, nullptr, nullptr, 0, &njumbled, &nzeros) ; OK (result == RBIO_OK) ; std::cout << "njumbled " << njumbled << ", nzeros " << nzeros << std::endl; std::string filename {"temp.rb"}; result = RBwrite (filename.c_str (), title.c_str (), key.c_str (), n, n, Ap, Ai, Ax, nullptr, nullptr, nullptr, 0, mtype) ; std::cout << "result " << result << std::endl; std::cout << "mtype: " << mtype << std::endl; // dump out the file FILE *f = fopen ("temp.rb", "r") ; OK (f != nullptr) ; int c ; while (1) { c = fgetc (f) ; if (c == EOF) break ; fputc (c, stdout) ; } fclose (f) ; //-------------------------------------------------------------------------- // SPEX //-------------------------------------------------------------------------- OK (SPEX_initialize ( ) == SPEX_OK) ; char spex_date [128] ; OK (SPEX_version (version, spex_date) == SPEX_OK) ; OK (my_check_version ("SPEX", SPEX_VERSION_MAJOR, SPEX_VERSION_MINOR, SPEX_VERSION_SUB, SPEX_DATE, version, SPEX__VERSION)) ; OK (SPEX_finalize ( ) == SPEX_OK) ; //-------------------------------------------------------------------------- // SPQR //-------------------------------------------------------------------------- SuiteSparseQR_version (version) ; OK (my_check_version ("SuiteSparseQR", SPQR_MAIN_VERSION, SPQR_SUB_VERSION, SPQR_SUBSUB_VERSION, SPQR_DATE, version, SPQR__VERSION)) ; cholmod_sparse *A2, A2_struct ; cholmod_dense *B2, B2_struct ; cholmod_dense *X2 ; // make a shallow CHOLMOD copy of A A2 = &A2_struct ; A2->nrow = n ; A2->ncol = n ; A2->p = Ap ; A2->i = Ai ; A2->x = Ax ; A2->z = nullptr ; A2->nzmax = NNZ ; A2->packed = true ; A2->sorted = true ; A2->nz = nullptr ; A2->itype = CHOLMOD_LONG ; A2->dtype = CHOLMOD_DOUBLE ; A2->xtype = CHOLMOD_REAL ; A2->stype = 0 ; // make a shallow CHOLMOD copy of b B2 = &B2_struct ; B2->nrow = n ; B2->ncol = 1 ; B2->x = b ; B2->z = nullptr ; B2->d = n ; B2->nzmax = n ; B2->dtype = CHOLMOD_DOUBLE ; B2->xtype = CHOLMOD_REAL ; X2 = SuiteSparseQR_C_backslash_default (A2, B2, &cc) ; OK (X2 != nullptr) ; OK (cc.status == CHOLMOD_OK) ; cc.print = 5 ; OK (cholmod_l_print_dense (X2, "X from QR", &cc)) ; //-------------------------------------------------------------------------- // UMFPACK //-------------------------------------------------------------------------- umfpack_version (version) ; OK (my_check_version ("UMFPACK", UMFPACK_MAIN_VERSION, UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE, version, UMFPACK__VERSION)) ; std::cout << UMFPACK_VERSION << std::endl; std::cout << UMFPACK_COPYRIGHT; std::cout << UMFPACK_LICENSE_PART1; std::cout << "BLAS used: " << SuiteSparse_BLAS_library ( ) << std::endl; std::cout << "BLAS integer size: " << sizeof (SUITESPARSE_BLAS_INT) << " bytes" << std::endl; double Control [UMFPACK_CONTROL] ; double Info [UMFPACK_INFO] ; umfpack_dl_defaults (Control) ; Control [UMFPACK_PRL] = 6 ; void *Sym, *Num ; (void) umfpack_dl_symbolic (n, n, Ap, Ai, Ax, &Sym, Control, Info) ; (void) umfpack_dl_numeric (Ap, Ai, Ax, Sym, &Num, Control, Info) ; umfpack_dl_free_symbolic (&Sym) ; result = umfpack_dl_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Num, Control, Info); umfpack_dl_free_numeric (&Num) ; for (int i = 0 ; i < n ; i++) { std::cout << "x [" << i << "] = " << x [i] << std::endl; } err = 0 ; for (int i = 0 ; i < n ; i++) { err = fmax (err, fabs (x [i] - xgood [i])) ; } std::cout << "error: " << err << std::endl; OK (err < 1e-12) ; umfpack_dl_report_status (Control, result) ; umfpack_dl_report_info (Control, Info) ; //-------------------------------------------------------------------------- // Mongoose //-------------------------------------------------------------------------- version [0] = Mongoose::major_version ( ) ; version [1] = Mongoose::minor_version ( ) ; version [2] = Mongoose::patch_version ( ) ; OK (my_check_version ("Mongoose", Mongoose_VERSION_MAJOR, Mongoose_VERSION_MINOR, Mongoose_VERSION_PATCH, Mongoose_DATE, version, Mongoose__VERSION)) ; std::cout << "Mongoose::mongoose_version(): " << Mongoose::mongoose_version ( ) << std::endl; //-------------------------------------------------------------------------- // not used //-------------------------------------------------------------------------- // std::cout << "ParU version code: " << PARU__VERSION << std::endl ; //-------------------------------------------------------------------------- // free workspace and return result //-------------------------------------------------------------------------- cs_dl_spfree (A) ; A = nullptr ; OK (cholmod_l_finish (&cc)) ; return (0) ; }