diff liboctave/ArrayN-idx.h @ 4493:49d88738a4a0

[project @ 2003-09-03 16:21:18 by jwe]
author jwe
date Wed, 03 Sep 2003 16:21:18 +0000
parents af308ca1a354
children 124c137af3db
line wrap: on
line diff
--- a/liboctave/ArrayN-idx.h
+++ b/liboctave/ArrayN-idx.h
@@ -27,7 +27,7 @@
 
 template <class T>
 void
-ArrayN<T>::maybe_delete_elements (Array<idx_vector>&)
+ArrayN<T>::maybe_delete_elements (Array<idx_vector>& idx, const T& rfv)
 {
   assert (0);
 }
@@ -258,14 +258,451 @@
   return retval;
 }
 
+#define MAYBE_RESIZE_ND_DIMS \
+  do \
+    { \
+      if (n_idx >= lhs_dims.length () && ! rhs_is_empty) \
+	{ \
+	  Array<int> max_idx (n_idx); \
+	  Array<int> new_idx (n_idx); \
+ \
+	  for (int i = 0; i < n_idx; i++) \
+	    { \
+	      if (lhs_dims.length () == 0 || i >= lhs_dims.length ()) \
+		new_idx(i) = idx(i).max () + 1; \
+	      else \
+		{ \
+		  if (i < rhs_dims.length ()) \
+		    max_idx(i) = idx(i).is_colon () ? rhs_dims(i) : idx(i).max () + 1; \
+		  else \
+		    max_idx(i) = idx(i).max () + 1; \
+ \
+		  new_idx(i) = max_idx(i) > lhs_dims(i) ? max_idx(i) : lhs_dims(i); \
+		} \
+            } \
+ \
+	  lhs.resize (new_idx, rfv); \
+	  lhs_dims = lhs.dims ();  \
+        } \
+    } \
+  while (0)
+
 template <class LT, class RT>
 int
-assign (ArrayN<LT>&, const ArrayN<RT>&, const LT&)
+assign (ArrayN<LT>& lhs, const ArrayN<RT>& rhs, const LT& rfv)
 {
-  assert (0);
-  return 0;
+  int retval = 1;
+
+  int n_idx = lhs.index_count ();
+
+  Array<int> lhs_dims = lhs.dims ();
+  Array<int> rhs_dims = rhs.dims ();
+
+  idx_vector *tmp = lhs.get_idx ();
+
+  Array<idx_vector> idx = conv_to_array (tmp, n_idx);
+
+  // This needs to be defined before MAYBE_RESIZE_ND_DIMS.
+
+  bool rhs_is_empty = rhs_dims.length () == 0 ? true : any_zero_len (rhs_dims);
+
+  // Maybe expand to more dimensions.
+
+  MAYBE_RESIZE_ND_DIMS;
+
+  Array<int> idx_is_colon (n_idx, 0);
+  Array<int> idx_is_colon_equiv (n_idx, 0);
+
+  for (int i = 0; i < n_idx; i++)
+    {
+      idx_is_colon_equiv(i) = idx(i).is_colon_equiv (lhs_dims(i), 1);
+
+      idx_is_colon(i) = idx(i).is_colon ();
+    }
+
+  int resize_ok = 1;
+
+  Array<int> frozen_len;
+
+  if (n_idx == lhs_dims.length ())
+    frozen_len = freeze (idx, lhs_dims, resize_ok);
+
+  bool rhs_is_scalar = is_scalar (rhs_dims);
+
+  bool idx_is_empty = any_zero_len (frozen_len);
+
+  if (rhs_is_empty)
+    {
+      lhs.maybe_delete_elements (idx, rfv);
+    }
+  else if (rhs_is_scalar)
+    {
+      if (n_idx == 0)
+	(*current_liboctave_error_handler)
+	  ("number of indices is zero.");
+		
+      else if (n_idx < lhs_dims.length ())
+	{
+	  // Number of indices is less than dimensions.
+
+	  if (any_ones (idx_is_colon)|| any_ones (idx_is_colon_equiv))
+	    {
+	      (*current_liboctave_error_handler)
+		("number of indices is less than number of dimensions, one or more indices are colons.");
+	    }
+	  else
+	    {
+	      // Fewer indices than dimensions, no colons.
+
+	      bool resize = false;
+
+	      // Subtract one since the last idx do not tell us
+	      // anything about dimensionality.
+
+	      for (int i = 0; i < idx.length () - 1; i++)
+		{
+		  // Subtract one since idx counts from 0 while dims
+		  // count from 1.
+
+		  if (idx(i).elem (0) + 1 > lhs_dims(i))
+		    resize = true;
+		}
+
+	      if (resize)
+		{
+		  Array<int> new_dims (lhs_dims.length ());
+
+		  for (int i = 0; i < lhs_dims.length (); i++)
+		    {
+		      if (i < idx.length () - 1
+			  && idx(i).elem (0) + 1 > lhs_dims(i))
+			new_dims(i) = idx(i).elem (0)+1;
+		      else
+			new_dims(i) = lhs_dims(i);
+		    }
+
+		  lhs.resize (new_dims, rfv);
+
+		  lhs_dims = lhs.dims ();
+		}
+
+	      Array<int> one_arg_temp (1, 0);
+		
+	      RT scalar = rhs.elem (one_arg_temp);
+
+	      Array<int> int_arr = conv_to_int_array (idx);
+
+	      int numelem = get_scalar_idx (int_arr, lhs_dims);
+	
+	      if (numelem > lhs.length () || numelem < 0)
+		(*current_liboctave_error_handler)
+		  ("attempt to grow array along ambiguous dimension.");
+	      else
+		lhs.Array<LT>::checkelem (numelem) = scalar;
+	    }
+	}
+      else
+	{
+	  // Scalar to matrix assignment with as many indices as lhs
+	  // dimensions.
+
+	  int n = ArrayN<LT>::get_size (frozen_len);
+	
+	  Array<int> result_idx (lhs_dims.length (), 0);
+
+	  Array<int> elt_idx;
+	
+	  Array<int> one_arg_temp(1,0);		
+	  RT scalar = rhs.elem (one_arg_temp);
+	
+	  for (int i = 0; i < n; i++)
+	    {
+	      elt_idx = get_elt_idx (idx, result_idx);
+	
+	      Array<int> lhs_inc(lhs_dims.length());
+	
+	      for (int i = 0; i < lhs_dims.length (); i++)
+		lhs_inc(i) = lhs_dims(i) + 1;
+	
+	      if (index_in_bounds(elt_idx, lhs_inc))
+		lhs.checkelem (elt_idx) = scalar;
+	      else
+		lhs.checkelem (elt_idx) = rfv;
+
+	      increment_index (result_idx, frozen_len);
+	    }
+	}
+    }
+  else if (rhs_dims.length () >= 2)
+    {
+      // RHS is matrix or higher dimension.
+
+      // Subtracting number of dimensions of length 1 will catch
+      // cases where: A(2,1,2)=3  A(:,1,:)=[2,3;4,5]
+
+      if (rhs_dims.length () != num_ones(idx_is_colon_equiv) - num_ones(lhs_dims))
+	{
+	  (*current_liboctave_error_handler)
+	    ("dimensions do not match in matrix assignment.");
+	}
+      else
+	{
+	  bool dim_ok(true);
+
+	  int jj = 0;
+
+	  // Check that RHS dimensions are the same length as the
+	  // corresponding LHS dimensions.
+
+	  for (int j = 0; j < idx_is_colon.length (); j++)
+	    {
+	      if (idx_is_colon(j) || idx_is_colon_equiv(j))
+		{
+		  if (rhs_dims(jj) < lhs_dims(j))
+		    {
+		      dim_ok = false;
+
+		      break;
+		    }
+
+		  jj++;
+		}
+	    }
+
+	  if (! dim_ok)
+	    (*current_liboctave_error_handler)
+	      ("subscripted assignment dimension mismatch.");
+	  else
+	    {
+	      Array<int> new_dims (n_idx);
+	
+	      bool resize = false;
+	
+	      int ii = 0;
+
+	      // Update idx vectors.
+
+	      for (int i = 0; i < n_idx; i++)
+		{
+		  if (idx(i).is_colon ())
+		    {
+		      // Add appropriate idx_vector to idx(i) since
+		      // index with : contains no indexes.
+
+		      frozen_len(i) = lhs_dims(i) > rhs_dims(ii) ? lhs_dims(i) : rhs_dims(ii);
+		
+		      new_dims(i) = lhs_dims(i) > rhs_dims(ii) ? lhs_dims(i) : rhs_dims(ii);
+		
+		      ii++;
+		
+		      Range idxrange (1, frozen_len(i), 1);
+		
+		      idx_vector idxv (idxrange);
+		
+		      idx(i) = idxv;
+		    }
+		  else
+		    {
+		      new_dims(i) = lhs_dims(i) > idx(i).max () + 1 ? lhs_dims(i) : idx(i).max () + 1;
+		
+		      if (frozen_len(i) > 1)
+			ii++;
+		    }
+		  if (new_dims(i) != lhs_dims(i))
+		    resize = true;
+		}
+	
+	      // Resize LHS if dimensions have changed.
+
+	      if (resize)
+		{
+		  lhs.resize (new_dims, rfv);
+		
+		  lhs_dims = lhs.dims ();
+		}
+	
+	      // Number of elements which need to be set.
+
+	      int n = ArrayN<LT>::get_size (frozen_len);
+	
+	      Array<int> result_idx (lhs_dims.length (), 0);
+	      Array<int> elt_idx;
+	
+	      Array<int> result_rhs_idx (rhs_dims.length (), 0);
+	      Array<int> frozen_rhs (rhs_dims.length(), 0);
+	
+	      for (int i = 0; i < rhs_dims.length (); i++)
+		frozen_rhs(i) = rhs_dims(i);
+	
+	      Array<int> lhs_inc (lhs_dims.length ());
+	
+	      for (int i = 0; i < lhs_dims.length (); i++)
+		lhs_inc(i) = lhs_dims(i) + 1;
+	
+	      for (int i = 0; i < n; i++)
+		{
+		  elt_idx = get_elt_idx (idx, result_idx);
+		
+		  if (index_in_bounds (elt_idx, lhs_inc))
+		    {
+		      int s = compute_index (result_rhs_idx,rhs_dims);
+		
+		      lhs.checkelem (elt_idx) = rhs.Array<RT>::elem (s);
+		
+		      increment_index (result_rhs_idx, frozen_rhs);
+		    }
+		  else
+		    lhs.checkelem (elt_idx) = rfv;
+		
+		  increment_index (result_idx, frozen_len);
+		}
+	    }
+	}
+    }
+  else if (idx_is_empty)
+    {
+      // Assignment to matrix with at least one empty index.
+
+      if (! rhs_is_empty || ! rhs_is_scalar)
+	{
+	  (*current_liboctave_error_handler)
+	    ("A([], []) = X: X must be an empty matrix or a scalar");
+	
+	  retval = 0;
+	}
+    }
+  else if (lhs_dims.length () != rhs_dims.length ())
+    {
+      (*current_liboctave_error_handler)
+	("A(I) = X: X must be a scalar or a matrix with the same size as I");
+      retval = 0;
+    }
+
+  return retval;
 }
 
+static inline int
+get_scalar_idx (Array<int>& idx, Array<int>& dims)
+{
+  int retval (-1);
+
+  int n = idx.length ();
+
+  if (n > 0)
+    {
+      retval = idx(--n);
+
+      while (--n >= 0)
+	{      		
+	  retval *= dims (n);
+	
+	  retval += idx(n);
+	}
+    }
+  return retval;
+}
+
+static inline int
+num_ones (const Array<int> ra_idx)
+{
+  int retval (0);
+  for (int i = 0; i < ra_idx.length (); i++)
+    {
+      if (ra_idx (i) == 1)
+	retval++;
+    }
+  return retval;
+}
+
+static inline bool
+is_scalar (const Array<int>& dim)
+{
+  bool retval = true;
+
+  int n = dim.length ();
+
+  if (n == 0)
+    {
+      retval = false;
+    }
+  else
+    {
+      for (int i = 0; i < n; i ++)
+	{
+	  if (dim (i) != 1)
+	    {
+	      retval = false;
+	
+	      break;
+	    }
+	}
+    }
+  return retval;
+}
+
+static inline bool
+any_ones (const Array<int> arr)
+{
+  bool retval = false;
+
+  for (int i = 0; i < arr.length (); i++)
+    {
+      if (arr (i) == 1)
+	{
+	  retval = true;
+	
+	  break;
+	}
+    }
+  return retval;
+}
+
+static inline int
+compute_index (const Array<int>& ra_idx, const Array<int>& dims)
+{
+  int retval = -1;
+
+  int n = dims.length ();
+
+  if (n > 0 && n == ra_idx.length ())
+    {
+      retval = ra_idx(--n);
+
+      while (--n >= 0)
+	{
+	  retval *= dims(n);
+	
+	  retval += ra_idx(n);
+	}
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("ArrayN<T>::compute_index: invalid ra_idxing operation");
+
+  return retval;
+}
+
+static inline Array<int>
+conv_to_int_array (const Array<idx_vector>& a)
+{
+  Array<int> retval (a.length ());
+
+  for (int i = 0; i < a.length (); i++)
+    retval (i) = a(i).elem (0);
+
+  return retval;
+}
+
+static inline Array<idx_vector>
+conv_to_array (const idx_vector *tmp, const int len)
+{
+  Array<idx_vector> retval (len);
+
+  for (int i = 0; i < len; i++)
+      retval (i) = tmp[i];
+
+  return retval;
+}
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***