#include "Solver.h" #include "Solution.h" #include "Assignment.h" #include "GeneticAlgorithm.h" #include "structures/Employee.h" #include #include #include #define RANDF() static_cast(rand()) / static_cast (RAND_MAX) void solver(int nPop, int nGen, float rCross, float rMut, Distances& distances, Centers& centers, Employees& employees, Missions& missions) { Solutions* population = generateSolutions(nPop, distances, centers, employees, missions); GeneticAlgorithm* GA = new GeneticAlgorithm(nGen, rCross, rMut, population, &fitness, &selection, &crossover, &mutator); try { GA->algorithm(); } catch (std::exception ex) { std::cerr << "Exception during GA.algorithm:\n" << ex.what() << "\n"; } } float fitness(Solution* individual) { std::cout << "Unassigned missions: " << individual->unassignedCount() << "\nCost: " << individual->cost() << "\n"; //individual->print(); return individual->cost(); } Solution* selection(Solutions* population, Scores* scores) { float fitnessTotal = std::reduce(scores->begin(), scores->end()); if (fitnessTotal == 0.f) return (*population)[rand() % population->size()]; int size = scores->size(); float* probabilities = new float[size]; float prevProb = 0; for (int i = 0; i < size; i++) { float score = (*scores)[i]; float prob = score / fitnessTotal + prevProb; probabilities[i] = prob; prevProb = prob; } float x = RANDF(); int best = 0; for (int i = 0; i < size; i++) { float prob = probabilities[i]; if (x < prob) return (*population)[i]; } // This should never happen, but just in case std::cout << "This should never be reached\n"; return (*population)[0]; } void crossover(float rCross, Solution* p1, Solution* p2, Solution** c1, Solution** c2) { *c1 = p1; *c2 = p2; } void mutator(Solution* individual, float rMut) { // For each assignment, loop through the missions, roll for each, if over rMut, pick a suitable mission to swap with for (Assignment* assignment : *(individual->getAssignments())) { std::cout << "Mutating assignment for employee: " << assignment->employee->id << "\n"; for (int i = 0; i < assignment->missions.size(); i++) { float x = RANDF(); std::cout << i << ": " << x << " > " << rMut << "\n"; if (x < rMut) { std::cout << "Mutating assignment mission " << i << "\n"; assignment->replaceMission(i, individual->getUnassignedMissions()); } } } } Solutions* generateSolutions(int nPop, Distances& distances, Centers& centers, Employees& employees, Missions& missions) { std::cout << "Generating " << nPop << " solutions\n"; Solutions* solutions = new Solutions {}; for (int i = 0; i < nPop; i++) { Solution* solution = generateSolution(distances, centers, employees, missions); //solution->print(); solutions->push_back(solution); } return solutions; } Solution* generateSolution(Distances& distances, Centers& centers, Employees& employees, Missions& missions) { // TODO: randomise // Maybe instead iterate over missions and pick a random employee to give it to? MissionList* remainingMissions = missions.copy(); Solution* solution = new Solution { missions.size(), remainingMissions }; for (Employee* employee : employees) { std::cout << "Creating assignment for employee " << employee->id << "\n"; Assignment* assignment = new Assignment { employee, &distances }; for (int day = 1; day < 6; day++) { //for (Mission* mission : *remainingMissions) for(int index = 0; index < remainingMissions->size(); index++) { Mission* mission = (*remainingMissions)[index]; if (mission->day != day) continue; Mission* lastMission = assignment->getLastMission(day); if (lastMission != nullptr && lastMission->end > mission->start) continue; float dailyWorkTime = assignment->getWorkTime(day); float workTime = assignment->getTotalWorkTime(mission); if (mission->profession == employee->profession && Employee::MaxWorkTime >= dailyWorkTime && Employee::MaxWorkTimeWeek >= workTime) { //std::cout << "Adding mission " << mission->id << "\n"; assignment->addMission(mission); remainingMissions->erase(remainingMissions->begin() + index); index--; } } } solution->addAssignment(assignment); } return solution; }