ov-base-diag.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2008-2012 Jaroslav Hajek
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <iostream>
00028 
00029 #include "mach-info.h"
00030 #include "lo-ieee.h"
00031 
00032 #include "ov-base.h"
00033 #include "ov-base-mat.h"
00034 #include "pr-output.h"
00035 #include "error.h"
00036 #include "gripes.h"
00037 #include "oct-stream.h"
00038 #include "ops.h"
00039 
00040 #include "ls-oct-ascii.h"
00041 
00042 template <class DMT, class MT>
00043 octave_value
00044 octave_base_diag<DMT, MT>::subsref (const std::string& type,
00045                                     const std::list<octave_value_list>& idx)
00046 {
00047   octave_value retval;
00048 
00049   switch (type[0])
00050     {
00051     case '(':
00052       retval = do_index_op (idx.front ());
00053       break;
00054 
00055     case '{':
00056     case '.':
00057       {
00058         std::string nm = type_name ();
00059         error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
00060       }
00061       break;
00062 
00063     default:
00064       panic_impossible ();
00065     }
00066 
00067   return retval.next_subsref (type, idx);
00068 }
00069 
00070 
00071 template <class DMT, class MT>
00072 octave_value
00073 octave_base_diag<DMT,MT>::diag (octave_idx_type k) const
00074 {
00075   octave_value retval;
00076   if (matrix.rows () == 1 || matrix.cols () == 1)
00077     {
00078       // Rather odd special case. This is a row or column vector
00079       // represented as a diagonal matrix with a single nonzero entry, but
00080       // Fdiag semantics are to product a diagonal matrix for vector
00081       // inputs.
00082       if (k == 0)
00083         // Returns Diag2Array<T> with nnz <= 1.
00084         retval = matrix.build_diag_matrix ();
00085       else
00086         // Returns Array<T> matrix
00087         retval = matrix.array_value ().diag (k);
00088     }
00089   else
00090     // Returns Array<T> vector
00091     retval = matrix.extract_diag (k);
00092   return retval;
00093 }
00094 
00095 
00096 template <class DMT, class MT>
00097 octave_value
00098 octave_base_diag<DMT, MT>::do_index_op (const octave_value_list& idx,
00099                                         bool resize_ok)
00100 {
00101   octave_value retval;
00102   typedef typename DMT::element_type el_type;
00103 
00104   if (idx.length () == 2 && ! resize_ok)
00105     {
00106       idx_vector idx0 = idx(0).index_vector ();
00107       idx_vector idx1 = idx(1).index_vector ();
00108 
00109       if (idx0.is_scalar () && idx1.is_scalar ())
00110         {
00111           retval = matrix.elem (idx0(0), idx1(0));
00112         }
00113       else
00114         {
00115           octave_idx_type m = idx0.length (matrix.rows ());
00116           octave_idx_type n = idx1.length (matrix.columns ());
00117           if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n)
00118               && m <= matrix.rows () && n <= matrix.rows ())
00119             {
00120               DMT rm (matrix);
00121               rm.resize (m, n);
00122               retval = rm;
00123             }
00124           else
00125             retval = to_dense ().do_index_op (idx, resize_ok);
00126         }
00127     }
00128   else
00129     retval = to_dense ().do_index_op (idx, resize_ok);
00130 
00131   return retval;
00132 }
00133 
00134 template <class DMT, class MT>
00135 octave_value
00136 octave_base_diag<DMT, MT>::subsasgn (const std::string& type,
00137                                      const std::list<octave_value_list>& idx,
00138                                      const octave_value& rhs)
00139 {
00140   octave_value retval;
00141 
00142   switch (type[0])
00143     {
00144     case '(':
00145       {
00146         if (type.length () == 1)
00147           {
00148             octave_value_list jdx = idx.front ();
00149             // Check for a simple element assignment. That means, if D is a diagonal matrix,
00150             // 'D(i,i) = x' will not destroy its diagonality (provided i is a valid index).
00151             if (jdx.length () == 2 && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ())
00152               {
00153                 typename DMT::element_type val;
00154                 idx_vector i0 = jdx(0).index_vector (), i1 = jdx(1).index_vector ();
00155                 if (! error_state  && i0(0) == i1(0)
00156                     && i0(0) < matrix.rows () && i1(0) < matrix.cols ()
00157                     && chk_valid_scalar (rhs, val))
00158                   {
00159                     matrix.dgelem (i0(0)) = val;
00160                     retval = this;
00161                     this->count++;
00162                     // invalidate cache
00163                     dense_cache = octave_value ();
00164                   }
00165               }
00166 
00167             if (! error_state && ! retval.is_defined ())
00168               retval = numeric_assign (type, idx, rhs);
00169           }
00170         else
00171           {
00172             std::string nm = type_name ();
00173             error ("in indexed assignment of %s, last lhs index must be ()",
00174                    nm.c_str ());
00175           }
00176       }
00177       break;
00178 
00179     case '{':
00180     case '.':
00181       {
00182         if (is_empty ())
00183           {
00184             octave_value tmp = octave_value::empty_conv (type, rhs);
00185 
00186             retval = tmp.subsasgn (type, idx, rhs);
00187           }
00188         else
00189           {
00190             std::string nm = type_name ();
00191             error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
00192           }
00193       }
00194       break;
00195 
00196     default:
00197       panic_impossible ();
00198     }
00199 
00200   return retval;
00201 }
00202 
00203 template <class DMT, class MT>
00204 octave_value
00205 octave_base_diag<DMT, MT>::resize (const dim_vector& dv, bool fill) const
00206 {
00207   octave_value retval;
00208   if (dv.length () == 2)
00209     {
00210       DMT rm (matrix);
00211       rm.resize (dv(0), dv(1));
00212       retval = rm;
00213     }
00214   else
00215     retval = to_dense ().resize (dv, fill);
00216   return retval;
00217 }
00218 
00219 template <class DMT, class MT>
00220 bool
00221 octave_base_diag<DMT, MT>::is_true (void) const
00222 {
00223   return to_dense ().is_true ();
00224 }
00225 
00226 // FIXME: this should be achieveable using ::real
00227 template <class T> inline T helper_getreal (T x) { return x; }
00228 template <class T> inline T helper_getreal (std::complex<T> x) { return x.real (); }
00229 // FIXME: we really need some traits so that ad hoc hooks like this are not necessary
00230 template <class T> inline T helper_iscomplex (T) { return false; }
00231 template <class T> inline T helper_iscomplex (std::complex<T>) { return true; }
00232 
00233 template <class DMT, class MT>
00234 double
00235 octave_base_diag<DMT, MT>::double_value (bool force_conversion) const
00236 {
00237   double retval = lo_ieee_nan_value ();
00238   typedef typename DMT::element_type el_type;
00239 
00240   if (helper_iscomplex (el_type ()) && ! force_conversion)
00241     gripe_implicit_conversion ("Octave:imag-to-real",
00242                                "complex matrix", "real scalar");
00243 
00244   if (numel () > 0)
00245     {
00246       gripe_implicit_conversion ("Octave:array-as-scalar",
00247                                  type_name (), "real scalar");
00248 
00249       retval = helper_getreal (el_type (matrix (0, 0)));
00250     }
00251   else
00252     gripe_invalid_conversion (type_name (), "real scalar");
00253 
00254   return retval;
00255 }
00256 
00257 template <class DMT, class MT>
00258 float
00259 octave_base_diag<DMT, MT>::float_value (bool force_conversion) const
00260 {
00261   float retval = lo_ieee_float_nan_value ();
00262   typedef typename DMT::element_type el_type;
00263 
00264   if (helper_iscomplex (el_type ()) && ! force_conversion)
00265     gripe_implicit_conversion ("Octave:imag-to-real",
00266                                "complex matrix", "real scalar");
00267 
00268   if (numel () > 0)
00269     {
00270       gripe_implicit_conversion ("Octave:array-as-scalar",
00271                                  type_name (), "real scalar");
00272 
00273       retval = helper_getreal (el_type (matrix (0, 0)));
00274     }
00275   else
00276     gripe_invalid_conversion (type_name (), "real scalar");
00277 
00278   return retval;
00279 }
00280 
00281 template <class DMT, class MT>
00282 Complex
00283 octave_base_diag<DMT, MT>::complex_value (bool) const
00284 {
00285   double tmp = lo_ieee_nan_value ();
00286 
00287   Complex retval (tmp, tmp);
00288 
00289   if (rows () > 0 && columns () > 0)
00290     {
00291       gripe_implicit_conversion ("Octave:array-as-scalar",
00292                                  type_name (), "complex scalar");
00293 
00294       retval = matrix (0, 0);
00295     }
00296   else
00297     gripe_invalid_conversion (type_name (), "complex scalar");
00298 
00299   return retval;
00300 }
00301 
00302 template <class DMT, class MT>
00303 FloatComplex
00304 octave_base_diag<DMT, MT>::float_complex_value (bool) const
00305 {
00306   float tmp = lo_ieee_float_nan_value ();
00307 
00308   FloatComplex retval (tmp, tmp);
00309 
00310   if (rows () > 0 && columns () > 0)
00311     {
00312       gripe_implicit_conversion ("Octave:array-as-scalar",
00313                                  type_name (), "complex scalar");
00314 
00315       retval = matrix (0, 0);
00316     }
00317   else
00318     gripe_invalid_conversion (type_name (), "complex scalar");
00319 
00320   return retval;
00321 }
00322 
00323 template <class DMT, class MT>
00324 Matrix
00325 octave_base_diag<DMT, MT>::matrix_value (bool) const
00326 {
00327   return Matrix (diag_matrix_value ());
00328 }
00329 
00330 template <class DMT, class MT>
00331 FloatMatrix
00332 octave_base_diag<DMT, MT>::float_matrix_value (bool) const
00333 {
00334   return FloatMatrix (float_diag_matrix_value ());
00335 }
00336 
00337 template <class DMT, class MT>
00338 ComplexMatrix
00339 octave_base_diag<DMT, MT>::complex_matrix_value (bool) const
00340 {
00341   return ComplexMatrix (complex_diag_matrix_value ());
00342 }
00343 
00344 template <class DMT, class MT>
00345 FloatComplexMatrix
00346 octave_base_diag<DMT, MT>::float_complex_matrix_value (bool) const
00347 {
00348   return FloatComplexMatrix (float_complex_diag_matrix_value ());
00349 }
00350 
00351 template <class DMT, class MT>
00352 NDArray
00353 octave_base_diag<DMT, MT>::array_value (bool) const
00354 {
00355   return NDArray (matrix_value ());
00356 }
00357 
00358 template <class DMT, class MT>
00359 FloatNDArray
00360 octave_base_diag<DMT, MT>::float_array_value (bool) const
00361 {
00362   return FloatNDArray (float_matrix_value ());
00363 }
00364 
00365 template <class DMT, class MT>
00366 ComplexNDArray
00367 octave_base_diag<DMT, MT>::complex_array_value (bool) const
00368 {
00369   return ComplexNDArray (complex_matrix_value ());
00370 }
00371 
00372 template <class DMT, class MT>
00373 FloatComplexNDArray
00374 octave_base_diag<DMT, MT>::float_complex_array_value (bool) const
00375 {
00376   return FloatComplexNDArray (float_complex_matrix_value ());
00377 }
00378 
00379 template <class DMT, class MT>
00380 boolNDArray
00381 octave_base_diag<DMT, MT>::bool_array_value (bool warn) const
00382 {
00383   return to_dense ().bool_array_value (warn);
00384 }
00385 
00386 template <class DMT, class MT>
00387 charNDArray
00388 octave_base_diag<DMT, MT>::char_array_value (bool warn) const
00389 {
00390   return to_dense ().char_array_value (warn);
00391 }
00392 
00393 template <class DMT, class MT>
00394 SparseMatrix
00395 octave_base_diag<DMT, MT>::sparse_matrix_value (bool) const
00396 {
00397   return SparseMatrix (diag_matrix_value ());
00398 }
00399 
00400 template <class DMT, class MT>
00401 SparseComplexMatrix
00402 octave_base_diag<DMT, MT>::sparse_complex_matrix_value (bool) const
00403 {
00404   return SparseComplexMatrix (complex_diag_matrix_value ());
00405 }
00406 
00407 template <class DMT, class MT>
00408 idx_vector
00409 octave_base_diag<DMT, MT>::index_vector (void) const
00410 {
00411   return to_dense ().index_vector ();
00412 }
00413 
00414 template <class DMT, class MT>
00415 octave_value
00416 octave_base_diag<DMT, MT>::convert_to_str_internal (bool pad, bool force, char type) const
00417 {
00418   return to_dense ().convert_to_str_internal (pad, force, type);
00419 }
00420 
00421 template <class DMT, class MT>
00422 bool
00423 octave_base_diag<DMT, MT>::save_ascii (std::ostream& os)
00424 {
00425   os << "# rows: " << matrix.rows () << "\n"
00426     << "# columns: " << matrix.columns () << "\n";
00427 
00428   os << matrix.diag ();
00429 
00430   return true;
00431 }
00432 
00433 template <class DMT, class MT>
00434 bool
00435 octave_base_diag<DMT, MT>::load_ascii (std::istream& is)
00436 {
00437   octave_idx_type r = 0, c = 0;
00438   bool success = true;
00439 
00440   if (extract_keyword (is, "rows", r, true)
00441       && extract_keyword (is, "columns", c, true))
00442     {
00443       octave_idx_type l = r < c ? r : c;
00444       MT tmp (l, 1);
00445       is >> tmp;
00446 
00447       if (!is)
00448         {
00449           error ("load: failed to load diagonal matrix constant");
00450           success = false;
00451         }
00452       else
00453         {
00454           // This is a little tricky, as we have the Matrix type, but
00455           // not ColumnVector type. We need to help the compiler get
00456           // through the inheritance tree.
00457           typedef typename DMT::element_type el_type;
00458           matrix = DMT (MDiagArray2<el_type> (MArray<el_type> (tmp)));
00459           matrix.resize (r, c);
00460 
00461           // Invalidate cache. Probably not necessary, but safe.
00462           dense_cache = octave_value ();
00463         }
00464     }
00465   else
00466     {
00467       error ("load: failed to extract number of rows and columns");
00468       success = false;
00469     }
00470 
00471   return success;
00472 }
00473 
00474 template <class DMT, class MT>
00475 void
00476 octave_base_diag<DMT, MT>::print_raw (std::ostream& os,
00477                                       bool pr_as_read_syntax) const
00478 {
00479   return octave_print_internal (os, matrix, pr_as_read_syntax,
00480                                 current_print_indent_level ());
00481 }
00482 
00483 template <class DMT, class MT>
00484 mxArray *
00485 octave_base_diag<DMT, MT>::as_mxArray (void) const
00486 {
00487   return to_dense ().as_mxArray ();
00488 }
00489 
00490 template <class DMT, class MT>
00491 bool
00492 octave_base_diag<DMT, MT>::print_as_scalar (void) const
00493 {
00494   dim_vector dv = dims ();
00495 
00496   return (dv.all_ones () || dv.any_zero ());
00497 }
00498 
00499 template <class DMT, class MT>
00500 void
00501 octave_base_diag<DMT, MT>::print (std::ostream& os, bool pr_as_read_syntax) const
00502 {
00503   print_raw (os, pr_as_read_syntax);
00504   newline (os);
00505 }
00506 template <class DMT, class MT>
00507 int
00508 octave_base_diag<DMT, MT>::write (octave_stream& os, int block_size,
00509                                   oct_data_conv::data_type output_type, int skip,
00510                                   oct_mach_info::float_format flt_fmt) const
00511 {
00512   return to_dense ().write (os, block_size, output_type, skip, flt_fmt);
00513 }
00514 
00515 template <class DMT, class MT>
00516 void
00517 octave_base_diag<DMT, MT>::print_info (std::ostream& os,
00518                                        const std::string& prefix) const
00519 {
00520   matrix.print_info (os, prefix);
00521 }
00522 
00523 template <class DMT, class MT>
00524 octave_value
00525 octave_base_diag<DMT, MT>::to_dense (void) const
00526 {
00527   if (! dense_cache.is_defined ())
00528     dense_cache = MT (matrix);
00529 
00530   return dense_cache;
00531 }
00532 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines