k-dot-p 0.1

digital_alloy_optimizer_1d.h++

Go to the documentation of this file.
00001 /*
00002  *Optimizes a material according to some number.
00003 
00004 
00005     Copyright (C) 2010 Joseph Pingenot
00006 
00007     This program is free software: you can redistribute it and/or modify
00008     it under the terms of the GNU Affero General Public License as published by
00009     the Free Software Foundation, either version 3 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU Affero General Public License for more details.
00016 
00017     You should have received a copy of the GNU Affero General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 
00020 */
00021 
00022 #ifndef ___LIBKDOTP_DIGITAL_ALLOY_OPTIMIZER_1D_HPP___
00023 #define ___LIBKDOTP_DIGITAL_ALLOY_OPTIMIZER_1D_HPP___
00024 
00025 #include <math.h>
00026 #include <gsl/gsl_rng.h>
00027 #include <gsl/gsl_errno.h>
00028 #include <libmodelxx/material.h++>
00029 #include <libmodelxx/generic_structure.h++>
00030 
00031 namespace kdotp {
00032   namespace libmetacalc {
00033     namespace optimizer {
00034 
00035       class digital_alloy_optimizer_1d {
00036       public:
00037   typedef void (*set_point_callback)(unsigned X, const kdotp::libmodelxx::structure::material* mat, void* privdat);
00038   enum goal {
00039     MAXIMIZE,
00040     MAXIMIZE_ABS,
00041     MINIMIZE,
00042     MAKE_ZERO
00043   };
00044 
00045   /**constructor and initializer in one
00046    *\param marker_material material used to mark the region to be optimized
00047    *\param a material to be used if the block is zero
00048    *\param b material to be used if the block is one
00049    *\param s generic_structure to be optimized
00050    *\param set_point callback to use when setting a point, or NULL if you don't want to do anything
00051    *\param blocksize number of points per block
00052    *\param err GError information if something failed. Untouched if successful.
00053    *\param assignements list of initial material assignments for each block (or for all blocks)
00054    *\param assignement_expr function to evaluate to get the initial material assignments.
00055    *\note Starting and stopping points are fetched from the generic structure.
00056    *\note that the assignments are done on the block level,
00057    *i.e. in blocks of points.  This is to improve efficiency and
00058    *accuracy, since structures can only be grown so finely, but
00059    *having a grid spacing which is a multiple of the minimum
00060    *feature size is desirable for high-accuracy calculations.
00061    *\note that any incommensurate number of points will be split
00062    *amongst the points as evenly as possible.
00063    *\note that this modifies the generic_structure, removing the marker material and replacing it with materials from the optimizer state.
00064    *\note that this constructor calls _set_point, since it has to initialize the material.
00065    */
00066   digital_alloy_optimizer_1d(
00067            kdotp::libmodelxx::structure::material* marker_material, 
00068            kdotp::libmodelxx::structure::material* _mat1, 
00069            kdotp::libmodelxx::structure::material* _mat0, 
00070            kdotp::libmodelxx::structure::generic_structure* s, 
00071            set_point_callback _set_point,
00072            unsigned _blocksize, 
00073            enum goal _goal, 
00074            GError** err, 
00075            void* privdat, 
00076            unsigned _N_blocks=0,
00077            long unsigned int rng_seed=0,
00078            GList* assignments=NULL,
00079            struct ::kdotp::libmodelxx::postprocessing::function_exp *assignment_expr=NULL,
00080            GHashTable *global_symbols=NULL
00081            );
00082   
00083   /*The two materials we can be using at each site*/
00084   kdotp::libmodelxx::structure::material* mat1;
00085   kdotp::libmodelxx::structure::material* mat0;
00086   /*This stores the current material assignments.*/
00087   short unsigned *current_assignments;
00088   /*This stores the set of bits which state that the material at that location is known optimum for this particular point*/
00089   short unsigned *material_is_optimum;
00090   /*Pointer to the generic structure we're to modify.
00091    *\note Please note that although it's perfectly doable to just set the genstruct
00092    *  and then use it to create the Hamiltonian over and over and over again, that it's
00093    *  much much more efficient to use the callback to also set the Hamiltonian directly.
00094    *\note To manipulate the Hamiltonian directly, you'll need to set the material yourself
00095    *  for now.  I may later add an interface through the generic hamltonian class to accomplish
00096    *  this.
00097    */
00098   kdotp::libmodelxx::structure::generic_structure* genstruct;
00099   /*The callback to use when setting a point*/
00100   set_point_callback call_set_point_callback;
00101   /*Starting and ending points. Derived in the constructor from
00102     the generic_structure.  These points are *in*clusive. */
00103   unsigned start_X;
00104   /*This one is exclusive, i.e. this is the first point after the optimizer region.*/
00105   unsigned stop_X;
00106   /*Size of a block, in points*/
00107   unsigned blocksize;
00108   /*Stores the number of points in each block*/
00109   unsigned* points_in_block;
00110   /*This stores the point that the start of the block corresponds to*/
00111   unsigned* point_start;
00112   /**the number of blocks*/
00113   unsigned N_blocks;
00114   /**This could be gleaned by counting material_is_optimum, but is faster.*/
00115   unsigned N_optimum;
00116   /**Previous value we're to track, to compare how we're changing.
00117    *\note this is a *pointer*; if it's NULL, the previous calculation was the first one, so all of the blocks had been changed.
00118    */
00119   double previous_value;
00120   /**Which block was last changed.
00121    *\note this is a *pointer*; if it's NULL, the previous calculation was the first one, so all of the blocks had been changed.
00122    *\note this is the block which was just tested
00123    */
00124   unsigned* current_block;
00125   enum goal goal;
00126   /**The GSL random number generator information.*/
00127   gsl_rng* rng;
00128   unsigned long int seed;
00129 
00130 
00131   /*Internal methods*/
00132   inline void reset_optimum_array() {
00133     for(unsigned i=0; i<N_blocks; i++) material_is_optimum[i]=0;
00134     N_optimum=0;
00135   }
00136   inline void randomize_array(short unsigned* array, unsigned int N) {
00137     for(unsigned i=0; i<N; i++) {
00138       /**\note that gsl_rng_uniform returns [0,1), so 0.5 will be considered in the upper half,
00139        *  so that both options will be equally probable
00140        *\note Upper half of [0,1) => 1; lower => 0.
00141        */
00142       if(gsl_rng_uniform(rng) >= 0.5) {
00143         array[i]=1;
00144       }else{
00145         array[i]=0;
00146       }
00147     }
00148   }
00149   inline bool is_improved(double value) {
00150     switch(goal) {
00151     case MAXIMIZE:
00152       return (value > previous_value);
00153       break;
00154     case MAXIMIZE_ABS:
00155       fprintf(stderr, "maximize_abs: value=%g previous_value=%g\n", value, previous_value);
00156       return (fabs(value) > fabs(previous_value));
00157       break;
00158     case MINIMIZE:
00159       return (value < previous_value);
00160       break;
00161     case MAKE_ZERO:
00162       return (fabs(value) < fabs(previous_value));
00163       break;
00164     }
00165     return false;
00166   }
00167   inline unsigned get_random_unoptimized_block() {
00168     unsigned check = (unsigned)floor(gsl_rng_uniform(rng)*(N_blocks - N_optimum-1));
00169     unsigned j=0;
00170     /*we need to find the check-th un-optimized block.
00171      *algorithm: walk through the list incrementing j when we have an unoptimized block
00172      *  return the block where j becomes check.
00173      */
00174     for(unsigned block=0; block<N_blocks; block++) {
00175       if(!material_is_optimum[block]) {
00176         if(j++ == check) return block;
00177       }
00178     }
00179     return N_blocks;
00180   }
00181   inline void toggle_block(unsigned block, void* privdat) {
00182     if(current_assignments[block] == 0) {
00183       current_assignments[block] = 1;
00184     }else{
00185       current_assignments[block] = 0;
00186     }
00187     set_block(block, privdat);
00188   }
00189   inline void set_block(unsigned block, void* privdat) {
00190 	  ::kdotp::libmodelxx::grid::cartesian_grid< ::kdotp::libmodelxx::structure::material*, 1, 1>* matgrid
00191       = (::kdotp::libmodelxx::grid::cartesian_grid< ::kdotp::libmodelxx::structure::material*, 1, 1>*)
00192       (genstruct->material_grid);
00193     unsigned final_point = point_start[block];
00194     for(unsigned pt=0; pt<points_in_block[block]; pt++) {
00195       matgrid->set_point(&final_point, (current_assignments[block]==0)?&mat0:&mat1);
00196       if(call_set_point_callback != NULL)
00197         call_set_point_callback(final_point, (current_assignments[block]==0)?mat0:mat1, privdat);
00198       final_point++;
00199     }
00200   }
00201   inline void set_block_as_optimum(unsigned block) {
00202     material_is_optimum[block]=1;
00203     N_optimum++;
00204   }
00205 
00206   inline void set_material_from_current_assignments(void* privdat) {
00207     for(unsigned block=0; block<N_blocks; block++) {
00208       set_block(block, privdat);
00209     }
00210   }
00211   /**Does the first step in the algorithm.
00212    *\param value the value that we're tracking
00213    *\param privdat pointer to data for the set_point callback.
00214    *\return 0 if we've not converged, or 1 if we've converged.
00215    */
00216   int do_first_step(double value, void* privdat);
00217   /**Does the later steps in the algorithm
00218    *\param value the value that we're tracking
00219    *\param privdat pointer to data for the set_point callback.
00220    *\return 0 if we've not converged, or 1 if we've converged.
00221    */
00222   int do_second_step(double value, void* privdat);
00223   /**Does the later steps in the algorithm
00224    *\param value the value that we're tracking
00225    *\param privdat pointer to data for the set_point callback.
00226    *\return 0 if we've not converged, or 1 if we've converged.
00227    */
00228   int do_subsequent_step(double value, void* privdat);
00229   /**Does any step in the algorithm, but checks to see if we've taken the first step yet.
00230    *\param value the value that we're tracking
00231    *\param privdat pointer to data for the set_point callback.
00232    *\return 0 if we've not converged, or 1 if we've converged.
00233    */
00234   int do_generic_step(double value, void* privdat);
00235 
00236   /*This performs the calculation without stepping through manually.
00237    *At each step, get_value is called with privdat
00238    *\param get_value callback to use after setting the materials.
00239    *\param privdat private data for the callback
00240    *\return NULL if we converged; GError* if there was an error.
00241    *\note that if NaN is returned, we stop and return an error
00242    *\note this should eventually deal with GErrors for better error reporting.
00243    */
00244   GError*  do_optimization(double (*get_value)(void* privdat, unsigned assignment, long unsigned iteration), void* get_value_privdat, void* set_point_privdat);
00245   /**Resets the state to get ready to do an optimization.
00246    *\note that this randomizes the current assignments array, so this is what
00247    *  you'll want to call to start from another initial condition
00248    */
00249   void initialize(void* privdat);
00250   /**Initializes to a known state.
00251    *\param state the state to initialize to (array of N_blocks short unsigned ints)
00252    */
00253   void initialize(const short unsigned* state, void* privdat);
00254   /*this should be virtual if we had any real inheritance, but we don't*/
00255   ~digital_alloy_optimizer_1d();
00256       private:
00257   digital_alloy_optimizer_1d() {}
00258   bool operator==(const digital_alloy_optimizer_1d& o) {return false;}
00259   digital_alloy_optimizer_1d operator=(const digital_alloy_optimizer_1d& o) {return *this;}
00260   digital_alloy_optimizer_1d(const digital_alloy_optimizer_1d& o){}
00261       };
00262 
00263 
00264 
00265     }
00266   }
00267 }
00268 
00269 
00270 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines