All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines
Public Member Functions
DinverCore::Neighborhood Class Reference

Brief description of class still missing. More...

#include <Neighborhood.h>

List of all members.

Public Member Functions

int activeModelCount () const
double bestIterationMisfit () const
int bestModelCount () const
int bestModelIndex () const
uint checksum () const
void clear ()
AbstractForwardforward ()
const AbstractForwardforward () const
int giveUpCount () const
bool importModels (QString fileName, bool strict=true)
void lock () const
double misfit (int modelIndex) const
const int * model (int modelIndex) const
 Neighborhood ()
bool openReport (const QString &fileName)
bool operator== (const Neighborhood &o) const
bool optimization (int ns=50, int nw=2)
bool random (int ns=50, int nw=2)
int rejectedCount () const
void setForward (AbstractForward *forward)
void setGiveUp (double giveUp)
void setMaximumSavedMisfit (double m)
void setNr (int nr)
void setSeed (int seed)
void setStorage ()
bool setThreadCount (int nThreads)
bool setVolumes ()
void sleep ()
void start (int itmax=50, int ns0=50, int ns=50, int nr=50)
void terminate (bool t=true)
void timeReport () const
void unlock () const
int validModelCount () const
const ParametervariableParameter (int paramIndex) const
int variableParameterCount () const
double variableParameterValue (int modelIndex, int paramIndex) const
int visitedModelCount () const
void wake ()
 ~Neighborhood ()

Detailed Description

Brief description of class still missing.

Full description of class still missing


Constructor & Destructor Documentation

Description of constructor still missing

References TRACE.

{
  TRACE;
  _allModels=0;
  _activeModels=0;
  _bestModels=0;
  _originalBestModels=0;
  _generator=new UniqueRandom(0);

  _report=0;
  _parameterSpaceChecksum=0;

  _giveUp=0.9;

  _deadCount=0;
  _giveUpCount=0;
  _rejectedCount=0;
  _maxModelCount=0;
  _maximumSavedMisfit=1e99; // by default no limit
}

Destructor. First forward object is not deleted. Assert that sleep() was called.

References TRACE.

{
  TRACE;
  delete _allModels;
  delete _activeModels;
  delete _bestModels;
  delete _generator;
  delete _report;
  ASSERT(_forwards.count()<2);
}

Member Function Documentation

References DinverCore::ActiveModels::count().

{
  return _activeModels ? _activeModels->count() : 0;
}
{return _iterationMinimumMisfit;}

References DinverCore::BestModels::count().

{
  return _bestModels ? _bestModels->count() : 0;
}

References DinverCore::ModelSet::bestModel().

Referenced by main(), and ToolNR::optimizeStack().

{
  // TODO: multi-dimensional misfit
  return _allModels->bestModel();
}
uint DinverCore::Neighborhood::checksum ( ) const [inline]
{return _parameterSpaceChecksum;}

References DinverCore::ActiveModels::clear(), DinverCore::BestModels::clear(), DinverCore::ModelSet::clear(), and TRACE.

{
  TRACE;
  _deadCount=0;
  _giveUpCount=0;
  _rejectedCount=0;
  _maxModelCount=0;
  _allModels->clear();
  _activeModels->clear();
  _bestModels->clear();
}
{return _forwards.isEmpty() ? 0 : _forwards.first();}
{return _forwards.isEmpty() ? 0 : _forwards.first();}
int DinverCore::Neighborhood::giveUpCount ( ) const [inline]
{return _giveUpCount;}
bool DinverCore::Neighborhood::importModels ( QString  fileName,
bool  strict = true 
)

References DinverCore::ActiveModels::add(), DinverCore::BestModels::add(), DinverCore::ActiveModels::count(), DinverCore::ModelSet::count(), DinverCore::ModelSet::importModels(), and TRACE.

{
  TRACE;
  int i=_allModels->count();
  if(!_allModels->importModels(forward()->parameterSpace(), fileName, strict)) {
    return false;
  }
  int n=_allModels->count();
  for(;i<n;i++) {
    _activeModels->add(i);
    _bestModels->add(_activeModels->count()-1);
  }
  return true;
}

Used only by external objects to acces generated models (read only)

References DinverCore::ModelSet::lock().

{
  if(_allModels) {
    _allModels->lock();
  }
}
double DinverCore::Neighborhood::misfit ( int  modelIndex) const

References DinverCore::ModelSet::misfit().

Referenced by main(), and ToolNR::optimizeStack().

{
  // TODO: multi-dimensional misfit
  return _allModels ? _allModels->misfit(modelIndex)[0] : 0;
}
const int * DinverCore::Neighborhood::model ( int  modelIndex) const

References DinverCore::ModelSet::model().

Referenced by ToolNR::optimizeStack(), and setThreadCount().

{
  return _allModels->model(modelIndex);
}
bool DinverCore::Neighborhood::openReport ( const QString &  fileName)

Initialize report. Can be called at any time.

References QGpCoreTools::endl(), DinverCore::ReportWriter::open(), and QGpCoreTools::tr().

Referenced by main().

{
  if( !fileName.isEmpty()) {
    delete _report;
    _report=new ReportWriter(fileName);
    if( !_report->open()) {
      App::stream() << tr("Cannot open report %1 for writing").arg(fileName) << endl;
      delete _report;
      _report=0;
      return false;
    }
  }
  return true;
}
bool DinverCore::Neighborhood::operator== ( const Neighborhood o) const
{
  return _forwards.first()->parameterSpace()==o._forwards.first()->parameterSpace();
}
bool DinverCore::Neighborhood::optimization ( int  ns = 50,
int  nw = 2 
)

Generates ns new samples with a Neighborhood Algorithm. Returns false if the inversion stops for an error

References DinverCore::ActiveModels::count(), DinverCore::BestModels::count(), QGpCoreTools::endl(), DinverCore::AbstractForward::generate(), DinverCore::AbstractForward::initGenerate(), DinverCore::ActiveModels::model(), DinverCore::BestModels::modelIndex(), DinverCore::ModelSet::parameterCount(), DinverCore::AbstractForward::parameterSpace(), DinverCore::ActiveModels::reserve(), DinverCore::BestModels::reserve(), DinverCore::ModelSet::reserve(), DinverCore::Parameter::setGridValue(), QGpCoreTools::tr(), TRACE, DinverCore::UniqueRandom::uniform(), DinverCore::AbstractForward::unlock(), DinverCore::BestModels::update(), and DinverCore::RealSpace::variableParameter().

Referenced by start().

{
  TRACE;
  QTime chrono;
  chrono.start();
  _iterationMinimumMisfit=1e99;
  if(_bestModels->count()==0) {  // Still no best model ... something wrong
    App::stream() << tr("No model in parameter space, cannot run iteration. Generate random models or import models.") << endl;
    return true;
  }

  // Complete if possible best models list to its maximum item count
  _bestModels->update();
  /*
     Reserve space for new models that will be generated to avoid locking for capacity increases.
     For _allmodels there might be much more than ns models added during this iteration hence
     locking is still necessary.
  */
  _bestModels->reserve(ns); // in the extreme case all generated models will be added to best models
                            // in a minimum misfit inversion, increasing the total number of best
                            // models by ns.
  _activeModels->reserve(ns);
  _allModels->reserve(2*ns);

  int ndVar=_allModels->parameterCount();
  int effectiveNr=_bestModels->count();
  enum Distribution {Ordered, Random};
  Distribution sampleDistribution=(effectiveNr>ns) ? Random : Ordered;
  int curCell=-1;
  ScaledModels scaledModels(_activeModels, scales());
  // Initialize the forward threads
  foreach(AbstractForward * f, _forwards) {
    f->initGenerate(&scaledModels, nw);
  }
  // Make a copy of _bestModels to avoid its modification while generating new cells
  _originalBestModels=new BestModels( *_bestModels);

  int timeStart=chrono.elapsed();
  _timeStartEnd+=timeStart;
  _maxModelCount=_activeModels->count() + ns;
  while(_activeModels->count()<_maxModelCount) {
    AbstractForward * forward=nextForward();
    if(terminated()) {
      if(forward) { // In case of unthreaded forward, the state is currently running
        forward->unlock();
      }
      return optimizationEnd(false);
    }
    ASSERT(forward);
    // Check if there are still enough best models, some of them might be lost if models
    // are rejected or in case of atomic cells
    if(_originalBestModels->count() < effectiveNr) {
      _originalBestModels->update();
    }
    switch(sampleDistribution) {
    case Ordered:
      curCell++;
      if(curCell>=effectiveNr) curCell=0;
      break;
    case Random:
      curCell=_generator->uniform(0, effectiveNr-1);
      break;
    }
    int modelIndex=_originalBestModels->modelIndex(curCell);
    // Copy model to param structure to enable condition testing
    const int * v=_activeModels->model(modelIndex);
    RealSpace& parameterSpace=forward->parameterSpace();
    for(int ip=0;ip < ndVar;ip++ ) {
      parameterSpace.variableParameter(ip)->setGridValue(v[ip] );
    }
    if(!forward->generate(modelIndex)) {
      break;
    }
  }
  int timeEnd=chrono.elapsed();
  _deadCount += removeDeadModels();
  _timeStartEnd+=chrono.elapsed()-timeEnd;
  _timeTotal+=chrono.elapsed();
  return optimizationEnd(true);
}
bool DinverCore::Neighborhood::random ( int  ns = 50,
int  nw = 2 
)

Generate ns random models

References DinverCore::ActiveModels::count(), DinverCore::AbstractForward::generate(), DinverCore::AbstractForward::initGenerate(), and TRACE.

Referenced by start().

{
  TRACE;
  QTime chrono;
  chrono.start();
  _iterationMinimumMisfit=1e99;
  _maxModelCount=_activeModels->count() + ns;
  // Initialize the forward threads
  foreach(AbstractForward * f, _forwards) {
    f->initGenerate(0, nw);
  }

  while(_activeModels->count()<_maxModelCount) {
    if(terminated()) {
      stopForwards();
      return false;
    }
    AbstractForward * f=nextForward();
    if(f) {
      if(!f->generate()) {
        break;
      }
    }
  }
  stopForwards();
  _timeTotal+=chrono.elapsed();
  return true;
}            
{return _rejectedCount;}

Set the forward object in charge of forward computation. Can be called only once. forward can be uninitialized (number of variable parameters).

References TRACE.

Referenced by main(), and ToolNR::optimizeStack().

{
  TRACE;
  ASSERT(_forwards.count()==0);
  // There is always at least one thread, create it
  _forwards.append(forward);
}
void DinverCore::Neighborhood::setGiveUp ( double  giveUp) [inline]
{_giveUp=giveUp;}
{_maximumSavedMisfit=m;}

References QGpCoreTools::endl(), DinverCore::BestModels::setNr(), and QGpCoreTools::tr().

Referenced by start().

{
  if(nr < 1) {
    App::stream() << tr("nr is less than 1, ignoring") << endl;
  } else {
    _bestModels->setNr(nr);
  }
}

If seed is null, a random number is calculated from current time.

References QGpCoreTools::endl(), and QGpCoreTools::tr().

{
  if(_forwards.isEmpty() || _forwards.first()->isSleeping()) {
    delete _generator;
    _generator=new UniqueRandom(seed);
    if( !_forwards.isEmpty()) _forwards.first()->setGenerator(_generator);
  } else {
    App::stream() << tr("Cannot change the random seed of a running inversion, first terminate it.") << endl;
  }
}

Initialize the model list, random generator, list of best models. The forward object must be initialized (number of variable parameters). Can be called only once.

Referenced by start().

{
  ASSERT(_forwards.count()==1);
  ASSERT( !_allModels && !_activeModels && !_bestModels);
  int ndVar=_forwards.first()->parameterSpace().variableParameterCount();
  // TODO: generalized multi-dimensional misfit
  _allModels=new ModelSet(ndVar, 1);
  _activeModels=new ActiveModels(_allModels);
  _bestModels=new BestModels (_activeModels);
}

If there is no model currently in list, it generates a random model without checking conditions between parameters limits. In a second step, the model is adjusted until matching all conditions of the parameter space.

References DinverCore::RealSpace::adjustRanges(), DinverCore::AbstractForward::clone(), DinverCore::AbstractForward::copyValues(), DinverCore::ActiveModels::count(), DinverCore::BestModels::count(), DinverCore::RealSpace::isOkDebug(), DinverCore::BestModels::model(), model(), DinverCore::AbstractForward::parameterSpace(), DinverCore::AbstractForward::setAllModels(), DinverCore::AbstractForward::setFinishSignal(), DinverCore::AbstractForward::setGenerator(), DinverCore::Parameter::setGridValue(), DinverCore::RealSpace::setVariableParameters(), TRACE, DinverCore::UniqueRandom::uniform(), DinverCore::RealSpace::variableParameter(), DinverCore::RealSpace::variableParameterCount(), and DinverCore::AbstractForward::wake().

Referenced by start().

{
  TRACE;
  QTime chrono;
  chrono.start();
  ASSERT(_forwards.count()==1);
  AbstractForward * refForward=_forwards.first();
  if(nThreads>CoreApplication::instance()->maximumThreadCount()) {
    nThreads=CoreApplication::instance()->maximumThreadCount();
  }
  if(nThreads>refForward->maximumThreadCount()) {
    nThreads=refForward->maximumThreadCount();
  }
  if(nThreads<1) nThreads=1;

  // Get the checksum of the parameterization
  _parameterSpaceChecksum=refForward->parameterSpace().checksum();

  refForward->setFinishSignal(&_forwardSignal);
  refForward->setGenerator(_generator);
  refForward->setAllModels(_allModels);
  if(_activeModels->count()==0) {
    if( ! refForward->firstModel()) {
      return false;
    }
  } else {
    // Load one of the best models into refForward
    RealSpace& parameterSpace=refForward->parameterSpace();
    int ndVar=parameterSpace.variableParameterCount();
    const int * model=_bestModels->model(_generator->uniform(0, _bestModels->count()-1) );
    for(int ip=0;ip < ndVar;ip++ ) {
      parameterSpace.variableParameter(ip)->setGridValue(model[ip] );
    }
    // Some parametrizations may need some updates before proceeding
    refForward->valueChanged();
    // Check validity of exisiting best models
    if( !parameterSpace.isOkDebug()) {
      return false;
    }
  }

  // Init all forwards with this first model
  //refForward->redirectStream();
  for(int i=1;i<nThreads; i++) {
    AbstractForward * f=refForward->clone();
    //f->redirectStream();
    f->setFinishSignal(&_forwardSignal);
    f->setGenerator(_generator);
    f->setAllModels(_allModels);
    RealSpace& parameterSpace=f->parameterSpace();
    parameterSpace.setVariableParameters();
    parameterSpace.adjustRanges(); // Assumed to be ok, because checked before for the first one
    _forwards.append(f);
    // Init first model for f
    f->copyValues( *refForward);
    // Activate this new forward thread
    f->wake();
  }
  _timeTotal+=chrono.elapsed();
  return true;
}

Initialize the volumes of all active models. It must be called before first optimization. Currenly not used.

References QGpCoreTools::abs(), DinverCore::VoronoiNavigator::cellLimits(), DinverCore::ActiveModels::count(), DinverCore::VoronoiNavigator::currentAxis(), DinverCore::Parameter::getGridLimits(), iModel, DinverCore::VoronoiNavigator::incrementAxis(), DinverCore::VoronoiNavigator::setCurrentAxis(), DinverCore::VoronoiNavigator::setCurrentPoint(), TRACE, DinverCore::RealSpace::variableParameter(), and DinverCore::RealSpace::variableParameterCount().

Referenced by start().

{
  TRACE;
  RealSpace& parameterSpace=_forwards.first()->parameterSpace();
  int ndVar=parameterSpace.variableParameterCount();
  ScaledModels scaledModels(_activeModels, scales());
  VoronoiNavigator nav(&scaledModels);
  int nModels=_activeModels->count();
  int xMin, xMax, iMin, iMax;
  for(int iModel=0;iModel<nModels; iModel++) {
    if(terminated()) {
      return false;
    }
    double volume=1.0;
    nav.setCurrentPoint(iModel);
    nav.setCurrentAxis(ndVar-1);
    for(int id=0; id<ndVar; id++) {
      nav.incrementAxis();
      Parameter * p=parameterSpace.variableParameter(nav.currentAxis());
      p->getGridLimits(xMin, xMax);
      nav.cellLimits(xMin, xMax, iMin, iMax);
      volume*=abs(xMax-xMin)+1;
    }
    //_allModels->setVolume(_activeModels->at(iModel).modelIndex(), volume);
  }
  return true;
}

References DinverCore::AbstractForward::sleep(), and TRACE.

Referenced by start().

{
  TRACE;
  // Remove all but one forward thread
  while(_forwards.count()>1) {
    AbstractForward * f=_forwards.last();
    f->sleep();
    delete f;
    _forwards.pop_back();
  }
  _forwards.first()->sleep();
}
void DinverCore::Neighborhood::start ( int  itmax = 50,
int  ns0 = 50,
int  ns = 50,
int  nr = 50 
)

For convenience, starts the inversion in current thread with the number of available threads. It does not return before the end. For specific applications, use the general interface.

References DinverCore::RealSpace::adjustRanges(), QGpCoreTools::endl(), DinverCore::RealSpace::humanInfo(), optimization(), random(), setNr(), setStorage(), setThreadCount(), DinverCore::RealSpace::setVariableParameters(), setVolumes(), sleep(), QGpCoreTools::tr(), TRACE, and wake().

Referenced by main(), and ToolNR::optimizeStack().

{
  TRACE;
  RealSpace& ps=_forwards.first()->parameterSpace();
  ps.setVariableParameters();
  if(!ps.adjustRanges()) {
    App::stream() << tr("Error adjusting ranges") << endl;
    return;
  }
  ps.humanInfo();
  App::stream() << tr("\nStarting %1 iterations\n").arg(itmax) << endl;
  if( !_allModels) {
    setStorage();
  }
  setNr(nr);
  wake();
  setThreadCount(Thread::idealThreadCount());
  random(ns0);
  setVolumes();
  for(int i=0; i< itmax; i++) {
    App::stream() << tr("Iteration %1").arg(i) << endl;
    optimization(ns);
  }
  sleep();
}
void DinverCore::Neighborhood::terminate ( bool  t = true)

References DinverCore::AbstractForward::abort(), and DinverCore::ForwardSignal::finished().

{
  _terminated.fetchAndStoreOrdered(t);
  if(t) {
    foreach(AbstractForward * f, _forwards) {
      f->abort();
    }
    _forwardSignal.finished(0);
  }
}

Report timing (must be called before sleep() to get reports about forward threads)

References QGpCoreTools::endl(), QGpCoreTools::tr(), and TRACE.

{
  TRACE;
  App::stream() << tr("\nTiming report\n"
                "--------------\n") << endl;
  App::stream() << tr("Waiting for forward threads: %1 ms").arg(_timeMainWait) << endl;
  App::stream() << tr("Adding new models: %1 ms").arg(_timeAdd) << endl;
  App::stream() << tr("Iteration init&cleanup: %1 ms").arg(_timeStartEnd) << endl;
  int n=_forwards.count();
  for(int i=0; i<n; i++) {
    App::stream() << tr("Foward computations[thread %1]:\n").arg(i+1);
    _forwards[i]->timeReport("  ");
  }
  App::stream() << tr("Total: %1 ms").arg(_timeTotal) << endl;
}

Used only by external objects to acces generated models (read only)

References DinverCore::ModelSet::unlock().

{
  if(_allModels) {
    _allModels->unlock();
  }
}

References DinverCore::ActiveModels::count().

Referenced by main().

{
  return (_activeModels ? _activeModels->count() : 0) + _deadCount;
}
const Parameter * DinverCore::Neighborhood::variableParameter ( int  paramIndex) const

References DinverCore::RealSpace::variableParameter().

Referenced by variableParameterValue().

{
  const RealSpace& parameterSpace=_forwards.first()->parameterSpace();
  return parameterSpace.variableParameter(paramIndex);
}

References DinverCore::ModelSet::parameterCount().

{
  return _allModels ? _allModels->parameterCount() : 0;
}
double DinverCore::Neighborhood::variableParameterValue ( int  modelIndex,
int  paramIndex 
) const

References DinverCore::ModelSet::model(), DinverCore::Parameter::realValue(), and variableParameter().

Referenced by main().

{
  return variableParameter(paramIndex)->realValue(_allModels->model(modelIndex)[paramIndex] );
}

References DinverCore::ModelSet::count().

{
  return _allModels ? _allModels->count() : 0;
}

Activate this first forward thread. This is used as a semaphore to indicate if the inversion is currently running or not.

References TRACE.

Referenced by start().

{
  TRACE;
  ASSERT(_forwards.count()==1);
  _forwards.first()->wake();

  _timeAdd=0;
  _timeMainWait=0;
  _timeStartEnd=0;
  _timeTotal=0;
}

The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines