changeset 8721:e9cb742df9eb

imported patch sort3.diff
author Jaroslav Hajek <highegg@gmail.com>
date Wed, 11 Feb 2009 15:25:53 +0100
parents dda421a1f1e6
children 3cedb606145d
files liboctave/Array-C.cc liboctave/Array-b.cc liboctave/Array-ch.cc liboctave/Array-d.cc liboctave/Array-f.cc liboctave/Array-fC.cc liboctave/Array-i.cc liboctave/Array-s.cc liboctave/Array.cc liboctave/Array.h liboctave/ChangeLog liboctave/CmplxQR.cc liboctave/Range.cc liboctave/Range.h liboctave/dbleQR.cc liboctave/dim-vector.h liboctave/fCmplxQR.cc liboctave/floatQR.cc liboctave/oct-sort.cc liboctave/oct-sort.h scripts/ChangeLog scripts/general/sortrows.m src/ChangeLog src/TEMPLATE-INST/Array-sym.cc src/TEMPLATE-INST/Array-tc.cc src/data.cc src/ov-base-diag.h src/ov-base-mat.h src/ov-base-scalar.h src/ov-base-sparse.h src/ov-base.cc src/ov-base.h src/ov-perm.h src/ov-range.h src/ov.h
diffstat 35 files changed, 949 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array-C.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-C.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -28,41 +28,79 @@
 // Instantiate Arrays of Complex values.
 
 #include "oct-cmplx.h"
+#include "lo-mappers.h"
 
 #include "Array.h"
 #include "Array.cc"
 #include "oct-sort.cc"
 
-static double
-xabs (const Complex& x)
+template <>
+inline bool _sort_isnan (Complex x)
 {
-  return (xisinf (x.real ()) || xisinf (x.imag ())) ? octave_Inf : abs (x);
+  return xisnan (x);
 }
 
 template <>
 bool
 octave_sort<Complex>::ascending_compare (Complex a, Complex b)
 {
-  return (xisnan (b) || (xabs (a) < xabs (b))
-	  || ((xabs (a) == xabs (b)) && (arg (a) < arg (b))));
+  return ((std::abs (a) < std::abs (b))
+	  || ((std::abs (a) == std::abs (b)) && (arg (a) < arg (b))));
 }
 
 template <>
 bool
 octave_sort<Complex>::descending_compare (Complex a, Complex b)
 {
-  return (xisnan (a) || (xabs (a) > xabs (b))
-	  || ((xabs (a) == xabs (b)) && (arg (a) > arg (b))));
+  return ((std::abs (a) > std::abs (b))
+	  || ((std::abs (a) == std::abs (b)) && (arg (a) > arg (b))));
+}
+
+static bool nan_ascending_compare (Complex x, Complex y)
+{
+  return xisnan (y) ? ! xisnan (x) : ((std::abs (x) < std::abs (x))
+	  || ((std::abs (x) == std::abs (x)) && (arg (x) < arg (x))));
+}
+
+static bool nan_descending_compare (Complex x, Complex y)
+{
+  return xisnan (x) ? ! xisnan (y) : ((std::abs (x) > std::abs (x))
+	  || ((std::abs (x) == std::abs (x)) && (arg (x) > arg (x))));
+}
+
+bool (*_sortrows_comparator (sortmode mode, 
+                             const Array<Complex>& a , bool allow_chk)) 
+(Complex, Complex)
+{
+  bool (*result) (Complex, Complex) = 0;
+
+  if (allow_chk)
+    {
+      octave_idx_type k = 0;
+      for (; k < a.numel () && ! xisnan (a(k)); k++) ;
+      if (k == a.numel ())
+        {
+          if (mode == ASCENDING)
+            result = octave_sort<Complex>::ascending_compare;
+          else if (mode == DESCENDING)
+            result = octave_sort<Complex>::descending_compare;
+        }
+    }
+
+  if (! result)
+    {
+      if (mode == ASCENDING)
+        result = nan_ascending_compare;
+      else if (mode == DESCENDING)
+        result = nan_descending_compare;
+    }
+
+  return result;
 }
 
 INSTANTIATE_ARRAY_SORT (Complex);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (Complex, OCTAVE_API);
-
-INSTANTIATE_ARRAY_ASSIGN (Complex, double, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (Complex, int, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (Complex, short, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (Complex, char, OCTAVE_API)
+INSTANTIATE_ARRAY (Complex, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-b.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-b.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -33,7 +33,7 @@
 
 INSTANTIATE_ARRAY_SORT (bool);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (bool, OCTAVE_API);
+INSTANTIATE_ARRAY (bool, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-ch.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-ch.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -33,7 +33,7 @@
 
 INSTANTIATE_ARRAY_SORT (char);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (char, OCTAVE_API);
+INSTANTIATE_ARRAY (char, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-d.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-d.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -42,13 +42,49 @@
   return lo_ieee_isnan (x);
 }
 
+static bool nan_ascending_compare (double x, double y)
+{
+  return lo_ieee_isnan (y) ? ! lo_ieee_isnan (x) : x < y;
+}
+
+static bool nan_descending_compare (double x, double y)
+{
+  return lo_ieee_isnan (x) ? ! lo_ieee_isnan (y) : x > y;
+}
+
+bool (*_sortrows_comparator (sortmode mode, 
+                             const Array<double>& a , bool allow_chk)) 
+(double, double)
+{
+  bool (*result) (double, double) = 0;
+
+  if (allow_chk)
+    {
+      octave_idx_type k = 0;
+      for (; k < a.numel () && ! xisnan (a(k)); k++) ;
+      if (k == a.numel ())
+        {
+          if (mode == ASCENDING)
+            result = octave_sort<double>::ascending_compare;
+          else if (mode == DESCENDING)
+            result = octave_sort<double>::descending_compare;
+        }
+    }
+
+  if (! result)
+    {
+      if (mode == ASCENDING)
+        result = nan_ascending_compare;
+      else if (mode == DESCENDING)
+        result = nan_descending_compare;
+    }
+
+  return result;
+}
+
 INSTANTIATE_ARRAY_SORT (double);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (double, OCTAVE_API);
-
-INSTANTIATE_ARRAY_ASSIGN (double, int, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (double, short, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (double, char, OCTAVE_API)
+INSTANTIATE_ARRAY (double, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-f.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-f.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -42,13 +42,49 @@
   return lo_ieee_isnan (x);
 }
 
+static bool nan_ascending_compare (float x, float y)
+{
+  return lo_ieee_isnan (y) ? ! lo_ieee_isnan (x) : x < y;
+}
+
+static bool nan_descending_compare (float x, float y)
+{
+  return lo_ieee_isnan (x) ? ! lo_ieee_isnan (y) : x > y;
+}
+
+bool (*_sortrows_comparator (sortmode mode, 
+                             const Array<float>& a , bool allow_chk)) 
+(float, float)
+{
+  bool (*result) (float, float) = 0;
+
+  if (allow_chk)
+    {
+      octave_idx_type k = 0;
+      for (; k < a.numel () && ! xisnan (a(k)); k++) ;
+      if (k == a.numel ())
+        {
+          if (mode == ASCENDING)
+            result = octave_sort<float>::ascending_compare;
+          else if (mode == DESCENDING)
+            result = octave_sort<float>::descending_compare;
+        }
+    }
+
+  if (! result)
+    {
+      if (mode == ASCENDING)
+        result = nan_ascending_compare;
+      else if (mode == DESCENDING)
+        result = nan_descending_compare;
+    }
+
+  return result;
+}
+
 INSTANTIATE_ARRAY_SORT (float);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (float, OCTAVE_API);
-
-INSTANTIATE_ARRAY_ASSIGN (float, int, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (float, short, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (float, char, OCTAVE_API)
+INSTANTIATE_ARRAY (float, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-fC.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-fC.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -28,41 +28,79 @@
 // Instantiate Arrays of FloatComplex values.
 
 #include "oct-cmplx.h"
+#include "lo-mappers.h"
 
 #include "Array.h"
 #include "Array.cc"
 #include "oct-sort.cc"
 
-static float
-xabs (const FloatComplex& x)
+template <>
+inline bool _sort_isnan (FloatComplex x)
 {
-  return (xisinf (x.real ()) || xisinf (x.imag ())) ? octave_Float_Inf : abs (x);
+  return xisnan (x);
 }
 
 template <>
 bool
 octave_sort<FloatComplex>::ascending_compare (FloatComplex a, FloatComplex b)
 {
-  return (xisnan (b) || (xabs (a) < xabs (b))
-	  || ((xabs (a) == xabs (b)) && (arg (a) < arg (b))));
+  return ((std::abs (a) < std::abs (b))
+	  || ((std::abs (a) == std::abs (b)) && (arg (a) < arg (b))));
 }
 
 template <>
 bool
 octave_sort<FloatComplex>::descending_compare (FloatComplex a, FloatComplex b)
 {
-  return (xisnan (a) || (xabs (a) > xabs (b))
-	  || ((xabs (a) == xabs (b)) && (arg (a) > arg (b))));
+  return ((std::abs (a) > std::abs (b))
+	  || ((std::abs (a) == std::abs (b)) && (arg (a) > arg (b))));
+}
+
+static bool nan_ascending_compare (FloatComplex x, FloatComplex y)
+{
+  return xisnan (y) ? ! xisnan (x) : ((std::abs (x) < std::abs (x))
+	  || ((std::abs (x) == std::abs (x)) && (arg (x) < arg (x))));
+}
+
+static bool nan_descending_compare (FloatComplex x, FloatComplex y)
+{
+  return xisnan (x) ? ! xisnan (y) : ((std::abs (x) > std::abs (x))
+	  || ((std::abs (x) == std::abs (x)) && (arg (x) > arg (x))));
+}
+
+bool (*_sortrows_comparator (sortmode mode, 
+                             const Array<FloatComplex>& a , bool allow_chk)) 
+(FloatComplex, FloatComplex)
+{
+  bool (*result) (FloatComplex, FloatComplex) = 0;
+
+  if (allow_chk)
+    {
+      octave_idx_type k = 0;
+      for (; k < a.numel () && ! xisnan (a(k)); k++) ;
+      if (k == a.numel ())
+        {
+          if (mode == ASCENDING)
+            result = octave_sort<FloatComplex>::ascending_compare;
+          else if (mode == DESCENDING)
+            result = octave_sort<FloatComplex>::descending_compare;
+        }
+    }
+
+  if (! result)
+    {
+      if (mode == ASCENDING)
+        result = nan_ascending_compare;
+      else if (mode == DESCENDING)
+        result = nan_descending_compare;
+    }
+
+  return result;
 }
 
 INSTANTIATE_ARRAY_SORT (FloatComplex);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (FloatComplex, OCTAVE_API);
-
-INSTANTIATE_ARRAY_ASSIGN (FloatComplex, float, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (FloatComplex, int, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (FloatComplex, short, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (FloatComplex, char, OCTAVE_API)
+INSTANTIATE_ARRAY (FloatComplex, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-i.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-i.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -42,34 +42,31 @@
 INSTANTIATE_ARRAY_SORT (long long);
 #endif
 
-INSTANTIATE_ARRAY_AND_ASSIGN (int, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (long, OCTAVE_API);
+INSTANTIATE_ARRAY (int, OCTAVE_API);
+INSTANTIATE_ARRAY (long, OCTAVE_API);
 #if defined (HAVE_LONG_LONG_INT)
-INSTANTIATE_ARRAY_AND_ASSIGN (long long, OCTAVE_API);
+INSTANTIATE_ARRAY (long long, OCTAVE_API);
 #endif
 
-INSTANTIATE_ARRAY_ASSIGN (int, short, OCTAVE_API)
-INSTANTIATE_ARRAY_ASSIGN (int, char, OCTAVE_API)
-
 INSTANTIATE_ARRAY_SORT (octave_int8);
 INSTANTIATE_ARRAY_SORT (octave_int16);
 INSTANTIATE_ARRAY_SORT (octave_int32);
 INSTANTIATE_ARRAY_SORT (octave_int64);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_int8, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_int16, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_int32, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_int64, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_int8, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_int16, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_int32, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_int64, OCTAVE_API);
 
 INSTANTIATE_ARRAY_SORT (octave_uint8);
 INSTANTIATE_ARRAY_SORT (octave_uint16);
 INSTANTIATE_ARRAY_SORT (octave_uint32);
 INSTANTIATE_ARRAY_SORT (octave_uint64);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_uint8, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_uint16, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_uint32, OCTAVE_API);
-INSTANTIATE_ARRAY_AND_ASSIGN (octave_uint64, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_uint8, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_uint16, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_uint32, OCTAVE_API);
+INSTANTIATE_ARRAY (octave_uint64, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array-s.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array-s.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -36,9 +36,7 @@
 
 INSTANTIATE_ARRAY_SORT (short);
 
-INSTANTIATE_ARRAY_AND_ASSIGN (short, OCTAVE_API);
-
-INSTANTIATE_ARRAY_ASSIGN (short, char, OCTAVE_API)
+INSTANTIATE_ARRAY (short, OCTAVE_API);
 
 #include "Array2.h"
 
--- a/liboctave/Array.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -1987,6 +1987,13 @@
 Array<T>
 Array<T>::sort (octave_idx_type dim, sortmode mode) const
 {
+  if (dim < 0 || dim >= ndims ())
+    {
+      (*current_liboctave_error_handler)
+        ("sort: invalid dimension");
+      return Array<T> ();
+    }
+
   Array<T> m (dims ());
 
   dim_vector dv = m.dims ();
@@ -2006,12 +2013,10 @@
 
   octave_sort<T> lsort;
   
-  if (mode == ASCENDING) 
-    lsort.set_compare (octave_sort<T>::ascending_compare);
-  else if (mode == DESCENDING)
-    lsort.set_compare (octave_sort<T>::descending_compare);
+  if (mode) 
+    lsort.set_compare (mode);
   else
-    abort ();
+    return m;
 
   if (stride == 1)
     {
@@ -2098,6 +2103,13 @@
 Array<T>::sort (Array<octave_idx_type> &sidx, octave_idx_type dim, 
 		sortmode mode) const
 {
+  if (dim < 0 || dim >= ndims ())
+    {
+      (*current_liboctave_error_handler)
+        ("sort: invalid dimension");
+      return Array<T> ();
+    }
+
   Array<T> m (dims ());
 
   dim_vector dv = m.dims ();
@@ -2123,12 +2135,10 @@
   sidx = Array<octave_idx_type> (dv);
   octave_idx_type *vi = sidx.fortran_vec ();
   
-  if (mode == ASCENDING) 
-    lsort.set_compare (octave_sort<T>::ascending_compare);
-  else if (mode == DESCENDING)
-    lsort.set_compare (octave_sort<T>::descending_compare);
+  if (mode) 
+    lsort.set_compare (mode);
   else
-    abort ();
+    return m;
 
   if (stride == 1)
     {
@@ -2239,6 +2249,171 @@
 }
 
 template <class T>
+sortmode
+Array<T>::is_sorted (sortmode mode) const
+{
+  if (nelem () <= 1)
+    return ASCENDING;
+
+  const T *lo = data (), *hi = data () + nelem () - 1;
+
+  // Check for NaNs at the beginning and end.
+  if (mode != ASCENDING && _sort_isnan (*lo))
+    {
+      mode = DESCENDING;
+      do
+        ++lo;
+      while (lo < hi && _sort_isnan (*lo));
+    }
+  else if (mode != DESCENDING && _sort_isnan (*hi))
+    {
+      mode = ASCENDING;
+      do
+        --hi;
+      while (lo < hi && _sort_isnan (*hi));
+    }
+  
+  octave_sort<T> lsort;
+
+  // If mode is still unknown, compare lo and hi
+  if (! mode)
+    {
+      if (lsort.descending_compare (*lo, *hi))
+        mode = DESCENDING;
+      else if (lsort.ascending_compare (*lo, *hi))
+        mode = ASCENDING;
+      else
+        mode = ASCENDING;
+    }
+
+  lsort.set_compare (mode);
+
+  if (! lsort.is_sorted (lo, hi - lo + 1))
+    mode = UNSORTED;
+
+  return mode;
+}
+
+template <class T>
+bool (*_sortrows_comparator (sortmode mode, 
+                             const Array<T>& /* a */, bool /* allow_chk */)) (T, T)
+{
+  if (mode == ASCENDING)
+    return octave_sort<T>::ascending_compare;
+  else if (mode == DESCENDING)
+    return octave_sort<T>::descending_compare;
+  else
+    return 0;
+}
+
+template <class T>
+Array<octave_idx_type>
+Array<T>::sort_rows_idx (sortmode mode) const
+{
+  Array<octave_idx_type> idx;
+
+  octave_sort<T> lsort;
+
+  lsort.set_compare (_sortrows_comparator (mode, *this, true));
+
+  octave_idx_type r = rows (), c = cols ();
+
+  idx = Array<octave_idx_type> (r);
+
+  lsort.sort_rows (data (), idx.fortran_vec (), r, c);
+
+  return idx;
+}
+
+
+template <class T>
+sortmode 
+Array<T>::is_sorted_rows (sortmode mode) const
+{
+  octave_sort<T> lsort;
+
+  octave_idx_type r = rows (), c = cols ();
+
+  if (r <= 1 || c == 0)
+    return mode ? mode : ASCENDING;
+
+  if (! mode)
+    {
+      // Auto-detect mode.
+      bool (*compare) (T, T) = _sortrows_comparator (ASCENDING, *this, false);
+
+      octave_idx_type i;
+      for (i = 0; i < cols (); i++)
+        {
+          T l = elem (0, i), u = elem (rows () - 1, i);
+          if (compare (l, u))
+            {
+              if (mode == DESCENDING)
+                {
+                  mode = UNSORTED;
+                  break;
+                }
+              else
+                mode = ASCENDING;
+            }
+          else if (compare (u, l))
+            {
+              if (mode == ASCENDING)
+                {
+                  mode = UNSORTED;
+                  break;
+                }
+              else
+                mode = DESCENDING;
+            }
+        }
+      if (! mode && i == cols ())
+        mode = ASCENDING;
+    }
+
+  if (mode)
+    {
+      lsort.set_compare (_sortrows_comparator (mode, *this, false));
+
+      if (! lsort.is_sorted_rows (data (), r, c))
+        mode = UNSORTED;
+    }
+
+  return mode;
+
+}
+
+#define INSTANTIATE_ARRAY_SORT(T) template class octave_sort<T>;
+
+#define NO_INSTANTIATE_ARRAY_SORT(T) \
+ \
+template <> Array<T>  \
+Array<T>::sort (octave_idx_type, sortmode) const { return *this; } \
+ \
+template <> Array<T>  \
+Array<T>::sort (Array<octave_idx_type> &sidx, octave_idx_type, sortmode) const \
+{ sidx = Array<octave_idx_type> (); return *this; } \
+ \
+template <> sortmode  \
+Array<T>::is_sorted (sortmode) const  \
+{ return UNSORTED; } \
+ \
+template <> \
+bool (*_sortrows_comparator (sortmode,  \
+                             const Array<T>&, bool)) (T, T) \
+{ return 0; } \
+ \
+template <> Array<octave_idx_type>  \
+Array<T>::sort_rows_idx (sortmode) const  \
+{ return Array<octave_idx_type> (); } \
+ \
+template <> sortmode  \
+Array<T>::is_sorted_rows (sortmode) const \
+{ return UNSORTED; } \
+
+
+
+template <class T>
 Array<T>
 Array<T>::diag (octave_idx_type k) const
 {
@@ -2342,6 +2517,9 @@
   //     << prefix << "cols: " << cols () << "\n";
 }
 
+#define INSTANTIATE_ARRAY(T, API) \
+  template class API Array<T>
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/liboctave/Array.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Array.h	Wed Feb 11 15:25:53 2009 +0100
@@ -554,6 +554,15 @@
   Array<T> sort (Array<octave_idx_type> &sidx, octave_idx_type dim = 0,
 		 sortmode mode = ASCENDING) const;
 
+  // Ordering is auto-detected or can be specified.
+  sortmode is_sorted (sortmode mode = UNSORTED) const;
+
+  // Sort by rows returns only indices.
+  Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
+
+  // Ordering is auto-detected or can be specified.
+  sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
+
   Array<T> diag (octave_idx_type k = 0) const;
 
   template <class U, class F>
@@ -578,30 +587,6 @@
   }
 };
 
-#define INSTANTIATE_ARRAY(T, API) \
-  template class API Array<T>
-
-// FIXME -- these are here for compatibility.  In the current
-// implementation, only homogeneous array assignments are actually
-// instantiated.  I think heterogeneous indexed assignments are rare
-// enough to be implemented via conversion first.  This decision may
-// still be revised, that's why these macros stay here.
-#define INSTANTIATE_ARRAY_AND_ASSIGN(T, API) \
-  INSTANTIATE_ARRAY(T, API)
-
-#define INSTANTIATE_ARRAY_ASSIGN(LT, RT, API)
-  // do nothing
-
-#define INSTANTIATE_ARRAY_SORT(T) \
-  template class octave_sort<T>; \
-
-#define NO_INSTANTIATE_ARRAY_SORT(T) \
-  template <> Array<T> Array<T>::sort \
-    (octave_idx_type, sortmode) const { return *this; } \
-  template <> Array<T> Array<T>::sort (Array<octave_idx_type> &sidx, \
-    octave_idx_type, sortmode) const \
-    { sidx = Array<octave_idx_type> (); return *this; }
-
 #endif
 
 /*
--- a/liboctave/ChangeLog	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/ChangeLog	Wed Feb 11 15:25:53 2009 +0100
@@ -1,3 +1,23 @@
+2009-02-11  Jaroslav Hajek  <highegg@gmail.com>
+
+	* oct-sort.cc (octave_sort<T>::is_sorted, octave_sort<T>::sort_rows,
+	octave_sort<T>::is_sorted_rows): New methods.
+	* oct-sort.h: Declare them.
+
+	* Array.cc (Array<T>::is_sorted): New method.
+	(INSTANTIATE_ARRAY_SORT, NO_INSTANTIATE_ARRAY_SORT,
+	INSTANTIATE_ARRAY_AND_ASSIGN, INSTANTIATE_ARRAY): Move macros here.
+	* Array.h: Reflect changes.
+
+	* dim-vector.h (dim_vector::is_vector): New method.
+	* Array-C.cc, Array-fC.cc: Override _sort_isnan, don't check for 
+	NaN in default comparators. Provide NaN-safe comparators, override
+	_sortrows_comparator.
+	* Array-d.cc, Array-f.cc: Provide NaN-safe comparators, override
+	_sortrows_comparator.	
+	* Range.cc (Range::is_sorted): New method.
+	* Range.h: Declare it.
+
 2009-02-09  Jaroslav Hajek  <highegg@gmail.com>
 
 	* oct-sort.cc (octave_sort<T>): Rewrite for optimizations. Allow
--- a/liboctave/CmplxQR.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/CmplxQR.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -293,7 +293,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -365,7 +365,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -590,7 +590,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -636,7 +636,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
--- a/liboctave/Range.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Range.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -223,8 +223,6 @@
 	retval.sort_internal (true);
       else if (mode == DESCENDING)
 	retval.sort_internal (false);
-      else
-	abort ();
     }
   else if (dim != 0)
     (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
@@ -244,8 +242,6 @@
 	  retval.sort_internal (sidx, true);
       else if (mode == DESCENDING)
 	retval.sort_internal (sidx, false);
-      else
-	abort ();
     }
   else if (dim != 0)
     (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
@@ -253,6 +249,17 @@
   return retval;
 }
 
+sortmode
+Range::is_sorted (sortmode mode) const
+{
+  if (rng_nelem > 1 && rng_inc < 0)
+    mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
+  else if (rng_nelem > 1 && rng_inc > 0)
+    mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
+  else
+    mode = mode ? mode : ASCENDING;
+}
+
 std::ostream&
 operator << (std::ostream& os, const Range& a)
 {
--- a/liboctave/Range.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/Range.h	Wed Feb 11 15:25:53 2009 +0100
@@ -77,6 +77,8 @@
   Range sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
 	      sortmode mode = ASCENDING) const;
 
+  sortmode is_sorted (sortmode mode = ASCENDING) const;
+
   void set_base (double b)
   {
     if (rng_base != b)
--- a/liboctave/dbleQR.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/dbleQR.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -289,7 +289,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -361,7 +361,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -584,7 +584,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -630,7 +630,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
--- a/liboctave/dim-vector.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/dim-vector.h	Wed Feb 11 15:25:53 2009 +0100
@@ -503,6 +503,12 @@
           return retval;
         }
     }
+
+  bool is_vector (void) const
+    {
+      return (length () == 2 && (elem (0) == 1 || elem (1) == 1));
+    }
+
 };
 
 static inline bool
--- a/liboctave/fCmplxQR.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/fCmplxQR.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -293,7 +293,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -364,7 +364,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -589,7 +589,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -635,7 +635,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
--- a/liboctave/floatQR.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/floatQR.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -289,7 +289,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -361,7 +361,7 @@
   octave_idx_type k = q.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -584,7 +584,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, ASCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
@@ -630,7 +630,7 @@
   octave_idx_type n = r.columns ();
 
   Array<octave_idx_type> jsi;
-  Array<octave_idx_type> js = j.sort (jsi, DESCENDING);
+  Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
   octave_idx_type nj = js.length ();
   bool dups = false;
   for (octave_idx_type i = 0; i < nj - 1; i++)
--- a/liboctave/oct-sort.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/oct-sort.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -97,25 +97,37 @@
 #include <cassert>
 #include <algorithm>
 #include <cstring>
+#include <stack>
 
 #include "lo-mappers.h"
 #include "quit.h"
 #include "oct-sort.h"
+#include "oct-locbuf.h"
 
 template <class T>
 octave_sort<T>::octave_sort (void) : compare (ascending_compare)
 { 
   merge_init ();
-  merge_getmem (1024);
 }
 
 template <class T>
 octave_sort<T>::octave_sort (bool (*comp) (T, T)) : compare (comp) 
 { 
   merge_init (); 
-  merge_getmem (1024);
 }
-  
+
+template <class T>
+void
+octave_sort<T>::set_compare (sortmode mode)
+{
+  if (mode == ASCENDING)
+    compare = ascending_compare;
+  else if (mode == DESCENDING)
+    compare = descending_compare;
+  else
+    compare = 0;
+}
+
 template <class T>
 template <class Comp>
 void
@@ -1508,6 +1520,7 @@
 void
 octave_sort<T>::sort (T *data, octave_idx_type nel)
 {
+  merge_getmem (1024);
 #ifdef INLINE_ASCENDING_SORT
   if (compare == ascending_compare)
     sort (data, nel, std::less<T> ());
@@ -1515,7 +1528,7 @@
 #endif
 #ifdef INLINE_DESCENDING_SORT    
     if (compare == descending_compare)
-    sort (data, nel, std::greater<T> ());
+      sort (data, nel, std::greater<T> ());
   else
 #endif
     if (compare)
@@ -1526,6 +1539,7 @@
 void
 octave_sort<T>::sort (T *data, octave_idx_type *idx, octave_idx_type nel)
 {
+  merge_getmemi (1024);
 #ifdef INLINE_ASCENDING_SORT
   if (compare == ascending_compare)
     sort (data, idx, nel, std::less<T> ());
@@ -1533,13 +1547,220 @@
 #endif
 #ifdef INLINE_DESCENDING_SORT    
     if (compare == descending_compare)
-    sort (data, idx, nel, std::greater<T> ());
+      sort (data, idx, nel, std::greater<T> ());
   else
 #endif
     if (compare)
       sort (data, idx, nel, compare);
 }
 
+template <class T> template <class Comp>
+bool 
+octave_sort<T>::is_sorted (const T *data, octave_idx_type nel, Comp comp)
+{
+  const T *end = data + nel;
+  if (data != end)
+    {
+      const T *next = data;
+      while (++next != end)
+        {
+          if (comp (*next, *data))
+            break;
+          data = next;
+        }
+      data = next;
+    }
+
+  return data == end;
+}
+
+template <class T> 
+bool 
+octave_sort<T>::is_sorted (const T *data, octave_idx_type nel)
+{
+  bool retval = false;
+#ifdef INLINE_ASCENDING_SORT
+  if (compare == ascending_compare)
+    retval = is_sorted (data, nel, std::less<T> ());
+  else
+#endif
+#ifdef INLINE_DESCENDING_SORT    
+    if (compare == descending_compare)
+      retval = is_sorted (data, nel, std::greater<T> ());
+  else
+#endif
+    if (compare)
+      retval = is_sorted (data, nel, compare);
+
+  return retval;
+}
+
+// FIXME: is there really no way to make this local to the following function?
+struct sortrows_run_t
+{
+  sortrows_run_t (octave_idx_type c, octave_idx_type o, octave_idx_type n)
+    : col (c), ofs (o), nel (n) { }
+  octave_idx_type col, ofs, nel;
+};
+
+
+template <class T> template <class Comp>
+void 
+octave_sort<T>::sort_rows (const T *data, octave_idx_type *idx,
+                           octave_idx_type rows, octave_idx_type cols,
+                           Comp comp)
+{
+  OCTAVE_LOCAL_BUFFER (T, buf, rows);
+  for (octave_idx_type i = 0; i < rows; i++)
+    idx[i] = i;
+
+  if (cols == 0 || rows <= 1)
+    return;
+
+
+  // This is a breadth-first traversal.
+  typedef sortrows_run_t run_t;
+  std::stack<run_t> runs;
+
+  runs.push (run_t (0, 0, rows));
+
+  while (! runs.empty ())
+    {
+      octave_idx_type col  = runs.top ().col;
+      octave_idx_type ofs  = runs.top ().ofs;
+      octave_idx_type nel  = runs.top ().nel;
+      runs.pop ();
+      assert (nel > 1);
+
+      T *lbuf = buf + ofs;
+      const T *ldata = data + rows*col;
+      octave_idx_type *lidx = idx + ofs;
+
+      // Gather.
+      for (octave_idx_type i = 0; i < nel; i++)
+        lbuf[i] = ldata[lidx[i]];
+
+      // Sort.
+      sort (lbuf, lidx, nel, comp);
+
+      // Identify constant runs and schedule subsorts.
+      if (col < cols-1)
+        {
+          octave_idx_type lst = 0;
+          for (octave_idx_type i = 0; i < nel; i++)
+            {
+              if (comp (lbuf[lst], lbuf[i]))
+                {
+                  if (i > lst + 1)
+                    runs.push (run_t (col+1, lst, i - lst));
+                  lst = i;
+                }
+            }
+          if (nel > lst + 1)
+            runs.push (run_t (col+1, lst, nel - lst));
+        }
+    }
+}
+
+template <class T>
+void 
+octave_sort<T>::sort_rows (const T *data, octave_idx_type *idx,
+                           octave_idx_type rows, octave_idx_type cols)
+{
+#ifdef INLINE_ASCENDING_SORT
+  if (compare == ascending_compare)
+    sort_rows (data, idx, rows, cols, std::less<T> ());
+  else
+#endif
+#ifdef INLINE_DESCENDING_SORT    
+    if (compare == descending_compare)
+      sort_rows (data, idx, rows, cols, std::greater<T> ());
+  else
+#endif
+    if (compare)
+      sort_rows (data, idx, rows, cols, compare);
+}
+
+template <class T> template <class Comp>
+bool 
+octave_sort<T>::is_sorted_rows (const T *data, octave_idx_type rows, 
+                                octave_idx_type cols, Comp comp)
+{
+  if (rows <= 1 || cols == 0)
+    return true;
+    
+  // This is a breadth-first traversal.
+  const T *lastrow = data + rows*(cols - 1);
+  typedef std::pair<const T *, octave_idx_type> run_t;
+  std::stack<run_t> runs;
+
+  bool sorted = true;
+  runs.push (run_t (data, rows));
+  while (sorted && ! runs.empty ())
+    {
+      const T *lo = runs.top ().first;
+      octave_idx_type n = runs.top ().second;
+      runs.pop ();
+      if (lo < lastrow)
+        {
+          // Not the final column.
+          assert (n > 1);
+          const T *hi = lo + n, *lst = lo;
+          for (lo++; lo < hi; lo++)
+            {
+              if (comp (*lst, *lo))
+                {
+                  if (lo > lst + 1)
+                      runs.push (run_t (lst + rows, lo - lst));
+                  lst = lo;
+                }
+              else if (comp (*lo, *lst))
+                break;
+
+            }
+          if (lo == hi)
+            {
+              if (lo > lst + 1)
+                runs.push (run_t (lst + rows, lo - lst));
+            }
+          else
+            {
+              sorted = false;
+              break;
+            }
+        }
+      else
+        // The final column - use fast code.
+        sorted = is_sorted (lo, n, comp);
+    }
+      
+  return sorted;
+}
+
+template <class T>
+bool 
+octave_sort<T>::is_sorted_rows (const T *data, octave_idx_type rows, 
+                                octave_idx_type cols)
+{
+  bool retval = false;
+
+#ifdef INLINE_ASCENDING_SORT
+  if (compare == ascending_compare)
+    retval = is_sorted_rows (data, rows, cols, std::less<T> ());
+  else
+#endif
+#ifdef INLINE_DESCENDING_SORT    
+    if (compare == descending_compare)
+      retval = is_sorted_rows (data, rows, cols, std::greater<T> ());
+  else
+#endif
+    if (compare)
+      retval = is_sorted_rows (data, rows, cols, compare);
+
+  return retval;
+}
+
+
 template <class T>
 bool 
 octave_sort<T>::ascending_compare (T x, T y)
--- a/liboctave/oct-sort.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/liboctave/oct-sort.h	Wed Feb 11 15:25:53 2009 +0100
@@ -97,7 +97,7 @@
 #define MERGESTATE_TEMP_SIZE 1024
 
 // Enum for type of sort function
-enum sortmode { ASCENDING, DESCENDING };
+enum sortmode { UNSORTED = 0, ASCENDING, DESCENDING };
 
 template <class T>
 class
@@ -113,10 +113,26 @@
 
   void set_compare (bool (*comp) (T, T)) { compare = comp; }
 
+  void set_compare (sortmode mode);
+
+  // Sort an array in-place.
   void sort (T *data, octave_idx_type nel);
 
+  // Ditto, but also permute the passed indices (may not be valid indices).
   void sort (T *data, octave_idx_type *idx, octave_idx_type nel);
 
+  // Check whether an array is sorted.
+  bool is_sorted (const T *data, octave_idx_type nel);
+
+  // Sort a matrix by rows, return a permutation
+  // vector.
+  void sort_rows (const T *data, octave_idx_type *idx,
+                  octave_idx_type rows, octave_idx_type cols);
+
+  // Determine whether a matrix (as a contiguous block) is sorted by rows.
+  bool is_sorted_rows (const T *data, 
+                       octave_idx_type rows, octave_idx_type cols);
+
   static bool ascending_compare (T, T);
   static bool descending_compare (T, T);
 
@@ -241,6 +257,18 @@
   template <class Comp>
   void sort (T *data, octave_idx_type *idx, octave_idx_type nel, Comp comp);
 
+  template <class Comp>
+  bool is_sorted (const T *data, octave_idx_type nel, Comp comp);
+
+  template <class Comp>
+  void sort_rows (const T *data, octave_idx_type *idx,
+                  octave_idx_type rows, octave_idx_type cols,
+                  Comp comp);
+
+  template <class Comp>
+  bool is_sorted_rows (const T *data, octave_idx_type rows, 
+                       octave_idx_type cols, Comp comp);
+
 };
 
 template <class T>
--- a/scripts/ChangeLog	Wed Feb 11 01:48:39 2009 -0500
+++ b/scripts/ChangeLog	Wed Feb 11 15:25:53 2009 +0100
@@ -1,3 +1,8 @@
+2009-02-11  Jaroslav Hajek  <highegg@gmail.com>
+
+	* general/sortrows.m: Employ __sortrows_idx__ when applicable,
+	gripe for sparse matrices.
+
 2009-02-11  John W. Eaton  <jwe@octave.org>
 
 	* miscellaneous/news.m: Look in octetcdir for NEWS file.
--- a/scripts/general/sortrows.m	Wed Feb 11 01:48:39 2009 -0500
+++ b/scripts/general/sortrows.m	Wed Feb 11 15:25:53 2009 +0100
@@ -1,4 +1,5 @@
 ## Copyright (C) 2000, 2005, 2007 Daniel Calvelo
+## Copyright (C) 2009 Jaroslav Hajek
 ##
 ## This file is part of Octave.
 ##
@@ -32,10 +33,20 @@
 
   default_mode = "ascend";
   other_mode = "descend";
-  if (nargin < 2)
-    indices = [1:size(m,2)]';
-    mode(1:size(m,2)) = {default_mode};
+
+  if (issparse (m))
+    error ("sortrows: sparse matrices not yet supported");
+  endif
+
+  ## If the sort is homogeneous, we use the built-in faster algorithm.
+  if (nargin == 1)
+    i = __sortrows_idx__ (m, default_mode);
+  elseif (all (c > 0))
+    i = __sortrows_idx__ (m(:,c), default_mode);
+  elseif (all (c < 0))
+    i = __sortrows_idx__ (m(:,c), other_mode);
   else
+    ## Otherwise, fall back to the old algorithm
     for ii = 1:length (c);
       if (c(ii) < 0)
         mode{ii} = other_mode;
@@ -44,30 +55,21 @@
       endif
     endfor
     indices = abs(c(:));
-  endif
 
-  if (ischar (m))
-    s = toascii (m);
-  else
-    s = m;
+    ## Since sort is 'stable' the order of identical elements will be
+    ## preserved, so by traversing the sort indices in reverse order we
+    ## will make sure that identical elements in index i are subsorted by
+    ## index j.
+    indices = flipud (indices);
+    mode = flipud (mode');
+    i = [1:size(m,1)]';
+    for ii = 1:length (indices);
+      [trash, idx] = sort (m(i, indices(ii)), mode{ii});
+      i = i(idx);
+    endfor
   endif
 
-  ## Since sort is 'stable' the order of identical elements will be
-  ## preserved, so by traversing the sort indices in reverse order we
-  ## will make sure that identical elements in index i are subsorted by
-  ## index j.
-  indices = flipud (indices);
-  mode = flipud (mode');
-  i = [1:size(m,1)]';
-  for ii = 1:length (indices);
-    [trash, idx] = sort (s(:,indices(ii)), mode{ii});
-    s = s(idx,:);
-    i = i(idx);
-  endfor
-
-  if (ischar (m))
-    s = char (s);
-  endif
+  s = m(i,:);
 
 endfunction
 
--- a/src/ChangeLog	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ChangeLog	Wed Feb 11 15:25:53 2009 +0100
@@ -1,3 +1,25 @@
+2009-02-11  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov.h (octave_value::issorted, octave_value::sortrows_idx,
+	octave_value::issorted_rows): New methods.
+	* ov.cc (octave_base_value::issorted, octave_base_value::sortrows_idx,
+	octave_base_value::issorted_rows): New methods.
+	* ov.cc: Declare them.
+
+	* ov-base-mat.h (octave_base_matrix::issorted, octave_base_matrix::sortrows_idx,
+	octave_base_matrix::issorted_rows): New methods.
+
+	* ov-base-diag.h (octave_base_diag::issorted, octave_base_diag::sortrows_idx,
+	octave_base_diag::issorted_rows): New methods.
+
+	* ov-perm.h (octave_perm_matrix::issorted, octave_perm_matrix::sortrows_idx,
+	octave_perm_matrix::issorted_rows): New methods.
+
+	* ov-range.h (octave_range::issorted, octave_range::sortrows_idx,
+	octave_range::issorted_rows): New methods.
+
+	* data.cc (F__sortrows_idx__, Fissorted): New defuns.
+
 2009-02-11  John W. Eaton  <jwe@octave.org>
 
 	* toplev.cc (octave_config_info): Add octetcdir to the struct.
--- a/src/TEMPLATE-INST/Array-sym.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/TEMPLATE-INST/Array-sym.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -34,6 +34,8 @@
 
 typedef symbol_record* symbol_record_ptr;
 
+NO_INSTANTIATE_ARRAY_SORT (symbol_record_ptr);
+
 INSTANTIATE_ARRAY (symbol_record_ptr, OCTINTERP_API);
 
 /*
--- a/src/TEMPLATE-INST/Array-tc.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/TEMPLATE-INST/Array-tc.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -58,9 +58,7 @@
 
 INSTANTIATE_ARRAY_SORT (octave_value);
 
-template class OCTINTERP_API Array<octave_value>;
-
-INSTANTIATE_ARRAY_ASSIGN (octave_value, octave_value, OCTINTERP_API);
+INSTANTIATE_ARRAY (octave_value, OCTINTERP_API);
 
 template class OCTINTERP_API Array2<octave_value>;
 
--- a/src/data.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/data.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -2,6 +2,7 @@
 
 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
               2003, 2004, 2005, 2006, 2007 John W. Eaton
+Copyright (C) 2009 Jaroslav Hajek
 
 This file is part of Octave.
 
@@ -5573,6 +5574,106 @@
 
 */
 
+DEFUN (__sortrows_idx__, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File} {} __sortrows_idx__ (@var{a}, @var{mode})\n\
+Sort the rows of the matrix @var{a} according to the order specified\n\
+by @var{mode}, which can either be `ascend' or `descend'.\n\
+Returns the index vector.\n\
+\n\
+This function does not yet support sparse matrices.\n\
+@end deftypefn\n")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+  sortmode smode = ASCENDING;
+
+  if (nargin < 1 || nargin > 2 || (nargin == 2 && ! args(1).is_string ()))
+    {
+      print_usage ();
+      return retval;
+    }
+
+  if (nargin > 1)
+    {
+      std::string mode = args(1).string_value();
+      if (mode == "ascend")
+        smode = ASCENDING;
+      else if (mode == "descend")
+        smode = DESCENDING;
+      else
+        {
+          error ("__sortrows_idx__: mode must be either \"ascend\" or \"descend\"");
+          return retval;
+        }
+    }
+
+  octave_value arg = args(0);
+
+  if (arg.is_sparse_type ())
+    error ("__sortrows_idx__: sparse matrices not yet supported");
+  if (arg.ndims () == 2)
+    {
+      Array<octave_idx_type> idx = arg.sortrows_idx (smode);
+
+      retval = NDArray (idx, true);
+    }
+  else
+    error ("__sortrows_idx__: needs a 2-dimensional object");
+
+  return retval;
+}
+
+DEFUN (issorted, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File} {} issorted (@var{a}, @var{rows})\n\
+Returns true if the array is sorted, ascending or descending.\n\
+NaNs are treated is by @code{sort}. If @var{rows} is supplied and\n\
+has the value \"rows\", checks whether the array is sorted by rows\n\
+as if output by @code{sortrows} (with no options).\n\
+\n\
+This function does not yet support sparse matrices.\n\
+@seealso{sortrows, sort}\n\
+@end deftypefn\n")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1)
+    {
+      octave_value arg = args(0);
+      if (arg.dims ().is_vector ())
+        retval = args(0).issorted () != UNSORTED;
+      else
+        error ("issorted: needs a vector");
+    }
+  else if (nargin == 2)
+    {
+      if (args(1).is_string () && args(1).string_value () == "rows")
+        {
+          octave_value arg = args(0);
+          sortmode smode = ASCENDING;
+
+          if (arg.is_sparse_type ())
+            error ("issorted: sparse matrices not yet supported");
+          if (arg.ndims () == 2)
+            retval = arg.issorted_rows (smode) != UNSORTED;
+          else
+            error ("issorted: needs a 2-dimensional object");
+        }
+      else
+        error ("issorted: second argument must be \"rows\"");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-base-diag.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base-diag.h	Wed Feb 11 15:25:53 2009 +0100
@@ -106,6 +106,15 @@
 		     sortmode mode = ASCENDING) const
     { return to_dense ().sort (sidx, dim, mode); }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return to_dense ().issorted (mode); }
+
+  Array<octave_idx_type> sortrows_idx (sortmode mode = ASCENDING) const
+    { return to_dense ().sortrows_idx (mode); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return to_dense ().issorted_rows (mode); }
+
   bool is_matrix_type (void) const { return true; }
 
   bool is_numeric_type (void) const { return true; }
--- a/src/ov-base-mat.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base-mat.h	Wed Feb 11 15:25:53 2009 +0100
@@ -124,6 +124,15 @@
 		     sortmode mode = ASCENDING) const
     { return octave_value (matrix.sort (sidx, dim, mode)); }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return matrix.is_sorted (mode); }
+
+  Array<octave_idx_type> sortrows_idx (sortmode mode = ASCENDING) const
+    { return matrix.sort_rows_idx (mode); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return matrix.is_sorted_rows (mode); }
+
   bool is_matrix_type (void) const { return true; }
 
   bool is_numeric_type (void) const { return true; }
--- a/src/ov-base-scalar.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base-scalar.h	Wed Feb 11 15:25:53 2009 +0100
@@ -108,6 +108,15 @@
       return octave_value (scalar); 
     }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return mode ? mode : ASCENDING; }
+
+  Array<octave_idx_type> sortrows_idx (sortmode) const
+    { return Array<octave_idx_type> (1, 0); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return mode ? mode : ASCENDING; }
+
   MatrixType matrix_type (void) const { return typ; }
   MatrixType matrix_type (const MatrixType& _typ) const
     { MatrixType ret = typ; typ = _typ; return ret; }
--- a/src/ov-base-sparse.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base-sparse.h	Wed Feb 11 15:25:53 2009 +0100
@@ -126,6 +126,9 @@
 		     sortmode mode = ASCENDING) const
     { return octave_value (matrix.sort (sidx, dim, mode)); }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return full_value ().issorted (mode); }
+
   MatrixType matrix_type (void) const { return typ; }
   MatrixType matrix_type (const MatrixType& _typ) const
     { MatrixType ret = typ; typ = _typ; return ret; }
--- a/src/ov-base.cc	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base.cc	Wed Feb 11 15:25:53 2009 +0100
@@ -978,6 +978,30 @@
   return octave_value();
 }
 
+sortmode
+octave_base_value::issorted (sortmode) const
+{
+  gripe_wrong_type_arg ("octave_base_value::issorted ()", type_name ());
+
+  return UNSORTED;
+}
+
+Array<octave_idx_type>
+octave_base_value::sortrows_idx (sortmode) const
+{
+  gripe_wrong_type_arg ("octave_base_value::sortrows_idx ()", type_name ());
+
+  return Array<octave_idx_type> ();
+}
+
+sortmode
+octave_base_value::issorted_rows (sortmode) const
+{
+  gripe_wrong_type_arg ("octave_base_value::issorted_rows ()", type_name ());
+
+  return UNSORTED;
+}
+
 #define UNDEFINED_MAPPER(F) \
   octave_value \
   octave_base_value::F (void) const \
--- a/src/ov-base.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-base.h	Wed Feb 11 15:25:53 2009 +0100
@@ -515,6 +515,12 @@
 			     octave_idx_type dim = 0,
 			     sortmode mode = ASCENDING) const;
 
+  virtual sortmode issorted (sortmode mode = UNSORTED) const;
+
+  virtual Array<octave_idx_type> sortrows_idx (sortmode mode = ASCENDING) const;
+
+  virtual sortmode issorted_rows (sortmode mode = UNSORTED) const;
+
   virtual void lock (void);
 
   virtual void unlock (void);
--- a/src/ov-perm.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-perm.h	Wed Feb 11 15:25:53 2009 +0100
@@ -93,6 +93,15 @@
 		     sortmode mode = ASCENDING) const
     { return to_dense ().sort (sidx, dim, mode); }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return to_dense ().issorted (mode); }
+
+  Array<octave_idx_type> sortrows_idx (sortmode mode = ASCENDING) const
+    { return to_dense ().sortrows_idx (mode); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return to_dense ().issorted_rows (mode); }
+
   bool is_perm_matrix (void) const { return true; }
 
   bool is_matrix_type (void) const { return true; }
--- a/src/ov-range.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov-range.h	Wed Feb 11 15:25:53 2009 +0100
@@ -140,6 +140,15 @@
 		     sortmode mode = ASCENDING) const
     { return range.sort (sidx, dim, mode); }
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return range.is_sorted (mode); }
+
+  Array<octave_idx_type> sortrows_idx (sortmode) const
+    { return Array<octave_idx_type> (1, 0); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return mode ? mode : ASCENDING; }
+
   bool is_real_type (void) const { return true; }
 
   bool is_double_type (void) const { return true; }
--- a/src/ov.h	Wed Feb 11 01:48:39 2009 -0500
+++ b/src/ov.h	Wed Feb 11 15:25:53 2009 +0100
@@ -996,6 +996,15 @@
 		 sortmode mode = ASCENDING) const
     { return rep->sort (sidx, dim, mode); } 
 
+  sortmode issorted (sortmode mode = UNSORTED) const
+    { return rep->issorted (mode); }
+
+  Array<octave_idx_type> sortrows_idx (sortmode mode = ASCENDING) const
+    { return rep->sortrows_idx (mode); }
+
+  sortmode issorted_rows (sortmode mode = UNSORTED) const
+    { return rep->issorted_rows (mode); }
+
   void lock (void) { rep->lock (); }
 
   void unlock (void) { rep->unlock (); }