function gauss_seidel_poisson_1d ( k )

%*****************************************************************************80
%
%% GAUSS_SEIDEL_POISSON_1D uses Gauss-Seidel iteration for 1D Poisson equation.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 November 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Commandline input, integer K, the grid index.
%    K specifies the number of nodes, by the formula NK = 2^K + 1.
%    K must be at least 0.
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'GAUSS_SEIDEL_POISSON_1D:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Use Gauss-Seidel iteration for the 1D Poisson equation.\n' );

  if ( nargin < 1 )
    k = input ( '  Enter K >= 0, the grid index, so that NK = 2^K + 1:  ' );
  elseif ( ischar ( k ) )
    k = str2num ( k );
  end
%
%  Set boundaries.
%
  a = 0.0;
  b = 1.0;
%
%  Set boundary conditions.
%
  ua = 0.0;
  ub = 0.0;
%
%  Get NK.
%
  nk = 2^k + 1;
%
%  Set XK.
%
  xk = ( linspace ( a, b, nk ) )';
%
%  Get HK.
%
  hk = ( b - a ) / ( nk - 1 );
%
%  Set FK.
%
  fk = force ( xk );
  fk(1) = ua;
  fk(nk) = ub;
%
%  Set the -1/2/-1 entries of Ak.
%
%  In order that the operator Ak approximate the Poisson operator,
%  and in order that we can compare linear systems for successive grids,
%  we should NOT multiply through by hk^2.
%
  Uk = sparse ( 2:nk-1, 3:nk,   -1.0, nk, nk ) / hk^2;
  Dk = sparse ( 2:nk-1, 2:nk-1,  2.0, nk, nk ) / hk^2;
  Dk(1,1) = 1.0;
  Dk(nk,nk) = 1.0;
  Lk = sparse ( 2:nk-1, 1:nk-2, -1.0, nk, nk ) / hk^2;
  Ak = Uk + Dk + Lk;
%
%  Just because we can, ask MATLAB to get the exact solution of the linear system
%  directly.
%
  udk = Ak \ fk;
%
%  Sample the solution to the continuous problem.
%
  uek = exact ( xk );
%
%  Use Gauss-Seidel iteration to solve the linear system to the given tolerance.
%
  ujk = zeros ( nk, 1 );
  it_max = 10000000;
  res_max = 0.000001;

  [ ujk, it_num, res_norm ] = gauss_seidel ( nk, Lk, Dk, Uk, fk, ujk, it_max, ...
    res_max );
%
%  Examine errors:
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Using grid index K = %d\n', k );
  fprintf ( 1, '  System size NK was %d\n', nk );
  fprintf ( 1, '  Tolerance for linear residual %g\n', res_max );
  fprintf ( 1, '  RMS of linear residual %g\n', res_norm );
  fprintf ( 1, '  Number of GS iterations taken was %d\n', it_num );
  fprintf ( 1, '  RMS GS error in solution of linear system = %g\n', ...
    norm ( udk - ujk ) / sqrt ( nk ) );
  fprintf ( 1, '  RMS discretization error in Poisson solution = %g\n', ...
    norm ( uek - ujk ) / sqrt ( nk ) );

  fprintf ( 1, '\n' );
  fprintf ( 1, '     I        X        U_Exact    U_Direct    U_GS\n' );
  fprintf ( 1, '\n' );
  for i = 1 : nk
    fprintf ( 1, '  %4d  %10.4f  %10.4g  %10.4g  %10.4g\n', ...
      i, xk(i), uek(i), udk(i), ujk(i) );
  end
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'GAUSS_SEIDEL_POISSON_1D:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end
function uex = exact ( x )

%*****************************************************************************80
%
%% UEX evaluates the solution of the continuous problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X(*), the evaluation points.
%
%    Output, real UEX(*), the solution of the continuous problem 
%    at the evaluation points.
%
  uex = x .* ( x - 1 ) .* exp ( x );

  return
end
function f = force ( x )

%*****************************************************************************80
%
%% FORCE evaluates the forcing term.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X(*), the evaluation points.
%
%    Output, real F(*), the forcing term at the evaluation points.
%
  f = - x .* ( x + 3 ) .* exp ( x );

  return
end
function [ u, it_num, res_norm ] = gauss_seidel ( n, Lk, Dk, Uk, f, u, ...
  it_max, res_max )

%*****************************************************************************80
%
%% GAUSS_SEIDEL carries out the Gauss-Seidel iteration.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 November 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real sparse Lk(*,*), Dk(*,*), Uk(*,*), the strict lower triangle,
%    the diagonal, and the strict upper triangle of A.
%
%    Input, real F(N), the right hand side.
%
%    Input, real U(N), the estimated solution.
%
%    Input, integer IT_MAX, the maximum number of iterations.
%
%    Input, real RES_MAX, a convergence tolerance on the residual.
%
%    Output, real U(N), the improved estimate of the solution.
%
%    Output, integer IT_NUM, the number of iterations taken.
%
%    Output, real RES_NORM, the RMS norm of the residual.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '    Step    Residual      Change\n' );
  fprintf ( 1, '\n' );

  it_num = it_max;

  for it = 1 : it_max

    u_old = u;
    u = ( Lk + Dk ) \ ( f - Uk * u_old );
    r = ( Lk + Dk + Uk ) * u - f;
    res_norm = norm ( r ) / sqrt ( n );

    fprintf ( 1, '  %6d  %10.4g  %10.4g\n', ...
      it, res_norm, norm ( u - u_old ) / sqrt ( n ) );

    if ( res_norm <= res_max )
      it_num = it;
      break;
    end

  end

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end
