changeset 6863:3c64128e621c

[project @ 2007-09-05 07:52:48 by dbateman]
author dbateman
date Wed, 05 Sep 2007 07:53:45 +0000
parents d63339cbb205
children ab9a0ffee27f
files doc/ChangeLog doc/interpreter/container.txi doc/interpreter/eval.txi doc/interpreter/stats.txi scripts/ChangeLog scripts/general/Makefile.in scripts/general/structfun.m scripts/miscellaneous/Makefile.in scripts/miscellaneous/run.m scripts/statistics/base/Makefile.in scripts/statistics/base/mode.m src/ChangeLog src/DLD-FUNCTIONS/sort.cc src/ov-cx-sparse.h src/ov-re-sparse.h src/ov.cc src/ov.h
diffstat 17 files changed, 626 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/doc/ChangeLog	Wed Sep 05 06:49:29 2007 +0000
+++ b/doc/ChangeLog	Wed Sep 05 07:53:45 2007 +0000
@@ -1,3 +1,9 @@
+2007-09-05  David Bateman  <dbateman@free.fr>
+
+        * interpreter/container.txi: Document struct2cell.
+        * interpreter/stats.txi: Document mode.
+        * interpreter/eval.txi: Document run.
+
 2007-09-01  David Bateman  <dbateman@free.fr>
 
 	* interpreter/Makefile.in: Remove stray character from
--- a/doc/interpreter/container.txi	Wed Sep 05 06:49:29 2007 +0000
+++ b/doc/interpreter/container.txi	Wed Sep 05 07:53:45 2007 +0000
@@ -200,6 +200,7 @@
 * Structure Arrays::
 * Creating Structures::
 * Manipulating Structures::
+* Processing Data in Structures::
 @end menu
 
 @node Structure Arrays
@@ -395,9 +396,22 @@
 
 @DOCSTRING(getfield)
 
-@DOCSTRING(struct2cell)
+@DOCSTRING(substruct)
+
+@node Processing Data in Structures
+@subsection Processing Data in Structures
 
-@DOCSTRING(substruct)
+The simpliest way to process data in a structure is within a @code{for}
+loop or othe means of iterating over the fields. A similar effect can be
+achieved with the @code{structfun} function, where a user defined
+function is applied to eacg field of the structure.
+
+@DOCSTRING(structfun)
+
+Alternatively, to process the data in a strcuture, the structure might
+be converted to another type of container before being treated.
+
+@DOCSTRING(struct2cell)
 
 @node Cell Arrays
 @section Cell Arrays
--- a/doc/interpreter/eval.txi	Wed Sep 05 06:49:29 2007 +0000
+++ b/doc/interpreter/eval.txi	Wed Sep 05 07:53:45 2007 +0000
@@ -75,6 +75,11 @@
 
 @DOCSTRING(feval)
 
+A similar function @code{run} exists for calling user script files, that
+are not necessarily on the user path
+
+@DOCSTRING(run)
+
 @node Evaluation in a Different Context
 @section Evaluation in a Different Context
 
--- a/doc/interpreter/stats.txi	Wed Sep 05 06:49:29 2007 +0000
+++ b/doc/interpreter/stats.txi	Wed Sep 05 07:53:45 2007 +0000
@@ -52,6 +52,8 @@
 
 @DOCSTRING(var)
 
+@DOCSTRING(mode)
+
 @DOCSTRING(cov)
 
 @DOCSTRING(cor)
--- a/scripts/ChangeLog	Wed Sep 05 06:49:29 2007 +0000
+++ b/scripts/ChangeLog	Wed Sep 05 07:53:45 2007 +0000
@@ -1,3 +1,12 @@
+2007-09-05  David Bateman  <dbateman@free.fr>
+
+        * general/structfun.m: New function.
+        * general/Makefile.in (SOURCES): Add it to sources.
+        * miscellaneous/run.m: New function.
+        * miscellaneous/Makefile.in (SOURCES): Add it to sources.
+        * statistics/base/mode.m: New function.
+        * statistics/base//Makefile.in (SOURCES): Add it to sources.
+
 2007-09-05  John W. Eaton  <jwe@octave.org>
 
 	* miscellaneous/orderfields.m: Use numel instead of length.
--- a/scripts/general/Makefile.in	Wed Sep 05 06:49:29 2007 +0000
+++ b/scripts/general/Makefile.in	Wed Sep 05 07:53:45 2007 +0000
@@ -30,7 +30,7 @@
   nargchk.m nextpow2.m nthroot.m num2str.m perror.m pol2cart.m \
   polyarea.m postpad.m prepad.m quadl.m randperm.m rat.m rem.m \
   repmat.m rot90.m rotdim.m shift.m shiftdim.m sortrows.m \
-  sph2cart.m strerror.m sub2ind.m trapz.m tril.m triu.m
+  sph2cart.m strerror.m structfun.m sub2ind.m trapz.m tril.m triu.m
 
 DISTFILES = $(addprefix $(srcdir)/, Makefile.in $(SOURCES))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/structfun.m	Wed Sep 05 07:53:45 2007 +0000
@@ -0,0 +1,87 @@
+## Copyright (C) 2007  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 2, 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, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} structfun (@var{func}, @var{s})
+## @deftypefnx {Function File} {[@var{a}, @var{b}] =} structfun (@dots{})
+## @deftypefnx {Function File} {} structfun (@dots{}, 'ErrorHandler', @var{errfunc})
+## @deftypefnx {Function File} {} structfun (@dots{}, 'UniformOutput', @var{val})
+## 
+## Evaluate the function named @var{name} on the fields of the structure
+## @var{s}. The fields of @var{s} are passed the the function @var{func}
+## individually.
+##
+## @code{structfun} accepts an arbitrary function @var{func} in the form of 
+## an inline function, function handle, or the name of a function (in a 
+## character string). In the case of a character string argument, the 
+## function must accept a single argument named @var{x}, and it must return 
+## a string value. If the function returns more than one argument, they are
+## returned as separate output variables.
+##
+## If the param 'UniformOutput' is set to true (the default), then the function
+## must return either a single element which will be concatenated into the
+## return value. If 'UniformOutput is false, the outputs placed in a structure
+## with the same fieldnames as the input structure.
+## 
+## @example
+## @group
+## s.name1 = "John Smith"; 
+## s.name2 = "Jill Jones"; 
+## structfun (@{x@} regexp (x, '(\w+)$', 'matches')@{1@}, s, 
+##            'UniformOutput', false)
+## @end group
+## @end example
+## 
+## Given the parameter 'ErrorHandler', then @var{errfunc} defines a function to
+## call in case @var{func} generates an error. The form of the function is
+## 
+## @example
+## function [@dots{}] = errfunc (@var{se}, @dots{})
+## @end example
+## 
+## where there is an additional input argument to @var{errfunc} relative to
+## @var{func}, given by @var{se}. This is a structure with the elements
+## 'identifier', 'message' and 'index', giving respectively the error
+## identifier, the error message, and the index into the input arguments
+## of the element that caused the error.
+## @seealso{cellfun, arrayfun}
+## @end deftypefn
+
+function varargout = structfun (fun, s, varargin);
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  varargout = cell (max ([nargout, 1]), 1);
+  [varargout{:}] = cellfun (fun, struct2cell (s), varargin {:});
+
+  if (iscell (varargout{1}))
+    [varargout{:}] = cell2struct (varargout{1}, fieldnames(s), 1);
+  endif
+endfunction
+
+
+%!test
+%! s.name1 = "John Smith"; 
+%! s.name2 = "Jill Jones"; 
+%! l.name1 = "Smith";
+%! l.name2 = "Jones";
+%! o = structfun (@(x) regexp (x, '(\w+)$', 'matches'){1}, s, 
+%!		  'UniformOutput', false);
+%! assert (o, l);
--- a/scripts/miscellaneous/Makefile.in	Wed Sep 05 06:49:29 2007 +0000
+++ b/scripts/miscellaneous/Makefile.in	Wed Sep 05 07:53:45 2007 +0000
@@ -27,7 +27,7 @@
   inputname.m ispc.m isunix.m license.m list_primes.m ls.m \
   ls_command.m menu.m mex.m mexext.m mkoctfile.m movefile.m \
   news.m orderfields.m pack.m paren.m parseparams.m \
-  semicolon.m setfield.m single.m substruct.m tar.m \
+  run.m semicolon.m setfield.m single.m substruct.m tar.m \
   tempdir.m tempname.m texas_lotto.m unix.m unpack.m untar.m \
   unzip.m ver.m version.m warning_ids.m xor.m zip.m
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/run.m	Wed Sep 05 07:53:45 2007 +0000
@@ -0,0 +1,56 @@
+## Copyright (C) 2007  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 2, 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, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} run (@var{f})
+## @deftypefnx {Command} {} run @var{f}
+## Run scripts in the current workspace that are not necessarily on the
+## path. If @var{f} is the script to run, including its path, then @code{run}
+## change the directory to the directory where @var{f} is found. @code{run}
+## then executes the script, and returns to the original directory.
+## @seealso{system}
+## @end deftypefn
+
+## PKG_ADD: mark_as_commnd run
+
+function run (s)
+  [d, f, ext] = fileparts (s);
+  if (! isempty (d))
+    if (exist (d, "dir"))
+      wd = pwd ();
+      unwind_protect
+	cd (d);
+	if (! exist (s, "file") ||  ! strcmp (ext, ".m"))
+	  error ("run: file must exist and be a valid Octave script file");
+	endif
+	evalin ("caller", [f, ";"], "rethrow (lasterror ())");
+      unwind_protect_cleanup
+	cd (wd);
+      end_unwind_protect
+    else
+      error ("run: the path %s doesn't exist", d);
+    endif
+  else
+    if (exist (script, "file"))
+      evalin ("caller", [script, ";"], "rethrow (lasterror ())");
+    else
+      error ("run: %s not found", s);
+    endif
+  endif
+endfunction
--- a/scripts/statistics/base/Makefile.in	Wed Sep 05 06:49:29 2007 +0000
+++ b/scripts/statistics/base/Makefile.in	Wed Sep 05 07:53:45 2007 +0000
@@ -22,7 +22,7 @@
 
 SOURCES = center.m cloglog.m cor.m corrcoef.m cov.m cut.m gls.m \
   iqr.m kendall.m kurtosis.m logit.m mahalanobis.m mean.m meansq.m \
-  median.m moment.m ols.m ppplot.m probit.m qqplot.m range.m \
+  median.m mode.m moment.m ols.m ppplot.m probit.m qqplot.m range.m \
   ranks.m run_count.m skewness.m spearman.m statistics.m std.m \
   studentize.m table.m values.m var.m
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/base/mode.m	Wed Sep 05 07:53:45 2007 +0000
@@ -0,0 +1,111 @@
+## Copyright (C) 2007  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 2, 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, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {[@var{m}, @var{f}, @var{c}] =} mode (@var{x}, @var{dim})
+## Count the most frequently appearing value. @code{mode} counts the 
+## frequency along the first non-singleton dimension and if two or more
+## values have te same frequency returns the smallest of the two in
+## @var{m}. The dimension along which to count can be specified by the
+## @var{dim} parameter.
+##
+## The variable @var{f} counts the frequency of each of the most frequently 
+## occuring ellements. The cell array @var{c} contains all of the elements
+## with the maximum frequency .
+## @end deftypefn
+
+function [m, f, c] = mode (x, dim)
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
+
+  nd = ndims (x);
+  sz = size (x);
+
+  if (nargin != 2)
+    ## Find the first non-singleton dimension.
+    dim  = 1;
+    while (dim < nd + 1 && sz(dim) == 1)
+      dim = dim + 1;
+    endwhile
+    if (dim > nd)
+      dim = 1;
+    endif
+  else
+    if (! (isscalar (dim) && dim == round (dim))
+        && dim > 0
+        && dim < (nd + 1))
+      error ("mode: dim must be an integer and valid dimension");
+    endif
+  endif
+
+  sz2 = sz;
+  sz2 (dim) = 1;
+  sz3 = ones (1, nd);
+  sz3 (dim) = sz (dim);
+
+  if (dim != 1)
+    perm = [1 : nd];
+    perm(1) = dim;
+    perm(dim) = 1;
+  endif
+
+  xs = sort (x, dim);
+  t = cat (dim, true (sz2), diff (xs, 1, dim) != 0);
+  if (issparse (x))
+    t2 = sparse (sz(1), sz(2));
+  else
+    t2 = zeros (size (t));
+  endif
+
+  if (dim != 1)
+    t2 (permute (t != 0, perm)) = diff ([find(permute (t, perm)); prod(sz)+1]);
+    f = max (ipermute (t2, perm), [], dim);
+    xs = permute (xs, perm);
+  else
+    t2 (t) = diff ([find(t); prod(sz)+1]);
+    f = max (t2, [], dim);
+  endif
+
+  c = cell (sz2);
+  m = zeros (sz2);
+  for i = 1 : prod (sz2)
+    c {i} = xs (t2 (:, i) == f(i), i);
+    m (i) = c{i}(1);
+  endfor
+endfunction
+
+%!test
+%! [m, f, c] = mode (toeplitz (1:5));
+%! assert (m, [1,2,2,2,1]);
+%! assert (f, [1,2,2,2,1]);
+%! assert (c, {[1;2;3;4;5],[2],[2;3],[2],[1;2;3;4;5]});
+%!test
+%! [m, f, c] = mode (toeplitz (1:5), 2);
+%! assert (m, [1;2;2;2;1]);
+%! assert (f, [1;2;2;2;1]);
+%! assert (c, {[1;2;3;4;5];[2];[2;3];[2];[1;2;3;4;5]});
+%!test
+%! a = sprandn (32, 32, 0.05);
+%! [m, f, c] = mode (a);
+%! [m2, f2, c2] = mode (full (a));
+%! assert (m, m2);
+%! assert (f, f2);
+%! assert (c, c2);
--- a/src/ChangeLog	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/ChangeLog	Wed Sep 05 07:53:45 2007 +0000
@@ -1,3 +1,23 @@
+2007-09-05  David Bateman  <dbateman@free.fr>
+
+        * DLD-FUNCTIONS/sort.cc (mx_sort_sparse, mx_sort_sparse_indexed):
+        New template classes for sparse sort functions.
+        (Fsort): Use them.
+        * ov.h (octave_value (const Sparse<double>&, const MatrixType&),
+        octave_value (const Sparse<Complex>&, const MatrixType&)): New
+        constructors.
+        * ov.cc (octave_value::octave_value (const Sparse<double>&, 
+        const MatrixType&), octave_value::octave_value (const 
+        Sparse<Complex>&, const MatrixType&)): Define them.
+        * ov-re-sparse.h (octave_sparse_matrix (const MSparse<double>&,
+        const MatrixType&), octave_sparse_matrix (const Sparse<double>&),
+        octave_sparse_matrix (const Sparse<double>&, const MatrixType&)):
+        New constructors.
+        * ov-cx-sparse.h (octave_sparse_complex_matrix (const MSparse<double>&,
+        const MatrixType&), octave_sparse_complex_matrix (const 
+        Sparse<double>&), octave_sparse_complex_matrix (const
+        Sparse<double>&, const MatrixType&)): ditto.
+
 2007-09-04  Gabriele Pannocchia  <g.pannocchia@ing.unipi.it>
 
 	* DLD-FUNCTIONS/__qp__.cc (qp): Use Wact(j) == i - n_eq when
--- a/src/DLD-FUNCTIONS/sort.cc	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/DLD-FUNCTIONS/sort.cc	Wed Sep 05 07:53:45 2007 +0000
@@ -236,6 +236,188 @@
   return retval;
 }
 
+template <class T>
+static octave_value
+mx_sort_sparse (Sparse<T> &m, int dim, sortmode mode = UNDEFINED)
+{
+  octave_value retval;
+
+  octave_idx_type nr = m.rows ();
+  octave_idx_type nc = m.columns ();
+
+  if (m.length () < 1)
+    return Sparse<T> (nr, nc);
+
+  if (dim > 0)
+    {
+      m = m.transpose ();
+      nr = m.rows ();
+      nc = m.columns ();
+    }
+
+  octave_sort<T> sort;
+
+  if (mode == ASCENDING) 
+    sort.set_compare (ascending_compare);
+  else if (mode == DESCENDING)
+    sort.set_compare (descending_compare);
+
+  T *v = m.data ();
+  octave_idx_type *cidx = m.cidx ();
+  octave_idx_type *ridx = m.ridx ();
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    {
+      octave_idx_type ns = cidx [j + 1] - cidx [j];
+      sort.sort (v, ns);
+
+      octave_idx_type i;
+      if (mode == ASCENDING) 
+	{
+	  for (i = 0; i < ns; i++)
+	    if (ascending_compare (static_cast<T> (0), v [i]))
+	      break;
+	}
+      else
+	{
+	  for (i = 0; i < ns; i++)
+	    if (descending_compare (static_cast<T> (0), v [i]))
+	      break;
+	}
+      for (octave_idx_type k = 0; k < i; k++)
+	ridx [k] = k;
+      for (octave_idx_type k = i; k < ns; k++)
+	ridx [k] = k - ns + nr; 
+
+      v += ns;
+      ridx += ns;
+    }
+
+  if (dim > 0)
+      m = m.transpose ();
+
+  retval = m;
+
+  return retval;
+}
+
+template <class T>
+static octave_value_list
+mx_sort_sparse_indexed (Sparse<T> &m, int dim, sortmode mode = UNDEFINED)
+{
+  octave_value_list retval;
+
+  octave_idx_type nr = m.rows ();
+  octave_idx_type nc = m.columns ();
+
+  if (m.length () < 1)
+    {
+      retval (1) = NDArray (dim_vector (nr, nc));
+      retval (0) = octave_value (SparseMatrix (nr, nc));
+      return retval;
+    }
+
+  if (dim > 0)
+    {
+      m = m.transpose ();
+      nr = m.rows ();
+      nc = m.columns ();
+    }
+
+  octave_sort<vec_index<T> *> indexed_sort;
+
+  if (mode == ASCENDING) 
+    indexed_sort.set_compare (ascending_compare);
+  else if (mode == DESCENDING)
+    indexed_sort.set_compare (descending_compare);
+
+  T *v = m.data ();
+  octave_idx_type *cidx = m.cidx ();
+  octave_idx_type *ridx = m.ridx ();
+
+  OCTAVE_LOCAL_BUFFER (vec_index<T> *, vi, nr);
+  OCTAVE_LOCAL_BUFFER (vec_index<T>, vix, nr);
+
+  for (octave_idx_type i = 0; i < nr; i++)
+    vi[i] = &vix[i];
+
+  Matrix idx (nr, nc);
+
+  for (octave_idx_type j = 0; j < nc; j++)
+    {
+      octave_idx_type ns = cidx [j + 1] - cidx [j];
+      octave_idx_type offset = j * nr;
+
+      if (ns == 0)
+	{
+	  for (octave_idx_type k = 0; k < nr; k++)
+	    idx (offset + k) = k + 1;
+	}
+      else
+	{
+	  for (octave_idx_type i = 0; i < ns; i++)
+	    {
+	      vi[i]->vec = v[i];
+	      vi[i]->indx = ridx[i] + 1;
+	    }
+
+	  indexed_sort.sort (vi, ns);
+
+	  octave_idx_type i;
+	  if (mode == ASCENDING) 
+	    {
+	      for (i = 0; i < ns; i++)
+		if (ascending_compare (static_cast<T> (0), vi [i] -> vec))
+		  break;
+	    }
+	  else
+	    {
+	      for (i = 0; i < ns; i++)
+		if (descending_compare (static_cast<T> (0), vi [i] -> vec))
+		  break;
+	    }
+
+	  octave_idx_type ii = 0;
+	  octave_idx_type jj = i;
+	  for (octave_idx_type k = 0; k < nr; k++)
+	    {
+	      if (ii < ns && ridx[ii] == k)
+		ii++;
+	      else
+		idx (offset + jj++) = k + 1;
+	    }
+
+	  for (octave_idx_type k = 0; k < i; k++)
+	    {
+	      v [k] = vi [k] -> vec;
+	      idx (k + offset) = vi [k] -> indx;
+	      ridx [k] = k;
+	    }
+
+	  for (octave_idx_type k = i; k < ns; k++)
+	    {
+	      v [k] = vi [k] -> vec;
+	      idx (k - ns + nr + offset) = vi [k] -> indx;
+	      ridx [k] = k - ns + nr; 
+	    }
+
+	  v += ns;
+	  ridx += ns;
+	}
+    }
+
+  if (dim > 0)
+    {
+      m = m.transpose ();
+      idx = idx.transpose ();
+    }
+
+  retval (1) = idx;
+  retval(0) = octave_value (m);
+
+  return retval;
+}
+
 // If we have IEEE 754 data format, then we can use the trick of
 // casting doubles as unsigned eight byte integers, and with a little
 // bit of magic we can automatically sort the NaN's correctly.
@@ -602,6 +784,14 @@
 #endif
 #endif
 
+#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
+static octave_value_list
+mx_sort_sparse (Sparse<double> &m, int dim, sortmode mode);
+
+static octave_value_list
+mx_sort_sparse_indexed (Sparse<double> &m, int dim, sortmode mode);
+#endif
+
 // std::abs(Inf) returns NaN!!
 static inline double
 xabs (const Complex& x)
@@ -611,6 +801,36 @@
 
 template <>
 bool
+ascending_compare (Complex a, Complex b)
+{
+  return (xisnan (b) || (xabs (a) < xabs (b)) || ((xabs (a) == xabs (b))
+	      && (arg (a) < arg (b))));
+}
+
+bool
+operator < (const Complex a, const Complex b)
+{
+  return (xisnan (b) || (xabs (a) < xabs (b)) || ((xabs (a) == xabs (b))
+	      && (arg (a) < arg (b))));
+}
+
+template <>
+bool
+descending_compare (Complex a, Complex b)
+{
+  return (xisnan (a) || (xabs (a) > xabs (b)) || ((xabs (a) == xabs (b))
+	      && (arg (a) > arg (b))));
+}
+
+bool
+operator > (const Complex a, const Complex b)
+{
+  return (xisnan (a) || (xabs (a) > xabs (b)) || ((xabs (a) == xabs (b))
+	      && (arg (a) > arg (b))));
+}
+
+template <>
+bool
 ascending_compare (vec_index<Complex> *a, vec_index<Complex> *b)
 {
   return (xisnan (b->vec)
@@ -629,12 +849,22 @@
 	      && (arg (a->vec) > arg (b->vec))));
 }
 
+template class octave_sort<Complex>;
 template class vec_index<Complex>;
 template class octave_sort<vec_index<Complex> *>;
 
 #if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
 static octave_value_list
+mx_sort (ArrayN<Complex> &m, int dim, sortmode mode);
+
+static octave_value_list
 mx_sort_indexed (ArrayN<Complex> &m, int dim, sortmode mode);
+
+static octave_value_list
+mx_sort_sparse (Sparse<Complex> &m, int dim, sortmode mode);
+
+static octave_value_list
+mx_sort_sparse_indexed (Sparse<Complex> &m, int dim, sortmode mode);
 #endif
 
 template class octave_sort<char>;
@@ -821,31 +1051,63 @@
 
   if (arg.is_real_type ())
     {
-      NDArray m = arg.array_value ();
-
-      if (! error_state)
+      if (arg.is_sparse_type ())
 	{
-#ifdef HAVE_IEEE754_DATA_FORMAT
-	  // As operator > gives the right result, can special case here
-	  if (! return_idx && smode == ASCENDING)
-	    retval = mx_sort (m, dim);
-	  else
-#endif
+	  SparseMatrix m = arg.sparse_matrix_value ();
+
+	  if (! error_state)
 	    {
 	      if (return_idx)
-		retval = mx_sort_indexed (m, dim, smode);
+		retval = mx_sort_sparse_indexed (m, dim, smode);
 	      else
-		retval = mx_sort (m, dim, smode);
+		retval = mx_sort_sparse (m, dim, smode);
+	    }
+	}
+      else
+	{
+	  NDArray m = arg.array_value ();
+
+	  if (! error_state)
+	    {
+#ifdef HAVE_IEEE754_DATA_FORMAT
+	      // As operator > gives the right result, can special case here
+	      if (! return_idx && smode == ASCENDING)
+		retval = mx_sort (m, dim);
+	      else
+#endif
+		{
+		  if (return_idx)
+		    retval = mx_sort_indexed (m, dim, smode);
+		  else
+		    retval = mx_sort (m, dim, smode);
+		}
 	    }
 	}
     }
   else if (arg.is_complex_type ())
     {
-      ComplexNDArray cm = arg.complex_array_value ();
+      if (arg.is_sparse_type ())
+	{
+	  SparseComplexMatrix cm = arg.sparse_complex_matrix_value ();
 
-      // Don't have unindexed version as no ">" operator
-      if (! error_state)
-	retval = mx_sort_indexed (cm, dim, smode);
+	  if (! error_state)
+	    {
+	      if (return_idx)
+		retval = mx_sort_sparse_indexed (cm, dim, smode);
+	      else
+		retval = mx_sort_sparse (cm, dim, smode);
+	    }
+	}
+      else
+	{
+	  ComplexNDArray cm = arg.complex_array_value ();
+
+	  if (! error_state)
+	    {
+	      // The indexed version seems to be slightly faster
+	      retval = mx_sort_indexed (cm, dim, smode);
+	    }
+	}
     }
   else if (arg.is_string ())
     {
--- a/src/ov-cx-sparse.h	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/ov-cx-sparse.h	Wed Sep 05 07:53:45 2007 +0000
@@ -73,6 +73,17 @@
   octave_sparse_complex_matrix (const MSparse<Complex>& m)
     : octave_base_sparse<SparseComplexMatrix> (m) { }
 
+  octave_sparse_complex_matrix (const MSparse<Complex>& m, 
+				const MatrixType &t)
+    : octave_base_sparse<SparseComplexMatrix> (m, t) { }
+
+  octave_sparse_complex_matrix (const Sparse<Complex>& m, 
+				const MatrixType &t)
+    : octave_base_sparse<SparseComplexMatrix> (SparseComplexMatrix (m), t) { }
+
+  octave_sparse_complex_matrix (const Sparse<Complex>& m)
+    : octave_base_sparse<SparseComplexMatrix> (SparseComplexMatrix (m)) { }
+
   octave_sparse_complex_matrix (const octave_sparse_complex_matrix& cm)
     : octave_base_sparse<SparseComplexMatrix> (cm) { }
 
--- a/src/ov-re-sparse.h	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/ov-re-sparse.h	Wed Sep 05 07:53:45 2007 +0000
@@ -73,6 +73,15 @@
   octave_sparse_matrix (const MSparse<double>& m)
     : octave_base_sparse<SparseMatrix> (m) { }
     
+  octave_sparse_matrix (const MSparse<double>& m, const MatrixType& t)
+    : octave_base_sparse<SparseMatrix> (m, t) { }
+
+  octave_sparse_matrix (const Sparse<double>& m)
+    : octave_base_sparse<SparseMatrix> (SparseMatrix (m)) { }
+    
+  octave_sparse_matrix (const Sparse<double>& m, const MatrixType& t)
+    : octave_base_sparse<SparseMatrix> (SparseMatrix (m), t) { }
+
   octave_sparse_matrix (const octave_sparse_matrix& m)
     : octave_base_sparse<SparseMatrix> (m) { }
 
--- a/src/ov.cc	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/ov.cc	Wed Sep 05 07:53:45 2007 +0000
@@ -534,12 +534,24 @@
   maybe_mutate ();
 }
 
+octave_value::octave_value (const Sparse<double>& m, const MatrixType &t)
+  : rep (new octave_sparse_matrix (m, t))
+{
+  maybe_mutate ();
+}
+
 octave_value::octave_value (const SparseComplexMatrix& m, const MatrixType &t)
   : rep (new octave_sparse_complex_matrix (m, t))
 {
   maybe_mutate ();
 }
 
+octave_value::octave_value (const Sparse<Complex>& m, const MatrixType &t)
+  : rep (new octave_sparse_complex_matrix (m, t))
+{
+  maybe_mutate ();
+}
+
 octave_value::octave_value (const SparseBoolMatrix& bm, const MatrixType &t)
   : rep (new octave_sparse_bool_matrix (bm, t))
 {
--- a/src/ov.h	Wed Sep 05 06:49:29 2007 +0000
+++ b/src/ov.h	Wed Sep 05 07:53:45 2007 +0000
@@ -192,8 +192,10 @@
   octave_value (const ArrayN<char>& chnda, bool is_string = false,
 		char type = '"');
   octave_value (const SparseMatrix& m, const MatrixType& t = MatrixType ());
+  octave_value (const Sparse<double>& m, const MatrixType& t = MatrixType ());
   octave_value (const SparseComplexMatrix& m, 
 		const MatrixType& t = MatrixType ());
+  octave_value (const Sparse<Complex>& m, const MatrixType& t = MatrixType ());
   octave_value (const SparseBoolMatrix& bm, 
 		const MatrixType& t = MatrixType ());
   octave_value (const octave_int8& i);