/* "Species" - a CoreWars evolver. Copyright (C) 2003 'Varfar' * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 1, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "species.hpp" #include "inst_gen_weighted_random.hpp" #include "rand.hpp" #include "opcode_branch_lookup.hpp" using namespace std; /***** CInstGeneratorWeightedRandom class implementation *********************/ CInstGeneratorWeightedRandom::CInstGeneratorWeightedRandom() { _type = WEIGHTED_RANDOM; // very important line! // init the freq_hint table to default values _freq_hint_sum = 0.0F; for(int i=0; i val) PANIC(NEG_OPCODEFREQ_HINT,"attempt to set negative freq_hint",NULL); _freq_hint_sum -= _freq_hint[opcode]; _freq_hint[opcode] = val; _freq_hint_sum += _freq_hint[opcode]; if(0.0F == _freq_hint_sum) PANIC(ZERO_OPCODEFREQ_HINT_SUM,"total freq_hints have zero sum",NULL); } void CInstGeneratorWeightedRandom::suggest_instruction(insn_t &instruction,const MODE /*mode*/) { // NOTE: might be more fair to maintain a _branch_hint_sum and scale the roulette to a single pass // generate a random number between 0.0F and freq_hint_sum const float x = CRand::frand(_freq_hint_sum); // the target value float y = 0.0F, // an iterator through all buckets bucket, // an intermediary for weighing branch instructions branch_weight = 1.0F; // a scale relative to the pivot int i; // need to weigh branches? if(_branch_bias) { // seek back to find a branch for(i=index()-1; i>0; --i) { if(OPCODE_IS_BRANCH[chromosome()->code(i).opcode()]) { // found? // calculate weight based on distance to pivot branch_weight = ((index()-i) / _branch_pivot); break; // stop searching then } } } // rolette-wheel to the choosen instruction do { for(i=0; i x) { // found? generate_completely_random(instruction); instruction.set_opcode((OPCODE)i); return; } } if(!_branch_bias) cerr << "WARNING: roulette past end of freq_hint range" << endl; } while(true); } void CInstGeneratorWeightedRandom::read_ini_impl(INIFile &ini) { // load the freq_hints int i; KeyValuePair *kvp; // opcodes for(i=0; igetValueAsFloat(OPCODE_FREQ_HINT_DEFAULT)); } // branch pivot? kvp = ini.get("branch_bias"); if(0 != kvp) { // set _branch_bias = kvp->getValueAsBool(_branch_bias); if(_branch_bias) { kvp = ini.get("branch_pivot"); if(0 != kvp) { _branch_pivot = kvp->getValueAsInt(_branch_pivot); if(1 > _branch_pivot) { // avoid a divzero further down the line! PANIC(NEG_OPCODEFREQ_HINT,"branch_pivot cannot be less than 1",NULL); } } } } } CInstGenerator *CInstGeneratorWeightedRandom::read_override_ini_impl(INIFile &ini) { CInstGeneratorWeightedRandom *ret = this; int i, pivot; bool bias; KeyValuePair *kvp; // load the freq_hints for(i=0; iset_freq_hint((OPCODE)i,kvp->getValueAsFloat(OPCODE_FREQ_HINT_DEFAULT)); } } // bias? kvp = ini.get("branch_bias"); if(0 != kvp) { // set? bias = kvp->getValueAsBool(ret->_branch_bias); if(bias != ret->_branch_bias) { // overriden? if(this == ret) { // first thing to be overriden? ret = new CInstGeneratorWeightedRandom(*this); // create a copy } ret->_branch_bias = bias; } kvp = ini.get("branch_pivot"); } // pivot? We'll ignore in the case when bias isn't set to keep things clean if(ret->_branch_bias) { kvp = ini.get("branch_pivot"); if(0 != kvp) { // set? pivot = kvp->getValueAsInt(ret->_branch_pivot); if(1 > pivot) { // avoid a divzero further down the line! PANIC(NEG_OPCODEFREQ_HINT,"branch_pivot cannot be less than 1",NULL); } if(pivot != ret->_branch_pivot) { if(this == ret) { // first thing to be overriden? ret = new CInstGeneratorWeightedRandom(*this); // create a copy } ret->_branch_pivot = pivot; } } } // done return ret; } void CInstGeneratorWeightedRandom::write_ini(ostream &os) { int i; // list freq_hints for(i=0; i_branch_bias) { os << "branch_bias=" << _branch_bias << endl; } if(_branch_bias && (_branch_pivot != ((CInstGeneratorWeightedRandom*)parent)->_branch_pivot)) { os << "branch_pivot=" << _branch_pivot << endl; } }