changeset 1988:7b56630a1e05

[project @ 1996-03-02 00:33:22 by jwe] Initial revision
author jwe
date Sat, 02 Mar 1996 00:33:22 +0000
parents 6df7b42db205
children a4b0826e240c
files liboctave/Array2-idx.h liboctave/Array2.cc liboctave/Array2.h liboctave/Array3-idx.h liboctave/Array3.cc liboctave/Array3.h liboctave/DiagArray2.cc liboctave/DiagArray2.h liboctave/MArray-defs.h liboctave/MArray2.cc liboctave/MArray2.h liboctave/MDiagArray2.cc liboctave/MDiagArray2.h
diffstat 13 files changed, 2330 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/liboctave/Array2-idx.h
@@ -0,0 +1,580 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "Array-flags.h"
+#include "idx-vector.h"
+#include "lo-error.h"
+
+template <class T>
+Array2<T>
+Array2<T>::value (void)
+{
+  Array2<T> retval;
+
+  int n_idx = index_count ();
+
+  int nr = d1;
+  int nc = d2;
+
+  if (n_idx == 2)
+    {
+      idx_vector *tmp = get_idx ();
+      idx_vector idx_i = tmp[0];
+      idx_vector idx_j = tmp[1];
+
+      int n = idx_i.freeze (nr, "row", liboctave_pzo_flag);
+      int m = idx_j.freeze (nc, "column", liboctave_pzo_flag);
+
+      if (idx_i && idx_j)
+	{
+	  if (n == 0)
+	    {
+	      if (m == 0 || idx_j.is_colon_equiv (nc, 1))
+		retval.resize (0, 0);
+	      else
+		(*current_liboctave_error_handler)
+		  ("invalid row index = 0");
+	    }
+	  else if (m == 0)
+	    {
+	      if (n == 0 || idx_i.is_colon_equiv (nr, 1))
+		retval.resize (0, 0);
+	      else
+		(*current_liboctave_error_handler)
+		  ("invalid column index = 0");
+	    }
+	  else if (idx_i.is_colon_equiv (nr) && idx_j.is_colon_equiv (nc))
+	    {
+	      retval = *this;
+	    }
+	  else
+	    {
+	      retval.resize (n, m);
+
+	      for (int j = 0; j < m; j++)
+		{
+		  int jj = idx_j.elem (j);
+		  for (int i = 0; i < n; i++)
+		    {
+		      int ii = idx_i.elem (i);
+		      retval.elem (i, j) = elem (ii, jj);
+		    }
+		}
+	    }
+	}
+      // idx_vector::freeze() printed an error message for us.
+    }
+  else if (n_idx == 1)
+    {
+      if (nr == 1 && nc == 1)
+	{
+	  Array<T> tmp = Array<T>::value ();
+
+	  int len = tmp.length ();
+
+	  if (len == 0)
+	    retval = Array2<T> (0, 0);
+	  else
+	    {
+	      if (liboctave_pcv_flag)
+		retval = Array2<T> (tmp, len, 1);
+	      else
+		retval = Array2<T> (tmp, 1, len);
+	    }
+	}
+      else if (nr == 1 || nc == 1)
+	{
+	  int result_is_column_vector = (nc == 1);
+
+	  if (liboctave_dfi_flag)
+	    {
+	      idx_vector *tmp = get_idx ();
+	      idx_vector idx = tmp[0];
+
+	      if (idx.is_colon ())
+		result_is_column_vector = 1;
+	    }
+
+	  Array<T> tmp = Array<T>::value ();
+
+	  int len = tmp.length ();
+
+	  if (len == 0)
+	    retval = Array2<T> (0, 0);
+	  else
+	    {
+	      if (result_is_column_vector)
+		retval = Array2<T> (tmp, len, 1);
+	      else
+		retval = Array2<T> (tmp, 1, len);
+	    }
+	}
+      else if (liboctave_dfi_flag)
+	{
+	  // This code is only for indexing matrices.  The vector
+	  // cases are handled above.
+
+	  idx_vector *tmp = get_idx ();
+	  idx_vector idx = tmp[0];
+
+	  idx.freeze (nr * nc, "matrix", liboctave_pzo_flag);
+
+	  if (idx)
+	    {
+	      int result_nr = idx.orig_rows ();
+	      int result_nc = idx.orig_columns ();
+
+	      if (idx.is_colon ())
+		{
+		  result_nr = nr * nc;
+		  result_nc = 1;
+		}
+	      else if (idx.one_zero_only ())
+		{
+		  result_nr = idx.ones_count ();
+		  result_nc = (result_nr > 0 ? 1 : 0);
+		}
+
+	      retval.resize (result_nr, result_nc);
+
+	      int k = 0;
+	      for (int j = 0; j < result_nc; j++)
+		{
+		  for (int i = 0; i < result_nr; i++)
+		    {
+		      int ii = idx.elem (k++);
+		      int fr = ii % nr;
+		      int fc = (ii - fr) / nr;
+		      retval.elem (i, j) = elem (fr, fc);
+		    }
+		}
+	    }
+	  // idx_vector::freeze() printed an error message for us.
+	}
+      else
+	(*current_liboctave_error_handler)
+	  ("single index only valid for row or column vector");
+    }
+  else
+    (*current_liboctave_error_handler)
+      ("invalid number of indices for matrix expression");
+
+  clear_index ();
+
+  return retval;
+}
+
+template <class T>
+void
+Array2<T>::maybe_delete_elements (idx_vector& idx_i, idx_vector& idx_j)
+{
+  int nr = d1;
+  int nc = d2;
+
+  if (nr == 0 && nc == 0)
+    return;
+
+  if (idx_i.is_colon_equiv (nr, 1))
+    {
+      if (idx_j.is_colon_equiv (nc, 1))
+	resize (0, 0);
+      else
+	{
+	  int num_to_delete = idx_j.length (nc);
+
+	  if (num_to_delete != 0)
+	    {
+	      if (nr == 1 && num_to_delete == nc)
+		resize (0, 0);
+	      else
+		{
+		  int new_nc = nc - num_to_delete;
+		  if (new_nc > 0)
+		    {
+		      T *new_data = new T [nr * new_nc];
+
+		      int jj = 0;
+		      int idx = 0;
+		      for (int j = 0; j < nc; j++)
+			{
+			  if (j == idx_j.elem (idx))
+			    idx++;
+			  else
+			    {
+			      for (int i = 0; i < nr; i++)
+				new_data[nr*jj+i] = elem (i, j);
+			      jj++;
+			    }
+			}
+
+		      if (--rep->count <= 0)
+			delete rep;
+
+		      rep = new ArrayRep (new_data, nr * new_nc);
+
+		      d2 = new_nc;
+
+		      set_max_indices (2);
+		    }
+		  else
+		    (*current_liboctave_error_handler)
+		      ("A(idx) = []: index out of range");
+		}
+	    }
+	}
+    }
+  else if (idx_j.is_colon_equiv (nr, 1))
+    {
+      if (idx_i.is_colon_equiv (nc, 1))
+	resize (0, 0);
+      else
+	{
+	  int num_to_delete = idx_i.length (nr);
+
+	  if (num_to_delete != 0)
+	    {
+	      if (nc == 1 && num_to_delete == nr)
+		resize (0, 0);
+	      else 
+		{
+		  int new_nr = nr - num_to_delete;
+		  if (new_nr > 0)
+		    {
+		      T *new_data = new T [new_nr * nc];
+
+		      int ii = 0;
+		      int idx = 0;
+		      for (int i = 0; i < nr; i++)
+			{
+			  if (i == idx_i.elem (idx))
+			    idx++;
+			  else
+			    {
+			      for (int j = 0; j < nc; j++)
+				new_data[new_nr*j+ii] = elem (i, j);
+			      ii++;
+			    }
+			}
+
+		      if (--rep->count <= 0)
+			delete rep;
+
+		      rep = new ArrayRep (new_data, new_nr * nc);
+
+		      d1 = new_nr;
+
+		      set_max_indices (2);
+		    }
+		  else
+		    (*current_liboctave_error_handler)
+		      ("A(idx) = []: index out of range");
+		}
+	    }
+	}
+    }
+}
+
+template <class LT, class RT>
+int
+assign (Array2<LT>& lhs, const Array2<RT>& rhs)
+{
+  int retval = 1;
+
+  int n_idx = lhs.index_count ();
+
+  int lhs_nr = lhs.rows ();
+  int lhs_nc = lhs.cols ();
+
+  int rhs_nr = rhs.rows ();
+  int rhs_nc = rhs.cols ();
+
+  if (n_idx == 2)
+    {
+      idx_vector *tmp = lhs.get_idx ();
+
+      idx_vector idx_i = tmp[0];
+      idx_vector idx_j = tmp[1];
+
+      int n = idx_i.freeze (lhs_nr, "row", liboctave_pzo_flag,
+			    liboctave_rre_flag);
+
+      int m = idx_j.freeze (lhs_nc, "column", liboctave_pzo_flag,
+			    liboctave_rre_flag);
+
+      int idx_i_is_colon = idx_i.is_colon ();
+      int idx_j_is_colon = idx_j.is_colon ();
+
+      if (idx_i_is_colon)
+	n = rhs_nr;
+
+      if (idx_j_is_colon)
+	m = rhs_nc;
+
+      if (idx_i && idx_j)
+	{
+	  if (rhs_nr == 0 && rhs_nc == 0)
+	    {
+	      lhs.maybe_delete_elements (idx_i, idx_j);
+	    }
+	  else
+	    {
+	      if (liboctave_rre_flag)
+		{
+		  int max_row_idx = idx_i_is_colon ? rhs_nr : idx_i.max () + 1;
+		  int max_col_idx = idx_j_is_colon ? rhs_nc : idx_j.max () + 1;
+
+		  int new_nr = max_row_idx > lhs_nr ? max_row_idx : lhs_nr;
+		  int new_nc = max_col_idx > lhs_nc ? max_col_idx : lhs_nc;
+
+		  lhs.resize (new_nr, new_nc, 0.0);
+		}
+
+	      if (n == rhs_nr && m == rhs_nc)
+		{
+		  for (int j = 0; j < m; j++)
+		    {
+		      int jj = idx_j.elem (j);
+		      for (int i = 0; i < n; i++)
+			{
+			  int ii = idx_i.elem (i);
+			  lhs.elem (ii, jj) = rhs.elem (i, j);
+			}
+		    }
+		}
+	      else if (rhs_nr == 1 && rhs_nc == 1)
+		{
+		  RT scalar = rhs.elem (0, 0);
+
+		  for (int j = 0; j < m; j++)
+		    {
+		      int jj = idx_j.elem (j);
+		      for (int i = 0; i < n; i++)
+			{
+			  int ii = idx_i.elem (i);
+			  lhs.elem (ii, jj) = scalar;
+			}
+		    }
+		}
+	      else
+		{
+		  (*current_liboctave_error_handler)
+    ("A(I, J) = X: X must be a scalar or the number of elements in I must");
+		  (*current_liboctave_error_handler)
+    ("match the number of rows in X and the number of elements in J must");
+		  (*current_liboctave_error_handler)
+    ("match the number of columns in X");
+
+		  retval = 0;
+		}
+	    }
+	}
+      // idx_vector::freeze() printed an error message for us.
+    }
+  else if (n_idx == 1)
+    {
+      if (lhs_nr == 0 || lhs_nc == 0
+	  || (lhs_nr == 1 && lhs_nc == 1))
+	{
+	  idx_vector *tmp = lhs.get_idx ();
+
+	  idx_vector idx = tmp[0];
+
+	  int lhs_len = lhs.length ();
+
+	  int n = idx.freeze (lhs_len, 0, liboctave_pzo_flag,
+			      liboctave_rre_flag);
+
+	  if (idx)
+	    {
+	      if (rhs_nr == 0 && rhs_nc == 0)
+		{
+		  if (n != 0 && (lhs_nr != 0 || lhs_nc != 0))
+		    {
+		      idx_vector tmp (':');
+		      lhs.maybe_delete_elements (idx, tmp);
+		    }
+		}
+	      else
+		{
+		  if (assign ((Array<LT>&) lhs, (Array<RT>&) rhs))
+		    {
+		      int len = lhs.length ();
+
+		      if (len > 0)
+			{
+			  int idx_nr = idx.orig_rows ();
+			  int idx_nc = idx.orig_columns ();
+
+			  if (liboctave_dfi_flag
+			      || (idx_nr == 1 && idx_nc == 1))
+			    {
+			      if (liboctave_pcv_flag)
+				{
+				  lhs.d1 = lhs.length ();
+				  lhs.d2 = 1;
+				}
+			      else
+				{
+				  lhs.d1 = 1;
+				  lhs.d2 = lhs.length ();
+				}
+			    }
+			  else if (idx_nr == 1 && rhs_nr == 1)
+			    {
+			      lhs.d1 = 1;
+			      lhs.d2 = lhs.length ();
+			    }
+			  else if (idx_nc == 1 && rhs_nc == 1)
+			    {
+			      lhs.d1 = lhs.length ();
+			      lhs.d2 = 1;
+			    }
+			  else
+			    (*current_liboctave_error_handler)
+      ("A(I) = X: X must be a scalar or a matrix with the same size as I");
+			}
+		      else
+			{
+			  lhs.d1 = 0;
+			  lhs.d2 = 0;
+			}
+		    }
+		  else
+		    retval = 0;
+		}
+	    }
+	  // idx_vector::freeze() printed an error message for us.
+	}
+      else if (lhs_nr == 1)
+	{
+	  idx_vector *tmp = lhs.get_idx ();
+
+	  idx_vector idx = tmp[0];
+
+	  idx.freeze (lhs_nc, "vector", liboctave_pzo_flag,
+		      liboctave_rre_flag);
+
+	  if (idx)
+	    {
+	      if (rhs_nr == 0 && rhs_nc == 0)
+		{
+		  idx_vector tmp (':');
+		  lhs.maybe_delete_elements (tmp, idx);
+		}
+	      else
+		{
+		  if (assign ((Array<LT>&) lhs, (Array<RT>&) rhs))
+		    lhs.d2 = lhs.length ();
+		  else
+		    retval = 0;
+		}
+	    }
+	  // idx_vector::freeze() printed an error message for us.
+	}
+      else if (lhs_nc == 1)
+	{
+	  idx_vector *tmp = lhs.get_idx ();
+
+	  idx_vector idx = tmp[0];
+
+	  idx.freeze (lhs_nr, "vector", liboctave_pzo_flag,
+		      liboctave_rre_flag);
+
+	  if (idx)
+	    {
+	      if (rhs_nr == 0 && rhs_nc == 0)
+		{
+		  idx_vector tmp (':');
+		  lhs.maybe_delete_elements (idx, tmp);
+		}
+	      else
+		{
+		  if (assign ((Array<LT>&) lhs, (Array<RT>&) rhs))
+		    lhs.d1 = lhs.length ();
+		  else
+		    retval = 0;
+		}
+	    }
+	  // idx_vector::freeze() printed an error message for us.
+	}
+      else if (liboctave_dfi_flag)
+	{
+	  idx_vector *tmp = lhs.get_idx ();
+	  idx_vector idx = tmp[0];
+
+	  int len = idx.freeze (lhs_nr * lhs_nc, "matrix",
+				liboctave_pzo_flag);
+
+	  if (idx)
+	    {
+	      if (len == rhs_nr * rhs_nc)
+		{
+		  int k = 0;
+		  for (int j = 0; j < rhs_nc; j++)
+		    {
+		      for (int i = 0; i < rhs_nr; i++)
+			{
+			  int ii = idx.elem (k++);
+			  int fr = ii % lhs_nr;
+			  int fc = (ii - fr) / lhs_nr;
+			  lhs.elem (fr, fc) = rhs.elem (i, j);
+			}
+		    }
+		}
+	      else
+		{
+		  (*current_liboctave_error_handler)
+      ("A(I) = X: X must be a scalar or a matrix with the same size as I");
+
+		  retval = 0;
+		}
+	    }
+	  // idx_vector::freeze() printed an error message for us.
+	}
+      else
+	{
+	  (*current_liboctave_error_handler)
+	    ("single index only valid for row or column vector");
+
+	  retval = 0;
+	}
+    }
+  else
+    {
+      (*current_liboctave_error_handler)
+	("invalid number of indices for matrix expression");
+
+      retval = 0;
+    }
+
+  lhs.clear_index ();
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/Array2.cc
@@ -0,0 +1,205 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+
+#include <iostream.h>
+
+#include "Array2.h"
+
+#if defined (HEAVYWEIGHT_INDEXING)
+#include "idx-vector.h"
+#include "Array2-idx.h"
+#endif
+
+#include "lo-error.h"
+
+// Two dimensional array class.
+
+template <class T>
+T&
+Array2<T>::checkelem (int i, int j)
+{
+  if (i < 0 || j < 0 || i >= d1 || j >= d2)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      static T foo;
+      return foo;
+    }
+  return Array<T>::elem (d1*j+i);
+}
+
+template <class T>
+T
+Array2<T>::elem (int i, int j) const
+{
+  return Array<T>::elem (d1*j+i);
+}
+
+template <class T>
+T
+Array2<T>::checkelem (int i, int j) const
+{
+  if (i < 0 || j < 0 || i >= d1 || j >= d2)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return Array<T>::elem (d1*j+i);
+}
+
+template <class T>
+T
+Array2<T>::operator () (int i, int j) const
+{
+  if (i < 0 || j < 0 || i >= d1 || j >= d2)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return Array<T>::elem (d1*j+i);
+}
+
+template <class T>
+void
+Array2<T>::resize (int r, int c)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler) ("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_len = length ();
+
+  rep = new ArrayRep (r*c);
+
+  d1 = r;
+  d2 = c;
+
+  if (old_data && old_len > 0)
+    {
+      int min_r = old_d1 < r ? old_d1 : r;
+      int min_c = old_d2 < c ? old_d2 : c;
+
+      for (int j = 0; j < min_c; j++)
+	for (int i = 0; i < min_r; i++)
+	  xelem (i, j) = old_data[old_d1*j+i];
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+Array2<T>::resize (int r, int c, const T& val)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler) ("can't resize to negative dimension");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+  int old_d1 = dim1 ();
+  int old_d2 = dim2 ();
+  int old_len = length ();
+
+  rep = new ArrayRep (r*c);
+
+  d1 = r;
+  d2 = c;
+
+  int min_r = old_d1 < r ? old_d1 : r;
+  int min_c = old_d2 < c ? old_d2 : c;
+
+  if (old_data && old_len > 0)
+    {
+      for (int j = 0; j < min_c; j++)
+	for (int i = 0; i < min_r; i++)
+	  xelem (i, j) = old_data[old_d1*j+i];
+    }
+
+  for (int j = 0; j < min_c; j++)
+    for (int i = min_r; i < r; i++)
+      xelem (i, j) = val;
+
+  for (int j = min_c; j < c; j++)
+    for (int i = 0; i < r; i++)
+      xelem (i, j) = val;
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+Array2<T>&
+Array2<T>::insert (const Array2<T>& a, int r, int c)
+{
+  int a_rows = a.rows ();
+  int a_cols = a.cols ();
+
+  if (r < 0 || r + a_rows > rows () || c < 0 || c + a_cols > cols ())
+    {
+      (*current_liboctave_error_handler) ("range error for insert");
+      return *this;
+    }
+
+  for (int j = 0; j < a_cols; j++)
+    for (int i = 0; i < a_rows; i++)
+      elem (r+i, c+j) = a.elem (i, j);
+
+  return *this;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/Array2.h
@@ -0,0 +1,155 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_Array2_h)
+#define octave_Array2_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#define HEAVYWEIGHT_INDEXING 1
+
+#include <cassert>
+#include <cstdlib>
+
+#include "Array.h"
+#include "lo-error.h"
+
+class idx_vector;
+
+// Two dimensional array class.
+
+template <class T>
+class Array2 : public Array<T>
+{
+protected:
+
+  Array2 (T *d, int n, int m) : Array<T> (d, n*m)
+    {
+      d1 = n;
+      d2 = m;
+      set_max_indices (2);
+    }
+
+public:
+
+  // These really need to be protected (and they will be in the
+  // future, so don't depend on them being here!), but they can't be
+  // until template friends work correctly in g++.
+
+  int d1;
+  int d2;
+
+  Array2 (void) : Array<T> ()
+    {
+      d1 = 0;
+      d2 = 0;
+      set_max_indices (2);
+    }
+
+  Array2 (int n, int m) : Array<T> (n*m)
+    {
+      d1 = n;
+      d2 = m;
+      set_max_indices (2);
+    }
+
+  Array2 (int n, int m, const T& val) : Array<T> (n*m, val)
+    {
+      d1 = n;
+      d2 = m;
+      set_max_indices (2);
+    }
+
+  Array2 (const Array2<T>& a) : Array<T> (a)
+    {
+      d1 = a.d1;
+      d2 = a.d2;
+      set_max_indices (2);
+    }
+
+  Array2 (const Array<T>& a, int n, int m) : Array<T> (a)
+    {
+      d1 = n;
+      d2 = m;
+      set_max_indices (2);
+    }
+
+  ~Array2 (void) { }
+
+  Array2<T>& operator = (const Array2<T>& a)
+    {
+      if (this != &a && rep != a.rep)
+	{
+	  Array<T>::operator = (a);
+	  d1 = a.d1;
+	  d2 = a.d2;
+	}
+
+      return *this;
+    }
+
+  int dim1 (void) const { return d1; }
+  int dim2 (void) const { return d2; }
+
+  int rows (void) const { return d1; }
+  int cols (void) const { return d2; }
+  int columns (void) const { return d2; }
+
+  T& elem (int i, int j) { return Array<T>::elem (d1*j+i); }
+  T& checkelem (int i, int j);
+  T& operator () (int i, int j) { return checkelem (i, j); }
+
+  T elem (int i, int j) const;
+  T checkelem (int i, int j) const;
+  T operator () (int i, int j) const;
+
+  // No checking.
+
+  T& xelem (int i, int j) { return Array<T>::xelem (d1*j+i); }
+  T xelem (int i, int j) const { return Array<T>::xelem (d1*j+i); }
+
+  void resize (int n, int m);
+  void resize (int n, int m, const T& val);
+
+  Array2<T>& insert (const Array2<T>& a, int r, int c);
+
+#ifdef HEAVYWEIGHT_INDEXING
+  void maybe_delete_elements (idx_vector& i, idx_vector& j);
+
+  Array2<T> value (void);
+#endif
+};
+
+template <class LT, class RT>
+int assign (Array2<LT>& lhs, const Array2<RT>& rhs);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/Array3-idx.h
@@ -0,0 +1,57 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "Array-flags.h"
+#include "idx-vector.h"
+#include "lo-error.h"
+
+template <class T>
+void
+Array3<T>::maybe_delete_elements (idx_vector&, idx_vector&, idx_vector&)
+{
+  assert (0);
+}
+
+template <class T>
+Array3<T>
+Array3<T>::value (void)
+{
+  Array3<T> retval;
+  assert (0);
+  return retval;
+}
+
+template <class LT, class RT>
+int
+assign (Array3<LT>&, const Array3<RT>&)
+{
+  assert (0);
+  return 0;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/Array3.cc
@@ -0,0 +1,114 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+
+#include <iostream.h>
+
+#include "Array3.h"
+
+#if defined (HEAVYWEIGHT_INDEXING)
+#include "idx-vector.h"
+#include "Array3-idx.h"
+#endif
+
+#include "lo-error.h"
+
+// Three dimensional array class.
+
+template <class T>
+T&
+Array3<T>::checkelem (int i, int j, int k)
+{
+  if (i < 0 || j < 0 || k < 0 || i >= d1 || j >= d2 || k >= d3)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      static T foo;
+      return foo;
+    }
+  return Array2<T>::elem (i, d1*k+j);
+}
+
+template <class T>
+T
+Array3<T>::elem (int i, int j, int k) const
+{
+  return Array2<T>::elem (i, d2*k+j);
+}
+
+template <class T>
+T
+Array3<T>::checkelem (int i, int j, int k) const
+{
+  if (i < 0 || j < 0 || k < 0 || i >= d1 || j >= d2 || k >= d3)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return Array2<T>::elem (i, d1*k+j);
+}
+
+template <class T>
+T
+Array3<T>::operator () (int i, int j, int k) const
+{
+  if (i < 0 || j < 0 || k < 0 || i >= d1 || j >= d2 || k >= d3)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return Array2<T>::elem (i, d2*k+j);
+}
+
+template <class T>
+void
+Array3<T>::resize (int n, int m, int k)
+{
+  assert (0); // XXX FIXME XXX
+}
+
+template <class T>
+void
+Array3<T>::resize (int n, int m, int k, const T& val)
+{
+  assert (0); // XXX FIXME XXX
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/Array3.h
@@ -0,0 +1,136 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_Array3_h)
+#define octave_Array3_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#define HEAVYWEIGHT_INDEXING 1
+
+#include <cassert>
+#include <cstdlib>
+
+#include "Array2.h"
+#include "lo-error.h"
+
+class idx_vector;
+
+// Three dimensional array class.
+
+template <class T>
+class Array3 : public Array2<T>
+{
+protected:
+
+  int d3;
+
+  Array3 (T *d, int n, int m, int k) : Array2<T> (d, n, m*k)
+    {
+      d2 = m;
+      d3 = k;
+      set_max_indices (3);
+    }
+
+public:
+
+  Array3 (void) : Array2<T> ()
+    {
+      d2 = 0;
+      d3 = 0;
+      set_max_indices (3);
+    }
+
+  Array3 (int n, int m, int k) : Array2<T> (n, m*k)
+    {
+      d2 = m;
+      d3 = k;
+      set_max_indices (3);
+    }
+
+  Array3 (int n, int m, int k, const T& val) : Array2<T> (n, m*k, val)
+    {
+      d2 = m;
+      d3 = k;
+      set_max_indices (3);
+    }
+
+  Array3 (const Array3<T>& a) : Array2<T> (a)
+    {
+      d2 = a.d2;
+      d3 = a.d3;
+      set_max_indices (3);
+    }
+
+  ~Array3 (void) { }
+
+  Array3<T>& operator = (const Array3<T>& a)
+    {
+      if (this != &a && rep != a.rep)
+	{
+	  Array<T>::operator = (a);
+	  d1 = a.d1;
+	  d2 = a.d2;
+	  d3 = a.d3;
+	}
+
+      return *this;
+    }
+
+  int dim3 (void) const { return d3; }
+
+  T& elem (int i, int j, int k) { return Array2<T>::elem (i, d2*k+j); }
+  T& checkelem (int i, int j, int k);
+  T& operator () (int i, int j, int k) { return checkelem (i, j, k); }
+
+  // No checking.
+
+  T& xelem (int i, int j, int k) { return Array2<T>::xelem (i, d2*k+j); }
+
+  T elem (int i, int j, int k) const;
+  T checkelem (int i, int j, int k) const;
+  T operator () (int i, int j, int k) const;
+
+  void resize (int n, int m, int k);
+  void resize (int n, int m, int k, const T& val);
+
+#ifdef HEAVYWEIGHT_INDEXING
+  void maybe_delete_elements (idx_vector& i, idx_vector& j, idx_vector& k);
+
+  Array3<T> value (void);
+#endif
+};
+
+template <class LT, class RT>
+int assign (Array3<LT>& lhs, const Array3<RT>& rhs);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/DiagArray2.cc
@@ -0,0 +1,208 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+
+#include <iostream.h>
+
+#include "DiagArray2.h"
+
+#include "lo-error.h"
+
+// A two-dimensional array with diagonal elements only.
+
+#if 0
+template <class T>
+T&
+DiagArray2<T>::elem (int r, int c)
+{
+  static T foo (0);
+  return (r == c) ? Array<T>::xelem (r) : foo;
+}
+
+template <class T>
+T&
+DiagArray2<T>::checkelem (int r, int c)
+{
+  static T foo (0);
+  if (r < 0 || c < 0 || r >= nr || c >= nc)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      return foo;
+    }
+  return (r == c) ? Array<T>::xelem (r) : foo;
+}
+
+template <class T>
+T&
+DiagArray2<T>::operator () (int r, int c)
+{
+  static T foo (0);
+  if (r < 0 || c < 0 || r >= nr || c >= nc)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      return foo;
+    }
+  return (r == c) ? Array<T>::xelem (r) : foo;
+}
+#endif
+
+template <class T>
+T
+DiagArray2<T>::elem (int r, int c) const
+{
+  return (r == c) ? Array<T>::xelem (r) : T (0);
+}
+
+template <class T>
+T
+DiagArray2<T>::checkelem (int r, int c) const
+{
+  if (r < 0 || c < 0 || r >= nr || c >= nc)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return (r == c) ? Array<T>::xelem (r) : T (0);
+}
+
+template <class T>
+T
+DiagArray2<T>::operator () (int r, int c) const
+{
+  if (r < 0 || c < 0 || r >= nr || c >= nc)
+    {
+      (*current_liboctave_error_handler) ("range error");
+      T foo;
+      static T *bar = &foo;
+      return foo;
+    }
+  return (r == c) ? Array<T>::xelem (r) : T (0);
+}
+
+template <class T>
+T&
+DiagArray2<T>::xelem (int r, int c)
+{
+  static T foo (0);
+  return (r == c) ? Array<T>::xelem (r) : foo;
+}
+
+template <class T>
+T
+DiagArray2<T>::xelem (int r, int c) const
+{
+  return (r == c) ? Array<T>::xelem (r) : T (0);
+}
+
+template <class T>
+void
+DiagArray2<T>::resize (int r, int c)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler) ("can't resize to negative dimensions");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+  int old_len = length ();
+
+  int new_len = r < c ? r : c;
+
+  rep = new ArrayRep (new_len);
+
+  nr = r;
+  nc = c;
+
+  if (old_data && old_len > 0)
+    {
+      int min_len = old_len < new_len ? old_len : new_len;
+
+      for (int i = 0; i < min_len; i++)
+	xelem (i, i) = old_data[i];
+    }
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+template <class T>
+void
+DiagArray2<T>::resize (int r, int c, const T& val)
+{
+  if (r < 0 || c < 0)
+    {
+      (*current_liboctave_error_handler) ("can't resize to negative dimensions");
+      return;
+    }
+
+  if (r == dim1 () && c == dim2 ())
+    return;
+
+  ArrayRep *old_rep = rep;
+  const T *old_data = data ();
+  int old_len = length ();
+
+  int new_len = r < c ? r : c;
+
+  rep = new ArrayRep (new_len);
+
+  nr = r;
+  nc = c;
+
+  int min_len = old_len < new_len ? old_len : new_len;
+
+  if (old_data && old_len > 0)
+    {
+      for (int i = 0; i < min_len; i++)
+	xelem (i, i) = old_data[i];
+    }
+
+  for (int i = min_len; i < new_len; i++)
+    xelem (i, i) = val;
+
+  if (--old_rep->count <= 0)
+    delete old_rep;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/DiagArray2.h
@@ -0,0 +1,250 @@
+// Template array classes                              -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_DiagArray2_h)
+#define octave_DiagArray2_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#define HEAVYWEIGHT_INDEXING 1
+
+#include <cassert>
+#include <cstdlib>
+
+#include "Array2.h"
+#include "lo-error.h"
+
+class idx_vector;
+
+// A two-dimensional array with diagonal elements only.
+//
+// Idea and example code for Proxy class and functions from:
+//
+// From: kanze@us-es.sel.de (James Kanze)
+// Subject: Re: How to overload [] to do READ/WRITE differently ?
+// Message-ID: <KANZE.93Nov29151407@slsvhdt.us-es.sel.de>
+// Sender: news@us-es.sel.de
+// Date: 29 Nov 1993 14:14:07 GMT
+// --
+// James Kanze                             email: kanze@us-es.sel.de
+// GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
+
+template <class T>
+class DiagArray2 : public Array<T>
+{
+private:
+
+  T get (int i) { return Array<T>::xelem (i); }
+
+  void set (const T& val, int i) { Array<T>::xelem (i) = val; }
+
+  class Proxy
+  {
+  public:
+
+    Proxy (DiagArray2<T> *ref, int r, int c)
+      : i (r), j (c), object (ref) { } 
+
+    const Proxy& operator = (const T& val) const
+      {
+	if (i == j)
+	  {
+	    if (object)
+	      object->set (val, i);
+	  }
+	else
+	  (*current_liboctave_error_handler)
+	    ("invalid assignment to off-diagonal in diagonal array");
+
+	return *this;
+      }
+
+    operator T () const
+      {
+	if (object && i == j)
+	  return object->get (i);
+	else
+	  {
+	    static T foo (0);
+	    return foo;
+	  }
+      }
+
+  private:
+
+    // XXX FIXME XXX -- this is declared private to keep the user from
+    // taking the address of a Proxy.  Maybe it should be implemented
+    // by means of a companion function in the DiagArray2 class.
+
+    T *operator& () const { assert (0); return (T *) 0; }
+
+    int i;
+    int j;
+
+    DiagArray2<T> *object;
+
+  };
+
+friend class Proxy;
+
+protected:
+
+  int nr;
+  int nc;
+
+  DiagArray2 (T *d, int r, int c) : Array<T> (d, r < c ? r : c)
+    {
+      nr = r;
+      nc = c;
+      set_max_indices (2);
+    }
+
+public:
+
+  DiagArray2 (void) : Array<T> ()
+    {
+      nr = 0;
+      nc = 0;
+      set_max_indices (2);
+    }
+
+  DiagArray2 (int r, int c) : Array<T> (r < c ? r : c)
+    {
+      nr = r;
+      nc = c;
+      set_max_indices (2);
+    }
+
+  DiagArray2 (int r, int c, const T& val) : Array<T> (r < c ? r : c, val)
+    {
+      nr = r;
+      nc = c;
+      set_max_indices (2);
+    }
+
+  DiagArray2 (const Array<T>& a) : Array<T> (a)
+    {
+      nr = nc = a.length ();
+      set_max_indices (2);
+    }
+
+  DiagArray2 (const DiagArray2<T>& a) : Array<T> (a)
+    {
+      nr = a.nr;
+      nc = a.nc;
+      set_max_indices (2);
+    }
+
+  ~DiagArray2 (void) { }
+
+  DiagArray2<T>& operator = (const DiagArray2<T>& a)
+    {
+      if (this != &a)
+	{
+	  Array<T>::operator = (a);
+	  nr = a.nr;
+	  nc = a.nc;
+	}
+
+      return *this;
+    }
+
+#if 0
+  operator Array2<T> () const
+    {
+      Array2<T> retval (nr, nc,  T (0));
+
+      int len = nr < nc ? nr : nc;
+
+      for (int i = 0; i < len; i++)
+	retval.xelem (i, i) = xelem (i, i);
+
+      return retval;
+    }
+#endif
+
+  int dim1 (void) const { return nr; }
+  int dim2 (void) const { return nc; }
+
+  int rows (void) const { return nr; }
+  int cols (void) const { return nc; }
+  int columns (void) const { return nc; }
+
+#if 1
+  Proxy elem (int r, int c)
+    {
+      return Proxy (this, r, c);
+    }
+
+  Proxy checkelem (int r, int c)
+    {
+      if (r < 0 || c < 0 || r >= nr || c >= nc)
+	{
+	  (*current_liboctave_error_handler) ("range error");
+	  return Proxy (0, r, c);
+	}
+      else
+	return Proxy (this, r, c);
+    }
+
+  Proxy operator () (int r, int c)
+    {
+      if (r < 0 || c < 0 || r >= nr || c >= nc)
+	{
+	  (*current_liboctave_error_handler) ("range error");
+	  return Proxy (0, r, c);
+	}
+      else
+	return Proxy (this, r, c);
+  }
+#else
+  T& elem (int r, int c);
+  T& checkelem (int r, int c);
+  T& operator () (int r, int c);
+#endif
+
+  T elem (int r, int c) const;
+  T checkelem (int r, int c) const;
+  T operator () (int r, int c) const;
+
+  // No checking.
+
+  T& xelem (int r, int c);
+  T xelem (int r, int c) const;
+
+  void resize (int n, int m);
+  void resize (int n, int m, const T& val);
+
+  void maybe_delete_elements (idx_vector& i, idx_vector& j);
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/MArray-defs.h
@@ -0,0 +1,67 @@
+// Nothing like a little CPP abuse to brighten everyone's day.  Would
+// have been nice to do this with template functions but as of 2.5.x,
+// g++ seems to fail to resolve them properly.
+
+#define DO_VS_OP(OP) \
+  int l = a.length (); \
+  T *result = 0; \
+  if (l > 0) \
+    { \
+      result = new T [l]; \
+      const T *x = a.data (); \
+      for (int i = 0; i < l; i++) \
+	result[i] = x[i] OP s; \
+    }
+
+#define DO_SV_OP(OP) \
+  int l = a.length (); \
+  T *result = 0; \
+  if (l > 0) \
+    { \
+      result = new T [l]; \
+      const T *x = a.data (); \
+      for (int i = 0; i < l; i++) \
+	result[i] = s OP x[i]; \
+    }
+
+#define DO_VV_OP(OP) \
+  T *result = 0; \
+  if (l > 0) \
+    { \
+      result = new T [l]; \
+      const T *x = a.data (); \
+      const T *y = b.data (); \
+      for (int i = 0; i < l; i++) \
+	result[i] = x[i] OP y[i]; \
+    }
+
+#define NEG_V \
+  int l = a.length (); \
+  T *result = 0; \
+  if (l > 0) \
+    { \
+      result = new T [l]; \
+      const T *x = a.data (); \
+      for (int i = 0; i < l; i++) \
+	result[i] = -x[i]; \
+    }
+
+#define DO_VS_OP2(OP) \
+  int l = a.length (); \
+  if (l > 0) \
+    { \
+      T *tmp = a.fortran_vec (); \
+      for (int i = 0; i < l; i++) \
+	tmp[i] OP s; \
+    }
+
+#define DO_VV_OP2(OP) \
+  do \
+    { \
+      T *a_tmp = a.fortran_vec (); \
+      const T *b_tmp = b.data (); \
+      for (int i = 0; i < l; i++) \
+	a_tmp[i] += b_tmp[i]; \
+    } \
+  while (0)
+
new file mode 100644
--- /dev/null
+++ b/liboctave/MArray2.cc
@@ -0,0 +1,177 @@
+// MArray.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MArray2.h"
+#include "lo-error.h"
+
+#include "MArray-defs.h"
+
+// Two dimensional array with math ops.
+
+// Element by element MArray2 by scalar ops.
+
+template <class T>
+MArray2<T>&
+operator += (MArray2<T>& a, const T& s)
+{
+  DO_VS_OP2 (+=)
+  return a;
+}
+
+template <class T>
+MArray2<T>&
+operator -= (MArray2<T>& a, const T& s)
+{
+  DO_VS_OP2 (-=)
+  return a;
+}
+
+// Element by element MArray2 by MArray2 ops.
+
+template <class T>
+MArray2<T>&
+operator += (MArray2<T>& a, const MArray2<T>& b)
+{
+  int r = a.rows ();
+  int c = a.cols ();
+  if (r != b.rows () || c != b.cols ())
+    {
+      (*current_liboctave_error_handler)
+	("nonconformant += array operation attempted");
+    }
+  else
+    {
+      if (r > 0 && c > 0)
+	{
+	  int l = a.length ();
+	  DO_VV_OP2 (+=);
+	}
+    }
+  return a;
+}
+
+template <class T>
+MArray2<T>&
+operator -= (MArray2<T>& a, const MArray2<T>& b)
+{
+  int r = a.rows ();
+  int c = a.cols ();
+  if (r != b.rows () || c != b.cols ())
+    {
+      (*current_liboctave_error_handler)
+	("nonconformant -= array operation attempted");
+    }
+  else
+    {
+      if (r > 0 && c > 0)
+	{
+	  int l = a.length ();
+	  DO_VV_OP2 (-=);
+	}
+    }
+  return a;
+}
+
+// Element by element MArray2 by scalar ops.
+
+#define MARRAY_A2S_OP(OP) \
+  template <class T> \
+  MArray2<T> \
+  operator OP (const MArray2<T>& a, const T& s) \
+  { \
+    DO_VS_OP (OP); \
+    return MArray2<T> (result, a.rows (), a.cols ()); \
+  }
+
+MARRAY_A2S_OP (+)
+MARRAY_A2S_OP (-)
+MARRAY_A2S_OP (*)
+MARRAY_A2S_OP (/)
+
+// Element by element scalar by MArray2 ops.
+
+#define MARRAY_SA2_OP(OP) \
+  template <class T> \
+  MArray2<T> \
+  operator OP (const T& s, const MArray2<T>& a) \
+  { \
+    DO_SV_OP (OP); \
+    return MArray2<T> (result, a.rows (), a.cols ()); \
+  }
+
+MARRAY_SA2_OP (+)
+MARRAY_SA2_OP (-)
+MARRAY_SA2_OP (*)
+MARRAY_SA2_OP (/)
+
+// Element by element MArray2 by MArray2 ops.
+
+#define MARRAY_A2A2_OP(FCN, OP, OP_STR) \
+  template <class T> \
+  MArray2<T> \
+  FCN (const MArray2<T>& a, const MArray2<T>& b) \
+  { \
+    int r = a.rows (); \
+    int c = a.cols (); \
+    if (r != b.rows () || c != b.cols ()) \
+      { \
+	(*current_liboctave_error_handler) \
+	  ("nonconformant array " OP_STR " attempted"); \
+	return MArray2<T> (); \
+      } \
+    if (r == 0 || c == 0) \
+      return MArray2<T> (); \
+    int l = a.length (); \
+    DO_VV_OP (OP); \
+    return MArray2<T> (result, r, c); \
+  }
+
+MARRAY_A2A2_OP (operator +, +, "addition")
+MARRAY_A2A2_OP (operator -, -, "subtraction")
+MARRAY_A2A2_OP (product,    *, "product")
+MARRAY_A2A2_OP (quotient,   /, "quotient")
+
+// Unary MArray2 ops.
+
+template <class T>
+MArray2<T>
+operator - (const MArray2<T>& a)
+{
+  NEG_V;
+  return MArray2<T> (result, a.rows (), a.cols ());
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/MArray2.h
@@ -0,0 +1,115 @@
+// Template array classes with like-type math ops          -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#if !defined (octave_MArray2_h)
+#define octave_MArray2_h 1
+
+#include "Array2.h"
+
+// Two dimensional array with math ops.
+
+template <class T>
+class MArray2 : public Array2<T>
+{
+protected:
+
+  MArray2 (T *d, int n, int m) : Array2<T> (d, n, m) { }
+
+public:
+
+  MArray2 (void) : Array2<T> () { }
+  MArray2 (int n, int m) : Array2<T> (n, m) { }
+  MArray2 (int n, int m, const T& val) : Array2<T> (n, m, val) { }
+  MArray2 (const Array2<T>& a) : Array2<T> (a) { }
+  MArray2 (const MArray2<T>& a) : Array2<T> (a) { }
+
+  ~MArray2 (void) { }
+
+  MArray2<T>& operator = (const MArray2<T>& a)
+    {
+      Array2<T>::operator = (a);
+      return *this;
+    }
+
+  // element by element MArray2 by scalar ops
+
+  friend MArray2<T>& operator += (MArray2<T>& a, const T& s);
+  friend MArray2<T>& operator -= (MArray2<T>& a, const T& s);
+
+  // element by element MArray2 by MArray2 ops
+
+  friend MArray2<T>& operator += (MArray2<T>& a, const MArray2<T>& b);
+  friend MArray2<T>& operator -= (MArray2<T>& a, const MArray2<T>& b);
+
+  // element by element MArray2 by scalar ops
+
+  friend MArray2<T> operator + (const MArray2<T>& a, const T& s);
+  friend MArray2<T> operator - (const MArray2<T>& a, const T& s);
+  friend MArray2<T> operator * (const MArray2<T>& a, const T& s);
+  friend MArray2<T> operator / (const MArray2<T>& a, const T& s);
+
+  // element by element scalar by MArray2 ops
+
+  friend MArray2<T> operator + (const T& s, const MArray2<T>& a);
+  friend MArray2<T> operator - (const T& s, const MArray2<T>& a);
+  friend MArray2<T> operator * (const T& s, const MArray2<T>& a);
+  friend MArray2<T> operator / (const T& s, const MArray2<T>& a);
+
+  // element by element MArray2 by MArray2 ops
+
+  friend MArray2<T> operator + (const MArray2<T>& a, const MArray2<T>& b);
+  friend MArray2<T> operator - (const MArray2<T>& a, const MArray2<T>& b);
+
+  friend MArray2<T> product (const MArray2<T>& a, const MArray2<T>& b);
+  friend MArray2<T> quotient (const MArray2<T>& a, const MArray2<T>& b);
+
+  friend MArray2<T> operator - (const MArray2<T>& a);
+};
+
+#define INSTANTIATE_MARRAY2_FRIENDS(T) \
+  template MArray2<T> operator + (const MArray2<T>& a, const T& s); \
+  template MArray2<T> operator - (const MArray2<T>& a, const T& s); \
+  template MArray2<T> operator * (const MArray2<T>& a, const T& s); \
+  template MArray2<T> operator / (const MArray2<T>& a, const T& s); \
+  template MArray2<T> operator + (const T& s, const MArray2<T>& a); \
+  template MArray2<T> operator - (const T& s, const MArray2<T>& a); \
+  template MArray2<T> operator * (const T& s, const MArray2<T>& a); \
+  template MArray2<T> operator / (const T& s, const MArray2<T>& a); \
+  template MArray2<T> operator + (const MArray2<T>& a, const MArray2<T>& b); \
+  template MArray2<T> operator - (const MArray2<T>& a, const MArray2<T>& b); \
+  template MArray2<T> product (const MArray2<T>& a, const MArray2<T>& b); \
+  template MArray2<T> quotient (const MArray2<T>& a, const MArray2<T>& b); \
+  template MArray2<T> operator - (const MArray2<T>& a);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/MDiagArray2.cc
@@ -0,0 +1,146 @@
+// MArray.cc                                             -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MDiagArray2.h"
+#include "lo-error.h"
+
+#include "MArray-defs.h"
+
+// Two dimensional diagonal array with math ops.
+
+// Element by element MDiagArray2 by MDiagArray2 ops.
+
+template <class T>
+MDiagArray2<T>&
+operator += (MDiagArray2<T>& a, const MDiagArray2<T>& b)
+{
+  int r = a.rows ();
+  int c = a.cols ();
+  if (r != b.rows () || c != b.cols ())
+    {
+      (*current_liboctave_error_handler)
+	("nonconformant array operator += attempted");
+      return MDiagArray2<T> ();
+    }
+  else
+    {
+      int l = a.length ();
+      DO_VV_OP2 (+=);
+    }
+  return a;
+}
+
+template <class T>
+MDiagArray2<T>&
+operator -= (MDiagArray2<T>& a, const MDiagArray2<T>& b)
+{
+  int r = a.rows ();
+  int c = a.cols ();
+  if (r != b.rows () || c != b.cols ())
+    {
+      (*current_liboctave_error_handler)
+	("nonconformant array operator -= attempted");
+      return MDiagArray2<T> ();
+    }
+  else
+    {
+      int l = a.length ();
+      DO_VV_OP2 (-=);
+    }
+  return a;
+}
+
+// Element by element MDiagArray2 by scalar ops.
+
+#define MARRAY_DAS_OP(OP) \
+  template <class T> \
+  MDiagArray2<T> \
+  operator OP (const MDiagArray2<T>& a, const T& s) \
+  { \
+    DO_VS_OP (OP); \
+    return MDiagArray2<T> (result, a.rows (), a.cols ()); \
+  }
+
+MARRAY_DAS_OP (*)
+MARRAY_DAS_OP (/)
+
+// Element by element scalar by MDiagArray2 ops.
+
+template <class T>
+MDiagArray2<T>
+operator * (const T& s, const MDiagArray2<T>& a)
+{
+  DO_SV_OP (*);
+  return MDiagArray2<T> (result, a.rows (), a.cols ());
+}
+
+// Element by element MDiagArray2 by MDiagArray2 ops.
+
+#define MARRAY_DADA_OP(FCN, OP, OP_STR) \
+  template <class T> \
+  MDiagArray2<T> \
+  FCN (const MDiagArray2<T>& a, const MDiagArray2<T>& b) \
+  { \
+    int r = a.rows (); \
+    int c = a.cols (); \
+    if (r != b.rows () || c != b.cols ()) \
+      { \
+	(*current_liboctave_error_handler) \
+	  ("nonconformant diagonal array " OP_STR " attempted"); \
+	return MDiagArray2<T> (); \
+      } \
+    if (c == 0 || r == 0) \
+      return MDiagArray2<T> (); \
+    int l = a.length (); \
+    DO_VV_OP (OP); \
+    return MDiagArray2<T> (result, r, c); \
+  }
+
+MARRAY_DADA_OP (operator +, +, "addition")
+MARRAY_DADA_OP (operator -, -, "subtraction")
+MARRAY_DADA_OP (product,    *, "product")
+
+// Unary MDiagArray2 ops.
+
+template <class T>
+MDiagArray2<T>
+operator - (const MDiagArray2<T>& a)
+{
+  NEG_V;
+  return MDiagArray2<T> (result, a.rows (), a.cols ());
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/liboctave/MDiagArray2.h
@@ -0,0 +1,120 @@
+// Template array classes with like-type math ops          -*- C++ -*-
+/*
+
+Copyright (C) 1996 John W. Eaton
+
+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 2, 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, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#if !defined (octave_MDiagArray2_h)
+#define octave_MDiagArray2_h 1
+
+#include "DiagArray2.h"
+#include "MArray2.h"
+
+// Two dimensional diagonal array with math ops.
+
+template <class T>
+class MDiagArray2 : public DiagArray2<T>
+{
+protected:
+
+  MDiagArray2 (T *d, int r, int c) : DiagArray2<T> (d, r, c) { }
+
+public:
+  
+  MDiagArray2 (void) : DiagArray2<T> () { }
+  MDiagArray2 (int r, int c) : DiagArray2<T> (r, c) { }
+  MDiagArray2 (int r, int c, const T& val) : DiagArray2<T> (r, c, val) { }
+  MDiagArray2 (const Array<T>& a) : DiagArray2<T> (a) { }
+  MDiagArray2 (const MArray<T>& a) : DiagArray2<T> (a) { }
+  MDiagArray2 (const DiagArray2<T>& a) : DiagArray2<T> (a) { }
+  MDiagArray2 (const MDiagArray2<T>& a) : DiagArray2<T> (a) { }
+
+  ~MDiagArray2 (void) { }
+
+  MDiagArray2<T>& operator = (const MDiagArray2<T>& a)
+    {
+      DiagArray2<T>::operator = (a);
+      return *this;
+    }
+
+  operator MArray2<T> () const
+    {
+      MArray2<T> retval (nr, nc,  T (0));
+
+      int len = nr < nc ? nr : nc;
+
+      for (int i = 0; i < len; i++)
+	retval.xelem (i, i) = xelem (i, i);
+
+      return retval;
+    }
+
+  // element by element MDiagArray2 by MDiagArray2 ops
+
+  friend MDiagArray2<T>&
+  operator += (MDiagArray2<T>& a, const MDiagArray2<T>& b);
+
+  friend MDiagArray2<T>&
+  operator -= (MDiagArray2<T>& a, const MDiagArray2<T>& b);
+
+  // element by element MDiagArray2 by scalar ops
+
+  friend MDiagArray2<T> operator * (const MDiagArray2<T>& a, const T& s);
+  friend MDiagArray2<T> operator / (const MDiagArray2<T>& a, const T& s);
+
+  // element by element scalar by MDiagArray2 ops
+
+  friend MDiagArray2<T> operator * (const T& s, const MDiagArray2<T>& a);
+
+  // element by element MDiagArray2 by MDiagArray2 ops
+
+  friend MDiagArray2<T>
+  operator + (const MDiagArray2<T>& a, const MDiagArray2<T>& b); 
+
+  friend MDiagArray2<T>
+  operator - (const MDiagArray2<T>& a, const MDiagArray2<T>& b);
+
+  friend MDiagArray2<T>
+  product (const MDiagArray2<T>& a, const MDiagArray2<T>& b);
+
+  friend MDiagArray2<T> operator - (const MDiagArray2<T>& a);
+};
+
+#define INSTANTIATE_MDIAGARRAY_FRIENDS(T) \
+  template MDiagArray2<T> operator * (const MDiagArray2<T>& a, const T& s); \
+  template MDiagArray2<T> operator / (const MDiagArray2<T>& a, const T& s); \
+  template MDiagArray2<T> operator * (const T& s, const MDiagArray2<T>& a); \
+  template MDiagArray2<T> operator + (const MDiagArray2<T>& a, const MDiagArray2<T>& b); \
+  template MDiagArray2<T> operator - (const MDiagArray2<T>& a, const MDiagArray2<T>& b); \
+  template MDiagArray2<T> product (const MDiagArray2<T>& a, const MDiagArray2<T>& b); \
+  template MDiagArray2<T> operator - (const MDiagArray2<T>& a);
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; page-delimiter: "^/\\*" ***
+;;; End: ***
+*/