libidx
/home/rex/ebltrunk/core/libidx/include/idxspec.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Yann LeCun and Pierre Sermanet *
00003  *   yann@cs.nyu.edu, pierre.sermanet@gmail.com *
00004  *   All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Redistribution under a license not approved by the Open Source
00014  *       Initiative (http://www.opensource.org) must display the
00015  *       following acknowledgement in all advertising material:
00016  *        This product includes software developed at the Courant
00017  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00018  *     * The names of the authors may not be used to endorse or promote products
00019  *       derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00025  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00028  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  ***************************************************************************/
00032 
00033 #ifndef IDXSPEC_HPP_
00034 #define IDXSPEC_HPP_
00035 
00036 namespace ebl {
00037 
00039   // idxdim: constructors
00040 
00041   template <typename T>
00042   idxd<T>::~idxd() {
00043     if (offsets) {
00044       delete[] offsets;
00045     }
00046   }
00047 
00048   template <typename T>
00049   idxd<T>::idxd() : offsets(NULL) {
00050     ndim = -1;
00051     memset(dims, -1, MAXDIMS * sizeof (T));
00052   }
00053 
00054   template <typename T> template <class T2>
00055   idxd<T>::idxd(const idx<T2> &i) : offsets(NULL) {
00056     setdims(i.spec);
00057   }
00058 
00059   template <typename T> template <class T2>
00060   idxd<T>::idxd(const idxd<T2> &i) : offsets(NULL) {
00061     *this = i;
00062   }
00063 
00064   template <typename T>
00065   idxd<T>::idxd(const idxspec &s) : offsets(NULL) {
00066     setdims(s);
00067   }
00068 
00069   template <typename T>
00070   idxd<T>::idxd(const idxd<T> &s) : offsets(NULL) {
00071     setdims(s);
00072   }
00073 
00074   template <typename T>
00075   idxd<T>::idxd(T s0, T s1, T s2, T s3, T s4, T s5, T s6, T s7)
00076   : offsets(NULL) {
00077     dims[0] = s0; dims[1] = s1; dims[2] = s2; dims[3] = s3;
00078     dims[4] = s4; dims[5] = s5; dims[6] = s6; dims[7] = s7;
00079     ndim = 0;
00080     for (int i = 0; i < MAXDIMS; i++)
00081       if (dims[i] >= 0) ndim++;
00082       else break;
00083   }
00084 
00086   // idxdim: set dimensions
00087 
00088   template <typename T> template <class Tidx>
00089   void idxd<T>::setdims(const idx<Tidx> &i) {
00090     setdims(i.spec);
00091   }
00092 
00093   template <typename T>
00094   void idxd<T>::setdims(const idxspec &s) {
00095     ndim = s.ndim;
00096     // copy existing dimensions
00097     for (int i = 0; i < ndim; ++i)
00098       dims[i] = (T) s.dim[i];
00099     // set remaining to -1
00100     int ord = std::max((int) 0, s.ndim);
00101     memset(dims + ord, -1, (MAXDIMS - ord) * sizeof (T));
00102   }
00103 
00104   template <typename T>
00105   void idxd<T>::setdims(const idxd<T> &s) {
00106     ndim = s.order();
00107     // copy existing dimensions
00108     for (int i = 0; i < s.order(); ++i)
00109       dims[i] = s.dim(i);
00110     // set remaining to -1
00111     intg ord = std::max((intg) 0, s.order());
00112     memset(dims + ord, -1, (MAXDIMS - ord) * sizeof (T));
00113     // copy all offsets if exist
00114     if (s.offsets) {
00115       if (!offsets)
00116         offsets = new T[MAXDIMS];
00117       memcpy(offsets, s.offsets, MAXDIMS * sizeof(T));
00118     } else if (offsets) { // no offsets, delete existing
00119       delete[] offsets;
00120       offsets = NULL;
00121     }
00122   }
00123 
00124   template <typename T>
00125   void idxd<T>::setdims(T n) {
00126     for (int i = 0; i < ndim; ++i)
00127       dims[i] = n;
00128   }
00129 
00130   template <typename T>
00131   void idxd<T>::insert_dim(intg pos, T dim_size) {
00132     if (ndim + 1 > MAXDIMS)
00133       eblerror("error: cannot add another dimension to dim."
00134                << " Maximum number of dimensions (" << MAXDIMS << ") reached.")
00135     // check that dim_size is valid
00136     if (dim_size <= 0)
00137       eblerror("cannot set negative or zero dimension");
00138     // check that all dimensions up to pos (excluded) are > 0.
00139     for (uint i = 0; i < pos; ++i)
00140       if (dims[i] <= 0)
00141         eblerror("error: cannot insert dimension " << pos
00142                  << " after empty dimensions: " << *this);
00143     // add order of 1
00144     ndim++;
00145     if (ndim == 0) // one more if it was empty
00146       ndim++;
00147     // shift all dimensions until position pos
00148     for (uint i = ndim - 1; i > pos && i >= 1; i--)
00149       dims[i] = dims[i - 1];
00150     if (offsets)
00151       for (uint i = ndim - 1; i > pos && i >= 1; i--)
00152         offsets[i] = offsets[i - 1];
00153     // insert new dim
00154     dims[pos] = dim_size;
00155     if (offsets)
00156       offsets[pos] = 0;
00157   }
00158 
00159   template <typename T>
00160   T idxd<T>::remove_dim(intg pos) {
00161     // check that dim_size is valid
00162     if (ndim == 0)
00163       eblerror("not enough dimensions for removing one in " << *this);
00164     T rdim = dim(pos);
00165     // shift all dimensions until position pos
00166     for (uint i = pos; i < ndim - 1; i++)
00167       dims[i] = dims[i + 1];
00168     dims[ndim - 1] = -1; // empty last dimension
00169     if (offsets) {
00170       for (uint i = pos; i < ndim - 1; i++)
00171         offsets[i] = offsets[i + 1];
00172       offsets[ndim - 1] = 0; // empty last offset
00173     }
00174     // decrease order by 1
00175     ndim--;
00176     return rdim;
00177   }
00178 
00179   template <typename T>
00180   void idxd<T>::setdim(intg dimn, T size) {
00181     if (dimn >= ndim)
00182       eblerror("error: trying to set dimension " << dimn << " to size "
00183                << size << " but idxidm has only " << ndim
00184                << " dimension(s): " << *this);
00185     dims[dimn] = size;
00186   }
00187 
00188   template <typename T>
00189   void idxd<T>::setoffset(intg dimn, T offset) {
00190     if (dimn >= ndim)
00191       eblerror("error: trying to set offset of dim " << dimn << " to "
00192                << offset << " but idxidm has only " << ndim
00193                << " dimension(s): " << *this);
00194     // allocate if not allocated
00195     if (!offsets) {
00196       offsets = new T[MAXDIMS];
00197       memset(offsets, 0, MAXDIMS * sizeof (T));
00198     }
00199     offsets[dimn] = offset;
00200   }
00201 
00202   template <typename T>
00203   bool idxd<T>::has_offsets() const {
00204     return offsets != NULL;
00205   }
00206 
00207   template <typename T>
00208   void idxd<T>::set_max(const idxd<T> &other) {
00209     if (other.order() != ndim)
00210       eblerror("expected same order in " << *this << " and " << other);
00211     for (uint i = 0; i < ndim; i++)
00212       dims[i] = std::max(dims[i], other.dim(i));
00213   }
00214 
00215   template <typename T>
00216   void idxd<T>::shift_dim(int d, int pos) {
00217     T dims2[MAXDIMS];
00218     for (int i = 0, j = 0; i < MAXDIMS; ++i) {
00219       if (i == pos)
00220         dims2[i] = dims[d];
00221       else {
00222         if (j == d)
00223           j++;
00224         dims2[i] = dims[j++];
00225       }
00226     }
00227     memcpy(dims, dims2, MAXDIMS * sizeof (T));
00228     if (offsets)
00229       eblerror("not implemented (TODO)");
00230   }
00231 
00233   // get dimensions
00234 
00235   template <typename T>
00236   intg idxd<T>::order() const {
00237     return ndim;
00238   }
00239 
00240   template <typename T>
00241   bool idxd<T>::empty() const {
00242     return ndim == -1;
00243   }
00244 
00245   template <typename T>
00246   T idxd<T>::dim(intg dimn) const {
00247     if (dimn >= ndim)
00248       eblerror("trying to access size of dimension " << dimn
00249                << " but idxdim's maximum dimensions is " << ndim);
00250     return dims[dimn];
00251   }
00252 
00253   template <typename T>
00254   T idxd<T>::maxdim() const {
00255     T m = 0;
00256     for (intg i = 0; i < ndim; ++i) 
00257       if (m < dims[i]) m = dims[i];
00258     return m;
00259   }
00260 
00261   template <typename T>
00262   T idxd<T>::offset(intg dimn) const {
00263     if (dimn >= ndim)
00264       eblerror("trying to access size of dimension " << dimn
00265                << " but idxdim's maximum dimensions is " << ndim);
00266     if (offsets)
00267       return offsets[dimn];
00268     else
00269       return 0;
00270   }
00271 
00272   template <typename T>
00273   bool idxd<T>::operator==(const idxd<T>& other) {
00274     if (other.ndim != ndim)
00275       return false;
00276     for (int i = 0; i < ndim; ++i)
00277       if (other.dim(i) != dim(i))
00278         return false;
00279     return true;
00280   }
00281 
00282   template <typename T>
00283   bool idxd<T>::operator!=(const idxd<T>& other) {
00284     return !(*this == other);
00285   }
00286 
00288   // operators
00289 
00290   // template <typename T>
00291   // idxd<T>& idxd<T>::operator=(const idxd<T> &d2) {
00292   //   if ((void*)this != (void*)&d2) { // protect against invalid self-assignment
00293   //     setdims(d2);
00294   //   }
00295   //   EDEBUG("this " << this << " " << *this << " <- d2 " << &d2 << " " << d2);
00296   //   return *this;
00297   // }
00298 
00299   template <typename T>
00300   idxd<T>& idxd<T>::operator=(idxd<T> d2) {
00301     setdims(d2);
00302     return *this;
00303   }
00304 
00305   template <typename T> template <typename T2>
00306   idxd<T>& idxd<T>::operator=(const idxd<T2> &d2) {
00307     if ((void*)this != (void*)&d2) { // protect against invalid self-assignment
00308       ndim = d2.order();
00309       for (intg i = 0; i < ndim; ++i)
00310         dims[i] = (T) d2.dim(i);
00311       if (offsets && !d2.has_offsets()) {
00312         delete[] offsets;
00313         offsets = NULL;
00314       } else if (d2.has_offsets()) {
00315         if (!offsets)
00316           offsets = new T[MAXDIMS];
00317         for (intg i = 0; i < d2.order(); ++i)
00318           offsets[i] = (T) d2.offset(i);
00319       }
00320     }
00321     return *this;
00322   }
00323 
00324   template <typename T>
00325   idxd<T> idxd<T>::operator*(const idxd<T> &d2) const {
00326     idxd<T> d = *this;
00327     if (d2.order() != d.order())
00328       eblerror("expected same order idxd but got " << d << " and " << d2);
00329     for (int i = 0; i < d.order(); ++i)
00330       d.setdim(i, (T) (d.dim(i) * d2.dim(i)));
00331     if (offsets)
00332       for (int i = 0; i < d.order(); ++i)
00333         d.setoffset(i, (T) (d.offset(i) * d2.dim(i)));
00334     return d;
00335   }
00336 
00337   template <typename T> template <typename T2>
00338   idxd<T> idxd<T>::operator*(const idxd<T2> &d2) const {
00339     idxd<T> d = *this;
00340     if (d2.order() != d.order())
00341       eblerror("expected same order idxd but got " << d << " and " << d2);
00342     for (int i = 0; i < d.order(); ++i)
00343       d.setdim(i, (T) ((T2)(d.dim(i)) * d2.dim(i)));
00344     if (offsets)
00345       for (int i = 0; i < d.order(); ++i)
00346         d.setoffset(i, (T) ((T2)(d.offset(i)) * d2.dim(i)));
00347     return d;
00348   }
00349 
00350   template <typename T> template <typename T2>
00351   idxd<T> idxd<T>::operator*(idxd<T2> &d2) {
00352     idxd<T> d = *this;
00353     if (d2.order() != d.order())
00354       eblerror("expected same order idxd but got " << d << " and " << d2);
00355     for (int i = 0; i < d.order(); ++i)
00356       d.setdim(i, (T) ((T2)(d.dim(i)) * d2.dim(i)));
00357     if (offsets)
00358       for (int i = 0; i < d.order(); ++i)
00359         d.setoffset(i, (T) ((T2)(d.offset(i)) * d2.dim(i)));
00360     return d;
00361   }
00362 
00363   template <typename T> template <typename T2>
00364   idxd<T> idxd<T>::operator*(T2 f) {
00365     idxd<T> d(*this);
00366     for (int i = 0; i < d.order(); ++i)
00367       d.setdim(i, (T) ((T2)(d.dim(i)) * f));
00368     if (offsets)
00369       for (int i = 0; i < d.order(); ++i)
00370         d.setoffset(i, (T) ((T2)(d.offset(i)) * f));
00371     return d;
00372   }
00373 
00374   template <typename T> template <typename T2>
00375   idxd<T> idxd<T>::operator+(T2 f) {
00376     idxd<T> d = *this;
00377     for (int i = 0; i < d.order(); ++i)
00378       d.setdim(i, (T) ((T2)(d.dim(i)) + f));
00379     return d;
00380   }
00381 
00382   template <typename T>
00383   idxd<T> idxd<T>::operator+(idxd<T> &d2) {
00384     idxd<T> d = *this;
00385     if (d.order() != d2.order())
00386       eblerror("cannot add two idxdim with different orders: " << d << " and "
00387                << d2);
00388     for (int i = 0; i < d.order(); ++i)
00389       d.setdim(i, d.dim(i) + d2.dim(i));
00390     return d;
00391   }
00392 
00393   template <typename T>
00394   bool idxd<T>::operator<=(idxd<T> &d2) {
00395     if (this->order() != d2.order())
00396       eblerror("cannot add two idxdim with different orders: " << *this
00397                << " and " << d2);
00398     for (int i = 0; i < this->order(); ++i)
00399       if (this->dim(i) > d2.dim(i))
00400         return false;
00401     return true;
00402   }
00403 
00404   template <typename T>
00405   bool idxd<T>::operator>=(idxd<T> &d2) {
00406     if (this->order() != d2.order())
00407       eblerror("cannot add two idxdim with different orders: " << *this
00408                << " and " << d2);
00409     for (int i = 0; i < this->order(); ++i)
00410       if (this->dim(i) < d2.dim(i))
00411         return false;
00412     return true;
00413   }
00414 
00416 
00417   template <typename T>
00418   intg idxd<T>::nelements() {
00419     intg total = 1;
00420     for (int i = 0; i < ndim; ++i)
00421       total *= dim(i);
00422     return total;
00423   }
00424 
00425   // midxdim ///////////////////////////////////////////////////////////////////
00426 
00427   template <typename T>
00428   midxd<T>::midxd() {
00429   }
00430 
00431   template <typename T>
00432   midxd<T>::midxd(uint n) : svector<idxd<T> >(n) {
00433   }
00434 
00435   template <typename T>
00436   midxd<T>::~midxd() {
00437   }
00438 
00439   template <typename T>
00440   midxd<T>::midxd(const idxd<T> &s) {
00441     push_back(s);
00442   }
00443 
00444   template <typename T> template <typename T2>
00445   midxd<T>::midxd(const midxd<T2> &s) {
00446     *this = s;
00447   }
00448 
00449   template <typename T>
00450   midxd<T> midxd<T>::narrow_copy(uint n, uint offset) {
00451     if (offset + n > this->size())
00452       eblerror("out-of-bounds narrow of size " << n << " starting at offset "
00453                << offset << " in " << *this);
00454     midxd<T> m;
00455     for (typename midxd<T>::iterator i = this->begin() + offset;
00456          i != this->begin() + offset + n; ++i)
00457       if (i.exists()) m.push_back(*i);
00458       else m.push_back_empty();
00459     return m;
00460   }
00461 
00462   template <typename T> template <typename T2>
00463   void midxd<T>::push_back(const idxd<T2> &m) {
00464     svector<idxd<T> >::push_back(new idxd<T>(m));
00465   }
00466 
00467   template <typename T>
00468   void midxd<T>::push_back(const midxd<T> &m) {
00469     for (typename midxd<T>::const_iterator i = m.begin(); i != m.end(); ++i) {
00470       if (i.exists())
00471         svector<idxd<T> >::push_back(new idxd<T>(*i));
00472       else
00473         this->push_back_empty();
00474     }
00475   }
00476 
00477   // template <typename T>
00478   // void midxd<T>::push_back(midxd<T> &m) {
00479   //   for (typename midxd<T>::iterator i = m.begin(); i != m.end(); ++i)
00480   //     svector<idxd<T> >::push_back((*i);
00481   // }
00482 
00483   template <typename T>
00484   midxd<T> midxd<T>::merge_all() {
00485     midxd<T> m;
00486     if (this->size() == 0) return m;
00487     // add first element
00488     idxd<T> &e0 = (*this)[0];
00489     m.push_back(e0);
00490     // check that remaining ones are the same
00491     for (typename midxd<T>::iterator i = this->begin(1); i != this->end(); ++i){
00492       if (((idxd<T>&)*i) != e0)
00493         eblerror("expected all elements to be the same in " << *this);
00494     }
00495     return m;
00496   }
00497 
00498   template <typename T> template <typename T2>
00499   midxd<T>& midxd<T>::operator=(const midxd<T2> &other) {
00500     if ((void*) &other != (void*) this) {
00501       this->clear();
00502       for (typename midxd<T2>::const_iterator i = other.begin();
00503            i != other.end(); ++i) {
00504         if (i.exists()) this->push_back(*i);
00505         else this->push_back_empty();
00506       }
00507     }
00508     return *this;
00509   }
00510 
00511   // printing //////////////////////////////////////////////////////////////////
00512 
00513   template<class T>
00514   std::string& operator<<(std::string &o, const midxd<T> &v) {
00515     o << "[ ";
00516     for (typename midxd<T>::const_iterator i = v.begin();
00517          i != v.end(); ++i) {
00518       if (i.exists())
00519         o << *i << " ";
00520       else
00521         o << " null ";
00522     }
00523     o << "]";
00524     return o;
00525   }
00526 
00527   template<class T>
00528   std::ostream& operator<<(std::ostream &o, const midxd<T> &v) {
00529     o << "[ ";
00530     for (typename midxd<T>::const_iterator i = v.begin();
00531          i != v.end(); ++i) {
00532       if (i.exists())
00533         o << *i << " ";
00534       else
00535         o << " null ";
00536     }
00537     o << "]";
00538     return o;
00539   }
00540 
00541 } // namespace ebl
00542 
00543 #endif /* IDXSPEC_HPP_ */