//------------------------------------------------------------------------------ // CHOLMOD/Utility/t_cholmod_add: C = alpha*A + beta*B //------------------------------------------------------------------------------ // CHOLMOD/Utility Module. Copyright (C) 2023, Timothy A. Davis, All Rights // Reserved. // SPDX-License-Identifier: LGPL-2.1+ //------------------------------------------------------------------------------ // The C matrix is returned as packed and sorted. A and B must have the same // xtype, unless one of them is pattern, in which case only the patterns of A // and B are used, and C has xtype of pattern. A, B, and C must all have the // same dtype. If A->stype and B->stype differ, then C is computed as // unsymmetric (stype of 0). #include "cholmod_internal.h" #define RETURN_IF_ERROR \ if (Common->status < CHOLMOD_OK) \ { \ CHOLMOD(free_sparse) (&C, Common) ; \ CHOLMOD(free_sparse) (&A2, Common) ; \ CHOLMOD(free_sparse) (&B2, Common) ; \ return (NULL) ; \ } //------------------------------------------------------------------------------ // t_cholmod_add_worker template //------------------------------------------------------------------------------ #define PATTERN #include "t_cholmod_add_worker.c" #define DOUBLE #define REAL #include "t_cholmod_add_worker.c" #define COMPLEX #include "t_cholmod_add_worker.c" #define ZOMPLEX #include "t_cholmod_add_worker.c" #undef DOUBLE #define SINGLE #define REAL #include "t_cholmod_add_worker.c" #define COMPLEX #include "t_cholmod_add_worker.c" #define ZOMPLEX #include "t_cholmod_add_worker.c" //------------------------------------------------------------------------------ // cholmod_add: C = alpha*A + beta*B //------------------------------------------------------------------------------ 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 entries used if complex) double beta [2], // scale factor for B (two entries used if complex) 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 ) { //-------------------------------------------------------------------------- // check inputs and determine the xtype and dtype of C //-------------------------------------------------------------------------- RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_SPARSE_MATRIX_INVALID (A, NULL) ; RETURN_IF_SPARSE_MATRIX_INVALID (B, NULL) ; Common->status = CHOLMOD_OK ; cholmod_sparse *A2 = NULL, *B2 = NULL, *C = NULL ; if (A->nrow != B->nrow || A->ncol != B->ncol) { ERROR (CHOLMOD_INVALID, "A and B dimensions do not match") ; return (NULL) ; } mode = RANGE (mode, 0, 2) ; int axtype = A->xtype ; int bxtype = B->xtype ; if (mode == 0 || axtype == CHOLMOD_PATTERN || bxtype == CHOLMOD_PATTERN) { // treat A and B as if they are pattern-only matrices; C is pattern mode = 0 ; axtype = CHOLMOD_PATTERN ; bxtype = CHOLMOD_PATTERN ; } if (axtype != bxtype) { ERROR (CHOLMOD_INVALID, "A and B xtypes do not match") ; return (NULL) ; } if (mode != 0 && A->dtype != B->dtype) { ERROR (CHOLMOD_INVALID, "A and B dtypes do not match") ; return (NULL) ; } 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 //-------------------------------------------------------------------------- size_t ei = sizeof (Int) ; size_t e = (dtype == CHOLMOD_SINGLE) ? sizeof (float) : sizeof (double) ; size_t ex = e * ((xtype == CHOLMOD_PATTERN) ? 0 : ((xtype == CHOLMOD_COMPLEX) ? 2 : 1)) ; size_t ez = e * ((xtype == CHOLMOD_ZOMPLEX) ? 1 : 0) ; //-------------------------------------------------------------------------- // convert/sort A and/or B, if needed //-------------------------------------------------------------------------- if (A->stype == B->stype) { //---------------------------------------------------------------------- // A and B have the same stype, but make sure they are both sorted //---------------------------------------------------------------------- // A2 = sorted copy of A, if A is not sorted, with same stype as A if (!A->sorted) { A2 = CHOLMOD(copy) (A, A->stype, mode, Common) ; RETURN_IF_ERROR ; CHOLMOD(sort) (A2, Common) ; RETURN_IF_ERROR ; A = A2 ; } // B2 = sorted copy of B, if B is not sorted, with same stype as B if (!B->sorted) { B2 = CHOLMOD(copy) (B, B->stype, mode, Common) ; RETURN_IF_ERROR ; CHOLMOD(sort) (B2, Common) ; RETURN_IF_ERROR ; B = B2 ; } } else { //---------------------------------------------------------------------- // the stype of A and B differ, so make both unsymmetric and sorted //---------------------------------------------------------------------- if (!(A->stype == 0 && A->sorted)) { // A2 = sorted unsymmetric copy of A with stype of zero A2 = CHOLMOD(copy) (A, 0, mode, Common) ; RETURN_IF_ERROR ; if (!A2->sorted) { CHOLMOD(sort) (A2, Common) ; RETURN_IF_ERROR ; } A = A2 ; } if (!(B->stype == 0 && B->sorted)) { // B2 = sorted unsymmetric copy of A with stype of zero B2 = CHOLMOD(copy) (B, 0, mode, Common) ; RETURN_IF_ERROR ; if (!B2->sorted) { CHOLMOD(sort) (B2, Common) ; RETURN_IF_ERROR ; } B = B2 ; } } // C, A, and B now all have the same stype, and are sorted ASSERT (A->stype == B->stype) ; ASSERT (A->sorted) ; ASSERT (B->sorted) ; //-------------------------------------------------------------------------- // allocate C //-------------------------------------------------------------------------- size_t nzmax = CHOLMOD(nnz) (A, Common) + CHOLMOD(nnz) (B, Common) ; C = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, nzmax, /* C is sorted: */ TRUE, /* C is packed: */ TRUE, A->stype, xtype + dtype, Common) ; RETURN_IF_ERROR ; //-------------------------------------------------------------------------- // C = alpha*A + beta*B //-------------------------------------------------------------------------- switch ((xtype + dtype) % 8) { default: p_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_REAL + CHOLMOD_SINGLE: rs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_COMPLEX + CHOLMOD_SINGLE: cs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_ZOMPLEX + CHOLMOD_SINGLE: zs_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_REAL + CHOLMOD_DOUBLE: rd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_COMPLEX + CHOLMOD_DOUBLE: cd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; case CHOLMOD_ZOMPLEX + CHOLMOD_DOUBLE: zd_cholmod_add_worker (C, A, B, alpha, beta, Common) ; break ; } //-------------------------------------------------------------------------- // free temporary copies of A and B, if created //-------------------------------------------------------------------------- CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; //-------------------------------------------------------------------------- // compact the space of C //-------------------------------------------------------------------------- size_t cnz = CHOLMOD(nnz) (C, Common) ; CHOLMOD(reallocate_sparse) (cnz, C, Common) ; RETURN_IF_ERROR ; //-------------------------------------------------------------------------- // return result //-------------------------------------------------------------------------- ASSERT (CHOLMOD(dump_sparse) (C, "add:C", Common) >= 0) ; return (C) ; }