|
k-dot-p 0.1
|
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