1 /*
2 ================================================================================
3     PROJECT:
4 
5         John Eddy's Genetic Algorithms (JEGA)
6 
7     CONTENTS:
8 
9         Implementation of class FlatFileInitializer.
10 
11     NOTES:
12 
13         See notes of FlatFileInitializer.hpp.
14 
15     PROGRAMMERS:
16 
17         John Eddy (jpeddy@sandia.gov) (JE)
18 
19     ORGANIZATION:
20 
21         Sandia National Laboratories
22 
23     COPYRIGHT:
24 
25         See the LICENSE file in the top level JEGA directory.
26 
27     VERSION:
28 
29         1.0.0
30 
31     CHANGES:
32 
33         Thu Jun 26 12:47:50 2003 - Original Version (JE)
34 
35 ================================================================================
36 */
37 
38 
39 
40 
41 /*
42 ================================================================================
43 Document This File
44 ================================================================================
45 */
46 /** \file
47  * \brief Contains the implementation of the FlatFileInitializer class.
48  */
49 
50 
51 
52 /*
53 ================================================================================
54 Includes
55 ================================================================================
56 */
57 // JEGAConfig.hpp should be the first include in all JEGA files.
58 #include <../Utilities/include/JEGAConfig.hpp>
59 
60 #include <../Utilities/include/Logging.hpp>
61 #include <Initializers/FlatFileInitializer.hpp>
62 #include <../Utilities/include/DesignGroup.hpp>
63 #include <utilities/include/EDDY_DebugScope.hpp>
64 #include <Initializers/RandomUniqueInitializer.hpp>
65 #include <../Utilities/include/DesignFileReader.hpp>
66 #include <../Utilities/include/ParameterExtractor.hpp>
67 
68 
69 
70 
71 
72 /*
73 ================================================================================
74 Namespace Using Directives
75 ================================================================================
76 */
77 using namespace std;
78 using namespace JEGA;
79 using namespace JEGA::Logging;
80 using namespace eddy::utilities;
81 using namespace JEGA::Utilities;
82 
83 
84 
85 
86 
87 
88 
89 
90 /*
91 ================================================================================
92 Begin Namespace
93 ================================================================================
94 */
95 namespace JEGA {
96     namespace Algorithms {
97 
98 
99 
100 
101 
102 
103 
104 
105 /*
106 ================================================================================
107 Static Member Data Definitions
108 ================================================================================
109 */
110 const std::string FlatFileInitializer::DEFAULT_DELIM;
111 
112 
113 
114 
115 
116 
117 
118 /*
119 ================================================================================
120 Mutators
121 ================================================================================
122 */
123 void
SetFileNames(const JEGA::StringSet & fileNames)124 FlatFileInitializer::SetFileNames(
125     const JEGA::StringSet& fileNames
126     )
127 {
128     EDDY_FUNC_DEBUGSCOPE
129     this->_fileNames = fileNames;
130     JEGA_LOGGING_IF_ON(this->LogFilenames());
131 }
132 
133 void
SetDelimiter(const std::string & delim)134 FlatFileInitializer::SetDelimiter(
135     const std::string& delim
136     )
137 {
138     EDDY_FUNC_DEBUGSCOPE
139 
140     this->_delim = delim;
141 
142     JEGALOG_II(this->GetLogger(), lverbose(), this,
143         text_entry(lverbose(),
144             this->GetName() + ": Delimiter now = " +
145             (this->_delim.empty() ? "<EMPTY STRING>" : this->_delim))
146         )
147 
148     JEGAIFLOG_CF_II(this->_delim.empty(), this->GetLogger(), lverbose(), this,
149         text_entry(lverbose(), this->GetName() + ": Empty delimiter received. "
150             "As a result, the automatic delimiter discovery algorithm "
151             "will be employed."
152             )
153         )
154 }
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 /*
165 ================================================================================
166 Accessors
167 ================================================================================
168 */
169 
170 
171 
172 
173 
174 
175 
176 
177 /*
178 ================================================================================
179 Public Methods
180 ================================================================================
181 */
182 
183 const string&
Name()184 FlatFileInitializer::Name(
185     )
186 {
187     EDDY_FUNC_DEBUGSCOPE
188     static const string ret("flat_file");
189     return ret;
190 }
191 
192 const string&
Description()193 FlatFileInitializer::Description(
194     )
195 {
196     EDDY_FUNC_DEBUGSCOPE
197 
198     static const string ret(
199         "This initializer attempts to read from a delimited file with the "
200         "following format:\n\n"
201         "dv0<delim>dv1...dvN[<delim>of0<delim>of1...ofM<delim>con0<delim>con1"
202         "...conK]\n\n"
203         "The delimiter can be any string.  It will continue to read until "
204         "the end of the file.  It will discard any configurations for which "
205         "it was unable to retrieve at least the number of design variables.  "
206         "The objective and constraint entries are not required but if all are "
207         "present, they will be recorded and the Design will be tagged as "
208         "evaluated so that evaluators may choose not to re-evaluate them.\n\n"
209         "Setting the size for this initializer has the effect of requiring a "
210         "minimum number of Designs to create.  If this minimum number has not "
211         "been created once the files are all read, the rest are created using "
212         "the random unique initializer."
213         );
214     return ret;
215 }
216 
217 GeneticAlgorithmOperator*
Create(GeneticAlgorithm & algorithm)218 FlatFileInitializer::Create(
219     GeneticAlgorithm& algorithm
220     )
221 {
222     EDDY_FUNC_DEBUGSCOPE
223     return new FlatFileInitializer(algorithm);
224 }
225 
226 bool
AddFileName(const string & fileName)227 FlatFileInitializer::AddFileName(
228     const string& fileName
229     )
230 {
231     EDDY_FUNC_DEBUGSCOPE
232     bool ret = this->_fileNames.insert(fileName).second;
233     JEGA_LOGGING_IF_ON(this->LogFilenames());
234     return ret;
235 }
236 
237 
238 
239 
240 
241 
242 
243 
244 /*
245 ================================================================================
246 Subclass Visible Methods
247 ================================================================================
248 */
249 JEGA::StringSet
ParseFileNames(const string & from)250 FlatFileInitializer::ParseFileNames(
251     const string& from
252     )
253 {
254     EDDY_FUNC_DEBUGSCOPE
255 
256     JEGA::StringSet ret;
257 
258     // if from is empty, there is nothing we can do.
259     if(from.empty()) return ret;
260 
261     // place to store each filename as we encounter it
262     string fname;
263 
264     // stores our current location in "from"
265     string::size_type strt = 0;
266 
267     // extract the first value as a string.
268     fname.assign(this->GetNextField(from, "\t", strt));
269 
270     // go for as long as we can get filenames.
271     while(!fname.empty())
272     {
273         // otherwise record the value
274         JEGA_LOGGING_IF_ON(bool inserted = ret.insert(fname).second;)
275         JEGA_LOGGING_IF_OFF(ret.insert(fname);)
276 
277         JEGAIFLOG_CF_II(!inserted, this->GetLogger(), lquiet(), this,
278             text_entry(lquiet(), this->GetName() + ": Filename \"" + fname +
279                         "\" found more than once.  Repetitions ignored.")
280             )
281 
282         // update the start to one past the most recent end
283         strt += fname.size() + 1;
284 
285         // extract the next value as a string.
286         fname.assign(this->GetNextField(from, strt));
287     }
288 
289     return ret;
290 }
291 
292 JEGA::StringSet
ParseFileNames(const JEGA::StringSet & from)293 FlatFileInitializer::ParseFileNames(
294     const JEGA::StringSet& from
295     )
296 {
297     EDDY_FUNC_DEBUGSCOPE
298     StringSet ret;
299 
300     for(StringSet::const_iterator it(from.begin()); it!=from.end(); ++it)
301     {
302         StringSet curr(this->ParseFileNames(*it));
303         ret.insert(curr.begin(), curr.end());
304     }
305 
306     return ret;
307 }
308 
309 string
GetNextField(const string & from,const string & delim,const string::size_type off)310 FlatFileInitializer::GetNextField(
311     const string& from,
312     const string& delim,
313     const string::size_type off
314     )
315 {
316     EDDY_FUNC_DEBUGSCOPE
317 
318     // Check for trivial abort condition.
319     if(off >= from.size()) return string();
320 
321     // Find the next occurrence of the delimiter.
322     string::size_type end = from.find(delim, off);
323 
324     // return the substring consisting of everything from
325     // the offset to the delimiter.
326     return from.substr(off, end-off);
327 }
328 
329 string
GetNextField(const string & from,const string::size_type off) const330 FlatFileInitializer::GetNextField(
331     const string& from,
332     const string::size_type off
333     ) const
334 {
335     EDDY_FUNC_DEBUGSCOPE
336     return this->GetNextField(from, this->_delim, off);
337 }
338 
339 
340 /*
341 ================================================================================
342 Subclass Overridable Methods
343 ================================================================================
344 */
345 
346 string
GetName() const347 FlatFileInitializer::GetName(
348     ) const
349 {
350     EDDY_FUNC_DEBUGSCOPE
351     return FlatFileInitializer::Name();
352 }
353 
354 string
GetDescription() const355 FlatFileInitializer::GetDescription(
356     ) const
357 {
358     EDDY_FUNC_DEBUGSCOPE
359     return FlatFileInitializer::Description();
360 }
361 
362 GeneticAlgorithmOperator*
Clone(GeneticAlgorithm & algorithm) const363 FlatFileInitializer::Clone(
364     GeneticAlgorithm& algorithm
365     ) const
366 {
367     EDDY_FUNC_DEBUGSCOPE
368     return new FlatFileInitializer(*this, algorithm);
369 }
370 
371 
372 void
Initialize(DesignGroup & into)373 FlatFileInitializer::Initialize(
374     DesignGroup& into
375     )
376 {
377     EDDY_FUNC_DEBUGSCOPE
378 
379     JEGALOG_II(this->GetLogger(), ldebug(), this,
380         text_entry(ldebug(), this->GetName() + ": Performing initialization.")
381         )
382 
383     // get the target for the designs we create.
384     DesignTarget& target = into.GetDesignTarget();
385 
386     // find out the requested minimum number of Designs
387     const std::size_t minsize = this->GetSize();
388 
389     JEGA_LOGGING_IF_ON(const std::size_t prevSize = into.GetSize();)
390 
391     // read in each file one at a time
392     for(StringSet::const_iterator it(this->_fileNames.begin());
393         it!=this->_fileNames.end(); ++it)
394     {
395         DesignFileReader::Result readResults(
396             DesignFileReader::ReadFlatFile(*it, this->_delim, target)
397             );
398 
399         if(readResults.GetErrorFlag())
400         {
401             JEGALOG_II(this->GetLogger(), lquiet(), this,
402                 text_entry(lquiet(), this->GetName() + ": Encountered fatal "
403                     "error while attempting to read file \"" + *it + "\".  "
404                     "Make sure the file exists and is a JEGA Design flat file."
405                     )
406                 )
407             continue;
408         }
409         else into.AbsorbDesigns(readResults.GetDesigns());
410 
411         // indicate what happened
412         JEGALOG_II(this->GetLogger(), lverbose(), this,
413             text_entry(
414                 lverbose(), this->GetName() + ": \n" +
415                 readResults.GetResultsString()
416                 )
417             )
418 
419     }
420 
421     JEGAIFLOG_CF_II(into.IsEmpty(), this->GetLogger(), lquiet(), this,
422         text_entry(lquiet(), this->GetName() + ": No designs were read from "
423             "initialization files.  All initial designs will be "
424             "generated by the random unique initializer.")
425         )
426 
427     // now we have to make sure that we have enough according to the
428     // requested minimum size.
429     if(into.GetSize() < minsize)
430     {
431         // we will use the random unique initializer to fill
432         // in the rest.
433 
434         JEGALOG_II(this->GetLogger(), lverbose(), this,
435             text_entry(lverbose(), this->GetName() + ": The desired number of "
436                 "designs were not found in the supplied file(s).  Using the "
437                 "random unique initializer to generate the remaining designs."
438                 )
439             )
440 
441         RandomUniqueInitializer subiniter(this->GetAlgorithm());
442         subiniter.SetSize(minsize - into.GetSize());
443         subiniter.Initialize(into);
444     }
445 
446     JEGAIFLOG_CF_II_F(into.IsEmpty(), this->GetLogger(), this,
447         text_entry(lfatal(), this->GetName() + ": Unable to generate any "
448             "initial designs even with the help of the random unique "
449             "initializer.")
450         )
451 
452     JEGAIFLOG_CF_II_F(into.GetSize() < 2, this->GetLogger(), this,
453         text_entry(lfatal(), this->GetName() + ": Unable to generate minimum "
454             "of 2 initial designs even with the help of the random "
455             "unique initializer.")
456         )
457 
458     JEGALOG_II(this->GetLogger(), lverbose(), this,
459         ostream_entry(lverbose(), this->GetName() + ": ")
460             << (into.GetSize() - prevSize)
461             << " total designs read or created."
462         )
463 
464     JEGALOG_II(this->GetLogger(), lquiet(), this,
465         ostream_entry(lquiet(),
466             this->GetName() + ": Final initial population size: ")
467             << into.GetSize() << "."
468         )
469 
470     // Set the size to the number of successful reads.
471     this->SetSize(into.GetSize());
472 }
473 
474 bool
PollForParameters(const JEGA::Utilities::ParameterDatabase & db)475 FlatFileInitializer::PollForParameters(
476     const JEGA::Utilities::ParameterDatabase& db
477     )
478 {
479     EDDY_FUNC_DEBUGSCOPE
480 
481     // Get the delimiter
482     bool success = ParameterExtractor::GetStringFromDB(
483         db, "method.jega.initializer_delimiter", _delim
484         );
485 
486     JEGAIFLOG_CF_II(!success, this->GetLogger(), lverbose(), this,
487         text_entry(lverbose(), this->GetName() + ": The field delimiter was "
488             "not found in the parameter database.  Using the current " +
489             "delimiter " +
490             (this->_delim.empty() ? "<EMPTY STRING>" : this->_delim) + ".")
491         )
492 
493     this->SetDelimiter(this->_delim);
494 
495     // The user may have given us a single filename or multiple or both!  First
496     // extract the single name if present.
497     string tstr;
498     success = ParameterExtractor::GetStringFromDB(db, "method.flat_file", tstr);
499 
500     // Create a temporary set and initialize it with our filename.  Don't parse
501     // it yet.  That will happen in one step when we have collected all our
502     // filenames.
503     JEGA::StringSet fnames;
504     if(success) fnames.insert(tstr);
505 
506     // Now get the multiple names and merge them with our existing name.
507     JEGA::StringVector sfnames;
508     success = ParameterExtractor::GetStringVectorFromDB(
509         db, "method.flat_files", sfnames
510         );
511 
512     if(success) fnames.insert(sfnames.begin(), sfnames.end());
513 
514     // Now parse all the items in fnames and make that our new list of files.
515     fnames = this->ParseFileNames(fnames);
516 
517     JEGAIFLOG_CF_II(fnames.empty(), this->GetLogger(), lquiet(), this,
518         text_entry(lquiet(), this->GetName() + ": No filenames obtained for "
519             "initialization.")
520         )
521 
522     // Even if no filenames have been supplied, continue.  The initialization
523     // will just use the random unique for all of them.
524     this->SetFileNames(fnames);
525 
526     return this->GeneticAlgorithmInitializer::PollForParameters(db);
527 }
528 
529 
530 
531 
532 
533 
534 /*
535 ================================================================================
536 Private Methods
537 ================================================================================
538 */
539 void
LogFilenames() const540 FlatFileInitializer::LogFilenames(
541     ) const
542 {
543 #ifdef JEGA_LOGGING_ON
544     if(this->GetLogger().Gate().will_log(this, lverbose()))
545     {
546         string allFiles;
547 
548         StringSet::const_iterator e(this->_fileNames.end());
549         if(!this->_fileNames.empty()) --e;
550         for(StringSet::const_iterator it(this->_fileNames.begin()); it!=e; ++it)
551             allFiles.append(*it + ",");
552 
553         if(!this->_fileNames.empty()) allFiles.append(*e);
554 
555         JEGALOG_II(this->GetLogger(), lverbose(), this,
556             text_entry(lverbose(), this->GetName() +
557                 ": Initialization file(s) now = " + allFiles)
558             )
559     }
560 #endif
561 
562 }
563 
564 
565 
566 
567 
568 
569 
570 
571 /*
572 ================================================================================
573 Structors
574 ================================================================================
575 */
576 
FlatFileInitializer(GeneticAlgorithm & algorithm)577 FlatFileInitializer::FlatFileInitializer(
578     GeneticAlgorithm& algorithm
579     ) :
580         GeneticAlgorithmInitializer(algorithm),
581         _delim(DEFAULT_DELIM),
582         _fileNames()
583 {
584     EDDY_FUNC_DEBUGSCOPE
585 
586     // override the default requested initial size to zero.
587     // For this initializer, this is the min size.  A value of
588     // 0 will result in using only the Designs found in the file.
589     this->SetSize(0);
590 }
591 
FlatFileInitializer(const FlatFileInitializer & copy)592 FlatFileInitializer::FlatFileInitializer(
593     const FlatFileInitializer& copy
594     ) :
595         GeneticAlgorithmInitializer(copy),
596         _delim(copy._delim),
597         _fileNames(copy._fileNames)
598 {
599     EDDY_FUNC_DEBUGSCOPE
600 }
601 
FlatFileInitializer(const FlatFileInitializer & copy,GeneticAlgorithm & algorithm)602 FlatFileInitializer::FlatFileInitializer(
603     const FlatFileInitializer& copy,
604     GeneticAlgorithm& algorithm
605     ) :
606         GeneticAlgorithmInitializer(copy, algorithm),
607         _delim(copy._delim),
608         _fileNames(copy._fileNames)
609 {
610     EDDY_FUNC_DEBUGSCOPE
611 }
612 
613 
614 
615 
616 
617 
618 
619 
620 /*
621 ================================================================================
622 End Namespace
623 ================================================================================
624 */
625     } // namespace Algorithms
626 } // namespace JEGA
627