dim-vector.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2003-2012 John W. Eaton
00004 Copyirght (C) 2009, 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <iostream>
00029 
00030 #include "dim-vector.h"
00031 
00032 // The maximum allowed value for a dimension extent. This will normally be a tiny bit
00033 // off the maximum value of octave_idx_type.
00034 // Currently 1 is subtracted to allow safe conversion of any 2D Array into Sparse,
00035 // but this offset may change in the future.
00036 octave_idx_type
00037 dim_vector::dim_max (void)
00038 {
00039   return std::numeric_limits<octave_idx_type>::max () - 1;
00040 }
00041 
00042 void
00043 dim_vector::chop_all_singletons (void)
00044 {
00045   make_unique ();
00046 
00047   int j = 0;
00048   int l = ndims();
00049 
00050   for (int i = 0; i < l; i++)
00051     {
00052       if (rep[i] != 1)
00053         rep[j++] = rep[i];
00054     }
00055 
00056   if (j == 1)
00057     rep[1] = 1;
00058 
00059   ndims () = j > 2 ? j : 2;
00060 }
00061 
00062 std::string
00063 dim_vector::str (char sep) const
00064 {
00065   std::ostringstream buf;
00066 
00067   for (int i = 0; i < length (); i++)
00068     {
00069       buf << elem (i);
00070 
00071       if (i < length () - 1)
00072         buf << sep;
00073     }
00074 
00075   std::string retval = buf.str ();
00076 
00077   return retval;
00078 }
00079 
00080 int
00081 dim_vector::num_ones (void) const
00082 {
00083   int retval = 0;
00084 
00085   for (int i = 0; i < length (); i++)
00086     if (elem (i) == 1)
00087       retval++;
00088 
00089   return retval;
00090 }
00091 
00092 octave_idx_type
00093 dim_vector::safe_numel (void) const
00094 {
00095   octave_idx_type idx_max = dim_max ();
00096   octave_idx_type n = 1;
00097   int n_dims = length ();
00098 
00099   for (int i = 0; i < n_dims; i++)
00100     {
00101       n *= rep[i];
00102       if (rep[i] != 0)
00103         idx_max /= rep[i];
00104       if (idx_max <= 0)
00105         throw std::bad_alloc ();
00106     }
00107 
00108   return n;
00109 }
00110 
00111 dim_vector
00112 dim_vector::squeeze (void) const
00113 {
00114   dim_vector new_dims = *this;
00115 
00116   bool dims_changed = 1;
00117 
00118   int k = 0;
00119 
00120   for (int i = 0; i < length (); i++)
00121     {
00122       if (elem (i) == 1)
00123         dims_changed = true;
00124       else
00125         new_dims(k++) = elem (i);
00126     }
00127 
00128   if (dims_changed)
00129     {
00130       if (k == 0)
00131         new_dims = dim_vector (1, 1);
00132       else if (k == 1)
00133         {
00134           // There is one non-singleton dimension, so we need
00135           // to decide the correct orientation.
00136 
00137           if (elem (0) == 1)
00138             {
00139               // The original dimension vector had a leading
00140               // singleton dimension.
00141 
00142               octave_idx_type tmp = new_dims(0);
00143 
00144               new_dims.resize (2);
00145 
00146               new_dims(0) = 1;
00147               new_dims(1) = tmp;
00148             }
00149           else
00150             {
00151               // The first element of the original dimension vector
00152               // was not a singleton dimension.
00153 
00154               new_dims.resize (2);
00155 
00156               new_dims(1) = 1;
00157             }
00158         }
00159       else
00160         new_dims.resize(k);
00161     }
00162 
00163   return new_dims;
00164 }
00165 
00166 // This is the rule for cat(). cat(dim, A, B) works if one
00167 // of the following holds, in this order:
00168 //
00169 // 1. size(A, k) == size(B, k) for all k != dim.
00170 // In this case, size (C, dim) = size (A, dim) + size (B, dim) and
00171 // other sizes remain intact.
00172 //
00173 // 2. A is 0x0, in which case B is the result
00174 // 3. B is 0x0, in which case A is the result
00175 
00176 bool
00177 dim_vector::concat (const dim_vector& dvb, int dim)
00178 {
00179   int orig_nd = ndims (), ndb = dvb.ndims ();
00180   int new_nd = dim < ndb ? ndb : dim + 1;
00181   if (new_nd > orig_nd)
00182     resize (new_nd, 1);
00183   else
00184     new_nd = orig_nd;
00185 
00186   make_unique ();
00187 
00188   bool match = true;
00189 
00190   for (int i = 0; i < ndb; i++)
00191     {
00192       if (i != dim && rep[i] != dvb(i))
00193         {
00194           match = false;
00195           break;
00196         }
00197     }
00198 
00199   for (int i = ndb; i < new_nd; i++)
00200     {
00201       if (i != dim && rep[i] != 1)
00202         {
00203           match = false;
00204           break;
00205         }
00206     }
00207 
00208   if (match)
00209     rep[dim] += (dim < ndb ? dvb(dim) : 1);
00210   else
00211     {
00212       // Dimensions don't match. The only allowed fix is
00213       // to omit 0x0.
00214       if (ndb == 2 && dvb(0) == 0 && dvb(1) == 0)
00215         match = true;
00216       else if (orig_nd == 2 && rep[0] == 0 && rep[1] == 0)
00217         {
00218           *this = dvb;
00219           match = true;
00220         }
00221     }
00222 
00223   chop_trailing_singletons ();
00224 
00225   return match;
00226 }
00227 
00228 // Rules for horzcat/vertcat are yet looser.
00229 // two arrays A, B can be concatenated
00230 // horizontally (dim = 2) or vertically (dim = 1) if one of the
00231 // following holds, in this order:
00232 //
00233 // 1. cat(dim, A, B) works
00234 //
00235 // 2. A, B are 2D and one of them is an empty vector, in which
00236 // case the result is the other one except if both of them
00237 // are empty vectors, in which case the result is 0x0.
00238 
00239 bool
00240 dim_vector::hvcat (const dim_vector& dvb, int dim)
00241 {
00242   if (concat (dvb, dim))
00243     return true;
00244   else if (length () == 2 && dvb.length () == 2)
00245     {
00246       bool e2dv = rep[0] + rep[1] == 1;
00247       bool e2dvb = dvb(0) + dvb(1) == 1;
00248       if (e2dvb)
00249         {
00250           if (e2dv)
00251             *this = dim_vector ();
00252           return true;
00253         }
00254       else if (e2dv)
00255         {
00256           *this = dvb;
00257           return true;
00258         }
00259     }
00260 
00261   return false;
00262 }
00263 
00264 dim_vector
00265 dim_vector::redim (int n) const
00266 {
00267   int n_dims = length ();
00268 
00269   if (n_dims == n)
00270     return *this;
00271   else if (n_dims < n)
00272     {
00273       dim_vector retval = alloc (n);
00274 
00275       for (int i = 0; i < n_dims; i++)
00276         retval.rep[i] = rep[i];
00277 
00278       for (int i = n_dims; i < n; i++)
00279         retval.rep[i] = 1;
00280 
00281       return retval;
00282     }
00283   else
00284     {
00285       if (n < 1) n = 1;
00286 
00287       dim_vector retval = alloc (n);
00288 
00289       retval.rep[1] = 1;
00290 
00291       for (int i = 0; i < n-1; i++)
00292         retval.rep[i] = rep[i];
00293 
00294       int k = rep[n-1];
00295       for (int i = n; i < n_dims; i++)
00296         k *= rep[i];
00297 
00298       retval.rep[n-1] = k;
00299 
00300       return retval;
00301     }
00302 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines