changeset 11848:79d5312ab8e6 release-3-0-x

make null assignment more Matlab-compatible
author Jaroslav Hajek <highegg@gmail.com>
date Sun, 21 Sep 2008 08:21:52 +0200
parents c7428cdd8e01
children 74802398931b
files liboctave/Array.cc liboctave/Array.h liboctave/ChangeLog test/ChangeLog test/test_null_assign.m
diffstat 5 files changed, 171 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array.cc	Sun Sep 21 08:20:39 2008 +0200
+++ b/liboctave/Array.cc	Sun Sep 21 08:21:52 2008 +0200
@@ -1389,12 +1389,19 @@
   octave_idx_type nr = dim1 ();
   octave_idx_type nc = dim2 ();
 
+  if (idx_arg.is_colon ())
+    {
+      // A(:) = [] always gives 0-by-0 matrix, even if A was empty.
+      resize_no_fill (0, 0);
+      return;
+    }
+
   octave_idx_type n;
   if (nr == 1)
     n = nc;
   else if (nc == 1)
     n = nr;
-  else
+  else if (! idx_arg.orig_empty ())
     {
       // Reshape to row vector for Matlab compatibility.
 
@@ -1403,19 +1410,17 @@
       nc = n;
     }
 
-  if (nr > 0 && nc > 0 && idx_arg.is_colon_equiv (n, 1))
+  idx_arg.sort (true);
+
+  if (idx_arg.is_colon_equiv (n, 1))
     {
-      // Either A(:) = [] or A(idx) = [] with idx enumerating all
-      // elements, so we delete all elements and return [](0x0).  To
-      // preserve the orientation of the vector, you have to use
-      // A(idx,:) = [] (delete rows) or A(:,idx) (delete columns).
-
-      resize_no_fill (0, 0);
+      if (nr == 1)
+        resize_no_fill (1, 0);
+      else if (nc == 1)
+        resize_no_fill (0, 1);
       return;
     }
 
-  idx_arg.sort (true);
-
   octave_idx_type num_to_delete = idx_arg.length (n);
 
   if (num_to_delete != 0)
@@ -1485,167 +1490,133 @@
   octave_idx_type nr = dim1 ();
   octave_idx_type nc = dim2 ();
 
-  if (nr == 0 && nc == 0)
-    return;
-
-  if (idx_i.is_colon ())
+  if (idx_i.is_colon () && idx_j.is_colon ())
     {
-      if (idx_j.is_colon ())
-	{
-	  // A(:,:) -- We are deleting columns and rows, so the result
-	  // is [](0x0).
-
-	  resize_no_fill (0, 0);
-	  return;
-	}
+      // A special case: A(:,:). Matlab gives 0-by-nc here, but perhaps we
+      // should not?
+      resize_no_fill (0, nc);
+    }
+  else if (idx_i.is_colon ())
+    {
+      idx_j.sort (true); // sort in advance to speed-up the following check
 
       if (idx_j.is_colon_equiv (nc, 1))
-	{
-	  // A(:,j) -- We are deleting columns by enumerating them,
-	  // 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);
-	  return;
-	}
-    }
-
-  if (idx_j.is_colon () && idx_i.is_colon_equiv (nr, 1))
-    {
-      // A(i,:) -- We are deleting rows by enumerating them.  If we
-      // enumerate all of them, we should have zero rows with the
-      // same number of columns that we started with.
-
-      resize_no_fill (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_no_fill (nr, 0);
       else
 	{
-	  idx_j.sort (true);
-
 	  octave_idx_type num_to_delete = idx_j.length (nc);
 
 	  if (num_to_delete != 0)
-	    {
-	      if (nr == 1 && num_to_delete == nc)
-		resize_no_fill (0, 0);
-	      else
-		{
-		  octave_idx_type new_nc = nc;
-
-		  octave_idx_type iidx = 0;
-
-		  for (octave_idx_type j = 0; j < nc; j++)
-		    if (j == idx_j.elem (iidx))
-		      {
-			iidx++;
-			new_nc--;
-
-			if (iidx == num_to_delete)
-			  break;
-		      }
-
-		  if (new_nc > 0)
-		    {
-		      T *new_data = new T [nr * new_nc];
-
-		      octave_idx_type jj = 0;
-		      iidx = 0;
-		      for (octave_idx_type j = 0; j < nc; j++)
-			{
-			  if (iidx < num_to_delete && j == idx_j.elem (iidx))
-			    iidx++;
-			  else
-			    {
-			      for (octave_idx_type i = 0; i < nr; i++)
-				new_data[nr*jj+i] = xelem (i, j);
-			      jj++;
-			    }
-			}
-
-		      if (--(Array<T>::rep)->count <= 0)
-			delete Array<T>::rep;
-
-		      Array<T>::rep = new typename Array<T>::ArrayRep (new_data, nr * new_nc);
-
-		      dimensions.resize (2);
-		      dimensions(1) = new_nc;
-		    }
-		  else
-		    (*current_liboctave_error_handler)
-		      ("A(idx) = []: index out of range");
-		}
-	    }
+            {
+              octave_idx_type new_nc = nc;
+
+              octave_idx_type iidx = 0;
+
+              for (octave_idx_type j = 0; j < nc; j++)
+                if (j == idx_j.elem (iidx))
+                  {
+                    iidx++;
+                    new_nc--;
+
+                    if (iidx == num_to_delete)
+                      break;
+                  }
+
+              if (new_nc > 0)
+                {
+                  T *new_data = new T [nr * new_nc];
+
+                  octave_idx_type jj = 0;
+                  iidx = 0;
+                  for (octave_idx_type j = 0; j < nc; j++)
+                    {
+                      if (iidx < num_to_delete && j == idx_j.elem (iidx))
+                        iidx++;
+                      else
+                        {
+                          for (octave_idx_type i = 0; i < nr; i++)
+                            new_data[nr*jj+i] = xelem (i, j);
+                          jj++;
+                        }
+                    }
+
+                  if (--(Array<T>::rep)->count <= 0)
+                    delete Array<T>::rep;
+
+                  Array<T>::rep = new typename Array<T>::ArrayRep (new_data, nr * new_nc);
+
+                  dimensions.resize (2);
+                  dimensions(1) = new_nc;
+                }
+              else
+                (*current_liboctave_error_handler)
+                  ("A(idx) = []: index out of range");
+            }
 	}
     }
-  else if (idx_j.is_colon_equiv (nc, 1))
+  else if (idx_j.is_colon ())
     {
+      idx_i.sort (true); // sort in advance to speed-up the following check
+
       if (idx_i.is_colon_equiv (nr, 1))
-	resize_no_fill (0, 0);
+	resize_no_fill (0, nc);
       else
 	{
-	  idx_i.sort (true);
-
 	  octave_idx_type num_to_delete = idx_i.length (nr);
 
 	  if (num_to_delete != 0)
-	    {
-	      if (nc == 1 && num_to_delete == nr)
-		resize_no_fill (0, 0);
-	      else
-		{
-		  octave_idx_type new_nr = nr;
-
-		  octave_idx_type iidx = 0;
-
-		  for (octave_idx_type i = 0; i < nr; i++)
-		    if (i == idx_i.elem (iidx))
-		      {
-			iidx++;
-			new_nr--;
-
-			if (iidx == num_to_delete)
-			  break;
-		      }
-
-		  if (new_nr > 0)
-		    {
-		      T *new_data = new T [new_nr * nc];
-
-		      octave_idx_type ii = 0;
-		      iidx = 0;
-		      for (octave_idx_type i = 0; i < nr; i++)
-			{
-			  if (iidx < num_to_delete && i == idx_i.elem (iidx))
-			    iidx++;
-			  else
-			    {
-			      for (octave_idx_type j = 0; j < nc; j++)
-				new_data[new_nr*j+ii] = xelem (i, j);
-			      ii++;
-			    }
-			}
-
-		      if (--(Array<T>::rep)->count <= 0)
-			delete Array<T>::rep;
-
-		      Array<T>::rep = new typename Array<T>::ArrayRep (new_data, new_nr * nc);
-
-		      dimensions.resize (2);
-		      dimensions(0) = new_nr;
-		    }
-		  else
-		    (*current_liboctave_error_handler)
-		      ("A(idx) = []: index out of range");
-		}
-	    }
+            {
+              octave_idx_type new_nr = nr;
+
+              octave_idx_type iidx = 0;
+
+              for (octave_idx_type i = 0; i < nr; i++)
+                if (i == idx_i.elem (iidx))
+                  {
+                    iidx++;
+                    new_nr--;
+
+                    if (iidx == num_to_delete)
+                      break;
+                  }
+
+              if (new_nr > 0)
+                {
+                  T *new_data = new T [new_nr * nc];
+
+                  octave_idx_type ii = 0;
+                  iidx = 0;
+                  for (octave_idx_type i = 0; i < nr; i++)
+                    {
+                      if (iidx < num_to_delete && i == idx_i.elem (iidx))
+                        iidx++;
+                      else
+                        {
+                          for (octave_idx_type j = 0; j < nc; j++)
+                            new_data[new_nr*j+ii] = xelem (i, j);
+                          ii++;
+                        }
+                    }
+
+                  if (--(Array<T>::rep)->count <= 0)
+                    delete Array<T>::rep;
+
+                  Array<T>::rep = new typename Array<T>::ArrayRep (new_data, new_nr * nc);
+
+                  dimensions.resize (2);
+                  dimensions(0) = new_nr;
+                }
+              else
+                (*current_liboctave_error_handler)
+                  ("A(idx) = []: index out of range");
+            }
 	}
     }
+  else
+    {
+      (*current_liboctave_error_handler)
+        ("a null assignment can have only one non-colon index");
+    }
 }
 
 template <class T>
--- a/liboctave/Array.h	Sun Sep 21 08:20:39 2008 +0200
+++ b/liboctave/Array.h	Sun Sep 21 08:21:52 2008 +0200
@@ -499,6 +499,8 @@
 
   void maybe_delete_elements (Array<idx_vector>& ra_idx, const T& rfv);
 
+  void maybe_delete_elements (octave_idx_type dim, idx_vector& i);
+
   Array<T> value (void) const;
 
   Array<T> index (idx_vector& i, int resize_ok = 0,
--- a/liboctave/ChangeLog	Sun Sep 21 08:20:39 2008 +0200
+++ b/liboctave/ChangeLog	Sun Sep 21 08:21:52 2008 +0200
@@ -1,3 +1,10 @@
+2008-09-18  Jaroslav Hajek  <highegg@gmail.com>
+
+	* Array.cc (maybe_delete_elements_2 (idx_vector&)): Fix tests to get
+	better Matlab compatibility.
+	(maybe_delete_elements (idx_vector&, idx_vector&)): Fix tests to get
+	better Matlab compatibility, simplify, gripe on invalid 2-D deletion.
+
 2008-01-18  Marco Caliari  <marco.caliari@univr.it>
 
 	* dMatrix.cc (Matrix::expm): Correctly perform reverse permutation.
--- a/test/ChangeLog	Sun Sep 21 08:20:39 2008 +0200
+++ b/test/ChangeLog	Sun Sep 21 08:21:52 2008 +0200
@@ -1,3 +1,7 @@
+2008-09-18  Jaroslav Hajek  <highegg@gmail.com>
+
+	* test_null_assign.m: New tests.
+
 2008-08-19  Jaroslav Hajek <highegg@gmail.com>
 
 	Version 3.0.2 released.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test_null_assign.m	Sun Sep 21 08:21:52 2008 +0200
@@ -0,0 +1,35 @@
+## Copyright (C) 2008 Jaroslav Hajek
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+%!test
+%! a = 1:3; a(:) = []; assert (size (a), [0, 0])
+%!test
+%! a = 1:3; a(1:3) = []; assert (size (a), [1, 0])
+%!test
+%! a = (1:3).'; a(1:3) = []; assert (size (a), [0, 1])
+%!test
+%! a = ones (3); a(:,:) = []; assert (size (a), [0, 3])
+%!test
+%! a = ones (3); a(1:3,:) = []; assert (size (a), [0, 3])
+%!test
+%! a = ones (3); a(:,1:3) = []; assert (size (a), [3, 0])
+%!test
+%! a = ones (3); fail ("a(1:2,1:2) = []", ".*");
+%!test
+%! a = ones (3); fail ("a(1:3,1:3) = []", ".*");
+