1#include "../ECF_base.h" 
    2#include "../SelRandomOp.h" 
    3#include "../SelFitnessProportionalOp.h" 
    4#include "../SelWorstOp.h" 
    5#include "../ECF_macro.h" 
   16#pragma region Intro comments 
   30bool cmp (ClassifierP a, ClassifierP b){
 
   31    return a->ind->fitness->getValue() > b->ind->fitness->getValue();
 
   40    selRandomOp = 
static_cast<SelectionOperatorP
> (
new SelRandomOp);
 
   42    selWorstOp = 
static_cast<SelectionOperatorP
> (
new SelWorstOp);
 
   51    params->registerParams(state->getRegistry());
 
   54    ClassifierParamsP params = 
static_cast<ClassifierParamsP
> (
new ClassifierParams(0,0,0));
 
   55    state->addGenotype(params);
 
   60    if (!Classifier::checkState(state)) {
 
   64    selRandomOp->initialize(state);
 
   65    selWorstOp->initialize(state);
 
   66    selFitPropOp->initialize(state);
 
   68    params->readParams(state->getRegistry());
 
   72    ClassifierParamsP clParams = 
static_cast<ClassifierParamsP
> (
new ClassifierParams(0,0,0));
 
   73    clParams->setGenotypeId(3);
 
   74    clParams->initialize(state);
 
   75    params->initF_ = clParams->F_;
 
   78    environment = boost::dynamic_pointer_cast<Environment> (
evalOp_);
 
   80    if (!environment->checkState(state)) {
 
   85        if (!environment->initialize()){
 
   86            throw (std::string(
"failed to initialize"));
 
   88    }
catch (std::string text){
 
   89        ECF_LOG_ERROR(state, 
"Environment error: "+text);
 
   95void XCS::printPopulation(){
 
   97    for (uint i = 0; i < populationSet.size(); i++)
 
   98        populationSet[i]->print();
 
  103    if (state->getGenerationNo() == 0){
 
  107        PopulationP pop = state->getPopulation();
 
  109        for (uint i = 0; i < pop->size(); i++){
 
  110            for (uint j = 0; j < pop->at(i)->size(); j++){
 
  111                classP = 
static_cast<ClassifierP
>  
  112                    (
new Classifier(params, time, pop->at(i)->at(j), state));
 
  113                populationSet.push_back(classP);
 
  117        for (uint i = 0; i < deme->size(); i++)
 
  118            deme->at(i)->fitness->setValue(params->initF_);
 
  119        environment->reset();
 
  122    std::vector<ClassifierP> lastActionSet;  
 
  123    double lastReward = 0;
 
  130        std::cout << 
"Press any key to continue..." << std::endl;
 
  134        std::vector<ClassifierP> matchSet; 
 
  135        std::vector<ClassifierP> actionSet;
 
  138        GenotypeP input = environment->getInput();
 
  141        std::cout << 
"Input value: ";
 
  142        Classifier::printBitString(boost::dynamic_pointer_cast<BitString::BitString> (input));
 
  143        std::cout << std::endl;
 
  146        matchSet = generateMatchSet(state, deme, input); 
 
  149        std::cout << 
"Match set [M]: "<< std::endl;
 
  150        for (uint i = 0; i < matchSet.size(); i++)
 
  151            matchSet[i]->print();
 
  155        std::map<int, double> PA = generatePA(matchSet);    
 
  158        int actionId = selectActionId(state, PA);
 
  160        std::cout << 
"action id = " << actionId<< std::endl;
 
  164        actionSet = generateActionSet(matchSet, actionId);
 
  167        std::cout << 
"\nAction set [A]: "<< std::endl;
 
  168        for (uint i = 0; i < actionSet.size(); i++)
 
  169            actionSet[i]->print();
 
  173        IndividualP ind = 
static_cast<IndividualP
> (
new Individual);
 
  174        ind->push_back(input);
 
  175        ind->push_back(actionSet[0]->getAction());
 
  179        double reward = ind->fitness->getValue();
 
  182        std::cout << 
"Reward: " << reward << std::endl;
 
  185        if (!lastActionSet.empty()){
 
  186            double P = lastReward + params->gama_ * getMaxFromPA(PA).second;
 
  188            updateActionSet(lastActionSet, deme,  P, state);
 
  189            if (!environment->isExploit()) {
 
  190                runGA(lastActionSet, lastInput, deme, state);
 
  193        if (environment->isOver()) {
 
  195            if (!environment->isExploit()) {
 
  196                updateActionSet(actionSet, deme, reward, state);
 
  198                runGA(actionSet, input, deme, state);
 
  199                lastActionSet.clear();
 
  203            lastActionSet = actionSet;
 
  207    } 
while (!environment->isOver());
 
  209    environment->nextTrial();
 
  212    std::cout << 
"Classifiers:" << std::endl;
 
  214    std::cout << 
" ===== advanceGeneration end ====="<< std::endl;
 
  220std::vector<ClassifierP> XCS::generateMatchSet(StateP state, DemeP deme, GenotypeP input) {
 
  223    std::vector<ClassifierP> matchSet;
 
  225    while(matchSet.empty()){
 
  227        for (uint i = 0; i < populationSet.size(); ++i){
 
  228            if (populationSet[i]->doesMatch(input))
 
  229                matchSet.push_back(populationSet[i]);
 
  232        uint noDiffActions = (uint) getActionsFromMs(matchSet).size();
 
  233        if (noDiffActions < params->mna_){
 
  235            ClassifierP coverCl = cover(state, deme, input, matchSet);
 
  236            deleteFromPopulation(state, deme);
 
  244std::set<int> XCS::getActionsFromMs (std::vector<ClassifierP> matchSet){
 
  246    std::set<int> actions;
 
  247    for (uint i = 0; i < matchSet.size(); ++i){
 
  248        actions.insert(matchSet[i]->getActionId());
 
  255ClassifierP XCS::cover (StateP state, DemeP deme, GenotypeP input, std::vector<ClassifierP> matchSet){
 
  257    IndividualP newInd = 
static_cast<IndividualP
> (
new Individual(state));
 
  259    ClassifierP newClassifier = 
static_cast<ClassifierP
> (
new  
  263    newClassifier->cover(getActionsFromMs(matchSet), input, state);
 
  264    newInd->index = (uint)deme->size();
 
  266    populationSet.push_back(newClassifier);
 
  267    deme->push_back(newInd);
 
  269        assert(deme->size() == populationSet.size());
 
  271    return newClassifier;
 
  275std::map<int, double> XCS::generatePA(std::vector<ClassifierP> matchSet){
 
  276    std::map<int, double> PA;
 
  277    std::map<int, double> fsa; 
 
  279        for (uint i = 0; i < matchSet.size(); ++i){
 
  281            ClassifierP cl = matchSet[i];
 
  282            double fitness = cl->getFitness();
 
  283            int action = cl->getActionId();
 
  285            if(PA[action] == NULL) {
 
  286                PA[action] = cl->getPrediction() * fitness;
 
  289                PA[action] += cl->getPrediction() * fitness;
 
  290            fsa[action] += fitness;
 
  292        for (std::map<int, double>::iterator it = PA.begin(); it != PA.end(); ++it){
 
  293            PA[it->first] /= (fsa[it->first] == 0 ? 1 : fsa[it->first]);
 
  299int XCS:: selectActionId(StateP state, std::map<int, double> PA){
 
  300    double rnd = state->getRandomizer()->getRandomDouble();
 
  301    int actionId = PA.begin()->first;
 
  304    if (environment->isExploit())
 
  305        return getMaxFromPA(PA).first;
 
  307    if (rnd < params->p_explore_) {
 
  309        rnd = state->getRandomizer()->getRandomDouble();
 
  311        for (std::map<int, double>::const_iterator it = PA.begin(); it != PA.end(); ++it){
 
  312            if (i > PA.size() * rnd){
 
  313                actionId = it->first;
 
  320        actionId = getMaxFromPA(PA).first;  
 
  325std::vector<ClassifierP> XCS::generateActionSet(std::vector<ClassifierP> matchSet, 
int actionId){
 
  326    std::vector<ClassifierP> actionSet;
 
  327    for (uint i = 0; i < matchSet.size(); i++)
 
  328        if (matchSet[i]->getActionId() == actionId)
 
  329            actionSet.push_back(matchSet[i]);
 
  333void XCS::updateActionSet(std::vector<ClassifierP> actionSet, DemeP deme, 
double reward, StateP state){
 
  337    std::vector<double> accuracy;
 
  340    for (uint i = 0; i < actionSet.size(); ++i)
 
  341        numSum += actionSet[i]->getNumerosity();
 
  344    for (uint i = 0; i < actionSet.size(); ++i){
 
  347        double exp = cl->getExperience() + 1;
 
  348        cl->setExperience(exp);
 
  350        double eps = cl->getError();
 
  351        double p = cl->getPrediction();
 
  352        double as = cl->getActSetSize();
 
  354        if (exp < 1 / params->beta_) {
 
  355            p += (reward - p) / exp;
 
  356            eps += (fabs(reward - p) - eps) / exp;
 
  357            as += (numSum - as) / exp;
 
  359            p += params->beta_ * (reward - p);
 
  360            eps += params->beta_ * (fabs(reward - p) - eps);
 
  361            as += params->beta_ * (numSum - as);
 
  364        if (eps < params->eps0_)
 
  365            accuracy.push_back(1);
 
  367            accuracy.push_back( params->alpha_ * pow(eps / params->eps0_, -params->accExp_) );
 
  369        sum += accuracy[i] * cl->getNumerosity();
 
  371        cl->setPrediction(p);
 
  373        cl->setActSetSize(as);
 
  377    for (uint i = 0; i < actionSet.size(); ++i){
 
  381        double F = cl->getFitness();
 
  382        F += params->beta_ * (accuracy[i] * cl->getNumerosity() / sum - F) ;
 
  386    actionSetSubsumption(&actionSet, deme, state);
 
  390double XCS::getAsTimeSum(std::vector<ClassifierP> as) {
 
  392    double sumNum = 0, sumTsNum = 0;
 
  393    for (uint i = 0; i < as.size(); ++i){
 
  394        sumTsNum += as[i]->getTimeStamp() * as[i]->getNumerosity();
 
  395        sumNum += as[i]->getNumerosity();
 
  398    return sumTsNum / sumNum;
 
  401void XCS::runGA(std::vector<ClassifierP> actionSet, GenotypeP genInput, DemeP deme, StateP state){
 
  403    if (time - getAsTimeSum(actionSet) < params->thresholdGA_) 
return;
 
  405    std::vector<IndividualP> tournament, vActionSet;
 
  407    for (uint i = 0; i < actionSet.size(); i++) {
 
  408        if (!actionSet[i]->valid) 
continue;
 
  409        vActionSet.push_back(actionSet[i]->ind);
 
  410        actionSet[i]->setTimeStamp(time);
 
  412    if (vActionSet.size() < 1) 
return;
 
  414    IndividualP parent[2];
 
  415    parent[0] = selFitPropOp->select(vActionSet);
 
  416    parent[1] = selFitPropOp->select(vActionSet);
 
  418    ClassifierP clParent[2];
 
  419    clParent[0] = populationSet[parent[0]->index];
 
  420    clParent[1] = populationSet[parent[1]->index];
 
  422    assert(clParent[0]->getActionId() == clParent[1]->getActionId());
 
  423    ClassifierP clChild[2];
 
  425    for (
int i = 0; i < 2; ++i) {
 
  427        clChild[i] = 
static_cast<ClassifierP
> (
new Classifier(clParent[i]));
 
  429        clChild[i]->setNumerosity(1);
 
  430        clChild[i]->setExperience(0);
 
  432        double f = clChild[i]->getFitness();
 
  434        if (state->getRandomizer()->getRandomDouble() < params->pCrossover_) {
 
  435            mate(parent[0], parent[1], clChild[i]->ind);
 
  437            clChild[i]->setAction(clParent[0]->getAction());
 
  439            assert(clChild[i]->getActionId() == clParent[i]->getActionId());
 
  441            clChild[i]->setPrediction((clParent[0]->getPrediction() + clParent[1]->getPrediction()) / 2);
 
  442            clChild[i]->setError((clParent[0]->getError() + clParent[1]->getError()) / 2);
 
  444            f = (clParent[0]->getFitness() + clParent[1]->getFitness()) / 2;
 
  447        clChild[i]->setFitness( 0.1 * f);
 
  449        clChild[i]->mutateRule(genInput, state);
 
  450        clChild[i]->mutateAction(state);
 
  452        if (clParent[0]->doesSubsume(clChild[i])) {
 
  453            clParent[0]->setNumerosity(clParent[0]->getNumerosity() + 1);
 
  454        } 
else if (clParent[1]->doesSubsume(clChild[i])) {
 
  455            clParent[1]->setNumerosity(clParent[1]->getNumerosity() + 1);
 
  457            clChild[i]->ind->index = (uint)deme->size();
 
  458            populationSet.push_back(clChild[i]);
 
  459            deme->push_back(clChild[i]->ind);
 
  461            assert(deme->size() == populationSet.size());
 
  463        deleteFromPopulation(state, deme);
 
  467std::pair<int, double> XCS::getMaxFromPA(std::map<int, double> PA){
 
  469    if (PA.empty()) 
return std::make_pair(-1, -1.);
 
  471    std::pair<int, double> maxPA = *PA.begin();
 
  472    for (std::map<int, double>::iterator it = PA.begin(); it != PA.end(); ++it){
 
  473        if (it->second > maxPA.second)
 
  479void XCS::deleteFromPopulation(StateP state, DemeP deme) {
 
  484    for ( uint i = 0; i < populationSet.size(); ++i) {
 
  485        sumNum += populationSet[i]->getNumerosity();
 
  486        sumFit += populationSet[i]->getFitness();
 
  488    if (sumNum <= (
int) params->popSize_) 
return;
 
  490    double avFitInPop = sumFit / sumNum;
 
  493    for ( uint i = 0; i < populationSet.size(); ++i) {
 
  494        sumVote += populationSet[i]->getDeletionVote(avFitInPop);
 
  496    double choicePoint = state->getRandomizer()->getRandomDouble() * sumVote;
 
  498    for ( uint i = 0; i < populationSet.size(); ++i) {
 
  499        ClassifierP cl = populationSet[i];
 
  500        sumVote += cl->getDeletionVote(avFitInPop);
 
  501        if (sumVote > choicePoint) {
 
  502            int n = cl->getNumerosity();
 
  504                cl->setNumerosity(n-1);
 
  506                removeFromPopSet(cl, deme);
 
  511    assert(deme->size() == populationSet.size());
 
  515void XCS::removeFromPopSet(ClassifierP cl, DemeP deme){
 
  517    IndividualP lastInd = deme->at(deme->size()-1);
 
  518    ClassifierP lastCl = populationSet[populationSet.size()-1];
 
  520    lastInd->index = cl->ind->index;
 
  522    populationSet[cl->ind->index] = lastCl;
 
  523    populationSet.erase(populationSet.begin() + populationSet.size() - 1);
 
  525    deme->at(cl->ind->index) = lastInd;
 
  526    deme->erase(deme->begin() + deme->size() - 1);
 
  528    assert(deme->size() == populationSet.size());
 
  532void XCS::actionSetSubsumption(std::vector<ClassifierP> *actionSet, DemeP deme, StateP state){
 
  536    for (uint i = 0; i < actionSet->size(); ++i){
 
  538        ClassifierP c = actionSet->at(i);
 
  539        if (c->couldSubsume()){
 
  541            int clDcb = c->numOfDCBits();
 
  542            double rnd = state->getRandomizer()->getRandomDouble();
 
  543            if (!clSet || clDcb > cl->numOfDCBits() || (clDcb == cl->numOfDCBits() && rnd < 0.5 )) {
 
  550        for (uint i = 0; i < actionSet->size(); ++i){
 
  551            ClassifierP c = actionSet->at(i);
 
  552            if (cl->isMoreGeneral(c)){
 
  553                cl->setNumerosity(cl->getNumerosity() + c->getNumerosity());
 
  554                actionSet->erase(actionSet->begin() + i);
 
  555                removeFromPopSet(c,deme);
 
EvaluateOpP evalOp_
sptr to evaluation operator (set by the system)
 
std::string name_
algorithm name
 
bool mate(IndividualP p1, IndividualP p2, IndividualP child)
Helper function: crossover two individuals.
 
void evaluate(IndividualP ind)
Helper function: evaluate an individual.
 
Classifier class that holds all parameters and pointer to individual to which the parameters belong.
 
Classifier data structure in XCS algorithm.
 
Individual class - inherits a vector of Genotype objects.
 
Fitness proportional (and inverse proportional) individual selection operator.
 
Random individual selection operator.
 
Worst individual selection operator.
 
bool advanceGeneration(StateP state, DemeP deme)
Perform a single generation on a single deme.
 
bool initialize(StateP state)
Initialize the algorithm, read parameters from the system, do a sanity check.
 
void registerParameters(StateP state)
Register algorithm's parameters (if any).
 
Parameters for the XCS algorithm.