Commit 34f7dd28 authored by Valentin Antuori's avatar Valentin Antuori
Browse files

-

parent 9f2fd4c9
......@@ -3,6 +3,8 @@
#include "heuristic.h"
#define DEBUG_H false
using namespace std;
double default_temperature = 0.1;
......@@ -77,29 +79,36 @@ void build(const Instance& data, Solution& sol, State& s)
for(int i = sol.size(); i < data.nb_tasks; ++i)
{
// std::cerr << "step "<< i << std::endl;
if(DEBUG_H)
std::cerr << "step "<< i << std::endl;
vector<int> actions = s.get_actions();
// std::cerr << "Candidates : " << std::endl;
if(DEBUG_H)
std::cerr << "Candidates : " << std::endl;
// compute proba;
vector<double> proba = get_distribution(data, s, actions);
// for(size_t i = 0; i < proba.size(); ++i){
// std::cerr << actions[i] << " : " << proba[i] << std::endl;
// }
if(DEBUG_H)
for(size_t i = 0; i < proba.size(); ++i){
std::cerr << actions[i] << " : " << proba[i] << std::endl;
}
int idx = choice(proba);
sol.append(actions[idx]);
s.update(actions[idx]);
// std::cerr << s << std::endl;
// std::cerr << sol << std::endl;
// std::cerr << " --- " << std::endl;
if(DEBUG_H){
std::cerr << s << std::endl;
std::cerr << sol << std::endl;
std::cerr << " --- " << std::endl;
}
}
// std::cerr << "End Build" << std::endl;
if(DEBUG_H)
std::cerr << "End Build" << std::endl;
}
......@@ -110,19 +119,31 @@ vector<double> get_distribution(const Instance& data, const State& s, const std:
vector<double> get_distribution(const Instance& data, const State& s, const std::vector<int>& actions, const double temperature)
{
if(DEBUG_H)
std::cerr << "Get distribution : " << std::endl;
// std::cerr << "Size : " << actions.size() << std::endl;
double sum_exp_fitness = 0;
// std::cerr << "exp_finess" << std::endl;
vector<double> exp_fitness(actions.size());
// std::cerr << "vector1" << std::endl;
vector<double> proba(actions.size());
// std::cerr << "vector2" << std::endl;
// std::cerr << "last action :" << s.last_action << std::endl;
if(DEBUG_H){
std::cerr << "last action :";
std::cerr << s.last_action << std::endl;
}
for(size_t i = 0; i < actions.size(); ++i)
{
//compute fitness for action i
// std::cerr << actions[i] << " : " ;
if(DEBUG_H)
std::cerr << actions[i] << " : " ;
double fitness = fitness_func(data, s, actions[i]);
// std::cerr << "Fitness="<<fitness << std::endl;
if(DEBUG_H)
std::cerr << "Fitness="<<fitness << std::endl;
exp_fitness[i] = exp(fitness / temperature);
sum_exp_fitness += exp_fitness[i];
......
......@@ -14,7 +14,7 @@ Instance::Instance(const std::string& filename)
std::ifstream infile(filename);
infile >> nb_tasks >> T_max;
std::cout << nb_tasks << " tasks" << std::endl;
//std::cout << nb_tasks << " tasks" << std::endl;
// pass lines
std::string line("");
......
......@@ -19,9 +19,86 @@
#include "mcts.h"
#include "heuristic.h"
#include <unistd.h>
namespace fs = std::experimental::filesystem;
using namespace std;
void random_tree()
{
std::cout << " =============== " << std::endl;
Node::count = 0;
Node root(0, 0, -1, 0, nullptr);
// vector<Node*> nodes_vector;
// nodes_vector.push_back(&root);
for(auto i = 0; i < 10; ++i){
root.add_child(/*reward=*/0, 0, 0, 0);
// nodes_vector.push_back(root.children.back());
}
{
std::list<Node*> nexts(root.children.begin(), root.children.end());
const int MAX_NODE = 10000000;
int nb_node = 1;
const double proba = 0.9;
while(!nexts.empty() && nb_node < MAX_NODE)
{
Node* current = nexts.front();
nexts.pop_front();
if(rand()/RAND_MAX < proba)
{
int nb_children = rand() % 8 + 3;
for(int i = 0; i < nb_children; ++i)
{
current->add_child(/*reward=*/0, 0, 0, 0);
nexts.push_back(current->children.back());
// nodes_vector.push_back(current->children.back());
nb_node++;
}
}
}
}
// std::cout << "Nb nodes : " << nodes_vector.size() << std::endl;
// nodes_vector.clear();
std::cout << "Root :";
for(auto child : root.children){
std::cout << child->id << ", ";
}
std::cout << std::endl;
sleep(3);
for(int i = 0; i < 5; ++i)
{
std::cout << " --- " << std::endl;
std::cout << "Delete node " << root.children[0]->id << std::endl;
delete root.children[0];
std::cout << "Root :";
for(auto child : root.children){
std::cout << child->id << ", ";
}
std::cout << std::endl << " --- " << std::endl;
sleep(3);
}
std::cout << "Creating new nodes..." << std::endl;
{
const int MAX_NODE = 4491163 + 247541 + 434232 + 786651 + 396212;
int nb_node = 1;
for(int i = 0; i < MAX_NODE; ++i)
root.add_child(0, 0, 0, 0);
}
sleep(5);
std::cout << "Adding a child to a new node" << std::endl;
root.children.back()->add_child(0, 0, 0, 0);
std::cout << std::endl;
std::cout << "Root has " << root.children.size() << " children" << std::endl;
delete root.children.back()->children[0];
std::cout << "Root has " << root.children.size() << " children" << std::endl;
}
void greedy_sample_stat(double temperature, Instance& data, int nb_iter)
{
......@@ -133,10 +210,7 @@ int main(int argc, char **argv){
}
else if(opt.mcts)
{
std::unique_ptr<Solution> sol = solve(data[0], opt.c);
std::unique_ptr<Solution> sol = solve(data[0], opt.c,/*print_stat=*/true, opt.time, opt.mcts_backup);
}
else if(opt.heuristic)
{
......@@ -144,6 +218,7 @@ int main(int argc, char **argv){
std::cout << best_sol->lmax() << std::endl;
}
else{
/*
int NB_ITER = 1000;
{
std::cout << "Random sample" << std::endl;
......@@ -184,9 +259,27 @@ int main(int argc, char **argv){
greedy_sample_stat(1, data[0], NB_ITER);
greedy_sample_stat(0.1, data[0], NB_ITER);
greedy_sample_stat(0.01, data[0], NB_ITER);
*/
// test tree structure
// sleep(3);
//random_tree();
auto sol = std::make_unique<Solution>(data[0]);
for(int i = 0; i < 10000000; ++i)
{
State s(data[0]);
auto sol2 = std::make_unique<Solution>(data[0]);
// auto sol2 = new Solution(data[0]);
build(data[0], *sol2, s);
sol = std::move(sol2);
std::cerr << "Obj=" <<sol->lmax() << std::endl;
}
}
std::cout << "Fin" << std::endl;
// std::cout << "Fin" << std::endl;
// for(int i = 0; i < 10000000000000; ++i ){
// }
......
#include <list>
#include <limits>
#include <vector>
#include <chrono>
#include <stdlib.h>
#include <math.h>
......@@ -10,21 +11,32 @@
#define DEBUG true
#define DEBUG_MODE true
#define EXPAND_TEMPERATURE 0.1
#define MAX_ITER 10000
#define MAX_ITER 20
#define NB_SAMPLE 1
#define NB_SAMPLE 100
/**
Main function, run the algorithm on the instance in data
@param data : the instance to solve
*/
std::unique_ptr<Solution> solve(const Instance& data, double c)
std::unique_ptr<Solution> solve(const Instance& data, double c, bool print_stat, int timeout, int backup)
{
bool DEBUG = DEBUG_MODE;
if(DEBUG)
std::cerr << "--- Start MCTS ---" << std::endl;
auto begin_time = std::chrono::steady_clock::now();
auto run_until = begin_time + std::chrono::seconds(timeout);
double mean_depth = 0.0;
long nb_node_created = 1; //root node
long nb_node_deleted = 0;
int best_iter = 0;
// initialize best_sol with heuristics
std::unique_ptr<Solution> best_sol = build(data);
if(DEBUG)
......@@ -33,15 +45,16 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
// create root node and all its children
Node root(0, 0, -1, 0, nullptr);
// get mean and std dev from root
auto sol = Solution(data);
State s(data);
// auto sol = Solution(data);
// State s(data);
//best_sol = samples(root, sol, s, std::move(best_sol));
// Add the first probe at the root node (in order to have N = 1 for it)
//root.update(root.mean);
int iter_count = 0;
while(best_sol->lmax() > 0 && iter_count < MAX_ITER)
while(best_sol->lmax() > 0 && std::chrono::steady_clock::now() < run_until)
{
iter_count++;
......@@ -53,6 +66,11 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
/////////////////////////////
///////// SELECTION /////////
/////////////////////////////
if(DEBUG)
{
std::cerr << " ======== Iter "<<iter_count << " ========" << std::endl;
std::cerr << "-- Selection --" << std::endl;
}
Node* current_node = &root;
while(!current_node->is_leaf())
{
......@@ -60,8 +78,9 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
double max_ucb = -std::numeric_limits<float>::infinity();
// compute ucb for each children and keep the best one
double sqrt_n = sqrt((double)current_node->N);
std::cerr << "mean=" << current_node->mean << ", std=" << current_node->std_dev << ", N=" << current_node->N << ", sqrt_n=" << sqrt_n << std::endl;
for(auto child : current_node->children){
if(DEBUG)
std::cerr << "mean=" << current_node->mean << ", std=" << current_node->std_dev << ", N=" << current_node->N << ", sqrt_n=" << sqrt_n << std::endl;
for(auto child : current_node->children){
double Q = -(child->avg_W - current_node->mean) / current_node->std_dev;
if(child->N < 1)
......@@ -87,13 +106,18 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
sol->append(best->action);
current_node = best;
}
std::cerr << "Partial Sol : " << *sol << std::endl;
if(DEBUG)
std::cerr << "Partial Sol : " << *sol << std::endl;
int cur_depth = sol->size();
mean_depth = mean_depth + (cur_depth - mean_depth)/iter_count;
////////////////////////////
///////// EXPAND /////////
////////////////////////////
std::cerr << "-- Expansion --" << std::endl;
if(DEBUG)
std::cerr << "-- Expansion --" << std::endl;
std::vector<int> actions = s.get_actions();
std::vector<double> action_distribution = get_distribution(data, s, actions, EXPAND_TEMPERATURE);
......@@ -102,21 +126,32 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
int end_date = current_node->end_date + data.distance(current_node->action, actions[i]) + data.duration(actions[i]);
if(end_date > data.due_date(actions[i])){ // Don't expand if a children gets tardiness
delete_current_node = true;
if(DEBUG)
{
std::cerr << actions[i] << " is late" << std::endl;
}
break;
}
current_node->add_child(/*reward=*/0, action_distribution[i], actions[i], end_date);
}
if(delete_current_node){
if(DEBUG)
std::cerr << "Delete Node" << std::endl;
std::cerr << "Delete Node "<< current_node->id << ", " << current_node->children.size() << " children" << std::endl;
// std::cout << "delete" << std::endl;
delete current_node;
nb_node_deleted++;
}else{
std::cerr << "-- Simulation --" << std::endl;
nb_node_created += actions.size();
if(DEBUG)
std::cerr << "-- Simulation --" << std::endl;
///////////////////////////////
////////// SIMULATION /////////
///////////////////////////////
int keep_best_lmax = best_sol->lmax();
/* //--- Classical simulation ---- /
//choose the next randomly here, as we already get the distribution
......@@ -128,25 +163,44 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
//*/
// -- Get mean and standard deviation from multiple `dives` --
// best_sol = samples(*current_node, *sol, s, std::move(best_sol));
std::unique_ptr<Solution> iter_best = samples(*current_node, *sol, s);
double backup_value = iter_best->lmax();
double backup_value;
if(iter_best->lmax() < best_sol->lmax())
// seperate cases for performance purpose (number of move operation for best sol is higher for the second case)
if(backup == BACKUP_MEAN)
{
best_sol = std::move(iter_best);
best_sol = samples(*current_node, *sol, s, std::move(best_sol));
backup_value = current_node->mean;
}else if(backup == BACKUP_BEST)
{
std::unique_ptr<Solution> iter_best = samples(*current_node, *sol, s);
backup_value = iter_best->lmax();
if(iter_best->lmax() < best_sol->lmax())
{
best_sol = std::move(iter_best);
}
}else{
backup_value = 0;
}
//
if(keep_best_lmax > best_sol->lmax())
{
best_iter = iter_count;
}
////////////////////////////
///////// BACKUP /////////
////////////////////////////
if(DEBUG)
std::cerr << "-- Backup --" << std::endl;
std::cerr << "-- Backup --" << std::endl;
// double backup_value = sol->lmax();
// double backup_value = current_node->mean;
while(!current_node->is_root()){
current_node->update(backup_value);
current_node = current_node->parent;
......@@ -162,11 +216,29 @@ std::unique_ptr<Solution> solve(const Instance& data, double c)
// }
}
std::cout << "iter " << iter_count << ", best solution = " << best_sol->lmax() << ", depth iter = " << sol->size() << std::endl;
std::cerr << "iter " << iter_count << ", best solution = " << best_sol->lmax() << ", depth iter = " << sol->size() << std::endl;
if(iter_count >= 399){
break;
}
}
return best_sol; //compiler replace by return std::move(best_sol)
auto end_time = std::chrono::steady_clock::now();
std::chrono::duration<double> resolutionTime = end_time - begin_time;
std::cout << "solve = " << (best_sol->lmax() == 0) << std::endl;
std::cout << "best objective = " << best_sol->lmax() << std::endl;
std::cout << "best iteration = " << best_iter << std::endl;
std::cout << "nb itereration = " << iter_count << std::endl;
std::cout << "resolution time = " << resolutionTime.count() << std::endl;
std::cout << "mean objective = " << root.avg_W << std::endl;
std::cout << "mean depth = " << mean_depth << std::endl;
std::cout << "nodes created = " << nb_node_created << std::endl;
std::cout << "nodes deleted = " << nb_node_deleted << std::endl;
return std::move(best_sol);
}
std::unique_ptr<Solution> samples(Node& current_node, const Solution& sol, const State& s, std::unique_ptr<Solution> best_sol)
......@@ -199,7 +271,7 @@ std::unique_ptr<Solution> samples(Node& current_node, const Solution& sol, const
current_node.mean = lmax_mean;
current_node.std_dev = lmax_std_dev;
return best_sol;
return std::move(best_sol);
}
std::unique_ptr<Solution> samples(Node& current_node, const Solution& sol, const State& s)
......@@ -235,7 +307,11 @@ std::unique_ptr<Solution> samples(Node& current_node, const Solution& sol, const
current_node.mean = lmax_mean;
current_node.std_dev = lmax_std_dev;
return best_sol;
//could be 0, in case of tiny sample size but shouldn't
if(current_node.std_dev == 0)
current_node.std_dev = 1;
return std::move(best_sol);
}
/////////////////////////
/// Class Node ///
......@@ -243,56 +319,80 @@ std::unique_ptr<Solution> samples(Node& current_node, const Solution& sol, const
int Node::count = 0;
Node::Node(double R, double P, int action, int end_date, Node* parent)
:R(R), W(0), avg_W(0), P(P), N(0), action(action), end_date(end_date), parent(parent)
{ id = count++; }
:R(R), W(0), avg_W(0), P(P), N(0), action(action), end_date(end_date), parent(parent), is_collected(false)
{
id = count++;
if(parent == nullptr){
depth = 0;
}else{
depth = parent->depth + 1;
}
}
Node* Node::add_child(double reward, double prior_proba, int action, int end_date) {
void Node::add_child(double reward, double prior_proba, int action, int end_date)
{
Node *n = new Node(reward, prior_proba, action, end_date, this);
children.push_back(n);
return n;
//return n;
}
Node::~Node()
{
if(children.size() > 0 && !is_root())
if(!is_collected)
{
std::cout << "Destructor" << std::endl;
// remove the node for the parent's children list
size_t i;
for(i = 0; i < parent->children.size(); ++i)
if(!is_root() && parent->children.size() == 1)
{
if(parent->children[i] == this)
if(DEBUG_MODE)
std::cerr << "Deleting parent of node " << id << ", depth = " << depth << std::endl;
delete parent;
}else{
if(DEBUG_MODE)
std::cerr << "Deleting node : " << id << ", depth = " << depth << std::endl;
if(!is_root())
{
break;
// remove the node from the parent's children list
size_t i;
for(i = 0; i < parent->children.size(); ++i)
{
if(parent->children[i] == this)
{
break;
}
}
std::swap(parent->children[i], parent->children.back());
parent->children.pop_back();
}
}
// remove in O(1) with idx;
std::swap(parent->children[i], parent->children.back());
parent->children.pop_back();
}
std::list<Node*> to_delete(children.begin(), children.end());
std::list<Node*> nexts(to_delete);
std::list<Node*> to_delete(children.begin(), children.end());
std::list<Node*> nexts(to_delete);
if(DEBUG_MODE)
std::cerr << "Collecting nodes..." << std::endl;
// collect all subnodes
while(!nexts.empty())
{
Node* current = nexts.front();
nexts.pop_front();
for(auto child : current->children){
nexts.push_back(child);
to_delete.push_back(child);
// collect all subnodes
while(!nexts.empty())
{
Node* current = nexts.front();
nexts.pop_front();
current->is_collected = true;
for(auto child : current->children){
nexts.push_back(child);
to_delete.push_back(child);
}
// clear the sub node vector here !!!
//current->children.clear();
}
if(DEBUG_MODE)
std::cerr << to_delete.size() << " nodes to delete" << std::endl;
// Then delete all the collected nodes (I don't remember why reverse order is/was relevant ?)
for (auto it {to_delete.rbegin() }; it != to_delete.rend(); ++it)
{
// here, collected node must have is_collected attribute set to true
delete (*it);
}
}
// clear the sub node vector here !!!
current->children.clear();
}
// Then delete all the collected nodes (I don't remember why reverse order is/was relevant ?)
for (auto it {to_delete.rbegin() }; it != to_delete.rend(); ++it)
{
delete (*it);
}
children.clear();
}
bool Node::is_leaf()
......
......@@ -7,12 +7,15 @@
#include "instance.h"
#include "solution.h"
#define BACKUP_MEAN 0
#define BACKUP_BEST 1
class Node;
/**
Main function, run the algorithm on the instance in data
@param data : the instance to solve
*/
std::unique_ptr<Solution> solve(const Instance& data, double c);
Solution solve(const Instance& data, double c, bool print_stat, int timeout, int backup);
/**
* Samples from the partial solution *sol*
* compute the mean value and the std deviation of the current_node
......@@ -44,6 +47,7 @@ class Node
Node *parent;
int id; // Identificator
int depth;