OptimisationProblem/Solver.cpp

149 lines
4.2 KiB
C++
Raw Permalink Normal View History

2023-07-17 00:19:10 +02:00
#include "Solver.h"
#include "Solution.h"
#include "Assignment.h"
#include "GeneticAlgorithm.h"
#include "structures/Employee.h"
#include <vector>
#include <numeric>
#include <iostream>
#define RANDF() static_cast<float>(rand()) / static_cast<float> (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;
}