# Ask about function file to optimize # Compute many things from it, like number of parameters in the genome # and returntype of same. # open file, where generated program is going to end open( OUTFILE, ">gags.cc" ); #start printing the headers, include files, and whatnots &ADDHEADER; #Include gnuplot-wrapper class header, but only if needed #the variable definition has been appended by the install procedure print OUTFILE "#include \"gstream.hpp\"\n" if ( $gnuplot == 1 ); # Include gnuplot-wrapper #look for the .ga function name, or query for it $funcName= &FUNCNAME; # Now start to parse the function, trying to compute # 1. The number of genes in the chromosome # 2. The dimension of the input vectors, and if there is an input file # Every (processed) function line will be kept inside the $funcLines array, # some thing must be prepended to it before writing it. #------------------------------------------------------------------------ $forRef = $fitnessRef = $funcRef = $sampleRef = 0; # Flags; tell if the subject has been ref'ed open( FUNC, "<$funcName"); $bigstNumFun=$bigstNumTra = 0; # biggest index, for function and input file $idxFun = 0; while () { if ( /#define\s(\w*)\s*(\d*)/ ) { # def'ed constants will be kept inside an associative array $define{$1} = $2; }elsif ( /\sfor[( ]*(\w*)\s=\s\d*[ ;]*\1([ =<]*)(\w*)/) { # This if looks for indices, and their limits. # The regular expression is a model for the beginning of a "for" # loop print "$1 $2 $3\n"; $idxName = $1; if ( $3 =~ /\d/ ) { # only numeric $idxLimit = $3; }else { # Must be a #def'ed constant $idxLimit = $define{$3}; } #$2 is the comparator $idxLimits{ $idxName } = ($2 eq "<")? $idxLimit + 1:$idxLimit; $forRef = 1; }elsif (/\s*(\w*)\s*fitness/) { # look for return type; saved in $returnType variable # regular expression is a model for fitness # Don't know how it will work without double or float. $returnType = $1; # Parenthesized expression print "We're gonna have trouble with this $returnType" if ( ($returnType !~ "float") && ($returnType !~ "double") ); $fitnessRef = 1; }elsif ( /__sample\[\w*\]\[\s*(\w*)\s*\]/ ) { $fooIndex = ($&=~/\d/) ? $&:( $idxLimits{$&} - 1); $bigstNumTra = ( $fooIndex > $bigstNumTra )? $fooIndex: $bigstNumTra; $sampleRef = 1; # Sample is referenced } if ( /__gen\[\s*(\w*)\s*\]/ ) { $fooIndex = ($&=~/\d/) ? $&:( $idxLimits{$&} - 1); $bigstNumFun = ( $fooIndex > $bigstNumFun )? $fooIndex: $bigstNumFun; $funcRef = 1; # Function is referenced } #substitute by "real names" s/FILESIZE/sample.getSize\(\)/g; s/__gen/myGen/g; s/__sample/sample/g; #stick it inside the array $funcLines[$idxFun++] = $_; } #print warnings and fatal errors die "There is no reference to the chromosome...check the .ga file\n" if $funcRef == 0; die "Fitness function does not seem to be defined\ There must be a fitness ( ) definition at the beginning\ of the file\n" if $fitnessRef == 0; print "No reference found to a training file\n" if $sampleRef == 0; # Print everything to the generated program; first the include, if needed print OUTFILE "#include \"ezsample.hpp\"\n" if $sampleRef; print OUTFILE "\n"; $fitnessLine = "$returnType fitness ( genSGAv & myGen "; $fitnessLine .= ", ezSample< float > & sample " if $sampleRef; $fitnessLine .= ") {\n"; # header finished, and customized for ( $i = 0; $i < $idxFun; $i ++ ) { print OUTFILE $funcLines[ $i ] unless $funcLines[$i] =~ /fitness/; print OUTFILE $fitnessLine if $funcLines[$i] =~ /fitness/; } print OUTFILE "\n\n"; #define constant number of loci in a genome $bigstNumFun++; #convert last index to size print OUTFILE "main( int argc, char ** argv ) {\n"; print OUTFILE "const unsigned genSize = $bigstNumFun;\n"; print OUTFILE "\t$returnType rangeStart[genSize], rangeEnd[genSize];\n"; #now start to stuff things into the configuration file #first get the config file name ($funcBase, $foo )=split(/\./, $funcName); open (CONFIG, ">$funcBase.ini"); if ($sampleRef) { $bigstNumTra++; #convert last index to size print "Training file name? "; $trngFileName = ; chop $trngFileName; print CONFIG "inputFile $trngFileName\n"; } #other genome parameters &INPDEFAULT( $numBytes, 2, "Number of bytes per parameter" ); print CONFIG "locusSize $numBytes\n"; print "Parameter range for each parameter [-1, 1] -- there are $bigstNumFun parameters \n"; for( $i = 0; $i < $bigstNumFun; $i ++ ) { &INPDEFAULT( $range, "-1, 1", "Parameter #$i "); ($rgStart, $rgEnd)=split(/,/, $range); $bigRgStart .= $rgStart.(($i != $bigstNumFun -1)?" ":" "); $bigRgEnd .= $rgEnd.(($i != $bigstNumFun -1)?" ":" " ); } print CONFIG "startRange $bigRgStart\n"; print CONFIG "endRange $bigRgEnd\n"; &ADDSCAN; # Adds some variable definition and file scanning &INPDEFAULT( $mutRate, 0.01, "Mutation rate" ); print CONFIG "mutRate $mutRate\n"; &INPDEFAULT( $popSize, 50, "Population size" ); print CONFIG "popSize $popSize\n"; #Mode of reproduction &INPDEFAULT( $repMode, "ELITE", "Reproduction mode (ELITE, ROULWHEEL, TOURNAMENT)" ); print CONFIG "repType $repMode " ; if ( $repMode eq "ELITE" ) { # ask about percentage &INPDEFAULT( $repArg, "0.2", "Percentage of altered population" ); }elsif ( $repMode =~ "TOUR" ) { # ask about size of tournament &INPDEFAULT( $repArg, "7", "Size of the tournament" ); } else { $repArg = ""; } print CONFIG "$repArg\n"; print OUTFILE "\tezSample<$returnType> sample( inputFile, genSize );\n" if $sampleRef == 1; print OUTFILE "\tpopSGAr<$returnType, genSGAv<$returnType> > myPop(popSize, mutRate, genSize, locusSize,rangeStart,rangeEnd);\n"; if ($gnuplot ) { &INPDEFAULT( $gnuStr, "", "Gnuplot initialization string" ); print OUTFILE "\tgstream gout(\"$gnuStr\");\n"; } &INPDEFAULT( $generations, "50", "Number of Generations" ); print CONFIG "Generations $generations\n"; &ADDLOOP; # prints the beginning of the GA loop #output info interval, and output file &INPDEFAULT( $interval, "1", "Output information every ... steps" ); &INPDEFAULT( $outInfo, "FV", "Save\n\tF - fitness\n\tV - best Vector\n\tor both" ); &INPDEFAULT( $outFileN, "STDOUT", "Output file name" ); print OUTFILE "\tif ( g % $interval == 0 ) {\n" if $interval > 1; if ( $outFileN ne "STDOUT" ) { print OUTFILE "\tfstream fout(\"$outFileN\", ios::app| ios::out);\n"; $outFileS = "fout"; } else { $outFileS = "cout"; } print OUTFILE "\t\t$outFileS << myPop.bestIndiv() << endl;\n" if $outInfo =~/V/;; print OUTFILE "\t\t$outFileS << myPop.bestFitness() << endl;\n" if $outInfo =~/F/; print OUTFILE "\t\tgout << myPop.bestFitness();\n"; print OUTFILE "\t\tfout.close();\n" if $outFileN ne "STDOUT"; print OUTFILE "\t}\n" if $interval > 1; &ADDEND; # Add fixed part at the end of the program close OUTFILE; # close program file close CONFIG; # and config file #And try to run it $incFlag =" -I$ENV{'GAGSINC'}" if defined $ENV{'GAGSINC'}; $libFlag =" -L$ENV{'GAGSLIB'}" if defined $ENV{'GAGSLIB'}; if (`g++ gags.cc -o gags $incFlag $libFlag -lGAGS -lm -g` != 0) { die "Problems with compilation...\n"; } &INPDEFAULT( $run, "Y", "Wanna run" ); if ($run=~/[Yy]/) { system "gags $funcBase.ini"; } ########################################################################## # SUBROUTINES # # all subroutines have been included here to avoid having too many # # environment variables around. # ########################################################################## ########################################################################## sub ADDHEADER { # one of the many "append" functions # just prints out those lines # Uses global variable OUTFILE print OUTFILE< 1 ) scanFile(rangeStart, rangeEnd, argv[1], inputFile, popSize, mutRate, generations, locusSize, thisRepMode, uArgRepMode, fArgRepMode, genSize ); else { cout << "Usage: " << argv[0] << " .ini \n"; exit(1); } mysrand(); EOC } ########################################################################## sub FUNCNAME { # Looks for function name. If there is # only one .ga file, takes it; if not, # queries the user $count = 0; #compute number of function files while (<*.ga>) { $funcfoo = $_; $count++; } if ( ($count == 0) || ($count > 1) ) { $funcfoo = ""; askFunc: { print "Function file [*.ga]? "; $funcfoo = ; chop $funcfoo; if ( -e $funcfoo ) { last askFunc; } else { print "File $funcName does not exist\n"; } }; return $funcfoo; } else { return $funcfoo; } } ########################################################################## sub INPDEFAULT { # for input with a default value... must use the original variables; # call is by reference # 0 - variable to assign # 1 - default value # 2 - message print $_[2]."? [".$_[1]."] "; $_[0] = ; if ($_[0]!~/\w/) { $_[0] = $_[1]; } else { chop $_[0]; } } ################################################################### sub ADDEND { # Adds the end of the program # Uses global variable OUTFILE print OUTFILE <