Commit 6dfc228f authored by Alexis Lebis's avatar Alexis Lebis

Merge branch 'determinisctic_rand' into 'master'

GA implementation + Better mut + randomizig Profession generation + random generation

Closes #15

See merge request !5
parents 1f148554 0e8e9fca
......@@ -2,3 +2,5 @@ correction/
build/
howto.pdf
.vscode/
.cmake/
......@@ -16,6 +16,8 @@ paradiseoPath> mkdir build && cd build && cmake ../ && make
2. Correctly link CEAO to your paradiseo install (Optional: **iff** you manually build Paradiseo)
Make sure that a folder cmake/module exists with a FindParadiseo.cmake file. It will be used to find your paradiseo install. Check e1124a07 for example.
Next, you need to locate your paradiseo install while invoking cmake, in order to have the library availables while building CEAO.
To do so, invoke cmake with the following option:
......
......@@ -15,7 +15,7 @@ ADD_EXECUTABLE(tryMutation tryMutation.cpp)
ADD_EXECUTABLE(tryCrossover tryCrossover.cpp)
ADD_EXECUTABLE(tryEval tryEval.cpp)
ADD_DEPENDENCIES(ceao lQueen lModel)
ADD_DEPENDENCIES(ceao lQueen lModel lEA lCstr)
ADD_DEPENDENCIES(ceao_competency lQueen lModel)
ADD_DEPENDENCIES(ceao_course lQueen lModel)
ADD_DEPENDENCIES(ceao_profession lQueen lModel)
......@@ -28,7 +28,7 @@ ADD_DEPENDENCIES(tryEval lQueen)
# 3) Link the librairies for your executable
TARGET_LINK_LIBRARIES(ceao ${PARADISEO_LIBRARIES} lQueen lModel)
TARGET_LINK_LIBRARIES(ceao ${PARADISEO_LIBRARIES} lQueen lModel lEA lCstr)
TARGET_LINK_LIBRARIES(ceao_competency ${PARADISEO_LIBRARIES} lQueen lModel)
TARGET_LINK_LIBRARIES(ceao_course ${PARADISEO_LIBRARIES} lQueen lModel)
TARGET_LINK_LIBRARIES(ceao_profession ${PARADISEO_LIBRARIES} lQueen lModel)
......
......@@ -84,6 +84,10 @@ int main(int argc, char* argv[])
}
pb.set_cfg_courseByTFMin(4);
assert(pb.getQuantityCoursesToPick() == -1);//'cauz pb is not yet fully config
pb.set_cfg_pickedCoursesByTimeFrame(3);
pb.set_cfg_ectsMax(2);
try
......@@ -142,6 +146,8 @@ int main(int argc, char* argv[])
assert(pb.checkConfig());
std::cout << "CSDVP has been correctly configurated" << std::endl;
assert(pb.getQuantityCoursesToPick() == 3 * 6);//course to pick * number of timeframe max - min +1
assert(pb.timeFrames().at(0) == pb.cfg_minimalTimeFrame());
assert(pb.timeFrames().at(1) == pb.cfg_minimalTimeFrame()+1);
assert(pb.timeFrames().at(pb.timeFrames().size()-1) == pb.cfg_maximalTimeFrame());
......@@ -205,5 +211,14 @@ int main(int argc, char* argv[])
std::cout << "CSDVP HAS BEEN CORRECTLY GENERATED!" << std::endl;
for(int i = 0 ; i < pb.coursesSortedByTF().size(); i++)
{
std::cout << "TF#" << std::to_string(i) << std::endl;
for(int j = 0; j < pb.coursesSortedByTF().at(i).size(); j++)
{
std::cout << pb.coursesSortedByTF().at(i).at(j) << std::endl;
}
}
return EXIT_SUCCESS;
}
\ No newline at end of file
This diff is collapsed.
......@@ -48,6 +48,7 @@ set(BUILD_DIR build)
# Path
set(PARADISEO_SRC_PATHS
/home/jerem/Softs/ParadisEO-2.0/
${PARADISEO_ROOT}
$ENV{PARADISEO_ROOT}
/usr/local/
......@@ -101,6 +102,7 @@ endif()
set(PARADISEO_FOUND true) # will be set to false if one of the required modules is not found
set(FIND_PARADISEO_LIB_PATHS
/home/jerem/Softs/ParadisEO-2.0/build/
${PARADISEO_ROOT}/${BUILD_DIR}
$ENV{PARADISEO_ROOT}
/usr/local/
......
......@@ -15,3 +15,5 @@ ADD_LIBRARY(lModel STATIC ${EXERCICE_SOURCES})
add_subdirectory(exception)
add_subdirectory(scale)
add_subdirectory(ea)
add_subdirectory(constraints)
\ No newline at end of file
......@@ -2,11 +2,14 @@
#include "competency.h"
#include "magnitude.h"
#include "tools.h"
#include "exception/magnitudeException.h"
#include "exception/competencyEvolvingException.h"
#include "exception/idOverflowException.h"
int Competency::COMPETENCY_COUNTER = 0;
int Competency::COMPETENCY_TMP_COUNTER = ID_RANGE_FOR_OBJECT + 1;
// === FACTORY
......@@ -37,6 +40,24 @@ Competency Competency::build(double d = 0, std::string name)
}
}
Competency Competency::buildTMP(double d, std::string name)
{
int id = Competency::assignID4TMP();
if(name.empty())
name = "Competency#"+std::to_string(id);
try
{
Magnitude m = Magnitude::build(d);
return Competency(id, m, name);
}
catch(MagnitudeException & e)
{
e.getMagnitude().rebase();
throw CompetencyEvolvingException(new Competency(id, e.getMagnitude(), name));
}
}
// === CONSTRUCTOR
Competency::Competency(int id, Magnitude m, std::string s)
......@@ -49,9 +70,21 @@ Competency::Competency(int id, Magnitude m, std::string s)
int Competency::assignID()
{
if(Competency::COMPETENCY_COUNTER + 1 > ID_RANGE_FOR_OBJECT)
throw idOverflowException("assignID()@Competency.cpp");
return ++Competency::COMPETENCY_COUNTER;
}
int Competency::assignID4TMP()
{
if(Competency::COMPETENCY_TMP_COUNTER + 1 > ID_RANGE_FOR_TEMPORARY_OBJECT)
{
std::cout << "INFO: COMPETENCY_TMP_COUNTER was about to overflow: restored to ID_RANGE_OBJECT + 1" << std::endl;
COMPETENCY_TMP_COUNTER = ID_RANGE_FOR_OBJECT + 1;
}
return ++Competency::COMPETENCY_TMP_COUNTER;
}
// === FUNCTION
void Competency::evolveTowards(Magnitude & m)
......
......@@ -24,10 +24,15 @@ class Competency
//STATIC
static int COMPETENCY_COUNTER;
static int COMPETENCY_TMP_COUNTER;
static int assignID();
static int assignID4TMP();//Called by the tmp builder
public:
static Competency build(Magnitude &, std::string s = "");
static Competency build(double, std::string = "");
///This builder should be used for TMP element
static Competency buildTMP(double, std::string);
Competency() = default;
// === FUNCTION
......
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/constraints)
include_directories(${PARADISEO_INCLUDE_DIR})
SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
SET (EXERCICE_SOURCES
ectsConstraints.cpp
repetitionConstraints.cpp
professionConstraints.cpp
prerequisitesConstraints.cpp
)
ADD_LIBRARY(lCstr STATIC ${EXERCICE_SOURCES})
\ No newline at end of file
#include "ectsConstraints.h"
#include "model/course.h"
std::pair<bool, double> ConstraintsECTS::integrityCheck(Cursus indiv)
{
std::vector<Course> courses = this->_pb.coursesCatalogue();
int tmpECTS = 0;
//std::cout << "courses size : " << std::to_string(courses.size()) << std::endl;
//std::cout << "courses catl : " << std::to_string(this->_pb.cfg_quantityCourses()) << std::endl;
for(int i = 0; i < indiv.size(); i++)
{
tmpECTS += courses.at(indiv[i]).ects();
//std::cout << std::to_string(courses.at(indiv[i]).ects()) << " + ";
}
//std::cout << " = " << std::to_string(tmpECTS) << std::endl;
bool isCheckOK = false;
if(tmpECTS >= this->_job.requiredECTS())
isCheckOK = true;
//std::cout << "Required: " << std::to_string(this->_job.requiredECTS());
double metric;
if(tmpECTS > this->_job.requiredECTS())
metric = 1;
else
metric = (double)tmpECTS / this->_job.requiredECTS();
return std::pair<bool, double>(isCheckOK, metric);
}
\ No newline at end of file
#ifndef SRC_MODEL_CONSTRAINTS_ECTS_CONSTRAINTS_H_
#define SRC_MODEL_CONSTRAINTS_ECTS_CONSTRAINTS_H_
#include <vector>
#include <utility>
#include <eo>
#include "model/problem.h"
#include "model/profession.h"
#include "model/ea/cursus.h"
/**
* This class is used to verify the constraints regarding ECTS
*/
class ConstraintsECTS
{
private:
CSDVP _pb; //Description of the pb
Profession _job;
public:
ConstraintsECTS(const CSDVP& csdvp, const Profession & p)
: _pb(csdvp), _job(p) {}
/** integrityCheck is used to investigate whether or not one individu (indiv) respects the constraints stated.
* Returns a std::pair. First is a boolean set to true when the individu passe the test and is ok with the constraints, false otherwise. Second is a metric inherent to the class caller which can be used during the fitness calcul.
* Metric here is : currentIndivECTS / expectedECTS
*/
std::pair<bool, double> integrityCheck(Cursus indiv);
};
#endif // SRC_MODEL_CONSTRAINTS_ECTS_CONSTRAINTS_H_
\ No newline at end of file
#include "prerequisitesConstraints.h"
#include <string>
#include <utility>
#include "model/course.h"
#include "model/competency.h"
#include "model/tools.h"
#include "model/exception/competencyEvolvingException.h"
std::pair<bool, double> ConstraintsPrerequisites::integrityCheck(Cursus indiv)
{
int currentTF = 0;
int notFound = 0;
int notRespected = 0;
int score = 0;
int nbPrereq = 0;
//Each comp availble at a specific TF. Decay can be applied between i and i+1
std::vector<std::vector<Competency>> compByTF(this->_pb.timeFrames().size());
Course currentCourse;
Competency currentCompetency;
std::pair<int, int> prereqFound; prereqFound.first = 0; prereqFound.second = 0;
std::pair<int, Competency> alreadyExists;
bool changedTF = false;
//std::cout << "=========START========" << std::endl;
for(int i = 0; i < indiv.size() ; i++)
{
if(currentTF != i / this->_pb.cfg_pickedCoursesByTimeFrame())
{
//std::cout << "I've changed of TF" << std::endl;
changedTF = true;
}
else
changedTF = false;
currentTF = i / this->_pb.cfg_pickedCoursesByTimeFrame();
//std::cout << "Current TF: " << std::to_string(currentTF) << std::endl;
//If changedTF is set to true, then we have changed of TF, we need to make available all the Comp in TF-1 here in TF, in addition to the new that'll be discovered in TF
for(int j = 0 ; changedTF && j < compByTF.at(currentTF-1).size(); j++)
{
// HERE, VARIABLE DECAY CAN BE APPLIED!!!!!!!!
compByTF.at(currentTF).push_back(compByTF.at(currentTF-1).at(j));
}
// Then, we explore the current TF for new Comp
currentCourse = this->_pb.coursesCatalogue().at(indiv.at(i));
//std::cout << "\t" << currentCourse << std::endl;
//std::cout << "\tPrereq: " << std::to_string(currentCourse.prerequisites().size()) << std::endl;
nbPrereq += currentCourse.prerequisites().size();
//Handling prereq
// Check if prerequisites exists in TF-1
if(currentTF > 0)
{
prereqFound = this->_prereqsInPreviousTF(compByTF.at(currentTF-1), currentCourse.prerequisites());
}
else
{
prereqFound = this->_prereqsInPreviousTF(std::vector<Competency>(0), currentCourse.prerequisites());
}
notFound += prereqFound.first;
notRespected += prereqFound.second;
// Handling teached comp
for(int j = 0; j < currentCourse.teachedCompetenciesWeighted().size() ; j++)
{
currentCompetency = currentCourse.teachedCompetenciesWeighted().at(j).first;
//Comp already exists in the array ?
alreadyExists = findInVector(compByTF.at(currentTF), currentCompetency);
if(alreadyExists.first >= 0) //Already Exists in the array
{
//std::cout << currentCompetency.c_name() << " already exists" <<std::endl;
try
{
compByTF.at(currentTF).at(alreadyExists.first).evolveTowards(currentCompetency.magnitude());
}
catch(CompetencyEvolvingException & e) //if CEE is thrown, then magnitude has been auto rebased
{
//Should has NTD here
//compToAnswer.at(posFound.first) = e.getCompetency();
//std::cout << "INFO:\n(during ConstraintsProfession)\n\n Compentecy evolution throw an exception. Auto rebase. New value is " << e.getCompetency() << std::endl;
//std::cout << "Comp rebased val is" << compByTF.at(currentTF).at(alreadyExists.first) << std::endl;
//std::cout << "exception.Rebased";
}
}
else
{
compByTF.at(currentTF).push_back(Competency::buildTMP(currentCompetency.c_magnitude().value(), currentCompetency.c_name()));
}
}
}
//std::cout << "==EXPLORING COMP BY TF" << std::endl;
for(int i = 0; i < compByTF.size(); i++)
{
//std::cout << "TF#" << std::to_string(i) << std::endl;
for(int j = 0; j < compByTF.at(i).size() ; j++)
{
//std::cout << compByTF.at(i).at(j) << std::endl;
}
}
bool isOK = ((notFound == 0) && (notRespected == 0));
/*
std::cout << "========== PREREQ CSTR RES ==========" << std::endl;
std::cout << "Not Found: " << std::to_string(notFound) << std::endl;
std::cout << "Not Respected: " << std::to_string(notRespected) << std::endl;
std::cout << "Nb Prereq: " << std::to_string(nbPrereq) << std::endl;
*/
double metric = 0;
if(nbPrereq > 0)
{
metric = 1.0 - ( (((double)2 * (double)notFound) + (double)notRespected ) / (2 * (double) nbPrereq) );
}
else //can't divide by 0
{
if(isOK)
metric = 1;
else
metric = 0;
}
//std::cout << "Metric: " << std::to_string(metric) << std::endl;
//std::cout << "====================" << std::endl;
return std::pair<bool, double>(isOK, metric);
}
std::pair<int, int> ConstraintsPrerequisites::_prereqsInPreviousTF(std::vector<Competency> cInTF, std::vector<Competency> prereqs)
{
int notFound = 0;
int notRespected = 0;
bool found = false;
if(cInTF.size() == 0) //if empty, we'll find nothing
return std::pair<int, int>(prereqs.size(), 0);
for(int i = 0; i < prereqs.size(); i++)
{
found = false;
//std::cout << "Looking for " << prereqs.at(i) << std::endl;
for(int j = 0 ; j < cInTF.size() && !found; j++)
{
//std::cout << "\n\t" << cInTF.at(j) << std::endl;
if(prereqs.at(i)==cInTF.at(j))
{
found = true;
if(prereqs.at(i).c_magnitude().value() > cInTF.at(j).c_magnitude().value())
notRespected++;
}
}
if(!found)
notFound++;
}
//std::cout << "NF: " << std::to_string(notFound) << " | NR: " << std::to_string(notRespected) << std::endl;
return std::pair<int, int>(notFound, notRespected);
}
#ifndef SRC_MODEL_CONSTRAINTS_PREREQUISITES_CONSTRAINTS_H_
#define SRC_MODEL_CONSTRAINTS_PREREQUISITES_CONSTRAINTS_H_
#include <vector>
#include <utility>
#include <eo>
#include "model/problem.h"
#include "model/profession.h"
#include "model/ea/cursus.h"
/**
* This class is used to verify constraints regarding the prerequisites of each courses of an individu (indiv).
* Each prerequisites of each courses must be respected. Note that the position of the courses in the indiv is important,
* since it represents how the courses are dispatched in the timeframes.
* Logically, a course see in TF t DO NOT CONTRIBUTE in the prerequisite for the courses in x < t
*/
class ConstraintsPrerequisites
{
private:
CSDVP _pb;
Profession _job;
/**
* Checks the prerequisites prereqs in the competencies cInTF (generally, the competencies from the previous TF).
* It returns a std::pair, where the first element indicates how many prerequisites HAS NOT BEEN FOUND.
* The second elements indicates how many prerequisites has not enought mastery (BUT EXISTS in cInTF!)
*/
std::pair<int,int> _prereqsInPreviousTF(std::vector<Competency> cInTF, std::vector<Competency> prereqs);
public:
ConstraintsPrerequisites(const CSDVP & csdvp, const Profession & job)
: _pb(csdvp), _job(job) {}
/** Integrity check is used to investigate wheteher or not one indiv respects the constraints represented by THIS.
* Returns a std::pair. First is a boolean set to true when the indiv passes the test and therefore is compilant with the constraint, false otherwise. Second is the associated metric, mostly usable during fitness calcul.
* @todo Decay competency magnitude
*/
std::pair<bool, double> integrityCheck(Cursus indiv);
};
#endif // SRC_MODEL_CONSTRAINTS_PREREQUISITES_CONSTRAINTS_H_
\ No newline at end of file
#include "professionConstraints.h"
#include <string>
#include <utility>
#include "model/course.h"
#include "model/competency.h"
#include "model/tools.h"
#include "model/exception/competencyEvolvingException.h"
std::pair<bool, double> ConstraintsProfession::integrityCheck(Cursus indiv)
{
std::vector<Competency> compToAnswer;
for(int i = 0 ; i < this->_job.prerequisites().size(); i++)
{
std::string name = this->_job.prerequisites().at(i).c_name();
compToAnswer.push_back(Competency::buildTMP(0, name)); //same name to exploit the Competency::operator== on name equality
}
Course current;
Competency currentComp;
std::pair<int, Competency> posFound;
for(int i = 0 ; i < indiv.size(); i++)
{
current = this->_pb.coursesCatalogue().at(indiv.at(i));
for(int j = 0 ; j < current.teachedCompetenciesWeighted().size() ; j++)
{
currentComp = current.teachedCompetenciesWeighted().at(j).first;
posFound = findInVector(compToAnswer, currentComp);
if(posFound.first != -1)
{
try
{
compToAnswer.at(posFound.first).evolveTowards(currentComp.magnitude());
}
catch(CompetencyEvolvingException & e) //if CEE is thrown, then magnitude has been auto rebased
{
//Should has NTD here
//compToAnswer.at(posFound.first) = e.getCompetency();
//std::cout << "INFO:\n(during ConstraintsProfession)\n\n Compentecy evolution throw an exception. Auto rebase. New value is " << e.getCompetency() << std::endl;
}
}
}
}
//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;
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++;
}
//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()));
}
#ifndef SRC_MODEL_CONSTRAINTS_PROFESSION_CONSTRAINTS_H_
#define SRC_MODEL_CONSTRAINTS_PROFESSION_CONSTRAINTS_H_
#include <vector>
#include <utility>
#include <eo>
#include "model/problem.h"
#include "model/profession.h"
#include "model/ea/cursus.h"
/**
* This class is used to verify the constraints regarding the profession expected by the student
* It mostly consist in *version 1* to check if all the prerequisites have been answered.
*/
class ConstraintsProfession
{
private:
CSDVP _pb;
Profession _job;
public:
ConstraintsProfession(const CSDVP & csdvp, const Profession & job)
: _pb(csdvp), _job(job) {}
/** Integrity check is used to investigate wheteher or not one indiv respects the constraints represented by THIS.
* Returns a std::pair. First is a boolean set to true when the indiv passes the test and therefore is compilant with the constraint, false otherwise. Second is the associated metric, mostly usable during fitness calcul.
* @todo Decay competency magnitude
*/
std::pair<bool, double> integrityCheck(Cursus indiv);
};
#endif // SRC_MODEL_CONSTRAINTS_PROFESSION_CONSTRAINTS_H_
\ No newline at end of file
#include "repetitionConstraints.h"
#include "model/course.h"
std::pair<bool, double> ConstraintsRepetition::integrityCheck(Cursus indiv)
{
int nbOfRepetition = 0;
for(int i = 0; i < indiv.size(); i++)
{
for(int j = i+1; j < indiv.size(); j++)
{
if(indiv.at(i) == indiv.at(j))
nbOfRepetition++;
}
}
bool isOK = nbOfRepetition == 0;
double metric = 1 - ( ( (double) nbOfRepetition * 2) / (double)indiv.size() );
return std::pair<bool, double>(isOK, metric);
}
\ No newline at end of file
#ifndef SRC_MODEL_CONSTRAINTS_REPETITION_CONSTRAINTS_H_
#define SRC_MODEL_CONSTRAINTS_REPETITION_CONSTRAINTS_H_
#include <eo>
#include <utility>
#include "model/problem.h"
#include "model/profession.h"
#include "model/ea/cursus.h"
/** This class is used to verify the integrity of an individu regarding repetition of courses in the sol.
*/
class ConstraintsRepetition
{
private:
CSDVP _pb;
Profession _job;
public:
ConstraintsRepetition(const CSDVP & csdvp, const Profession & job)
: _pb(csdvp), _job(job) {}
/** Integrity check is used to investigate wheteher or not one indiv respects the constraints represented by THIS.
* Returns a std::pair. First is a boolean set to true when the indiv passes the test and therefore is compilant with the constraint, false otherwise. Second is the associated metric, mostly usable during fitness calcul.
*/
std::pair<bool, double> integrityCheck(Cursus indiv);
};
#endif //SRC_MODEL_CONSTRAINTS_REPETITION_CONSTRAINTS_H_
\ No newline at end of file
......@@ -11,8 +11,10 @@
#include "exception/courseECTSException.h"
#include "exception/courseTemporalFrameException.h"
#include "exception/notImplementedException.h"
#include "exception/idOverflowException.h"
int Course::COURSE_COUNTER = 0;
int Course::COURSE_TMP_COUNTER = ID_RANGE_FOR_OBJECT + 1;
// === FACTORY
Course Course::build(int ects, std::string name)
......@@ -27,6 +29,19 @@ Course Course::build(int ects, std::string name)
else
return Course(id, ects, name);
}
Course Course::buildTMP(int ects, std::string name)
{
int id = Course::assignID4TMP();
if(name.empty())
name = "Course#"+std::to_string(id);
if(ects < 0)
throw CourseECTSException(new Course(id, ects, name));
else
return Course(id, ects, name);
}
// === END FACTORY
// === CONSTRUCTOR
......@@ -217,8 +232,8 @@ bool Course::_duplicataProtection(std::vector<std::pair<Competency,double>> *tea
bool Course::_lazyEquality(const Course & c) const
{
return (this->_id == c.id() &&
this->_name.compare(c.name()) == 0 &&
return ( (this->_id == c.id() ||
this->_name.compare(c.name()) == 0 ) &&
this->_ects == c.ects()
);
}
......@@ -241,6 +256,19 @@ std::ostream& operator<<(std::ostream& Stream, const Course & c)
tf+=std::to_string(c.timeFrame().at(c.timeFrame().size()-1));
s+="\n\tTimeFrames: ["+tf+"]";
}
s+="\n\tRequirement: [";
for(int i = 0; i < c.prerequisites().size(); i++)
{
s+="" + c.prerequisites().at(i).c_name()+ "("+ std::to_string(c.prerequisites().at(i).c_magnitude().value()) + ") ; ";
}
s+="]";
s+="\n\tTeaches: [";
for(int i = 0 ; i < c.teachedCompetenciesWeighted().size(); i++)
{
s+= "" + c.teachedCompetenciesWeighted().at(i).first.c_name() + "("+ std::to_string(c.teachedCompetenciesWeighted().at(i).first.c_magnitude().value())+") ; ";
}
s+="]";
Stream << s;
return Stream;
}
......@@ -256,6 +284,39 @@ bool Course::operator==(const Course & c) const
/// Course counter
int Course::assignID()
{
if(Course::COURSE_COUNTER + 1 > ID_RANGE_FOR_OBJECT)
throw idOverflowException("assignID()@Course.cpp");
return ++Course::COURSE_COUNTER;
}
int Course::assignID4TMP()
{
if(Course::COURSE_TMP_COUNTER + 1 > ID_RANGE_FOR_TEMPORARY_OBJECT)
{
std::cout << "INFO: COURSE_TMP_COUNTER was about to overflow: restored to ID_RANGE_OBJECT + 1" << std::endl;
COURSE_TMP_COUNTER = ID_RANGE_FOR_OBJECT + 1;
}
return ++COURSE_TMP_COUNTER;
}
/** It produces a new vector, which is another view of courses in param, sorted by TF
* Duplicates the behaviour of CSDVP::_makeCoursesSortedByTF() except that it applies to any vector of courses
* size of timeFrames must be equal to the maximal TF value in courses.timeFrames !
*/
std::vector<std::vector<Course>> Course::organiseByTF(std::vector<Course> courses, std::vector<int> timeFrames)
{
std::vector<std::vector<Course>> coursesByTF(timeFrames.size());
int tmpIdx;
for(int i = 0; i < courses.size(); i++)
{
for(int j = 0; j < courses.at(i).timeFrame().size(); j++)
{
tmpIdx = courses.at(i).timeFrame().at(j) - timeFrames.at(0);
coursesByTF.at(tmpIdx).push_back(courses.at(i));
}
}
return coursesByTF;
}
// === END STATIC
\ No newline at end of file
......@@ -5,6 +5,7 @@
#include <utility>
#include "competency.h"
#include "model/exception/notImplementedException.h"
/**
* Represents a course in an academic structure.
......@@ -54,13 +55,19 @@ class Course
// Static
static int COURSE_COUNTER;
static int COURSE_TMP_COUNTER;
static int assignID();
static int assignID4TMP();
// Constructor
//Course();
Course(int id, int ects, std::string name);
public:
static Course build(int ects = 0, std::string name = "");
static Course buildTMP(int ects = 0, std::string name = "");
static std::vector<std::vector<Course>> organiseByTF(std::vector<Course> courses, std::vector<int> timeFrames);
/// Default constructor. Use Course::build instead !
Course() = default;
......@@ -70,6 +77,7 @@ class Course
const std::string name() const{return this->_name;};
const int ects() const{return this->_ects;}
const std::vector<Competency> prerequisites() const {return this->_prerequisites;}
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;}
......
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/ea)
include_directories(${PARADISEO_INCLUDE_DIR})
SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
SET (EXERCICE_SOURCES
evaluator.cpp
)
ADD_LIBRARY(lEA STATIC ${EXERCICE_SOURCES})
\ No newline at end of file
#ifndef SRC_MODEL_EA_CROSSOVER_H_
#define SRC_MODEL_EA_CROSSOVER_H_
#include <model/ea/initConstraint.h>
template <class EOT>
class crossCSDVP: public eoQuadOp<EOT>
{
public:
crossCSDVP(CSDVP& _pb, ConstraintsRepetition& _ctr, CursusInitConstraint& _init):pb(_pb),ctr(_ctr), init(_init), cpt(0){}
virtual bool operator()(EOT& _chrom1, EOT& _chrom2){
cpt++;
//Integrity Check BEFORE CROSS
std::pair<bool, double> ctrRes1= ctr.integrityCheck(_chrom1);
std::pair<bool, double> ctrRes2= ctr.integrityCheck(_chrom2);
assert(ctrRes1.first && ctrRes2.first);
//Cross by using tmp solution
EOT tmp;
tmp.resize(0);
for(int i=0; i<_chrom1.size(); i++)
tmp.push_back(_chrom1[i]);
cross(_chrom1,_chrom2);
cross(_chrom2, tmp);
//Integrity Check AFTER CROSS
ctrRes1= ctr.integrityCheck(_chrom1);
ctrRes2= ctr.integrityCheck(_chrom2);
assert(ctrRes1.first && ctrRes2.first);
return true;
}
//Cross modify _chrom1
void cross(EOT& _chrom1,const EOT& _chrom2){
bool needRepair=false;
bool errorFound=false;
unsigned int i, tmp;
const std::vector<int> TF = pb.timeFrames();
unsigned int nbTF=TF.size();
unsigned int sizeTF=_chrom1.size()/nbTF;
std::vector<Course> catalogue = pb.coursesCatalogue();
std::vector<int> courseID;
//Create a vector with all position
for(i=0; i<catalogue.size(); i++)
courseID.push_back(i);
//Define a cut point between time frames
unsigned int cut = eo::rng.random(nbTF-1)+1;
//copie right part from cut with chrom2, -1 if impossible
for(i=cut*sizeTF; i<_chrom1.size(); i++){
if(notin(_chrom1, _chrom2[i],i)){
_chrom1[i]=_chrom2[i];
}
else{
_chrom1[i]=-1;
needRepair=true;
}
}
//Repair
if(needRepair){
//search a course available in the TF for each -1 (impossible position of previous step)
coursenotin(courseID, _chrom1);
for(i=0; i<_chrom1.size(); i++){
if(_chrom1[i]==-1){
tmp=0;
while(!isInTF(catalogue[courseID[tmp]], (i/sizeTF)+pb.cfg_minimalTimeFrame()) && tmp < courseID.size()){
tmp++;
}
if(tmp<courseID.size()){
_chrom1[i]=courseID[tmp];
remove(courseID, _chrom1[i]);
}
else{
//no possibility
errorFound=true;
}
}
}
}
//If no possibility, reinit the sol
if(errorFound){
std::cout << "Impossibility in Cross > Reinit sol" << std::endl;
init(_chrom1);
}
}
//Return if a course can be in a TF
bool isInTF(Course& _c, int _TF){
bool res=false;
std::vector<int> tf=_c.timeFrame();
for(int i=0; i<tf.size(); i++)
if(_TF=tf[i])
res=true;
return res;
}
//remove an _id from a vector
void remove(std::vector<int>& _chrom, int _id){
int i=0;
while(_chrom[i]!= _id)
i++;
_chrom[i]=_chrom[_chrom.size()-1];
_chrom.pop_back();
}
//return if a id is not in the left side of a sol (side depend of _size)
bool notin(EOT& _chrom, int _id, int _size){
bool res=true;
int i=0;
while(res && i<_size){
if(_chrom[i]==_id)
res=false;
i++;
}
return res;
}
//_CourseID subastraction from _chrom
void coursenotin(std::vector<int>& _courseID, std::vector<int>& _chrom){
int tmp;
for (int i=0; i<_chrom.size(); i++){
tmp=0;
while(tmp<_courseID.size() && _chrom[i]!=_courseID[tmp])
tmp++;
if(tmp<=_courseID.size()){
_courseID[tmp]=_courseID[_courseID.size()-1];
_courseID.pop_back();
}
}
}
int cpt;
private:
CSDVP pb;
ConstraintsRepetition ctr;
CursusInitConstraint init;
};
typedef crossCSDVP<Cursus> CursusCrossover;
#endif // SRC_MODEL_EA_CROSSOVER_H_
#ifndef SRC_MODEL_EA_CURSUS_H_
#define SRC_MODEL_EA_CURSUS_H_
#include <eoInt.h>
#include <eoScalarFitness.h>
/**
* Represents a cursus of a student. It is equivalent to an individu in a EA.
* Here, it is defined as an eoVector of int: eoInt with a "eoMinimizingFitness" template. Each int represents a course.
* In version 1.1, the representation is based on the course's position in the vector. Older version dealing with the course's ID **IS** deprecated
* @version 1
*/
typedef eoInt<eoMinimizingFitness> Cursus;
#endif // SRC_MODEL_EA_CURSUS_H_
#include "evaluator.h"
void CursusEval::operator()(Cursus & _cursus){
double fit=0.0;
int pCE, pCP, pCR, pCPR;
pCE=1;
pCR=1;
pCP=1;
pCPR=1;
std::pair<bool, double> resCE;
std::pair<bool, double> resCP;
std::pair<bool, double> resCR;
std::pair<bool, double> resCPR;
resCE=ce.integrityCheck(_cursus);
resCP=cp.integrityCheck(_cursus);
resCR=cr.integrityCheck(_cursus);
resCPR=cpr.integrityCheck(_cursus);
/*
std::cout << "EVAL: ";
std::cout << resCE.first << " " << resCE.second << std::endl;
std::cout << resCP.first << " " << resCP.second << std::endl;
std::cout << resCR.first << " " << resCR.second << std::endl;
std::cout << resCPR.first << " " << resCPR.second << std::endl;
std::cout << std::endl << std::endl;
*/
double sum=pCE*resCE.second + pCR*resCR.second + pCP*resCP.second + pCPR*resCPR.second;
fit=1.0/(1+sum)*100;
_cursus.fitness(fit);
}
#ifndef SRC_MODEL_EA_EVALUATOR_H_
#define SRC_MODEL_EA_EVALUATOR_H_
#include <eoEvalFunc.h>
#include "cursus.h"
#include <model/constraints/ectsConstraints.h>
#include <model/constraints/repetitionConstraints.h>
#include <model/constraints/professionConstraints.h>
#include <model/constraints/prerequisitesConstraints.h>
class CursusEval : public eoEvalFunc<Cursus>
{
public:
CursusEval(ConstraintsPrerequisites& _cpr, ConstraintsRepetition& _cr, ConstraintsProfession& _cp, ConstraintsECTS& _ce):cpr(_cpr), cr(_cr), cp(_cp), ce(_ce){}
void operator()(Cursus & _cursus);
private:
ConstraintsPrerequisites cpr;
ConstraintsRepetition cr;
ConstraintsProfession cp;
ConstraintsECTS ce;
};
#endif // SRC_MODEL_EA_EVALUATOR_H_
#ifndef SRC_MODEL_EA_INITCONSTRAINT_H_
#define SRC_MODEL_EA_INITCONSTRAINT_H_
#include<queue>
#include<vector>
#include<cassert>
#include<algorithm>
#include<random>
#include<functional>
#include <eoInit.h>
#include "model/problem.h"
#include "cursus.h"
template <class EOT>
class eoInitConstraintCSDVP: public eoInit<EOT>
{
public:
typedef typename EOT::AtomType AtomType;
eoInitConstraintCSDVP(CSDVP& _pb): pb(_pb){
std::vector<int> tmp;
chromSize=pb.getQuantityCoursesToPick();
maxVal=pb.coursesCatalogue().size();
seed=pb.seed();
TF = pb.timeFrames();
nbTF=TF.size();
sizeTF=chromSize/nbTF;
catalogue = pb.coursesCatalogue();
possibleIDbyTF.resize(nbTF);
for(int i=0; i<maxVal; i++){
tmp=catalogue[i].timeFrame();
for(int j=0; j<tmp.size(); j++){
possibleIDbyTF[tmp[j]-pb.cfg_minimalTimeFrame()].push_back(i);
}
}
// for(int i=0; i<possibleIDbyTF.size(); i++){
// std::cout << "Possible course in TF " << i+pb.cfg_minimalTimeFrame() << ": ";
// for(int j=0; j<possibleIDbyTF[i].size(); j++){
// std::cout << possibleIDbyTF[i][j] << " ";
// }
// std::cout << std::endl;
// }
}
virtual void operator()(EOT& chrom){
int cpt=0;
//std::cout << "Enter init" << std::endl;
unsigned int r=eo::rng.random(possibleIDbyTF[0].size());
chrom.resize(0);
chrom.push_back(possibleIDbyTF[0][r]);
//std::cout << "push " << possibleIDbyTF[0][r] << std::endl;
for(int i = 1; i < chromSize; i++){
cpt=0;
r=eo::rng.random(possibleIDbyTF[i/sizeTF].size());
while(!notin(chrom, possibleIDbyTF[i/sizeTF][r], i) && cpt<maxVal){
r=eo::rng.random(possibleIDbyTF[i/sizeTF].size());
cpt++;
}
if(cpt<maxVal){
//std::cout << i << " " << r << " ";
chrom.push_back(possibleIDbyTF[i/sizeTF][r]);
//std::cout << "push " << possibleIDbyTF[i/sizeTF][r] << std::endl;
}
else{
r=eo::rng.random(maxVal);
while(!notin(chrom, r, i))
r=eo::rng.random(maxVal);
chrom.push_back(r);
std::cout << "push with error " << r << std::endl;
}
}
chrom.invalidate();
// chrom.printOn(std::cout);
//std::cout << std::endl;
//std::cout << "End init" << std::endl;
}
bool notin(EOT& _chrom, int _id, int _size){
bool res=true;
int i=0;
while(res && i<_size){
if(_chrom[i]==_id)
res=false;
i++;
}
return res;
}
private :
std::vector< std::vector<int> > possibleIDbyTF;
std::vector<Course> catalogue;
std::vector<int> TF;
unsigned int nbTF;
unsigned int sizeTF;
CSDVP pb;
unsigned chromSize;
unsigned maxVal;
UF_random_generator<unsigned int> gen;
int seed;
};
typedef eoInitConstraintCSDVP<Cursus> CursusInitConstraint;
#endif // SRC_MODEL_EA_INITIALIZER_H_
#ifndef SRC_MODEL_EA_INITIALIZER_H_
#define SRC_MODEL_EA_INITIALIZER_H_
#include<queue>
#include<vector>
#include<cassert>
#include<algorithm>
#include<random>
#include<functional>
#include <eoInit.h>
#include "model/problem.h"
#include "cursus.h"
template <class EOT>
class eoInitCSDVP: public eoInit<EOT>
{
public:
typedef typename EOT::AtomType AtomType;
eoInitCSDVP(unsigned _chromSize, unsigned _maxVal, int _seed)
: chromSize(_chromSize), maxVal(_maxVal), seed(_seed)
{}
virtual void operator()(EOT& chrom)
{
chrom.resize(0);
for(int i = 0; i < maxVal; i++)
chrom.push_back(i);
std::random_shuffle(chrom.begin(), chrom.end());
chrom.resize(chromSize);
chrom.invalidate();
}
private :
unsigned chromSize;
unsigned maxVal;
UF_random_generator<unsigned int> gen;
int seed;
};
typedef eoInitCSDVP<Cursus> CursusInit;
#endif // SRC_MODEL_EA_INITIALIZER_H_
#ifndef SRC_MODEL_EA_INITIALIZER_H_
#define SRC_MODEL_EA_INITIALIZER_H_
#include<queue>
#include<vector>
#include<cassert>
#include<algorithm>
#include<random>
#include<functional>
#include <eoInit.h>
#include "model/problem.h"
#include "cursus.h"
template <class EOT>
class eoInitCSDVP: public eoInit<EOT>
{
public:
typedef typename EOT::AtomType AtomType;
eoInitCSDVP(unsigned _chromSize, unsigned _maxVal, int _seed)
: chromSize(_chromSize), maxVal(_maxVal), seed(_seed)
{}
virtual void operator()(EOT& chrom)
{
chrom.resize(0);
for(int i = 0; i < maxVal; i++)
chrom.push_back(i);
std::random_shuffle(chrom.begin(), chrom.end());
chrom.resize(chromSize);
chrom.invalidate();
}
private :
unsigned chromSize;
unsigned maxVal;
UF_random_generator<unsigned int> gen;
int seed;
};
typedef eoInitCSDVP<Cursus> CursusInit;
#endif // SRC_MODEL_EA_INITIALIZER_H_
This diff is collapsed.
#ifndef SRC_MODEL_EXCEPTION_JOB_OVERLAPING_BOUNDARIES_EXCEPTION_H_
#define SRC_MODEL_EXCEPTION_JOB_OVERLAPING_BOUNDARIES_EXCEPTION_H_
#include <exception>
#include <iostream>
#include <string>
#include "../profession.h"
class JobOverlappingBoundariesException : public std::exception
{
private:
Profession * _job;
std::string _msg;
public:
JobOverlappingBoundariesException(Profession * pb) throw()
: _job(pb)
{
this->_msg = "Boundaries of the Profession (aka Job) (id:"+std::to_string(pb->id())+") are overlaping.";
}
~JobOverlappingBoundariesException() throw()
{ delete(this->_job); }
virtual const char* what() const throw()
{return this->_msg.c_str();}
Profession & getCSDVP() {return *(this->_job);}
};
#endif // SRC_MODEL_EXCEPTION_JOB_OVERLAPING_BOUNDARIES_EXCEPTION_H_
\ No newline at end of file
#ifndef SRD_MODEL_EXCEPTION_ID_OVERFLOW_EXCEPTION_H_
#define SRD_MODEL_EXCEPTION_ID_OVERFLOW_EXCEPTION_H_
#include <exception>
#include <string>
class idOverflowException : public std::exception
{
private:
std::string _msg;
public:
idOverflowException(std::string buildInfo) throw()
{
this->_msg = "The id of an object has overflow the maximal value. Where: "+buildInfo;
}
virtual const char* what() const throw()
{
return this->_msg.c_str();
}
};
#endif //SRD_MODEL_EXCEPTION_ID_OVERFLOW_EXCEPTION_H_
\ No newline at end of file
......@@ -27,11 +27,12 @@ class MagnitudeException : public std::exception
virtual ~MagnitudeException() throw()
{
//this->_triedValue must not be freed by ~this !
delete(this->_triedValue);
}
Magnitude & getMagnitude() const {return *(this->_triedValue);}
};
#endif // SRC_EXCEPTION_MAGNITUDE_EXCEPTION_H_
\ No newline at end of file
#ifndef SRC_MODEL_PARCOURS_H_
#define SRC_MODEL_PARCOURS_H_
/**
* Represents a cursus of a student. It is equivalent to an individu in a EA.
*/
#endif // SRC_MODEL_PARCOURS_H_
\ No newline at end of file
......@@ -66,6 +66,8 @@ int CSDVP::CSDVP_COUNTER = 0;
{this->_minimalPrerequisiteByCourse = nb;}
void CSDVP::set_cfg_maximalPrerequisiteByCourse(int nb)
{this->_maximalPrerequisiteByCourse = nb;}
void CSDVP::set_cfg_pickedCoursesByTimeFrame(int nb)
{this->_pickedCoursesByTimeFrame = nb;}
void CSDVP::set_cfg_minimalMagnitude(double m)
{
this->_minimalMagnitude = Magnitude::build(m);
......@@ -128,7 +130,8 @@ int CSDVP::CSDVP_COUNTER = 0;
this->_maximalCompetencyByCourse < 0 ||
this->_minimalCompetencyByCourse < 0 ||
this->_minimalPrerequisiteByCourse < 0 ||
this->_maximalPrerequisiteByCourse < 0 )
this->_maximalPrerequisiteByCourse < 0 ||
this->_pickedCoursesByTimeFrame < 1 )
{
this->_isConfig = false;
return this->_isConfig;
......@@ -153,10 +156,37 @@ int CSDVP::CSDVP_COUNTER = 0;
throw CSDVPBadlyConfiguratedException("this->_minimalCompetencyByCourse >= this->_quantityAvailableCompetencies");
if(this->_quantityAvailableCompetencies < this->_maximalCompetencyByCourse)
throw CSDVPBadlyConfiguratedException("this->_quantityAvailableCompetencies < this->_maximalCompetencyByCourse");
if(this->_pickedCoursesByTimeFrame > this->_minimalCoursesByTimeFrame)
throw CSDVPBadlyConfiguratedException("this->_pickedCoursesByTimeFrame > this->_minimalCoursesByTimeFrame");
if(this->_pickedCoursesByTimeFrame * ( (this->_maximalTimeFrame - this->_minimalTimeFrame) + 1) > this->_quantityAvailableCourses)
throw CSDVPBadlyConfiguratedException("this->_pickedCoursesByTimeFrame * ( (this->_maximalTimeFrame - this->_minimalTimeFrame) + 1) > this->_quantityAvailableCourses");
this->_isConfig = true;
return this->_isConfig;
}
void CSDVP::_makeCoursesSortedByTF()
{
//Init the vector of the size of the time frames
for(int i = 0; i < this->_timeFrames.size(); i++)
this->_coursesSortedByTF.push_back(std::vector<Course>());
int tmpIdx;
for(int i = 0; i < this->_availableCourses.size(); i++)
{
for(int j = 0; j < this->_availableCourses.at(i).timeFrame().size(); j++)
{
tmpIdx = this->_availableCourses.at(i).timeFrame().at(j) - this->_minimalTimeFrame;
this->_coursesSortedByTF.at(tmpIdx).push_back(this->_availableCourses.at(i));
}
}
}
int CSDVP::mapCourseToPosition(const Course & c)
{
for(int i = 0; i < this->coursesCatalogue().size(); i++)
if(c == this->coursesCatalogue().at(i))
return i;
return -1;
}
// === END FUNC
// === STATIC
......@@ -181,6 +211,7 @@ int CSDVP::CSDVP_COUNTER = 0;
}
}
/// [x;y[ ?
int CSDVP::_randomizeIn(const int min, const int max)
{
return min + ( rand() % (max - min + 1) );
......@@ -225,32 +256,76 @@ int CSDVP::CSDVP_COUNTER = 0;
std::vector<Course> tmpCourses;
for(int i = 0; i < pb._quantityAvailableCourses; i++)
{
tmpCourses.push_back(Course::build(CSDVP::_randomizeIn(pb.cfg_minimalTimeFrame(), pb.cfg_maximalTimeFrame())));
tmpCourses.push_back(Course::build(CSDVP::_randomizeIn(pb.cfg_ectsMin(), pb.cfg_ectsMax())));
}
/* We obtain how many courses n by semester s
* then we create an idxCourses vector of size n * s
* then we shuffle it
* then we distribute the course accordingly. If a course already exists, we repick one randomly until it's ok
*/
std::vector<int> idxCourses;
std::vector<int> nbCoursesByTF;
for(int i = 0 ; i < pb.timeFrames().size(); i++)
nbCoursesByTF.push_back(CSDVP::_randomizeIn(pb._minimalCoursesByTimeFrame, pb._maximalCoursesByTimeFrame));
int idxCoursesCounter = 0;
for(int i = 0; i < nbCoursesByTF.size(); i++)
{
for(int j = 0; j < nbCoursesByTF.at(i); j++)
{
idxCourses.push_back(idxCoursesCounter % pb._quantityAvailableCourses);
idxCoursesCounter++;
}
}
std::random_shuffle(idxCourses.begin(), idxCourses.end());
bool insertRez;
int rndIdx;
idxCoursesCounter = 0;
for(int i = 0; i < pb.timeFrames().size(); i++)
{
int nbCoursesInThisTF = CSDVP::_randomizeIn(pb._minimalCoursesByTimeFrame, pb._maximalCoursesByTimeFrame);
int courseIdx;
std::cout << "In the TF "+std::to_string(i)+" I plan " << std::to_string(nbCoursesInThisTF) << " courses." << std::endl;
for(int j = 0; j < nbCoursesInThisTF; j++)
for(int j = 0; j < nbCoursesByTF.at(i); j++)
{
insertRez = true;
courseIdx = CSDVP::_randomizeIn(0,tmpCourses.size()-1);
insertRez = tmpCourses.at(courseIdx).addTemporalFrame(pb.timeFrames().at(i));
int cc = idxCourses.at(idxCoursesCounter);
insertRez = tmpCourses.at(idxCourses.at(idxCoursesCounter)).addTemporalFrame(pb.timeFrames().at(i));
if(!insertRez) //If a duplicata has been prevented, we do not count the attempt
j--;
while(!insertRez)//if duplicataProtection (i.e. course already in this semester)
{
rndIdx = CSDVP::_randomizeIn(0, pb._quantityAvailableCourses);
insertRez = tmpCourses.at(rndIdx).addTemporalFrame(pb.timeFrames().at(i));
}
idxCoursesCounter++;
}
}
// // OLD WAY
// bool insertRez;
// for(int i = 0; i < pb.timeFrames().size(); i++)
// {
// int nbCoursesInThisTF = CSDVP::_randomizeIn(pb._minimalCoursesByTimeFrame, pb._maximalCoursesByTimeFrame);
// int courseIdx;
// std::cout << "In the TF "+std::to_string(i)+" I plan " << std::to_string(nbCoursesInThisTF) << " courses." << std::endl;
// for(int j = 0; j < nbCoursesInThisTF; j++)
// {
// insertRez = true;
// courseIdx = CSDVP::_randomizeIn(0,tmpCourses.size()-1);
// insertRez = tmpCourses.at(courseIdx).addTemporalFrame(pb.timeFrames().at(i));
// if(!insertRez) //If a duplicata has been prevented, we do not count the attempt
// j--;
// }
// }
for(int i = 0; i < tmpCourses.size(); i++)
if(tmpCourses.at(i).timeFrame().size() > 0)
pb.addCourseToCatalogue(tmpCourses.at(i));
//From here, coursesCatalogue can still be < to minCourseTF * nbTF (due to the fact that a same course can belongs to )
pb._makeCoursesSortedByTF();
/* COMPETENCY CREATION
* We create _quantityAvailableCompetency competencies. For each comp, we randomly define it's magnitude.
*/
......@@ -288,7 +363,9 @@ int CSDVP::CSDVP_COUNTER = 0;
{
tmpComp = queue.front();
queue.pop();queue.push(tmpComp);
teachedComp = std::pair<Competency,double>(tmpComp, 1.0);
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);
pb.unlocked_coursesCatalogue().at(i).addTeachedComp(teachedComp);
}
}
......@@ -307,8 +384,12 @@ int CSDVP::CSDVP_COUNTER = 0;
for(int j = 0; j < x; j++)
{
tmpComp = queue.front();
queue.pop(); queue.push(tmpComp);
pb.unlocked_coursesCatalogue().at(i).addPrerequisite(tmpComp);
queue.pop();
//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());
pb.unlocked_coursesCatalogue().at(i).addPrerequisite(cpt);
queue.push(tmpComp);
}
}
......
......@@ -44,15 +44,18 @@ class CSDVP
int _minimalPrerequisiteByCourse;
int _maximalPrerequisiteByCourse;
int _pickedCoursesByTimeFrame;
Magnitude _minimalMagnitude;
Magnitude _maximalMagnitude;
// ---------- END CONFIGURATION ATTRIBUTES ----------
// ---------- PROBLEM SPECIFIC ATTRIBUTES ----------
// Theses attributes represent the CSDVP
std::vector<int> _timeFrames;
std::vector<int> _timeFrames; // Time frames stocks the VALUE, not the index
std::vector<Course> _availableCourses;
std::vector<Competency> _availableCompentecies;
std::vector<std::vector<Course>> _coursesSortedByTF; //sorted by standard index. e.g. TF[4;6] -> [0]=4; [1]=5 ; [2] = 6
std::vector<Competency> _availableCompentecies; //The competency's magnitude should not be used here.
///@todo implements a decay politics
//DecayPolitics
......@@ -75,6 +78,9 @@ class CSDVP
static double _randomizeIn(const double min, const double max);
// --------- END GENERATION RELATED FUNCTION ---------
/// It sources _coursesSortedByTF, which is another view of _availableCourses, sorted by TF
void _makeCoursesSortedByTF();
public:
// --------- GENERATION RELATED FUNCTION ---------
/// allows a random attribution of pb's attributes
......@@ -90,7 +96,9 @@ class CSDVP
// === CONSTRUCTOR
CSDVP();
/// Generate an instance of the CSDVP iff isConfig is true. Thus, seed != -1;
/**Generate an instance of the CSDVP iff isConfig is true. Thus, seed != -1;
* @developper each kind of generation must sources correctly the main arrays (_availableCours/comp) TF and _sortedCoursesByTF
*/
static void generateProblem(CSDVP & csdvp, CSDVP::GenerationType type, int seed= -1 );
// === GETTER
......@@ -108,15 +116,30 @@ class CSDVP
const int cfg_competencyByCourseMax() const {return this->_maximalCompetencyByCourse;}
const int cfg_prerequisiteByCourseMin() const {return this->_minimalPrerequisiteByCourse;}
const int cfg_prerequisiteByCourseMax() const {return this->_maximalPrerequisiteByCourse;}
const int cfg_pickedCoursesByTimeFrame() const {return this->_pickedCoursesByTimeFrame;}
const Magnitude & cfg_magnitudeMin() const{return this->_minimalMagnitude;}
const Magnitude & cfg_magnitudeMax() const{return this->_maximalMagnitude;}
const std::vector<int> & timeFrames() const{return this->_timeFrames;}
const std::vector<Course> & coursesCatalogue() const{return this->_availableCourses;}
/**CompetencyCatalogue should be used to know which competency exists in the current pb. However, it should not
* be used to know the magnitude of each comp in the pb, since these mag changes accordingly to the courses (and if it is teached or a prereq)
*/
const std::vector<Competency> & competencyCatalogue() const{return this->_availableCompentecies;}
const std::vector<std::vector<Course>> & coursesSortedByTF() const {return this->_coursesSortedByTF;}
std::vector<int> & unlocked_timeFrames(){return this->_timeFrames;}
std::vector<Course> & unlocked_coursesCatalogue(){return this->_availableCourses;}
std::vector<Competency> & unlocked_competenciesCatalogue(){return this->_availableCompentecies;}
const int getQuantityCoursesToPick() const{
if(this->_isConfig)
return this->_timeFrames.size() * this->_pickedCoursesByTimeFrame;
return -1;//if not config
}
/** Maps a course into its position inside the this->courseCatalogue().
* returns the index of the course within the coursesCatalogue [0;size[ ; otherwise return -1 if the course is not found.
*/
int mapCourseToPosition(const Course & c);
///@todo getDecayPolitic
// === MUTATOR
......@@ -137,6 +160,7 @@ class CSDVP
void set_cfg_maximalCompetencyByCourse(int nb);
void set_cfg_minimalPrerequisiteByCourse(int nb);
void set_cfg_maximalPrerequisiteByCourse(int nb);
void set_cfg_pickedCoursesByTimeFrame(int nb);
void setTimeFrames(std::vector<int> & v);
void setCoursesCatalogue(std::vector<Course> &);
......
......@@ -2,10 +2,13 @@
#include <vector>
#include <utility>
#include <algorithm>
#include <cassert>
#include "profession.h"
#include "competency.h"
#include "exception/JobOverlappingBoundariesException.h"
int Profession::PROFESSION_COUNTER = 0;
// === FACTORY
......@@ -54,6 +57,32 @@ int Profession::PROFESSION_COUNTER = 0;
return *old;
}
void Profession::setRequiredECTS(int nb)
{
assert(nb >= 0);
this->_requiredECTS = nb;
}
void Profession::setRequiredECTS(Profession::GenerationType type)
{
if(type == Profession::GenerationType::RANDOM)
this->_isECTSRandom = true;
}
void Profession::set_cfg_minimalPrerequisites(int nb)
{this->_minimalPrerequisites = nb;}
void Profession::set_cfg_maximalPrerequisites(int nb)
{this->_maximalPrerequisites = nb;}
void Profession::set_cfg_minimalMagnitude(double mag)
{
this->_minimalMagnitude = Magnitude::build(mag);
}
void Profession::set_cfg_maximalMagnitude(double mag)
{
this->_maximalMagnitude = Magnitude::build(mag);
}
// ADDER
/** Adds a new competency to the prerequisites of a profession. It is protected against duplicata: it can't have twice the same competency.
*
......@@ -81,10 +110,127 @@ int Profession::PROFESSION_COUNTER = 0;
// === OPERATOR
std::ostream & operator<<(std::ostream & Stream, const Profession & p)
{
std::string s = "Profession\n\tid:"+std::to_string(p.id())+"\n\tname:"+p.name()+"\n\t#Prereq:"+std::to_string(p.prerequisites().size());
Stream << s;
std::string s = "Profession\n\tid:"+std::to_string(p.id())+"\n\tName:"+p.name()+"\n\tECTS: " + std::to_string(p.requiredECTS()) +"\n\t#Prereq:"+std::to_string(p.prerequisites().size())+"\n\t===Details:===\n\t";
Stream << s ;
for(int i = 0; i < p.prerequisites().size(); i++)
Stream << "("<< i<< "th) " << p.prerequisites().at(i) << "\n\t";
Stream << "==========" << std::endl;
return Stream;
}
bool Profession::checkConfig()
{
if( !this->_isECTSRandom && this->_requiredECTS <= 0)
{
this->_isConfig = false;
std::cout << "INFO: Profession lacks ECTS config" << std::endl;
return false;
}
if(this->_name.empty())
{
this->_isConfig = false;
std::cout << "INFO: Profession lacks name config" << std::endl;
return false;
}
if( this->_minimalPrerequisites < 0 ||
this->_maximalPrerequisites < 0 ||
this->_minimalMagnitude.value() < 0 ||
this->_maximalMagnitude.value() < 0 )
{
std::cout << "INFO: Config attributes not yet config" << std::endl;
this->_isConfig = false;
return false;
}
//verifying overlapping range
if( this->_minimalPrerequisites > this->_maximalPrerequisites ||
this->_minimalMagnitude.value() > this->_maximalMagnitude.value())
{
throw JobOverlappingBoundariesException(this);
}
this->_isConfig = true;
return true;
}
void Profession::_randomlyGenerate(Profession & job, CSDVP & pb)
{
srand(job.seed());
job.unlocked_prerequisites().clear();
int howManyPrereq = job.cfg_minimalPrerequisites() + ( rand() % ( job.cfg_maximalPrerequisites() - job.cfg_minimalPrerequisites() + 1) );
std::vector<Competency> tmpComp = pb.competencyCatalogue();
Competency ctmp;
double magVal;
std::random_shuffle(tmpComp.begin(), tmpComp.end());
int i;
for(i = 0; i < tmpComp.size() && i < howManyPrereq; i++)
{
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());
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());
}
}
// If ECTS is set to be random, then calculating it
if(!job._isECTSRandom)
return;
// Formula of ECTS calcul is : SIGMA_{i=0}^{maxTF}(SIGMA_{j=0}^{nbCourseAvg}(rand(pb.minECTS,pb.maxECTS)))
int ects= 0;
// ects = pb.timeFrames().size() * 30; //30 is the default european value
for(i = 0; i < pb.timeFrames().size(); i++)
{
for(int j = 0; j < pb.cfg_pickedCoursesByTimeFrame(); j++)
{
if( (rand() % 100) > 35) //Take the average in 100-35 % of the cases
ects += ( pb.cfg_ectsMin() + rand() % (pb.cfg_ectsMax() - pb.cfg_ectsMin() +1) );
else
ects += ( pb.cfg_ectsMin() + rand() % ( (pb.cfg_ectsMax() -1) - pb.cfg_ectsMin() +1) );
}
}
job.setRequiredECTS(ects);
}
// === STATIC
int Profession::assignID(){return ++Profession::PROFESSION_COUNTER;}
// ---------- GENERATION FUNCTIONS ----------
void Profession::generateProfession(Profession & job, Profession::GenerationType type, CSDVP & csdvp, int seed)
{
job._seed = seed;
if( !job.checkConfig() || !csdvp.checkConfig())
{
std::cout << "Can't generate a profession with non configurated problem and profession !" << std::endl;
return;
}
switch (type)
{
case Profession::GenerationType::RANDOM:
_randomlyGenerate(job, csdvp);
break;
default:
break;
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@
#include <vector>
#include "competency.h"
#include "problem.h"
/**
* A profession is a job sought by a student.
......@@ -13,9 +14,27 @@
class Profession
{
private:
std::vector<Competency> _prerequisites;
// ---------- CONFIGURATION ATTRIBUTES ---------
std::string _name;
int _requiredECTS = -1;
int _minimalPrerequisites = -1;
int _maximalPrerequisites = -1;
Magnitude _minimalMagnitude;
Magnitude _maximalMagnitude;
// ---------- END CONFIGURATIONS ATTRIBUTES ----------
// ---------- PROFESSION SPECIFIC ATTRIBUTES ----------
std::vector<Competency> _prerequisites;
// ---------- END PROFESSION SPECIFIC ATTRIBUTES
int _id;
int _seed;
/// Use to determine if Profession has been config by the user.
bool _isConfig;
bool _isECTSRandom =false;
// === FUNC
/** _duplicataProtection returns true if the value (2nd param) searched into (1st param) is found*/
......@@ -24,29 +43,57 @@ class Profession
// Static
static int PROFESSION_COUNTER;
static int assignID();
static void _randomlyGenerate(Profession & job, CSDVP & pb);
public:
enum GenerationType
{
RANDOM
//PRESET
};
Profession();
Profession(std::string name);
Profession(std::vector<Competency> & p, std::string n = "");
/** Generates the profession configuration. ECTS still needs to be filled before calling this function.
* Nonetheless, progession _prerequisites are taken randomly in the problem
*/
static void generateProfession(Profession & job, Profession::GenerationType type, CSDVP & csdvp, int seed = 0);
/**Checks the configuration of a profession, mostly before performing a generation.*/
bool checkConfig();
// === GETTER
const int id() const{return this->_id;}
const int seed() const{return this->_seed;}
const int requiredECTS() const{return this->_requiredECTS;}
const std::string name() const{return this->_name;}
const std::vector<Competency> & prerequisites() const{return this->_prerequisites;}
/// return a modifiable reference to _prerequisite;
std::vector<Competency> & unlocked_prerequisites(){return this->_prerequisites;}
const int cfg_minimalPrerequisites() const{return this->_minimalPrerequisites;}
const int cfg_maximalPrerequisites() const{return this->_maximalPrerequisites;}
const Magnitude cfg_minimalMagnitude() const{return this->_minimalMagnitude;}
const Magnitude cfg_maximalMagnitude() const{return this->_maximalMagnitude;}
// === MUTATOR
// SETTER
/// Set name of the profession. If name empty, creates a default name based on ID
void setName(std::string name);
/// Set the prerequisites of a profession. The old prereq is returned.
std::vector<Competency> & setPrerequisites(std::vector<Competency> & v);
void setRequiredECTS(int ects);
void setRequiredECTS(Profession::GenerationType type);
// ADDER
bool addPrerequisite(Competency &);
void set_cfg_minimalPrerequisites(int nb);
void set_cfg_maximalPrerequisites(int nb);
void set_cfg_minimalMagnitude(double mag);
void set_cfg_maximalMagnitude(double mag);
};
// === OPERATOR
......
#ifndef SRC_MODEL_TOOLS_H_
#define SRC_MODEL_TOOLS_H
#define SRC_MODEL_TOOLS_H_
#include <vector>
#include <utility>
#include <algorithm>
#include <queue>
#include <random>
#include <limits>
static const int ID_RANGE_FOR_OBJECT = 10000;
static const int ID_RANGE_FOR_TEMPORARY_OBJECT = std::numeric_limits<int>::max();
template<typename T>
/** Searches into vec the element findMe. The class T must have T() defined ( T()=default; is OK) */
......@@ -38,4 +44,38 @@ static bool duplicataFlag(std::vector<T> & toProtect, T & toAdd)
}
template<typename T>
static std::pair<bool,T> getElementById(const std::vector<T> & elem, int idToFind)
{
for(int i = 0; i < elem.size(); i++)
{
if(elem.at(i).id() == idToFind)
return std::pair<bool,T>(true, elem.at(i));
}
return std::pair<bool, T>(false, T());
}
///Not working properly yet, just for debug
// static std::queue<int> RNG_QUEUE;
// /**Init a queue of size s from 0 to s, then shuffle it*/
// static void initRandomSuite(const unsigned int s)
// {
// RNG_QUEUE = std::queue<int>();
// std::vector<int> tmp (s);
// for(int i = 0; i < s; i++)
// tmp.push_back(i);
// // std::random_device rng;
// // std::mt19937 urng(rng());
// std::random_shuffle(tmp.begin(), tmp.end());
// for(int i = 0; i < tmp.size(); i++)
// RNG_QUEUE.push(tmp.at(i));
// }
// static int getNextRandom()
// {
// int tmp = RNG_QUEUE.front();
// RNG_QUEUE.pop();
// return tmp;
// }
#endif // SRC_MODEL_TOOLS_H_
\ No newline at end of file
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