Brief description of class still missing. More...
#include <VoronoiNavigator.h>
Public Member Functions | |
QVector< int > | cellAt (const int *p) const |
QVector< int > | cellAt (const double *p) const |
int | cellCount () const |
void | cellLimits (int &xMin, int &xMax, int &iMin, int &iMax) |
void | checkAxisDistances () |
void | checkCurrentPoint () |
int | currentAxis () const |
int | currentCell () const |
void | incrementAxis () |
PdfCurve | intersections (double xMinLimit, double xMaxLimit) |
void | printCurrentPoint () |
void | setCurrentAxis (int a) |
void | setCurrentCell (int index) |
void | setCurrentPoint (int index) |
void | setCurrentPoint (const int *coordinates) |
void | setValue (int v) |
void | setValue (double v) |
VoronoiNavigator (const ScaledModels *m) | |
~VoronoiNavigator () |
Brief description of class still missing.
Full description of class still missing
Description of constructor still missing
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), and TRACE.
{ TRACE; _cells=m; _currentAxis=-1; _currentCell=-1; _axisDistances=new double [ _cells->modelCount() ]; _currentPoint=new double [ _cells->parameterCount() ]; }
QVector< int > DinverCore::VoronoiNavigator::cellAt | ( | const int * | p | ) | const |
Debug purpose, get the cells containing model.
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), DinverCore::ScaledModels::scale(), TRACE, and DinverCore::ScaledModels::v().
Referenced by checkCurrentPoint().
{ TRACE; QVector<int> belongs; double minDistance=1e99; int nm=_cells->modelCount(); int nd=_cells->parameterCount(); for(int im=0; im < nm; im++ ) { double distance=0.0, tmp; for(int id=0; id < nd; id++) { tmp=_cells->v(id)[im] - p[id] * _cells->scale(id); distance += tmp*tmp; } if(distance<minDistance) { belongs.clear(); belongs.append(im); minDistance=distance; } else if(distance==minDistance) { belongs.append(im); } } return belongs; }
QVector< int > DinverCore::VoronoiNavigator::cellAt | ( | const double * | p | ) | const |
Debug purpose, get the cells containing scaled model.
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), TRACE, and DinverCore::ScaledModels::v().
{ TRACE; QVector<int> belongs; double minDistance=1e99; int nm=_cells->modelCount(); int nd=_cells->parameterCount(); for(int im=0; im < nm; im++ ) { double distance=0.0, tmp; for(int id=0; id < nd; id++) { tmp=_cells->v(id)[im] - p[id]; distance += tmp*tmp; } if(distance<minDistance) { belongs.clear(); belongs.append(im); minDistance=distance; } else if(distance==minDistance) { belongs.append(im); } } return belongs; }
int DinverCore::VoronoiNavigator::cellCount | ( | ) | const [inline] |
{return _cells->modelCount();}
void DinverCore::VoronoiNavigator::cellLimits | ( | int & | xMin, |
int & | xMax, | ||
int & | iMin, | ||
int & | iMax | ||
) |
If Xj[i] is right on the cell border (between Vj and Vk),
2 * Xj[i] * s[i]^2 * (Vk[i] - Vj[i] )=(Vk[i]^2 - Vj[i]^2) * s[i]^2 + (dk^2 - dj^2)
Or,
2 * Xj[i] * s[i]=xLim/dx, dx includes the scaling
if xLim/(2*dx)<Pk[i]*s[i] && xLim/dx>xMin, move xMin to xLim/dx if xLim/(2*dx)>Pk[i]*s[i] && xLim/dx<xMax, move xMax to xLim/dx
Where Pk is the current point inside cell of Vk, hence,
xLim < 2 * s[i] * Pk[i] * dx
if dx>0, xLim/dx < 2 * s[i] * Pk[i] if dx<0, xLim/dx > 2 * s[i] * Pk[i]
We would like to postpone the division by dx only when the limits is really moved. hence, we multiply xMin and xMax by dx (division is approximately 5 times slower than multiplication). xMin and xMax are multiplied by 2 upon startup.
if dx>0, the conditions become:
if xLim/dx<2*Pk[i]*s[i] && xLim>xMin*dx, move xMin to xLim/dx (a) if xLim/dx>2*Pk[i]*s[i] && xLim<xMax*dx, move xMax to xLim/dx (b) (first condition of (b) is always false, of (a) is always true)
if dx<0, the conditions become:
if xLim/dx<2*Pk[i]*s[i] && xLim<xMin*dx, move xMin to xLim/dx (a) if xLim/dx>2*Pk[i]*s[i] && xLim>xMax*dx, move xMax to xLim/dx (b) (first condition of (a) is always false, of (b) is always true)
if dx==0, no intersection, hence skip
if dx>0, the conditions become:
if xLim>xMin*dx, move xMin to xLim/dx (a)
if dx<0, the conditions become:
if xLim>xMax*dx, move xMax to xLim/dx (b)
_currentCell is k, _axisDistances[ _currentCell ] is dk _axisDistances[ j ] is dj
Thus, we just test the sign of dx and we can directly compare to the current min and max of the cell.
iMin and iMax are set the cell indexes of the two neighbors crossed by the current axis (-1 if there are no neighbors).
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::scale(), TRACE, DinverCore::ScaledModels::v(), and DinverCore::ScaledModels::v2().
Referenced by DinverCore::Neighborhood::setVolumes().
{ TRACE; ASSERT(_currentAxis>-1); ASSERT(_currentCell>-1); const double * vp=_cells->v(_currentAxis); const double * v2p=_cells->v2(_currentAxis); double vk=vp[ _currentCell ]; double vk2dk2=v2p[ _currentCell ] + _axisDistances[ _currentCell ]; double xLim, dx; double s=_cells->scale(_currentAxis); double s2=2.0*s; double dxMin=(double)xMin*s2; double dxMax=(double)xMax*s2; iMin=-1; iMax=-1; int n=_cells->modelCount(); for(int j=0; j< n; j++ ) { dx=vk - vp[ j ]; xLim=vk2dk2 - (v2p[ j ] + _axisDistances[ j ] ); if(dx > 0.0) { if(xLim > dxMin * dx) { ASSERT(xLim>0); dxMin=xLim/dx; iMin=j; } } else if(dx < 0.0) { if(xLim > dxMax * dx) { ASSERT(xLim<0); dxMax=xLim/dx; iMax=j; } } } /* Distances to axes are updated incrementaly, which is likely to introduce some errors in the determination of dxMin and dxMax. By experience, the maximum relative error is of the order of 1e-16. This is negligible except when rounding limits to integers. By default, we keep as conservative as possible, hence limits are rounded with ceil and floor for xMin and xMax, respectively. If the current point, which is a valid model (fit with all conditions) and which has proved to belong to the current cell, is very close to the edge of the cell, the conservative rounding might consider the current point as outside. */ double invS=1.0/s; double invS2=0.5*invS; int pk=(int)round(_currentPoint[ _currentAxis ]*invS); if(iMin>-1) { dxMin*=invS2; xMin=(int) ceil(dxMin); if(pk==xMin-1) { xMin=pk; //App::stream() << tr("Adjust xMin limit to Pk(%1), dxMin=%2") // .arg(pk).arg(dxMin, 0, 'g', 20) << endl; } } if(iMax>-1) { dxMax*=invS2; xMax=(int) floor(dxMax); if(pk==xMax+1) { xMax=pk; //App::stream() << tr("Adjust xMax limit to Pk(%1), dxMax=%2") // .arg(pk).arg(dxMax, 0, 'g', 20) << endl; } } }
Brute comparison of current distance, check for precison leakage This function is strictly for debug purposes
References QGpCoreTools::endl(), DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), QGpCoreTools::tr(), TRACE, and DinverCore::ScaledModels::v().
{ TRACE; double d, dtot; double * dist=_axisDistances; int id; int nm=_cells->modelCount(); int nd=_cells->parameterCount(); for(int im=0;im<nm; im++ ) { dtot=0; for(id=0; id < _currentAxis; id++ ) { d=_currentPoint[ id ] - _cells->v(id)[im]; dtot += d * d; } for(id++; id < nd; id++ ) { d=_currentPoint[ id ] - _cells->v(id)[im]; dtot += d * d; } if(dtot > 0.0) { double relErr=( *dist - dtot)/dtot; if(fabs( relErr) > 1e-10) { App::stream() << tr( " Error in iterative square distance for model %1: %2\n" " iterative square distance=%3\n" " true square distance=%4" ) .arg(im).arg(relErr).arg(*dist).arg(dtot) << endl; } } else { if(fabs(*dist)>1e-15) { App::stream() << tr( " Error in iterative square distance for model %1:\n" " iterative square distance=%2\n" " true square distance=%3" ) .arg(im).arg(*dist).arg(dtot) << endl; } } dist++; } }
Check if current point belongs to current cell
References cellAt().
{ QVector<int> iGenModel=cellAt(_currentPoint); if( ! iGenModel.contains(_currentCell) ) { printf("Model effectively NOT generated in cell %i but:\n", _currentCell); for(QVector<int>::iterator it=iGenModel.begin(); it!=iGenModel.end(); it++) { printf("%i ", *it); } printf("\n" ); ASSERT(false); } }
int DinverCore::VoronoiNavigator::currentAxis | ( | ) | const [inline] |
Referenced by DinverCore::ImportanceSampling::generate(), and DinverCore::Neighborhood::setVolumes().
{return _currentAxis;}
int DinverCore::VoronoiNavigator::currentCell | ( | ) | const [inline] |
{return _currentCell;}
Increment axis and update the distances to new axis
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), TRACE, and DinverCore::ScaledModels::v().
Referenced by DinverCore::ImportanceSampling::generate(), and DinverCore::Neighborhood::setVolumes().
{ TRACE; ASSERT(_currentAxis>-1); double d; int newAxis=_currentAxis + 1; if(newAxis==_cells->parameterCount()) newAxis=0; double xcur=_currentPoint[ _currentAxis ]; double xnew=_currentPoint[ newAxis ]; double * dist=_axisDistances; int nm=_cells->modelCount(); for(int im=0;im<nm; im++ ) { d=xnew - _cells->v(newAxis)[im]; double& distVal=*dist; distVal -= d * d; d=xcur - _cells->v(_currentAxis)[im]; distVal += d * d; //fprintf(stdout,"Axis Dist=%8lg\n",sqrt(distVal)); dist++; } _currentAxis=newAxis; }
PdfCurve DinverCore::VoronoiNavigator::intersections | ( | double | xMin, |
double | xMax | ||
) |
The intersections are returned along current axis set by setAxis()
References QGpCoreTools::Curve< pointType >::append(), DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::scale(), QGpCoreTools::Curve< pointType >::setFunction(), DinverCore::ScaledModels::v(), and DinverCore::ScaledModels::v2().
Referenced by DinverCore::ImportanceSampling::generate().
{ ASSERT(_currentAxis>-1); ASSERT(_currentCell>-1); PdfCurve f; // f for the first cell, separate models into lower and higher (along axis) const double * vp=_cells->v(_currentAxis); const double * v2p=_cells->v2(_currentAxis); double vk=vp[_currentCell]; double vk2dk2=v2p[ _currentCell ] + _axisDistances[ _currentCell ]; double xLim, dx; double s=_cells->scale(_currentAxis); double s2=2.0*s; double dxMinLimit=xMin*s2; double dxMaxLimit=xMax*s2; double dxMin=dxMinLimit; double dxMax=dxMaxLimit; int n=_cells->modelCount(); int * lowerCells=new int [n]; int * higherCells=new int [n]; int nLowerCells=0, nHigherCells=0, iMin=-1, iMax=-1; for(int j=0; j< n; j++ ) { dx=vk - vp[ j ]; xLim=vk2dk2 - (v2p[ j ] + _axisDistances[ j ] ); if(dx > 0.0) { if(xLim > dxMin * dx) { ASSERT(xLim>0); dxMin=xLim/dx; iMin=j; } lowerCells[nLowerCells]=j; nLowerCells++; } else if(dx < 0.0) { if(xLim > dxMax * dx) { ASSERT(xLim<0); dxMax=xLim/dx; iMax=j; } higherCells[nHigherCells]=j; nHigherCells++; } } /*if(dxMin>=dxMax) { printf("dxMin %lf dxMax %lf\n",dxMin,dxMax); checkCurrentPoint(); ASSERT(false); }*/ int originalCell=_currentCell; double invS2=0.5/s; if(iMin>-1) { _currentCell=iMin; lowerIntersections(f, dxMinLimit, lowerCells, nLowerCells, invS2); } //App::stream() << "main append " << invS2*dxMin << " " << originalCell << endl; f.append(PdfPoint(invS2*dxMin, originalCell)); //App::stream() << "main append " << invS2*dxMax << " " << iMax << endl; f.append(PdfPoint(invS2*dxMax, iMax)); //ASSERT(f.count()>1); if(iMax>-1) { _currentCell=iMax; higherIntersections(f, dxMaxLimit, higherCells, nHigherCells, invS2); } _currentCell=originalCell; delete [] lowerCells; delete [] higherCells; f.setFunction(); //ASSERT(f.count()>1); return f; }
References DinverCore::ScaledModels::parameterCount(), and DinverCore::ScaledModels::scale().
{ int nd=_cells->parameterCount(); for(int id=0; id<nd; id++) { printf(" %lf",_currentPoint[id]/_cells->scale(id)); } printf("\n"); }
void DinverCore::VoronoiNavigator::setCurrentAxis | ( | int | a | ) |
Set current axis and calculate the square distances to axis to init the iterative computation implemented in incrementAxis(). The current pos must be initialized by setCurrentPos().
|Vk-Xj|=|Vj-Xj| defines the intersection of the cell boundary (between cells k and j) with the considered axis. k is the current cell.
Along the axis i, looking at the cell boundary between cells k and j:
dk^2 + (( Vk[i] - Xj[i] ) * s[i] )^2=dj^2 + (( Vj[i] - Xj[i] ) * s[i] )^2
dk^2 + (Vk[i] * s[i] )^2 + (Xj[i] * s[i] )^2 - 2 * Vk[i] * Xj[i] * s[i]^2 =dj^2 + (Vj[i] * s[i] )^2 + (Xj[i] * s[i] )^2 - 2 * Vj[i] * Xj[i] * s[i]^2
dk^2 + (Vk[i] * s[i] )^2=dj^2 + (Vj[i] * s[i] )^2 - 2 * s[i]^2 * Xj[i] (Vj[i] - Vk[i] )
where dk and dj are the distances from axis to centers of cells. Vk and Vj are the centers of cells k and j, respectively. Vk[i] is the ith coordinate of point Vk. s[i] is the scale along axis i.
2 * Xj[i] * s[i]^2 * (Vk[i] - Vj[i] )=(Vk[i]^2 - Vj[i]^2) * s[i]^2 + (dk^2 - dj^2)
Pre-calculates all dk and dj.
References DinverCore::ScaledModels::modelCount(), DinverCore::ScaledModels::parameterCount(), and DinverCore::ScaledModels::v().
Referenced by DinverCore::ImportanceSampling::generate(), and DinverCore::Neighborhood::setVolumes().
{ if(a==_cells->parameterCount()) a=0; _currentAxis=a; double d, dtot; double * dist=_axisDistances; int nm=_cells->modelCount(); int nd=_cells->parameterCount(); int id; for(int im=0;im<nm; im++ ) { dtot=0.0; for(id=0; id < _currentAxis; id++ ) { d=_currentPoint[ id ] - _cells->v(id)[im]; dtot += d * d; } for(id++; id < nd;id++ ) { d=_currentPoint[ id ] - _cells->v(id)[im]; dtot += d * d; } *(dist++ )=dtot; } }
void DinverCore::VoronoiNavigator::setCurrentCell | ( | int | index | ) | [inline] |
Referenced by DinverCore::ImportanceSampling::generate().
{_currentCell=index;}
void DinverCore::VoronoiNavigator::setCurrentPoint | ( | int | index | ) | [inline] |
References DinverCore::ScaledModels::parameterCount(), TRACE, and DinverCore::ScaledModels::v().
Referenced by DinverCore::ImportanceSampling::generate(), and DinverCore::Neighborhood::setVolumes().
{ TRACE; _currentCell=index; int nd=_cells->parameterCount(); for(int id=0; id < nd; id++ ) { _currentPoint[ id ]=_cells->v(id)[_currentCell]; } }
void DinverCore::VoronoiNavigator::setCurrentPoint | ( | const int * | coordinates | ) | [inline] |
References DinverCore::ScaledModels::parameterCount(), DinverCore::ScaledModels::scale(), and TRACE.
{ TRACE; _currentCell=-1; int nd=_cells->parameterCount(); for(int id=0; id < nd; id++ ) { _currentPoint[ id ]=_cells->scale(id) * coordinates[id]; } }
void DinverCore::VoronoiNavigator::setValue | ( | int | v | ) | [inline] |
Referenced by DinverCore::ImportanceSampling::generate().
{_currentPoint[ _currentAxis ]=v * _cells->scale(_currentAxis);}
void DinverCore::VoronoiNavigator::setValue | ( | double | v | ) | [inline] |
{_currentPoint[ _currentAxis ]=v * _cells->scale(_currentAxis);}