Mercurial > hg > octave-avbm
view src/pt-mat.cc @ 1742:a02f140ed897
[project @ 1996-01-12 11:09:39 by jwe]
author | jwe |
---|---|
date | Fri, 12 Jan 1996 11:21:53 +0000 |
parents | 6ec1465f60f0 |
children | effa9400766f |
line wrap: on
line source
// pt-mat.cc -*- C++ -*- /* Copyright (C) 1992, 1993, 1994, 1995 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 <iostream.h> #include <strstream.h> #include "error.h" #include "oct-obj.h" #include "pt-const.h" #include "pt-exp.h" #include "pt-fvc.h" #include "pt-mat.h" #include "pt-misc.h" #include "pt-mvr.h" #include "user-prefs.h" // General matrices. This list type is much more work to handle than // constant matrices, but it allows us to construct matrices from // other matrices, variables, and functions. tree_matrix::~tree_matrix (void) { delete element; delete next; } int tree_matrix::is_matrix_constant (void) const { const tree_matrix *list = this; while (list) { tree_expression *elem = list->element; if (! elem->is_constant ()) return 0; list = list->next; } return 1; } tree_matrix * tree_matrix::chain (tree_expression *t, tree_matrix::dir d) { tree_matrix *tmp = new tree_matrix (t, d); tmp->next = this; return tmp; } tree_matrix * tree_matrix::reverse (void) { tree_matrix *list = this; tree_matrix *next; tree_matrix *prev = 0; while (list) { next = list->next; list->next = prev; prev = list; list = next; } return prev; } int tree_matrix::length (void) { tree_matrix *list = this; int len = 0; while (list) { len++; list = list->next; } return len; } tree_return_list * tree_matrix::to_return_list (void) { tree_return_list *retval = 0; tree_matrix *list; for (list = this; list; list = list->next) { tree_expression *elem = list->element; int is_id = elem->is_identifier (); int is_idx_expr = elem->is_index_expression (); if (is_id || is_idx_expr) { tree_index_expression *idx_expr; if (is_id) { tree_identifier *id = (tree_identifier *) elem; idx_expr = new tree_index_expression (id); } else idx_expr = (tree_index_expression *) elem; if (list == this) retval = new tree_return_list (idx_expr); else retval->append (idx_expr); } else { delete retval; retval = 0; break; } } return retval; } // Just about as ugly as it gets. struct const_matrix_list { tree_matrix::dir direction; tree_constant elem; int nr; int nc; }; // Less ugly than before, anyway. tree_constant tree_matrix::eval (int /* print */) { tree_constant retval; if (error_state) return retval; // Just count the elements without looking at them. int total_len = length (); // Easier to deal with this later instead of a tree_matrix // structure. const_matrix_list *list = new const_matrix_list [total_len]; // Stats we want to keep track of. int all_strings = 1; int found_complex = 0; int row_total = 0; int col_total = 0; int row_height = 0; int cols_this_row = 0; int first_row = 1; int empties_ok = user_pref.empty_list_elements_ok; tree_matrix *ptr = this; // Stuff for the result matrix or string. Declared here so that we // don't get warnings from gcc about the goto crossing the // initialization of these values. int put_row = 0; int put_col = 0; int prev_nr = 0; int prev_nc = 0; Matrix m; ComplexMatrix cm; charMatrix chm; // Eliminate empties and gather stats. int found_new_row_in_empties = 0; int len = 0; for (int i = 0; i < total_len; i++) { tree_expression *elem = ptr->element; if (! elem) { retval = tree_constant (Matrix ()); goto done; } tree_constant tmp = elem->eval (0); if (error_state || tmp.is_undefined ()) { retval = tree_constant (); goto done; } int nr = tmp.rows (); int nc = tmp.columns (); dir direct = ptr->direction; if (nr == 0 || nc == 0) { if (empties_ok < 0) warning ("empty matrix found in matrix list"); else if (empties_ok == 0) { ::error ("empty matrix found in matrix list"); retval = tree_constant (); goto done; } if (direct == md_down) found_new_row_in_empties = 1; goto next; } if (found_new_row_in_empties) { found_new_row_in_empties = 0; list[len].direction = md_down; } else list[len].direction = direct; list[len].elem = tmp; list[len].nr = nr; list[len].nc = nc; if (all_strings && ! tmp.is_string ()) all_strings = 0; if (! found_complex && tmp.is_complex_type ()) found_complex = 1; len++; next: ptr = ptr->next; } // if (all_strings) // cerr << "all strings\n"; // Compute size of result matrix, and check to see that the dimensions // of all the elements will match up properly. for (int i = 0; i < len; i++) { dir direct = list[i].direction; int nr = list[i].nr; int nc = list[i].nc; if (i == 0) { row_total = nr; col_total = nc; row_height = nr; cols_this_row = nc; } else { switch (direct) { case md_right: { if (nr != row_height) { ::error ("number of rows must match"); goto done; } else { cols_this_row += nc; if (first_row) col_total = cols_this_row; else if (all_strings && cols_this_row > col_total) col_total = cols_this_row; } } break; case md_down: { if (cols_this_row != col_total && ! all_strings) { ::error ("number of columns must match"); goto done; } first_row = 0; row_total += nr; row_height = nr; cols_this_row = nc; } break; default: panic_impossible (); break; } } } // Don't forget to check to see if the last element will fit. if (all_strings && cols_this_row > col_total) { col_total = cols_this_row; } else if (cols_this_row != col_total) { ::error ("number of columns must match"); goto done; } // Now, extract the values from the individual elements and insert // them in the result matrix. if (all_strings) chm.resize (row_total, col_total, 0); else if (found_complex) cm.resize (row_total, col_total, 0.0); else m.resize (row_total, col_total, 0.0); for (int i = 0; i < len; i++) { tree_constant tmp = list[i].elem; int nr = list[i].nr; int nc = list[i].nc; if (nr == 0 || nc == 0) continue; if (i == 0) { put_row = 0; put_col = 0; } else { switch (list[i].direction) { case md_right: put_col += prev_nc; break; case md_down: put_row += prev_nr; put_col = 0; break; default: panic_impossible (); break; } } if (found_complex) { if (tmp.is_real_scalar ()) { cm (put_row, put_col) = tmp.double_value (); } else if (tmp.is_real_matrix () || tmp.is_range ()) { cm.insert (tmp.matrix_value (), put_row, put_col); } else if (tmp.is_complex_scalar ()) { cm (put_row, put_col) = tmp.complex_value (); } else { ComplexMatrix cm_tmp = tmp.complex_matrix_value (); if (error_state) goto done; cm.insert (cm_tmp, put_row, put_col); } } else { if (tmp.is_real_scalar ()) { m (put_row, put_col) = tmp.double_value (); } else if (tmp.is_string () && all_strings) { charMatrix chm_tmp = tmp.all_strings (); if (error_state) goto done; chm.insert (chm_tmp, put_row, put_col); } else { Matrix m_tmp = tmp.matrix_value (); if (error_state) goto done; m.insert (m_tmp, put_row, put_col); } } prev_nr = nr; prev_nc = nc; } if (all_strings && chm.rows () > 0 && chm.cols () > 0) retval = tree_constant (chm, 1); else if (found_complex) retval = cm; else retval = m; done: delete [] list; return retval; } void tree_matrix::print_code (ostream& os) { print_code_indent (os); if (in_parens) os << "("; os << "["; tree_matrix *list = this; while (list) { list->element->print_code (os); list = list->next; if (list) { switch (list->direction) { case md_right: os << ", "; break; case md_down: os << "; "; break; default: break; } } } os << "]"; if (in_parens) os << ")"; } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; page-delimiter: "^/\\*" *** ;;; End: *** */