Actual source code: normm.c

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

      4: typedef struct {
      5:   Mat         A;
      6:   Vec         w,left,right,leftwork,rightwork;
      7:   PetscScalar scale;
      8: } Mat_Normal;

     10: PetscErrorCode MatScale_Normal(Mat inA,PetscScalar scale)
     11: {
     12:   Mat_Normal *a = (Mat_Normal*)inA->data;

     14:   a->scale *= scale;
     15:   return 0;
     16: }

     18: PetscErrorCode MatDiagonalScale_Normal(Mat inA,Vec left,Vec right)
     19: {
     20:   Mat_Normal     *a = (Mat_Normal*)inA->data;

     22:   if (left) {
     23:     if (!a->left) {
     24:       VecDuplicate(left,&a->left);
     25:       VecCopy(left,a->left);
     26:     } else {
     27:       VecPointwiseMult(a->left,left,a->left);
     28:     }
     29:   }
     30:   if (right) {
     31:     if (!a->right) {
     32:       VecDuplicate(right,&a->right);
     33:       VecCopy(right,a->right);
     34:     } else {
     35:       VecPointwiseMult(a->right,right,a->right);
     36:     }
     37:   }
     38:   return 0;
     39: }

     41: PetscErrorCode MatIncreaseOverlap_Normal(Mat A,PetscInt is_max,IS is[],PetscInt ov)
     42: {
     43:   Mat_Normal     *a = (Mat_Normal*)A->data;
     44:   Mat            pattern;

     47:   MatProductCreate(a->A,a->A,NULL,&pattern);
     48:   MatProductSetType(pattern,MATPRODUCT_AtB);
     49:   MatProductSetFromOptions(pattern);
     50:   MatProductSymbolic(pattern);
     51:   MatIncreaseOverlap(pattern,is_max,is,ov);
     52:   MatDestroy(&pattern);
     53:   return 0;
     54: }

     56: PetscErrorCode MatCreateSubMatrices_Normal(Mat mat,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat *submat[])
     57: {
     58:   Mat_Normal     *a = (Mat_Normal*)mat->data;
     59:   Mat            B = a->A, *suba;
     60:   IS             *row;
     61:   PetscInt       M;

     64:   if (scall != MAT_REUSE_MATRIX) {
     65:     PetscCalloc1(n,submat);
     66:   }
     67:   MatGetSize(B,&M,NULL);
     68:   PetscMalloc1(n,&row);
     69:   ISCreateStride(PETSC_COMM_SELF,M,0,1,&row[0]);
     70:   ISSetIdentity(row[0]);
     71:   for (M = 1; M < n; ++M) row[M] = row[0];
     72:   MatCreateSubMatrices(B,n,row,icol,MAT_INITIAL_MATRIX,&suba);
     73:   for (M = 0; M < n; ++M) {
     74:     MatCreateNormal(suba[M],*submat+M);
     75:     ((Mat_Normal*)(*submat)[M]->data)->scale = a->scale;
     76:   }
     77:   ISDestroy(&row[0]);
     78:   PetscFree(row);
     79:   MatDestroySubMatrices(n,&suba);
     80:   return 0;
     81: }

     83: PetscErrorCode MatPermute_Normal(Mat A,IS rowp,IS colp,Mat *B)
     84: {
     85:   Mat_Normal     *a = (Mat_Normal*)A->data;
     86:   Mat            C,Aa = a->A;
     87:   IS             row;

     90:   ISCreateStride(PetscObjectComm((PetscObject)Aa),Aa->rmap->n,Aa->rmap->rstart,1,&row);
     91:   ISSetIdentity(row);
     92:   MatPermute(Aa,row,colp,&C);
     93:   ISDestroy(&row);
     94:   MatCreateNormal(C,B);
     95:   MatDestroy(&C);
     96:   return 0;
     97: }

     99: PetscErrorCode MatDuplicate_Normal(Mat A, MatDuplicateOption op, Mat *B)
    100: {
    101:   Mat_Normal     *a = (Mat_Normal*)A->data;
    102:   Mat            C;

    105:   MatDuplicate(a->A,op,&C);
    106:   MatCreateNormal(C,B);
    107:   MatDestroy(&C);
    108:   if (op == MAT_COPY_VALUES) ((Mat_Normal*)(*B)->data)->scale = a->scale;
    109:   return 0;
    110: }

    112: PetscErrorCode MatCopy_Normal(Mat A,Mat B,MatStructure str)
    113: {
    114:   Mat_Normal     *a = (Mat_Normal*)A->data,*b = (Mat_Normal*)B->data;

    117:   MatCopy(a->A,b->A,str);
    118:   b->scale = a->scale;
    119:   VecDestroy(&b->left);
    120:   VecDestroy(&b->right);
    121:   VecDestroy(&b->leftwork);
    122:   VecDestroy(&b->rightwork);
    123:   return 0;
    124: }

    126: PetscErrorCode MatMult_Normal(Mat N,Vec x,Vec y)
    127: {
    128:   Mat_Normal     *Na = (Mat_Normal*)N->data;
    129:   Vec            in;

    131:   in = x;
    132:   if (Na->right) {
    133:     if (!Na->rightwork) {
    134:       VecDuplicate(Na->right,&Na->rightwork);
    135:     }
    136:     VecPointwiseMult(Na->rightwork,Na->right,in);
    137:     in   = Na->rightwork;
    138:   }
    139:   MatMult(Na->A,in,Na->w);
    140:   MatMultTranspose(Na->A,Na->w,y);
    141:   if (Na->left) {
    142:     VecPointwiseMult(y,Na->left,y);
    143:   }
    144:   VecScale(y,Na->scale);
    145:   return 0;
    146: }

    148: PetscErrorCode MatMultAdd_Normal(Mat N,Vec v1,Vec v2,Vec v3)
    149: {
    150:   Mat_Normal     *Na = (Mat_Normal*)N->data;
    151:   Vec            in;

    153:   in = v1;
    154:   if (Na->right) {
    155:     if (!Na->rightwork) {
    156:       VecDuplicate(Na->right,&Na->rightwork);
    157:     }
    158:     VecPointwiseMult(Na->rightwork,Na->right,in);
    159:     in   = Na->rightwork;
    160:   }
    161:   MatMult(Na->A,in,Na->w);
    162:   VecScale(Na->w,Na->scale);
    163:   if (Na->left) {
    164:     MatMultTranspose(Na->A,Na->w,v3);
    165:     VecPointwiseMult(v3,Na->left,v3);
    166:     VecAXPY(v3,1.0,v2);
    167:   } else {
    168:     MatMultTransposeAdd(Na->A,Na->w,v2,v3);
    169:   }
    170:   return 0;
    171: }

    173: PetscErrorCode MatMultTranspose_Normal(Mat N,Vec x,Vec y)
    174: {
    175:   Mat_Normal     *Na = (Mat_Normal*)N->data;
    176:   Vec            in;

    178:   in = x;
    179:   if (Na->left) {
    180:     if (!Na->leftwork) {
    181:       VecDuplicate(Na->left,&Na->leftwork);
    182:     }
    183:     VecPointwiseMult(Na->leftwork,Na->left,in);
    184:     in   = Na->leftwork;
    185:   }
    186:   MatMult(Na->A,in,Na->w);
    187:   MatMultTranspose(Na->A,Na->w,y);
    188:   if (Na->right) {
    189:     VecPointwiseMult(y,Na->right,y);
    190:   }
    191:   VecScale(y,Na->scale);
    192:   return 0;
    193: }

    195: PetscErrorCode MatMultTransposeAdd_Normal(Mat N,Vec v1,Vec v2,Vec v3)
    196: {
    197:   Mat_Normal     *Na = (Mat_Normal*)N->data;
    198:   Vec            in;

    200:   in = v1;
    201:   if (Na->left) {
    202:     if (!Na->leftwork) {
    203:       VecDuplicate(Na->left,&Na->leftwork);
    204:     }
    205:     VecPointwiseMult(Na->leftwork,Na->left,in);
    206:     in   = Na->leftwork;
    207:   }
    208:   MatMult(Na->A,in,Na->w);
    209:   VecScale(Na->w,Na->scale);
    210:   if (Na->right) {
    211:     MatMultTranspose(Na->A,Na->w,v3);
    212:     VecPointwiseMult(v3,Na->right,v3);
    213:     VecAXPY(v3,1.0,v2);
    214:   } else {
    215:     MatMultTransposeAdd(Na->A,Na->w,v2,v3);
    216:   }
    217:   return 0;
    218: }

    220: PetscErrorCode MatDestroy_Normal(Mat N)
    221: {
    222:   Mat_Normal     *Na = (Mat_Normal*)N->data;

    224:   MatDestroy(&Na->A);
    225:   VecDestroy(&Na->w);
    226:   VecDestroy(&Na->left);
    227:   VecDestroy(&Na->right);
    228:   VecDestroy(&Na->leftwork);
    229:   VecDestroy(&Na->rightwork);
    230:   PetscFree(N->data);
    231:   PetscObjectComposeFunction((PetscObject)N,"MatNormalGetMat_C",NULL);
    232:   PetscObjectComposeFunction((PetscObject)N,"MatConvert_normal_seqaij_C",NULL);
    233:   PetscObjectComposeFunction((PetscObject)N,"MatConvert_normal_mpiaij_C",NULL);
    234:   PetscObjectComposeFunction((PetscObject)N,"MatProductSetFromOptions_normal_seqdense_C",NULL);
    235:   PetscObjectComposeFunction((PetscObject)N,"MatProductSetFromOptions_normal_mpidense_C",NULL);
    236:   PetscObjectComposeFunction((PetscObject)N,"MatProductSetFromOptions_normal_dense_C",NULL);
    237:   return 0;
    238: }

    240: /*
    241:       Slow, nonscalable version
    242: */
    243: PetscErrorCode MatGetDiagonal_Normal(Mat N,Vec v)
    244: {
    245:   Mat_Normal        *Na = (Mat_Normal*)N->data;
    246:   Mat               A   = Na->A;
    247:   PetscInt          i,j,rstart,rend,nnz;
    248:   const PetscInt    *cols;
    249:   PetscScalar       *diag,*work,*values;
    250:   const PetscScalar *mvalues;

    252:   PetscMalloc2(A->cmap->N,&diag,A->cmap->N,&work);
    253:   PetscArrayzero(work,A->cmap->N);
    254:   MatGetOwnershipRange(A,&rstart,&rend);
    255:   for (i=rstart; i<rend; i++) {
    256:     MatGetRow(A,i,&nnz,&cols,&mvalues);
    257:     for (j=0; j<nnz; j++) {
    258:       work[cols[j]] += mvalues[j]*mvalues[j];
    259:     }
    260:     MatRestoreRow(A,i,&nnz,&cols,&mvalues);
    261:   }
    262:   MPIU_Allreduce(work,diag,A->cmap->N,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)N));
    263:   rstart = N->cmap->rstart;
    264:   rend   = N->cmap->rend;
    265:   VecGetArray(v,&values);
    266:   PetscArraycpy(values,diag+rstart,rend-rstart);
    267:   VecRestoreArray(v,&values);
    268:   PetscFree2(diag,work);
    269:   VecScale(v,Na->scale);
    270:   return 0;
    271: }

    273: PetscErrorCode MatNormalGetMat_Normal(Mat A,Mat *M)
    274: {
    275:   Mat_Normal *Aa = (Mat_Normal*)A->data;

    277:   *M = Aa->A;
    278:   return 0;
    279: }

    281: /*@
    282:       MatNormalGetMat - Gets the Mat object stored inside a MATNORMAL

    284:    Logically collective on Mat

    286:    Input Parameter:
    287: .   A  - the MATNORMAL matrix

    289:    Output Parameter:
    290: .   M - the matrix object stored inside A

    292:    Level: intermediate

    294: .seealso: MatCreateNormal()

    296: @*/
    297: PetscErrorCode MatNormalGetMat(Mat A,Mat *M)
    298: {
    302:   PetscUseMethod(A,"MatNormalGetMat_C",(Mat,Mat*),(A,M));
    303:   return 0;
    304: }

    306: PetscErrorCode MatConvert_Normal_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
    307: {
    308:   Mat_Normal     *Aa = (Mat_Normal*)A->data;
    309:   Mat            B;
    310:   PetscInt       m,n,M,N;

    312:   MatGetSize(A,&M,&N);
    313:   MatGetLocalSize(A,&m,&n);
    314:   if (reuse == MAT_REUSE_MATRIX) {
    315:     B = *newmat;
    316:     MatProductReplaceMats(Aa->A,Aa->A,NULL,B);
    317:   } else {
    318:     MatProductCreate(Aa->A,Aa->A,NULL,&B);
    319:     MatProductSetType(B,MATPRODUCT_AtB);
    320:     MatProductSetFromOptions(B);
    321:     MatProductSymbolic(B);
    322:     MatSetOption(B,MAT_SYMMETRIC,PETSC_TRUE);
    323:   }
    324:   MatProductNumeric(B);
    325:   if (reuse == MAT_INPLACE_MATRIX) {
    326:     MatHeaderReplace(A,&B);
    327:   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
    328:   MatConvert(*newmat,MATAIJ,MAT_INPLACE_MATRIX,newmat);
    329:   return 0;
    330: }

    332: typedef struct {
    333:   Mat work[2];
    334: } Normal_Dense;

    336: PetscErrorCode MatProductNumeric_Normal_Dense(Mat C)
    337: {
    338:   Mat            A,B;
    339:   Normal_Dense   *contents;
    340:   Mat_Normal     *a;
    341:   PetscScalar    *array;

    343:   MatCheckProduct(C,3);
    344:   A = C->product->A;
    345:   a = (Mat_Normal*)A->data;
    346:   B = C->product->B;
    347:   contents = (Normal_Dense*)C->product->data;
    349:   if (a->right) {
    350:     MatCopy(B,C,SAME_NONZERO_PATTERN);
    351:     MatDiagonalScale(C,a->right,NULL);
    352:   }
    353:   MatProductNumeric(contents->work[0]);
    354:   MatDenseGetArrayWrite(C,&array);
    355:   MatDensePlaceArray(contents->work[1],array);
    356:   MatProductNumeric(contents->work[1]);
    357:   MatDenseRestoreArrayWrite(C,&array);
    358:   MatDenseResetArray(contents->work[1]);
    359:   MatSetOption(C,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
    360:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
    361:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
    362:   MatScale(C,a->scale);
    363:   return 0;
    364: }

    366: PetscErrorCode MatNormal_DenseDestroy(void *ctx)
    367: {
    368:   Normal_Dense   *contents = (Normal_Dense*)ctx;

    370:   MatDestroy(contents->work);
    371:   MatDestroy(contents->work+1);
    372:   PetscFree(contents);
    373:   return 0;
    374: }

    376: PetscErrorCode MatProductSymbolic_Normal_Dense(Mat C)
    377: {
    378:   Mat            A,B;
    379:   Normal_Dense   *contents = NULL;
    380:   Mat_Normal     *a;
    381:   PetscScalar    *array;
    382:   PetscInt       n,N,m,M;

    384:   MatCheckProduct(C,4);
    386:   A = C->product->A;
    387:   a = (Mat_Normal*)A->data;
    389:   B = C->product->B;
    390:   MatGetLocalSize(C,&m,&n);
    391:   MatGetSize(C,&M,&N);
    392:   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
    393:     MatGetLocalSize(B,NULL,&n);
    394:     MatGetSize(B,NULL,&N);
    395:     MatGetLocalSize(A,&m,NULL);
    396:     MatGetSize(A,&M,NULL);
    397:     MatSetSizes(C,m,n,M,N);
    398:   }
    399:   MatSetType(C,((PetscObject)B)->type_name);
    400:   MatSetUp(C);
    401:   PetscNew(&contents);
    402:   C->product->data = contents;
    403:   C->product->destroy = MatNormal_DenseDestroy;
    404:   if (a->right) {
    405:     MatProductCreate(a->A,C,NULL,contents->work);
    406:   } else {
    407:     MatProductCreate(a->A,B,NULL,contents->work);
    408:   }
    409:   MatProductSetType(contents->work[0],MATPRODUCT_AB);
    410:   MatProductSetFromOptions(contents->work[0]);
    411:   MatProductSymbolic(contents->work[0]);
    412:   MatProductCreate(a->A,contents->work[0],NULL,contents->work+1);
    413:   MatProductSetType(contents->work[1],MATPRODUCT_AtB);
    414:   MatProductSetFromOptions(contents->work[1]);
    415:   MatProductSymbolic(contents->work[1]);
    416:   MatDenseGetArrayWrite(C,&array);
    417:   MatSeqDenseSetPreallocation(contents->work[1],array);
    418:   MatMPIDenseSetPreallocation(contents->work[1],array);
    419:   MatDenseRestoreArrayWrite(C,&array);
    420:   C->ops->productnumeric = MatProductNumeric_Normal_Dense;
    421:   return 0;
    422: }

    424: PetscErrorCode MatProductSetFromOptions_Normal_Dense_AB(Mat C)
    425: {
    426:   C->ops->productsymbolic = MatProductSymbolic_Normal_Dense;
    427:   return 0;
    428: }

    430: PetscErrorCode MatProductSetFromOptions_Normal_Dense(Mat C)
    431: {
    432:   Mat_Product    *product = C->product;

    434:   if (product->type == MATPRODUCT_AB) {
    435:     MatProductSetFromOptions_Normal_Dense_AB(C);
    436:   }
    437:   return 0;
    438: }

    440: /*@
    441:       MatCreateNormal - Creates a new matrix object that behaves like A'*A.

    443:    Collective on Mat

    445:    Input Parameter:
    446: .   A  - the (possibly rectangular) matrix

    448:    Output Parameter:
    449: .   N - the matrix that represents A'*A

    451:    Level: intermediate

    453:    Notes:
    454:     The product A'*A is NOT actually formed! Rather the new matrix
    455:           object performs the matrix-vector product by first multiplying by
    456:           A and then A'
    457: @*/
    458: PetscErrorCode  MatCreateNormal(Mat A,Mat *N)
    459: {
    460:   PetscInt       n,nn;
    461:   Mat_Normal     *Na;
    462:   VecType        vtype;

    464:   MatGetSize(A,NULL,&nn);
    465:   MatGetLocalSize(A,NULL,&n);
    466:   MatCreate(PetscObjectComm((PetscObject)A),N);
    467:   MatSetSizes(*N,n,n,nn,nn);
    468:   PetscObjectChangeTypeName((PetscObject)*N,MATNORMAL);
    469:   PetscLayoutReference(A->cmap,&(*N)->rmap);
    470:   PetscLayoutReference(A->cmap,&(*N)->cmap);

    472:   PetscNewLog(*N,&Na);
    473:   (*N)->data = (void*) Na;
    474:   PetscObjectReference((PetscObject)A);
    475:   Na->A      = A;
    476:   Na->scale  = 1.0;

    478:   MatCreateVecs(A,NULL,&Na->w);

    480:   (*N)->ops->destroy           = MatDestroy_Normal;
    481:   (*N)->ops->mult              = MatMult_Normal;
    482:   (*N)->ops->multtranspose     = MatMultTranspose_Normal;
    483:   (*N)->ops->multtransposeadd  = MatMultTransposeAdd_Normal;
    484:   (*N)->ops->multadd           = MatMultAdd_Normal;
    485:   (*N)->ops->getdiagonal       = MatGetDiagonal_Normal;
    486:   (*N)->ops->scale             = MatScale_Normal;
    487:   (*N)->ops->diagonalscale     = MatDiagonalScale_Normal;
    488:   (*N)->ops->increaseoverlap   = MatIncreaseOverlap_Normal;
    489:   (*N)->ops->createsubmatrices = MatCreateSubMatrices_Normal;
    490:   (*N)->ops->permute           = MatPermute_Normal;
    491:   (*N)->ops->duplicate         = MatDuplicate_Normal;
    492:   (*N)->ops->copy              = MatCopy_Normal;
    493:   (*N)->assembled              = PETSC_TRUE;
    494:   (*N)->preallocated           = PETSC_TRUE;

    496:   PetscObjectComposeFunction((PetscObject)(*N),"MatNormalGetMat_C",MatNormalGetMat_Normal);
    497:   PetscObjectComposeFunction((PetscObject)(*N),"MatConvert_normal_seqaij_C",MatConvert_Normal_AIJ);
    498:   PetscObjectComposeFunction((PetscObject)(*N),"MatConvert_normal_mpiaij_C",MatConvert_Normal_AIJ);
    499:   PetscObjectComposeFunction((PetscObject)(*N),"MatProductSetFromOptions_normal_seqdense_C",MatProductSetFromOptions_Normal_Dense);
    500:   PetscObjectComposeFunction((PetscObject)(*N),"MatProductSetFromOptions_normal_mpidense_C",MatProductSetFromOptions_Normal_Dense);
    501:   PetscObjectComposeFunction((PetscObject)(*N),"MatProductSetFromOptions_normal_dense_C",MatProductSetFromOptions_Normal_Dense);
    502:   MatSetOption(*N,MAT_SYMMETRIC,PETSC_TRUE);
    503:   MatGetVecType(A,&vtype);
    504:   MatSetVecType(*N,vtype);
    505: #if defined(PETSC_HAVE_DEVICE)
    506:   MatBindToCPU(*N,A->boundtocpu);
    507: #endif
    508:   return 0;
    509: }