[超初心者向け] ICCGでAx=bを解くwith PETSc

この記事は、実際に、PETScの関数を用いて、Ax=bの方程式を解くやり方についての備忘録です。
今回は、大規模疎行列に対して非常に有効な解法であるICCG法( 不完全コレスキー分解付き共役勾配法 )をPETScを用いて簡単に実装したいと思います。

私もそうですが、シミュレーションのコードでPETScのようなライブラリを使用する場合、行列 A やベクトル b の値を保持する配列がすでに存在しており、解くべきxに値する配列(例えば圧力など)もすでに存在しています。

したがって、PETScを用いる関数の外で定義された A と b をPETScが計算できる形にして(`Vec`と`Mat`)計算し、そこで得た解を配列に変換してやるという作業が必要になります。この記事では特にこの部分について、解説します。

また、筆者は数値計算の専門家でもなければ、プログラミングの専門家でもないので、この実装をするととりあえず動くというくらいの認識でお願いします( どうしても英語ドキュメントを読みたくない人向け？？ )。

[ 9/9 追記 ]
[src/ksp/ksp/tutorials/ex13.c.html](https://www.mcs.anl.gov/petsc/petsc-current/src/ksp/ksp/tutorials/ex13.c.html)では、Cのarray から PETScのVecに代入せずに計算する方法が記載してあります。(ただし、`Vec`の方の操作のみ)
`Vec`側については、こちらの[ VecCreateSeqWithArray ](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecCreateSeqWithArray.html)と、[VecPlaceArray](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecPlaceArray.html#VecPlaceArray)と[VecResetArray](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecResetArray.html#VecResetArray)の３つの関数を用いた方法が良いと思われます。
また、`Mat`についても、[MatCreateSeqAIJWithArrays](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatCreateSeqAIJWithArrays.html)が用意されているので、こちらもご参照ください。

## 環境
この記事では、[公式マニュアルの1.2章](https://www.mcs.anl.gov/petsc/petsc-current/docs/manual.pdf)でも使用されている`$PETSC_DIR/src/ksp/ksp/tutorials/ex1.c`を題材にしていきます。

また、今回使用するPETScの環境は"[MacでPETScをMPI無しで使う](https://qiita.com/K-eno/items/8d7cdef79d2015503309)"の記事にある通り、mpi無しで`./configure`を行っています。(MPIありでも結果は変わらないと思います。)

コンパイルは同様に[MacでPETScをMPI無しで使う](https://qiita.com/K-eno/items/8d7cdef79d2015503309)"の記事で示したのと同様のmakeファイルを用いています。

今回解く方程式は以下の簡単な三重対角行列を解いていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586286/7226539f-fd7d-dc9d-140f-656add779877.png)
(画像は[PC: Preconditioners](https://docs.petsc.org/en/wg-beginners-tutorials/tutorials/introductory_tutorial_pc.html)より引用)

## main関数
今回使用するmainプログラムは以下の通りです。( 余計な関数を使わなかったので、長くなって申し訳ないです。)

```main.c
#include <petscksp.h>

int main(int argc,char **args){
   double *A,*x,*b;
   int n = 10; 
   int i,j;

   A = malloc(n * n * sizeof(double));
   x = malloc(n * sizeof(double));
   b = malloc(n * sizeof(double));

   for(i=0; i<n; i++){
      x[i] = 0.0;
   }

   printf("---------x before using petsc-------------\n");
   for(i=0; i<n; i++){
      printf("%lf \n",x[i]);
   }
   // set b 
   b[0] = 1.0 ; b[n-1] = 1.0;
   for(i=1; i<n-1; i++){
      b[i] = 0.0;
   }
   printf("--------- b -------------\n");
   for(i=0;i<n;i++){
      printf("%lf \n",b[i]);
   }
   printf("\n");

  //Assemble matrix A [a_ii = 2.0, a_i(i-1) = a_i(i+1) = -1.0]
   A[0] = 2.0 ;A[1] = -1.0; for(i=2;i<n;i++){A[i] = 0.0;} //row 0 
   for(i=1; i<n-1; i++){
     for(j=0; j<n; j++){
        if(j == i-1 || j == i+1){ A[n*i + j] = -1.0; }
        else if(j == i){ A[n*i + j] = 2.0; }
        else { A[n*i + j] = 0.0; } 
      }
   }
   for(i=0; i<n-2;i++){ A[n*(n-1) + i] = 0.0; } A[n*n -2] = -1.0; A[n*n -1] = 2.0; //row n-1

   printf("---------- A --------------\n");
   for(i=0;i<n;i++){
      for(j=0;j<n;j++){
         printf("%lf ",A[n * i + j]);
      }
      printf("\n");
   }

   calcAxb(argc,args,A,x,b,n); //here use PETSc library

   printf("-----------x after using petsc------------\n");
   for(int i=0; i<n; i++){
      printf("%lf \n",x[i]);
   }
   free(x);free(A);free(b);

   return 0;
}
```

ここでやっているのは、

- A と b の定義と x の初期化
- それらの確認(print)
- `calcAxb`でPETScを用いて、Ax=bを解く

です。

## calcAxb関数
中身はこんな感じです。(ex1.c のプログラムを少しいじって作りました。)

```calcAxb.c

PetscErrorCode calcAxb(int argc,char **args,double *A_input, double *x_input, double *b_input,int n)
{
  Vec            x, b, u;      /* approx solution, RHS, exact solution */
  Mat            A;            /* linear system matrix */
  KSP            ksp;          /* linear solver context */
  PC             pc;           /* preconditioner context */
  PetscReal      norm;         /* norm of solution error */
  PetscErrorCode ierr;
  PetscInt       its,*ix;
  PetscMPIInt    size;
  
//ix = PetscInt *indices in VecSetValues(),MatSetValues(),VecGetValues()
  ix = malloc(sizeof(int) * n); 
  for(int k=0; k<n; k++){
     ix[k] = k;
  }

// must do this procedure for uniprocessor 
  ierr = PetscInitialize(&argc,&args,(char*)0,help); if (ierr) return ierr; 
  ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
  if (size != 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");
  ierr = PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL);CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
         Compute the matrix and right-hand-side vector that define
         the linear system, Ax = b.
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  /* Create vectors. */
  ierr = VecCreate(PETSC_COMM_WORLD,&x);CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) x, "Solution");CHKERRQ(ierr);
  ierr = VecSetSizes(x,PETSC_DECIDE,n);CHKERRQ(ierr);
  ierr = VecSetFromOptions(x);CHKERRQ(ierr); //must, but I don't know this function's mean 
  ierr = VecDuplicate(x,&b);CHKERRQ(ierr); //let b same size of vector as x (not copy)
  ierr = VecDuplicate(x,&u);CHKERRQ(ierr); 

   // set vector values
   VecSetValues(b,n,ix,b_input,INSERT_VALUES); //b_input --> b 

   //If it is finished to insert value in vector, these two functions are necessary.
   ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
   ierr = VecAssemblyEnd(b);CHKERRQ(ierr);

   printf("---- b in petsc -------\n");
   ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);

  /* Create matrix.  When using MatCreate(), the matrix format can be specified at runtime. */
 
  ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr);
  ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,n,n);CHKERRQ(ierr);
  ierr = MatSetFromOptions(A);CHKERRQ(ierr);
  ierr = MatSetUp(A);CHKERRQ(ierr);

  // Assemble matrix [a_ii = 2.0, a_i(j-1) = a_i(j+1) = -1.0] 
  ierr = MatSetValues(A,n,ix,n,ix,A_input,INSERT_VALUES); CHKERRQ(ierr);
  ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr);
  
  /* A is symmetric. Set symmetric flag to enable ICC/Cholesky preconditioner */
  ierr = MatSetOption(A,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
  
  /*  These two funtion is needed if assemblying matirix is finished. */
  ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
  ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);

  printf("----- A in petsc -------\n");
  ierr = MatView(A,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
  
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
                Create the linear solver and set various options
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = KSPCreate(PETSC_COMM_WORLD,&ksp);CHKERRQ(ierr);
  /*
     Set operators. Here the matrix that defines the linear system
     also serves as the matrix that defines the preconditioner.
  */
  ierr = KSPSetOperators(ksp,A,A);CHKERRQ(ierr); //set A is the matrix to solve 
  
/* Set linear solver defaults for this problem (optional). */
  ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
  ierr = PCSetType(pc,PCICC);CHKERRQ(ierr);
  ierr = KSPSetTolerances(ksp,1.e-5,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); //誤差の設定
  ierr = KSPSetType(ksp,KSPCG); CHKERRQ(ierr);

  /* Set runtime options */
 ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
                      Solve the linear system
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = KSPSolve(ksp,b,x);CHKERRQ(ierr);

  /* View solver info */
  ierr = KSPView(ksp,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
  ierr = PetscPrintf(PETSC_COMM_WORLD,"View matrix and vector \n");CHKERRQ(ierr);
  ierr = VecView(x,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
  
  /* get the x vector  (x --> x_input) */
  ierr = VecGetValues(x,n,ix,x_input);

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      Check the solution and clean up
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ierr = VecSet(u,1.0);CHKERRQ(ierr); //u[i] = 1.0 
  ierr = VecAXPY(x,-1.0,u);CHKERRQ(ierr); //x = x + (-1.0)*u
  ierr = VecNorm(x,NORM_2,&norm);CHKERRQ(ierr); 
  ierr = KSPGetIterationNumber(ksp,&its);CHKERRQ(ierr); 
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Norm of error %g, Iterations %D\n",(double)norm,its);CHKERRQ(ierr);

  /* Free work space */
  ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr);
  ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = MatDestroy(&A);CHKERRQ(ierr);
  ierr = KSPDestroy(&ksp);CHKERRQ(ierr)
  
  /* finish */
  ierr = PetscFinalize();
  return 0;
}
```
いじった部分としては

- `Vec b` への値の代入
- `Mat A` への値の代入
- 解となる`Vec x`を関数外に出す
- ソルバーは`CG`(共役勾配法、CG法)、前処理(PC)は`ICC`(不完全コレスキー分解)

になるでしょうか。

## PETScの型とCの型

普通、Cでベクトルや行列を扱う際は配列を使用します。
しかし、PETScではベクトルについては`Vec`、行列については`Mat`の型を定義し計算します。
つまり、上記のmain関数で使用した A や b はそのままの`double の配列`のままでは使用できず、それぞれ`Vec`や`Mat`の型に変換する必要があります。

また、Cのデフォルトの型と一致しているものもいくつか存在します。今回のコードでは以下の三つが該当します。

- `PetscInt` = `int`
- `PetscReal` = `PetscScalar` = `double`

おそらく`float`や`char`もあると思います。

## `Vec`の作成

ベクトル b の作成パートは以下の部分になります。

```vector_part.c
 /* Create vectors. */
  ierr = VecCreate(PETSC_COMM_WORLD,&x);CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) x, "Solution");CHKERRQ(ierr);
  ierr = VecSetSizes(x,PETSC_DECIDE,n);CHKERRQ(ierr);
  ierr = VecSetFromOptions(x);CHKERRQ(ierr); //must, but I don't know this function's mean 
  ierr = VecDuplicate(x,&b);CHKERRQ(ierr); //let b same size of vector as x (not copy)
  ierr = VecDuplicate(x,&u);CHKERRQ(ierr); 

   // set vector values
   VecSetValues(b,n,ix,b_input,INSERT_VALUES); //b_input --> b 

   //If it is finished to insert value in vector, these two functions are necessary.
   ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
   ierr = VecAssemblyEnd(b);CHKERRQ(ierr);

   printf("---- b in petsc -------\n");
   ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);

```

実際に、`Vec b`に`double b_input[n]`を代入しているのは[VecSetValues(Vec x,PetscInt ni,const PetscInt ix[],const PetscScalar y[],InsertMode iora)](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecSetValues.html)の部分になります。

引数の`const PetscScalar y[]`が今回は`b_input`に当たります。
`PetscScalar`が`double`と等しいのでそのまま代入することができます。

ベクトルの値の設定が終わり次第、[VecAssemblyBegin( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecAssemblyBegin.html) と [VecAssemblyEnd( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecAssemblyEnd.html) を行ってください。

代入結果は[VecView( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecView.html)で見ることができます。

```
---- b in petsc -------
Vec Object: 1 MPI processes
  type: seq
1.
0.
0.
0.
0.
0.
0.
0.
0.
1.
```
ちゃんと代入できていますね。

[追記]
すでに、データの入った配列が用意されている場合(上記の場合に相当)にはを使うそうです。

参考 : [Petsc for ISPH](https://lists.mcs.anl.gov/pipermail/petsc-users/2016-November/030984.html)
## `Mat`の作成
マトリックス A の作成パートは以下の部分になります。

```Matrix_part.c
  ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr);
  ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,n,n);CHKERRQ(ierr);
  ierr = MatSetFromOptions(A);CHKERRQ(ierr);
  ierr = MatSetUp(A);CHKERRQ(ierr);

  // Assemble matrix [a_ii = 2.0, a_i(j-1) = a_i(j+1) = -1.0] 
  ierr = MatSetValues(A,n,ix,n,ix,A_input,INSERT_VALUES); CHKERRQ(ierr);
  ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr);
  
  /* A is symmetric. Set symmetric flag to enable ICC/Cholesky preconditioner */
  ierr = MatSetOption(A,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
  
  /*  These two funtion is needed if assemblying matirix is finished. */
  ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
  ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);

  printf("----- A in petsc -------");
  ierr = MatView(A,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
```

実際に`Mat A`に`double A_input[n*n]`の値を代入するのは、[MatSetValues(Mat mat,PetscInt m,const PetscInt idxm[],PetscInt n,const PetscInt idxn[],const PetscScalar v[],InsertMode addv)](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatSetValues.html)になります。

おそらく、sequential matrix ([MATSEQAIJ](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MATSEQAIJ.html)や[MATSEQBAIJ](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MATSEQBAIJ.html)など) では、`A_input`のように1次元配列で値を保持しているため、このように1行で値を代入することができているのだと思います。(未確認なのであまり信じないでください。)

[MatSetType( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatSetType.html) では今回は`A` が　`MATSEQAIJ` であることを指定しています。( CG法を使用するため )

[MatSetOption( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatSetOption.html) では、`A` が `MAT_SYMMETRIC`（ 対称行列 ）であるということを指定しています。

`Mat`についても、値を代入次第、[MatAssemblyBegin( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatAssemblyBegin.html) と [MatAssemblyEnd( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatAssemblyEnd.html) を忘れずに行ってください。

代入結果は[MatView( )](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Mat/MatView.html) で確認することができます。

```
----- A in petsc -------
Mat Object: 1 MPI processes
  type: seqaij
row 0: (0, 2.)  (1, -1.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 1: (0, -1.)  (1, 2.)  (2, -1.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 2: (0, 0.)  (1, -1.)  (2, 2.)  (3, -1.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 3: (0, 0.)  (1, 0.)  (2, -1.)  (3, 2.)  (4, -1.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 4: (0, 0.)  (1, 0.)  (2, 0.)  (3, -1.)  (4, 2.)  (5, -1.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 5: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, -1.)  (5, 2.)  (6, -1.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 6: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, -1.)  (6, 2.)  (7, -1.)  (8, 0.)  (9, 0.) 
row 7: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, -1.)  (7, 2.)  (8, -1.)  (9, 0.) 
row 8: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, -1.)  (8, 2.)  (9, -1.) 
row 9: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, -1.)  (9, 2.) 
```
正しく代入できていますね。
元の`ex1.c`で`MatView( )`を行うと、以下の通りになります。

```
----- A in petsc -------
Mat Object: 1 MPI processes
  type: seqaij
row 0: (0, 2.)  (1, -1.) 
row 1: (0, -1.)  (1, 2.)  (2, -1.) 
row 2: (1, -1.)  (2, 2.)  (3, -1.) 
row 3: (2, -1.)  (3, 2.)  (4, -1.) 
row 4: (3, -1.)  (4, 2.)  (5, -1.) 
row 5: (4, -1.)  (5, 2.)  (6, -1.) 
row 6: (5, -1.)  (6, 2.)  (7, -1.) 
row 7: (6, -1.)  (7, 2.)  (8, -1.) 
row 8: (7, -1.)  (8, 2.)  (9, -1.) 
row 9: (8, -1.)  (9, 2.) 
```
お気づきの通り、`ex1.c`では0以外の値のみを代入したので、0じゃない値のみを保持しています。(こちらが理想)
しかし、今回のコードでは、0もそうでない値も直接全て代入したため 10×10＝100 個の値を保持しています。
ここから分かることは、0の値を`Mat`に代入した場合、その0の値はそのままデータとして保持されるということです。
つまり、PETScでの疎行列の形式ではないということになります。

この疎行列の扱い方については別記事で解説します。

## ソルバー`KSP`の設定

ソルバーの設定パートは以下の部分です。

```ksp_part.c
 ierr = KSPCreate(PETSC_COMM_WORLD,&ksp);CHKERRQ(ierr);
  /*
     Set operators. Here the matrix that defines the linear system
     also serves as the matrix that defines the preconditioner.
  */
  ierr = KSPSetOperators(ksp,A,A);CHKERRQ(ierr); //set A is the matrix to solve 
  
/* Set linear solver defaults for this problem (optional). */
  ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
  ierr = PCSetType(pc,PCICC);CHKERRQ(ierr);
  ierr = KSPSetTolerances(ksp,1.e-5,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); //誤差の設定
  ierr = KSPSetType(ksp,KSPCG); CHKERRQ(ierr);

  /* Set runtime options */
 ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);

```

[PCSetType(PC pc,PCType type)](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/PC/PCSetType.html) で前処理方法の指定、
[KSPSetType(KSP ksp, KSPType type)](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/KSP/KSPSetType.html)で解法の指定をします。

## 解ベクトル( x )の受け取り
以下の部分で`x_input[]`に解である`Vec x`の値を渡します。

```x.c
/* get the x vector  (x --> x_input) */
  ierr = VecGetValues(x,n,ix,x_input);
```
[ VecGetValues(Vec x,PetscInt ni,const PetscInt ix[],PetscScalar y[])](https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecGetValues.html)で`x`の値を`x_input`に渡します。
使い方は、`VecSetValues( )`と同様です。

## 計算結果の確認
実行ログは以下の通りです。

```terminal
$ make 
$ ./a.out
---------x before using petsc-------------
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
--------- b -------------
1.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
0.000000 
1.000000 

---------- A --------------
2.000000 -1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 
-1.000000 2.000000 -1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 
0.000000 -1.000000 2.000000 -1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 
0.000000 0.000000 -1.000000 2.000000 -1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 
0.000000 0.000000 0.000000 -1.000000 2.000000 -1.000000 0.000000 0.000000 0.000000 0.000000 
0.000000 0.000000 0.000000 0.000000 -1.000000 2.000000 -1.000000 0.000000 0.000000 0.000000 
0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 2.000000 -1.000000 0.000000 0.000000 
0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 2.000000 -1.000000 0.000000 
0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 2.000000 -1.000000 
0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -1.000000 2.000000 
---- b in petsc -------
Vec Object: 1 MPI processes
  type: seq
1.
0.
0.
0.
0.
0.
0.
0.
0.
1.
----- A in petsc -------
Mat Object: 1 MPI processes
  type: seqaij
row 0: (0, 2.)  (1, -1.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 1: (0, -1.)  (1, 2.)  (2, -1.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 2: (0, 0.)  (1, -1.)  (2, 2.)  (3, -1.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 3: (0, 0.)  (1, 0.)  (2, -1.)  (3, 2.)  (4, -1.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 4: (0, 0.)  (1, 0.)  (2, 0.)  (3, -1.)  (4, 2.)  (5, -1.)  (6, 0.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 5: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, -1.)  (5, 2.)  (6, -1.)  (7, 0.)  (8, 0.)  (9, 0.) 
row 6: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, -1.)  (6, 2.)  (7, -1.)  (8, 0.)  (9, 0.) 
row 7: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, -1.)  (7, 2.)  (8, -1.)  (9, 0.) 
row 8: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, -1.)  (8, 2.)  (9, -1.) 
row 9: (0, 0.)  (1, 0.)  (2, 0.)  (3, 0.)  (4, 0.)  (5, 0.)  (6, 0.)  (7, 0.)  (8, -1.)  (9, 2.) 
KSP Object: 1 MPI processes
  type: cg
  maximum iterations=10000, initial guess is zero
  tolerances:  relative=1e-05, absolute=1e-50, divergence=10000.
  left preconditioning
  using PRECONDITIONED norm type for convergence test
PC Object: 1 MPI processes
  type: icc
    out-of-place factorization
    0 levels of fill
    tolerance for zero pivot 2.22045e-14
    using Manteuffel shift [POSITIVE_DEFINITE]
    matrix ordering: natural
    factor fill ratio given 1., needed 1.
      Factored matrix follows:
        Mat Object: 1 MPI processes
          type: seqsbaij
          rows=10, cols=10
          package used to perform factorization: petsc
          total: nonzeros=55, allocated nonzeros=55
          total number of mallocs used during MatSetValues calls=0
              block size is 1
  linear system matrix = precond matrix:
  Mat Object: 1 MPI processes
    type: seqaij
    rows=10, cols=10
    total: nonzeros=100, allocated nonzeros=200
    total number of mallocs used during MatSetValues calls=10
      using I-node routines: found 2 nodes, limit used is 5
View matrix and vector 
Vec Object: Solution 1 MPI processes
  type: seq
1.
1.
1.
1.
1.
1.
1.
1.
1.
1.
Norm of error 2.22045e-16, Iterations 1
-----------x after using petsc------------
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
1.000000 
```
とりあえず、うまくいきました！　万歳！！

## さらに改善するには、、、

- 疎行列 `Mat A` を圧縮する  
つまり、0以外の値だけを`Mat A`に代入する必要があります。
こちらについては、[公式マニュアル](https://www.mcs.anl.gov/petsc/petsc-current/docs/manual.pdf)の3.1.1章の手順にしたがう必要があります。  
こちらについては[次の記事](https://qiita.com/K-eno/private/f71e47f2ab2f0b8be76d)で解説しようと思います。  
また、[こちらの記事](https://qiita.com/KQTS/items/e5500ba6e2681456e268#3-%E5%9B%9B%E5%89%87%E6%BC%94%E7%AE%97%E3%81%AA%E3%81%A9)に疎行列やその扱いについてわかりやすく書いてあります。
- `PCType`や`KSPType`の変更  
今回は前処理についてはICC( 不完全コレスキー分解 )、逆行列を求めるにはCG法( 共役勾配法 )を使用しました。このICCG法は A が正定値対称行列の時のみに使用することができる解法です。このように、Aの形式によって、効果的な解法は異なります。数値計算についての理解を深めるとより良い解法が見つかると思います。(これは戒めでもある。)

ただ、いずれにしろ配列を経由してから値を代入するのではなく、直接`Mat`や`Vec`に値を代入する方法が推奨されているようです。