octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: eigs and ARPACK


From: David Bateman
Subject: Re: eigs and ARPACK
Date: Fri, 05 Dec 2008 00:09:42 +0100
User-agent: Mozilla-Thunderbird 2.0.0.17 (X11/20081018)

John W. Eaton wrote:
On  3-Dec-2008, Søren Hauberg wrote:

|   It was just pointed out on the Octave-Forge list that ARPACK seems to
| have been released under a standard BSD license [1]. Doesn't this mean
| that we can move the code from the 'arpack' package into core Octave,
| which would give us the 'eigs' and 'svds' functions?
| | Søren | | [1] http://www.caam.rice.edu/software/ARPACK/RiceBSD.txt

Yes, this is great news.  Would someone like to prepare a patch?

jwe



Well attached is an untested port of the octave-forge code. I don't know if I'll have the time to test this code before a few days and so I'm sending it even if it is untested. It also doesn't support single precision matrices and probably should..

Regards
David


--
David Bateman                                address@hidden
35 rue Gambetta                              +33 1 46 04 02 18 (Home)
92100 Boulogne-Billancourt FRANCE            +33 6 72 01 06 33 (Mob)
# HG changeset patch
# User David Bateman <address@hidden>
# Date 1228431849 -3600
# Node ID b066459427388ea53edb1531e8e4bde36fa2cb7e
# Parent  b5f0f1c09661795d26a76e54ec77ce1709721ddf
Add eigs and svds functions

diff --git a/Makeconf.in b/Makeconf.in
--- a/Makeconf.in
+++ b/Makeconf.in
@@ -237,6 +237,7 @@
 CHOLMOD_LIBS = @CHOLMOD_LIBS@
 CXSPARSE_LIBS = @CXSPARSE_LIBS@
 OPENGL_LIBS = @OPENGL_LIBS@
+ARPACK_LIBS = @ARPACK_LIBS@
 LIBS = @LIBS@
 
 USE_64_BIT_IDX_T = @USE_64_BIT_IDX_T@
diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
@@ -1042,6 +1042,27 @@
 fi
 if test -n "$warn_cxsparse"; then
   AC_MSG_WARN($warn_cxsparse)
+fi
+
+ARPACK_LIBS=
+AC_SUBST(ARPACK_LIBS)
+
+AC_ARG_WITH(arpack,
+  [AS_HELP_STRING([--without-arpack],
+     [don't use ARPACK, disable some sparse functionality])],
+  with_arpack=$withval, with_arpack=yes)
+
+warn_arpack="arpack not found. This will result in a lack of the eigs 
function."
+if test "$with_arpack" = yes; then
+  with_arpack=no
+  AC_CHECK_LIB(arpack, F77_FUNC(dseupd,DSEUPD), [ARPACK_LIBS="-larpack"; 
with_arpack=yes])
+  if test "$with_arpack" = yes; then
+    AC_DEFINE(HAVE_ARPACK, 1, [Define if the ARPACK library is used.])
+    warn_cxsparse=
+  fi
+fi
+if test -n "$warn_arpack"; then
+  AC_MSG_WARN($warn_arpack)
 fi
 
 ### Handle shared library options.
@@ -2038,6 +2059,7 @@
   CCOLAMD libraries:    $CCOLAMD_LIBS
   CHOLMOD libraries:    $CHOLMOD_LIBS
   CXSPARSE libraries:   $CXSPARSE_LIBS
+  ARPACK libraries:     $ARPACK_LIBS
   HDF5 libraries:       $HDF5_LIBS
   CURL libraries:       $CURL_LIBS
   REGEX libraries:      $REGEX_LIBS
@@ -2146,6 +2168,11 @@
 
 if test -n "$warn_cxsparse"; then
   AC_MSG_WARN($warn_cxsparse)
+  warn_msg_printed=true
+fi
+
+if test -n "$warn_arpack"; then
+  AC_MSG_WARN($warn_arpack)
   warn_msg_printed=true
 fi
 
diff --git a/doc/interpreter/sparse.txi b/doc/interpreter/sparse.txi
--- a/doc/interpreter/sparse.txi
+++ b/doc/interpreter/sparse.txi
@@ -473,9 +473,8 @@
   @dfn{dmperm}, @dfn{symamd}, @dfn{randperm}, @dfn{symrcm}
 
 @item Linear algebra:
-  @dfn{matrix_type}, @dfn{normest}, @dfn{condest}, @dfn{sprank}
-  @dfn{spaugment}
address@hidden @dfn{eigs}, @dfn{svds} but these are in octave-forge for now
+  @dfn{condest}, @dfn{eigs}, @dfn{matrix_type}, @dfn{normest}, @dfn{sprank},
+  @dfn{spaugment}, @dfn{svds}
 
 @item Iterative techniques:
   @dfn{luinc}, @dfn{pcg}, @dfn{pcr}
@@ -831,6 +830,15 @@
 function to find a least squares solution to a linear equation.
 
 @DOCSTRING(spaugment)
+
+Finally, the function @code{eigs} can be used to calculate a limited
+number of eigenvalues and eigenvectors based on a selection criteria
+and likewise for @code{svds} which calculates a limited number of
+singular values and vectors.
+
address@hidden(eigs)
+
address@hidden(svds)
 
 @node Iterative Techniques, Real Life Example, Sparse Linear Algebra, Sparse 
Matrices
 @section Iterative Techniques applied to sparse matrices
diff --git a/liboctave/Makefile.in b/liboctave/Makefile.in
--- a/liboctave/Makefile.in
+++ b/liboctave/Makefile.in
@@ -105,8 +105,8 @@
 
 TEMPLATE_SRC := Array.cc ArrayN.cc DiagArray2.cc \
        MArray.cc MArray2.cc MArrayN.cc MDiagArray2.cc \
-       base-lu.cc oct-sort.cc sparse-base-lu.cc sparse-base-chol.cc \
-       sparse-dmsolve.cc
+       base-lu.cc eigs-base.cc oct-sort.cc sparse-base-lu.cc \
+       sparse-base-chol.cc sparse-dmsolve.cc
 
 TI_SRC := Array-C.cc Array-b.cc Array-ch.cc Array-i.cc Array-d.cc \
        Array-f.cc Array-fC.cc Array-s.cc Array-str.cc \
diff --git a/liboctave/eigs-base.cc b/liboctave/eigs-base.cc
new file mode 100755
--- /dev/null
+++ b/liboctave/eigs-base.cc
@@ -0,0 +1,3762 @@
+/*
+
+Copyright (C) 2005 David Bateman
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cfloat>
+#include <cmath>
+#include <vector>
+#include <iostream>
+
+#include "f77-fcn.h"
+#include "quit.h"
+#include "SparsedbleLU.h"
+#include "SparseCmplxLU.h"
+#include "dSparse.h"
+#include "CSparse.h"
+#include "MatrixType.h"
+#include "SparsedbleCHOL.h"
+#include "SparseCmplxCHOL.h"
+#include "oct-rand.h"
+#include "dbleCHOL.h"
+#include "CmplxCHOL.h"
+#include "dbleLU.h"
+#include "CmplxLU.h"
+
+#ifdef HAVE_ARPACK
+typedef ColumnVector (*EigsFunc) (const ColumnVector &x, int &eigs_error);
+typedef ComplexColumnVector (*EigsComplexFunc) 
+  (const ComplexColumnVector &x, int &eigs_error);
+
+// Arpack and blas fortran functions we call.
+extern "C"
+{
+  F77_RET_T
+  F77_FUNC (dsaupd, DSAUPD) (octave_idx_type&, F77_CONST_CHAR_ARG_DECL,
+                            const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, 
+                            const octave_idx_type&, const double&,
+                            double*, const octave_idx_type&, double*,
+                            const octave_idx_type&, octave_idx_type*,
+                            octave_idx_type*, double*, double*, 
+                            const octave_idx_type&, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dseupd, DSEUPD) (const int&, F77_CONST_CHAR_ARG_DECL,
+                            int*, double*, double*,
+                            const octave_idx_type&, const double&,
+                            F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, 
+                            F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, 
+                            const double&, double*, const octave_idx_type&, 
+                            double*, const octave_idx_type&, octave_idx_type*,
+                            octave_idx_type*, double*, double*, 
+                            const octave_idx_type&, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL
+                            F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dnaupd, DNAUPD) (octave_idx_type&, F77_CONST_CHAR_ARG_DECL,
+                            const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, 
+                            octave_idx_type&, const double&,
+                            double*, const octave_idx_type&, double*,
+                            const octave_idx_type&, octave_idx_type*,
+                            octave_idx_type*, double*, double*, 
+                            const octave_idx_type&, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dneupd, DNEUPD) (const int&, F77_CONST_CHAR_ARG_DECL,
+                            int*, double*, double*,
+                            double*, const octave_idx_type&, const double&,
+                            const double&, double*, F77_CONST_CHAR_ARG_DECL, 
+                            const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, 
+                            octave_idx_type&, const double&, double*, 
+                            const octave_idx_type&, double*, 
+                            const octave_idx_type&, octave_idx_type*, 
+                            octave_idx_type*, double*, double*, 
+                            const octave_idx_type&, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL
+                            F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (znaupd, ZNAUPD) (octave_idx_type&, F77_CONST_CHAR_ARG_DECL,
+                            const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, 
+                            const octave_idx_type&, const double&,
+                            Complex*, const octave_idx_type&, Complex*,
+                            const octave_idx_type&, octave_idx_type*,
+                            octave_idx_type*, Complex*, Complex*, 
+                            const octave_idx_type&, double *, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (zneupd, ZNEUPD) (const int&, F77_CONST_CHAR_ARG_DECL,
+                            int*, Complex*, Complex*, 
+                            const octave_idx_type&, const Complex&,
+                            Complex*, F77_CONST_CHAR_ARG_DECL,
+                            const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, 
+                            const octave_idx_type&, const double&,
+                            Complex*, const octave_idx_type&, Complex*,
+                            const octave_idx_type&, octave_idx_type*,
+                            octave_idx_type*, Complex*, Complex*, 
+                            const octave_idx_type&, double *, octave_idx_type&
+                            F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL
+                            F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dgemv, DGEMV) (F77_CONST_CHAR_ARG_DECL,
+                          const octave_idx_type&, const octave_idx_type&, 
const double&,
+                          const double*, const octave_idx_type&, const double*,
+                          const octave_idx_type&, const double&, double*,
+                          const octave_idx_type&
+                          F77_CHAR_ARG_LEN_DECL);
+
+
+  F77_RET_T
+  F77_FUNC (zgemv, ZGEMV) (F77_CONST_CHAR_ARG_DECL,
+                           const octave_idx_type&, const octave_idx_type&, 
const Complex&,
+                           const Complex*, const octave_idx_type&, const 
Complex*,
+                           const octave_idx_type&, const Complex&, Complex*, 
const octave_idx_type&
+                           F77_CHAR_ARG_LEN_DECL);
+
+}
+
+
+#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
+static octave_idx_type
+lusolve (const SparseMatrix&, const SparseMatrix&, Matrix&);
+
+static octave_idx_type
+lusolve (const SparseComplexMatrix&, const SparseComplexMatrix&, 
+        ComplexMatrix&);
+
+static octave_idx_type
+lusolve (const Matrix&, const Matrix&, Matrix&);
+
+static octave_idx_type
+lusolve (const ComplexMatrix&, const ComplexMatrix&, ComplexMatrix&);
+
+static ComplexMatrix
+ltsolve (const SparseComplexMatrix&, const ColumnVector&, 
+               const ComplexMatrix&);
+
+static Matrix
+ltsolve (const SparseMatrix&, const ColumnVector&, const Matrix&,);
+
+static ComplexMatrix
+ltsolve (const ComplexMatrix&, const ColumnVector&, const ComplexMatrix&);
+
+static Matrix
+ltsolve (const Matrix&, const ColumnVector&, const Matrix&,);
+
+static ComplexMatrix
+utsolve (const SparseComplexMatrix&, const ColumnVector&, const 
ComplexMatrix&);
+
+static Matrix
+utsolve (const SparseMatrix&, const ColumnVector&, const Matrix&);
+
+static ComplexMatrix
+utsolve (const ComplexMatrix&, const ColumnVector&, const ComplexMatrix&);
+
+static Matrix
+utsolve (const Matrix&, const ColumnVector&, const Matrix&);
+
+#endif
+
+template <class M, class SM>
+static octave_idx_type
+lusolve (const SM& L, const SM& U, M& m)
+{
+  octave_idx_type err = 0;
+  double rcond;
+  MatrixType utyp (MatrixType::Upper);
+
+  // Sparse L is lower triangular, Dense L is permuted lower triangular!!!
+  m = L.solve (m, err, rcond, 0);
+  if (err)
+    return err;
+
+  m = U.solve (utyp, m, err, rcond, 0);
+
+  return err;
+}
+
+template <class SM, class M>
+static M
+ltsolve (const SM& L, const ColumnVector& Q, const M& m)
+{
+  octave_idx_type n = L.cols();
+  octave_idx_type b_nc = m.cols();
+  octave_idx_type err = 0;
+  double rcond;
+  MatrixType ltyp (MatrixType::Lower);
+  M tmp = L.solve (ltyp, m, err, rcond, 0);
+  M retval;
+  const double* qv = Q.fortran_vec();
+
+  if (!err)
+    {
+      retval.resize (n, b_nc);
+      for (octave_idx_type j = 0; j < b_nc; j++)
+       {
+         for (octave_idx_type i = 0; i < n; i++)
+           retval.elem(static_cast<octave_idx_type>(qv[i]), j)  = 
+             tmp.elem(i,j);
+       }
+    }
+
+  return retval;
+}
+
+template <class SM, class M>
+static M
+utsolve (const SM& U, const ColumnVector& Q, const M& m)
+{
+  octave_idx_type n = U.cols();
+  octave_idx_type b_nc = m.cols();
+  octave_idx_type err = 0;
+  double rcond;
+  MatrixType utyp (MatrixType::Upper);
+
+  M retval (n, b_nc);
+  const double* qv = Q.fortran_vec();
+  for (octave_idx_type j = 0; j < b_nc; j++)
+    {
+      for (octave_idx_type i = 0; i < n; i++)
+       retval.elem(i,j) = m.elem(static_cast<octave_idx_type>(qv[i]), j);
+    }
+  return U.solve (utyp, retval, err, rcond, 0);
+}
+
+static bool
+vector_product (const SparseMatrix& m, const double* x, double* y)
+{
+  octave_idx_type nc = m.cols ();
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    y[j] = 0.;
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
+      y[m.ridx(i)] += m.data(i) * x[j];
+
+  return true;
+}
+
+static bool
+vector_product (const Matrix& m, const double *x, double *y)
+{
+  octave_idx_type nr = m.rows ();
+  octave_idx_type nc = m.cols ();
+
+  F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 ("N", 1),
+                          nr, nc, 1.0,  m.data (), nr,
+                          x, 1, 0.0, y, 1
+                          F77_CHAR_ARG_LEN (1)));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecoverable error in dgemv");
+      return false;
+    }
+  else
+    return true;
+}
+
+static bool
+vector_product (const SparseComplexMatrix& m, const Complex* x, 
+                       Complex* y)
+{
+  octave_idx_type nc = m.cols ();
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    y[j] = 0.;
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++)
+      y[m.ridx(i)] += m.data(i) * x[j];
+
+  return true;
+}
+
+static bool
+vector_product (const ComplexMatrix& m, const Complex *x, Complex *y)
+{
+  octave_idx_type nr = m.rows ();
+  octave_idx_type nc = m.cols ();
+
+  F77_XFCN (zgemv, ZGEMV, (F77_CONST_CHAR_ARG2 ("N", 1),
+                          nr, nc, 1.0,  m.data (), nr,
+                          x, 1, 0.0, y, 1
+                          F77_CHAR_ARG_LEN (1)));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecoverable error in zgemv");
+      return false;
+    }
+  else
+    return true;
+}
+
+static bool
+make_cholb (Matrix& b, Matrix& bt, ColumnVector& permB)
+{
+  octave_idx_type info;
+  CHOL fact (b, info);
+  octave_idx_type n = b.cols();
+
+  if (info != 0)
+    return false;
+  else
+    {
+      bt = fact.chol_matrix ();
+      b =  bt.transpose();
+      permB = ColumnVector(n);
+      for (octave_idx_type i = 0; i < n; i++)
+       permB(i) = i;
+      return true;
+    }
+}
+
+static bool
+make_cholb (SparseMatrix& b, SparseMatrix& bt, ColumnVector& permB)
+{
+  octave_idx_type info;
+  SparseCHOL fact (b, info, false);
+
+  if (fact.P() != 0)
+    return false;
+  else
+    {
+      b = fact.L();
+      bt = b.transpose();
+      permB = fact.perm() - 1.0;
+      return true;
+    }
+}
+
+static bool
+make_cholb (ComplexMatrix& b, ComplexMatrix& bt, ColumnVector& permB)
+{
+  octave_idx_type info;
+  ComplexCHOL fact (b, info);
+  octave_idx_type n = b.cols();
+
+  if (info != 0)
+    return false;
+  else
+    {
+      bt = fact.chol_matrix ();
+      b =  bt.hermitian();
+      permB = ColumnVector(n);
+      for (octave_idx_type i = 0; i < n; i++)
+       permB(i) = i;
+      return true;
+    }
+}
+
+static bool
+make_cholb (SparseComplexMatrix& b, SparseComplexMatrix& bt, 
+           ColumnVector& permB)
+{
+  octave_idx_type info;
+  SparseComplexCHOL fact (b, info, false);
+
+  if (fact.P() != 0)
+    return false;
+  else
+    {
+      b = fact.L();
+      bt = b.hermitian();
+      permB = fact.perm() - 1.0;
+      return true;
+    }
+}
+
+static bool
+LuAminusSigmaB (const SparseMatrix &m, const SparseMatrix &b, 
+               bool cholB, const ColumnVector& permB, double sigma,
+               SparseMatrix &L, SparseMatrix &U, octave_idx_type *P, 
+               octave_idx_type *Q)
+{
+  bool have_b = ! b.is_empty ();
+  octave_idx_type n = m.rows();
+
+  // Caclulate LU decomposition of 'A - sigma * B'
+  SparseMatrix AminusSigmaB (m);
+
+  if (have_b)
+    {
+      if (cholB)
+       {
+         if (permB.length())
+           {
+             SparseMatrix tmp(n,n,n);
+             for (octave_idx_type i = 0; i < n; i++)
+               {
+                 tmp.xcidx(i) = i;
+                 tmp.xridx(i) = 
+                   static_cast<octave_idx_type>(permB(i));
+                 tmp.xdata(i) = 1;
+               }
+             tmp.xcidx(n) = n;
+
+             AminusSigmaB = AminusSigmaB - sigma * tmp *
+               b.transpose() * b * tmp.transpose();
+           }
+         else
+           AminusSigmaB = AminusSigmaB - sigma *
+             b.transpose() * b;
+       }
+      else
+       AminusSigmaB = AminusSigmaB - sigma * b;
+    }
+  else
+    {
+      SparseMatrix sigmat (n, n, n);
+
+         // Create sigma * speye(n,n)
+         sigmat.xcidx (0) = 0;
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             sigmat.xdata(i) = sigma;
+             sigmat.xridx(i) = i;
+             sigmat.xcidx(i+1) = i + 1;
+           }
+
+         AminusSigmaB = AminusSigmaB - sigmat;
+       }
+
+  SparseLU fact (AminusSigmaB);
+
+  L = fact.L ();
+  U = fact.U ();
+  const octave_idx_type *P2 = fact.row_perm ();
+  const octave_idx_type *Q2 = fact.col_perm ();
+
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      P[j] = P2[j];
+      Q[j] = Q2[j];
+    }
+
+  // Test condition number of LU decomposition
+  double minU = octave_NaN;
+  double maxU = octave_NaN;
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      double d = 0.;
+      if (U.xcidx(j+1) > U.xcidx(j) &&
+         U.xridx (U.xcidx(j+1)-1) == j)
+       d = std::abs (U.xdata (U.xcidx(j+1)-1));
+
+      if (xisnan (minU) || d < minU)
+       minU = d;
+
+      if (xisnan (maxU) || d > maxU)
+       maxU = d;
+    }
+
+  double rcond = (minU / maxU);
+  volatile double rcond_plus_one = rcond + 1.0;
+
+  if (rcond_plus_one == 1.0 || xisnan (rcond))
+    {
+      (*current_liboctave_warning_handler)
+       ("eigs: 'A - sigma*B' is singular, indicating sigma is exactly");
+      (*current_liboctave_warning_handler)
+       ("       an eigenvalue. Convergence is not guaranteed");
+    }
+
+  return true;
+}
+
+static bool
+LuAminusSigmaB (const Matrix &m, const Matrix &b, 
+               bool cholB, const ColumnVector& permB, double sigma,
+               Matrix &L, Matrix &U, octave_idx_type *P, 
+               octave_idx_type *Q)
+{
+  bool have_b = ! b.is_empty ();
+  octave_idx_type n = m.cols();
+
+  // Caclulate LU decomposition of 'A - sigma * B'
+  Matrix AminusSigmaB (m);
+
+  if (have_b)
+    {
+      if (cholB)
+       {
+         Matrix tmp = sigma * b.transpose() * b;
+         const double *pB = permB.fortran_vec();
+         double *p = AminusSigmaB.fortran_vec();
+
+         if (permB.length())
+           {
+             for (octave_idx_type j = 0; 
+                  j < b.cols(); j++)
+               for (octave_idx_type i = 0; 
+                    i < b.rows(); i++)
+                 *p++ -=  tmp.xelem (static_cast<octave_idx_type>(pB[i]),
+                                     static_cast<octave_idx_type>(pB[j]));
+           }
+         else
+           AminusSigmaB = AminusSigmaB - tmp;
+       }
+      else
+       AminusSigmaB = AminusSigmaB - sigma * b;
+    }
+  else
+    {
+      double *p = AminusSigmaB.fortran_vec();
+
+      for (octave_idx_type i = 0; i < n; i++)
+       p[i*(n+1)] -= sigma;
+    }
+
+  LU fact (AminusSigmaB);
+
+  L = fact.P().transpose() * fact.L ();
+  U = fact.U ();
+  for (octave_idx_type j = 0; j < n; j++)
+    P[j] = Q[j] = j;  
+
+  // Test condition number of LU decomposition
+  double minU = octave_NaN;
+  double maxU = octave_NaN;
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      double d = std::abs (U.xelem(j,j));
+      if (xisnan (minU) || d < minU)
+       minU = d;
+
+      if (xisnan (maxU) || d > maxU)
+       maxU = d;
+    }
+
+  double rcond = (minU / maxU);
+  volatile double rcond_plus_one = rcond + 1.0;
+
+  if (rcond_plus_one == 1.0 || xisnan (rcond))
+    {
+      (*current_liboctave_warning_handler) 
+       ("eigs: 'A - sigma*B' is singular, indicating sigma is exactly");
+      (*current_liboctave_warning_handler) 
+       ("       an eigenvalue. Convergence is not guaranteed");
+    }
+
+  return true;
+}
+
+static bool
+LuAminusSigmaB (const SparseComplexMatrix &m, const SparseComplexMatrix &b, 
+               bool cholB, const ColumnVector& permB, Complex sigma,
+               SparseComplexMatrix &L, SparseComplexMatrix &U,
+               octave_idx_type *P, octave_idx_type *Q)
+{
+  bool have_b = ! b.is_empty ();
+  octave_idx_type n = m.rows();
+
+  // Caclulate LU decomposition of 'A - sigma * B'
+  SparseComplexMatrix AminusSigmaB (m);
+
+  if (have_b)
+    {
+      if (cholB)
+       {
+         if (permB.length())
+           {
+             SparseMatrix tmp(n,n,n);
+             for (octave_idx_type i = 0; i < n; i++)
+               {
+                 tmp.xcidx(i) = i;
+                 tmp.xridx(i) = 
+                   static_cast<octave_idx_type>(permB(i));
+                 tmp.xdata(i) = 1;
+               }
+             tmp.xcidx(n) = n;
+
+             AminusSigmaB = AminusSigmaB - tmp * b.hermitian() * b * 
+               tmp.transpose() * sigma;
+           }
+         else
+           AminusSigmaB = AminusSigmaB - sigma * b.hermitian() * b;
+       }
+      else
+       AminusSigmaB = AminusSigmaB - sigma * b;
+    }
+  else
+    {
+      SparseComplexMatrix sigmat (n, n, n);
+
+      // Create sigma * speye(n,n)
+      sigmat.xcidx (0) = 0;
+      for (octave_idx_type i = 0; i < n; i++)
+       {
+         sigmat.xdata(i) = sigma;
+         sigmat.xridx(i) = i;
+         sigmat.xcidx(i+1) = i + 1;
+       }
+
+      AminusSigmaB = AminusSigmaB - sigmat;
+    }
+
+  SparseComplexLU fact (AminusSigmaB);
+
+  L = fact.L ();
+  U = fact.U ();
+  const octave_idx_type *P2 = fact.row_perm ();
+  const octave_idx_type *Q2 = fact.col_perm ();
+
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      P[j] = P2[j];
+      Q[j] = Q2[j];
+    }
+
+  // Test condition number of LU decomposition
+  double minU = octave_NaN;
+  double maxU = octave_NaN;
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      double d = 0.;
+      if (U.xcidx(j+1) > U.xcidx(j) &&
+         U.xridx (U.xcidx(j+1)-1) == j)
+       d = std::abs (U.xdata (U.xcidx(j+1)-1));
+
+      if (xisnan (minU) || d < minU)
+       minU = d;
+
+      if (xisnan (maxU) || d > maxU)
+       maxU = d;
+    }
+
+  double rcond = (minU / maxU);
+  volatile double rcond_plus_one = rcond + 1.0;
+
+  if (rcond_plus_one == 1.0 || xisnan (rcond))
+    {
+      (*current_liboctave_warning_handler)
+       ("eigs: 'A - sigma*B' is singular, indicating sigma is exactly");
+      (*current_liboctave_warning_handler)
+       ("       an eigenvalue. Convergence is not guaranteed");
+    }
+
+  return true;
+}
+
+static bool
+LuAminusSigmaB (const ComplexMatrix &m, const ComplexMatrix &b, 
+               bool cholB, const ColumnVector& permB, Complex sigma,
+               ComplexMatrix &L, ComplexMatrix &U, octave_idx_type *P, 
+               octave_idx_type *Q)
+{
+  bool have_b = ! b.is_empty ();
+  octave_idx_type n = m.cols();
+
+  // Caclulate LU decomposition of 'A - sigma * B'
+  ComplexMatrix AminusSigmaB (m);
+
+  if (have_b)
+    {
+      if (cholB)
+       {
+         ComplexMatrix tmp = sigma * b.hermitian() * b;
+         const double *pB = permB.fortran_vec();
+         Complex *p = AminusSigmaB.fortran_vec();
+
+         if (permB.length())
+           {
+             for (octave_idx_type j = 0; 
+                  j < b.cols(); j++)
+               for (octave_idx_type i = 0; 
+                    i < b.rows(); i++)
+                 *p++ -=  tmp.xelem (static_cast<octave_idx_type>(pB[i]),
+                                     static_cast<octave_idx_type>(pB[j]));
+           }
+         else
+           AminusSigmaB = AminusSigmaB - tmp;
+       }
+      else
+       AminusSigmaB = AminusSigmaB - sigma * b;
+    }
+  else
+    {
+      Complex *p = AminusSigmaB.fortran_vec();
+
+      for (octave_idx_type i = 0; i < n; i++)
+       p[i*(n+1)] -= sigma;
+    }
+
+  ComplexLU fact (AminusSigmaB);
+
+  L = fact.P().transpose() * fact.L ();
+  U = fact.U ();
+  for (octave_idx_type j = 0; j < n; j++)
+    P[j] = Q[j] = j;  
+
+  // Test condition number of LU decomposition
+  double minU = octave_NaN;
+  double maxU = octave_NaN;
+  for (octave_idx_type j = 0; j < n; j++)
+    {
+      double d = std::abs (U.xelem(j,j));
+      if (xisnan (minU) || d < minU)
+       minU = d;
+
+      if (xisnan (maxU) || d > maxU)
+       maxU = d;
+    }
+
+  double rcond = (minU / maxU);
+  volatile double rcond_plus_one = rcond + 1.0;
+
+  if (rcond_plus_one == 1.0 || xisnan (rcond))
+    {
+      (*current_liboctave_warning_handler) 
+       ("eigs: 'A - sigma*B' is singular, indicating sigma is exactly");
+      (*current_liboctave_warning_handler) 
+       ("       an eigenvalue. Convergence is not guaranteed");
+    }
+
+  return true;
+}
+
+template <class M>
+octave_idx_type
+EigsRealSymmetricMatrix (const M& m, const std::string typ, 
+                        octave_idx_type k, octave_idx_type p,
+                        octave_idx_type &info, Matrix &eig_vec,
+                        ColumnVector &eig_val, const M& _b,
+                        ColumnVector &permB, ColumnVector &resid, 
+                        std::ostream& os, double tol, int rvec, 
+                        bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 1;
+  bool have_b = ! b.is_empty();
+  bool note3 = false;
+  char bmat = 'I';
+  double sigma = 0.;
+  M bt;
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p <= k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k and n");
+      return -1;
+    }
+
+  if (k > n )
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n).\n"
+        "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check the we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+      typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+      typ != "SI")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecognized sigma value");
+      return -1;
+    }
+  
+  if (typ == "LI" || typ == "SI" || typ == "LR" || typ == "SR")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: invalid sigma value for real symmetric problem");
+      return -1;
+    }
+
+  if (have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+       {
+         bt = b;
+         b = b.transpose();
+         if (permB.length() == 0)
+           {
+             permB = ColumnVector(n);
+             for (octave_idx_type i = 0; i < n; i++)
+               permB(i) = i;
+           }
+       }
+      else
+       {
+         if (! make_cholb(b, bt, permB))
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: The matrix B is not positive definite");
+             return -1;
+           }
+       }
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = p * (p + 8);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * p);
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dsaupd, DSAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dsaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             Matrix mtmp (n,1);
+             for (octave_idx_type i = 0; i < n; i++)
+               mtmp(i,0) = workd[i + iptr(0) - 1];
+             
+             mtmp = utsolve(bt, permB, m * ltsolve(b, permB, mtmp));
+
+             for (octave_idx_type i = 0; i < n; i++)
+               workd[i+iptr(1)-1] = mtmp(i,0);
+           }
+         else if (!vector_product (m, workd + iptr(0) - 1, 
+                                   workd + iptr(1) - 1))
+           break;
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+                       
+  eig_vec.resize (n, k);
+  double *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k);
+  double *d = eig_val.fortran_vec ();
+
+  F77_FUNC (dseupd, DSEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, 
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n, 
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
+     ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) 
+     F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dseupd");
+      return -1;
+    }
+  else
+    {
+      if (info2 == 0)
+       {
+         octave_idx_type k2 = k / 2;
+         if (typ != "SM" && typ != "BE")
+           {
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 double dtmp = d[i];
+                 d[i] = d[k - i - 1];
+                 d[k - i - 1] = dtmp;
+               }
+           }
+
+         if (rvec)
+           {
+             if (typ != "SM" && typ != "BE")
+               {
+                 OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                 for (octave_idx_type i = 0; i < k2; i++)
+                   {
+                     octave_idx_type off1 = i * n;
+                     octave_idx_type off2 = (k - i - 1) * n;
+
+                     if (off1 == off2)
+                       continue;
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       dtmp[j] = z[off1 + j];
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       z[off1 + j] = z[off2 + j];
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       z[off2 + j] = dtmp[j];
+                   }
+               }
+
+             if (note3)
+               eig_vec = ltsolve(b, permB, eig_vec);
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: error %d in dseupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+template <class M>
+octave_idx_type
+EigsRealSymmetricMatrixShift (const M& m, double sigma,
+                             octave_idx_type k, octave_idx_type p, 
+                             octave_idx_type &info, Matrix &eig_vec, 
+                             ColumnVector &eig_val, const M& _b,
+                             ColumnVector &permB, ColumnVector &resid, 
+                             std::ostream& os, double tol, int rvec, 
+                             bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 3;
+  bool have_b = ! b.is_empty();
+  std::string typ = "LM";
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
+  //if (! std::abs (sigma))
+  //  return EigsRealSymmetricMatrix (m, "SM", k, p, info, eig_vec, eig_val,
+  //                               _b, permB, resid, os, tol, rvec, cholB,
+  //                               disp, maxit);
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p <= k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k and n");
+      return -1;
+    }
+
+  if (k > n )
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check the we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  char bmat = 'I';
+  if (have_b)
+    bmat = 'G';
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  M L, U;
+
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows() : m.rows()));
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols() : m.cols()));
+
+  if (! LuAminusSigmaB(m, b, cholB, permB, sigma, L, U, P, Q))
+    return -1;
+
+  octave_idx_type lwork = p * (p + 8);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * p);
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dsaupd, DSAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dsaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             if (ido == -1)
+               {
+                 OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                 vector_product (m, workd+iptr(0)-1, dtmp);
+
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = dtmp[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 double *ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+             else if (ido == 2)
+               vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
+             else
+               {
+                 double *ip2 = workd+iptr(2)-1;
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+         else
+           {
+             if (ido == 2)
+               {
+                 for (octave_idx_type i = 0; i < n; i++)
+                   workd[iptr(0) + i - 1] = workd[iptr(1) + i - 1];
+               }
+             else
+               {
+                 double *ip2 = workd+iptr(0)-1;
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+                       
+  eig_vec.resize (n, k);
+  double *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k);
+  double *d = eig_val.fortran_vec ();
+
+  F77_FUNC (dseupd, DSEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, 
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
+     k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2
+     F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dseupd");
+      return -1;
+    }
+  else
+    {
+      if (info2 == 0)
+       {
+         octave_idx_type k2 = k / 2;
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             double dtmp = d[i];
+             d[i] = d[k - i - 1];
+             d[k - i - 1] = dtmp;
+           }
+
+         if (rvec)
+           {
+             OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (k - i - 1) * n;
+
+                 if (off1 == off2)
+                   continue;
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   dtmp[j] = z[off1 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off1 + j] = z[off2 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off2 + j] = dtmp[j];
+               }
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler)
+           ("eigs: error %d in dseupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+octave_idx_type
+EigsRealSymmetricFunc (EigsFunc fun, octave_idx_type n,
+                      const std::string &_typ, double sigma,
+                      octave_idx_type k, octave_idx_type p, 
+                      octave_idx_type &info, Matrix &eig_vec, 
+                      ColumnVector &eig_val, ColumnVector &resid, 
+                      std::ostream& os, double tol, int rvec, bool cholB, 
+                      int disp, int maxit)
+{
+  std::string typ (_typ);
+  bool have_sigma = (sigma ? true : false);
+  char bmat = 'I';
+  octave_idx_type mode = 1;
+  int err = 0;
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p <= k || p > n)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: opts.p must be between k and n");
+      return -1;
+    }
+
+  if (k > n )
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: Too many eigenvalues to extract (k >= n).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (! have_sigma)
+    {
+      if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+         typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+         typ != "SI")
+       (*current_liboctave_error_handler) 
+         ("eigs: unrecognized sigma value");
+
+      if (typ == "LI" || typ == "SI" || typ == "LR" || typ == "SR")
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: invalid sigma value for real symmetric problem");
+         return -1;
+       }
+
+      if (typ == "SM")
+       {
+         typ = "LM";
+         sigma = 0.;
+         mode = 3;
+       }
+    }
+  else if (! std::abs (sigma))
+    typ = "SM";
+  else
+    {
+      typ = "LM";
+      mode = 3;
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = p * (p + 8);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * p);
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dsaupd, DSAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dsaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         double *ip2 = workd + iptr(0) - 1;
+         ColumnVector x(n);
+
+         for (octave_idx_type i = 0; i < n; i++)
+           x(i) = *ip2++;
+
+         ColumnVector y = fun (x, err);
+
+         if (err)
+           return false;
+
+         ip2 = workd + iptr(1) - 1;
+         for (octave_idx_type i = 0; i < n; i++)
+           *ip2++ = y(i);
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+                       
+  eig_vec.resize (n, k);
+  double *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k);
+  double *d = eig_val.fortran_vec ();
+
+  F77_FUNC (dseupd, DSEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, 
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
+     k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2
+     F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dseupd");
+      return -1;
+    }
+  else
+    {
+      if (info2 == 0)
+       {
+         octave_idx_type k2 = k / 2;
+         if (typ != "SM" && typ != "BE")
+           {
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 double dtmp = d[i];
+                 d[i] = d[k - i - 1];
+                 d[k - i - 1] = dtmp;
+               }
+           }
+
+         if (rvec)
+           {
+             if (typ != "SM" && typ != "BE")
+               {
+                 OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                 for (octave_idx_type i = 0; i < k2; i++)
+                   {
+                     octave_idx_type off1 = i * n;
+                     octave_idx_type off2 = (k - i - 1) * n;
+
+                     if (off1 == off2)
+                       continue;
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       dtmp[j] = z[off1 + j];
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       z[off1 + j] = z[off2 + j];
+
+                     for (octave_idx_type j = 0; j < n; j++)
+                       z[off2 + j] = dtmp[j];
+                   }
+               }
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler)
+           ("eigs: error %d in dseupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+template <class M>
+octave_idx_type
+EigsRealNonSymmetricMatrix (const M& m, const std::string typ, 
+                           octave_idx_type k, octave_idx_type p,
+                           octave_idx_type &info, ComplexMatrix &eig_vec,
+                           ComplexColumnVector &eig_val, const M& _b,
+                           ColumnVector &permB, ColumnVector &resid, 
+                           std::ostream& os, double tol, int rvec, 
+                           bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 1;
+  bool have_b = ! b.is_empty();
+  bool note3 = false;
+  char bmat = 'I';
+  double sigmar = 0.;
+  double sigmai = 0.;
+  M bt;
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+        "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check the we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+      typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+      typ != "SI")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecognized sigma value");
+      return -1;
+    }
+  
+  if (typ == "LA" || typ == "SA" || typ == "BE")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: invalid sigma value for unsymmetric problem");
+      return -1;
+    }
+
+  if (have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+       {
+         bt = b;
+         b = b.transpose();
+         if (permB.length() == 0)
+           {
+             permB = ColumnVector(n);
+             for (octave_idx_type i = 0; i < n; i++)
+               permB(i) = i;
+           }
+       }
+      else
+       {
+         if (! make_cholb(b, bt, permB))
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: The matrix B is not positive definite");
+             return -1;
+           }
+       }
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = 3 * p * (p + 2);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dnaupd, DNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dnaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             Matrix mtmp (n,1);
+             for (octave_idx_type i = 0; i < n; i++)
+               mtmp(i,0) = workd[i + iptr(0) - 1];
+             
+             mtmp = utsolve(bt, permB, m * ltsolve(b, permB, mtmp));
+
+             for (octave_idx_type i = 0; i < n; i++)
+               workd[i+iptr(1)-1] = mtmp(i,0);
+           }
+         else if (!vector_product (m, workd + iptr(0) - 1, 
+                                   workd + iptr(1) - 1))
+           break;
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dnaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+
+  Matrix eig_vec2 (n, k + 1);
+  double *z = eig_vec2.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
+
+  F77_FUNC (dneupd, DNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, 
+     sigmai, workev,  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
+     ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) 
+     F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dneupd");
+      return -1;
+    }
+  else
+    {
+      eig_val.resize (k+1);
+      Complex *d = eig_val.fortran_vec ();
+
+      if (info2 == 0)
+       {
+         octave_idx_type jj = 0;
+         for (octave_idx_type i = 0; i < k+1; i++)
+           {
+             if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0)
+               jj++;
+             else
+               d [i-jj] = Complex (dr[i], di[i]);
+           }
+         if (jj == 0 && !rvec)
+           for (octave_idx_type i = 0; i < k; i++)
+             d[i] = d[i+1];
+
+         octave_idx_type k2 = k / 2;
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             Complex dtmp = d[i];
+             d[i] = d[k - i - 1];
+             d[k - i - 1] = dtmp;
+           }
+         eig_val.resize(k);
+
+         if (rvec)
+           {
+             OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (k - i - 1) * n;
+
+                 if (off1 == off2)
+                   continue;
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   dtmp[j] = z[off1 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off1 + j] = z[off2 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off2 + j] = dtmp[j];
+               }
+
+             eig_vec.resize (n, k);
+             octave_idx_type i = 0;
+             while (i < k)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (i+1) * n;
+                 if (std::imag(eig_val(i)) == 0)
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       eig_vec(j,i) = 
+                         Complex(z[j+off1],0.);
+                     i++;
+                   }
+                 else
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       {
+                         eig_vec(j,i) = 
+                           Complex(z[j+off1],z[j+off2]);
+                         if (i < k - 1)
+                           eig_vec(j,i+1) = 
+                             Complex(z[j+off1],-z[j+off2]);
+                       }
+                     i+=2;
+                   }
+               }
+
+             if (note3)
+               eig_vec = ltsolve(M (b), permB, eig_vec);
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: error %d in dneupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+template <class M>
+octave_idx_type
+EigsRealNonSymmetricMatrixShift (const M& m, double sigmar,
+                                octave_idx_type k, octave_idx_type p, 
+                                octave_idx_type &info, 
+                                ComplexMatrix &eig_vec, 
+                                ComplexColumnVector &eig_val, const M& _b,
+                                ColumnVector &permB, ColumnVector &resid, 
+                                std::ostream& os, double tol, int rvec, 
+                                bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 3;
+  bool have_b = ! b.is_empty();
+  std::string typ = "LM";
+  double sigmai = 0.;
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
+  //if (! std::abs (sigmar))
+  //  return EigsRealNonSymmetricMatrix (m, "SM", k, p, info, eig_vec, eig_val,
+  //                                  _b, permB, resid, os, tol, rvec, cholB,
+  //                                  disp, maxit);
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check that we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  char bmat = 'I';
+  if (have_b)
+    bmat = 'G';
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  M L, U;
+
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows() : m.rows()));
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols() : m.cols()));
+
+  if (! LuAminusSigmaB(m, b, cholB, permB, sigmar, L, U, P, Q))
+    return -1;
+
+  octave_idx_type lwork = 3 * p * (p + 2);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dnaupd, DNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dsaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             if (ido == -1)
+               {
+                 OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                 vector_product (m, workd+iptr(0)-1, dtmp);
+
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = dtmp[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 double *ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+             else if (ido == 2)
+               vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
+             else
+               {
+                 double *ip2 = workd+iptr(2)-1;
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+         else
+           {
+             if (ido == 2)
+               {
+                 for (octave_idx_type i = 0; i < n; i++)
+                   workd[iptr(0) + i - 1] = workd[iptr(1) + i - 1];
+               }
+             else
+               {
+                 double *ip2 = workd+iptr(0)-1;
+                 Matrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+                       
+  Matrix eig_vec2 (n, k + 1);
+  double *z = eig_vec2.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
+
+  F77_FUNC (dneupd, DNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, 
+     sigmai, workev,  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
+     ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) 
+     F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dneupd");
+      return -1;
+    }
+  else
+    {
+      eig_val.resize (k+1);
+      Complex *d = eig_val.fortran_vec ();
+
+      if (info2 == 0)
+       {
+         octave_idx_type jj = 0;
+         for (octave_idx_type i = 0; i < k+1; i++)
+           {
+             if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0)
+               jj++;
+             else
+               d [i-jj] = Complex (dr[i], di[i]);
+           }
+         if (jj == 0 && !rvec)
+           for (octave_idx_type i = 0; i < k; i++)
+             d[i] = d[i+1];
+
+         octave_idx_type k2 = k / 2;
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             Complex dtmp = d[i];
+             d[i] = d[k - i - 1];
+             d[k - i - 1] = dtmp;
+           }
+         eig_val.resize(k);
+
+         if (rvec)
+           {
+             OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (k - i - 1) * n;
+
+                 if (off1 == off2)
+                   continue;
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   dtmp[j] = z[off1 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off1 + j] = z[off2 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off2 + j] = dtmp[j];
+               }
+
+             eig_vec.resize (n, k);
+             octave_idx_type i = 0;
+             while (i < k)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (i+1) * n;
+                 if (std::imag(eig_val(i)) == 0)
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       eig_vec(j,i) = 
+                         Complex(z[j+off1],0.);
+                     i++;
+                   }
+                 else
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       {
+                         eig_vec(j,i) = 
+                           Complex(z[j+off1],z[j+off2]);
+                         if (i < k - 1)
+                           eig_vec(j,i+1) = 
+                             Complex(z[j+off1],-z[j+off2]);
+                       }
+                     i+=2;
+                   }
+               }
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: error %d in dneupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+octave_idx_type
+EigsRealNonSymmetricFunc (EigsFunc fun, octave_idx_type n,
+                         const std::string &_typ, double sigmar,
+                         octave_idx_type k, octave_idx_type p, 
+                         octave_idx_type &info, ComplexMatrix &eig_vec, 
+                         ComplexColumnVector &eig_val, ColumnVector &resid, 
+                         std::ostream& os, double tol, int rvec, bool cholB, 
+                         int disp, int maxit)
+{
+  std::string typ (_typ);
+  bool have_sigma = (sigmar ? true : false);
+  char bmat = 'I';
+  double sigmai = 0.;
+  octave_idx_type mode = 1;
+  int err = 0;
+
+  if (resid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      resid = ColumnVector (octave_rand::vector(n));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+
+  if (! have_sigma)
+    {
+      if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+         typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+         typ != "SI")
+       (*current_liboctave_error_handler) 
+         ("eigs: unrecognized sigma value");
+
+      if (typ == "LA" || typ == "SA" || typ == "BE")
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: invalid sigma value for unsymmetric problem");
+         return -1;
+       }
+
+      if (typ == "SM")
+       {
+         typ = "LM";
+         sigmar = 0.;
+         mode = 3;
+       }
+    }
+  else if (! std::abs (sigmar))
+    typ = "SM";
+  else
+    {
+      typ = "LM";
+      mode = 3;
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = 3 * p * (p + 2);
+
+  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
+  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
+  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
+  double *presid = resid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (dnaupd, DNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in dnaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         double *ip2 = workd + iptr(0) - 1;
+         ColumnVector x(n);
+
+         for (octave_idx_type i = 0; i < n; i++)
+           x(i) = *ip2++;
+
+         ColumnVector y = fun (x, err);
+
+         if (err)
+           return false;
+
+         ip2 = workd + iptr(1) - 1;
+         for (octave_idx_type i = 0; i < n; i++)
+           *ip2++ = y(i);
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+
+  Matrix eig_vec2 (n, k + 1);
+  double *z = eig_vec2.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
+  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
+
+  F77_FUNC (dneupd, DNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, 
+     sigmai, workev,  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
+     ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) 
+     F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: unrecoverable exception encountered in dneupd");
+      return -1;
+    }
+  else
+    {
+      eig_val.resize (k+1);
+      Complex *d = eig_val.fortran_vec ();
+
+      if (info2 == 0)
+       {
+         octave_idx_type jj = 0;
+         for (octave_idx_type i = 0; i < k+1; i++)
+           {
+             if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0)
+               jj++;
+             else
+               d [i-jj] = Complex (dr[i], di[i]);
+           }
+         if (jj == 0 && !rvec)
+           for (octave_idx_type i = 0; i < k; i++)
+             d[i] = d[i+1];
+
+         octave_idx_type k2 = k / 2;
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             Complex dtmp = d[i];
+             d[i] = d[k - i - 1];
+             d[k - i - 1] = dtmp;
+           }
+         eig_val.resize(k);
+
+         if (rvec)
+           {
+             OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+             for (octave_idx_type i = 0; i < k2; i++)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (k - i - 1) * n;
+
+                 if (off1 == off2)
+                   continue;
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   dtmp[j] = z[off1 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off1 + j] = z[off2 + j];
+
+                 for (octave_idx_type j = 0; j < n; j++)
+                   z[off2 + j] = dtmp[j];
+               }
+
+             eig_vec.resize (n, k);
+             octave_idx_type i = 0;
+             while (i < k)
+               {
+                 octave_idx_type off1 = i * n;
+                 octave_idx_type off2 = (i+1) * n;
+                 if (std::imag(eig_val(i)) == 0)
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       eig_vec(j,i) = 
+                         Complex(z[j+off1],0.);
+                     i++;
+                   }
+                 else
+                   {
+                     for (octave_idx_type j = 0; j < n; j++)
+                       {
+                         eig_vec(j,i) = 
+                           Complex(z[j+off1],z[j+off2]);
+                         if (i < k - 1)
+                           eig_vec(j,i+1) = 
+                             Complex(z[j+off1],-z[j+off2]);
+                       }
+                     i+=2;
+                   }
+               }
+           }
+       }
+      else
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: error %d in dneupd", info2);
+         return -1;
+       }
+    }
+
+  return ip(4);
+}
+
+template <class M>
+octave_idx_type
+EigsComplexNonSymmetricMatrix (const M& m, const std::string typ, 
+                              octave_idx_type k, octave_idx_type p,
+                              octave_idx_type &info, ComplexMatrix &eig_vec,
+                              ComplexColumnVector &eig_val, const M& _b,
+                              ColumnVector &permB, 
+                              ComplexColumnVector &cresid, 
+                              std::ostream& os, double tol, int rvec, 
+                              bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 1;
+  bool have_b = ! b.is_empty();
+  bool note3 = false;
+  char bmat = 'I';
+  Complex sigma = 0.;
+  M bt;
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  if (cresid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      Array<double> rr (octave_rand::vector(n));
+      Array<double> ri (octave_rand::vector(n));
+      cresid = ComplexColumnVector (n);
+      for (octave_idx_type i = 0; i < n; i++)
+       cresid(i) = Complex(rr(i),ri(i));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+        "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check the we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+      typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+      typ != "SI")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecognized sigma value");
+      return -1;
+    }
+  
+  if (typ == "LA" || typ == "SA" || typ == "BE")
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: invalid sigma value for complex problem");
+      return -1;
+    }
+
+  if (have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+       {
+         bt = b;
+         b = b.hermitian();
+         if (permB.length() == 0)
+           {
+             permB = ColumnVector(n);
+             for (octave_idx_type i = 0; i < n; i++)
+               permB(i) = i;
+           }
+       }
+      else
+       {
+         if (! make_cholb(b, bt, permB))
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: The matrix B is not positive definite");
+             return -1;
+           }
+       }
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = p * (3 * p + 5);
+             
+  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
+  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
+  OCTAVE_LOCAL_BUFFER (double, rwork, p);
+  Complex *presid = cresid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (znaupd, ZNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, rwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in znaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+                         
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             ComplexMatrix mtmp (n,1);
+             for (octave_idx_type i = 0; i < n; i++)
+               mtmp(i,0) = workd[i + iptr(0) - 1];
+             mtmp = utsolve(bt, permB, m * ltsolve(b, permB, mtmp));
+             for (octave_idx_type i = 0; i < n; i++)
+               workd[i+iptr(1)-1] = mtmp(i,0);
+
+           }
+         else if (!vector_product (m, workd + iptr(0) - 1, 
+                                   workd + iptr(1) - 1))
+           break;
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in znaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+
+  eig_vec.resize (n, k);
+  Complex *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k+1);
+  Complex *d = eig_val.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
+
+  F77_FUNC (zneupd, ZNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, workev,
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
+     k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, rwork, info2
+     F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecoverable exception encountered in zneupd");
+      return -1;
+    }
+
+  if (info2 == 0)
+    {
+      octave_idx_type k2 = k / 2;
+      for (octave_idx_type i = 0; i < k2; i++)
+       {
+         Complex ctmp = d[i];
+         d[i] = d[k - i - 1];
+         d[k - i - 1] = ctmp;
+       }
+      eig_val.resize(k);
+
+      if (rvec)
+       {
+         OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
+
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             octave_idx_type off1 = i * n;
+             octave_idx_type off2 = (k - i - 1) * n;
+
+             if (off1 == off2)
+               continue;
+
+             for (octave_idx_type j = 0; j < n; j++)
+               ctmp[j] = z[off1 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off1 + j] = z[off2 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off2 + j] = ctmp[j];
+           }
+
+         if (note3)
+           eig_vec = ltsolve(b, permB, eig_vec);
+       }
+    }
+  else
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: error %d in zneupd", info2);
+      return -1;
+    }
+
+  return ip(4);
+}
+
+template <class M>
+octave_idx_type
+EigsComplexNonSymmetricMatrixShift (const M& m, Complex sigma,
+                                   octave_idx_type k, octave_idx_type p, 
+                                   octave_idx_type &info, 
+                                   ComplexMatrix &eig_vec, 
+                                   ComplexColumnVector &eig_val, const M& _b,
+                                   ColumnVector &permB, 
+                                   ComplexColumnVector &cresid, 
+                                   std::ostream& os, double tol, int rvec, 
+                                   bool cholB, int disp, int maxit)
+{
+  M b(_b);
+  octave_idx_type n = m.cols ();
+  octave_idx_type mode = 3;
+  bool have_b = ! b.is_empty();
+  std::string typ = "LM";
+
+  if (m.rows() != m.cols())
+    {
+      (*current_liboctave_error_handler) ("eigs: A must be square");
+      return -1;
+    }
+  if (have_b && (m.rows() != b.rows() || m.rows() != b.cols()))
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: B must be square and the same size as A");
+      return -1;
+    }
+
+  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
+  //if (! std::abs (sigma))
+  //  return EigsComplexNonSymmetricMatrix (m, "SM", k, p, info, eig_vec,
+  //                                     eig_val, _b, permB, cresid, os, tol,
+  //                                     rvec, cholB, disp, maxit);
+
+  if (cresid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      Array<double> rr (octave_rand::vector(n));
+      Array<double> ri (octave_rand::vector(n));
+      cresid = ComplexColumnVector (n);
+      for (octave_idx_type i = 0; i < n; i++)
+       cresid(i) = Complex(rr(i),ri(i));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (have_b && cholB && permB.length() != 0) 
+    {
+      // Check that we really have a permutation vector
+      if (permB.length() != n)
+       {
+         (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+         return -1;
+       }
+      else
+       {
+         Array<bool> checked(n,false);
+         for (octave_idx_type i = 0; i < n; i++)
+           {
+             octave_idx_type bidx = 
+               static_cast<octave_idx_type> (permB(i));
+             if (checked(bidx) || bidx < 0 ||
+                 bidx >= n || D_NINT (bidx) != bidx)
+               {
+                 (*current_liboctave_error_handler) 
+                   ("eigs: permB vector invalid");
+                 return -1;
+               }
+           }
+       }
+    }
+
+  char bmat = 'I';
+  if (have_b)
+    bmat = 'G';
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  M L, U;
+
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows() : m.rows()));
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols() : m.cols()));
+
+  if (! LuAminusSigmaB(m, b, cholB, permB, sigma, L, U, P, Q))
+    return -1;
+
+  octave_idx_type lwork = p * (3 * p + 5);
+             
+  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
+  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
+  OCTAVE_LOCAL_BUFFER (double, rwork, p);
+  Complex *presid = cresid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (znaupd, ZNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, rwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in znaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+                         
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         if (have_b)
+           {
+             if (ido == -1)
+               {
+                 OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
+
+                 vector_product (m, workd+iptr(0)-1, ctmp);
+
+                 ComplexMatrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ctmp[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 Complex *ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+             else if (ido == 2)
+               vector_product (b, workd + iptr(0) - 1, workd + iptr(1) - 1);
+             else
+               {
+                 Complex *ip2 = workd+iptr(2)-1;
+                 ComplexMatrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+         else
+           {
+             if (ido == 2)
+               {
+                 for (octave_idx_type i = 0; i < n; i++)
+                   workd[iptr(0) + i - 1] =
+                     workd[iptr(1) + i - 1];
+               }
+             else
+               {
+                 Complex *ip2 = workd+iptr(0)-1;
+                 ComplexMatrix tmp(n, 1);
+
+                 for (octave_idx_type i = 0; i < n; i++)
+                   tmp(i,0) = ip2[P[i]];
+                                 
+                 lusolve (L, U, tmp);
+
+                 ip2 = workd+iptr(1)-1;
+                 for (octave_idx_type i = 0; i < n; i++)
+                   ip2[Q[i]] = tmp(i,0);
+               }
+           }
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+
+  eig_vec.resize (n, k);
+  Complex *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k+1);
+  Complex *d = eig_val.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
+
+  F77_FUNC (zneupd, ZNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, workev,
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
+     k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, rwork, info2
+     F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecoverable exception encountered in zneupd");
+      return -1;
+    }
+
+  if (info2 == 0)
+    {
+      octave_idx_type k2 = k / 2;
+      for (octave_idx_type i = 0; i < k2; i++)
+       {
+         Complex ctmp = d[i];
+         d[i] = d[k - i - 1];
+         d[k - i - 1] = ctmp;
+       }
+      eig_val.resize(k);
+
+      if (rvec)
+       {
+         OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
+
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             octave_idx_type off1 = i * n;
+             octave_idx_type off2 = (k - i - 1) * n;
+
+             if (off1 == off2)
+               continue;
+
+             for (octave_idx_type j = 0; j < n; j++)
+               ctmp[j] = z[off1 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off1 + j] = z[off2 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off2 + j] = ctmp[j];
+           }
+       }
+    }
+  else
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: error %d in zneupd", info2);
+      return -1;
+    }
+
+  return ip(4);
+}
+
+octave_idx_type
+EigsComplexNonSymmetricFunc (EigsComplexFunc fun, octave_idx_type n,
+                            const std::string &_typ, Complex sigma,
+                            octave_idx_type k, octave_idx_type p, 
+                            octave_idx_type &info, ComplexMatrix &eig_vec, 
+                            ComplexColumnVector &eig_val, 
+                            ComplexColumnVector &cresid, std::ostream& os, 
+                            double tol, int rvec, bool cholB, int disp, 
+                            int maxit)
+{
+  std::string typ (_typ);
+  bool have_sigma = (std::abs(sigma) ? true : false);
+  char bmat = 'I';
+  octave_idx_type mode = 1;
+  int err = 0;
+
+  if (cresid.is_empty())
+    {
+      std::string rand_dist = octave_rand::distribution();
+      octave_rand::distribution("uniform");
+      Array<double> rr (octave_rand::vector(n));
+      Array<double> ri (octave_rand::vector(n));
+      cresid = ComplexColumnVector (n);
+      for (octave_idx_type i = 0; i < n; i++)
+       cresid(i) = Complex(rr(i),ri(i));
+      octave_rand::distribution(rand_dist);
+    }
+
+  if (p < 0)
+    {
+      p = k * 2 + 1;
+
+      if (p < 20)
+       p = 20;
+      
+      if (p > n - 1)
+       p = n - 1 ;
+    }
+  else if (p < k || p > n)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: opts.p must be between k+1 and n");
+      return -1;
+    }
+
+  if (k > n - 1)
+    {
+      (*current_liboctave_error_handler)
+       ("eigs: Too many eigenvalues to extract (k >= n-1).\n"
+            "      Use 'eig(full(A))' instead");
+      return -1;
+    }
+
+  if (! have_sigma)
+    {
+      if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA" && 
+         typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI" &&
+         typ != "SI")
+       (*current_liboctave_error_handler) 
+         ("eigs: unrecognized sigma value");
+
+      if (typ == "LA" || typ == "SA" || typ == "BE")
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: invalid sigma value for complex problem");
+         return -1;
+       }
+
+      if (typ == "SM")
+       {
+         typ = "LM";
+         sigma = 0.;
+         mode = 3;
+       }
+    }
+  else if (! std::abs (sigma))
+    typ = "SM";
+  else
+    {
+      typ = "LM";
+      mode = 3;
+    }
+
+  Array<octave_idx_type> ip (11);
+  octave_idx_type *iparam = ip.fortran_vec ();
+
+  ip(0) = 1; //ishift
+  ip(1) = 0;   // ip(1) not referenced
+  ip(2) = maxit; // mxiter, maximum number of iterations
+  ip(3) = 1; // NB blocksize in recurrence
+  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
+  ip(5) = 0; //ip(5) not referenced
+  ip(6) = mode; // mode
+  ip(7) = 0;
+  ip(8) = 0;
+  ip(9) = 0;
+  ip(10) = 0;
+  // ip(7) to ip(10) return values
+ 
+  Array<octave_idx_type> iptr (14);
+  octave_idx_type *ipntr = iptr.fortran_vec ();
+
+  octave_idx_type ido = 0;
+  int iter = 0;
+  octave_idx_type lwork = p * (3 * p + 5);
+             
+  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
+  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
+  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
+  OCTAVE_LOCAL_BUFFER (double, rwork, p);
+  Complex *presid = cresid.fortran_vec ();
+
+  do 
+    {
+      F77_FUNC (znaupd, ZNAUPD) 
+       (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+        F77_CONST_CHAR_ARG2 ((typ.c_str()), 2),
+        k, tol, presid, p, v, n, iparam,
+        ipntr, workd, workl, lwork, rwork, info
+        F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+      if (f77_exception_encountered)
+       {
+         (*current_liboctave_error_handler) 
+           ("eigs: unrecoverable exception encountered in znaupd");
+         return -1;
+       }
+
+      if (disp > 0 && !xisnan(workl[iptr(5)-1]))
+       {
+         if (iter++)
+           {
+             os << "Iteration " << iter - 1 << 
+               ": a few Ritz values of the " << p << "-by-" <<
+               p << " matrix\n";
+             for (int i = 0 ; i < k; i++)
+               os << "    " << workl[iptr(5)+i-1] << "\n";
+           }
+                         
+         // This is a kludge, as ARPACK doesn't give its
+         // iteration pointer. But as workl[iptr(5)-1] is
+         // an output value updated at each iteration, setting
+         // a value in this array to NaN and testing for it
+         // is a way of obtaining the iteration counter.
+         if (ido != 99)
+           workl[iptr(5)-1] = octave_NaN; 
+       }
+
+      if (ido == -1 || ido == 1 || ido == 2)
+       {
+         Complex *ip2 = workd + iptr(0) - 1;
+         ComplexColumnVector x(n);
+
+         for (octave_idx_type i = 0; i < n; i++)
+           x(i) = *ip2++;
+
+         ComplexColumnVector y = fun (x, err);
+
+         if (err)
+           return false;
+
+         ip2 = workd + iptr(1) - 1;
+         for (octave_idx_type i = 0; i < n; i++)
+           *ip2++ = y(i);
+       }
+      else
+       {
+         if (info < 0)
+           {
+             (*current_liboctave_error_handler) 
+               ("eigs: error %d in dsaupd", info);
+             return -1;
+           }
+         break;
+       }
+    } 
+  while (1);
+
+  octave_idx_type info2;
+
+  // We have a problem in that the size of the C++ bool 
+  // type relative to the fortran logical type. It appears 
+  // that fortran uses 4-bytes per logical and C++ 1-byte 
+  // per bool, though this might be system dependent. As 
+  // long as the HOWMNY arg is not "S", the logical array
+  // is just workspace for ARPACK, so use int type to 
+  // avoid problems.
+  Array<int> s (p);
+  int *sel = s.fortran_vec ();
+
+  eig_vec.resize (n, k);
+  Complex *z = eig_vec.fortran_vec ();
+
+  eig_val.resize (k+1);
+  Complex *d = eig_val.fortran_vec ();
+
+  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
+
+  F77_FUNC (zneupd, ZNEUPD) 
+    (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma, workev,
+     F77_CONST_CHAR_ARG2 (&bmat, 1), n,
+     F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
+     k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, rwork, info2
+     F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
+
+  if (f77_exception_encountered)
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: unrecoverable exception encountered in zneupd");
+      return -1;
+    }
+
+  if (info2 == 0)
+    {
+      octave_idx_type k2 = k / 2;
+      for (octave_idx_type i = 0; i < k2; i++)
+       {
+         Complex ctmp = d[i];
+         d[i] = d[k - i - 1];
+         d[k - i - 1] = ctmp;
+       }
+      eig_val.resize(k);
+
+      if (rvec)
+       {
+         OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
+
+         for (octave_idx_type i = 0; i < k2; i++)
+           {
+             octave_idx_type off1 = i * n;
+             octave_idx_type off2 = (k - i - 1) * n;
+
+             if (off1 == off2)
+               continue;
+
+             for (octave_idx_type j = 0; j < n; j++)
+               ctmp[j] = z[off1 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off1 + j] = z[off2 + j];
+
+             for (octave_idx_type j = 0; j < n; j++)
+               z[off2 + j] = ctmp[j];
+           }
+       }
+    }
+  else
+    {
+      (*current_liboctave_error_handler) 
+       ("eigs: error %d in zneupd", info2);
+      return -1;
+    }
+
+  return ip(4);
+}
+
+#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
+extern octave_idx_type
+EigsRealSymmetricMatrix (const Matrix& m, const std::string typ, 
+                        octave_idx_type k, octave_idx_type p,
+                        octave_idx_type &info, Matrix &eig_vec,
+                        ColumnVector &eig_val, const Matrix& b,
+                        ColumnVector &permB, ColumnVector &resid, 
+                        std::ostream &os, double tol = DBL_EPSILON,
+                        int rvec = 0, bool cholB = 0, int disp = 0,
+                        int maxit = 300);
+
+extern octave_idx_type
+EigsRealSymmetricMatrix (const SparseMatrix& m, const std::string typ, 
+                        octave_idx_type k, octave_idx_type p,
+                        octave_idx_type &info, Matrix &eig_vec,
+                        ColumnVector &eig_val, const SparseMatrix& b,
+                        ColumnVector &permB, ColumnVector &resid, 
+                        std::ostream& os, double tol = DBL_EPSILON,
+                        int rvec = 0, bool cholB = 0, int disp = 0, 
+                        int maxit = 300);
+
+extern octave_idx_type
+EigsRealSymmetricMatrixShift (const Matrix& m, double sigma,
+                             octave_idx_type k, octave_idx_type p, 
+                             octave_idx_type &info, Matrix &eig_vec, 
+                             ColumnVector &eig_val, const Matrix& b,
+                             ColumnVector &permB, ColumnVector &resid, 
+                             std::ostream &os, double tol = DBL_EPSILON,
+                             int rvec = 0, bool cholB = 0, int disp = 0, 
+                             int maxit = 300);
+
+extern octave_idx_type
+EigsRealSymmetricMatrixShift (const SparseMatrix& m, double sigma,
+                             octave_idx_type k, octave_idx_type p, 
+                             octave_idx_type &info, Matrix &eig_vec, 
+                             ColumnVector &eig_val, const SparseMatrix& b,
+                             ColumnVector &permB, ColumnVector &resid, 
+                             std::ostream &os, double tol = DBL_EPSILON,
+                             int rvec = 0, bool cholB = 0, int disp = 0, 
+                             int maxit = 300);
+
+extern octave_idx_type
+EigsRealSymmetricFunc (EigsFunc fun, octave_idx_type n,
+                      const std::string &typ, double sigma,
+                      octave_idx_type k, octave_idx_type p, 
+                      octave_idx_type &info,
+                      Matrix &eig_vec, ColumnVector &eig_val, 
+                      ColumnVector &resid, std::ostream &os,
+                      double tol = DBL_EPSILON, int rvec = 0,
+                      bool cholB = 0, int disp = 0, int maxit = 300);
+
+extern octave_idx_type
+EigsRealNonSymmetricMatrix (const Matrix& m, const std::string typ, 
+                           octave_idx_type k, octave_idx_type p,
+                           octave_idx_type &info, ComplexMatrix &eig_vec,
+                           ComplexColumnVector &eig_val, const Matrix& b,
+                           ColumnVector &permB, ColumnVector &resid, 
+                           std::ostream &os, double tol = DBL_EPSILON,
+                           int rvec = 0, bool cholB = 0, int disp = 0,
+                           int maxit = 300);
+
+extern octave_idx_type
+EigsRealNonSymmetricMatrix (const SparseMatrix& m, const std::string typ, 
+                           octave_idx_type k, octave_idx_type p,
+                           octave_idx_type &info, ComplexMatrix &eig_vec,
+                           ComplexColumnVector &eig_val, 
+                           const SparseMatrix& b,
+                           ColumnVector &permB, ColumnVector &resid, 
+                           std::ostream &os, double tol = DBL_EPSILON,
+                           int rvec = 0, bool cholB = 0, int disp = 0,
+                           int maxit = 300);
+
+extern octave_idx_type
+EigsRealNonSymmetricMatrixShift (const Matrix& m, double sigma,
+                                octave_idx_type k, octave_idx_type p, 
+                                octave_idx_type &info,
+                                ComplexMatrix &eig_vec, 
+                                ComplexColumnVector &eig_val, const Matrix& b,
+                                ColumnVector &permB, ColumnVector &resid, 
+                                std::ostream &os, double tol = DBL_EPSILON,
+                                int rvec = 0, bool cholB = 0, int disp = 0, 
+                                int maxit = 300);
+
+extern octave_idx_type
+EigsRealNonSymmetricMatrixShift (const SparseMatrix& m, double sigma,
+                                octave_idx_type k, octave_idx_type p, 
+                                octave_idx_type &info,
+                                ComplexMatrix &eig_vec, 
+                                ComplexColumnVector &eig_val, 
+                                const SparseMatrix& b,
+                                ColumnVector &permB, ColumnVector &resid, 
+                                std::ostream &os, double tol = DBL_EPSILON,
+                                int rvec = 0, bool cholB = 0, int disp = 0, 
+                                int maxit = 300);
+
+extern octave_idx_type
+EigsRealNonSymmetricFunc (EigsFunc fun, octave_idx_type n,
+                         const std::string &_typ, double sigma,
+                         octave_idx_type k, octave_idx_type p, 
+                         octave_idx_type &info, ComplexMatrix &eig_vec, 
+                         ComplexColumnVector &eig_val, 
+                         ColumnVector &resid, std::ostream& os, 
+                         double tol = DBL_EPSILON, int rvec = 0,
+                         bool cholB = 0, int disp = 0, int maxit = 300);
+
+extern octave_idx_type
+EigsComplexNonSymmetricMatrix (const ComplexMatrix& m, const std::string typ, 
+                              octave_idx_type k, octave_idx_type p,
+                              octave_idx_type &info, ComplexMatrix &eig_vec,
+                              ComplexColumnVector &eig_val, 
+                              const ComplexMatrix& b, ColumnVector &permB, 
+                              ComplexColumnVector &resid, 
+                              std::ostream &os, double tol = DBL_EPSILON,
+                              int rvec = 0, bool cholB = 0, int disp = 0, 
+                              int maxit = 300);
+
+extern octave_idx_type
+EigsComplexNonSymmetricMatrix (const SparseComplexMatrix& m, 
+                              const std::string typ, octave_idx_type k, 
+                              octave_idx_type p, octave_idx_type &info, 
+                              ComplexMatrix &eig_vec,
+                              ComplexColumnVector &eig_val, 
+                              const SparseComplexMatrix& b,
+                              ColumnVector &permB,
+                              ComplexColumnVector &resid, 
+                              std::ostream &os, double tol = DBL_EPSILON,
+                              int rvec = 0, bool cholB = 0, int disp = 0, 
+                              int maxit = 300);
+
+extern octave_idx_type
+EigsComplexNonSymmetricMatrixShift (const ComplexMatrix& m, Complex sigma,
+                                   octave_idx_type k, octave_idx_type p, 
+                                   octave_idx_type &info, 
+                                   ComplexMatrix &eig_vec, 
+                                   ComplexColumnVector &eig_val,
+                                   const ComplexMatrix& b,
+                                   ColumnVector &permB,
+                                   ComplexColumnVector &resid, 
+                                   std::ostream &os, double tol = DBL_EPSILON,
+                                   int rvec = 0, bool cholB = 0,
+                                   int disp = 0, int maxit = 300);
+
+extern octave_idx_type
+EigsComplexNonSymmetricMatrixShift (const SparseComplexMatrix& m,
+                                   Complex sigma,
+                                   octave_idx_type k, octave_idx_type p, 
+                                   octave_idx_type &info, 
+                                   ComplexMatrix &eig_vec, 
+                                   ComplexColumnVector &eig_val, 
+                                   const SparseComplexMatrix& b,
+                                   ColumnVector &permB,
+                                   ComplexColumnVector &resid, 
+                                   std::ostream &os, double tol = DBL_EPSILON,
+                                   int rvec = 0, bool cholB = 0,
+                                   int disp = 0, int maxit = 300);
+
+extern octave_idx_type
+EigsComplexNonSymmetricFunc (EigsComplexFunc fun, octave_idx_type n,
+                            const std::string &_typ, Complex sigma,
+                            octave_idx_type k, octave_idx_type p, 
+                            octave_idx_type &info, ComplexMatrix &eig_vec, 
+                            ComplexColumnVector &eig_val, 
+                            ComplexColumnVector &resid, std::ostream& os, 
+                            double tol = DBL_EPSILON, int rvec = 0,
+                            bool cholB = 0, int disp = 0, int maxit = 300);
+#endif
+
+#ifndef _MSC_VER
+template static octave_idx_type
+lusolve (const SparseMatrix&, const SparseMatrix&, Matrix&);
+
+template static octave_idx_type
+lusolve (const SparseComplexMatrix&, const SparseComplexMatrix&, 
+        ComplexMatrix&);
+
+template static octave_idx_type
+lusolve (const Matrix&, const Matrix&, Matrix&);
+
+template static octave_idx_type
+lusolve (const ComplexMatrix&, const ComplexMatrix&, ComplexMatrix&);
+
+template static ComplexMatrix
+ltsolve (const SparseComplexMatrix&, const ColumnVector&, 
+        const ComplexMatrix&);
+
+template static Matrix
+ltsolve (const SparseMatrix&, const ColumnVector&, const Matrix&);
+
+template static ComplexMatrix
+ltsolve (const ComplexMatrix&, const ColumnVector&, const ComplexMatrix&);
+
+template static Matrix
+ltsolve (const Matrix&, const ColumnVector&, const Matrix&);
+
+template static ComplexMatrix
+utsolve (const SparseComplexMatrix&, const ColumnVector&,
+        const ComplexMatrix&);
+
+template static Matrix
+utsolve (const SparseMatrix&, const ColumnVector&, const Matrix&);
+
+template static ComplexMatrix
+utsolve (const ComplexMatrix&, const ColumnVector&, const ComplexMatrix&);
+
+template static Matrix
+utsolve (const Matrix&, const ColumnVector&, const Matrix&);
+#endif
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
diff --git a/scripts/sparse/Makefile.in b/scripts/sparse/Makefile.in
--- a/scripts/sparse/Makefile.in
+++ b/scripts/sparse/Makefile.in
@@ -35,7 +35,7 @@
 SOURCES = cgs.m colperm.m etreeplot.m gplot.m nonzeros.m normest.m \
   pcg.m pcr.m spalloc.m spaugment.m spconvert.m spdiags.m speye.m \
   spfun.m sphcat.m spones.m sprand.m sprandn.m sprandsym.m spstats.m \
-  spvcat.m spy.m treelayout.m treeplot.m
+  spvcat.m spy.m svds.m treelayout.m treeplot.m
 
 DISTFILES = $(addprefix $(srcdir)/, Makefile.in $(SOURCES))
 
diff --git a/scripts/sparse/svds.m b/scripts/sparse/svds.m
new file mode 100755
--- /dev/null
+++ b/scripts/sparse/svds.m
@@ -0,0 +1,231 @@
+## Copyright (C) 2006 David Bateman
+##
+## 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, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} address@hidden =} svds (@var{a})
+## @deftypefnx {Function File} address@hidden =} svds (@var{a}, @var{k})
+## @deftypefnx {Function File} address@hidden =} svds (@var{a}, @var{k}, 
@var{sigma})
+## @deftypefnx {Function File} address@hidden =} svds (@var{a}, @var{k}, 
@var{sigma}, @var{opts})
+## @deftypefnx {Function File} address@hidden, @var{s}, @var{v}, @var{flag}] 
=} svds (@dots{})
+##
+## Find a few singular values of the matrix @var{a}. The singular values
+## are calculated using 
+##
+## @example
+## @group
+## address@hidden, @var{n}] = size(@var{a})
+## @var{s} = eigs([sparse(@var{m}, @var{m}), @var{a}; @dots{}
+##                 @var{a}', sparse(@var{n}, @var{n})])
+## @end group
+## @end example
+##
+## The eigenvalues returned by @code{eigs} correspond to the singular
+## values of @var{a}. The number of singular values to calculate is given
+## by @var{k}, whose default value is 6.
+## 
+## The argument @var{sigma} can be used to specify which singular values
+## to find. @var{sigma} can be either the string 'L', the default, in 
+## which case the largest singular values of @var{a} are found. Otherwise
+## @var{sigma} should be a real scalar, in which case the singular values
+## closest to @var{sigma} are found. Note that for relatively small values
+## of @var{sigma}, there is the chance that the requested number of singular
+## values are not returned. In that case @var{sigma} should be increased.
+##
+## If @var{opts} is given, then it is a structure that defines options
+## that @code{svds} will pass to @var{eigs}. The possible fields of this
+## structure are therefore determined by @code{eigs}. By default three
+## fields of this structure are set by @code{svds}.
+##
+## @table @code
+## @item tol
+## The required convergence tolerance for the singular values. @code{eigs}
+## is passed @var{tol} divided by @code{sqrt(2)}. The default value is 
+## 1e-10.
+##
+## @item maxit
+## The maximum number of iterations. The defaut is 300.
+##
+## @item disp
+## The level of diagnostic printout. If @code{disp} is 0 then there is no
+## printout. The default value is 0.
+## @end table
+##
+## If more than one output argument is given, then @code{svds} also
+## calculates the left and right singular vectors of @var{a}. @var{flag}
+## is used to signal the convergence of @code{svds}. If @code{svds} 
+## converges to the desired tolerance, then @var{flag} given by
+##
+## @example
+## @group
+## norm (@var{a} * @var{v} - @var{u} * @var{s}, 1) <= @dots{}
+##         @var{tol} * norm (@var{a}, 1)
+## @end group
+## @end example
+##
+## will be zero.
+## @end deftypefn
+## @seealso{eigs}
+
+function [u, s, v, flag] = svds (a, k, sigma, opts)
+
+  if (nargin < 1 || nargin > 4)
+    error ("Incorrect number of arguments");
+  endif
+
+  if (nargin < 4)
+    opts.tol = 1e-10 / sqrt(2);
+    opts.disp = 0;
+    opts.maxit = 300;
+  else
+    if (!isstruct(opts))
+      error("opts must be a structure");
+    endif
+    if (!isfield(opts,"tol"))
+      opts.tol = 1e-10 / sqrt(2);
+    endif
+  endif
+
+  if (nargin < 3 || strcmp(sigma,"L"))
+    if (isreal(a))
+      sigma = "LA";
+    else
+      sigma = "LR";
+    endif
+  elseif (isscalar(sigma) && isreal(sigma))
+    if ((sigma < 0))
+      error ("sigma must be a positive real value");
+    endif
+  else
+    error ("sigma must be a positive real value or the string 'L'");
+  endif
+
+  maxA = max(max(abs(a)));
+  if (maxA == 0)
+    u = eye(m, k);
+    s = zeros(k, k);
+    v = eye(n, k);
+  else
+    [m, n] = size(a);
+    if (nargin < 2)
+      k = min([6, m, n]);
+    else
+      k = min([k, m, n]);
+    endif
+
+    ## Scale everything by the 1-norm to make things more stable.
+    B = a / maxA;
+    Bopts = opts;
+    Bopts.tol = opts.tol / maxA;
+    Bsigma = sigma;
+    if (!ischar(Bsigma))
+      Bsigma = Bsigma / maxA;
+    endif
+
+    if (!ischar(Bsigma) && Bsigma == 0)
+      ## The eigenvalues returns by eigs are symmetric about 0. As we 
+      ## are only interested in the positive eigenvalues, we have to
+      ## double k. If sigma is smaller than the smallest singular value
+      ## this can also be an issue. However, we'd like to avoid double
+      ## k for all scalar value of sigma...
+      [V, s, flag] = eigs ([sparse(m,m), B; B', sparse(n,n)], 
+                          2 * k, Bsigma, Bopts);
+    else
+      [V, s, flag] = eigs ([sparse(m,m), B; B', sparse(n,n)],
+                          k, Bsigma, Bopts);
+    endif
+    s = diag(s);
+
+    if (ischar(sigma))
+      norma = max(s);
+    else
+      norma = normest(a);
+    endif
+    V = sqrt(2) * V;
+    u = V(1:m,:);
+    v = V(m+1:end,:);
+
+    ## We wish to exclude all eigenvalues that are less than zero as these
+    ## are artifacts of the way the matrix passed to eigs is formed. There 
+    ## is also the possibility that the value of sigma chosen is exactly 
+    ## a singular value, and in that case we're dead!! So have to rely on 
+    ## the warning from eigs. We exclude the singular values which are
+    ## less than or equal to zero to within some tolerance scaled by the
+    ## norm since if we don't we might end up with too many singular
+    ## values. What is appropriate for the tolerance?
+    tol = norma * opts.tol;
+    ind = find(s > tol);
+    if (length(ind) < k)
+      ## Find the zero eigenvalues of B, Ignore the eigenvalues that are 
+      ## nominally negative.
+      zind = find(abs(s) <= tol);
+      p = min(length(zind), k-length(ind));
+      ind = [ind;zind(1:p)];
+    elseif (length(ind) > k)
+      ind = ind(1:k);
+    endif
+    u = u(:,ind);
+    s = s(ind);
+    v = v(:,ind);
+
+    if (length(s) < k)
+      warning("returning fewer singular values than requested.");
+      if (!ischar(sigma))
+       warning("try increasing the value of sigma");
+      endif
+    endif
+
+    s = s * maxA;
+  endif
+
+  if (nargout < 2)
+    u = s;
+  else
+    s = diag(s);
+    if (nargout > 3)
+      flag = norm(a*v - u*s, 1) > sqrt(2) * opts.tol * norm(a, 1);
+    endif
+  endif
+endfunction
+
+%!shared n, k, a, u, s, v, opts
+%! n = 100;
+%! k = 7;
+%! a = 
sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),0.4*n*ones(1,n),ones(1,n-2)]);
+%! %%a = 
sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)]);
+%! [u,s,v] = svd(full(a));
+%! s = diag(s);
+%! [dum, idx] = sort(abs(s));
+%! s = s(idx);
+%! u = u(:,idx);
+%! v = v(:,idx);
+%! randn('state',42)
+%!test
+%! [u2,s2,v2,flag] = svds(a,k);
+%! s2 = diag(s2);
+%! assert(flag,!1);
+%! assert(s(end:-1:end-k+1), s2, 1e-10); 
+%!test
+%! [u2,s2,v2,flag] = svds(a,k,0);
+%! s2 = diag(s2);
+%! assert(flag,!1);
+%! assert(s(k:-1:1), s2, 1e-10); 
+%!test
+%! idx = floor(n/2);
+%! % Don't put sigma right on a singular value or there are convergence 
+%! sigma = 0.99*s(idx) + 0.01*s(idx+1); 
+%! [u2,s2,v2,flag] = svds(a,k,sigma);
+%! s2 = diag(s2);
+%! assert(flag,!1);
+%! assert(s((idx+floor(k/2)):-1:(idx-floor(k/2))), s2, 1e-10); 
diff --git a/src/DLD-FUNCTIONS/eigs.cc b/src/DLD-FUNCTIONS/eigs.cc
new file mode 100755
--- /dev/null
+++ b/src/DLD-FUNCTIONS/eigs.cc
@@ -0,0 +1,1465 @@
+/*
+
+Copyright (C) 2005 David Bateman
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ov.h"
+#include "defun-dld.h"
+#include "error.h"
+#include "gripes.h"
+#include "quit.h"
+#include "variables.h"
+#include "ov-re-sparse.h"
+#include "ov-cx-sparse.h"
+#include "oct-map.h"
+#include "pager.h"
+#include "unwind-prot.h"
+
+#include "eigs-base.cc"
+
+// Global pointer for user defined function.
+static octave_function *eigs_fcn = 0;
+
+// Have we warned about imaginary values returned from user function?
+static bool warned_imaginary = false;
+
+// Is this a recursive call?
+static int call_depth = 0;
+
+ColumnVector
+eigs_func (const ColumnVector &x, int &eigs_error)
+{
+  ColumnVector retval;
+  octave_value_list args;
+  args(0) = x;
+
+  if (eigs_fcn)
+    {
+      octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args);
+
+      if (error_state)
+       {
+         eigs_error = 1;
+         gripe_user_supplied_eval ("eigs");
+         return retval;
+       }
+
+      if (tmp.length () && tmp(0).is_defined ())
+       {
+         if (! warned_imaginary && tmp(0).is_complex_type ())
+           {
+             warning ("eigs: ignoring imaginary part returned from 
user-supplied function");
+             warned_imaginary = true;
+           }
+
+         retval = ColumnVector (tmp(0).vector_value ());
+
+         if (error_state)
+           {
+             eigs_error = 1;
+             gripe_user_supplied_eval ("eigs");
+           }
+       }
+      else
+       {
+         eigs_error = 1;
+         gripe_user_supplied_eval ("eigs");
+       }
+    }
+
+  return retval;
+}
+
+ComplexColumnVector
+eigs_complex_func (const ComplexColumnVector &x, int &eigs_error)
+{
+  ComplexColumnVector retval;
+  octave_value_list args;
+  args(0) = x;
+
+  if (eigs_fcn)
+    {
+      octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args);
+
+      if (error_state)
+       {
+         eigs_error = 1;
+         gripe_user_supplied_eval ("eigs");
+         return retval;
+       }
+
+      if (tmp.length () && tmp(0).is_defined ())
+       {
+         retval = ComplexColumnVector (tmp(0).complex_vector_value ());
+
+         if (error_state)
+           {
+             eigs_error = 1;
+             gripe_user_supplied_eval ("eigs");
+           }
+       }
+      else
+       {
+         eigs_error = 1;
+         gripe_user_supplied_eval ("eigs");
+       }
+    }
+
+  return retval;
+}
+
+DEFUN_DLD (eigs, args, nargout,
+  "-*- texinfo -*-\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{k})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{k}, 
@var{sigma})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{k}, 
@var{sigma},@var{opts})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{b})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{b}, 
@var{k})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{b}, 
@var{k}, @var{sigma})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{a}, @var{b}, 
@var{k}, @var{sigma}, @var{opts})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{b})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{k})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{b}, @var{k})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{k}, @var{sigma})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{b}, @var{k}, @var{sigma})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{k}, @var{sigma}, @var{opts})\n\
address@hidden {Loadable Function} address@hidden = eigs (@var{af}, @var{n}, 
@var{b}, @var{k}, @var{sigma}, @var{opts})\n\
address@hidden {Loadable Function} address@hidden, @var{d}]} = eigs (@var{a}, 
@dots{})\n\
address@hidden {Loadable Function} address@hidden, @var{d}]} = eigs (@var{af}, 
@var{n}, @dots{})\n\
address@hidden {Loadable Function} address@hidden, @var{d}, @var{flag}]} = eigs 
(@var{a}, @dots{})\n\
address@hidden {Loadable Function} address@hidden, @var{d}, @var{flag}]} = eigs 
(@var{af}, @var{n}, @dots{})\n\
+Calculate a limited number of eigenvalues and eigenvectors of @var{a},\n\
+based on a selection criteria. The number eigenvalues and eigenvectors to\n\
+calculate is given by @var{k} whose default value is 6.\n\
+\n\
+By default @code{eigs} solve the equation\n\
address@hidden
address@hidden
+$A \\nu = \\lambda \\nu$\n\
address@hidden tex\n\
address@hidden iftex\n\
address@hidden
address@hidden * v = lambda * v}\n\
address@hidden ifinfo\n\
+, where\n\
address@hidden
address@hidden
+$\\lambda$ is a scalar representing one of the eigenvalues, and $\\nu$\n\
address@hidden tex\n\
address@hidden iftex\n\
address@hidden
address@hidden is a scalar representing one of the eigenvalues, and @code{v}\n\
address@hidden ifinfo\n\
+is the corresponding eigenvector. If given the positive definite matrix\n\
address@hidden then @code{eigs} solves the general eigenvalue equation\n\
address@hidden
address@hidden
+$A \\nu = \\lambda B \\nu$\n\
address@hidden tex\n\
address@hidden iftex\n\
address@hidden
address@hidden * v = lambda * B * v}\n\
address@hidden ifinfo\n\
+.\n\
+\n\
+The argument @var{sigma} determines which eigenvalues are returned.\n\
address@hidden can be either a scalar or a string. When @var{sigma} is a 
scalar,\n\
+the @var{k} eigenvalues closest to @var{sigma} are returned. If @var{sigma}\n\
+is a string, it must have one of the values\n\
+\n\
address@hidden @asis\n\
address@hidden 'lm'\n\
+Largest magnitude (default).\n\
+\n\
address@hidden 'sm'\n\
+Smallest magnitude.\n\
+\n\
address@hidden 'la'\n\
+Largest Algebraic (valid only for real symmetric problems).\n\
+\n\
address@hidden 'sa'\n\
+Smallest Algebraic (valid only for real symmetric problems).\n\
+\n\
address@hidden 'be'\n\
+Both ends, with one more from the high-end if @var{k} is odd (valid only for\n\
+real symmetric problems).\n\
+\n\
address@hidden 'lr'\n\
+Largest real part (valid only for complex or unsymmetric problems).\n\
+\n\
address@hidden 'sr'\n\
+Smallest real part (valid only for complex or unsymmetric problems).\n\
+\n\
address@hidden 'li'\n\
+Largest imaginary part (valid only for complex or unsymmetric problems).\n\
+\n\
address@hidden 'si'\n\
+Smallest imaginary part (valid only for complex or unsymmetric problems).\n\
address@hidden table\n\
+\n\
+If @var{opts} is given, it is a structure defining some of the options that\n\
address@hidden should use. The fields of the structure @var{opts} are\n\
+\n\
address@hidden @code\n\
address@hidden issym\n\
+If @var{af} is given, then flags whether the function @var{af} defines a\n\
+symmetric problem. It is ignored if @var{a} is given. The default is false.\n\
+\n\
address@hidden isreal\n\
+If @var{af} is given, then flags whether the function @var{af} defines a\n\
+real problem. It is ignored if @var{a} is given. The default is true.\n\
+\n\
address@hidden tol\n\
+Defines the required convergence tolerance, given as @code{tol * norm (A)}.\n\
+The default is @code{eps}.\n\
+\n\
address@hidden maxit\n\
+The maximum number of iterations. The default is 300.\n\
+\n\
address@hidden p\n\
+The number of Lanzcos basis vectors to use. More vectors will result in\n\
+faster convergence, but a larger amount of memory. The optimal value of 'p'\n\
+is problem dependent and should be in the range @var{k} to @var{n}. The\n\
+default value is @code{2 * @var{k}}.\n\
+\n\
address@hidden v0\n\
+The starting vector for the computation. The default is to have @sc{Arpack}\n\
+randomly generate a starting vector.\n\
+\n\
address@hidden disp\n\
+The level of diagnostic printout. If @code{disp} is 0 then there is no\n\
+printout. The default value is 1.\n\
+\n\
address@hidden cholB\n\
+Flag if @code{chol (@var{b})} is passed rather than @var{b}. The default is\n\
+false.\n\
+\n\
address@hidden permB\n\
+The permutation vector of the Cholesky factorization of @var{b} if\n\
address@hidden is true. That is @code{chol ( @var{b} (permB, permB))}. The\n\
+default is @code{1:@var{n}}.\n\
+\n\
address@hidden table\n\
+\n\
+It is also possible to represent @var{a} by a function denoted @var{af}.\n\
address@hidden must be followed by a scalar argument @var{n} defining the 
length\n\
+of the vector argument accepted by @var{af}. @var{af} can be passed either\n\
+as an inline function, function handle or as a string. In the case where\n\
address@hidden is passed as a string, the name of the string defines the 
function\n\
+to use.\n\
+\n\
address@hidden is a function of the form @code{function y = af (x), y = 
@dots{};\n\
+endfunction}, where the required return value of @var{af} is determined by\n\
+the value of @var{sigma}, and are\n\
+\n\
address@hidden @code\n\
address@hidden A * x\n\
+If @var{sigma} is not given or is a string other than 'sm'.\n\
+\n\
address@hidden A \\ x\n\
+If @var{sigma} is 'sm'.\n\
+\n\
address@hidden (A - sigma * I) \\ x\n\
+for standard eigenvalue problem, where @code{I} is the identity matrix of\n\
+the same size as @code{A}. If @var{sigma} is zero, this reduces the\n\
address@hidden \\ x}.\n\
+\n\
address@hidden (A - sigma * B) \\ x\n\
+for the general eigenvalue problem.\n\
address@hidden table\n\
+\n\
+The return arguments of @code{eigs} depends on the number of return\n\
+arguments. With a single return argument, a vector @var{d} of length @var{k}\n\
+is returned, represent the @var{k} eigenvalues that have been found. With 
two\n\
+return arguments, @var{v} is a @address@hidden matrix whose columns are\n\
+the @var{k} eigenvectors corresponding to the returned eigenvalues. The\n\
+eigenvalues themselves are then returned in @var{d} in the form of a\n\
address@hidden@var{k} matrix, where the elements on the diagonal are the\n\
+eigenvalues.\n\
+\n\
+Given a third return argument @var{flag}, @code{eigs} also returns the 
status\n\
+of the convergence. If @var{flag} is 0, then all eigenvalues have converged,\n\
+otherwise not.\n\
+\n\
+This function is based on the @sc{Arpack} package, written by R Lehoucq,\n\
+K Maschhoff, D Sorensen and C Yang. For more information see\n\
address@hidden://www.caam.rice.edu/software/ARPACK/}.\n\
+\n\
address@hidden deftypefn\n\
address@hidden, svds}")
+{
+  octave_value_list retval;
+#ifdef HAVE_ARPACK
+  int nargin = args.length ();
+  std::string fcn_name;
+  octave_idx_type n = 0;
+  octave_idx_type k = 6;
+  Complex sigma = 0.;
+  double sigmar, sigmai;
+  bool have_sigma = false;
+  std::string typ = "LM";
+  Matrix amm, bmm, bmt;
+  ComplexMatrix acm, bcm, bct;
+  SparseMatrix asmm, bsmm, bsmt;
+  SparseComplexMatrix ascm, bscm, bsct;
+  int b_arg = 0;
+  bool have_b = false;
+  bool have_a_fun = false;
+  bool a_is_complex = false;
+  bool b_is_complex = false;
+  bool symmetric = false;
+  bool cholB = false;
+  bool a_is_sparse = false;
+  ColumnVector permB;
+  int arg_offset = 0;
+  double tol = DBL_EPSILON;
+  int maxit = 300;
+  int disp = 0;
+  octave_idx_type p = -1;
+  ColumnVector resid;
+  ComplexColumnVector cresid;
+  octave_idx_type info = 1;
+  char bmat = 'I';
+
+  warned_imaginary = false;
+
+  unwind_protect::begin_frame ("Feigs");
+
+  unwind_protect_int (call_depth);
+  call_depth++;
+
+  if (call_depth > 1)
+    {
+      error ("eigs: invalid recursive call");
+      if (fcn_name.length())
+       clear_function (fcn_name);
+      unwind_protect::run_frame ("Feigs");
+      return retval;
+    }
+
+  if (nargin == 0)
+    print_usage ();
+  else if (args(0).is_function_handle () || args(0).is_inline_function () ||
+      args(0).is_string ())
+    {
+      if (args(0).is_string ())
+       {
+         std::string name = args(0).string_value ();
+         std::string fname = "function y = ";
+         fcn_name = unique_symbol_name ("__eigs_fcn_");
+         fname.append (fcn_name);
+         fname.append ("(x) y = ");
+         eigs_fcn = extract_function (args(0), "eigs", fcn_name, fname,
+                                      "; endfunction");
+       }
+      else
+       eigs_fcn = args(0).function_value ();
+
+      if (!eigs_fcn)
+       error ("eigs: unknown function");
+
+      if (nargin < 2)
+       error ("eigs: incorrect number of arguments");
+      else
+       {
+         n = args(1).nint_value ();
+         arg_offset = 1;
+         have_a_fun = true;
+       }
+    }
+  else
+    {
+      if (args(0).is_complex_type ())
+       {
+         if (args(0).is_sparse_type ())
+           {
+             ascm = (args(0).sparse_complex_matrix_value());
+             a_is_sparse = true;
+           }
+         else
+           acm = (args(0).complex_matrix_value());
+         a_is_complex = true;
+         symmetric = false; // ARAPACK doesn't special case complex symmetric
+       }
+      else
+       {
+         if (args(0).is_sparse_type ())
+           {
+             asmm = (args(0).sparse_matrix_value());
+             a_is_sparse = true;
+             symmetric = asmm.is_symmetric();
+           }
+         else
+           {
+             amm = (args(0).matrix_value());
+             symmetric = amm.is_symmetric();
+           }
+       }
+
+      // Note hold off reading B till later to avoid issues of double 
+      // copies of the matrix if B is full/real while A is complex..
+      if (!error_state && nargin > 1 && 
+         !(args(1).is_real_scalar ()))
+       if (args(1).is_complex_type ())
+         {
+           b_arg = 1+arg_offset;
+           have_b = true;
+           bmat = 'G';
+           b_is_complex = true;
+           arg_offset++;
+         }
+       else
+         {
+           b_arg = 1+arg_offset;
+           have_b = true;
+           bmat = 'G';
+           arg_offset++;
+         }
+    }
+
+  if (!error_state && nargin > (1+arg_offset))
+    k = args(1+arg_offset).nint_value ();
+
+  if (!error_state && nargin > (2+arg_offset))
+    if (args(2+arg_offset).is_real_scalar () ||
+       args(2+arg_offset).is_complex_scalar ())
+      {
+       sigma = args(2+arg_offset).complex_value ();
+       have_sigma = true;
+      }
+    else if (args(2+arg_offset).is_string ())
+      {
+       typ = args(2+arg_offset).string_value ();
+
+       // Use STL function to convert to upper case
+       transform (typ.begin (), typ.end (), typ.begin (), toupper);
+
+       sigma = 0.;
+      }
+    else
+      error ("eigs: sigma must be a scalar or a string");
+
+  sigmar = std::real (sigma);
+  sigmai = std::imag (sigma);
+
+  if (!error_state && nargin > (3+arg_offset))
+    if (args(3+arg_offset).is_map ())
+      {
+       Octave_map map = args(3+arg_offset).map_value ();
+
+       // issym is ignored if A is not a function
+       if (map.contains ("issym"))
+         if (have_a_fun)
+           symmetric = map.contents ("issym")(0).double_value () != 0.;
+
+       // isreal is ignored if A is not a function
+       if (map.contains ("isreal"))
+         if (have_a_fun)
+           a_is_complex = ! (map.contents ("isreal")(0).double_value () != 0.);
+
+       if (map.contains ("tol"))
+         tol = map.contents ("tol")(0).double_value ();
+
+       if (map.contains ("maxit"))
+         maxit = map.contents ("maxit")(0).nint_value ();
+
+       if (map.contains ("p"))
+         p = map.contents ("p")(0).nint_value ();
+
+       if (map.contains ("v0"))
+         {
+           if (a_is_complex || b_is_complex)
+             cresid = ComplexColumnVector 
+               (map.contents ("v0")(0).complex_vector_value());
+           else
+             resid = ColumnVector (map.contents ("v0")(0).vector_value());
+         }
+
+       if (map.contains ("disp"))
+         disp = map.contents ("disp")(0).nint_value ();
+
+       if (map.contains ("cholB"))
+         cholB = map.contents ("cholB")(0).double_value () != 0.;
+
+       if (map.contains ("permB"))
+         permB = ColumnVector (map.contents ("permB")(0).vector_value ()) 
+           - 1.0;
+      }
+    else
+      error ("eigs: options argument must be a structure");
+
+  if (nargin > (4+arg_offset))
+    error ("eigs: incorrect number of arguments");
+
+  if (have_b)
+    {
+      if (a_is_complex || b_is_complex)
+       {
+         if (a_is_sparse)
+           bscm = args(b_arg).sparse_complex_matrix_value ();
+         else
+           bcm = args(b_arg).complex_matrix_value ();
+       }
+      else
+       {
+         if (a_is_sparse)
+           bsmm = args(b_arg).sparse_matrix_value ();
+         else
+           bmm = args(b_arg).matrix_value ();
+       }
+    }
+
+  // Mode 1 for SM mode seems unstable for some reason. 
+  // Use Mode 3 instead, with sigma = 0.
+  if (!error_state && !have_sigma && typ == "SM")
+    have_sigma = true;
+
+  if (!error_state)
+    {
+      octave_idx_type nconv;
+      if (a_is_complex || b_is_complex)
+       {
+         ComplexMatrix eig_vec;
+         ComplexColumnVector eig_val;
+
+
+         if (have_a_fun)
+           nconv = EigsComplexNonSymmetricFunc 
+             (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec, eig_val,
+              cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+         else if (have_sigma)
+           if (a_is_sparse)
+             nconv = EigsComplexNonSymmetricMatrixShift
+               (ascm, sigma, k, p, info, eig_vec, eig_val, bscm, permB,
+                cresid, octave_stdout, tol, (nargout > 1), cholB, disp, 
+                maxit);
+           else
+             nconv = EigsComplexNonSymmetricMatrixShift
+               (acm, sigma, k, p, info, eig_vec, eig_val, bcm, permB, cresid,
+                octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+         else
+           if (a_is_sparse)
+             nconv = EigsComplexNonSymmetricMatrix
+               (ascm, typ, k, p, info, eig_vec, eig_val, bscm, permB, cresid,
+                octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+           else
+             nconv = EigsComplexNonSymmetricMatrix
+               (acm, typ, k, p, info, eig_vec, eig_val, bcm, permB, cresid,
+                octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+
+         if (nargout < 2)
+           retval (0) = eig_val;
+         else
+           {
+             retval(2) = double (info);
+             retval(1) = ComplexDiagMatrix (eig_val);
+             retval(0) = eig_vec;
+           }
+       }
+      else if (sigmai != 0.)
+       {
+         // Promote real problem to a complex one.
+         ComplexMatrix eig_vec;
+         ComplexColumnVector eig_val;
+
+         if (have_a_fun)
+           nconv = EigsComplexNonSymmetricFunc 
+             (eigs_complex_func, n, typ,  sigma, k, p, info, eig_vec, eig_val,
+              cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+         else
+           if (a_is_sparse)
+             nconv = EigsComplexNonSymmetricMatrixShift 
+               (SparseComplexMatrix (asmm), sigma, k, p, info, eig_vec,
+                eig_val, SparseComplexMatrix (bsmm), permB, cresid,
+                octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+           else
+             nconv = EigsComplexNonSymmetricMatrixShift 
+               (ComplexMatrix (amm), sigma, k, p, info, eig_vec,
+                eig_val, ComplexMatrix (bmm), permB, cresid,
+                octave_stdout, tol, (nargout > 1), cholB, disp, maxit);
+
+         if (nargout < 2)
+           retval (0) = eig_val;
+         else
+           {
+             retval(2) = double (info);
+             retval(1) = ComplexDiagMatrix (eig_val);
+             retval(0) = eig_vec;
+           }
+       }
+      else
+       {
+         if (symmetric)
+           {
+             Matrix eig_vec;
+             ColumnVector eig_val;
+
+             if (have_a_fun)
+               nconv = EigsRealSymmetricFunc 
+                 (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val,
+                  resid, octave_stdout, tol, (nargout > 1), cholB, disp, 
+                  maxit);
+             else if (have_sigma)
+               if (a_is_sparse)
+                 nconv = EigsRealSymmetricMatrixShift 
+                   (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp, 
+                    maxit);
+               else
+                 nconv = EigsRealSymmetricMatrixShift 
+                   (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+             else
+               if (a_is_sparse)
+                 nconv = EigsRealSymmetricMatrix 
+                   (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+               else
+                 nconv = EigsRealSymmetricMatrix 
+                   (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+
+             if (nargout < 2)
+               retval (0) = eig_val;
+             else
+               {
+                 retval(2) = double (info);
+                 retval(1) = DiagMatrix (eig_val);
+                 retval(0) = eig_vec;
+               }
+           }
+         else
+           {
+             ComplexMatrix eig_vec;
+             ComplexColumnVector eig_val;
+
+             if (have_a_fun)
+               nconv = EigsRealNonSymmetricFunc 
+                 (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val,
+                  resid, octave_stdout, tol, (nargout > 1), cholB, disp, 
+                  maxit);
+             else if (have_sigma)
+               if (a_is_sparse)
+                 nconv = EigsRealNonSymmetricMatrixShift 
+                   (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp, 
+                    maxit);
+               else
+                 nconv = EigsRealNonSymmetricMatrixShift 
+                   (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+             else
+               if (a_is_sparse)
+                 nconv = EigsRealNonSymmetricMatrix 
+                   (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+               else
+                 nconv = EigsRealNonSymmetricMatrix 
+                   (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB,
+                    resid, octave_stdout, tol, (nargout > 1), cholB, disp,
+                    maxit);
+
+             if (nargout < 2)
+               retval (0) = eig_val;
+             else
+               {
+                 retval(2) = double (info);
+                 retval(1) = ComplexDiagMatrix (eig_val);
+                 retval(0) = eig_vec;
+               }
+           }
+       }
+
+      if (nconv <= 0)
+       warning ("eigs: None of the %d requested eigenvalues converged", k);
+      else if (nconv < k)
+       warning ("eigs: Only %d of the %d requested eigenvalues converged", 
+                nconv, k);
+    }
+
+  if (! fcn_name.empty ())
+    clear_function (fcn_name);
+
+  unwind_protect::run_frame ("Feigs");
+#else
+  error ("eigs: not available in this version of Octave");
+#endif
+
+  return retval;
+}
+
+/* #### SPARSE MATRIX VERSIONS #### */
+
+/*
+
+%% Real positive definite tests, n must be even
+%!shared n, k, A, d0, d2
+%! n = 20;
+%! k = 4;
+%! A = 
sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)]);
+%! d0 = eig (A);
+%! d2 = sort(d0);
+%! [dum, idx] = sort( abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (d1, d0(end:-1:(end-k)),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (d1, d0(k:-1:1), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'la');
+%! assert (d1, d2(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sa');
+%! assert (d1, d2(1:k), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'be');
+%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-12);
+%!test
+%! d1 = eigs (A, k+1, 'be');
+%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (d1(idx1), d0(idx0(1:k)), 1e-12);
+%!test
+%! d1 = eigs(A, speye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!assert (eigs(A,k,4.1), eigs(A,speye(n),k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!assert (eigs(A,k,4.1), eigs(A,speye(n),k,4.1), 1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (d1, d0(k:-1:1), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (d1, eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'la');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sa');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'be');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/*
+
+%% Real unsymmetric tests
+%!shared n, k, A, d0
+%! n = 20;
+%! k = 4;
+%! A =  
sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)]);
+%! d0 = eig (A);
+%! [dum, idx] = sort(abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (abs(d1), abs(d0(end:-1:(end-k))),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (abs(d1), abs(d0(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'lr');
+%! [dum, idx] = sort (real(d0));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'li');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(end:-1:(end-k+1)))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'si');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(1:k))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (abs(d1(idx1)), abs(d0(idx0(1:k))), 1e-12);
+%! assert (sort(imag(d1(idx1))), sort(imag(d0(idx0(1:k)))), 1e-12);
+%!test
+%! d1 = eigs(A, speye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!assert (abs(eigs(A,k,4.1)), abs(eigs(A,speye(n),k,4.1)), 1e-12);
+%!assert (sort(imag(eigs(A,k,4.1))), sort(imag(eigs(A,speye(n),k,4.1))), 
1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (abs(d1), d0(1:k), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'lr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'li');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'si');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/*
+
+%% Complex hermitian tests
+%!shared n, k, A, d0
+%! n = 20;
+%! k = 4;
+%! A = 
sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)]);
+%! d0 = eig (A);
+%! [dum, idx] = sort(abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (abs(d1), abs(d0(end:-1:(end-k))),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (abs(d1), abs(d0(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'lr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'li');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(end:-1:(end-k+1)))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'si');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(1:k))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (abs(d1(idx1)), abs(d0(idx0(1:k))), 1e-12);
+%! assert (sort(imag(d1(idx1))), sort(imag(d0(idx0(1:k)))), 1e-12);
+%!test
+%! d1 = eigs(A, speye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, speye(n), k, 4.1, opts);
+%! assert (abs(abs(d1)), abs(eigs(A,k,4.1)), 1e-12);
+%! assert (sort(imag(abs(d1))), sort(imag(eigs(A,k,4.1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, speye(n)(q,q), k, 4.1, opts);
+%! assert (abs(abs(d1)), abs(eigs(A,k,4.1)), 1e-12);
+%! assert (sort(imag(abs(d1))), sort(imag(eigs(A,k,4.1))), 1e-12);
+%!assert (abs(eigs(A,k,4.1)), abs(eigs(A,speye(n),k,4.1)), 1e-12);
+%!assert (sort(imag(eigs(A,k,4.1))), sort(imag(eigs(A,speye(n),k,4.1))), 
1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (abs(d1), d0(1:k), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'lr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'li');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'si');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*speye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/* #### FULL MATRIX VERSIONS #### */
+
+/*
+
+%% Real positive definite tests, n must be even
+%!shared n, k, A, d0, d2
+%! n = 20;
+%! k = 4;
+%! A = 
full(sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)]));
+%! d0 = eig (A);
+%! d2 = sort(d0);
+%! [dum, idx] = sort( abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (d1, d0(end:-1:(end-k)),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (d1, d0(k:-1:1), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'la');
+%! assert (d1, d2(end:-1:(end-k+1)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sa');
+%! assert (d1, d2(1:k), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'be');
+%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-12);
+%!test
+%! d1 = eigs (A, k+1, 'be');
+%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (d1(idx1), d0(idx0(1:k)), 1e-12);
+%!test
+%! d1 = eigs(A, eye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!assert (eigs(A,k,4.1), eigs(A,eye(n),k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!assert (eigs(A,k,4.1), eigs(A,eye(n),k,4.1), 1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (d1, d0(end:-1:(end-k+1)), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (d1, d0(k:-1:1), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 1; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (d1, eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'la');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sa');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'be');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/*
+
+%% Real unsymmetric tests
+%!shared n, k, A, d0
+%! n = 20;
+%! k = 4;
+%! A =  
full(sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)]));
+%! d0 = eig (A);
+%! [dum, idx] = sort(abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (abs(d1), abs(d0(end:-1:(end-k))),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (abs(d1), abs(d0(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'lr');
+%! [dum, idx] = sort (real(d0));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'li');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(end:-1:(end-k+1)))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'si');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(1:k))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (abs(d1(idx1)), abs(d0(idx0(1:k))), 1e-12);
+%! assert (sort(imag(d1(idx1))), sort(imag(d0(idx0(1:k)))), 1e-12);
+%!test
+%! d1 = eigs(A, eye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!assert (abs(eigs(A,k,4.1)), abs(eigs(A,eye(n),k,4.1)), 1e-12);
+%!assert (sort(imag(eigs(A,k,4.1))), sort(imag(eigs(A,eye(n),k,4.1))), 1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (abs(d1), d0(1:k), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 0; opts.isreal = 1;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'lr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'li');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'si');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/*
+
+%% Complex hermitian tests
+%!shared n, k, A, d0
+%! n = 20;
+%! k = 4;
+%! A = 
full(sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)]));
+%! d0 = eig (A);
+%! [dum, idx] = sort(abs(d0));
+%! d0 = d0(idx);
+%!test
+%! d1 = eigs (A, k);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A,k+1);
+%! assert (abs(d1), abs(d0(end:-1:(end-k))),1e-12);
+%!test
+%! d1 = eigs (A, k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sm');
+%! assert (abs(d1), abs(d0(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'lr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(end:-1:(end-k+1))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'sr');
+%! [dum, idx] = sort (real(abs(d0)));
+%! d2 = d0(idx);
+%! assert (real(d1), real(d2(1:k)), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'li');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(end:-1:(end-k+1)))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 'si');
+%! [dum, idx] = sort (imag(abs(d0)));
+%! d2 = d0(idx);
+%! assert (sort(imag(d1)), sort(imag(d2(1:k))), 1e-12);
+%!test
+%! d1 = eigs (A, k, 4.1);
+%! [dum,idx0] = sort (abs(d0 - 4.1));
+%! [dum,idx1] = sort (abs(d1 - 4.1));
+%! assert (abs(d1(idx1)), abs(d0(idx0(1:k))), 1e-12);
+%! assert (sort(imag(d1(idx1))), sort(imag(d0(idx0(1:k)))), 1e-12);
+%!test
+%! d1 = eigs(A, eye(n), k, 'lm');
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! d1 = eigs(A, eye(n), k, 4.1, opts);
+%! assert (abs(abs(d1)), abs(eigs(A,k,4.1)), 1e-12);
+%! assert (sort(imag(abs(d1))), sort(imag(eigs(A,k,4.1))), 1e-12);
+%!test
+%! opts.cholB=true;
+%! q = [2:n,1];
+%! opts.permB=q;
+%! d1 = eigs(A, eye(n)(q,q), k, 4.1, opts);
+%! assert (abs(abs(d1)), abs(eigs(A,k,4.1)), 1e-12);
+%! assert (sort(imag(abs(d1))), sort(imag(eigs(A,k,4.1))), 1e-12);
+%!assert (abs(eigs(A,k,4.1)), abs(eigs(A,eye(n),k,4.1)), 1e-12);
+%!assert (sort(imag(eigs(A,k,4.1))), sort(imag(eigs(A,eye(n),k,4.1))), 1e-12);
+%!test
+%! fn = @(x) A * x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 'lm', opts);
+%! assert (abs(d1), abs(d0(end:-1:(end-k+1))), 1e-12);
+%!test
+%! fn = @(x) A \ x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 'sm', opts);
+%! assert (abs(d1), d0(1:k), 1e-12);
+%!test
+%! fn = @(x) (A - 4.1 * eye(n)) \ x;
+%! opts.issym = 0; opts.isreal = 0;
+%! d1 = eigs (fn, n, k, 4.1, opts);
+%! assert (abs(d1), eigs(A,k,4.1), 1e-12);
+%!test
+%! [v1,d1] = eigs(A, k, 'lm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sm');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'lr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'sr');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'li');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+%!test
+%! [v1,d1] = eigs(A, k, 'si');
+%! d1 = diag(d1);
+%! for i=1:k
+%!  assert(max(abs((A - d1(i)*eye(n))*v1(:,i))),0.,1e-12)
+%! endfor
+
+*/
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
diff --git a/src/Makefile.in b/src/Makefile.in
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -65,7 +65,7 @@
 DLD_XSRC := amd.cc balance.cc besselj.cc betainc.cc bsxfun.cc cellfun.cc \
        chol.cc ccolamd.cc colamd.cc colloc.cc conv2.cc convhulln.cc daspk.cc \
        dasrt.cc dassl.cc det.cc dispatch.cc dlmread.cc dmperm.cc eig.cc \
-       expm.cc fft.cc fft2.cc fftn.cc fftw.cc filter.cc find.cc \
+       eigs.cc expm.cc fft.cc fft2.cc fftn.cc fftw.cc filter.cc find.cc \
        fltk_backend.cc \
        gammainc.cc gcd.cc getgrent.cc getpwent.cc getrusage.cc \
        givens.cc hess.cc hex2num.cc inv.cc kron.cc lookup.cc lsode.cc \
@@ -650,6 +650,7 @@
 convhulln.oct: OCT_LINK_DEPS += $(QHULL_LIBS)
 __delaunayn__.oct: OCT_LINK_DEPS += $(QHULL_LIBS)
 __voronoi__.oct: OCT_LINK_DEPS += $(QHULL_LIBS)
+eigs.oct: OCT_LINK_DEPS += $(ARPACK_LIBS)
 regexp.oct: OCT_LINK_DEPS += $(REGEX_LIBS)
 urlwrite.oct: OCT_LINK_DEPS += $(CURL_LIBS)
 __glpk__.oct: OCT_LINK_DEPS += $(GLPK_LIBS)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]