diff liboctave/Sparse.cc @ 7620:36594d5bbe13

Move diag function into the octave_value class
author David Bateman <dbateman@free.fr>
date Fri, 21 Mar 2008 00:08:24 +0100
parents 755bf7ecc29b
children ff918ee1a983
line wrap: on
line diff
--- a/liboctave/Sparse.cc	Fri Mar 21 13:20:11 2008 -0400
+++ b/liboctave/Sparse.cc	Fri Mar 21 00:08:24 2008 +0100
@@ -2253,6 +2253,156 @@
   return m;
 }
 
+template <class T>
+Sparse<T>
+Sparse<T>::diag (octave_idx_type k) const
+{
+  octave_idx_type nnr = rows ();
+  octave_idx_type nnc = cols ();
+  Sparse<T> d;
+
+  if (nnr == 0 || nnc == 0)
+    ; // do nothing
+  else if (nnr != 1 && nnc != 1)
+    {
+      if (k > 0)
+	nnc -= k;
+      else if (k < 0)
+	nnr += k;
+
+      if (nnr > 0 && nnc > 0)
+	{
+	  octave_idx_type ndiag = (nnr < nnc) ? nnr : nnc;
+
+	  // Count the number of non-zero elements
+	  octave_idx_type nel = 0;
+	  if (k > 0)
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		if (elem (i, i+k) != 0.)
+		  nel++;
+	    }
+	  else if ( k < 0)
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		if (elem (i-k, i) != 0.)
+		  nel++;
+	    }
+	  else
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		if (elem (i, i) != 0.)
+		  nel++;
+	    }
+      
+	  d = Sparse<T> (ndiag, 1, nel);
+	  d.xcidx (0) = 0;
+	  d.xcidx (1) = nel;
+
+	  octave_idx_type ii = 0;
+	  if (k > 0)
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		{
+		  T tmp = elem (i, i+k);
+		  if (tmp != 0.)
+		    {
+		      d.xdata (ii) = tmp;
+		      d.xridx (ii++) = i;
+		    }
+		}
+	    }
+	  else if ( k < 0)
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		{
+		  T tmp = elem (i-k, i);
+		  if (tmp != 0.)
+		    {
+		      d.xdata (ii) = tmp;
+		      d.xridx (ii++) = i;
+		    }
+		}
+	    }
+	  else
+	    {
+	      for (octave_idx_type i = 0; i < ndiag; i++)
+		{
+		  T tmp = elem (i, i);
+		  if (tmp != 0.)
+		    {
+		      d.xdata (ii) = tmp;
+		      d.xridx (ii++) = i;
+		    }
+		}
+	    }
+	}
+      else
+	(*current_liboctave_error_handler) 
+	  ("diag: requested diagonal out of range");
+    }
+  else if (nnr != 0 && nnc != 0)
+    {
+      octave_idx_type roff = 0;
+      octave_idx_type coff = 0;
+      if (k > 0) 
+	{
+	  roff = 0;
+	  coff = k;
+	} 
+      else if (k < 0) 
+	{
+	  roff = -k;
+	  coff = 0;
+	}
+
+      if (nnr == 1) 
+	{
+	  octave_idx_type n = nnc + std::abs (k);
+	  octave_idx_type nz = nzmax ();
+	  d = Sparse<T> (n, n, nz);
+	  for (octave_idx_type i = 0; i < coff+1; i++)
+	    d.xcidx (i) = 0;
+	  for (octave_idx_type j = 0; j < nnc; j++)
+	    {
+	      for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
+		{
+		  d.xdata (i) = data (i);
+		  d.xridx (i) = j + roff;
+		}
+	      d.xcidx (j + coff + 1) = cidx(j+1);
+	    }
+	  for (octave_idx_type i = nnc + coff + 1; i < n + 1; i++)
+	    d.xcidx (i) = nz;
+	} 
+      else 
+	{
+	  octave_idx_type n = nnr + std::abs (k);
+	  octave_idx_type nz = nzmax ();
+	  octave_idx_type ii = 0;
+	  octave_idx_type ir = ridx(0);
+	  d = Sparse<T> (n, n, nz);
+	  for (octave_idx_type i = 0; i < coff+1; i++)
+	    d.xcidx (i) = 0;
+	  for (octave_idx_type i = 0; i < nnr; i++)
+	    {
+	      if (ir == i)
+		{
+		  d.xdata (ii) = data (ii);
+		  d.xridx (ii++) = ir + roff;
+		  if (ii != nz)
+		    ir = ridx (ii);
+		}
+	      d.xcidx (i + coff + 1) = ii;
+	    }
+	  for (octave_idx_type i = nnr + coff + 1; i < n+1; i++)
+	    d.xcidx (i) = nz;
+	}
+    }
+
+  return d;
+}
+
 // FIXME
 // Unfortunately numel can overflow for very large but very sparse matrices.
 // For now just flag an error when this happens.