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