00001 //$Header: /home/ben/Mapper/c++/RCS/mapper.cpp,v 6.14 2002/07/09 23:03:15 ben Exp $
00002 // Copyright Benedict Adamson 2002.
00003 // This file is part of Mapper.
00004
00005 // Mapper 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 // Mapper 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 Mapper; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018
00029 #include <cassert>
00030 #include <cmath>
00031 #include <cstdlib>
00032 #include <fstream>
00033 #include <unistd.h>
00034 #include <vector>
00035
00036 #include <framework/LocalFileInputSource.hpp>
00037 #include <framework/StdInInputSource.hpp>
00038 #include <util/PlatformUtils.hpp>
00039 #include <util/XMLString.hpp>
00040
00041 #include "MapDataDocument.h"
00042 #include "MapperErrorHandler.h"
00043 #include "assoc.h"
00044 #include "curve.h"
00045 #include "minimise.h"
00046 #include "total_energy_function.h"
00047
00048
00049
00054 namespace status {
00055 enum code {
00056 OK = 0,
00057 error = 1
00058 };
00059 }
00060
00061
00062 namespace {
00063
00083 void solve(
00084 total_energy_function &e,
00085 vector<double> &p, //input, output
00086 const double ftol,
00087 unsigned max_iter,
00088 unsigned &iter, //output
00089 double &fmin //output
00090 )
00091 {
00092 {//preconditions:
00093 assert( p.size() );
00094 assert( 0.0 < ftol && ftol < 1 );
00095 assert( 0 < max_iter );
00096 };
00097 unsigned iter1;
00098 if( ftol < 1E-3 && 4 <= max_iter ){
00099 //find an approximate solution first,
00100 //before solving to the fine tolerance.
00101 const double ftol1 = 10.0 * ftol;
00102 const unsigned max_iter1 = max_iter/2;
00103 e.set_tol( ftol1 );
00104 solve(
00105 e,
00106 p,
00107 ftol1, max_iter1,
00108 iter1, fmin
00109 );
00110 }else
00111 iter1 = 0;
00112 ;
00113 unsigned max_iter2 = max_iter2 = max_iter - iter1;
00114 unsigned iter2;
00115 e.set_tol( ftol );
00116 minimise::Fletcher_Reeves_Polak_Ribere(
00117 e,
00118 p,
00119 ftol, 2U, max_iter2,
00120 iter2, fmin
00121 );
00122 iter = iter1 + iter2;
00123 {//postconditions:
00124 assert( iter <= max_iter );
00125 //assert( fmin == f(p) || iter == max_iter); within rounding error.
00126 };
00127 }
00128
00129 }
00130
00131
00132
00142 int main(
00143 int argc,
00144 char **argv
00145 )
00146 {
00147 const char *my_name = argv[0];
00148 {//initialisation
00149 try{ //Initialise Xerces
00150 XMLPlatformUtils::Initialize();
00151 }catch( const XMLException &toCatch ){
00152 cerr << my_name << ":error: during initialization\n";
00153 return status::error;
00154 };
00155 };
00156 MapperErrorHandler error_handler( my_name );
00157 //Initialise command-line options
00158 const char *input_file = 0; //0 indicates stdin.
00159 const char *output_file = 0; //0 indicates stdout.
00160 double ftol = 1E-8;
00161 unsigned max_iter = 0U;
00162 {//process the command line arguments
00163 int c;
00164 while( (c = getopt( argc, argv, "f:i:o:" )) != -1 ){
00165 switch( c ){
00166 case 'o':
00167 output_file = optarg;
00168 break;
00169 case 'f':{
00170 char *end;
00171 ftol = strtod( optarg, &end );
00172 if( *end || ftol <= 0.0 || 1.0 <= ftol ){
00173 error_handler.badOptionArgument( 'f', optarg );
00174 ftol = 1E-8;
00175 };
00176 break;}
00177 case 'i':{
00178 char *end;
00179 unsigned long i;
00180 i = strtoul( optarg, &end, 10 );
00181 if( *end ){
00182 error_handler.badOptionArgument( 'i', optarg );
00183 i = 0;
00184 };
00185 max_iter = i;
00186 break;}
00187 case '?':
00188 error_handler.error( "unrecognised command-line option" );
00189 break; //Give the compiler a break
00190 #ifndef NDEBUG
00191 default: //unexpected
00192 abort();
00193 break; //Give the compiler a break
00194 #endif
00195 };
00196 };
00197 if( optind == argc-1 ) //file given
00198 input_file = argv[optind];
00199 else if( optind == argc ) //no file given
00200 ; //OK
00201 else{ //several files given
00202 error_handler.error( "too many files" );
00203 };
00204 if( error_handler.errors ){//usage error(s)
00205 XMLPlatformUtils::Terminate();
00206 return status::error;
00207 };
00208 };
00209
00210 MapDataDocument doc;
00211
00212 {//read input file
00213 InputSource *source;
00214 if( input_file )
00215 source = new LocalFileInputSource(
00216 XMLString::transcode(input_file)
00217 );
00218 else
00219 source = new StdInInputSource;
00220 ;
00221 doc.read( *source, error_handler );
00222 delete source;
00223 if( error_handler.errors ){//error(s) during parsing
00224 XMLPlatformUtils::Terminate();
00225 return status::error;
00226 };
00227 };
00228
00229 unsigned n_constraints;
00230 {//report on and check input data
00231 const unsigned n_points = doc.named_points().size();
00232 const unsigned n_curves = doc.curves().size();
00233 const unsigned n_fixed_points = doc.fixed_points().size();
00234 n_constraints = doc.constraints().size();
00235 assert( n_fixed_points <= n_points );
00236 cerr << n_points << " points, "
00237 << n_fixed_points << " fixed points, "
00238 << n_curves << " curves, "
00239 << n_constraints << " constraints\n";
00240 if( n_fixed_points < 2 )
00241 error_handler.warning( "fewer than 2 fixed points" );
00242 ;
00243 if( n_constraints == 0 )
00244 error_handler.warning( "no constraints" );
00245 ;
00246 if( n_constraints < (n_points-n_fixed_points) )
00247 error_handler.warning(
00248 "fewer constraints than named moveable points"
00249 );
00250 ;
00251 };
00252
00253 if( 0 < max_iter ){//calculation
00254 total_energy_function e( ftol );
00255 const set< vector2 * > ps( doc.all_points() );
00256 const vector< vector2 * > pv( ps.begin(), ps.end() );
00257 assoc( e, pv, doc.fixed_points(), doc.constraints() );
00258 try{//calculate point positions
00259 const unsigned n = e.n_vars();
00260 if( n && n_constraints ){
00261 vector<double> p(n);
00262 p = e.current_var(); //use any hints provided
00263 unsigned iter;
00264 double fmin;
00265 solve(
00266 e,
00267 p,
00268 ftol, max_iter,
00269 iter, fmin
00270 );
00271 e.move_points( p );
00272 cerr << iter << " iterations, "
00273 << fmin << " total energy\n";
00274 if( max_iter <= iter )
00275 error_handler.warning( "iteration limit reached" );
00276 ;
00277 };
00278 }catch( ... ){
00279 error_handler.error( "during minimisation" );
00280 };
00281 if( error_handler.errors ){//error(s) during minimisation
00282 XMLPlatformUtils::Terminate();
00283 return status::error;
00284 };
00285 };
00286
00287 try{//output
00288 if( output_file ){
00289 ofstream file(output_file);
00290 doc.write( file, ftol );
00291 }else
00292 doc.write( cout, ftol );
00293 ;
00294 }catch( ... ){
00295 error_handler.unexpectedError();
00296 #ifndef NDEBUG
00297 abort();
00298 #endif
00299 };
00300
00301 XMLPlatformUtils::Terminate();
00302 if( error_handler.errors ){
00303 return status::error;
00304 }else
00305 return status::OK;
00306 ;
00307 }
00308