/*************************************************************************
* Project: Library of Evolutionary Algoriths
*************************************************************************
* Author: Changhe Li & Ming Yang
* Email: changhe.lw@google.com Or yangming0702@gmail.com
* Language: C++
*************************************************************************
*  This file is part of EAlib. This library 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 2, or (at your option) any later version.
*************************************************************************/
// Created: 29 Nov 2011
// Last modified:
#include "SelfLearnParticle.h"

SelfLearnParticle::SelfLearnParticle():Particle(),m_itersUnimpr(0),m_updateFre(0),m_learnRatio(0)
{
    //ctor
    mp_prog=Progress::allocateMemoryProgress(ms_numOperators);
    mp_monitor=Progress::allocateMemoryProgress(ms_numOperators);

}

SelfLearnParticle::~SelfLearnParticle()
{
    //dtor
    if(mp_prog){
		delete []mp_prog;
		mp_prog=0;
	}

	if(mp_monitor){
		delete []mp_monitor;
		mp_monitor=0;

	}
}

SelfLearnParticle::SelfLearnParticle( SelfLearnParticle& other):Particle(other)
{
    //copy ctor
    mp_prog=Progress::allocateMemoryProgress(ms_numOperators);
    mp_monitor=Progress::allocateMemoryProgress(ms_numOperators);

    m_itersUnimpr=other.m_itersUnimpr;
	m_updateFre=other.m_updateFre;
	m_learnRatio=other.m_learnRatio;

    gCopy<Progress>(mp_prog,other.mp_prog,ms_numOperators);
    gCopy<Progress>(mp_monitor,other.mp_monitor,ms_numOperators);


}

SelfLearnParticle& SelfLearnParticle::operator=( SelfLearnParticle& rhs)
{
    if (this == &rhs) return *this; // handle self assignment
    //assignment operator

    Particle::operator=(rhs);
	m_itersUnimpr=rhs.m_itersUnimpr;
	m_updateFre=rhs.m_updateFre;
	m_learnRatio=rhs.m_learnRatio;

    gCopy<Progress>(mp_prog,rhs.mp_prog,ms_numOperators);
    gCopy<Progress>(mp_monitor,rhs.mp_monitor,ms_numOperators);


    return *this;
}




void SelfLearnParticle::initialize(bool mode){
    Particle::initialize(mode);

    defaultSet();
}
void SelfLearnParticle::initialize(const int idex,const int id,bool mode){
     Particle::initialize(idex,id,mode);
    defaultSet();
}
void SelfLearnParticle::initialize(Chromosome &p,const int idex,const int id){
     Particle::initialize(p,idex,id);
    defaultSet();
}
void SelfLearnParticle::initialize(Chromosome &p,double radius,const int idex,const int id,bool mode){
    Particle::initialize(p,radius,idex,id,mode);
    defaultSet();

}
void SelfLearnParticle::initialize(int rIdx,int rID,PopInitMethod rMethod, int rPopsize,bool mode){
    Particle::initialize(rIdx,rID,rMethod,rPopsize,mode);
    defaultSet();

}
void SelfLearnParticle::initialize(Chromosome *w, int mode,bool mode2){
    Particle::initialize(w,mode,mode2);
    defaultSet();

}

void SelfLearnParticle::defaultSet(){

    m_itersUnimpr=0;
	m_flag=false;
	m_updateFre=0;
	m_learnRatio=0;

	for(int i=0;i<ms_numOperators;i++)	{
	    mp_prog[i].initialize(ms_numOperators);

		if(m_flag)
		mp_prog[i].m_ratio=1./ms_numOperators;
		else{
			if(i==ms_numOperators-1)mp_prog[i].m_ratio=0.0;
			else mp_prog[i].m_ratio=1./(ms_numOperators-1);
		}

		mp_monitor[i]=mp_prog[i];
	}

}
void SelfLearnParticle::setSelRatio(){
	for(int i=0;i<ms_numOperators;i++)	{
		if(m_flag)
		mp_prog[i].m_ratio=1./ms_numOperators;
		else{
			if(i==ms_numOperators-1)mp_prog[i].m_ratio=0.0;
			else mp_prog[i].m_ratio=1./(ms_numOperators-1);
		}

		mp_prog[i].m_minRatio=0.001;
		mp_prog[i].m_numSelected=0;
		mp_prog[i].m_numSuccess=0;
		mp_prog[i].m_rewards=0;
		mp_monitor[i]=mp_prog[i];
	}

}
void SelfLearnParticle::nonLearnToLearn(){
    for( int m=0;m<ms_numOperators;m++){
        mp_prog[m].initialize(ms_numOperators);
	}

	double sum=0;

	for(int m=0;m<ms_numOperators-1;m++) sum+=mp_monitor[m].m_ratio;

	int m;
	for( m=0;m<ms_numOperators-1;m++)	{
		mp_monitor[m].m_ratio=(double)(ms_numOperators-1.)/ms_numOperators*(mp_monitor[m].m_ratio/sum);

	}
	mp_monitor[m].initialize(ms_numOperators);

}
void SelfLearnParticle::learnToNonLearn(){
    double sum=0;
	for(int j=0;j<ms_numOperators-1;j++)
		sum+=mp_prog[j].m_ratio;
	for(int j=0;j<ms_numOperators-1;j++)
		mp_prog[j].m_ratio=mp_prog[j].m_ratio/sum;

	mp_prog[ms_numOperators-1].m_ratio=0;
	sum=0;
	for(int j=0;j<ms_numOperators-1;j++)
		sum+=mp_monitor[j].m_ratio;
	for(int j=0;j<ms_numOperators-1;j++)
		mp_monitor[j].m_ratio=mp_monitor[j].m_ratio/sum;
	mp_monitor[ms_numOperators-1].m_ratio=0;

}
void SelfLearnParticle::updateSelectionRatioMonitor(){

    if(m_flag)
		Progress::updateProgress(mp_monitor,ms_numOperators);
	else
		Progress::updateProgress(mp_monitor,ms_numOperators-1);

	for(int j=0;j<ms_numOperators;j++){
        mp_monitor[j].m_numSelected=0;
        mp_monitor[j].m_numSuccess=0;
        mp_monitor[j].m_rewards=0;
    }
}
void SelfLearnParticle::updateSelectionRatioProg(){
    if(m_flag)
		Progress::updateProgress(mp_prog,ms_numOperators);
	else
		Progress::updateProgress(mp_prog,ms_numOperators-1);

	for(int j=0;j<ms_numOperators;j++){
			mp_prog[j].m_numSelected=0;
			mp_prog[j].m_numSuccess=0;
			mp_prog[j].m_rewards=0;
	}

}
int SelfLearnParticle::selectOperator(){
    if(m_flag)	return Progress::getAction(ms_numOperators,mp_prog);
	else	return Progress::getAction(ms_numOperators-1,mp_prog);

}

void SelfLearnParticle::move(Chromosome &lbest,double w, double c1){

	double l,u;
	for(int j=0;j<Global::g_dimNumber;j++){
        Global::gp_problem->getSearchRange<double>(l,u,j);
        mp_vel[j]=w*mp_vel[j]+c1*Global::gp_uniformAlg->Next()*(lbest.getGene<double>(j) -m_pself.getGene<double>(j));
        if(mp_vel[j]>mp_vMax[j].m_max)	mp_vel[j]=mp_vMax[j].m_max;
        else if(mp_vel[j]<mp_vMax[j].m_min)		mp_vel[j]=mp_vMax[j].m_min;
		m_pself.getGene<double>(j)+= mp_vel[j];

	}
	m_pself.validate();
	m_pself.evaluate();


}
