changeset 10425:0677c5d80b77

rewrite 1D sparse indexing
author Jaroslav Hajek <highegg@gmail.com>
date Fri, 19 Mar 2010 13:00:06 +0100
parents 0b05b204775b
children 4db7beace28e
files liboctave/Array-util.cc liboctave/Array-util.h liboctave/Array.cc liboctave/ChangeLog liboctave/Sparse.cc liboctave/Sparse.h liboctave/idx-vector.cc liboctave/idx-vector.h test/ChangeLog test/test_slice.m
diffstat 10 files changed, 251 insertions(+), 376 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array-util.cc	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/Array-util.cc	Fri Mar 19 13:00:06 2010 +0100
@@ -701,3 +701,16 @@
     (err_id, "subscript indices must be either positive integers or logicals.");
 }
 
+// FIXME -- the following is a common error message to resize,
+// regardless of whether it's called from assign or elsewhere.  It
+// seems OK to me, but eventually the gripe can be specialized.
+// Anyway, propagating various error messages into procedure is, IMHO,
+// a nonsense.  If anything, we should change error handling here (and
+// throughout liboctave) to allow custom handling of errors
+void gripe_invalid_resize (void)
+{
+  (*current_liboctave_error_with_id_handler)
+    ("Octave:invalid-resize", 
+     "Invalid resizing operation or ambiguous assignment to an out-of-bounds array element.");
+}
+
--- a/liboctave/Array-util.h	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/Array-util.h	Fri Mar 19 13:00:06 2010 +0100
@@ -116,4 +116,6 @@
 
 extern void OCTAVE_API gripe_invalid_index (void);
 
+extern void OCTAVE_API gripe_invalid_resize (void);
+
 #endif
--- a/liboctave/Array.cc	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/Array.cc	Fri Mar 19 13:00:06 2010 +0100
@@ -933,18 +933,6 @@
   return retval;
 }
 
-// FIXME -- the following is a common error message to resize,
-// regardless of whether it's called from assign or elsewhere.  It
-// seems OK to me, but eventually the gripe can be specialized.
-// Anyway, propagating various error messages into procedure is, IMHO,
-// a nonsense.  If anything, we should change error handling here (and
-// throughout liboctave) to allow custom handling of errors
-static void gripe_invalid_resize (void)
-{
-  (*current_liboctave_error_handler)
-    ("resize: Invalid resizing operation or ambiguous assignment to an out-of-bounds array element.");
-}
-
 // The default fill value.  Override if you want a different one.
 
 template <class T>
--- a/liboctave/ChangeLog	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/ChangeLog	Fri Mar 19 13:00:06 2010 +0100
@@ -1,3 +1,21 @@
+2010-03-19  Jaroslav Hajek  <highegg@gmail.com>
+
+	* Array-util.cc (gripe_invalid_resize): Move here from Array.cc.
+	* Array-util.h: Declare it.
+	* Array.cc: Use it.
+
+	* idx-vector.cc (idx_vector::idx_mask_rep::unconvert): Fix non-owned
+	case.
+	(idx_vector::idx_mask_rep::as_array): New method.
+	* idx-vector.h: Declare it.
+
+	* Sparse.cc (Sparse<T>::index (const idx_vector&, bool)): Rewrite.
+	(Sparse<T>::array_value): New method.
+	(Sparse<T>::resize1): New method.
+	(Sparse<T>::resize): Move resize_no_fill bodies in here.
+	(Sparse<T>::resize_no_fill): Remove.
+	* Sparse.h: Update decls.
+
 2010-03-18  Jaroslav Hajek  <highegg@gmail.com>
 
 	* Sparse.h (Sparse<T>::index): Use const references. Use bool for
--- a/liboctave/Sparse.cc	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/Sparse.cc	Fri Mar 19 13:00:06 2010 +0100
@@ -45,6 +45,7 @@
 #include "sparse-sort.h"
 #include "sparse-util.h"
 #include "oct-spparms.h"
+#include "mx-inlines.cc"
 
 template <class T>
 T&
@@ -819,7 +820,21 @@
 
 template <class T>
 void
-Sparse<T>::resize_no_fill (const dim_vector& dv)
+Sparse<T>::resize1 (octave_idx_type n)
+{
+  octave_idx_type nr = rows (), nc = cols ();
+
+  if (nr == 1 || nr == 0)
+    resize (1, n);
+  else if (nc == 1)
+    resize (n, 1);
+  else
+    gripe_invalid_resize ();
+}
+
+template <class T>
+void
+Sparse<T>::resize (const dim_vector& dv)
 {
   octave_idx_type n = dv.length ();
 
@@ -829,12 +844,12 @@
       return;
     }
 
-  resize_no_fill (dv(0), dv(1));
+  resize (dv(0), dv(1));
 }
 
 template <class T>
 void
-Sparse<T>::resize_no_fill (octave_idx_type r, octave_idx_type c)
+Sparse<T>::resize (octave_idx_type r, octave_idx_type c)
 {
   if (r < 0 || c < 0)
     {
@@ -1137,7 +1152,7 @@
       // preserve the orientation of the vector, you have to use
       // A(idx,:) = [] (delete rows) or A(:,idx) (delete columns).
 
-      resize_no_fill (0, 0);
+      resize (0, 0);
       return;
     }
 
@@ -1381,7 +1396,7 @@
           // A(:,:) -- We are deleting columns and rows, so the result
           // is [](0x0).
 
-          resize_no_fill (0, 0);
+          resize (0, 0);
           return;
         }
 
@@ -1391,7 +1406,7 @@
           // If we enumerate all of them, we should have zero columns
           // with the same number of rows that we started with.
 
-          resize_no_fill (nr, 0);
+          resize (nr, 0);
           return;
         }
     }
@@ -1402,14 +1417,14 @@
       // enumerate all of them, we should have zero rows with the
       // same number of columns that we started with.
 
-      resize_no_fill (0, nc);
+      resize (0, nc);
       return;
     }
 
   if (idx_i.is_colon_equiv (nr, 1))
     {
       if (idx_j.is_colon_equiv (nc, 1))
-        resize_no_fill (0, 0);
+        resize (0, 0);
       else
         {
           idx_j.sort (true);
@@ -1419,7 +1434,7 @@
           if (num_to_delete != 0)
             {
               if (nr == 1 && num_to_delete == nc)
-                resize_no_fill (0, 0);
+                resize (0, 0);
               else
                 {
                   octave_idx_type new_nc = nc;
@@ -1484,7 +1499,7 @@
   else if (idx_j.is_colon_equiv (nc, 1))
     {
       if (idx_i.is_colon_equiv (nr, 1))
-        resize_no_fill (0, 0);
+        resize (0, 0);
       else
         {
           idx_i.sort (true);
@@ -1494,7 +1509,7 @@
           if (num_to_delete != 0)
             {
               if (nc == 1 && num_to_delete == nr)
-                resize_no_fill (0, 0);
+                resize (0, 0);
               else
                 {
                   octave_idx_type new_nr = nr;
@@ -1611,45 +1626,55 @@
 
 template <class T>
 Sparse<T>
-Sparse<T>::index (const idx_vector& idx_arg, bool resize_ok) const
+Sparse<T>::index (const idx_vector& idx, bool resize_ok) const
 {
   Sparse<T> retval;
 
   assert (ndims () == 2);
 
+  // FIXME: please don't fix the shadowed member warning yet because
+  // Sparse<T>::idx will eventually go away.
+
   octave_idx_type nr = dim1 ();
   octave_idx_type nc = dim2 ();
   octave_idx_type nz = nnz ();
 
-  // Use safe_numel so that we get an error if the matrix is too big to be indexed.
-  octave_idx_type orig_len = nr * nc;
-
-  dim_vector idx_orig_dims = idx_arg.orig_dimensions ();
-
-  octave_idx_type idx_orig_rows = idx_arg.orig_rows ();
-  octave_idx_type idx_orig_columns = idx_arg.orig_columns ();
-
-  if (idx_orig_dims.length () > 2)
+  octave_idx_type nel = numel (); // Can throw.
+
+  const dim_vector idx_dims = idx.orig_dimensions ();
+
+  if (idx_dims.length () > 2)
     (*current_liboctave_error_handler)
       ("cannot index sparse matrix with an N-D Array");
-  else if (idx_arg.is_colon ())
+  else if (idx.is_colon ())
     {
       // Fast magic colon processing.
-      retval = Sparse<T> (nr * nc, 1, nz);
+      retval = Sparse<T> (nel, 1, nz);
 
       for (octave_idx_type i = 0; i < nc; i++)
-        for (octave_idx_type j = cidx(i); j < cidx(i+1); j++)
-          {
-            octave_quit ();
-            retval.xdata(j) = data(j); 
-            retval.xridx(j) = ridx(j) + i * nr;
-          }
+        {
+          for (octave_idx_type j = cidx(i); j < cidx(i+1); j++)
+            {
+              retval.xdata(j) = data(j); 
+              retval.xridx(j) = ridx(j) + i * nr;
+            }
+        }
+
       retval.xcidx(0) = 0;
       retval.xcidx(1) = nz;
     }
-  else if (! resize_ok && idx_arg.extent (length ()) > length ())
+  else if (idx.extent (nel) > nel)
     {
-      gripe_index_out_of_range (1, 1, idx_arg.extent (orig_len), orig_len);
+      // resize_ok is completely handled here.
+      if (resize_ok)
+        {
+          octave_idx_type ext = idx.extent (nel);
+          Sparse<T> tmp = *this;
+          tmp.resize1 (ext);
+          retval = tmp.index (idx);
+        }
+      else
+        gripe_index_out_of_range (1, 1, idx.extent (nel), nel);
     }
   else if (nr == 1 && nc == 1)
     {
@@ -1658,260 +1683,106 @@
       // then want to make a dense matrix with sparse 
       // representation. Ok, we'll do it, but you deserve what 
       // you get!!
-      octave_idx_type n = idx_arg.length (length ());
-      if (n == 0)
-
-          retval = Sparse<T> (idx_orig_dims);
-      else if (nz < 1)
-        if (n >= idx_orig_dims.numel ())
-          retval = Sparse<T> (idx_orig_dims);
-        else
-          retval = Sparse<T> (dim_vector (n, 1));
-      else if (n >= idx_orig_dims.numel ())
-        {
-          T el = elem (0);
-          octave_idx_type new_nr = idx_orig_rows;
-          octave_idx_type new_nc = idx_orig_columns;
-          for (octave_idx_type i = 2; i < idx_orig_dims.length (); i++)
-            new_nc *= idx_orig_dims (i);
-                
-          retval = Sparse<T> (new_nr, new_nc, idx_arg.ones_count ());
-
-          octave_idx_type ic = 0;
-          for (octave_idx_type i = 0; i < n; i++)
-            {
-              if (i % new_nr == 0)
-                retval.xcidx(i / new_nr) = ic;
-
-              octave_idx_type ii = idx_arg.elem (i);
-              if (ii == 0)
-                {
-                  octave_quit ();
-                  retval.xdata(ic) = el;
-                  retval.xridx(ic++) = i % new_nr;
-                }
-            }
-          retval.xcidx (new_nc) = ic;
-        }
-      else
-        {
-          T el = elem (0);
-          retval = Sparse<T> (n, 1, nz);
-         
-          for (octave_idx_type i = 0; i < nz; i++) 
-            {
-              octave_quit ();
-              retval.xdata(i) = el;
-              retval.xridx(i) = i;
-            }
-          retval.xcidx(0) = 0;   
-          retval.xcidx(1) = n;   
-        }
+      retval = Sparse<T> (idx_dims(0), idx_dims(1), nz ? data (0) : T ());
     }
-  else if (nr == 1 || nc == 1)
+  else if (nc == 1)
     {
-      // If indexing a vector with a matrix, return value has same
-      // shape as the index.  Otherwise, it has same orientation as
-      // indexed object.
-      octave_idx_type len = length ();
-      octave_idx_type n = idx_arg.length (len);
-      octave_idx_type l, u;
-      if (n == 0)
-        if (nr == 1)
-          retval = Sparse<T> (dim_vector (1, 0));
-        else
-          retval = Sparse<T> (dim_vector (0, 1));
-      else if (nz < 1)
-        if (idx_orig_rows == 1 || idx_orig_columns == 1)
-          retval = Sparse<T> ((nr == 1 ? 1 : n), (nr == 1 ? n : 1));
-        else
-          retval = Sparse<T> (idx_orig_dims);
-      else if (idx_arg.is_range () && idx_arg.is_cont_range (n, l, u))
+      // Sparse column vector.
+      octave_idx_type lb, ub;
+      octave_sort<octave_idx_type> isort;
+
+      if (idx.is_scalar ())
         {
-          // Special case of indexing a sparse vector by a continuous range
-          if (nr == 1)
-            {
-              octave_idx_type new_nzmx = cidx(u) - cidx(l);
-              retval = Sparse<T> (1, n, new_nzmx);
-              octave_idx_type *iidx = retval.xcidx ();
-              copy_or_memcpy (n + 1, rep->c + l, iidx);
-              octave_idx_type ii = iidx[0];
-              if (ii != 0)
-                {
-                  for (octave_idx_type i = 0; i < n + 1; i++)
-                    iidx[i] -= ii;
-                }
-              copy_or_memcpy (new_nzmx, rep->d + ii, retval.rep->d);
-              copy_or_memcpy (new_nzmx, rep->r + ii, retval.rep->r);
-            }
+          // Scalar index - just a binary lookup.
+          octave_idx_type i = isort.lookup (ridx (), nz, idx(0));
+          if (i > 0 && ridx(i-1) == idx(0))
+            retval = Sparse (1, 1, data (i-1));
           else
-            {
-              octave_idx_type j1 = -1;
-
-              octave_idx_type new_nzmx = 0;
-              for (octave_idx_type j = 0; j < nz; j++)
-                {
-                  octave_idx_type j2 = ridx (j);
-                  if (j2 >= l && j2 < u)
-                    {
-                      new_nzmx++;
-                      if (j1 < 0)
-                        j1 = j;
-                    }
-                    if (j2 >= u)
-                      break;
-                  }
-
-              retval = Sparse<T> (n, 1, new_nzmx);
-              if (new_nzmx > 0)
-                {
-                  retval.xcidx(0) = 0;
-                  retval.xcidx(1) = new_nzmx;
-                  copy_or_memcpy (new_nzmx, rep->d + j1, retval.rep->d);
-                  octave_idx_type *iidx = retval.xridx ();
-                  copy_or_memcpy (new_nzmx, rep->r + j1, iidx);
-                  if (l != 0)
-                    {
-                      for (octave_idx_type i = 0; i < new_nzmx; i++)
-                        iidx[i] -= l;
-                    }
-                }
-            }
+            retval = Sparse (1, 1);
+        }
+      else if (idx.is_cont_range (nel, lb, ub))
+        {
+          // Special-case a contiguous range.
+          // Look-up indices first.
+          octave_idx_type li = isort.lookup (ridx (), nz, lb);
+          octave_idx_type ui = isort.lookup (ridx (), nz, ub);
+          // Adjust to lower bounds.
+          li -= (li > 0 && ridx(li-1) == lb);
+          ui -= (ui > 0 && ridx(ui-1) == ub);
+          // Copy data and adjust indices.
+          octave_idx_type nz_new = ui - li;
+          retval = Sparse<T> (ub - lb, 1, nz_new);
+          copy_or_memcpy (nz_new, data () + li, retval.data ());
+          mx_inline_sub (nz_new, retval.xridx (), ridx () + li, lb);
+          retval.xcidx(1) = nz_new;
         }
       else
         {
-          octave_idx_type new_nzmx = 0;
-          if (nr == 1)
-            for (octave_idx_type i = 0; i < n; i++)
-              {
-                octave_quit ();
-
-                octave_idx_type ii = idx_arg.elem (i);
-                if (ii < len)
-                  if (cidx(ii) != cidx(ii+1))
-                    new_nzmx++;
-              }
-          else
-             for (octave_idx_type i = 0; i < n; i++)
-              {
-                octave_idx_type ii = idx_arg.elem (i);
-                if (ii < len)
-                  for (octave_idx_type j = 0; j < nz; j++)
-                    {
-                      octave_quit ();
-
-                      if (ridx(j) == ii)
-                        new_nzmx++;
-                      if (ridx(j) >= ii)
-                        break;
-                    }
-              }
-
-          if (idx_orig_rows == 1 || idx_orig_columns == 1)
+          // If indexing a sparse column vector by a vector, the result is a
+          // sparse column vector, otherwise it inherits the shape of index.
+          // Vector transpose is cheap, so do it right here.
+          const Array<octave_idx_type> idxa = (idx_dims(0) == 1 
+                                               ? idx.as_array ().transpose ()
+                                               : idx.as_array ());
+
+          octave_idx_type new_nr = idxa.rows (), new_nc = idxa.cols ();
+
+          // Lookup.
+          // FIXME: Could specialize for sorted idx?
+          NoAlias< Array<octave_idx_type> > lidx (new_nr, new_nc);
+          isort.lookup (ridx (), nz, idxa.data (), idxa.numel (), lidx.fortran_vec ());
+
+          // Count matches.
+          retval = Sparse<T> (idxa.rows (), idxa.cols ());
+          for (octave_idx_type j = 0; j < new_nc; j++)
             {
-              if (nr == 1)
-                {
-                  retval = Sparse<T> (1, n, new_nzmx);
-                  octave_idx_type jj = 0;
-                  retval.xcidx(0) = 0;
-                  for (octave_idx_type i = 0; i < n; i++)
-                    {
-                      octave_quit ();
-
-                      octave_idx_type ii = idx_arg.elem (i);
-                      if (ii < len)
-                        if (cidx(ii) != cidx(ii+1))
-                          {
-                            retval.xdata(jj) = data(cidx(ii));
-                            retval.xridx(jj++) = 0;
-                          }
-                      retval.xcidx(i+1) = jj;
-                    }
-                }
-              else
+              octave_idx_type nzj = 0;
+              for (octave_idx_type i = 0; i < new_nr; i++)
                 {
-                  retval = Sparse<T> (n, 1, new_nzmx);
-                  retval.xcidx(0) = 0;
-                  retval.xcidx(1) = new_nzmx;
-                  octave_idx_type jj = 0;
-                  for (octave_idx_type i = 0; i < n; i++)
-                    {
-                      octave_idx_type ii = idx_arg.elem (i);
-                      if (ii < len)
-                        for (octave_idx_type j = 0; j < nz; j++)
-                          {
-                            octave_quit ();
-
-                            if (ridx(j) == ii)
-                              {
-                                retval.xdata(jj) = data(j);
-                                retval.xridx(jj++) = i;
-                              }
-                            if (ridx(j) >= ii)
-                              break;
-                          }
-                    }
-                }
-            }
-          else 
-            {
-              octave_idx_type new_nr;
-              octave_idx_type new_nc;
-              if (n >= idx_orig_dims.numel ())
-                {
-                  new_nr = idx_orig_rows;
-                  new_nc = idx_orig_columns;
-                }
-              else
-                {
-                  new_nr = n;
-                  new_nc = 1;
+                  octave_idx_type l = lidx(i, j);
+                  if (l > 0 && ridx(l-1) == idxa(i, j))
+                    nzj++;
+                  else
+                    lidx(i, j) = 0;
                 }
-
-              retval = Sparse<T> (new_nr, new_nc, new_nzmx);
-
-              if (nr == 1)
-                {
-                  octave_idx_type jj = 0;
-                  retval.xcidx(0) = 0;
-                  for (octave_idx_type i = 0; i < n; i++)
-                    {
-                      octave_quit ();
-
-                      octave_idx_type ii = idx_arg.elem (i);
-                      if (ii < len)
-                        if (cidx(ii) != cidx(ii+1))
-                          {
-                            retval.xdata(jj) = data(cidx(ii));
-                            retval.xridx(jj++) = 0;
-                          }
-                      retval.xcidx(i/new_nr+1) = jj;
-                    }
-                }
-              else
-                {
-                  octave_idx_type jj = 0;
-                  retval.xcidx(0) = 0;
-                  for (octave_idx_type i = 0; i < n; i++)
-                    {
-                      octave_idx_type ii = idx_arg.elem (i);
-                      if (ii < len)
-                        for (octave_idx_type j = 0; j < nz; j++)
-                          {
-                            octave_quit ();
-
-                            if (ridx(j) == ii)
-                              {
-                                retval.xdata(jj) = data(j);
-                                retval.xridx(jj++) = i;
-                              }
-                            if (ridx(j) >= ii)
-                              break;
-                          }
-                      retval.xcidx(i/new_nr+1) = jj;
-                    }
-                }
+              retval.xcidx(j+1) = retval.xcidx(j) + nzj;
             }
+
+          retval.change_capacity (retval.xcidx(new_nc));
+          
+          // Copy data and set row indices.
+          octave_idx_type k = 0;
+          for (octave_idx_type j = 0; j < new_nc; j++)
+            for (octave_idx_type i = 0; i < new_nr; i++)
+              {
+                octave_idx_type l = lidx(i, j) - 1;
+                if (l >= 0)
+                  {
+                    retval.data(k) = data(l);
+                    retval.xridx(k++) = i;
+                  }
+              }
+        }
+    }
+  else if (nr == 1)
+    {
+      octave_idx_type lb, ub;
+      if (idx.is_scalar ())
+        retval = Sparse<T> (1, 1, elem (0, idx(0)));
+      else if (idx.is_cont_range (nel, lb, ub))
+        {
+          // Special-case a contiguous range.
+          octave_idx_type lbi = cidx(lb), ubi = cidx(ub), new_nz = ubi - lbi;
+          retval = Sparse<T> (1, ub - lb, new_nz);
+          copy_or_memcpy (new_nz, data () + lbi, retval.data ());
+          fill_or_memset (new_nz, static_cast<octave_idx_type> (0), retval.ridx ());
+          mx_inline_sub (ub - lb, retval.cidx () + 1, cidx () + lb, lbi);
+        }
+      else
+        {
+          // Sparse row vectors occupy O(nr) storage anyway, so let's just
+          // convert the matrix to full, index, and sparsify the result.
+          retval = Sparse<T> (array_value ().index (idx));
         }
     }
   else
@@ -1919,71 +1790,18 @@
       (*current_liboctave_warning_with_id_handler) 
         ("Octave:fortran-indexing", "single index used for sparse matrix");
 
-      // This code is only for indexing matrices.  The vector
-      // cases are handled above.
-
-      octave_idx_type result_nr = idx_orig_rows;
-      octave_idx_type result_nc = idx_orig_columns;
-
-      if (nz < 1)
-        retval = Sparse<T> (result_nr, result_nc);
+      if (nr != 0 && idx.is_scalar ())
+        retval = Sparse<T> (1, 1, elem (idx(0) % nr, idx(0) / nr));
       else
         {
-          // Count number of non-zero elements
-          octave_idx_type new_nzmx = 0;
-          octave_idx_type kk = 0;
-          for (octave_idx_type j = 0; j < result_nc; j++)
-            {
-              for (octave_idx_type i = 0; i < result_nr; i++)
-                {
-                  octave_quit ();
-
-                  octave_idx_type ii = idx_arg.elem (kk++);
-                  if (ii < orig_len)
-                    {
-                      octave_idx_type fr = ii % nr;
-                      octave_idx_type fc = (ii - fr) / nr;
-                      for (octave_idx_type k = cidx(fc); k < cidx(fc+1); k++)
-                        {
-                          if (ridx(k) == fr)
-                            new_nzmx++;
-                          if (ridx(k) >= fr)
-                            break;
-                        }
-                    }
-                }
-            }
-
-          retval = Sparse<T> (result_nr, result_nc, new_nzmx);
-
-          kk = 0;
-          octave_idx_type jj = 0;
-          retval.xcidx(0) = 0;
-          for (octave_idx_type j = 0; j < result_nc; j++)
-            {
-              for (octave_idx_type i = 0; i < result_nr; i++)
-                {
-                  octave_quit ();
-
-                  octave_idx_type ii = idx_arg.elem (kk++);
-                  if (ii < orig_len)
-                    {
-                      octave_idx_type fr = ii % nr;
-                      octave_idx_type fc = (ii - fr) / nr;
-                      for (octave_idx_type k = cidx(fc); k < cidx(fc+1); k++)
-                        {
-                          if (ridx(k) == fr)
-                            {
-                              retval.xdata(jj) = data(k);
-                              retval.xridx(jj++) = i;
-                            }
-                          if (ridx(k) >= fr)
-                            break;
-                        }
-                    }
-                }
-              retval.xcidx(j+1) = jj;
-            }
+          // Indexing a non-vector sparse matrix by linear indexing. 
+          // I suppose this is rare (and it may easily overflow), so let's take the easy way,
+          // and reshape first to column vector, which is already handled above.
+          retval = index (idx_vector::colon).index (idx);
+          // In this case we're supposed to always inherit the shape, but column(row) doesn't do
+          // it, so we'll do it instead.
+          if (idx_dims (0) == 1 && idx_dims (1) != 1)
+            retval = retval.transpose ();
         }
     }
 
@@ -2019,7 +1837,7 @@
     {
       if (n == 0 || m == 0)
         {
-          retval.resize_no_fill (n, m);
+          retval.resize (n, m);
         }
       else 
         {
@@ -2575,6 +2393,30 @@
   return d;
 }
 
+template <class T>
+Array<T>
+Sparse<T>::array_value () const
+{
+  NoAlias< Array<T> > retval (dims (), T());
+  if (rows () == 1)
+    {
+      octave_idx_type i = 0;
+      for (octave_idx_type j = 0, nc = cols (); j < nc; j++)
+        {
+          if (cidx(j+1) > i)
+            retval(j) = data (i++);
+        }
+    }
+  else
+    {
+      for (octave_idx_type j = 0, nc = cols (); j < nc; j++)
+        for (octave_idx_type i = cidx(j), iu = cidx(j+1); i < iu; i++)
+          retval (ridx(i), j) = data (i);
+    }
+
+  return retval;
+}
+
 // FIXME
 // Unfortunately numel can overflow for very large but very sparse matrices.
 // For now just flag an error when this happens.
--- a/liboctave/Sparse.h	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/Sparse.h	Fri Mar 19 13:00:06 2010 +0100
@@ -237,13 +237,11 @@
   octave_idx_type capacity (void) const { return nzmax (); }
   octave_idx_type nnz (void) const { return rep->nnz (); }
 
-  // Paranoid number of elements test for case of dims = (-1,-1)
+  // Querying the number of elements (incl. zeros) may overflow the index type,
+  // so don't do it unless you really need it.
   octave_idx_type numel (void) const 
     { 
-      if (dim1() < 0 || dim2() < 0)
-        return 0;
-      else
-        return dimensions.numel (); 
+      return dimensions.safe_numel (); 
     }
 
   octave_idx_type nelem (void) const { return capacity (); }
@@ -418,26 +416,16 @@
 
   Sparse<T> reshape (const dim_vector& new_dims) const;
 
-  // !!! WARNING !!! -- the following resize_no_fill functions are 
-  // public because template friends don't work properly with versions
-  // of gcc earlier than 3.3.  You should use these functions only in 
-  // classes that are derived from Sparse<T>.
-
-  // protected:
-
-  void resize_no_fill (octave_idx_type r, octave_idx_type c);
-
-  void resize_no_fill (const dim_vector& dv);
-
-public:
   Sparse<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
 
   Sparse<T> ipermute (const Array<octave_idx_type>& vec) const
     { return permute (vec, true); }
 
-  void resize (octave_idx_type r, octave_idx_type c) { resize_no_fill (r, c); }
+  void resize1 (octave_idx_type n);
 
-  void resize (const dim_vector& dv) { resize_no_fill (dv); }
+  void resize (octave_idx_type r, octave_idx_type c);
+
+  void resize (const dim_vector& dv);
 
   void change_capacity (octave_idx_type nz) { rep->change_length (nz); }
 
@@ -515,6 +503,8 @@
 
   Sparse<T> diag (octave_idx_type k = 0) const;
 
+  Array<T> array_value (void) const;
+
   template <class U, class F>
   Sparse<U>
   map (F fcn) const
--- a/liboctave/idx-vector.cc	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/idx-vector.cc	Fri Mar 19 13:00:06 2010 +0100
@@ -722,9 +722,25 @@
     return *aowner;
   else
     {
+      Array<bool> retval (ext, 1);
+      for (octave_idx_type i = 0; i < ext; i++)
+        retval.xelem (i) = data[i];
+      return retval;
+    }
+}
+
+Array<octave_idx_type>
+idx_vector::idx_mask_rep::as_array (void)
+{
+  if (aowner)
+    return aowner->find ().reshape (orig_dims);
+  else
+    {
       Array<bool> retval (orig_dims);
-      for (octave_idx_type i = 0; i < len; i++)
-        retval.xelem (i) = data[i];
+      for (octave_idx_type i = 0, j = 0; i < ext; i++)
+        if (data[i])
+          retval.xelem (j++) = i;
+
       return retval;
     }
 }
--- a/liboctave/idx-vector.h	Fri Mar 19 07:12:21 2010 +0100
+++ b/liboctave/idx-vector.h	Fri Mar 19 13:00:06 2010 +0100
@@ -404,6 +404,8 @@
 
     Array<bool> unconvert (void) const;
 
+    Array<octave_idx_type> as_array (void);
+    
   private:
 
     DECLARE_OCTAVE_ALLOCATOR
--- a/test/ChangeLog	Fri Mar 19 07:12:21 2010 +0100
+++ b/test/ChangeLog	Fri Mar 19 13:00:06 2010 +0100
@@ -1,3 +1,7 @@
+2010-03-19  Jaroslav Hajek  <highegg@gmail.com>
+
+	* test_slice.m: Use ID check rather than message for invalid resizing.
+
 2010-03-05  Jaroslav Hajek  <highegg@gmail.com>
 
 	* test_logical-wfi-f.m: Update.
--- a/test/test_slice.m	Fri Mar 19 07:12:21 2010 +0100
+++ b/test/test_slice.m	Fri Mar 19 13:00:06 2010 +0100
@@ -38,9 +38,9 @@
 
 ## size = [2 0]
 %!assert(set_slice([2 0], 11, []), zeros([2 0]));
-%!error <resize: Invalid.*> set_slice([2 0], 11, 1)
-%!error <resize: Invalid.*> set_slice([2 0], 11, 2)
-%!error <resize: Invalid.*> set_slice([2 0], 11, 3)
+%!error id=Octave:invalid-resize set_slice([2 0], 11, 1)
+%!error id=Octave:invalid-resize set_slice([2 0], 11, 2)
+%!error id=Octave:invalid-resize set_slice([2 0], 11, 3)
 %!assert(set_slice([2 0], 21, []), zeros([2 0]));
 %!assert(set_slice([2 0], 21, 1), zeros([2 0]));
 %!assert(set_slice([2 0], 21, 2), zeros([2 0]));
@@ -152,8 +152,8 @@
 %!assert(set_slice([2 2], 11, 2), [1 1;2 1]);
 %!assert(set_slice([2 2], 11, 3), [1 2;1 1]);
 %!assert(set_slice([2 2], 11, 4), [1 1;1 2]);
-%!error <resize: Invalid.*> set_slice([2 2], 11, 5)
-%!error <resize: Invalid.*> set_slice([2 2], 11, 6)
+%!error id=Octave:invalid-resize set_slice([2 2], 11, 5)
+%!error id=Octave:invalid-resize set_slice([2 2], 11, 6)
 %!assert(set_slice([2 2], 21, []), ones([2 2]));
 %!assert(set_slice([2 2], 21, 1), [2 2;1 1]);
 %!assert(set_slice([2 2], 21, 2), [1 1;2 2]);