00001 //$Header: /home/ben/Mapper/c++/RCS/total_energy_function.cpp,v 6.4 2002/06/25 16:13:50 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 <climits>
00030
00031 #include "total_energy_function.h"
00032
00033
00034
00035 const unsigned total_energy_function::fixed_point = UINT_MAX;
00036
00037
00038
00039 total_energy_function::total_energy_function(
00040 const double t
00041 )
00042 :
00043 tol_( t ),
00044 points_( 0 ),
00045 fixed_points_( 0 ),
00046 constraints_( 0 ),
00047 constraint_to_var(),
00048 point_to_var()
00049 {
00050 {//preconditions:
00051 assert( 0 < t && t < 1 );
00052 };
00053 {//postconditions
00054 assert( this->tol() == t );
00055 assert( this->points() == 0 );
00056 assert( this->fixed_points() == 0 );
00057 assert( this->constraints() == 0 );
00058 };
00059 }
00060
00061
00062
00063 total_energy_function::~total_energy_function(void)
00064 {
00065 //Do nothing
00066 }
00067
00068
00069
00070 void total_energy_function::set_tol(
00071 const double t
00072 )
00073 {
00074 {//preconditions:
00075 assert( 0 < t && t < 1 );
00076 };
00077 this->tol_ = t;
00078 {//preconditions:
00079 assert( this->tol() == t );
00080 };
00081 }
00082
00083
00084
00085 void assoc(
00086 total_energy_function &f,
00087 const vector< vector2 * > &po,
00088 const set< vector2 * > &fp,
00089 const vector< constraint * > &co
00090 )
00091 {
00092 {//preconditions
00093 assert( f.points() == 0 );
00094 assert( f.fixed_points() == 0 );
00095 assert( f.constraints() == 0 );
00096 assert( fp.size() <= po.size() );
00097 };
00098 f.points_ = &po;
00099 f.fixed_points_ = &fp;
00100 f.constraints_ = &co;
00101 {//compute point_to_var
00102 unsigned i = 0;
00103 for( vector< vector2 * >::const_iterator j = po.begin();
00104 j != po.end();
00105 j++ )
00106 {
00107 vector2 *pj = *j;
00108 assert( pj );
00109 if( fp.count( pj ) ) //pj is a fixed point
00110 f.point_to_var[ pj ] = total_energy_function::fixed_point;
00111 else{
00112 f.point_to_var[ pj ] = i;
00113 i += 2; //allocate variables for x and y coordinates
00114 };
00115 };
00116 };
00117 {//compute constraint_to_var
00118 const unsigned nc = co.size();
00119 f.constraint_to_var = vector< vector<unsigned> >( nc );
00120 for( unsigned i = 0; i < nc; i++ ){
00121 const vector< vector2 * > &cp( co[i]->points() );
00122 const unsigned np = cp.size();
00123 assert( 0 < np ); //otherwise, constrains nothing
00124 f.constraint_to_var[i] = vector<unsigned>( np );
00125 for( unsigned j = 0; j < np; j++ ){
00126 vector2 *p = cp[j];
00127 assert( p );
00128 assert( f.point_to_var.count( p ) );
00129 f.constraint_to_var[i][j] = f.point_to_var[ p ];
00130 };
00131 };
00132 };
00133 {//postconditions
00134 assert( f.points() == &po );
00135 assert( f.fixed_points() == &fp );
00136 assert( f.constraints() == &co );
00137 };
00138 }
00139
00140
00141
00142 double total_energy_function::operator() (
00143 const vector<double> &x
00144 ) const
00145 {
00146 {//preconditions:
00147 assert( this->points() );
00148 assert( this->fixed_points() );
00149 assert( this->constraints() );
00150 assert( x.size() == this->n_vars() );
00151 };
00152 double e;
00153 vector<double> dedx( this->n_vars() );
00154 this->evaluate( x, e, dedx );
00155 //discard dedx
00156 return e;
00157 }
00158
00159
00160
00161
00162 void total_energy_function::evaluate(
00163 const vector<double> &x,
00164 double &e, //output
00165 vector<double> &gradient //output
00166 ) const
00167 {
00168 {//preconditions:
00169 assert( this->points() );
00170 assert( this->fixed_points() );
00171 assert( this->constraints() );
00172 assert( x.size() == this->n_vars() );
00173 };
00174 //f == (*this)( x )
00175 {//initialise running totals
00176 e = 0.0;
00177 gradient = vector<double>( this->n_vars() );
00178 };
00179 const unsigned n_constraints = this->constraints()->size();
00180 const double tol_c = this->tol()/double(1U + n_constraints);
00181 for( unsigned i = 0; i < n_constraints; i++ ){
00182 const constraint *c = (*(this->constraints()))[i];
00183 assert( c );
00184 const vector< unsigned > &ctv( this->constraint_to_var[i] );
00185 const unsigned np = c->points().size();
00186 assert( 0 < np );
00187 vector< vector2 > p( np ), dedp( np );
00188 for( unsigned j = 0; j < np; j++ ){
00189 const unsigned var = ctv[j];
00190 if( var == fixed_point ){
00191 const vector2 *pj = c->points()[j];
00192 assert( pj );
00193 p[j] = *pj;
00194 }else{
00195 assert( var+1 < this->n_vars() );
00196 p[j] = vector2( x[ var ], x[ var+1 ] );
00197 };
00198 };
00199 double ep;
00200 c->energy( tol_c, p, ep, dedp );
00201 {//increase the running totals
00202 e += ep;
00203 for( unsigned j = 0; j < np; j++ ){
00204 const unsigned var = ctv[j];
00205 if( var != fixed_point ){
00206 assert( var+1 < this->n_vars() );
00207 gradient[ var ] += dedp[j].x;
00208 gradient[ var+1 ] += dedp[j].y;
00209 };//else no effect on gradient
00210 };
00211 };
00212 };
00213 }
00214
00215
00216
00217 vector<double> total_energy_function::current_var(void) const
00218 {
00219 {//preconditions
00220 assert( this->points() );
00221 assert( this->fixed_points() );
00222 };
00223 vector<double> result( this->n_vars() );
00224 map< vector2 *, unsigned > &m(
00225 const_cast< map< vector2 *, unsigned > & >(
00226 this->point_to_var
00227 )); //circumvent const
00228 for( vector< vector2 *const >::iterator i = points()->begin();
00229 i != points()->end();
00230 i++ ){
00231 vector2 *p = *i;
00232 assert( p );
00233 assert( m.count( p ) );
00234 const unsigned j = m[ p ];
00235 if( j == fixed_point )
00236 ;//no variables
00237 else{ //j and j+1 are the corresponding variables
00238 assert( j+1 < this->n_vars() );
00239 result[j] = p->x;
00240 result[j+1] = p->y;
00241 };
00242 };
00243 return result;
00244 }
00245
00246
00247
00248 void total_energy_function::move_points(
00249 const vector<double> & x
00250 ) const
00251 {
00252 {//preconditions:
00253 assert( x.size() == this->n_vars() );
00254 };
00255 map< vector2 *, unsigned > &m(
00256 const_cast< map< vector2 *, unsigned > & >(
00257 this->point_to_var
00258 )); //circumvent const
00259 for( vector< vector2 *const >::iterator i = points()->begin();
00260 i != points()->end();
00261 i++ ){
00262 vector2 *p = *i;
00263 assert( p );
00264 assert( m.count( p ) );
00265 const unsigned j = m[ p ];
00266 if( j == fixed_point )
00267 ;//no variables
00268 else{ //j and j+1 are the corresponding variables
00269 assert( j+1 < this->n_vars() );
00270 p->x = x[j];
00271 p->y = x[j+1];
00272 };
00273 };
00274 {//postconditions:
00275 assert( this->current_var() == x );
00276 };
00277 }