changeset 22183:bfb1b089c230

New function normest1 as replacement for onenormest (patch #8837) * scripts/linear-algebra/normest1.m: new function to replace onenormest so it's Matlab compatible. It works as a drop-in replacement when input is a matrix. Usage with functions as input is no longer supported as it is only a little useful. * scripts/linear-algebra/onenormest.m: moved to deprecated/. * scripts/linear-algebra/module.mk: add normest1, remove onenormest. * scripts/linear-algebra/condest.m: add normest1 syntax. It still accepts onenormest syntax but marked as deprecated. * scripts/deprecated/onenormest.m: moved from linear-algebra/, added deprecation warning. * scripts/deprecated/module.mk: add onenormest. * NEWS: Added normest1 to the list of new functions, made onenormest deprecated. * doc/interpreter/sparse.txi: replace onenormest with normest1.
author Marco Caliari <marco.caliari@univr.it>
date Mon, 25 Jul 2016 14:50:29 +0100
parents eb8667f2faac
children a032ffb80704
files NEWS doc/interpreter/sparse.txi scripts/deprecated/module.mk scripts/deprecated/onenormest.m scripts/linear-algebra/condest.m scripts/linear-algebra/module.mk scripts/linear-algebra/normest1.m scripts/linear-algebra/onenormest.m
diffstat 8 files changed, 898 insertions(+), 327 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Jun 30 18:20:37 2016 +1000
+++ b/NEWS	Mon Jul 25 14:50:29 2016 +0100
@@ -1,6 +1,8 @@
 Summary of important user-visible changes for version 4.2:
 ---------------------------------------------------------
 
+ ** condest now works with a normest1 compatible syntax.
+
  ** The parser has been extended to accept, but ignore, underscore
     characters in numbers.  This facilitates writing more legible code
     by using '_' as a thousands separator or to group nibbles into bytes
@@ -110,6 +112,7 @@
       hash
       im2double
       localfunctions
+      normest1
       ode45
       odeget
       odeset
@@ -130,6 +133,7 @@
       mahalanobis          | mahal in Octave-Forge statistics pkg
       md5sum               | hash
       octve_config_info    | __octave_config_info__
+      onenormest           | normest1
       sleep                | pause
       usleep               | pause
       wavread              | audioread
--- a/doc/interpreter/sparse.txi	Thu Jun 30 18:20:37 2016 +1000
+++ b/doc/interpreter/sparse.txi	Mon Jul 25 14:50:29 2016 +0100
@@ -486,7 +486,7 @@
 
 @item Linear algebra:
   @dfn{condest}, @dfn{eigs}, @dfn{matrix_type},
-  @dfn{normest}, @dfn{sprank}, @dfn{spaugment}, @dfn{svds}
+  @dfn{normest}, @dfn{normest1}, @dfn{sprank}, @dfn{spaugment}, @dfn{svds}
 
 @item Iterative techniques:
   @dfn{ichol}, @dfn{ilu}, @dfn{pcg}, @dfn{pcr}
@@ -830,7 +830,7 @@
 
 @DOCSTRING(normest)
 
-@DOCSTRING(onenormest)
+@DOCSTRING(normest1)
 
 @DOCSTRING(condest)
 
--- a/scripts/deprecated/module.mk	Thu Jun 30 18:20:37 2016 +1000
+++ b/scripts/deprecated/module.mk	Mon Jul 25 14:50:29 2016 +0100
@@ -19,6 +19,7 @@
   scripts/deprecated/nfields.m \
   scripts/deprecated/octave_config_info.m \
   scripts/deprecated/octave_tmp_file_name.m \
+  scripts/deprecated/onenormest.m \
   scripts/deprecated/playaudio.m \
   scripts/deprecated/saveaudio.m \
   scripts/deprecated/setaudio.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/deprecated/onenormest.m	Mon Jul 25 14:50:29 2016 +0100
@@ -0,0 +1,307 @@
+## Copyright (C) 2007-2015 Regents of the University of California
+##
+## 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/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {[@var{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{A}, @var{t})
+## @deftypefnx {} {[@var{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{apply}, @var{apply_t}, @var{n}, @var{t})
+##
+## @code{onenormest} is deprecated and will be removed in Octave version 4.4.
+## Use @code{normest1} for the equivalent functionality.
+##
+## Apply @nospell{Higham and Tisseur's} randomized block 1-norm estimator to
+## matrix @var{A} using @var{t} test vectors.
+##
+## If @var{t} exceeds 5, then only 5 test vectors are used.
+##
+## If the matrix is not explicit, e.g., when estimating the norm of
+## @code{inv (@var{A})} given an LU@tie{}factorization, @code{onenormest}
+## applies @var{A} and its conjugate transpose through a pair of functions
+## @var{apply} and @var{apply_t}, respectively, to a dense matrix of size
+## @var{n} by @var{t}.  The implicit version requires an explicit dimension
+## @var{n}.
+##
+## Returns the norm estimate @var{est}, two vectors @var{v} and @var{w} related
+## by norm @code{(@var{w}, 1) = @var{est} * norm (@var{v}, 1)}, and the number
+## of iterations @var{iter}.  The number of iterations is limited to 10 and is
+## at least 2.
+##
+## References:
+##
+## @itemize
+## @item
+## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
+## for Matrix 1-Norm Estimation, with an Application to 1-Norm
+## Pseudospectra}. SIMAX vol 21, no 4, pp 1185-1201.
+## @url{http://dx.doi.org/10.1137/S0895479899356080}
+##
+## @item
+## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
+## for Matrix 1-Norm Estimation, with an Application to 1-Norm
+## Pseudospectra}. @url{http://citeseer.ist.psu.edu/223007.html}
+## @end itemize
+##
+## @seealso{condest, norm, cond}
+## @end deftypefn
+
+## Code originally licensed under:
+##
+## Copyright (c) 2007, Regents of the University of California
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+##    * Redistributions of source code must retain the above copyright
+##      notice, this list of conditions and the following disclaimer.
+##
+##    * Redistributions in binary form must reproduce the above
+##      copyright notice, this list of conditions and the following
+##      disclaimer in the documentation and/or other materials provided
+##      with the distribution.
+##
+##    * Neither the name of the University of California, Berkeley nor
+##      the names of its contributors may be used to endorse or promote
+##      products derived from this software without specific prior
+##      written permission.
+##
+## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
+## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+## PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND
+## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+## SUCH DAMAGE.
+
+## Author: Jason Riedy <ejr@cs.berkeley.edu>
+## Keywords: linear-algebra norm estimation
+## Version: 0.2
+
+function [est, v, w, iter] = onenormest (varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:deprecated-function",
+             "onenormest is obsolete and will be removed from a future version of Octave, please use normest1 instead");
+  endif
+
+
+  if (nargin < 1 || nargin > 4)
+    print_usage ();
+  endif
+
+  default_t = 5;
+  itmax = 10;
+
+  if (isnumeric (varargin{1}))
+    [n, nc] = size (varargin{1});
+    if (n != nc)
+      error ("onenormest: matrix must be square");
+    endif
+    apply = @(x) varargin{1} * x;
+    apply_t = @(x) varargin{1}' * x;
+    if (nargin > 1)
+      t = varargin{2};
+    else
+      t = min (n, default_t);
+    endif
+    issing = isa (varargin{1}, "single");
+  else
+    if (nargin < 3)
+      print_usage ();
+    endif
+    apply = varargin{1};
+    apply_t = varargin{2};
+    n = varargin{3};
+    if (nargin > 3)
+      t = varargin{4};
+    else
+      t = default_t;
+    endif
+    issing = isa (n, "single");
+  endif
+
+  ## Initial test vectors X.
+  X = rand (n, t);
+  X ./= ones (n,1) * sum (abs (X), 1);
+
+  ## Track if a vertex has been visited.
+  been_there = zeros (n, 1);
+
+  ## To check if the estimate has increased.
+  est_old = 0;
+
+  ## Normalized vector of signs.
+  S = zeros (n, t);
+
+  if (issing)
+    myeps = eps ("single");
+    X = single (X);
+  else
+    myeps = eps;
+  endif
+
+  for iter = 1 : itmax + 1
+    Y = feval (apply, X);
+
+    ## Find the initial estimate as the largest A*x.
+    [est, ind_best] = max (sum (abs (Y), 1));
+    if (est > est_old || iter == 2)
+      w = Y(:,ind_best);
+    endif
+    if (iter >= 2 && est < est_old)
+      ## No improvement, so stop.
+      est = est_old;
+      break;
+    endif
+
+    est_old = est;
+    S_old = S;
+    if (iter > itmax),
+      ## Gone too far.  Stop.
+      break;
+    endif
+
+    S = sign (Y);
+
+    ## Test if any of S are approximately parallel to previous S
+    ## vectors or current S vectors.  If everything is parallel,
+    ## stop.  Otherwise, replace any parallel vectors with
+    ## rand{-1,+1}.
+    partest = any (abs (S_old' * S - n) < 4*eps*n);
+    if (all (partest))
+      ## All the current vectors are parallel to old vectors.
+      ## We've hit a cycle, so stop.
+      break;
+    endif
+    if (any (partest))
+      ## Some vectors are parallel to old ones and are cycling,
+      ## but not all of them.  Replace the parallel vectors with
+      ## rand{-1,+1}.
+      numpar = sum (partest);
+      replacements = 2*(rand (n,numpar) < 0.5) - 1;
+      S(:,partest) = replacements;
+    endif
+    ## Now test for parallel vectors within S.
+    partest = any ((S' * S - eye (t)) == n);
+    if (any (partest))
+      numpar = sum (partest);
+      replacements = 2*(rand (n,numpar) < 0.5) - 1;
+      S(:,partest) = replacements;
+    endif
+
+    Z = feval (apply_t, S);
+
+    ## Now find the largest non-previously-visted index per vector.
+    h = max (abs (Z),2);
+    [mh, mhi] = max (h);
+    if (iter >= 2 && mhi == ind_best)
+      ## Hit a cycle, stop.
+      break;
+    endif
+    [h, ind] = sort (h, 'descend');
+    if (t > 1)
+      firstind = ind(1:t);
+      if (all (been_there(firstind)))
+        ## Visited all these before, so stop.
+        break;
+      endif
+      ind = ind(! been_there(ind));
+      if (length (ind) < t)
+        ## There aren't enough new vectors, so we're practically
+        ## in a cycle.  Stop.
+        break;
+      endif
+    endif
+
+    ## Visit the new indices.
+    X = zeros (n, t);
+    for zz = 1 : t
+      X(ind(zz),zz) = 1;
+    endfor
+    been_there(ind(1 : t)) = 1;
+  endfor
+
+  ## The estimate est and vector w are set in the loop above.
+  ## The vector v selects the ind_best column of A.
+  v = zeros (n, 1);
+  v(ind_best) = 1;
+
+endfunction
+
+
+%!demo
+%! N = 100;
+%! A = randn (N) + eye (N);
+%! [L,U,P] = lu (A);
+%! nm1inv = onenormest (@(x) U\(L\(P*x)), @(x) P'*(L'\(U'\x)), N, 30)
+%! norm (inv (A), 1)
+
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! N = 10;
+%! A = ones (N);
+%! [nm1, v1, w1] = onenormest (A);
+%! [nminf, vinf, winf] = onenormest (A', 6);
+%! assert (nm1, N, -2*eps);
+%! assert (nminf, N, -2*eps);
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
+
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! N = 10;
+%! A = ones (N);
+%! [nm1, v1, w1] = onenormest (@(x) A*x, @(x) A'*x, N, 3);
+%! [nminf, vinf, winf] = onenormest (@(x) A'*x, @(x) A*x, N, 3);
+%! assert (nm1, N, -2*eps);
+%! assert (nminf, N, -2*eps);
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
+
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! N = 5;
+%! A = hilb (N);
+%! [nm1, v1, w1] = onenormest (A);
+%! [nminf, vinf, winf] = onenormest (A', 6);
+%! assert (nm1, norm (A, 1), -2*eps);
+%! assert (nminf, norm (A, inf), -2*eps);
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
+
+## Only likely to be within a factor of 10.
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! old_state = rand ("state");
+%! restore_state = onCleanup (@() rand ("state", old_state));
+%! rand ("state", 42);  # Initialize to guarantee reproducible results
+%! N = 100;
+%! A = rand (N);
+%! [nm1, v1, w1] = onenormest (A);
+%! [nminf, vinf, winf] = onenormest (A', 6);
+%! assert (nm1, norm (A, 1), -.1);
+%! assert (nminf, norm (A, inf), -.1);
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
--- a/scripts/linear-algebra/condest.m	Thu Jun 30 18:20:37 2016 +1000
+++ b/scripts/linear-algebra/condest.m	Mon Jul 25 14:50:29 2016 +0100
@@ -1,4 +1,5 @@
 ## Copyright (C) 2007-2015 Regents of the University of California
+## Copyright (C) 2016 Marco Caliari
 ##
 ## This file is part of Octave.
 ##
@@ -20,8 +21,8 @@
 ## @deftypefn  {} {} condest (@var{A})
 ## @deftypefnx {} {} condest (@var{A}, @var{t})
 ## @deftypefnx {} {[@var{est}, @var{v}] =} condest (@dots{})
-## @deftypefnx {} {[@var{est}, @var{v}] =} condest (@var{A}, @var{solve}, @var{solve_t}, @var{t})
-## @deftypefnx {} {[@var{est}, @var{v}] =} condest (@var{apply}, @var{apply_t}, @var{solve}, @var{solve_t}, @var{n}, @var{t})
+## @deftypefnx {} {[@var{est}, @var{v}] =} condest (@var{A}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {} {[@var{est}, @var{v}] =} condest (@var{afun}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
 ##
 ## Estimate the 1-norm condition number of a matrix @var{A} using @var{t} test
 ## vectors using a randomized 1-norm estimator.
@@ -32,23 +33,39 @@
 ## number of @var{A} given an LU@tie{}factorization, @code{condest} uses the
 ## following functions:
 ##
-## @table @var
-## @item apply
-## @code{A*x} for a matrix @code{x} of size @var{n} by @var{t}.
-##
-## @item apply_t
-## @code{A'*x} for a matrix @code{x} of size @var{n} by @var{t}.
+## @itemize @minus
+## @item @var{afun} which should returns
+## @itemize @bullet
+## @item
+## the dimension @var{n} of @var{a}, if @var{flag} is "dim"
+## @item
+## true if @var{a} is a real operator, if @var{flag} is "real"
+## @item
+## the result @code{@var{a} * @var{x}}, if @var{flag} is "notransp"
+## @item
+## the result @code{@var{a}' * @var{x}}, if @var{flag} is "transp"
+## @end itemize
+## @item @var{solvefun} which should returns
+## @itemize @bullet
+## @item
+## the dimension @var{n} of @var{a}, if @var{flag} is "dim"
+## @item
+## true if @var{a} is a real operator, if @var{flag} is "real"
+## @item
+## the result @code{@var{a} \ @var{x}}, if @var{flag} is "notransp"
+## @item
+## the result @code{@var{a}' \ @var{x}}, if @var{flag} is "transp"
+## @end itemize
+## @end itemize
 ##
-## @item solve
-## @code{A \ b} for a matrix @code{b} of size @var{n} by @var{t}.
+## The parameters @var{p1}, @var{p2}, @dots{} are arguments of
+## @code{@var{afun} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}
+## and @code{@var{solvefun} (@var{flag}, @var{x}, @var{p1}, @var{p2},
+## @dots{})}.
 ##
-## @item solve_t
-## @code{A' \ b} for a matrix @code{b} of size @var{n} by @var{t}.
-## @end table
-##
-## The implicit version requires an explicit dimension @var{n}.
-##
-## @code{condest} uses a randomized algorithm to approximate the 1-norms.
+## @code{condest} uses a randomized algorithm to approximate the
+## 1-norms. Therefore, if consistent results are required, the "state" of the
+## random generator should be fixed before invoking @code{normest1}.
 ##
 ## @code{condest} returns the 1-norm condition estimate @var{est} and a vector
 ## @var{v} satisfying @code{norm (A*v, 1) == norm (A, 1) * norm
@@ -70,7 +87,7 @@
 ## Pseudospectra}. @url{http://citeseer.ist.psu.edu/223007.html}
 ## @end itemize
 ##
-## @seealso{cond, norm, onenormest}
+## @seealso{cond, norm, normest1}
 ## @end deftypefn
 
 ## Code originally licensed under:
@@ -120,10 +137,129 @@
 
   default_t = 5;
 
+  if ((nargin == 3 && is_function_handle (varargin{3}))
+      || (nargin == 4 && is_function_handle (varargin{3})
+          && isnumeric (varargin{4})))
+    ## onenormest syntax, deprecated in 4.2
+    [est, v] = condest_legacy (varargin{:});
+    return
+  elseif ((nargin >= 5) && is_function_handle (varargin{4}))
+    ## onenormest syntax, deprecated in 4.2
+    [est, v] = condest_legacy (varargin{:});
+    return
+  endif
+
+  have_A = false;
+  have_t = false;
+  have_apply_normest1 = false;
+  have_solve_normest1 = false;
+
+  if (isnumeric (varargin{1}))
+    A = varargin{1};
+    if (! issquare (A))
+      error ("condest: matrix must be square");
+    endif
+    n = rows (A);
+    have_A = true;
+    if (nargin > 1)
+      if (is_function_handle (varargin{2}))
+        solve = varargin{2};
+        have_solve_normest1 = true;
+        if (nargin > 2)
+          t = varargin{3};
+          have_t = true;
+        endif
+      else
+        t = varargin{2};
+        have_t = true;
+        real_op = isreal (A);
+      endif
+    else
+      real_op = isreal (A);
+    endif
+  else # varargin{1} is function handle
+    apply = varargin{1};
+    if (nargin > 1)
+      solve = varargin{2};
+      have_apply_normest1 = true;
+      have_solve_normest1 = true;
+      n = apply ("dim", [], varargin{4:end});
+      if (nargin > 2)
+        t = varargin{3};
+        have_t = true;
+      endif
+    else
+      error("condest: wrong number of input parameters");
+    endif
+  endif
+
+  if (! have_t)
+    t = min (n, default_t);
+  endif
+
+  if (! have_solve_normest1)
+     ## prepare solve in normest1 form
+    if (issparse (A))
+      [L, U, P, Pc] = lu (A);
+      solve = @(flag, x) solve_sparse (flag, x, n, real_op, L, U, P, Pc);
+    else
+      [L, U, P] = lu (A);
+      solve = @(flag, x) solve_not_sparse (flag, x, n, real_op, L, U, P);
+    endif
+  endif
+
+  if (have_A)
+    Anorm = norm (A, 1);
+  else
+    Anorm = normest1 (apply, t, [], varargin{4:end});
+  endif
+  [Ainv_norm, v, w] = normest1 (solve, t, [], varargin{4:end});
+
+  est = Anorm * Ainv_norm;
+  v = w / norm (w, 1);
+
+endfunction
+
+function value = solve_sparse (flag, x, n, real_op, L , U , P , Pc)
+  switch flag
+    case "dim"
+      value = n;
+    case "real"
+      value = real_op;
+    case "notransp"
+      value = P' * (L' \ (U' \ (Pc * x)));
+    case "transp"
+      value = Pc' * (U \ (L \ (P * x)));
+  endswitch
+endfunction
+
+function value = solve_not_sparse (flag, x, n, real_op, L, U, P)
+  switch flag
+    case "dim"
+      value = n;
+    case "real"
+      value = real_op;
+    case "notransp"
+      value = P' * (L' \ (U' \ x));
+    case "transp"
+      value = U \ (L \ (P * x));
+  endswitch
+endfunction
+
+function [est, v] = condest_legacy (varargin) # to be removed after 4.2
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:deprecated-function",
+             "condest: this syntax is deprecated, call condest (A, SOLVEFUN, T, P1, P2, ...) instead.");
+  endif
+
+  default_t = 5;
+
   have_A = false;
   have_t = false;
   have_solve = false;
-
   if (isnumeric (varargin{1}))
     A = varargin{1};
     if (! issquare (A))
@@ -182,6 +318,10 @@
     endif
   endif
 
+  ## We already warned about this usage being deprecated.  Don't
+  ## warn again about onenormest.
+  warning ("off", "Octave:deprecated-function", "local");
+
   if (have_A)
     Anorm = norm (A, 1);
   else
@@ -195,19 +335,40 @@
 
 endfunction
 
-
-%!demo
-%! N = 100;
-%! A = randn (N) + eye (N);
-%! condest (A)
-%! [L,U,P] = lu (A);
-%! condest (A, @(x) U \ (L \ (P*x)), @(x) P'*(L' \ (U'\x)))
-%! condest (@(x) A*x, @(x) A'*x, @(x) U \ (L \ (P*x)), @(x) P'*(L' \ (U'\x)), N)
-%! norm (inv (A), 1) * norm (A, 1)
-
 ## Yes, these test bounds are really loose.  There's
 ## enough randomization to trigger odd cases with hilb().
 
+%!function value = apply_fun (flag, x, A, m)
+%!  if (nargin == 3)
+%!    m = 1;
+%!  endif
+%!  switch flag
+%!    case "dim"
+%!      value = length (A);
+%!    case "real"
+%!      value = isreal (A);
+%!    case "notransp"
+%!      value = x; for i = 1:m, value = A * value;, endfor
+%!    case "transp"
+%!      value = x; for i = 1:m, value = A' * value;, endfor
+%!  endswitch
+%!endfunction
+%!function value = solve_fun (flag, x, A, m)
+%!  if (nargin == 3)
+%!    m = 1;
+%!  endif
+%!  switch flag
+%!    case "dim"
+%!      value = length (A);
+%!    case "real"
+%!      value = isreal (A);
+%!    case "notransp"
+%!      value = x; for i = 1:m, value = A \ value;, endfor;
+%!    case "transp"
+%!      value = x; for i = 1:m, value = A' \ value;, endfor;
+%!  endswitch
+%!endfunction
+
 %!test
 %! N = 6;
 %! A = hilb (N);
@@ -215,7 +376,8 @@
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-8);
 
-%!test
+%!test # to be removed after 4.2
+%! warning ("off", "Octave:deprecated-function", "local");
 %! N = 6;
 %! A = hilb (N);
 %! solve = @(x) A\x; solve_t = @(x) A'\x;
@@ -223,7 +385,8 @@
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-8);
 
-%!test
+%!test # to be removed after 4.2
+%! warning ("off", "Octave:deprecated-function", "local");
 %! N = 6;
 %! A = hilb (N);
 %! apply = @(x) A*x; apply_t = @(x) A'*x;
@@ -232,6 +395,16 @@
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-6);
 
+%!test # to be removed after 4.2
+%! warning ("off", "Octave:deprecated-function", "local");
+%! N = 6;
+%! A = hilb (N);
+%! apply = @(x) A*x; apply_t = @(x) A'*x;
+%! solve = @(x) A\x; solve_t = @(x) A'\x;
+%! cA = condest (apply, apply_t, solve, solve_t, N, 2);
+%! cA_test = norm (inv (A), 1) * norm (A, 1);
+%! assert (cA, cA_test, -2^-6);
+
 %!test
 %! warning ("off", "Octave:nearly-singular-matrix", "local");
 %! N = 12;
@@ -240,3 +413,26 @@
 %! x = A*v;
 %! assert (norm (x, inf), 0, eps);
 
+%!test
+%! N = 6;
+%! A = hilb (N);
+%! solve = @(flag, x) solve_fun (flag, x, A);
+%! cA = condest (A, solve);
+%! cA_test = norm (inv (A), 1) * norm (A, 1);
+%! assert (cA, cA_test, -2^-6);
+%!test
+%! N = 6;
+%! A = hilb (N);
+%! apply = @(flag, x) apply_fun (flag, x, A);
+%! solve = @(flag, x) solve_fun (flag, x, A);
+%! cA = condest (apply, solve);
+%! cA_test = norm (inv (A), 1) * norm (A, 1);
+%! assert (cA, cA_test, -2^-6);
+
+%!test # parameters for apply and solve functions
+%! N = 6;
+%! A = hilb (N);
+%! m = 2;
+%! cA = condest (@apply_fun, @solve_fun, [], A, m);
+%! cA_test = norm (inv (A^2), 1) * norm (A^2, 1);
+%! assert (cA, cA_test, -2^-6);
--- a/scripts/linear-algebra/module.mk	Thu Jun 30 18:20:37 2016 +1000
+++ b/scripts/linear-algebra/module.mk	Mon Jul 25 14:50:29 2016 +0100
@@ -21,8 +21,8 @@
   scripts/linear-algebra/linsolve.m \
   scripts/linear-algebra/logm.m \
   scripts/linear-algebra/normest.m \
+  scripts/linear-algebra/normest1.m \
   scripts/linear-algebra/null.m \
-  scripts/linear-algebra/onenormest.m \
   scripts/linear-algebra/orth.m \
   scripts/linear-algebra/planerot.m \
   scripts/linear-algebra/qzhess.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/linear-algebra/normest1.m	Mon Jul 25 14:50:29 2016 +0100
@@ -0,0 +1,356 @@
+## Copyright (C) 2016 Marco Caliari
+##
+## 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/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Function File} {@var{c} =} normest1 (@var{a})
+## @deftypefnx {Function File} {@var{c} =} normest1 (@var{a}, @var{t})
+## @deftypefnx {Function File} {@var{c} =} normest1 (@var{a}, @var{t}, @var{x0})
+## @deftypefnx {Function File} {@var{c} =} normest1 (@var{afun}, @var{t}, @var{x0}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {Function File} {[@var{c}, @var{v}] =} normest1 (@var{a}, @dots{})
+## @deftypefnx {Function File} {[@var{c}, @var{v}, @var{w}] =} normest1 (@var{a}, @dots{})
+## @deftypefnx {Function File} {[@var{c}, @var{v}, @var{w}, @var{it}] =} normest1 (@var{a}, @dots{})
+## Estimate the 1-norm of the matrix @var{a} using a block algorithm.
+##
+## For a medium size matrix @var{a}, @code{norm (@var{a}, 1)} should be
+## used instead. For a large sparse matrix, when only an estimate of the norm
+## is needed, @code{normest1 (@var{a})} might be faster. Moreover, it can be
+## used for the estimate of the 1-norm of a linear
+## operator @var{a} when matrix-vector products @code{@var{a} * @var{x}} and
+## @code{@var{a}' * @var{x}} can be cheaply computed. In this case,
+## instead of the matrix @var{a}, a function
+## @code{@var{afun} (@var{flag}, @var{x})} can be used. It should return:
+##
+## @itemize @bullet
+## @item
+## the dimension @var{n} of @var{a}, if @var{flag} is @qcode{"dim"}
+## @item
+## true if @var{a} is a real operator, if @var{flag} is @qcode{"real"}
+## @item
+## the result @code{@var{a} * @var{x}}, if @var{flag} is @qcode{"notransp"}
+## @item
+## the result @code{@var{a}' * @var{x}}, if @var{flag} is @qcode{"transp"}
+## @end itemize
+##
+## A typical case is @var{a} defined by @code{@var{b} ^ @var{m}},
+## in which the result @code{@var{a} * @var{x}} can be computed without
+## even forming explicitely @code{@var{b} ^ @var{m}} by:
+##
+## @example
+## @var{y} = @var{x};
+## for @var{i} = 1:@var{m}
+##   @var{y} = @var{b} * @var{y};
+## endfor
+## @end example
+##
+## The parameters @var{p1}, @var{p2}, @dots{} are arguments of
+## @code{@var{afun} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}.
+##
+## The default value for @var{t} is 2. The algorithm requires
+## matrix-matrix products with sizes @var{n} x @var{n} and
+## @var{n} x @var{t}.
+##
+## The initial matrix @var{x0} should have columns of unit 1-norm.
+## The default initial matrix @var{x0} has the first column
+## @code{ones (@var{n}, 1) / @var{n}}
+## and, if @var{t} >  1, the remaining columns with random elements
+## @code{-1 / @var{n}}, @code{1 / @var{n}}, divided by @var{n}.
+## Therefore, if consistent results are required, the "state" of the
+## random generator should be fixed before invoking @code{normest1}.
+##
+## On output, @var{c} is the desired estimate, @var{v} and @var{w}
+## vectors such that @code{@var{w} = @var{a} * @var{v}}, with
+## @code{norm (@var{w}, 1)} = @code{@var{c} * norm (@var{v}, 1)}.
+## @var{it} contains in @code{@var{it}(1)} the number of iterations
+## (the maximum number is hardcoded to 5) and in  @code{@var{it}(2)}
+## the total number of products @code{@var{a} * @var{x}} or
+## @code{@var{a}' * @var{x}} performed by the algorithm.
+##
+## Reference: @nospell{N. J. Higham and F. Tisseur},
+## @cite{A block algorithm for matrix 1-norm estimation, with and
+## application to 1-norm pseudospectra}, SIAM J. Matrix Anal. Appl.,
+## pp. 1185--1201, Vol 21, No. 4, 2000.
+##
+## @seealso{normest, rand}
+## @end deftypefn
+
+## Ideally, we would set t and X to their default values but Matlab
+## compatibility would require we set the default even when they are
+## empty.
+function [est, v, w, k] = normest1 (A, t = [], X = [], varargin)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (isempty (t))
+    t = 2;
+  endif
+
+  ## FIXME: t < 0 should print trace information
+  if (isnumeric (A) && issquare (A))
+    Aisnum = true;
+    n = rows (A);
+    if ((n <= 4) || (t == n))
+      ## compute directly
+      [est, idx] = max (sum (abs (A), 1), [] ,2);
+      v = zeros (n, 1);
+      v(idx) = 1;
+      w = A(:, idx);
+      k = [0, 1];
+      return
+    else
+      realm = isreal (A);
+    endif
+  elseif (is_function_handle (A))
+    Aisnum = false;
+    n = A ("dim", [], varargin{:});
+    realm = A ("real", [], varargin{:});
+    Afun = @(x) A ("notransp", x, varargin{:});
+    A1fun = @(x) A ("transp", x, varargin{:});
+  else
+    error ("normest1: A must be a square matrix or a function handle");
+  endif
+
+  t = min (t, n);
+
+  if (isempty (X))
+    X = [ones(n, 1), sign(2 * rand(n, t - 1) - 1)];
+    i = 2;
+    imax = min (t, 2 ^ (n - 1));
+    ## There are at most 2^(n-1) unparallel columns, see later.
+    while (i <= imax)
+      if (any (abs (X(:,i)' * X(:,1:i-1)) == n))
+        ## column i is parallel to a colum 1:i-1. Change it.
+        X(:,i) = sign (2 * rand (n, 1) - 1);
+      else
+        i++;
+      endif
+    endwhile
+    X /= n;
+  elseif (columns (X) < t)
+    error ("normest1: X should have %d columns", t);
+  endif
+
+  itmax = 5;
+  ind_hist = zeros (n, 1);
+  est_old = 0;
+  ind = zeros (n, 1);
+  S = zeros (n, t);
+  k = [0; 0];
+  conv = false;
+  while ((! conv) && (k(1) < itmax))
+    k(1)++;
+    if (Aisnum)
+      Y = A * X;
+    else
+      Y = Afun (X);
+    endif
+    k(2)++;
+    [est, j] = max (sum (abs (Y), 1), [], 2);
+    if ((est > est_old) || (k(1) == 2))
+      ind_best = ind(j);
+      w = Y(:, j); # there is an error in Algorithm 2.4
+    endif
+    if ((est <= est_old) && (k(1) >= 2)) # (1) of Algorithm 2.4
+      est = est_old;
+      break; # while
+    endif
+    est_old = est;
+    Sold = S;
+    S = sign (Y);
+    S(S==0) = 1;
+    possible_break = false;
+    if (realm)
+      ## test parallel (only real case)
+      if (all (any (abs (Sold' * S) == n))) # (2) of Algorithm 2.4
+        ## all columns of S parallel to a column of Sold, exit
+        possible_break = true;
+        conv = true;
+      else
+        if (t > 1)
+          ## at least two columns of S are not parallel
+          i = 1;
+          imax = min (t, 2 ^ (n - 1));
+          while (i <= imax)
+            ## The maximum number of parallel columns of length n with entries
+            ## {-1,1} is 2^(n-1). Therefore, if the number of columns of S is
+            ## greater than 2^(n-1), for sure some of them are parallel to some
+            ## columns of Sold. Don't even try to change them (i <= 2^(n-1)).
+            ## Now, check if S(:,i) is parallel to any previous column of S
+            p = (any (abs (S(:,i)' * S(:,1:i-1)) == n));
+            if (p || (any (abs (S(:,i)' * Sold) == n)))
+              ## i-th column of S parallel to a previous or to a
+              ## column of Sold: change it.
+              S(:,i) = sign (2*rand (n, 1)-1);
+            else
+              i++;
+            endif
+          endwhile
+        endif
+      endif
+    endif
+    if (! possible_break)
+      if (Aisnum)
+        Z = A' * S;
+      else
+        Z = A1fun (S); # (3) of Algorithm 2.4
+      endif
+      k(2)++;
+      h = max (abs (Z), [], 2);
+      ind = (1:n)';
+      if ((k(1) >= 2) && (max (h, [], 1) == h(ind_best))) # (4) of Alg. 2.4
+        break; # while
+      endif
+      [h, ind] = sort (h, "descend");
+      if (t > 1)
+       if (all (ind_hist(ind(1:t)))) # (5) of Algorithm 2.4
+          break; # while
+        endif
+        ind = ind(! ind_hist(ind));
+        ## length(ind) could be less than t, especially if t is not << n.
+        ## This is not considered in point (5) of Algorithm 2.4.
+        tmax = min (numel (ind), t);
+        ind = ind(1:tmax);
+      else
+        tmax = 1;
+      endif
+      X = zeros (n, tmax);
+      X(sub2ind (size (X), ind(1:tmax), (1:tmax)')) = 1;
+      ind_hist(ind(1:tmax)) = 1;
+    endif
+  endwhile
+  v = zeros (n, 1);
+  v(ind_best) = 1;
+endfunction
+
+%!function z = afun_A (flag, x, A, n)
+%! switch flag
+%! case {"dim"}
+%!   z = n;
+%! case {"real"}
+%!   z = isreal (A);
+%! case {"transp"}
+%!   z = A' * x;
+%! case {"notransp"}
+%!   z = A * x;
+%! endswitch
+%!endfunction
+%!function z = afun_A_P (flag, x, A, m)
+%! switch flag
+%! case "dim"
+%!   z = length (A);
+%! case "real"
+%!   z = isreal (A);
+%! case "transp"
+%!   z = x; for i = 1:m, z = A' * z;, endfor
+%! case "notransp"
+%!   z = x; for i = 1:m, z = A * z;, endfor
+%! endswitch
+%!endfunction
+
+%!test
+%! A = reshape ((1:16)-8, 4, 4);
+%! assert (normest1 (A), norm (A, 1), eps)
+
+## test t=1
+%!test
+%! A = rand (4); # for positive matrices always work
+%! assert (normest1 (A, 1), norm (A,1), 2 * eps)
+
+## test t=3
+%!test
+%! A = [-0.21825   0.16598   0.19388   0.75297
+%!      -1.47732   0.78443  -1.04254   0.42240
+%!       1.39857  -0.34046   2.28617   0.68089
+%!       0.31205   1.50529  -0.75804  -1.22476];
+%! X = [1,1,-1;1,1,1;1,1,-1;1,-1,-1]/3;
+%! assert (normest1 (A, 3, X), norm (A, 1), 2 * eps)
+
+## test afun
+%!test
+%! A = rand (10);
+%! n = length (A);
+%! afun = @(flag, x) afun_A (flag, x, A, n);
+%! assert (normest1 (afun), norm (A, 1), 2 * eps)
+
+## test afun with parameters
+%!test
+%! A = rand (10);
+%! assert (normest1 (@afun_A_P, [], [], A, 3), norm (A ^ 3, 1), 1000 * eps)
+
+## test output
+%!test
+%! A = reshape (1:16,4,4);
+%! [c, v, w, it] = normest1 (A);
+%! assert (norm (w, 1), c * norm (v, 1), eps)
+
+## test output
+%!test
+%! A = rand (100);
+%! A(A <= 1/3) = -1;
+%! A(A > 1/3 & A <= 2/3) = 0;
+%! A(A > 2/3) = 1;
+%! [c, v, w, it] = normest1 (A, 10);
+%! assert (w, A * v, eps)
+
+%!test
+%! A = rand (5);
+%! c = normest1 (A, 6);
+%! assert (c, norm (A,1), eps)
+
+%!test
+%! A = rand (5);
+%! c = normest1 (A, 2, ones (5, 2) / 5);
+%! assert (c, norm (A,1), eps)
+
+%!test
+%! N = 10;
+%! A = ones (N);
+%! [nm1, v1, w1] = normest1 (A);
+%! [nminf, vinf, winf] = normest1 (A', 6);
+%! assert (nm1, N, -2*eps)
+%! assert (nminf, N, -2*eps)
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps)
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps)
+
+%!test
+%! N = 5;
+%! A = hilb (N);
+%! [nm1, v1, w1] = normest1 (A);
+%! [nminf, vinf, winf] = normest1 (A', 6);
+%! assert (nm1, norm (A, 1), -2*eps)
+%! assert (nminf, norm (A, inf), -2*eps)
+%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps)
+%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps)
+
+## Only likely to be within a factor of 10.
+%!test
+%! old_state = rand ("state");
+%! unwind_protect
+%!   rand ("state", 42);  # Initialize to guarantee reproducible results
+%!   N = 100;
+%!   A = rand (N);
+%!   [nm1, v1, w1] = normest1 (A);
+%!   [nminf, vinf, winf] = normest1 (A', 6);
+%!   assert (nm1, norm (A, 1), -.1)
+%!   assert (nminf, norm (A, inf), -.1)
+%!   assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps)
+%!   assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps)
+%! unwind_protect_cleanup
+%!   rand ("state", old_state);
+%! end_unwind_protect
--- a/scripts/linear-algebra/onenormest.m	Thu Jun 30 18:20:37 2016 +1000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,293 +0,0 @@
-## Copyright (C) 2007-2015 Regents of the University of California
-##
-## 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/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {[@var{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{A}, @var{t})
-## @deftypefnx {} {[@var{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{apply}, @var{apply_t}, @var{n}, @var{t})
-##
-## Apply @nospell{Higham and Tisseur's} randomized block 1-norm estimator to
-## matrix @var{A} using @var{t} test vectors.
-##
-## If @var{t} exceeds 5, then only 5 test vectors are used.
-##
-## If the matrix is not explicit, e.g., when estimating the norm of
-## @code{inv (@var{A})} given an LU@tie{}factorization, @code{onenormest}
-## applies @var{A} and its conjugate transpose through a pair of functions
-## @var{apply} and @var{apply_t}, respectively, to a dense matrix of size
-## @var{n} by @var{t}.  The implicit version requires an explicit dimension
-## @var{n}.
-##
-## Returns the norm estimate @var{est}, two vectors @var{v} and @var{w} related
-## by norm @code{(@var{w}, 1) = @var{est} * norm (@var{v}, 1)}, and the number
-## of iterations @var{iter}.  The number of iterations is limited to 10 and is
-## at least 2.
-##
-## References:
-##
-## @itemize
-## @item
-## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
-## for Matrix 1-Norm Estimation, with an Application to 1-Norm
-## Pseudospectra}. SIMAX vol 21, no 4, pp 1185-1201.
-## @url{http://dx.doi.org/10.1137/S0895479899356080}
-##
-## @item
-## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
-## for Matrix 1-Norm Estimation, with an Application to 1-Norm
-## Pseudospectra}. @url{http://citeseer.ist.psu.edu/223007.html}
-## @end itemize
-##
-## @seealso{condest, norm, cond}
-## @end deftypefn
-
-## Code originally licensed under:
-##
-## Copyright (c) 2007, Regents of the University of California
-## All rights reserved.
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-##    * Redistributions of source code must retain the above copyright
-##      notice, this list of conditions and the following disclaimer.
-##
-##    * Redistributions in binary form must reproduce the above
-##      copyright notice, this list of conditions and the following
-##      disclaimer in the documentation and/or other materials provided
-##      with the distribution.
-##
-##    * Neither the name of the University of California, Berkeley nor
-##      the names of its contributors may be used to endorse or promote
-##      products derived from this software without specific prior
-##      written permission.
-##
-## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
-## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-## PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND
-## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-## SUCH DAMAGE.
-
-## Author: Jason Riedy <ejr@cs.berkeley.edu>
-## Keywords: linear-algebra norm estimation
-## Version: 0.2
-
-function [est, v, w, iter] = onenormest (varargin)
-
-  if (nargin < 1 || nargin > 4)
-    print_usage ();
-  endif
-
-  default_t = 5;
-  itmax = 10;
-
-  if (isnumeric (varargin{1}))
-    [n, nc] = size (varargin{1});
-    if (n != nc)
-      error ("onenormest: matrix must be square");
-    endif
-    apply = @(x) varargin{1} * x;
-    apply_t = @(x) varargin{1}' * x;
-    if (nargin > 1)
-      t = varargin{2};
-    else
-      t = min (n, default_t);
-    endif
-    issing = isa (varargin{1}, "single");
-  else
-    if (nargin < 3)
-      print_usage ();
-    endif
-    apply = varargin{1};
-    apply_t = varargin{2};
-    n = varargin{3};
-    if (nargin > 3)
-      t = varargin{4};
-    else
-      t = default_t;
-    endif
-    issing = isa (n, "single");
-  endif
-
-  ## Initial test vectors X.
-  X = rand (n, t);
-  X ./= ones (n,1) * sum (abs (X), 1);
-
-  ## Track if a vertex has been visited.
-  been_there = zeros (n, 1);
-
-  ## To check if the estimate has increased.
-  est_old = 0;
-
-  ## Normalized vector of signs.
-  S = zeros (n, t);
-
-  if (issing)
-    myeps = eps ("single");
-    X = single (X);
-  else
-    myeps = eps;
-  endif
-
-  for iter = 1 : itmax + 1
-    Y = feval (apply, X);
-
-    ## Find the initial estimate as the largest A*x.
-    [est, ind_best] = max (sum (abs (Y), 1));
-    if (est > est_old || iter == 2)
-      w = Y(:,ind_best);
-    endif
-    if (iter >= 2 && est < est_old)
-      ## No improvement, so stop.
-      est = est_old;
-      break;
-    endif
-
-    est_old = est;
-    S_old = S;
-    if (iter > itmax),
-      ## Gone too far.  Stop.
-      break;
-    endif
-
-    S = sign (Y);
-
-    ## Test if any of S are approximately parallel to previous S
-    ## vectors or current S vectors.  If everything is parallel,
-    ## stop.  Otherwise, replace any parallel vectors with
-    ## rand{-1,+1}.
-    partest = any (abs (S_old' * S - n) < 4*eps*n);
-    if (all (partest))
-      ## All the current vectors are parallel to old vectors.
-      ## We've hit a cycle, so stop.
-      break;
-    endif
-    if (any (partest))
-      ## Some vectors are parallel to old ones and are cycling,
-      ## but not all of them.  Replace the parallel vectors with
-      ## rand{-1,+1}.
-      numpar = sum (partest);
-      replacements = 2*(rand (n,numpar) < 0.5) - 1;
-      S(:,partest) = replacements;
-    endif
-    ## Now test for parallel vectors within S.
-    partest = any ((S' * S - eye (t)) == n);
-    if (any (partest))
-      numpar = sum (partest);
-      replacements = 2*(rand (n,numpar) < 0.5) - 1;
-      S(:,partest) = replacements;
-    endif
-
-    Z = feval (apply_t, S);
-
-    ## Now find the largest non-previously-visted index per vector.
-    h = max (abs (Z),2);
-    [mh, mhi] = max (h);
-    if (iter >= 2 && mhi == ind_best)
-      ## Hit a cycle, stop.
-      break;
-    endif
-    [h, ind] = sort (h, 'descend');
-    if (t > 1)
-      firstind = ind(1:t);
-      if (all (been_there(firstind)))
-        ## Visited all these before, so stop.
-        break;
-      endif
-      ind = ind(! been_there(ind));
-      if (length (ind) < t)
-        ## There aren't enough new vectors, so we're practically
-        ## in a cycle.  Stop.
-        break;
-      endif
-    endif
-
-    ## Visit the new indices.
-    X = zeros (n, t);
-    for zz = 1 : t
-      X(ind(zz),zz) = 1;
-    endfor
-    been_there(ind(1 : t)) = 1;
-  endfor
-
-  ## The estimate est and vector w are set in the loop above.
-  ## The vector v selects the ind_best column of A.
-  v = zeros (n, 1);
-  v(ind_best) = 1;
-
-endfunction
-
-
-%!demo
-%! N = 100;
-%! A = randn (N) + eye (N);
-%! [L,U,P] = lu (A);
-%! nm1inv = onenormest (@(x) U\(L\(P*x)), @(x) P'*(L'\(U'\x)), N, 30)
-%! norm (inv (A), 1)
-
-%!test
-%! N = 10;
-%! A = ones (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, N, -2*eps);
-%! assert (nminf, N, -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-%!test
-%! N = 10;
-%! A = ones (N);
-%! [nm1, v1, w1] = onenormest (@(x) A*x, @(x) A'*x, N, 3);
-%! [nminf, vinf, winf] = onenormest (@(x) A'*x, @(x) A*x, N, 3);
-%! assert (nm1, N, -2*eps);
-%! assert (nminf, N, -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-%!test
-%! N = 5;
-%! A = hilb (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, norm (A, 1), -2*eps);
-%! assert (nminf, norm (A, inf), -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-## Only likely to be within a factor of 10.
-%!test
-%! old_state = rand ("state");
-%! restore_state = onCleanup (@() rand ("state", old_state));
-%! rand ("state", 42);  # Initialize to guarantee reproducible results
-%! N = 100;
-%! A = rand (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, norm (A, 1), -.1);
-%! assert (nminf, norm (A, inf), -.1);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-