nnfw/include/vectors.h

Go to the documentation of this file.
00001 /********************************************************************************
00002  *  Neural Network Framework.                                                   *
00003  *  Copyright (C) 2005-2011 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #ifndef VECTORS_H
00021 #define VECTORS_H
00022 
00028 #include "memutils.h"
00029 #include "QVector"
00030 #include "nnfwexceptions.h"
00031 
00032 namespace farsa {
00033 
00041 class FARSA_NNFW_TEMPLATE doubleRef {
00042 public:
00044     doubleRef() : ref(&dummy), ref2(&dummy) {
00045     };
00047     operator double() {
00048         return *ref;
00049     };
00051     doubleRef& operator=( const doubleRef& src ) {
00052         ref2 = src.ref2;
00053         return (*this);
00054     };
00056     doubleRef& operator=( const double& src ) {
00057         *ref2 = src;
00058         return (*this);
00059     };
00061     doubleRef& operator+=( const double& src ) {
00062         *ref2 += src;
00063         return (*this);
00064     };
00066     doubleRef& operator-=( const double& src ) {
00067         *ref2 -= src;
00068         return (*this);
00069     };
00071     doubleRef& operator*=( const double& src ) {
00072         *ref2 *= src;
00073         return (*this);
00074     };
00076     doubleRef& operator/=( const double& src ) {
00077         *ref2 /= src;
00078         return (*this);
00079     };
00081     void setRef( double* src) {
00082         ref = src;
00083         ref2 = src;
00084     };
00086     void setNoSteady() {
00087         ref2 = ref;
00088     };
00090     void setSteady() {
00091         ref2 = &dummy;
00092     };
00094     bool isSteady() {
00095         return ref != ref2;
00096     };
00097 private:
00098     //--- How it works:
00099     //--- ref is always returned when the data is retrieved,
00100     //--- while ref2 is used during all assignments operation
00101     //--- FIXED data: ref2 points to dummy variable, in this way each assignment will change
00102     //---             the dummy variable and not the data pointed by ref
00103     //--- NOT FIXED : ref2 points to same variable of ref, in this way each assignement will change
00104     //---             the data pointed by ref (i.e. the source data)
00105     double* ref;
00106     double* ref2;
00107     static double dummy;
00108 };
00109 
00121 class FARSA_NNFW_TEMPLATE DoubleVector {
00122 public:
00124     DoubleVector() {
00125         shData = new sharedData();
00126         shData->vsize = 0;
00127         //shData->data = 0;
00128         //shData->dataref = 0;
00129         shData->refcounts = 1;
00130         shData->temporary = false;
00131         shData->nodata = false;
00132         this->isinternal = false;
00133     };
00138     DoubleVector( unsigned int size, bool isinternal = false ) {
00139         shData = new sharedData();
00140         shData->vsize = size;
00141         shData->data = new double[size];
00142         memoryZeroing( shData->data, size );
00143         shData->dataref = new doubleRef[size];
00144         shData->refcounts = 1;
00145         shData->temporary = false;
00146         shData->nodata = false;
00147         for( unsigned int i=0; i<shData->vsize; i++ ) {
00148             shData->dataref[i].setRef( shData->data + i );
00149         }
00150         this->isinternal = isinternal;
00151     };
00156     DoubleVector( unsigned int size, double value, bool isinternal = false ) {
00157         shData = new sharedData();
00158         shData->vsize = size;
00159         shData->data = new double[size];
00160         shData->dataref = new doubleRef[size];
00161         shData->refcounts = 1;
00162         shData->temporary = false;
00163         shData->nodata = false;
00164         for( unsigned int i=0; i<shData->vsize; i++ ) {
00165             shData->data[i] = value;
00166             shData->dataref[i].setRef( shData->data + i );
00167         }
00168         this->isinternal = isinternal;
00169     };
00174     DoubleVector( const double* r, unsigned int dim, bool isinternal = false ) {
00175         shData = new sharedData();
00176         shData->vsize = dim;
00177         shData->data = new double[dim];
00178         shData->dataref = new doubleRef[dim];
00179         shData->refcounts = 1;
00180         shData->temporary = false;
00181         shData->nodata = false;
00182         for( unsigned int i=0; i<shData->vsize; i++ ) {
00183             shData->data[i] = r[i];
00184             shData->dataref[i].setRef( shData->data + i );
00185         }
00186         this->isinternal = isinternal;
00187     };
00189     DoubleVector( const DoubleVector& src ) {
00190         shData = src.shData;
00191         shData->refcounts += 1;
00192         //--- is not a temporary anymore !
00193         shData->temporary = false;
00194         isinternal = false;
00195     };
00225     DoubleVector( unsigned int dim, bool temp, unsigned int dummy ) {
00226         (void)dummy; // This stops warnings. Assigning dummy a value would have produce a "parameter ‘dummy’ set but not used" warning
00227         shData = new sharedData();
00228         shData->vsize = dim;
00229         shData->data = new double[dim];
00230         shData->dataref = new doubleRef[dim];
00231         shData->refcounts = 1;
00232         shData->temporary = temp;
00233         shData->nodata = false;
00234         for( unsigned int i=0; i<shData->vsize; i++ ) {
00235             shData->dataref[i].setRef( shData->data + i );
00236         }
00237         this->isinternal = false;
00238     };
00240     ~DoubleVector() {
00241         shData->refcounts -= 1;
00242         if ( shData->refcounts == 0 ) {
00243             //--- the last destroy the data
00244             if ( shData->vsize > 0 ) {
00245                 delete [](shData->dataref);
00246                 if ( !(shData->nodata) ) {
00247                     delete [](shData->data);
00248                 }
00249             }
00250             delete shData;
00251         }
00252     };
00254     unsigned int size() const {
00255         return shData->vsize;
00256     };
00258     bool isNull() const {
00259         return (shData->vsize==0);
00260     };
00262     bool operator==( const DoubleVector& b ) const {
00263         if ( shData == b.shData ) return true;
00264         if ( shData->vsize != b.shData->vsize ) return false;
00265         for( unsigned int i=0; i<shData->vsize; i++ ) {
00266             if ( shData->dataref[i] != b.shData->dataref[i] ) return false;
00267         }
00268         return true;
00269     };
00271     bool operator!=( const DoubleVector& b ) const {
00272         return !( *this == b );
00273     };
00280     DoubleVector& operator=( const DoubleVector& src ) {
00281         if ( isinternal ) throw VectorAssignmentNotAllowed();
00282         if ( src.shData == shData ) return (*this);
00283         //--- eliminate the previous data
00284         shData->refcounts -= 1;
00285         if ( shData->refcounts == 0 ) {
00286             //--- the last destroy the data
00287             if ( shData->vsize > 0 ) {
00288                 delete [](shData->dataref);
00289                 if ( !(shData->nodata) ) {
00290                     delete [](shData->data);
00291                 }
00292             }
00293             delete shData;
00294         }
00295         //--- set the new data taken from src
00296         shData = src.shData;
00297         shData->refcounts++;
00298         //--- is not a temporary anymore !
00299         shData->temporary = false;
00300         return (*this);
00301     };
00309     DoubleVector& copyValues( const DoubleVector& src ) {
00310         // if shared data is the same, they already share the same values
00311         if ( shData == src.shData ) return (*this);
00312         detach();
00313         unsigned int max = qMin( shData->vsize, src.size() );
00314         for( unsigned int i=0; i<max; i++ ) {
00315             shData->dataref[i] = src[i];
00316         }
00317         return (*this);
00318     };
00326     DoubleVector& copyValues( const QVector<double>& src ) {
00327         detach();
00328         unsigned int max = qMin( shData->vsize, (unsigned int)(src.size()) );
00329         for( unsigned int i=0; i<max; i++ ) {
00330             shData->dataref[i] = src[i];
00331         }
00332         return (*this);
00333     };
00341     DoubleVector& copyValues( const DoubleVector& src, unsigned int srcOffset, unsigned int thisOffset ) {
00342         // if shared data is the same and offsets are zero, then there is nothing to do
00343         if ( shData == src.shData && srcOffset == 0 && thisOffset == 0 ) return (*this);
00344         detach();
00345         unsigned int max = qMin( shData->vsize-thisOffset, src.size()-srcOffset );
00346         for( unsigned int i=0; i<max; i++ ) {
00347             shData->dataref[i+thisOffset] = src[i+srcOffset];
00348         }
00349         return (*this);
00350     };
00362     DoubleVector& copyValues( const DoubleVector& src, unsigned int srcOffset, unsigned int thisOffset, unsigned int stride ) {
00363         if ( stride == 0 ) return (*this);
00364         // if shared data is the same and offsets are zero, then there is nothing to do
00365         if ( shData == src.shData && srcOffset == 0 && thisOffset == 0 ) return (*this);
00366         detach();
00367         unsigned int max = qMin( shData->vsize-thisOffset, src.size()-srcOffset );
00368         for( unsigned int i=0; i<max; i=i+stride ) {
00369             shData->dataref[i+thisOffset] = src[i+srcOffset];
00370         }
00371         return (*this);
00372     };
00376     DoubleVector& detach() {
00377         if ( shData->refcounts > 1 ) {
00378             sharedData* tmp = new sharedData();
00379             unsigned int size = shData->vsize;
00380             tmp->vsize = size;
00381             tmp->data = new double[size];
00382             if ( shData->nodata ) {
00383                 for( unsigned int i=0; i<size; i++ ) {
00384                     tmp->data[i] = shData->dataref[i];
00385                 }
00386             } else {
00387                 memoryCopy( tmp->data, shData->data, size );
00388             }
00389             tmp->dataref = new doubleRef[size];
00390             tmp->refcounts = 1;
00391             tmp->temporary = false;
00392             tmp->nodata = false;
00393             for( unsigned int i=0; i<size; i++ ) {
00394                 tmp->dataref[i].setRef( tmp->data + i );
00395             }
00396             shData->refcounts--;
00397             shData = tmp;
00398         }
00399         return (*this);
00400     };
00402     const DoubleVector& operator+() const {
00403         return (*this);
00404     };
00406     const DoubleVector operator-() const {
00407         if ( shData->temporary ) {
00408             for( unsigned int i=0; i<shData->vsize; i++ ) {
00409                 shData->dataref[i] = -shData->dataref[i];
00410             }
00411             return (*this);
00412         } else {
00413             DoubleVector ret( shData->vsize, true, 0 );
00414             for( unsigned int i=0; i<shData->vsize; i++ ) {
00415                 ret.shData->dataref[i] = -shData->dataref[i];
00416             }
00417             return ret;
00418         }
00419     };
00423     const DoubleVector operator+( const DoubleVector& right ) const {
00424 #ifdef FARSA_DEBUG
00425         if ( shData->vsize != right.shData->vsize ) {
00426             throw IncompatibleVectors("Incompatible DoubleVectors in operator+ (dimension must be equals)");
00427         }
00428 #endif
00429         if ( right.shData->temporary ) {
00430             for( unsigned int i=0; i<shData->vsize; i++ ) {
00431                 right.shData->dataref[i] = shData->dataref[i] + right.shData->dataref[i];
00432             }
00433             return right;
00434         } else if ( shData->temporary ) {
00435             for( unsigned int i=0; i<shData->vsize; i++ ) {
00436                 shData->dataref[i] = shData->dataref[i] + right.shData->dataref[i];
00437             }
00438             return (*this);
00439         } else {
00440             DoubleVector ret( shData->vsize, true, 0 );
00441             for( unsigned int i=0; i<shData->vsize; i++ ) {
00442                 ret.shData->dataref[i] = shData->dataref[i] + right.shData->dataref[i];
00443             }
00444             return ret;
00445         }
00446     };
00450     const DoubleVector operator-( const DoubleVector& right ) const {
00451 #ifdef FARSA_DEBUG
00452         if ( shData->vsize != right.shData->vsize ) {
00453             throw IncompatibleVectors("Incompatible DoubleVectors in operator- (dimension must be equals)");
00454         }
00455 #endif
00456         if ( right.shData->temporary ) {
00457             for( unsigned int i=0; i<shData->vsize; i++ ) {
00458                 right.shData->dataref[i] = shData->dataref[i] - right.shData->dataref[i];
00459             }
00460             return right;
00461         } else if ( shData->temporary ) {
00462             for( unsigned int i=0; i<shData->vsize; i++ ) {
00463                 shData->dataref[i] = shData->dataref[i] - right.shData->dataref[i];
00464             }
00465             return (*this);
00466         } else {
00467             DoubleVector ret( shData->vsize, true, 0 );
00468             for( unsigned int i=0; i<shData->vsize; i++ ) {
00469                 ret.shData->dataref[i] = shData->dataref[i] - right.shData->dataref[i];
00470             }
00471             return ret;
00472         }
00473     };
00477     const DoubleVector operator*( const DoubleVector& right ) const {
00478 #ifdef FARSA_DEBUG
00479         if ( shData->vsize != right.shData->vsize ) {
00480             throw IncompatibleVectors("Incompatible DoubleVectors in operator* (dimension must be equals)");
00481         }
00482 #endif
00483         if ( right.shData->temporary ) {
00484             for( unsigned int i=0; i<shData->vsize; i++ ) {
00485                 right.shData->dataref[i] = shData->dataref[i] * right.shData->dataref[i];
00486             }
00487             return right;
00488         } else if ( shData->temporary ) {
00489             for( unsigned int i=0; i<shData->vsize; i++ ) {
00490                 shData->dataref[i] = shData->dataref[i] * right.shData->dataref[i];
00491             }
00492             return (*this);
00493         } else {
00494             DoubleVector ret( shData->vsize, true, 0 );
00495             for( unsigned int i=0; i<shData->vsize; i++ ) {
00496                 ret.shData->dataref[i] = shData->dataref[i] * right.shData->dataref[i];
00497             }
00498             return ret;
00499         }
00500     };
00504     const DoubleVector operator/( const DoubleVector& right ) const {
00505 #ifdef FARSA_DEBUG
00506         if ( shData->vsize != right.shData->vsize ) {
00507             throw IncompatibleVectors("Incompatible DoubleVectors in operator/ (dimension must be equals)");
00508         }
00509 #endif
00510         if ( right.shData->temporary ) {
00511             for( unsigned int i=0; i<shData->vsize; i++ ) {
00512                 right.shData->dataref[i] = shData->dataref[i] / right.shData->dataref[i];
00513             }
00514             return right;
00515         } else if ( shData->temporary ) {
00516             for( unsigned int i=0; i<shData->vsize; i++ ) {
00517                 shData->dataref[i] = shData->dataref[i] / right.shData->dataref[i];
00518             }
00519             return (*this);
00520         } else {
00521             DoubleVector ret( shData->vsize, true, 0 );
00522             for( unsigned int i=0; i<shData->vsize; i++ ) {
00523                 ret.shData->dataref[i] = shData->dataref[i] / right.shData->dataref[i];
00524             }
00525             return ret;
00526         }
00527     };
00531     DoubleVector& operator+=( const DoubleVector& right ) {
00532 #ifdef FARSA_DEBUG
00533         if ( shData->vsize != right.shData->vsize ) {
00534             throw IncompatibleVectors("Incompatible DoubleVectors in operator+= (dimension must be equals)");
00535         }
00536 #endif
00537         detach();
00538         for( unsigned int i=0; i<shData->vsize; i++ ) {
00539             shData->dataref[i] = shData->dataref[i] + right.shData->dataref[i];
00540         }
00541         return (*this);
00542     };
00546     DoubleVector& operator-=( const DoubleVector& right ) {
00547 #ifdef FARSA_DEBUG
00548         if ( shData->vsize != right.shData->vsize ) {
00549             throw IncompatibleVectors("Incompatible DoubleVectors in operator-= (dimension must be equals)");
00550         }
00551 #endif
00552         detach();
00553         for( unsigned int i=0; i<shData->vsize; i++ ) {
00554             shData->dataref[i] = shData->dataref[i] - right.shData->dataref[i];
00555         }
00556         return (*this);
00557     };
00561     DoubleVector& operator*=( const DoubleVector& right ) {
00562 #ifdef FARSA_DEBUG
00563         if ( shData->vsize != right.shData->vsize ) {
00564             throw IncompatibleVectors("Incompatible DoubleVectors in operator*= (dimension must be equals)");
00565         }
00566 #endif
00567         detach();
00568         for( unsigned int i=0; i<shData->vsize; i++ ) {
00569             shData->dataref[i] = shData->dataref[i] * right.shData->dataref[i];
00570         }
00571         return (*this);
00572     };
00576     DoubleVector& operator/=( const DoubleVector& right ) {
00577 #ifdef FARSA_DEBUG
00578         if ( shData->vsize != right.shData->vsize ) {
00579             throw IncompatibleVectors("Incompatible DoubleVectors in operator/= (dimension must be equals)");
00580         }
00581 #endif
00582         detach();
00583         for( unsigned int i=0; i<shData->vsize; i++ ) {
00584             shData->dataref[i] = shData->dataref[i] / right.shData->dataref[i];
00585         }
00586         return (*this);
00587     };
00589     DoubleVector& operator+=( const double& right ) {
00590         detach();
00591         for( unsigned int i=0; i<shData->vsize; i++ ) {
00592             shData->dataref[i] = shData->dataref[i] + right;
00593         }
00594         return (*this);
00595     };
00597     DoubleVector& operator-=( const double& right ) {
00598         detach();
00599         for( unsigned int i=0; i<shData->vsize; i++ ) {
00600             shData->dataref[i] = shData->dataref[i] - right;
00601         }
00602         return (*this);
00603     };
00605     DoubleVector& operator*=( const double& right ) {
00606         detach();
00607         for( unsigned int i=0; i<shData->vsize; i++ ) {
00608             shData->dataref[i] = shData->dataref[i] * right;
00609         }
00610         return (*this);
00611     };
00613     DoubleVector& operator/=( const double& right ) {
00614         detach();
00615         for( unsigned int i=0; i<shData->vsize; i++ ) {
00616             shData->dataref[i] = shData->dataref[i] / right;
00617         }
00618         return (*this);
00619     };
00624     DoubleVector& steady( unsigned int i ) {
00625 #ifdef FARSA_DEBUG
00626         if( i >= shData->vsize ) {
00627             throw OutsideVectorBoundaries("Fixating elements outside boundary");
00628         }
00629 #endif
00630         detach();
00631         shData->dataref[i].setSteady();
00632         return (*this);
00633     };
00637     DoubleVector& unsteady( unsigned int i ) {
00638 #ifdef FARSA_DEBUG
00639         if( i >= shData->vsize ) {
00640             throw OutsideVectorBoundaries("Un-Fixating elements outside boundary");
00641         }
00642 #endif
00643         detach();
00644         shData->dataref[i].setNoSteady();
00645         return (*this);
00646     };
00650     bool isSteady( unsigned int i ) const {
00651 #ifdef FARSA_DEBUG
00652         if( i >= shData->vsize ) {
00653             throw OutsideVectorBoundaries("isSteady - Accessing element outside boundary");
00654         }
00655 #endif
00656         return shData->dataref[i].isSteady();
00657     };
00661     DoubleVector& zeroing() {
00662         detach();
00663         for( unsigned int i=0; i<shData->vsize; i++ ) {
00664             shData->dataref[i] = 0;
00665         }
00666         return (*this);
00667     };
00671     DoubleVector& setAll( const double value ) {
00672         detach();
00673         for( unsigned int i=0; i<shData->vsize; i++ ) {
00674             shData->dataref[i] = value;
00675         }
00676         return (*this);
00677     };
00681     doubleRef& operator[]( unsigned int index ) {
00682 #ifdef FARSA_DEBUG
00683         if( index >= shData->vsize ) {
00684             throw OutsideVectorBoundaries("operator[] - Accessing elements outside boundary");
00685         }
00686 #endif
00687         detach();
00688         return shData->dataref[index];
00689     };
00693     double operator[]( unsigned int index ) const {
00694 #ifdef FARSA_DEBUG
00695         if( index >= shData->vsize ) {
00696             throw OutsideVectorBoundaries("operator[] - Accessing elements outside boundary");
00697         }
00698 #endif
00699         return shData->dataref[index];
00700     };
00702     DoubleVector& resize( unsigned int newsize ) {
00703         if ( shData->nodata || isinternal ) {
00704             throw VectorResizeNotAllowed();
00705         }
00706         detach();
00707         if ( newsize > shData->vsize ) {
00708             double* newdata = new double[newsize];
00709             memoryCopy( newdata, shData->data, shData->vsize );
00710             delete [](shData->data);
00711             delete [](shData->dataref);
00712             shData->data = newdata;
00713             shData->vsize = newsize;
00714             shData->dataref = new doubleRef[ newsize ];
00715             for( unsigned int i=0; i<shData->vsize; i++ ) {
00716                 shData->dataref[i].setRef( shData->data + i );
00717             }
00718         } else {
00719             shData->vsize = newsize;
00720         }
00721         return (*this);
00722     };
00724     DoubleVector& append( const double& value ) {
00725         //--- detach (and throw) done by resize
00726         resize( shData->vsize+1 );
00727         shData->data[ shData->vsize-1 ] = value;
00728         return (*this);
00729     };
00731     DoubleVector& operator<<( const double& value ) {
00732         //--- detach (and throw) done by resize (append)
00733         append( value );
00734         return (*this);
00735     };
00736 
00737 private:
00738     class sharedData {
00739     public:
00741         unsigned int vsize;
00743         double* data;
00745         int refcounts;
00747         doubleRef* dataref;
00749         bool temporary;
00751         bool nodata;
00752     };
00754     sharedData* shData;
00759     bool isinternal;
00760 
00761     friend class DoubleMatrix;
00767     void resizeNoData( unsigned int newsize ) {
00768         if ( shData->vsize > 0 ) {
00769             if ( shData->data ) { delete [](shData->data); }
00770             delete [](shData->dataref);
00771         }
00772         shData->vsize = newsize;
00773         shData->dataref = new doubleRef[ newsize ];
00774         shData->nodata = true;
00775         isinternal = true;
00776     };
00777 };
00778 
00779 }
00780 
00781 #endif