// CXSparse/MATLAB/CSparse/cs_usolve: x=U\b, where x,b are sparse or dense // CXSparse, Copyright (c) 2006-2022, Timothy A. Davis. All Rights Reserved. // SPDX-License-Identifier: LGPL-2.1+ #include "cs_mex.h" /* cs_usolve: x=U\b. U must be sparse and upper triangular. b must be a * full or sparse vector. x is full or sparse, depending on b. * * Time taken is O(flop count), which may be less than n if b is sparse, * depending on U and b. * * This function works with MATLAB 7.2, but is not perfectly compatible with * the requirements of a MATLAB mexFunction when b is sparse. X is returned * as an unsorted sparse vector. Also, this mexFunction temporarily modifies * its input, U, by modifying U->p (in the cs_dfs function) and then restoring * it. This could be corrected by creating a copy of U->p * (see cs_dmperm_mex.c), but this would take O(n) time, destroying the * O(flop count) time complexity of this function. * * Note that b cannot be sparse complex. This function does not support * sparse complex U and b because the sparse x=U\b only accesses part of the * matrix U. Converting U from a MATLAB complex matrix to a CXSparse complex * matrix requires all of U to be accessed, defeating the purpose of this * function. * * U can be sparse complex, but in that case b must be full real or complex, * not sparse. */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { int64_t top, nz, p, *xi, n ; if (nargout > 1 || nargin != 2) { mexErrMsgTxt ("Usage: x = cs_usolve(U,b)") ; } if (mxIsSparse (pargin [1])) { cs_dl Umatrix, Bmatrix, *U, *B, *X ; double *x ; if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { mexErrMsgTxt ("sparse complex case not supported") ; } U = cs_dl_mex_get_sparse (&Umatrix, 1, 1, pargin [0]) ;/* get U */ n = U->n ; B = cs_dl_mex_get_sparse (&Bmatrix, 0, 1, pargin [1]) ;/* get sparse b*/ cs_mex_check (0, n, 1, 0, 1, 1, pargin [1]) ; xi = cs_dl_malloc (2*n, sizeof (int64_t)) ; /* get workspace */ x = cs_dl_malloc (n, sizeof (double)) ; top = cs_dl_spsolve (U, B, 0, xi, x, NULL, 0) ; /* x = U\b */ X = cs_dl_spalloc (n, 1, n-top, 1, 0) ; /* create sparse x*/ X->p [0] = 0 ; nz = 0 ; for (p = top ; p < n ; p++) { X->i [nz] = xi [p] ; X->x [nz++] = x [xi [p]] ; } X->p [1] = nz ; pargout [0] = cs_dl_mex_put_sparse (&X) ; cs_dl_free (x) ; cs_dl_free (xi) ; } else if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl Umatrix, *U ; cs_complex_t *x ; U = cs_cl_mex_get_sparse (&Umatrix, 1, pargin [0]) ; /* get U */ n = U->n ; x = cs_cl_mex_get_double (n, pargin [1]) ; /* x = b */ cs_cl_usolve (U, x) ; /* x = U\x */ cs_cl_free (U->x) ; pargout [0] = cs_cl_mex_put_double (n, x) ; /* return x */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl Umatrix, *U ; double *x, *b ; U = cs_dl_mex_get_sparse (&Umatrix, 1, 1, pargin [0]) ; /* get U */ n = U->n ; b = cs_dl_mex_get_double (n, pargin [1]) ; /* get b */ x = cs_dl_mex_put_double (n, b, &(pargout [0])) ; /* x = b */ cs_dl_usolve (U, x) ; /* x = U\x */ } }