ov-perm.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 "byte-swap.h"
00028 
00029 #include "ov-perm.h"
00030 #include "ov-re-mat.h"
00031 #include "ov-scalar.h"
00032 #include "error.h"
00033 #include "gripes.h"
00034 #include "ops.h"
00035 #include "pr-output.h"
00036 
00037 #include "ls-oct-ascii.h"
00038 
00039 octave_value
00040 octave_perm_matrix::subsref (const std::string& type,
00041                              const std::list<octave_value_list>& idx)
00042 {
00043   octave_value retval;
00044 
00045   switch (type[0])
00046     {
00047     case '(':
00048       retval = do_index_op (idx.front ());
00049       break;
00050 
00051     case '{':
00052     case '.':
00053       {
00054         std::string nm = type_name ();
00055         error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
00056       }
00057       break;
00058 
00059     default:
00060       panic_impossible ();
00061     }
00062 
00063   return retval.next_subsref (type, idx);
00064 }
00065 
00066 octave_value
00067 octave_perm_matrix::do_index_op (const octave_value_list& idx,
00068                                  bool resize_ok)
00069 {
00070   octave_value retval;
00071   octave_idx_type nidx = idx.length ();
00072   idx_vector idx0, idx1;
00073   if (nidx == 2)
00074     {
00075       idx0 = idx(0).index_vector ();
00076       idx1 = idx(1).index_vector ();
00077     }
00078 
00079   // This hack is to allow constructing permutation matrices using
00080   // eye(n)(p,:), eye(n)(:,q) && eye(n)(p,q) where p & q are permutation
00081   // vectors.
00082   // Note that, for better consistency, eye(n)(:,:) still converts to a full
00083   // matrix.
00084   if (! error_state && nidx == 2)
00085     {
00086       bool left = idx0.is_permutation (matrix.rows ());
00087       bool right = idx1.is_permutation (matrix.cols ());
00088 
00089       if (left && right)
00090         {
00091           if (idx0.is_colon ()) left = false;
00092           if (idx1.is_colon ()) right = false;
00093           if (left || right)
00094             {
00095               PermMatrix p = matrix;
00096               if (left)
00097                 p = PermMatrix (idx0, false) * p;
00098               if (right)
00099                 p = p * PermMatrix (idx1, true);
00100               retval = p;
00101             }
00102           else
00103             {
00104               retval = this;
00105               this->count++;
00106             }
00107         }
00108     }
00109 
00110   // if error_state is set, we've already griped.
00111   if (! error_state && ! retval.is_defined ())
00112     {
00113       if (nidx == 2 && ! resize_ok &&
00114           idx0.is_scalar () && idx1.is_scalar ())
00115         {
00116           retval = matrix.checkelem (idx0(0), idx1(0));
00117         }
00118       else
00119         retval = to_dense ().do_index_op (idx, resize_ok);
00120     }
00121 
00122   return retval;
00123 }
00124 
00125 bool
00126 octave_perm_matrix::is_true (void) const
00127 {
00128   return to_dense ().is_true ();
00129 }
00130 
00131 double
00132 octave_perm_matrix::double_value (bool) const
00133 {
00134   double retval = lo_ieee_nan_value ();
00135 
00136   if (numel () > 0)
00137     {
00138       gripe_implicit_conversion ("Octave:array-as-scalar",
00139                                  type_name (), "real scalar");
00140 
00141       retval = matrix (0, 0);
00142     }
00143   else
00144     gripe_invalid_conversion (type_name (), "real scalar");
00145 
00146   return retval;
00147 }
00148 
00149 float
00150 octave_perm_matrix::float_value (bool) const
00151 {
00152   float retval = lo_ieee_float_nan_value ();
00153 
00154   if (numel () > 0)
00155     {
00156       gripe_implicit_conversion ("Octave:array-as-scalar",
00157                                  type_name (), "real scalar");
00158 
00159       retval = matrix (0, 0);
00160     }
00161   else
00162     gripe_invalid_conversion (type_name (), "real scalar");
00163 
00164   return retval;
00165 }
00166 
00167 Complex
00168 octave_perm_matrix::complex_value (bool) const
00169 {
00170   double tmp = lo_ieee_nan_value ();
00171 
00172   Complex retval (tmp, tmp);
00173 
00174   if (rows () > 0 && columns () > 0)
00175     {
00176       gripe_implicit_conversion ("Octave:array-as-scalar",
00177                                  type_name (), "complex scalar");
00178 
00179       retval = matrix (0, 0);
00180     }
00181   else
00182     gripe_invalid_conversion (type_name (), "complex scalar");
00183 
00184   return retval;
00185 }
00186 
00187 FloatComplex
00188 octave_perm_matrix::float_complex_value (bool) const
00189 {
00190   float tmp = lo_ieee_float_nan_value ();
00191 
00192   FloatComplex retval (tmp, tmp);
00193 
00194   if (rows () > 0 && columns () > 0)
00195     {
00196       gripe_implicit_conversion ("Octave:array-as-scalar",
00197                                  type_name (), "complex scalar");
00198 
00199       retval = matrix (0, 0);
00200     }
00201   else
00202     gripe_invalid_conversion (type_name (), "complex scalar");
00203 
00204   return retval;
00205 }
00206 
00207 #define FORWARD_MATRIX_VALUE(TYPE, PREFIX) \
00208 TYPE \
00209 octave_perm_matrix::PREFIX ## _value (bool frc_str_conv) const \
00210 { \
00211   return to_dense ().PREFIX ## _value (frc_str_conv); \
00212 }
00213 
00214 SparseMatrix
00215 octave_perm_matrix::sparse_matrix_value (bool) const
00216 {
00217   return SparseMatrix (matrix);
00218 }
00219 
00220 SparseBoolMatrix
00221 octave_perm_matrix::sparse_bool_matrix_value (bool) const
00222 {
00223   return SparseBoolMatrix (matrix);
00224 }
00225 
00226 SparseComplexMatrix
00227 octave_perm_matrix::sparse_complex_matrix_value (bool) const
00228 {
00229   return SparseComplexMatrix (sparse_matrix_value ());
00230 }
00231 
00232 FORWARD_MATRIX_VALUE (Matrix, matrix)
00233 FORWARD_MATRIX_VALUE (FloatMatrix, float_matrix)
00234 FORWARD_MATRIX_VALUE (ComplexMatrix, complex_matrix)
00235 FORWARD_MATRIX_VALUE (FloatComplexMatrix, float_complex_matrix)
00236 
00237 FORWARD_MATRIX_VALUE (NDArray, array)
00238 FORWARD_MATRIX_VALUE (FloatNDArray, float_array)
00239 FORWARD_MATRIX_VALUE (ComplexNDArray, complex_array)
00240 FORWARD_MATRIX_VALUE (FloatComplexNDArray, float_complex_array)
00241 
00242 FORWARD_MATRIX_VALUE (boolNDArray, bool_array)
00243 FORWARD_MATRIX_VALUE (charNDArray, char_array)
00244 
00245 idx_vector
00246 octave_perm_matrix::index_vector (void) const
00247 {
00248   return to_dense ().index_vector ();
00249 }
00250 
00251 octave_value
00252 octave_perm_matrix::convert_to_str_internal (bool pad, bool force, char type) const
00253 {
00254   return to_dense ().convert_to_str_internal (pad, force, type);
00255 }
00256 
00257 bool
00258 octave_perm_matrix::save_ascii (std::ostream& os)
00259 {
00260   typedef octave_int<octave_idx_type> idx_int_type;
00261 
00262   os << "# size: " << matrix.rows () << "\n";
00263   os << "# orient: " << (matrix.is_col_perm () ? 'c' : 'r') << '\n';
00264 
00265   Array<octave_idx_type> pvec = matrix.pvec ();
00266   octave_idx_type n = pvec.length ();
00267   ColumnVector tmp (n);
00268   for (octave_idx_type i = 0; i < n; i++) tmp(i) = pvec(i) + 1;
00269   os << tmp;
00270 
00271   return true;
00272 }
00273 
00274 bool
00275 octave_perm_matrix::load_ascii (std::istream& is)
00276 {
00277   typedef octave_int<octave_idx_type> idx_int_type;
00278   octave_idx_type n;
00279   bool success = true;
00280   char orient;
00281 
00282   if (extract_keyword (is, "size", n, true)
00283       && extract_keyword (is, "orient", orient, true))
00284     {
00285       bool colp = orient == 'c';
00286       ColumnVector tmp (n);
00287       is >> tmp;
00288       if (!is)
00289         {
00290           error ("load: failed to load permutation matrix constant");
00291           success = false;
00292         }
00293       else
00294         {
00295           Array<octave_idx_type> pvec (dim_vector (n, 1));
00296           for (octave_idx_type i = 0; i < n; i++) pvec(i) = tmp(i) - 1;
00297           matrix = PermMatrix (pvec, colp);
00298 
00299           // Invalidate cache. Probably not necessary, but safe.
00300           dense_cache = octave_value ();
00301         }
00302     }
00303   else
00304     {
00305       error ("load: failed to extract size & orientation");
00306       success = false;
00307     }
00308 
00309   return success;
00310 }
00311 
00312 bool
00313 octave_perm_matrix::save_binary (std::ostream& os, bool&)
00314 {
00315 
00316   int32_t sz = matrix.rows ();
00317   bool colp = matrix.is_col_perm ();
00318   os.write (reinterpret_cast<char *> (&sz), 4);
00319   os.write (reinterpret_cast<char *> (&colp), 1);
00320   os.write (reinterpret_cast<const char *> (matrix.data ()), matrix.byte_size ());
00321 
00322   return true;
00323 }
00324 
00325 bool
00326 octave_perm_matrix::load_binary (std::istream& is, bool swap,
00327                                  oct_mach_info::float_format )
00328 {
00329   int32_t sz;
00330   bool colp;
00331   if (! (is.read (reinterpret_cast<char *> (&sz), 4)
00332          && is.read (reinterpret_cast<char *> (&colp), 1)))
00333     return false;
00334 
00335   MArray<octave_idx_type> m (dim_vector (sz, 1));
00336 
00337   if (! is.read (reinterpret_cast<char *> (m.fortran_vec ()), m.byte_size ()))
00338     return false;
00339 
00340   if (swap)
00341     {
00342       int nel = m.numel ();
00343       for (int i = 0; i < nel; i++)
00344         switch (sizeof (octave_idx_type))
00345           {
00346           case 8:
00347             swap_bytes<8> (&m(i));
00348             break;
00349           case 4:
00350             swap_bytes<4> (&m(i));
00351             break;
00352           case 2:
00353             swap_bytes<2> (&m(i));
00354             break;
00355           case 1:
00356           default:
00357             break;
00358           }
00359     }
00360 
00361   matrix = PermMatrix (m, colp);
00362   return true;
00363 }
00364 
00365 void
00366 octave_perm_matrix::print_raw (std::ostream& os,
00367                                bool pr_as_read_syntax) const
00368 {
00369   return octave_print_internal (os, matrix, pr_as_read_syntax,
00370                                 current_print_indent_level ());
00371 }
00372 
00373 mxArray *
00374 octave_perm_matrix::as_mxArray (void) const
00375 {
00376   return to_dense ().as_mxArray ();
00377 }
00378 
00379 bool
00380 octave_perm_matrix::print_as_scalar (void) const
00381 {
00382   dim_vector dv = dims ();
00383 
00384   return (dv.all_ones () || dv.any_zero ());
00385 }
00386 
00387 void
00388 octave_perm_matrix::print (std::ostream& os, bool pr_as_read_syntax) const
00389 {
00390   print_raw (os, pr_as_read_syntax);
00391   newline (os);
00392 }
00393 
00394 int
00395 octave_perm_matrix::write (octave_stream& os, int block_size,
00396                                 oct_data_conv::data_type output_type, int skip,
00397                                 oct_mach_info::float_format flt_fmt) const
00398 {
00399   return to_dense ().write (os, block_size, output_type, skip, flt_fmt);
00400 }
00401 
00402 void
00403 octave_perm_matrix::print_info (std::ostream& os,
00404                                     const std::string& prefix) const
00405 {
00406   matrix.print_info (os, prefix);
00407 }
00408 
00409 
00410 octave_value
00411 octave_perm_matrix::to_dense (void) const
00412 {
00413   if (! dense_cache.is_defined ())
00414       dense_cache = Matrix (matrix);
00415 
00416   return dense_cache;
00417 }
00418 
00419 DEFINE_OCTAVE_ALLOCATOR (octave_perm_matrix);
00420 
00421 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_perm_matrix,
00422                                      "permutation matrix", "double");
00423 
00424 static octave_base_value *
00425 default_numeric_conversion_function (const octave_base_value& a)
00426 {
00427   CAST_CONV_ARG (const octave_perm_matrix&);
00428 
00429   return new octave_matrix (v.matrix_value ());
00430 }
00431 
00432 octave_base_value::type_conv_info
00433 octave_perm_matrix::numeric_conversion_function (void) const
00434 {
00435   return octave_base_value::type_conv_info (default_numeric_conversion_function,
00436                                             octave_matrix::static_type_id ());
00437 }
00438 
00439 octave_base_value *
00440 octave_perm_matrix::try_narrowing_conversion (void)
00441 {
00442   octave_base_value *retval = 0;
00443 
00444   if (matrix.nelem () == 1)
00445     retval = new octave_scalar (matrix (0, 0));
00446 
00447   return retval;
00448 }
00449 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines