openModeller  Version 1.4.0
minimum_distance.cpp
Go to the documentation of this file.
00001 
00028 #include "minimum_distance.hh"
00029 
00030 #include <string.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <math.h>
00034 
00035 #include <openmodeller/ScaleNormalizer.hh>
00036 
00037 //debug
00038 #include <iostream>
00039 
00040 
00041 /****************************************************************/
00042 /********************** Algorithm's Metadata ********************/
00043 
00044 #define NUM_PARAM 1
00045 
00046 #define MAXDIST_ID "MaximumDistance"
00047 
00048 
00049 /******************************/
00050 /*** Algorithm's parameters ***/
00051 
00052 static AlgParamMetadata parameters[NUM_PARAM] = {
00053 
00054   // Metadata of the first parameter.
00055   {
00056     MAXDIST_ID,         // Id.
00057     "Maximum distance", // Name.
00058     Real,               // Type.
00059     "Maximum cartesian distance to closest point", // Overview
00060     "Maximum cartesian distance to closest point", // Description.
00061 
00062     1,         // Not zero if the parameter has lower limit.
00063     0.0,       // Parameter's lower limit.
00064     1,         // Not zero if the parameter has upper limit.
00065     1.0,       // Parameter's upper limit.
00066     "0.1"      // Parameter's typical (default) value.
00067   },
00068 };
00069 
00070 
00071 /************************************/
00072 /*** Algorithm's general metadata ***/
00073 
00074 static AlgMetadata metadata = {
00075 
00076   "MinimumDistance",  // Id.
00077   "Minimum distance",   // Name.
00078   "0.2",                // Version.
00079 
00080   // Overview
00081   "Probability is inversely proportional to the cartesian\
00082  distance in environmental space to the nearest presence point.",
00083 
00084   // Description.
00085   "Normalizes the environmental variables values and the\
00086  parameter (according to the number of environmental variables).\
00087  Calculates the distance between the given environmental conditions\
00088  to each occurrence point and selects the closest distance.\n\
00089  If distance 'dist' is within [0, MaxDist] then probability will\
00090  be in [0,1]. If 'dist' > MaxDist then probability will be zero.",
00091 
00092 
00093   "Mauro E. S. Munoz",  // Algorithm author.
00094   "",               // Bibliography.
00095 
00096   "Mauro E. S. Munoz",       // Code author.
00097   "mauro [at] cria.org.br",  // Code author's contact.
00098 
00099   0,  // Does not accept categorical data.
00100   0,  // Does not need (pseudo)absence points.
00101 
00102   NUM_PARAM,   // Algorithm's parameters.
00103   parameters
00104 };
00105 
00106 
00107 
00108 /****************************************************************/
00109 /****************** Algorithm's factory function ****************/
00110 
00111 OM_ALG_DLL_EXPORT
00112 AlgorithmImpl *
00113 algorithmFactory()
00114 {
00115   return new MinimumDistance();
00116 }
00117 
00118 OM_ALG_DLL_EXPORT
00119 AlgMetadata const *
00120 algorithmMetadata()
00121 {
00122   return &metadata;
00123 }
00124 
00125 /****************************************************************/
00126 /************************ Minimum Distance **********************/
00127 
00128 /*******************/
00129 /*** constructor ***/
00130 
00131 MinimumDistance::MinimumDistance() :
00132   AlgorithmImpl( &metadata ),
00133   _done( false ),
00134   _dist(0.0),
00135   _hasCategorical( false ),
00136   _numLayers( 0 )
00137 {
00138   _normalizerPtr = new ScaleNormalizer( 0.0, 1.0, true );
00139 }
00140 
00141 
00142 /******************/
00143 /*** destructor ***/
00144 
00145 MinimumDistance::~MinimumDistance()
00146 {
00147 }
00148 
00149 
00150 /******************/
00151 /*** initialize ***/
00152 int
00153 MinimumDistance::initialize()
00154 {
00155   if ( ! getParameter( MAXDIST_ID, &_dist ) ) {
00156     Log::instance()->error("Parameter '" MAXDIST_ID "' not set properly.\n");
00157     return 0;
00158   }
00159 
00160   // Distance should range from 0 to 1
00161   if (_dist > 1.0)       _dist = 1.0;
00162   else if (_dist < 0.0)  _dist = 0.0;
00163 
00164   int dim = _samp->numIndependent();
00165 
00166   _dist *= sqrt( (double) dim );
00167 
00168   if ( _samp->numPresence() == 0 ) {
00169     Log::instance()->warn( "MinDistance: No occurrences inside the mask!\n" );
00170     return 0;
00171   }
00172 
00173   OccurrencesPtr presences = _samp->getPresences();
00174 
00175   // Load vector with samples containing the environmental
00176   // values at each presence point
00177   OccurrencesImpl::const_iterator p_iterator = presences->begin();
00178   OccurrencesImpl::const_iterator p_end = presences->end();
00179 
00180   while ( p_iterator != p_end ) {
00181 
00182     Sample point = (*p_iterator)->environment();
00183  
00184     _envPoints.push_back(point);
00185 
00186     ++p_iterator;
00187   }
00188 
00189   // Identify categorical layers
00190   _numLayers = _samp->numIndependent();
00191   _isCategorical.resize( _numLayers );
00192 
00193   for( int i = 0; i < _numLayers; ++i ) {
00194     if ( _samp->isCategorical( i ) ) {
00195       _hasCategorical = true;
00196       _isCategorical[i] = 1.0;
00197     }
00198   }
00199 
00200   _done = true;
00201 
00202   return 1;
00203 
00204 }
00205 
00206 
00207 /***************/
00208 /*** iterate ***/
00209 int
00210 MinimumDistance::iterate()
00211 {
00212   return 1;
00213 }
00214 
00215 
00216 /************/
00217 /*** done ***/
00218 int
00219 MinimumDistance::done() const
00220 {
00221   return _done;
00222 }
00223 
00224 
00225 /*****************/
00226 /*** get Value ***/
00227 Scalar
00228 MinimumDistance::getValue( const Sample& x ) const
00229 {
00230   // Calculate the smallest distance between *x and the occurrence
00231   // points.
00232   Scalar min = -1;
00233 
00234   for( unsigned int i=0; i<_envPoints.size(); i++) {
00235 
00236     Scalar dist = findDist( x, _envPoints[i] );
00237 
00238     if ( (dist >= 0) && (dist < min || min < 0) )
00239       min = dist;
00240   }
00241   
00242   // Too far away or categories didn't match any occurrence
00243   if ( min < 0 || min > _dist )
00244     return 0.0;
00245   
00246   return 1.0 - (min / _dist);
00247 
00248 }
00249 
00250 
00251 /***********************/
00252 /*** get Convergence ***/
00253 int
00254 MinimumDistance::getConvergence( Scalar *val )
00255 {
00256   *val = 1.0;
00257   return 1;
00258 }
00259 
00260 
00261 /*****************/
00262 /*** find Dist ***/
00263 Scalar
00264 MinimumDistance::findDist( const Sample& x, const Sample& pnt ) const
00265 {
00266 
00267   if ( _hasCategorical ) {
00268     for( int i=0; i< _numLayers ; ++i ) {
00269       if ( _isCategorical[i] ) {
00270         if ( x[i] != pnt[i] ) {
00271           return -1.0;
00272         }
00273       }
00274     }
00275   }
00276 
00277   Sample dif = x;
00278   dif -= pnt;
00279 
00280   return dif.norm();
00281 
00282 }
00283 
00284 
00285 /****************************************************************/
00286 /****************** configuration *******************************/
00287 void
00288 MinimumDistance::_getConfiguration( ConfigurationPtr& config ) const
00289 {
00290   if (!_done )
00291     return;
00292 
00293   ConfigurationPtr model_config( new ConfigurationImpl("MinimumDistance") );
00294   config->addSubsection( model_config );
00295 
00296   model_config->addNameValue( "IsCategoricalLayer", _isCategorical );
00297   model_config->addNameValue( "Distance", _dist );
00298 
00299   ConfigurationPtr envpoints_config( new ConfigurationImpl("EnvironmentalReferences") );
00300   model_config->addSubsection( envpoints_config );
00301 
00302   for( unsigned int i=0; i<_envPoints.size(); i++) {
00303 
00304     ConfigurationPtr point_config( new ConfigurationImpl("Reference") );
00305     envpoints_config->addSubsection( point_config );
00306 
00307     point_config->addNameValue( "Value", _envPoints[i] );
00308   }
00309 }
00310 
00311 void
00312 MinimumDistance::_setConfiguration( const ConstConfigurationPtr& config )
00313 {
00314   ConstConfigurationPtr model_config = config->getSubsection( "MinimumDistance",false );
00315 
00316   if (!model_config)
00317     return;
00318 
00319   // Information about categorical layers
00320   _isCategorical = model_config->getAttributeAsSample( "IsCategoricalLayer" );
00321   _numLayers = (int)_isCategorical.size();
00322 
00323   for( int i=0; i<_numLayers; i++) {
00324 
00325     if ( _isCategorical[i] ) {
00326 
00327       _hasCategorical = true;
00328       break;
00329     }
00330   }
00331 
00332   // Maximum distance
00333   _dist = model_config->getAttributeAsDouble( "Distance", 0.0 );
00334 
00335   // Environmental points
00336   ConstConfigurationPtr envpoints_config = model_config->getSubsection( "EnvironmentalReferences",false );
00337 
00338   Configuration::subsection_list subs = envpoints_config->getAllSubsections();
00339 
00340   Configuration::subsection_list::iterator begin = subs.begin();
00341   Configuration::subsection_list::iterator end = subs.end();
00342   for ( ; begin != end; ++begin ) {
00343 
00344     if ( (*begin)->getName() != "Reference" ) 
00345       continue;
00346 
00347     Sample point = (*begin)->getAttributeAsSample( "Value" );
00348 
00349     _envPoints.push_back( point );
00350   }
00351 
00352   _done = true;
00353 }