diff main/splines/trisolve.cc @ 0:6b33357c7561 octave-forge

Initial revision
author pkienzle
date Wed, 10 Oct 2001 19:54:49 +0000
parents
children 23ab5a2ed477
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/splines/trisolve.cc	Wed Oct 10 19:54:49 2001 +0000
@@ -0,0 +1,255 @@
+/* Copyright (C) 2001  Kai Habel
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+## 2001-02-19 Paul Kienzle
+##    * common interface trisolve() for +/- cyclic, +/- symmetric
+*/
+
+#include <octave/oct.h>
+#include <octave/f77-fcn.h>
+
+// LAPACK 3.0 functions not in libcruft
+extern "C" {
+  extern int F77_FCN (dgtsv, DGTSV)
+    (const int &n, const int &nrhs, double *l, 
+	  double *d, double *u, double *b, const int &ldb, int *info);
+
+  extern int F77_FCN (dptsv, DPTSV)
+    (const int &n, const int &nrhs, double *d, 
+	  double *e, double *b, const int &ldb, int *info);
+}
+
+DEFUN_DLD(trisolve, args, ,"\
+x = trisolve(d,e,b)\n\n\
+Solves the symmetric positive definite tridiagonal system:\n\
+  / d1 e1  0  . . .  0    0 \\     / b11 b12 . . . b1k \\\n\
+  | e1 d2 e2  . . .  0    0 |     | b21 b22 . . . b2k |\n\
+  |  0 e2 d3  . . .  0    0 | x = | b31 b22 . . . b3k |\n\
+  |           . . .         |     |         . . .     |\n\
+  \\  0  0  0  . . . en-1 dn /     \\ bn1 bn2 . . . bnk /\n\n\
+If the system is not positive definite, then use the following form.\n\n
+x = trisolve(l,d,u,b)\n\n\
+Solves the tridiagonal system:\n\
+  / d1 u1  0  . . .  0    0 \\     / b11 b12 . . . b1k \\\n\
+  | l1 d2 u2  . . .  0    0 |     | b21 b22 . . . b2k |\n\
+  |  0 l2 d3  . . .  0    0 | x = | b31 b22 . . . b3k |\n\
+  |           . . .         |     |         . . .     |\n\
+  \\  0  0  0  . . . ln-1 dn /     \\ bn1 bn2 . . . bnk /\n\n\
+x = trisolve(d,e,b,cl,cu)\n\n\
+Solves the cyclic system with symmetric positive definite tridiagonal:\n\
+  / d1 e1  0  . . .  0   cu \\     / b11 b12 . . . b1k \\\n\
+  | e1 d2 e2  . . .  0    0 |     | b21 b22 . . . b2k |\n\
+  |  0 e2 d3  . . .  0    0 | x = | b31 b22 . . . b3k |\n\
+  |           . . .         |     |         . . .     |\n\
+  \\ cl  0  0  . . . en-1 dn /     \\ bn1 bn2 . . . bnk /\n\n\
+If the system is not positive definite, then use the following form.\n\n
+x = trisolve(l,d,u,b,cl,cu)\n\n\
+Solves the cyclic tridiagonal system:\n\
+  / d1 u1  0  . . .  0   cu \\     / b11 b12 . . . b1k \\\n\
+  | l1 d2 u2  . . .  0    0 |     | b21 b22 . . . b2k |\n\
+  |  0 l2 d3  . . .  0    0 | x = | b31 b22 . . . b3k |\n\
+  |           . . .         |     |         . . .     |\n\
+  \\ cl  0  0  . . . ln-1 dn /     \\ bn1 bn2 . . . bnk /\n\n\
+Uses LAPACK routines DGTSVX or DPTSVX to solve the tridiagonal\n\
+system.  Uses the Sherman-Morrison formula to extend the solution\n\
+to the cyclic system. See Numerical Recipes, pp 73-75\n\
+<http://lib-www.lanl.gov/numerical/bookc/c2-7.pdf>\n\
+")
+{
+  octave_value_list retval;
+  const int nargin = args.length();
+
+  if (nargin == 3)
+    {
+      ColumnVector d(args(0).vector_value());
+      ColumnVector e(args(1).vector_value());
+      Matrix b(args(2).matrix_value());
+      if ( error_state ) return retval;
+
+      int n = d.length();
+      int nrhs = b.columns();
+      if (e.length() != n-1)
+	{
+	  error ("trisolve: e must be one shorter than d");
+	  return retval;
+	}
+      if (b.rows() != n)
+	{
+	  error ("trisolve: b must have same number of rows as d");
+	  return retval;
+	}
+
+      int info;
+      F77_FCN (dptsv, DPTSV) (n, nrhs, d.fortran_vec(), e.fortran_vec(), 
+			      b.fortran_vec(), n, &info);
+       
+      if (info > 0)
+	error ("trisolve: not positive definite---use trisolve(e,d,e,b).");
+      else if (info < 0) // will never happen
+	error ("trisolve: lapack dptsv called incorrectly.");
+      else
+	retval(0) = b;
+
+    }
+  else if (nargin == 5)
+    {
+      ColumnVector d(args(0).vector_value());
+      ColumnVector e(args(1).vector_value());
+      Matrix b(args(2).matrix_value());
+      double cl = args(3).double_value();
+      double cu = args(4).double_value();
+      if ( error_state ) return retval;
+
+      int n = d.length();
+      int nrhs = b.columns();
+      if (e.length() != n-1)
+	{
+	  error ("trisolve: e must be one shorter than d");
+	  return retval;
+	}
+      if (b.rows() != n)
+	{
+	  error ("trisolve: b must have same number of rows as d");
+	  return retval;
+	}
+
+      double gamma = -d(0);
+      d(0) -= gamma;
+      d(n-1) -= cl * cu / gamma;
+      Matrix z(n, nrhs+1, 0);
+      z(0,0) = gamma;
+      z(n-1,0) = cl;
+      z.insert(b, 0, 1);
+
+      int info;
+      F77_FCN (dptsv, DPTSV) (n, nrhs+1, d.fortran_vec(), e.fortran_vec(), 
+			      z.fortran_vec(), n, &info);
+
+      if (info == 0)
+	{
+	  for (int i = 1; i <= nrhs; i++)
+	    {
+	      const double fact =
+		(z(0,i) + cu*z(n-1,i)/gamma)
+		/ (1.0 + z(0,0) + cu*z(n-1,0)/gamma);
+	      for (int j = 0; j < n; j++) b(j,i-1) = z(j,i) - fact * z(j,0);
+	    }
+	}
+      
+      if (info > 0)
+	error ("trisolve: not positive definite---use trisolve(e,d,e,b,cl,cu).");
+      else if (info < 0) // will never happen
+	error ("trisolve: lapack dptsv called incorrectly.");
+      else
+	retval(0) = b;
+
+    }
+  else if (nargin == 4)
+    {
+      ColumnVector l(args(0).vector_value());
+      ColumnVector d(args(1).vector_value());
+      ColumnVector u(args(2).vector_value());
+      Matrix b(args(3).matrix_value());
+      if ( error_state ) return retval;
+
+      int n = d.length();
+      int nrhs = b.columns();
+      if (u.length() != n-1 || l.length() != n-1)
+	{
+	  error ("trisolve: l,u must be one shorter than d");
+	  return retval;
+	}
+      if (b.rows() != n)
+	{
+	  error ("trisolve: b must have same number of rows as d");
+	  return retval;
+	}
+
+      int info;
+      F77_FCN (dgtsv, DGTSV) (n, nrhs, l.fortran_vec(), d.fortran_vec(), 
+			      u.fortran_vec(), b.fortran_vec(), n, &info);
+       
+      if (info > 0)
+	error ("trisolve: singular system.");
+      else if (info < 0) // will never happen
+	error ("trisolve: lapack dptsv called incorrectly.");
+      else
+	retval(0) = b;
+
+    }
+  else if (nargin == 6)
+    {
+      ColumnVector l(args(0).vector_value());
+      ColumnVector d(args(1).vector_value());
+      ColumnVector u(args(2).vector_value());
+      Matrix b(args(3).matrix_value());
+      double cl = args(4).double_value();
+      double cu = args(5).double_value();
+      if ( error_state ) return retval;
+
+      int n = d.length();
+      int nrhs = b.columns();
+      if (u.length() != n-1 || l.length() != n-1)
+	{
+	  error ("trisolve: l,u must be one shorter than d");
+	  return retval;
+	}
+      if (b.rows() != n)
+	{
+	  error ("trisolve: b must have same number of rows as d");
+	  return retval;
+	}
+
+      double gamma = -d(0);
+      d(0) -= gamma;
+      d(n-1) -= cl * cu / gamma;
+      Matrix z(n, nrhs+1, 0);
+      z(0,0) = gamma;
+      z(n-1,0) = cl;
+      z.insert(b, 0, 1);
+
+      int info;
+      F77_FCN (dgtsv, DGTSV) (n, nrhs+1, l.fortran_vec(), d.fortran_vec(), 
+			      u.fortran_vec(), z.fortran_vec(), n, &info);
+
+      if (info == 0)
+	{
+	  for (int i = 1; i <= nrhs; i++)
+	    {
+	      const double fact =
+		(z(0,i) + cu*z(n-1,i)/gamma)
+		/ (1.0 + z(0,0) + cu*z(n-1,0)/gamma);
+	      for (int j = 0; j < n; j++) b(j,i-1) = z(j,i) - fact * z(j,0);
+	    }
+	}
+      
+      if (info > 0)
+	error ("trisolve: singular system.");
+      else if (info < 0) // will never happen
+	error ("trisolve: lapack dptsv called incorrectly.");
+      else
+	retval(0) = b;
+
+    }
+  else
+    {
+      print_usage("trisolve");
+      return retval;
+    }
+
+  return retval;
+
+}