Blame spblas/spdgemm.c

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() */