// Template array classes /* Copyright (C) 1996, 1997 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 Array2 Array2::value (void) { Array2 retval; int n_idx = index_count (); if (n_idx == 2) { idx_vector *tmp = get_idx (); idx_vector idx_i = tmp[0]; idx_vector idx_j = tmp[1]; return index (idx_i, idx_j); } else if (n_idx == 1) { idx_vector *tmp = get_idx (); idx_vector idx = tmp[0]; return index (idx); } else (*current_liboctave_error_handler) ("invalid number of indices for matrix expression"); clear_index (); return retval; } template Array2 Array2::index (idx_vector& idx) const { Array2 retval; int nr = d1; int nc = d2; if (nr == 1 && nc == 1) { Array tmp = Array::index (idx); int len = tmp.length (); if (len == 0) retval = Array2 (0, 0); else { if (liboctave_pcv_flag) retval = Array2 (tmp, len, 1); else retval = Array2 (tmp, 1, len); } } else if (nr == 1 || nc == 1) { int result_is_column_vector = (nc == 1 || idx.is_colon ()); Array tmp = Array::index (idx); int len = tmp.length (); if (len == 0) retval = Array2 (0, 0); else { if (result_is_column_vector) retval = Array2 (tmp, len, 1); else retval = Array2 (tmp, 1, len); } } else if (liboctave_dfi_flag || idx.is_colon ()) { // This code is only for indexing matrices. The vector // cases are handled above. idx.freeze (nr * nc, "matrix"); if (idx) { int result_nr = idx.orig_rows (); int result_nc = idx.orig_columns (); if (idx.is_colon ()) { result_nr = nr * nc; result_nc = result_nr ? 1 : 0; } 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"); return retval; } template Array2 Array2::index (idx_vector& idx_i, idx_vector& idx_j) const { Array2 retval; int nr = d1; int nc = d2; int n = idx_i.freeze (nr, "row"); int m = idx_j.freeze (nc, "column"); if (idx_i && idx_j) { if (idx_i.orig_empty () || idx_j.orig_empty ()) { retval.resize (n, m); } else if (n == 0) { if (m == 0) retval.resize (0, 0); else if (idx_j.is_colon_equiv (nc, 1)) retval.resize (0, nc); else if (idx_i.is_colon_equiv (nr, 1)) retval.resize (0, m); else (*current_liboctave_error_handler) ("invalid row index = 0"); } else if (m == 0) { if (n == 0) retval.resize (0, 0); else if (idx_i.is_colon_equiv (nr, 1)) retval.resize (nr, 0); else if (idx_j.is_colon_equiv (nc, 1)) retval.resize (n, 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. return retval; } template void Array2::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 { idx_j.sort (true); 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; int idx = 0; for (int j = 0; j < nc; j++) if (j == idx_j.elem (idx)) { idx++; new_nc--; if (idx == num_to_delete) break; } if (new_nc > 0) { T *new_data = new T [nr * new_nc]; int jj = 0; idx = 0; for (int j = 0; j < nc; j++) { if (idx < num_to_delete && 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 (nc, 1)) { if (idx_i.is_colon_equiv (nr, 1)) resize (0, 0); else { idx_i.sort (true); 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; int idx = 0; for (int i = 0; i < nr; i++) if (i == idx_i.elem (idx)) { idx++; new_nr--; if (idx == num_to_delete) break; } if (new_nr > 0) { T *new_data = new T [new_nr * nc]; int ii = 0; idx = 0; for (int i = 0; i < nr; i++) { if (idx < num_to_delete && 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"); } } } } } #define MAYBE_RESIZE_LHS \ do \ { \ 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); \ } \ } \ while (0) template int assign (Array2& lhs, const Array2& 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_rre_flag); int m = idx_j.freeze (lhs_nc, "column", 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 = lhs_nr > 0 ? lhs_nr : rhs_nr; if (idx_j_is_colon) m = lhs_nc > 0 ? lhs_nc : rhs_nc; if (idx_i && idx_j) { if (rhs_nr == 0 && rhs_nc == 0) { lhs.maybe_delete_elements (idx_i, idx_j); } else { if (rhs_nr == 1 && rhs_nc == 1 && n > 0 && m > 0) { MAYBE_RESIZE_LHS; 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 if (n == rhs_nr && m == rhs_nc) { MAYBE_RESIZE_LHS; 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 (n == 0 && m == 0) { if (! ((rhs_nr == 1 && rhs_nc == 1) || (rhs_nr == 0 && rhs_nc == 0))) { (*current_liboctave_error_handler) ("A([], []) = X: X must be an empty matrix or a scalar"); retval = 0; } } 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) { int lhs_is_empty = lhs_nr == 0 || lhs_nc == 0; if (lhs_is_empty || (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_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 (! liboctave_dfi_flag && lhs_is_empty && idx.is_colon () && ! (rhs_nr == 1 || rhs_nc == 1)) { (*current_liboctave_error_handler) ("A(:) = X: X must be a vector"); } else { if (assign ((Array&) lhs, (Array&) rhs)) { int len = lhs.length (); if (len > 0) { int idx_nr = idx.orig_rows (); int idx_nc = idx.orig_columns (); // lhs_is_empty now means that lhs was // *originally* empty, and lhs_len is the // *original* length of the lhs. if (liboctave_dfi_flag || (idx_nr == 1 && idx_nc == 1) || (rhs_nr == 1 && rhs_nc == 1 && lhs_len == 1)) { if (liboctave_pcv_flag) { lhs.d1 = lhs.length (); lhs.d2 = 1; } else { lhs.d1 = 1; lhs.d2 = lhs.length (); } } else if (lhs_is_empty && idx.is_colon ()) { lhs.d1 = rhs.d1; lhs.d2 = rhs.d2; } else if (rhs_nr == 1 && (idx_nr == 1 || lhs_len == 1)) { lhs.d1 = 1; lhs.d2 = lhs.length (); } else if (rhs_nc == 1 && (idx_nc == 1 || lhs_len == 1)) { lhs.d1 = lhs.length (); lhs.d2 = 1; } else if (idx_nr == 0 && idx_nc == 0) { if (! ((rhs.d1 == 1 && rhs.d2 == 1) || (rhs.d1 == 0 && rhs.d2 == 0))) (*current_liboctave_error_handler) ("A([]) = X: X must be an empty matrix or scalar"); } 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_rre_flag); if (idx) { if (rhs_nr == 0 && rhs_nc == 0) { idx_vector tmp (':'); lhs.maybe_delete_elements (tmp, idx); } else { if (assign ((Array&) lhs, (Array&) 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_rre_flag); if (idx) { if (rhs_nr == 0 && rhs_nc == 0) { idx_vector tmp (':'); lhs.maybe_delete_elements (idx, tmp); } else { if (assign ((Array&) lhs, (Array&) 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"); if (idx) { if (len == 0) { if (! ((rhs_nr == 1 && rhs_nc == 1) || (rhs_nr == 0 && rhs_nc == 0))) (*current_liboctave_error_handler) ("A([]) = X: X must be an empty matrix or scalar"); } else 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 if (rhs_nr == 1 && rhs_nc == 1 && len <= lhs_nr * lhs_nc) { RT scalar = rhs.elem (0, 0); for (int i = 0; i < len; i++) { int ii = idx.elem (i); int fr = ii % lhs_nr; int fc = (ii - fr) / lhs_nr; lhs.elem (fr, fc) = scalar; } } 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++ *** ;;; End: *** */