Actual source code: centering.c

  1: #include <petsc/private/matimpl.h>

  3: static PetscErrorCode MatMult_Centering(Mat A, Vec xx, Vec yy)
  4: {
  5:   PetscScalar       *y;
  6:   const PetscScalar *x;
  7:   PetscScalar        sum, mean;
  8:   PetscInt           i, m = A->rmap->n, size;

 10:   PetscFunctionBegin;
 11:   PetscCall(VecSum(xx, &sum));
 12:   PetscCall(VecGetSize(xx, &size));
 13:   mean = sum / (PetscScalar)size;
 14:   PetscCall(VecGetArrayRead(xx, &x));
 15:   PetscCall(VecGetArray(yy, &y));
 16:   for (i = 0; i < m; i++) y[i] = x[i] - mean;
 17:   PetscCall(VecRestoreArrayRead(xx, &x));
 18:   PetscCall(VecRestoreArray(yy, &y));
 19:   PetscFunctionReturn(PETSC_SUCCESS);
 20: }

 22: /*MC
 23:   MATCENTERING - matrix object that implements the (symmetric and idempotent) centering matrix, $ I - (1/N) * 1^T * 1$

 25:   Level: beginner

 27:   Note:
 28:   See `MatCreateCentering()`

 30: .seealso:  `Mat`, `MatCreateCentering()`
 31: M*/

 33: /*@
 34:   MatCreateCentering - Creates a new matrix object that implements the (symmetric and idempotent) centering matrix, $ I - (1/N) * 1^T * 1$

 36:   Collective

 38:   Input Parameters:
 39: + comm - MPI communicator
 40: . n    - number of local rows (or `PETSC_DECIDE` to have calculated if `N` is given)
 41:          This value should be the same as the local size used in creating the
 42:          `y` vector for the matrix-vector product $y = Ax$.
 43: - N    - number of global rows (or `PETSC_DETERMINE` to have calculated if `n` is given)

 45:   Output Parameter:
 46: . C - the matrix

 48:   Notes:
 49:   The entries of the matrix `C` are not explicitly stored. Instead, the new matrix
 50:   object is a shell that simply performs the action of the centering matrix, i.e.,
 51:   multiplying $ C*x$ subtracts the mean of the vector `x` from each of its elements.
 52:   This is useful for preserving sparsity when mean-centering the columns of a
 53:   matrix is required. For instance, to perform principal components analysis with
 54:   a matrix `A`, the composite matrix $C*A$ can be passed to a partial SVD solver.

 56:   Level: intermediate

 58: .seealso: [](ch_matrices), `Mat`, `MatCreateLRC()`, `MatCreateComposite()`
 59: @*/
 60: PetscErrorCode MatCreateCentering(MPI_Comm comm, PetscInt n, PetscInt N, Mat *C)
 61: {
 62:   PetscMPIInt size;

 64:   PetscFunctionBegin;
 65:   PetscCall(MatCreate(comm, C));
 66:   PetscCall(MatSetSizes(*C, n, n, N, N));
 67:   PetscCallMPI(MPI_Comm_size(comm, &size));
 68:   PetscCall(PetscObjectChangeTypeName((PetscObject)*C, MATCENTERING));

 70:   (*C)->ops->mult                   = MatMult_Centering;
 71:   (*C)->assembled                   = PETSC_TRUE;
 72:   (*C)->preallocated                = PETSC_TRUE;
 73:   (*C)->symmetric                   = PETSC_BOOL3_TRUE;
 74:   (*C)->symmetry_eternal            = PETSC_TRUE;
 75:   (*C)->structural_symmetry_eternal = PETSC_TRUE;
 76:   PetscCall(MatSetUp(*C));
 77:   PetscFunctionReturn(PETSC_SUCCESS);
 78: }