Commit d14eaec3 authored by Alexis Lebis's avatar Alexis Lebis

working Hlevel systems, with some conceptual flaw for now

parent 0d6209d6
......@@ -10,6 +10,7 @@
#include <model/magnitude.h>
#include <model/tools.h>
#include <model/competency.h>
#include <model/competencyDistribution.h>
#include <model/decay.h>
#include <model/ea/cursus.h>
......@@ -75,7 +76,8 @@ int main(int argc, char* argv[]){
unsigned int JOB_MAXPRE = parser.createParam((unsigned int)(4), "jobMaxPre" , "maximal competency prerequisite by a job", 'J', "Param").value();
double JOB_MINMAG = parser.createParam((double)(0.5), "jobMinMag" , "miminal magnitude for a job" , 'h', "Param").value();
double JOB_MAXMAG = parser.createParam((double)(0.95), "jobMaxMag" , "maxima magnitude for a job" , 'H', "Param").value();
Profession::JOB_SELECTION_TYPE = parser.createParam((unsigned int)(0), "jobSelectType" , "Which type to use to select job", 'z', "Param").value();
Profession::JOB_EVAL_DISCRETE = parser.createParam((unsigned int)(1), "jobEvalDiscrete" , "What type of metric to use between discret and continue with mag", 'Z', "Param").value();
//EVOLUTION ENGINE PARAMETERS
unsigned int POPSIZE = parser.createParam((unsigned int)(100), "popSize", "Population size", 'P', "Evolution Engine").value();
double PMUT = parser.createParam((double)(0.5), "pMut", "mutation rate", 'x', "Evolution Engine").value();
......@@ -309,7 +311,16 @@ int main(int argc, char* argv[]){
if(localDisplay)
{
std::cout << pb << std::endl;
std::cout << job << std::endl;
std::vector<Competency> compHL = CompetencyDistribution::upToHLevel(pb,2);
std::cout << "HL GTTING" << std::endl;
for(int i = 0 ; i < compHL.size(); i++)
std::cout << compHL[i] << std::endl;
std::cout << "===== CURRENT POP =====" << std::endl;
// pop.printOn(std::cout);
pop.best_element().printOn(std::cout);
std::cout << " fitness:" << pop.best_element().fitness() << std::endl;
std::cout << "Stats & metrics: \n" << std::endl;
......
......@@ -10,6 +10,7 @@ SET (EXERCICE_SOURCES
profession.cpp
problem.cpp
decay.cpp
competencyDistribution.cpp
)
ADD_LIBRARY(lModel STATIC ${EXERCICE_SOURCES})
......
......@@ -145,7 +145,7 @@ void Competency::saveDecay()
// === OPERATOR
std::ostream& operator<<(std::ostream& Stream, const Competency & c)
{
std::string s = "Competency\n\tid:"+std::to_string(c.id())+"\n\tname:"+c.c_name()+"\n\tvalue:"+std::to_string(c.competencyValue());
std::string s = "Competency\n\tid:"+std::to_string(c.id())+"\n\tname:"+c.c_name()+"\n\tvalue:"+std::to_string(c.competencyValue())+"\n\tHLevel:"+std::to_string(c.hLevel());
Stream << s ;
return Stream;
}
......
......@@ -23,7 +23,7 @@ class Competency
std::string _name;
int _howLongDecaying; //Decay related
bool _isDecaying; //Decay related
int _hLevel; // Hierarchy level (HL) of the competency. HL should onlye have lower HL comp as prereq. thus HL 0 has no prereq
//Constructor
Competency(int, Magnitude, std::string);
......@@ -64,12 +64,15 @@ class Competency
///Retrieves the name of the competency
const std::string c_name() const {return this->_name;}
std::string & name() {return this->_name;}
int hLevel() const{return this->_hLevel;}
int id() const {return this->_id;}
// === SETTER
void setMagnitude(Magnitude & m){this->_m = m;}
void setName(std::string s){this->_name = s;}
void setHL(int hl){this->_hLevel = hl;}
// === DECAY
bool isDecaying() const {return this->_isDecaying;}
......
#include <iostream>
#include "competencyDistribution.h"
void CompetencyDistribution::linearDistribution(CSDVP &pb)
{
int interval = CompetencyDistribution::HLevelRange(pb);
if(pb.cfg_competencyByCourseMin() != 0) //if the min borne is not 0, we add another interval for comp with no prereq
interval++;
int nbCompByHL = pb.cfg_quantityCompetencies() / interval;
std::cout << "Interval" << interval << " -- nbCompByHL:" << nbCompByHL << std::endl;
for(int i = 0; i < pb.cfg_quantityCompetencies() && i < nbCompByHL * interval; i++)
{
pb.unlocked_competenciesCatalogue().at(i).setHL(i/nbCompByHL);
}
//Taking into account comp missed with the division
int diff = pb.cfg_quantityCompetencies() - nbCompByHL*interval;
int idxInterval = 0;
for(int i = pb.cfg_quantityCompetencies()-1; i >= nbCompByHL*interval; i--)
{
pb.unlocked_competenciesCatalogue().at( i ).setHL(idxInterval%interval);
idxInterval++;
}
}
// === STATIC
int CompetencyDistribution::HLevelRange(CSDVP & pb)
{
int interval = pb.cfg_competencyByCourseMax() - pb.cfg_competencyByCourseMin();
return interval;
}
std::vector<Competency> CompetencyDistribution::getHLevel(CSDVP & pb, int level)
{
std::vector<Competency> comp = std::vector<Competency>();
if(level < 0)
return comp;
if(level > CompetencyDistribution::HLevelRange(pb))
return comp;
std::vector<Competency> pbComp = pb.competencyCatalogue();
for(int i = 0; i < pbComp.size(); i++)
if(pbComp[i].hLevel() == level)
comp.push_back(pbComp[i]);
return comp;
}
std::vector<Competency> CompetencyDistribution::upToHLevel(CSDVP & pb, int level)
{
std::vector<Competency> res = std::vector<Competency>();
std::vector<Competency> tmp; //dry prog
int start;
for(start = 0; start <= level ; start++)
{
tmp = CompetencyDistribution::getHLevel(pb, start);
for(int i = 0; i < tmp.size(); i++)
res.push_back(tmp[i]);
}
return res;
}
\ No newline at end of file
#ifndef SRC_COMPETENCY_DISTRIBUTION_H_
#define SRC_COMPETENCY_DISTRIBUTION_H_
#include <vector>
#include "problem.h"
#include "competency.h"
/**
* Represents the distribution of prerequisites from competencies.
*
* This is used to implement some hierarchy between competencies.
* CompetencyDistribution must be called after the competencies has been created within the problem
* and preferably before the compentecies have been affected to the courses.
*
* @author alexis.lebis
* @version 1
*/
class CompetencyDistribution
{
public:
void linearDistribution(CSDVP &);
// === STATIC
static int HLevelRange(CSDVP &); //return the range max (starting from 0) of the HL
static std::vector<Competency> getHLevel(CSDVP &, int); // returns all the competency of a given HL
static std::vector<Competency> upToHLevel(CSDVP &, int); // retrieves all the comp comprised between [0;int] (and NOT [0;int[)
};
#endif // SRC_COMPETENCY_DISTRIBUTION_H_
\ No newline at end of file
......@@ -72,16 +72,26 @@ std::pair<bool, double> ConstraintsProfession::integrityCheck(Cursus indiv)
//Now that we have evolve all the tmp competency, we compate their mag to the requirement. We count how many is not met to define the metric
int score = 0;
double magDiff = 0; // addendum from HL
for(int i = 0; i < this->_job.prerequisites().size(); i++)
{
if(compToAnswer.at(i).magnitude().value() < this->_job.prerequisites().at(i).c_magnitude().value())
{
score++;
magDiff += ( this->_job.prerequisites().at(i).c_magnitude().value() - compToAnswer.at(i).magnitude().value() ) / this->_job.prerequisites().at(i).c_magnitude().value() ;
}
}
//std::cout << "Score: " << std::to_string(score) << std::endl;
//std::cout << "Size: " << std::to_string(compToAnswer.size()) << std::endl;
bool res = score == 0;
return std::pair<bool, double>(res, 1 - ( (double)score / (double)compToAnswer.size()));
switch (Profession::JOB_EVAL_DISCRETE) //whether we use discrete or continue metrics
{
case 0:
return std::pair<bool, double>(res, 1 - ( magDiff / (double)compToAnswer.size() ) );
default:
return std::pair<bool, double>(res, 1 - ( (double)score / (double)compToAnswer.size()));
}
}
......@@ -53,6 +53,15 @@ Course::Course(int id, int ects, std::string name)
// === GETTER
//cf. course.h
const int Course::lastTimeFrame() const
{
int max = this->_temporalAvailability[0];
for(int i = 1; i < this->_temporalAvailability.size(); i++)
if(max < this->_temporalAvailability[i])
max = this->_temporalAvailability[i];
return max;
}
// === END GETTER
// === MUTATOR
......
......@@ -81,6 +81,7 @@ class Course
std::vector<Competency>& unlocked_prerequisites() {return this->_prerequisites;}
const std::vector<int> timeFrame() const {return this->_temporalAvailability;}
const std::vector<std::pair<Competency, double>> teachedCompetenciesWeighted() const{return this->_weightedTeached;}
const int lastTimeFrame() const;
// === MUTATOR
// SETTER
......
......@@ -8,6 +8,7 @@
#include "problem.h"
#include "tools.h"
#include "competencyDistribution.h"
#include "exception/csdvpOverlapingBoundaryException.h"
#include "exception/notImplementedException.h"
......@@ -340,6 +341,13 @@ int CSDVP::CSDVP_COUNTER = 0;
pb.addCompetencyToCatalogue(c);
assert(c == pb.competencyCatalogue().at(pb.competencyCatalogue().size()-1));
}
/* Assigning Hierachy Level (HL) for each comp
* HL is used to improve the average quality of the course catalogue compared to random
*/
CompetencyDistribution distr = CompetencyDistribution();
distr.linearDistribution(pb);
/* COMPETENCY ASSIGNATION FOR TEACHED
* For each course c, we roll x, the nb of competencies associated to c.
* To assign a competency to c exhaustively, we create a tmp competency vector v, where the competencies are randomly sorted, then create a queue from it.
......@@ -350,7 +358,17 @@ int CSDVP::CSDVP_COUNTER = 0;
std::queue<Competency> queue;
for(unsigned int i = 0 ; i < randomVec.size(); i++)
queue.push(randomVec.at(i));
/*
* ADDENDUM:
* We use the HierarchyLevel to condition the assignation of competency.
* A course at level i (defined by its biggest TF) cannot have a comp with HL > i*HLrange / NbTF
*/
int lastTF;
int nbTF = pb.timeFrames().size();
int hLevelR = CompetencyDistribution::HLevelRange(pb);
int maxLevel; //used to identify which HL are authorized;
std::vector<Competency> HLComp;
int x;
Competency tmpComp;
std::pair<Competency, double> teachedComp;
......@@ -358,10 +376,17 @@ int CSDVP::CSDVP_COUNTER = 0;
for(unsigned int i = 0; i < pb.coursesCatalogue().size(); i++)
{
x = _randomizeIn(pb.cfg_competencyByCourseMin(), pb.cfg_competencyByCourseMax());
for(int j = 0; j < x; j++)
lastTF = pb.coursesCatalogue().at(i).lastTimeFrame();
maxLevel = lastTF * hLevelR / nbTF;
HLComp = CompetencyDistribution::upToHLevel(pb, maxLevel);
std::random_shuffle(HLComp.begin(), HLComp.end());
std::cout << "SIZE OF HLCOMP : " << HLComp.size() << std::endl;
for(int j = 0; j < x && HLComp.size() > 0 && j < HLComp.size(); j++)
{
tmpComp = queue.front();
queue.pop();queue.push(tmpComp);
// tmpComp = queue.front();
tmpComp = HLComp.at(j);
magVal = pb.cfg_magnitudeMin().value() + ( (double)rand()/RAND_MAX) * ( pb.cfg_magnitudeMax().value() - pb.cfg_magnitudeMin().value()) ;
Competency cpt = Competency::build(magVal,tmpComp.c_name());
teachedComp = std::pair<Competency,double>(cpt, 1.0);
......@@ -372,6 +397,24 @@ int CSDVP::CSDVP_COUNTER = 0;
/* COMPETENCY ASSIGNATION FOR PREREQ
* IDEM AS ABOVE
*/
/*
* ADDENDUM :
* Specific behavior for cour level 0: no prereq
* Prereq for level i only draw from HL-1
*
* WARNING :
* Such a behavior induces a strong hypothesis on how courses draw their comp!
*
*/
/*
* NEXT TO DO :
* Array of boolean : true comp assignée ; évolution un tableau de -1 si pas assigné et [0;1] pour les magn des comp à chaque case puis assigné decay sur l'ensemble du tab -> utile pour borner les mag max du job
* POur prereq juste prendre les comp a true
* +
* Vecteur pour le HLevel en entree en % [20,30,10,10,30] (x cases) a passer en dur
* +
* Comp prereq metric comme job metric continue
*/
std::random_shuffle(randomVec.begin(), randomVec.end());
queue = std::queue<Competency>();
for(unsigned int i = 0 ; i < randomVec.size(); i++)
......@@ -380,10 +423,19 @@ int CSDVP::CSDVP_COUNTER = 0;
for(unsigned int i = 0; i < pb.coursesCatalogue().size(); i++)
{
x = _randomizeIn(pb.cfg_prerequisiteByCourseMin(), pb.cfg_prerequisiteByCourseMax());
for(int j = 0; j < x; j++)
lastTF = pb.coursesCatalogue().at(i).lastTimeFrame();
maxLevel = lastTF * hLevelR / nbTF;
HLComp = CompetencyDistribution::upToHLevel(pb, maxLevel-1);
std::random_shuffle(HLComp.begin(), HLComp.end());
if(x == 0)
std::cout << "X is 0! for " << pb.coursesCatalogue().at(i).name() << std::endl;
if(HLComp.size() == 0)
std::cout << "HLComp size is 0! for " << pb.coursesCatalogue().at(i).name() << std::endl;
for(int j = 0; j < x && HLComp.size() > 0 && j < HLComp.size(); j++)
{
tmpComp = queue.front();
queue.pop();
tmpComp = HLComp.at(j);
//we change mag value for prereq
magVal = pb.cfg_magnitudeMin().value() + ( (double)rand()/RAND_MAX) * ( pb.cfg_magnitudeMax().value() - pb.cfg_magnitudeMin().value()) ;
Competency cpt = Competency::build(magVal,tmpComp.c_name());
......@@ -400,12 +452,23 @@ int CSDVP::CSDVP_COUNTER = 0;
// === OPERATOR
std::ostream & operator<<(std::ostream & Stream, const CSDVP & c)
{
std::string s = "--------------\n| Problem n°"+std::to_string(c.id())+"|\n---------------\n| Configuration:";
s+= "\n\tseed: "+std::to_string(c.seed())+"\n\tNb comp: "+std::to_string(c.cfg_quantityCompetencies())+"\n\tNb courses: "+std::to_string(c.cfg_quantityCourses())+"\n\tMin TimeF: "+std::to_string(c.cfg_minimalTimeFrame())+"\n\tMax TimeF: "+std::to_string(c.cfg_maximalTimeFrame());
s+= "\n\tECTS Min: "+std::to_string(c.cfg_ectsMin())+"\n\tECTS Max: "+std::to_string(c.cfg_ectsMax())+"\n\tCourse by TF min: "+std::to_string(c.cfg_courseByTFMin())+"\n\tCourse by TF max: "+std::to_string(c.cfg_courseByTFMax());
s+="\n\tMagnitude min: "+std::to_string(c.cfg_magnitudeMin().value())+"\n\tMagnitude max: "+std::to_string(c.cfg_magnitudeMax().value());
std::string s = "--------------\n| Problem n°"+std::to_string(c.id())+"|\n--------------\n| Configuration:";
s+= "\n|\tseed: "+std::to_string(c.seed())+"\n|\tNb comp: "+std::to_string(c.cfg_quantityCompetencies())+"\n|\tNb courses: "+std::to_string(c.cfg_quantityCourses())+"\n|\tMin TimeF: "+std::to_string(c.cfg_minimalTimeFrame())+"\n|\tMax TimeF: "+std::to_string(c.cfg_maximalTimeFrame());
s+= "\n|\tECTS Min: "+std::to_string(c.cfg_ectsMin())+"\n|\tECTS Max: "+std::to_string(c.cfg_ectsMax())+"\n|\tCourse by TF min: "+std::to_string(c.cfg_courseByTFMin())+"\n|\tCourse by TF max: "+std::to_string(c.cfg_courseByTFMax());
s+="\n|\tMagnitude min: "+std::to_string(c.cfg_magnitudeMin().value())+"\n|\tMagnitude max: "+std::to_string(c.cfg_magnitudeMax().value());
s+= "\n| Detail:\n";
Stream << s;
std::vector<Course> courses = c.coursesCatalogue();
for(int i = 0; i < courses.size(); i++)
Stream << courses[i] << "\n";
Stream << "===Competencies:";
std::vector<Competency> comp = c.competencyCatalogue();
for(int i = 0; i < comp.size(); i++)
Stream << comp[i] << "\n";
return Stream;
}
// === END OPERATOR
\ No newline at end of file
......@@ -6,10 +6,13 @@
#include "profession.h"
#include "competency.h"
#include "competencyDistribution.h"
#include "exception/JobOverlappingBoundariesException.h"
int Profession::PROFESSION_COUNTER = 0;
unsigned int Profession::JOB_SELECTION_TYPE = 0;
unsigned int Profession::JOB_EVAL_DISCRETE = 1;
// === FACTORY
// No factory needed
......@@ -170,21 +173,52 @@ void Profession::_randomlyGenerate(Profession & job, CSDVP & pb)
std::random_shuffle(tmpComp.begin(), tmpComp.end());
int i;
for(i = 0; i < (int)tmpComp.size() && i < howManyPrereq; i++)
std::vector<Competency> compHigherHL;
switch (Profession::JOB_SELECTION_TYPE)
{
magVal = job.cfg_minimalMagnitude().value() + ( (double)rand()/RAND_MAX) * ( job.cfg_maximalMagnitude().value() - job.cfg_minimalMagnitude().value()) ;
ctmp = Competency::buildTMP(magVal,tmpComp.at(i).name());
case 1: //at least one comp in the higher HL
compHigherHL = CompetencyDistribution::getHLevel(pb, CompetencyDistribution::HLevelRange(pb));
std::cout << "compHigherHL size :" << compHigherHL.size() << std::endl;
std::random_shuffle(compHigherHL.begin(), compHigherHL.end());
assert(compHigherHL.size() > 0); //if no comp retrieved in the higher hlevel (hhl), there is a pb here !
magVal = job.cfg_minimalMagnitude().value() + ( (double)rand()/RAND_MAX) * ( job.cfg_maximalMagnitude().value() - job.cfg_minimalMagnitude().value()) ;
ctmp = Competency::buildTMP(magVal,compHigherHL.at(0).name());
ctmp.setHL(compHigherHL.at(0).hLevel());
job.addPrerequisite(ctmp);
}
if(i != howManyPrereq) //Warning need to check if still in range because not enought courses
{
if(i < job.cfg_minimalPrerequisites() || i > job.cfg_maximalPrerequisites())
// !! No duplicata protection: we can insert another time the competency above from the HHL
for(i = 0; i < (int)tmpComp.size() && i < howManyPrereq-1; i++) //cp/paste from default case
{
magVal = job.cfg_minimalMagnitude().value() + ( (double)rand()/RAND_MAX) * ( job.cfg_maximalMagnitude().value() - job.cfg_minimalMagnitude().value()) ;
ctmp = Competency::buildTMP(magVal,tmpComp.at(i).name());
ctmp.setHL(tmpComp.at(i).hLevel());
job.addPrerequisite(ctmp);
}
break;
case 2: // emphasis on higher HL
_pickWithHLWeighting(howManyPrereq, job, pb);
break;
default: //classic behavior
for(i = 0; i < (int)tmpComp.size() && i < howManyPrereq; i++)
{
//considering as a fail during generation
assert(i < job.cfg_minimalPrerequisites() || i > job.cfg_maximalPrerequisites());
magVal = job.cfg_minimalMagnitude().value() + ( (double)rand()/RAND_MAX) * ( job.cfg_maximalMagnitude().value() - job.cfg_minimalMagnitude().value()) ;
ctmp = Competency::buildTMP(magVal,tmpComp.at(i).name());
ctmp.setHL(tmpComp.at(i).hLevel());
job.addPrerequisite(ctmp);
}
if(i != howManyPrereq) //Warning need to check if still in range because not enought courses
{
if(i < job.cfg_minimalPrerequisites() || i > job.cfg_maximalPrerequisites())
{
//considering as a fail during generation
assert(i < job.cfg_minimalPrerequisites() || i > job.cfg_maximalPrerequisites());
}
}
break;
}
// If ECTS is set to be random, then calculating it
......@@ -210,6 +244,47 @@ void Profession::_randomlyGenerate(Profession & job, CSDVP & pb)
job.setRequiredECTS(ects);
}
// Here we weight where we pick the comp, the higher the HL, more likely a comp is to be pick
void Profession::_pickWithHLWeighting(int nbToPick, Profession & job, CSDVP & pb)
{
std::vector<int> range;
int sumInterval = 0;
int x; int currentHL;
double magVal;
Competency ctmp;
const int hLRange = CompetencyDistribution::HLevelRange(pb);
std::vector<Competency> hlComp;
for(int i = 0; i <= hLRange ; i++)
{
sumInterval+=i;
range.push_back(sumInterval);
}
for(int i = 0; i < nbToPick; i++)
{
x = rand() % ( sumInterval + 1);
assert(x <= sumInterval);
currentHL = 0;
std::cout << "sumInterval: " << sumInterval << " & x: " << x << std::endl;
while(x > range[currentHL] && currentHL < range.size())
{
currentHL++;
}
std::cout << "I pick the prereq in the HL: " << currentHL << std::endl;
hlComp = CompetencyDistribution::getHLevel(pb, currentHL);//we get the correspond hl level
assert(hlComp.size() > 0);
std::random_shuffle(hlComp.begin(), hlComp.end());
magVal = job.cfg_minimalMagnitude().value() + ( (double)rand()/RAND_MAX) * ( job.cfg_maximalMagnitude().value() - job.cfg_minimalMagnitude().value()) ;
ctmp = Competency::buildTMP(magVal,hlComp.at(0).name());
ctmp.setHL(hlComp.at(0).hLevel());
job.addPrerequisite(ctmp);
}
}
// === STATIC
int Profession::assignID(){return ++Profession::PROFESSION_COUNTER;}
......
......@@ -40,12 +40,17 @@ class Profession
/** _duplicataProtection returns true if the value (2nd param) searched into (1st param) is found*/
bool _duplicataProtection(std::vector<Competency> *, Competency);
static void _pickWithHLWeighting(int nbToPick, Profession &, CSDVP &);
// Static
static int PROFESSION_COUNTER;
static int assignID();
static void _randomlyGenerate(Profession & job, CSDVP & pb);
public:
static unsigned int JOB_SELECTION_TYPE;
static unsigned int JOB_EVAL_DISCRETE;
enum GenerationType
{
RANDOM
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment