GNU Scientific Library – Reference Manual: Sparse Linear Algebra Examples

Next: Sparse Linear Algebra References and Further Reading, Previous: Sparse Iterative Solvers, Up: Sparse Linear Algebra [Index]

### 43.3 Examples

This example program demonstrates the sparse linear algebra routines on the solution of a simple 1D Poisson equation on [0,1]:

    u''(x) = f(x) = -\pi^2 \sin(\pi x)

with boundary conditions u(0) = u(1) = 0. The analytic solution of this simple problem is u(x) = \sin{\pi x}. We will solve this problem by finite differencing the left hand side to give

    1/h^2 ( u_(i+1) - 2 u_i + u_(i-1) ) = f_i

Defining a grid of N points, h = 1/(N-1). In the finite difference equation above, u_0 = u_{N-1} = 0 are known from the boundary conditions, so we will only put the equations for i = 1, ..., N-2 into the matrix system. The resulting (N-2) \times (N-2) matrix equation is An example program which constructs and solves this system is given below. The system is solved using the iterative GMRES solver. Here is the output of the program:

    iter 0 residual = 4.297275996844e-11
    Converged

showing that the method converged in a single iteration. The calculated solution is shown in the following plot.

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    #include <gsl/gsl_math.h>
    #include <gsl/gsl_vector.h>
    #include <gsl/gsl_spmatrix.h>
    #include <gsl/gsl_splinalg.h>

    int
    main()
    {
      const size_t N = 100;                       /* number of grid points */
      const size_t n = N - 2;                     /* subtract 2 to exclude boundaries */
      const double h = 1.0 / (N - 1.0);           /* grid spacing */
      gsl_spmatrix *A = gsl_spmatrix_alloc(n ,n); /* triplet format */
      gsl_spmatrix *C;                            /* compressed format */
      gsl_vector *f = gsl_vector_alloc(n);        /* right hand side vector */
      gsl_vector *u = gsl_vector_alloc(n);        /* solution vector */
      size_t i;

      /* construct the sparse matrix for the finite difference equation */

      /* construct first row */
      gsl_spmatrix_set(A, 0, 0, -2.0);
      gsl_spmatrix_set(A, 0, 1, 1.0);

      /* construct rows [1:n-2] */
      for (i = 1; i < n - 1; ++i)
        {
          gsl_spmatrix_set(A, i, i + 1, 1.0);
          gsl_spmatrix_set(A, i, i, -2.0);
          gsl_spmatrix_set(A, i, i - 1, 1.0);
        }

      /* construct last row */
      gsl_spmatrix_set(A, n - 1, n - 1, -2.0);
      gsl_spmatrix_set(A, n - 1, n - 2, 1.0);

      /* scale by h^2 */
      gsl_spmatrix_scale(A, 1.0 / (h * h));

      /* construct right hand side vector */
      for (i = 0; i < n; ++i)
        {
          double xi = (i + 1) * h;
          double fi = -M_PI * M_PI * sin(M_PI * xi);
          gsl_vector_set(f, i, fi);
        }

      /* convert to compressed column format */
      C = gsl_spmatrix_ccs(A);

      /* now solve the system with the GMRES iterative solver */
      {
        const double tol = 1.0e-6;  /* solution relative tolerance */
        const size_t max_iter = 10; /* maximum iterations */
        const gsl_splinalg_itersolve_type *T = gsl_splinalg_itersolve_gmres;
        gsl_splinalg_itersolve *work =
          gsl_splinalg_itersolve_alloc(T, n, 0);
        size_t iter = 0;
        double residual;
        int status;

        /* initial guess u = 0 */
        gsl_vector_set_zero(u);

        /* solve the system A u = f */
        do
          {
            status = gsl_splinalg_itersolve_iterate(C, f, tol, u, work);

            /* print out residual norm ||A*u - f|| */
            residual = gsl_splinalg_itersolve_normr(work);
            fprintf(stderr, "iter %zu residual = %.12e\n", iter, residual);

            if (status == GSL_SUCCESS)
              fprintf(stderr, "Converged\n");
          }
        while (status == GSL_CONTINUE && ++iter < max_iter);

        /* output solution */
        for (i = 0; i < n; ++i)
          {
            double xi = (i + 1) * h;
            double u_exact = sin(M_PI * xi);
            double u_gsl = gsl_vector_get(u, i);

            printf("%f %.12e %.12e\n", xi, u_gsl, u_exact);
          }

        gsl_splinalg_itersolve_free(work);
      }

      gsl_spmatrix_free(A);
      gsl_spmatrix_free(C);
      gsl_vector_free(f);
      gsl_vector_free(u);

      return 0;
    } /* main() */

Next: Sparse Linear Algebra References and Further Reading, Previous: Sparse Iterative Solvers, Up: Sparse Linear Algebra [Index]