00001 #include "saupePredictor.h"
00002 #include "stdDomains.h"
00003 using namespace std;
00004
00005 IStdEncPredictor::IOneRangePredictor* MSaupePredictor
00006 ::newPredictor(const NewPredictorData &data) {
00007
00008 int level= data.rangeBlock->level;
00009 if ( level >= (int)levelTrees.size() )
00010 levelTrees.resize( level+1, (Tree*)0 );
00011
00012 Tree *tree= levelTrees[level];
00013 if (!tree)
00014 tree= levelTrees[level]= createTree(data);
00015 ASSERT(tree);
00016
00017 int maxPredicts= (int)ceil(maxPredCoeff()*tree->count);
00018 if (maxPredicts<=0)
00019 maxPredicts= 1;
00020 OneRangePredictor *result=
00021 new OneRangePredictor( data, settingsInt(ChunkSize), *tree, maxPredicts );
00022
00023 #ifndef NDEBUG // collecting debugging stats
00024 maxpred+= tree->count*(data.allowRotations?8:1)*(data.allowInversion?2:1);
00025 result->predicted= &predicted;
00026 #endif
00027
00028 return result;
00029 }
00030
00031 namespace MatrixWalkers {
00033 template<class T,class I> Checked<T,I> makeLinearizer(T* start,I inCount,I outCount) {
00034 return Checked<T,I>
00035 ( MatrixSlice<T,I>::makeRaw(start,inCount), Block(0,0,outCount,inCount) );
00036 }
00037
00040 template < class SumT, class PixT, class I >
00041 struct SumWalker {
00042 SummedMatrix<SumT,PixT,I> matrix;
00043 I width, height, y0;
00044 I x, y;
00045
00046
00047 void outerStep() { x+= width; }
00048
00049 void innerInit() { y= y0; }
00050
00051 void innerStep() { y+= height; }
00052
00053 SumT get() { return matrix.getValueSum(x,y,x+width,y+height); }
00054 };
00057 template < class SumT, class PixT, class I >
00058 SumWalker<SumT,PixT,I> makeSumWalker
00059 ( const SummedMatrix<SumT,PixT,I> &matrix, I x0, I y0, I inLevel, I outLevel ) {
00060 ASSERT( x0>=0 && y0>=0 && inLevel>=0 && outLevel>=0 && inLevel>=outLevel );
00061 SumWalker<SumT,PixT,I> result;
00062 result.matrix= matrix;
00063 result.width= result.height= powers[inLevel-outLevel];
00064 result.y0= y0;
00065
00066
00067 result.x= x0;
00068 DEBUG_ONLY( result.y= numeric_limits<I>::max(); )
00069 return result;
00070 }
00071
00074 template<class T,class I=PtrInt,class R=Real>
00075 struct HalfShrinkerMul: public HalfShrinker<T,I> { ROTBASE_INHERIT
00076 R toMul;
00077
00078 HalfShrinkerMul( TMatrix matrix, R toMul_, I x0=0, I y0=0 )
00079 : HalfShrinker<T,I>(matrix,x0,y0), toMul(toMul_) {}
00080
00081 T get() {
00082 TMatrix &c= current;
00083 T *cs= c.start;
00084 return toMul * ( cs[0] + cs[1] + cs[c.colSkip] + cs[c.colSkip+1] );
00085 }
00086 };
00087 }
00088 namespace NOSPACE {
00089 typedef MSaupePredictor::KDReal KDReal;
00092 inline static void refineBlock( const SummedPixels &pixMatrix, int x0, int y0
00093 , int predWidth, int predHeight, Real multiply, Real avg
00094 , int realLevel, int predLevel, SReal *pixelResult ) {
00095 using namespace MatrixWalkers;
00096
00097 int levelDiff= realLevel-predLevel;
00098 if (levelDiff)
00099 multiply= ldexp(multiply,-2*levelDiff);
00100 ASSERT( finite(multiply) && finite(avg) );
00101
00102 AddMulCopy<Real> oper( -avg, multiply );
00103 Checked<KDReal> linWalker= makeLinearizer(pixelResult,predWidth,predHeight);
00104
00105 if (levelDiff==0)
00106 walkOperate( linWalker, Rotation_0<SReal>(pixMatrix.pixels,x0,y0), oper );
00107 else if (levelDiff==1)
00108 walkOperate( linWalker
00109 , HalfShrinkerMul<SReal>(pixMatrix.pixels,multiply,x0,y0), oper );
00110 else
00111 walkOperate( linWalker
00112 , makeSumWalker(pixMatrix,x0,y0,realLevel,predLevel), oper );
00113 }
00114 }
00115 void MSaupePredictor::refineDomain( const SummedPixels &pixMatrix, int x0, int y0
00116 , bool allowInversion, int realLevel, int predLevel, SReal *pixelResult ) {
00117
00118 int realSide= powers[realLevel];
00119 Real sum, sum2;
00120 pixMatrix.getSums(x0,y0,x0+realSide,y0+realSide).unpack(sum,sum2);
00121 Real avg= ldexp(sum,-2*realLevel);
00122
00123 Real multiply= 1 / sqrt( sum2 - sqr(ldexp(sum,-realLevel)) );
00124 if ( !finite(multiply) )
00125 multiply= 1;
00126
00127 if ( allowInversion && pixMatrix.pixels[x0][y0] < avg )
00128 multiply= -multiply;
00129
00130 int predSide= powers[predLevel];
00131 refineBlock( pixMatrix, x0, y0, predSide, predSide, multiply, avg
00132 , realLevel, predLevel, pixelResult );
00133 }
00134 void MSaupePredictor::refineRange
00135 ( const NewPredictorData &data, int predLevel, SReal *pixelResult ) {
00136 const ISquareRanges::RangeNode &rb= *data.rangeBlock;
00137 Real avg, multiply;
00138 if ( data.isRegular || predLevel==rb.level ) {
00139
00140 avg= data.rSum/data.pixCount;
00141 multiply= ( data.isRegular ? powers[rb.level] : sqrt(data.pixCount) ) / data.rnDev;
00142 } else {
00143
00144 int mask= powers[rb.level-predLevel]-1;
00145 int adjWidth= rb.width() & mask;
00146 int adjHeight= rb.height() & mask;
00147 int pixCount= adjWidth*adjHeight;
00148 if (pixCount==0)
00149 return;
00150
00151 Real sum, sum2;
00152 data.rangePixels->getSums( rb.x0, rb.y0, rb.x0+adjWidth, rb.y0+adjHeight )
00153 .unpack(sum,sum2);
00154 avg= sum/pixCount;
00155 multiply= 1 / sqrt( sum2 - sqr(sum)/pixCount );
00156 }
00157
00158 int levelDiff= rb.level-predLevel;
00159 refineBlock( *data.rangePixels, rb.x0, rb.y0
00160 , rShift(rb.width(),levelDiff), rShift(rb.height(),levelDiff)
00161 , multiply, avg, rb.level, predLevel, pixelResult );
00162 }
00163
00164 MSaupePredictor::Tree* MSaupePredictor::createTree(const NewPredictorData &data) {
00165
00166 const ISquareEncoder::LevelPoolInfos::value_type &poolInfos= *data.poolInfos;
00167 const int domainCount= poolInfos.back().indexBegin
00168 , realLevel= data.rangeBlock->level
00169 , predLevel= getPredLevel(realLevel)
00170 , realSide= powers[realLevel]
00171 , predPixCount= powers[2*predLevel];
00172 ASSERT(realLevel>=predLevel);
00173
00174 KDReal *domPix= new KDReal[ domainCount * predPixCount ];
00175
00176 KDReal *domPixNow= domPix;
00177 int poolCount= data.pools->size();
00178 for (int poolID=0; poolID<poolCount; ++poolID) {
00179
00180 ASSERT( domPixNow-domPix == poolInfos[poolID].indexBegin*predPixCount );
00181 const ISquareDomains::Pool &pool= (*data.pools)[poolID];
00182 int density= poolInfos[poolID].density;
00183 if (!density)
00184 continue;
00185 int poolXend= density*getCountForDensity( pool.width, density, realSide );
00186 int poolYend= density*getCountForDensity( pool.height, density, realSide );
00187
00188 for (int x0=0; x0<poolXend; x0+=density)
00189 for (int y0=0; y0<poolYend; y0+=density) {
00190 refineDomain( pool, x0, y0, data.allowInversion, realLevel, predLevel, domPixNow );
00191 domPixNow+= predPixCount;
00192 }
00193 }
00194 ASSERT( domPixNow-domPix == domainCount*predPixCount );
00195
00196 Tree *result= Tree::Builder
00197 ::makeTree( domPix, predPixCount, domainCount, &Tree::Builder::chooseApprox );
00198
00199 delete[] domPix;
00200 return result;
00201 }
00202
00203 namespace MatrixWalkers {
00205 template<class T> struct AddMulCopyTo2nd {
00206 T toAdd, toMul;
00207
00208 AddMulCopyTo2nd(T add,T mul)
00209 : toAdd(add), toMul(mul) {}
00210
00211 template<class R1,class R2> void operator()(R1 f,R2 &res) const
00212 { res= (f+toAdd)*toMul; }
00213 void innerEnd() const {}
00214 };
00216 struct Assigner: public OperatorBase {
00217 template<class R1,class R2> void operator()(const R1 &src,R2 &dest) const
00218 { dest= src; }
00219 };
00221 struct SignChanger {
00222 template<class R1,class R2> void operator()(R1 src,R2 &dest) const
00223 { dest= -src; }
00224 };
00225 }
00226 MSaupePredictor::OneRangePredictor::OneRangePredictor
00227 ( const NewPredictorData &data, int chunkSize_, const Tree &tree, int maxPredicts )
00228 : chunkSize(chunkSize_), predsRemain(maxPredicts)
00229 , firstChunk(true), allowRotations(data.allowRotations), isRegular(data.isRegular)
00230 {
00231
00232 int rotationCount= allowRotations ? 8 : 1;
00233 heapCount= rotationCount * (data.allowInversion ? 2 : 1);
00234 points= new KDReal[tree.length*heapCount];
00235
00236
00237 if (!isRegular)
00238 fill( points, points+tree.length, numeric_limits<KDReal>::quiet_NaN() );
00239
00240
00241 int predLevel= log2ceil(tree.length)/2;
00242 int predSideLen= powers[predLevel];
00243 ASSERT( powers[2*predLevel] == tree.length );
00244
00245 errorNorm.initialize(data,predLevel);
00246
00247 refineRange( data, predLevel, points );
00248
00249
00250 if (allowRotations) {
00251 using namespace MatrixWalkers;
00252
00253 Checked<KDReal> refBlockWalker= makeLinearizer( points, predSideLen, predSideLen );
00254
00255 MatrixSlice<KDReal> rotMatrix= MatrixSlice<KDReal>::makeRaw(points,predSideLen);
00256 Block shiftedBlock( 0, 0, predSideLen, predSideLen );
00257
00258 for (int rot=1; rot<rotationCount; ++rot) {
00259 rotMatrix.start+= tree.length;
00260 walkOperateCheckRotate
00261 ( refBlockWalker, Assigner(), rotMatrix, shiftedBlock, rot );
00262 }
00263 ASSERT( rotMatrix.start == points+tree.length*(rotationCount-1) );
00264 }
00265
00266
00267 if (data.allowInversion) {
00268 KDReal *pointsMiddle= points+tree.length*rotationCount;
00269 FieldMath::transform2
00270 ( points, pointsMiddle, pointsMiddle, MatrixWalkers::SignChanger() );
00271 }
00272
00273
00274 heaps.reserve(heapCount);
00275 infoHeap.reserve(heapCount);
00276 for (int i=0; i<heapCount; ++i) {
00277 PointHeap *heap= new PointHeap( tree, points+i*tree.length, !data.isRegular );
00278 heaps.push_back(heap);
00279 infoHeap.push_back(HeapInfo( i, heap->getTopSE() ));
00280 }
00281
00282 make_heap( infoHeap.begin(), infoHeap.end() );
00283 }
00284
00285 MSaupePredictor::Predictions& MSaupePredictor::OneRangePredictor
00286 ::getChunk(float maxPredictedSE,Predictions &store) {
00287 ASSERT( PtrInt(heaps.size())==heapCount && PtrInt(infoHeap.size())<=heapCount );
00288 if ( infoHeap.empty() || predsRemain<=0 ) {
00289 store.clear();
00290 return store;
00291 }
00292
00293 int predCount= chunkSize;
00294 if (firstChunk) {
00295 firstChunk= false;
00296 if (heapCount>predCount)
00297 predCount= heapCount;
00298 }
00299
00300 if (predCount>predsRemain)
00301 predCount= predsRemain;
00302 predsRemain-= predCount;
00303
00304 float maxNormalizedSE= errorNorm.normSE(maxPredictedSE);
00305
00306 Predictions result;
00307 swap(result,store);
00308 result.resize(predCount);
00309
00310 for (Predictions::iterator it=result.begin(); it!=result.end(); ++it) {
00311 pop_heap( infoHeap.begin(), infoHeap.end() );
00312 HeapInfo &bestInfo= infoHeap.back();
00313
00314 if ( bestInfo.bestError > maxNormalizedSE ) {
00315 result.erase( it, result.end() );
00316 infoHeap.clear();
00317 break;
00318 }
00319
00320 ASSERT( 0<=bestInfo.index && bestInfo.index<heapCount );
00321 PointHeap &bestHeap= *heaps[bestInfo.index];
00322 it->domainID= isRegular
00323 ? bestHeap.popLeaf<false>(maxNormalizedSE)
00324 : bestHeap.popLeaf<true>(maxNormalizedSE);
00325 it->rotation= allowRotations ? bestInfo.index%8 : 0;
00326
00327 if ( !bestHeap.isEmpty() ) {
00328
00329 bestInfo.bestError= bestHeap.getTopSE();
00330 push_heap( infoHeap.begin(), infoHeap.end() );
00331 } else {
00332 infoHeap.pop_back();
00333
00334 if ( infoHeap.empty() )
00335 break;
00336 }
00337 }
00338
00339 swap(result,store);
00340
00341 #ifndef NDEBUG
00342 *predicted+= store.size();
00343 #endif
00344
00345 return store;
00346 }