|
Packit |
67cb25 |
/* spdgemm.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2014 Patrick Alken
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <stdlib.h>
|
|
Packit |
67cb25 |
#include <math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_spmatrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_spblas.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_spblas_dgemm()
|
|
Packit |
67cb25 |
Multiply two sparse matrices
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: alpha - scalar factor
|
|
Packit |
67cb25 |
A - sparse matrix
|
|
Packit |
67cb25 |
B - sparse matrix
|
|
Packit |
67cb25 |
C - (output) C = alpha * A * B
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) based on CSparse routine cs_multiply
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_spblas_dgemm(const double alpha, const gsl_spmatrix *A,
|
|
Packit |
67cb25 |
const gsl_spmatrix *B, gsl_spmatrix *C)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (A->size2 != B->size1 || A->size1 != C->size1 || B->size2 != C->size2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("matrix dimensions do not match", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (A->sptype != B->sptype || A->sptype != C->sptype)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("matrix storage formats do not match", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (!GSL_SPMATRIX_ISCCS(A))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("compressed column format required", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int status = GSL_SUCCESS;
|
|
Packit |
67cb25 |
const size_t M = A->size1;
|
|
Packit |
67cb25 |
const size_t N = B->size2;
|
|
Packit |
67cb25 |
size_t *Bi = B->i;
|
|
Packit |
67cb25 |
size_t *Bp = B->p;
|
|
Packit |
67cb25 |
double *Bd = B->data;
|
|
Packit |
67cb25 |
size_t *w = (size_t *) A->work; /* workspace of length M */
|
|
Packit |
67cb25 |
double *x = (double *) C->work; /* workspace of length M */
|
|
Packit |
67cb25 |
size_t *Cp, *Ci;
|
|
Packit |
67cb25 |
double *Cd;
|
|
Packit |
67cb25 |
size_t j, p;
|
|
Packit |
67cb25 |
size_t nz = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (C->nzmax < A->nz + B->nz)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
status = gsl_spmatrix_realloc(A->nz + B->nz, C);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("unable to realloc matrix C", status);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize workspace to 0 */
|
|
Packit |
67cb25 |
for (j = 0; j < M; ++j)
|
|
Packit |
67cb25 |
w[j] = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Cp = C->p;
|
|
Packit |
67cb25 |
Ci = C->i;
|
|
Packit |
67cb25 |
Cd = C->data;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < N; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (nz + M > C->nzmax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
status = gsl_spmatrix_realloc(2 * C->nzmax + M, C);
|
|
Packit |
67cb25 |
if (status)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR("unable to realloc matrix C", status);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* these pointers could have changed due to reallocation */
|
|
Packit |
67cb25 |
Ci = C->i;
|
|
Packit |
67cb25 |
Cd = C->data;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Cp[j] = nz; /* column j of C starts here */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (p = Bp[j]; p < Bp[j + 1]; ++p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nz = gsl_spblas_scatter(A, Bi[p], Bd[p], w, x, j + 1, C, nz);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (p = Cp[j]; p < nz; ++p)
|
|
Packit |
67cb25 |
Cd[p] = x[Ci[p]];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Cp[N] = nz;
|
|
Packit |
67cb25 |
C->nz = nz;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* scale by alpha */
|
|
Packit |
67cb25 |
gsl_spmatrix_scale(C, alpha);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return status;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_spblas_dgemm() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_spblas_scatter()
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Keep a running total x -> x + alpha*A(:,j) for adding matrices together in CCS,
|
|
Packit |
67cb25 |
which will eventually be stored in C(:,j)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
When a new non-zero element with row index i is found, update C->i with
|
|
Packit |
67cb25 |
the row index. C->data is updated only by the calling function after all
|
|
Packit |
67cb25 |
matrices have been added via this function.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - sparse matrix m-by-n
|
|
Packit |
67cb25 |
j - column index
|
|
Packit |
67cb25 |
alpha - scalar factor
|
|
Packit |
67cb25 |
w - keeps track which rows of column j have been added to C;
|
|
Packit |
67cb25 |
initialize to 0 prior to first call
|
|
Packit |
67cb25 |
x - column vector of length m
|
|
Packit |
67cb25 |
mark -
|
|
Packit |
67cb25 |
C - output matrix whose jth column will be added to A(:,j)
|
|
Packit |
67cb25 |
nz - (input/output) number of non-zeros in matrix C
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
1) This function is designed to be called successively when adding multiple
|
|
Packit |
67cb25 |
matrices together. Column j of C is stored contiguously as per CCS but not
|
|
Packit |
67cb25 |
necessarily in order - ie: the row indices C->i may not be in ascending order.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) based on CSparse routine cs_scatter
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
size_t
|
|
Packit |
67cb25 |
gsl_spblas_scatter(const gsl_spmatrix *A, const size_t j, const double alpha,
|
|
Packit |
67cb25 |
size_t *w, double *x, const size_t mark, gsl_spmatrix *C,
|
|
Packit |
67cb25 |
size_t nz)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t p;
|
|
Packit |
67cb25 |
size_t *Ai = A->i;
|
|
Packit |
67cb25 |
size_t *Ap = A->p;
|
|
Packit |
67cb25 |
double *Ad = A->data;
|
|
Packit |
67cb25 |
size_t *Ci = C->i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (p = Ap[j]; p < Ap[j + 1]; ++p)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i = Ai[p]; /* A(i,j) is nonzero */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w[i] < mark) /* check if row i has been stored in column j yet */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w[i] = mark; /* i is new entry in column j */
|
|
Packit |
67cb25 |
Ci[nz++] = i; /* add i to pattern of C(:,j) */
|
|
Packit |
67cb25 |
x[i] = alpha * Ad[p]; /* x(i) = alpha * A(i,j) */
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else /* this (i,j) exists in C from a previous call */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
x[i] += alpha * Ad[p]; /* add alpha*A(i,j) to C(i,j) */
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return (nz) ;
|
|
Packit |
67cb25 |
} /* gsl_spblas_scatter() */
|