Commit f13f15c4 authored by ehebrard's avatar ehebrard
Browse files

restarts and sigmoid

parent 65a9d949
......@@ -2,6 +2,7 @@
#include <assert.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include "DFSRollout.h"
......@@ -31,11 +32,18 @@ int DFSRollout::component_ect(const int op) const
return t;
}
// should return a number in [0,1] that correlates with the action's fitness
double DFSRollout::fitness_func(const int action) const
{
int ect{component_ect(action)};
double lambda1{static_cast<double>(data.due_date(action) - ect) / static_cast<double>(data.max_slack)};
auto prev_tardiness{maximum_positive_tardiness[maximum_positive_tardiness.size() - 2]};
// double lambda1{static_cast<double>(data.due_date(action) - ect) / static_cast<double>(data.max_slack)};
// double lambda1{static_cast<double>(prev_tardiness-tardiness[action]) / static_cast<double>(data.max_slack)};
double lambda1{fast_sigmoid(prev_tardiness - tardiness[action], sigmoid_slope)};
// double lambda1{1.0 - fast_sigmoid(tardiness[action], sigmoid_slope)};
// double lambda1{1.0 - fast_sigmoid(tardiness[action] - , .1)};
// double lambda1{1.0 - fast_sigmoid(tardiness[action] - get_tardiness())};
double lambda2{static_cast<double>(start[action] - tour_length) / static_cast<double>(data.max_dist)};
double lambda3{1 - (static_cast<double>(data.trolley_length(action)) / static_cast<double>(data.T_max))};
double lambda4{static_cast<double>(data.is_pickup(action))};
......@@ -43,17 +51,99 @@ double DFSRollout::fitness_func(const int action) const
return 1 - (THETA_1 * lambda1 + THETA_2 * lambda2 + THETA_3 * lambda3 + THETA_4 * lambda4);
}
double DFSRollout::DFSRollout::get_avg_travel_time(const int op) const {
return avg_travel_time[op % 4][data.component(op)];
}
double DFSRollout::get_avg_train_time(const int op) const {
assert(data.is_delivery(op));
return avg_travel_time[(op % 4)/2][data.component(op)];
}
int DFSRollout::get_cur_train_time(const int op) const {
if(data.is_pickup(op))
return 0;
auto c{data.component(op)};
auto prev{prev_operation[c]};
return start[op] - start[prev] - data.duration(prev);
}
double DFSRollout::new_fitness_func(const int action) const
{
int ect{component_ect(action)};
auto prev_tardiness{maximum_positive_tardiness[maximum_positive_tardiness.size() - 2]};
// double lambda1{static_cast<double>(max(-100,data.due_date(action) - ect)) / static_cast<double>(data.max_slack+100)};
double lambda1{1.0 - fast_sigmoid(tardiness[action] - prev_tardiness, .0001)};
// double lambda1{static_cast<double>(min_action_tardiness - data.due_date(action) + ect) / static_cast<double>(min_action_tardiness - max_action_tardiness)};
double lambda2{static_cast<double>(start[action] - tour_length) / static_cast<double>(data.max_dist)};
double lambda3{1.0 - (static_cast<double>(data.trolley_length(action)) / static_cast<double>(data.T_max))};
// // auto f{(1.0 - fast_sigmoid(tardiness[op] - get_tardiness()))};
// cout << "T = " << setw(4) << prev_tardiness << " / " << setw(6) << tardiness[action] << ": " << setw(8) << lambda1
// << " D = " << setw(4) << data.max_dist << " / " << setw(4) << (start[action] - tour_length) << ": " << setw(8) << lambda2
// << endl;
// if(lambda1 < .2)
// exit(1);
// double lambda3{1 - static_cast<double>(get_cur_train_time(action)) / static_cast<double>(data.max_slack)};
// double lambda2{(static_cast<double>(start[action] - tour_length) - get_avg_travel_time(action)) / static_cast<double>(data.max_dist)};
// double lambda3{1 - (static_cast<double>(data.trolley_length(action)) / static_cast<double>(data.T_max))};
// double lambda4{static_cast<double>(data.is_pickup(action))};
// lambda1 += 1;
// lambda1 /= 2;
//
// // if(lambda2 > 1) {
// // cout << action << " " << (start[action] - tour_length) << " " << (data.release_date(action) - tour_length) << " " << data.max_dist << endl;
// // }
//
//
// if(lambda1 < 0 or lambda1 > 1) {
// cout << data.component(action) << " dd=" << data.due_date(action) << " ect=" << ect << " tard=[" << min_action_tardiness << ".." << max_action_tardiness << "]" << endl;
// }
//
//
// assert(lambda1 >= 0);
// assert(lambda1 <= 1);
//
// assert(lambda2 >= 0);
// // assert(lambda2 <= 1);
//
// assert(lambda3 >= 0);
// assert(lambda3 <= 1);
return 1 - (lambda1 * .5 + lambda2 * .5); // + lambda3 * .05);
}
DFSRollout::DFSRollout(Instance& data) : data(data) {
period.resize(data.nb_components, 0);
prev_operation.resize(data.nb_components, -1);
num_operation.resize(data.nb_components, 0);
start_period.resize(data.nb_components, 0);
start_prev_operation.resize(data.nb_components, -1);
start_num_operation.resize(data.nb_components, 0);
start.resize(data.nb_tasks, 0);
distance.resize(data.nb_tasks, 0);
tardiness.resize(data.nb_tasks, 0);
proba.resize(data.nb_tasks, 0);
maximum_tardiness.push_back(0);
maximum_positive_tardiness.push_back(0);
maximum_tardiness.push_back(numeric_limits<int>::min());
domain.resize(data.nb_tasks);
action.resize(data.nb_tasks);
......@@ -61,34 +151,66 @@ DFSRollout::DFSRollout(Instance& data) : data(data) {
random_generator.seed(12345);
// #ifdef STATS
// travel_time.resize(data.nb_components);
for(auto i{0}; i<4; ++i) {
avg_travel_time[i].resize(data.nb_components, 0.0);
num_att[i].resize(data.nb_components, 0);
}
for(auto i{0}; i<2; ++i) {
avg_train_time[i].resize(data.nb_components, 0.0);
}
// #endif
}
void DFSRollout::clear() {
sequence.clear();
void DFSRollout::clear(const int lvl) {
sequence.resize(lvl);
// std::fill(period.begin(), period.end(), 0);
// std::fill(num_operation.begin(), num_operation.end(), 0);
// std::fill(prev_operation.begin(), prev_operation.end(), -1);
for(auto i{0}; i<data.nb_components; ++i) {
period[i] = start_period[i];
num_operation[i] = start_num_operation[i];
prev_operation[i] = start_prev_operation[i];
}
std::fill(period.begin(), period.end(), 0);
std::fill(num_operation.begin(), num_operation.end(), 0);
std::fill(prev_operation.begin(), prev_operation.end(), -1);
maximum_tardiness.clear();
maximum_tardiness.push_back(0);
// maximum_positive_tardiness.clear();
// maximum_positive_tardiness.push_back(0);
maximum_positive_tardiness.resize(1+lvl);
// maximum_tardiness.clear();
// maximum_tardiness.push_back(numeric_limits<int>::min());
maximum_tardiness.resize(1+lvl);
tour_length = 0;
train_length = 0;
tour_length = start_tour_length;
train_length = start_train_length;
}
void DFSRollout::verify(const char* msg, const int offset) {
if(maximum_positive_tardiness.size() != sequence.size() + 1 + offset) {
cout << msg << ", tardiness stack length: " << (maximum_positive_tardiness.size()) << " != " << (sequence.size() + 1) << endl;
exit(1);
}
if(maximum_tardiness.size() != sequence.size() + 1 + offset) {
cout << msg << ", tardiness stack length: " << (maximum_tardiness.size()) << " != " << (sequence.size() + 1) << endl;
exit(1);
}
if(sequence.size() > 0) {
auto tl{data.train_use(sequence[0])};
for(int i{1}; i<sequence.size(); ++i) {
assert(max(0, maximum_tardiness[i]) == maximum_positive_tardiness[i]);
int x{sequence[i-1]};
int y{sequence[i]};
......@@ -108,7 +230,7 @@ void DFSRollout::verify(const char* msg, const int offset) {
cout << msg << ", wrong tardiness for " << y << ": " << (start[y] + data.duration(y) - data.due_date(y))
<< " > " << maximum_tardiness[i+1] << endl;
// cout << " tardiness stack length: " << (maximum_tardiness.size()) << " != " << (sequence.size() + 1) << endl;
// cout << " tardiness stack length: " << (maximum_positive_tardiness.size()) << " != " << (sequence.size() + 1) << endl;
exit(1);
}
......@@ -160,6 +282,7 @@ void DFSRollout::get_distribution(const double temperature)
double max_fit = -std::numeric_limits<float>::infinity();
// cout << endl;
// Need Max fitness for soft max regularization
for(auto i{0}; i < actions.size(); ++i)
{
......@@ -217,43 +340,59 @@ int DFSRollout::get_previous_operations(const int op) const {
return data.get_pickup(op);
}
int DFSRollout::compute_distance(const int op) {
auto here{sequence.back()};
void DFSRollout::compute_distance(const int op) {
distance[op] = 0;
start[op] = 0;
tardiness[op] = 0;
if(sequence.size() > 0) {
auto here{sequence.back()};
distance[op] = data.distance(here, op);
distance[op] = data.distance(here, op);
start[op] = data.release_date(op);
if(tour_length + distance[op] > start[op]) {
start[op] = tour_length + distance[op];
} else {
distance[op] = start[op] - tour_length;
start[op] = data.release_date(op);
if(tour_length + distance[op] > start[op]) {
start[op] = tour_length + distance[op];
} else {
distance[op] = start[op] - tour_length;
}
}
return start[op] + data.duration(op) - data.due_date(op);
tardiness[op] = component_ect(op) - data.due_date(op);
// auto f{(1.0 - fast_sigmoid(tardiness[op] - get_tardiness()))};
// cout << get_tardiness() << " / " << tardiness[op] << ": " << f << endl;
//
//
// if(f < .5)
// exit(1);
// return ;
// return start[op] + data.duration(op) - data.due_date(op);
// auto tardiness{start[op] + data.duration(op) - data.due_date(op)};
}
void DFSRollout::compute_distances() {
if(sequence.size() == 0) {
maximum_tardiness.push_back(0);
for(auto op : actions) {
start[op] = 0;
distance[op] = 0;
}
} else {
auto max_tardiness{0};
for(auto op : actions) {
auto tardiness{compute_distance(op)};
max_tardiness = std::max(max_tardiness, tardiness);
}
maximum_tardiness.push_back(std::max(get_tardiness(), max_tardiness));
// cout << endl << "dists (" << maximum_positive_tardiness.size() << ")\n";
max_action_tardiness = numeric_limits<int>::min();
min_action_tardiness = numeric_limits<int>::max();
for(auto op : actions) {
compute_distance(op);
max_action_tardiness = std::max(max_action_tardiness, tardiness[op]);
min_action_tardiness = std::min(min_action_tardiness, tardiness[op]);
}
maximum_tardiness.push_back(std::max(maximum_tardiness.back(), max_action_tardiness));
maximum_positive_tardiness.push_back(max(0, maximum_tardiness.back()));
}
void DFSRollout::print_step() const {
// for(auto p : sequence) {
// cout << " " << p;
// }
// cout << endl;
if(sequence.size() == 0)
cout << sequence.size() << " empty!\n";
else {
......@@ -264,6 +403,20 @@ void DFSRollout::print_step() const {
}
}
void DFSRollout::print_sol() const {
// #ifdef STATS
for(int c{0}; c<data.nb_components; ++c) {
if(c)
cout
<< " | ";
for(auto t{0}; t<2; ++t) {
cout << " " << setw(3) << (int)(avg_train_time[t][c]);
}
}
cout << endl;
// #endif
}
void DFSRollout::greedy_first() {
while(sequence.size() < data.nb_tasks) {
get_operations();
......@@ -276,6 +429,11 @@ void DFSRollout::greedy_first() {
// print_step();
}
if(get_tardiness() < best_tardiness) {
best_sequence = sequence;
best_tardiness = get_tardiness();
}
}
void DFSRollout::random_walk() {
......@@ -288,6 +446,11 @@ void DFSRollout::random_walk() {
// print_step();
}
if(get_tardiness() < best_tardiness) {
best_sequence = sequence;
best_tardiness = get_tardiness();
}
}
void DFSRollout::greedy_best() {
......@@ -310,6 +473,11 @@ void DFSRollout::greedy_best() {
// print_step();
}
if(get_tardiness() < best_tardiness) {
best_sequence = sequence;
best_tardiness = get_tardiness();
}
}
void DFSRollout::greedy_stochastic() {
......@@ -339,18 +507,20 @@ void DFSRollout::greedy_stochastic() {
}
void DFSRollout::do_op(const int op) {
if(sequence.size() == 0) {
maximum_tardiness.push_back(0);
start[op] = 0;
distance[op] = 0;
} else {
maximum_tardiness.push_back(std::max(0,compute_distance(op)));
}
// auto i{sequence.size()};
// domain[i].clear();
// domain[i].push_back(op);
// action[i] = domain[i].begin();
// if(sequence.size() == 0) {
// maximum_positive_tardiness.push_back(0);
// start[op] = 0;
// distance[op] = 0;
// } else {
compute_distance(op);
maximum_tardiness.push_back(tardiness[op]);
maximum_positive_tardiness.push_back(std::max(0,tardiness[op]));
// }
//
// // auto i{sequence.size()};
// // domain[i].clear();
// // domain[i].push_back(op);
// // action[i] = domain[i].begin();
commit(op);
}
......@@ -368,12 +538,29 @@ void DFSRollout::commit(const int op) {
auto c{data.component(op)};
// #ifdef STATS
// travel_time[c].push_back(distance[op]);
auto t{(op%4)};
avg_travel_time[t][c] += (static_cast<double>(distance[op]) - avg_travel_time[t][c])/(++num_att[t][c]);
if(data.is_delivery(op)) {
auto train_time{start[op] - start[prev_operation[c]] - data.duration(prev_operation[c])};
assert(train_time >= 0);
avg_train_time[t/2][c] += (static_cast<double>(train_time) - avg_train_time[t/2][c])/num_att[t][c];
}
// #endif
prev_operation[c] = op;
if(++num_operation[c] == 4) {
num_operation[c] = 0;
++period[c];
}
#ifdef DEBUG
verify("after commit");
#endif
......@@ -389,6 +576,7 @@ void DFSRollout::undo() {
int op{sequence.back()};
sequence.pop_back();
maximum_positive_tardiness.pop_back();
maximum_tardiness.pop_back();
auto dist = 0;
......@@ -411,6 +599,10 @@ void DFSRollout::undo() {
--period[c];
}
// #ifdef STATS
// travel_time[c].pop_back();
// #endif
#ifdef DEBUG
verify("after undo");
#endif
......@@ -421,16 +613,24 @@ void DFSRollout::undo() {
void DFSRollout::search(const int ub) {
const auto start_level{sequence.size()};
start_train_length = train_length;
start_tour_length = tour_length;
start_period = period;
start_prev_operation = prev_operation;
start_num_operation = num_operation;
best_tardiness=ub;
best_sequence.clear();
int iter{0};
int restart_limit{restart_base};
int restart_size{restart_base};
while(true) {
++iter;
// branch
while(sequence.size() < data.nb_tasks) {
......@@ -445,6 +645,7 @@ void DFSRollout::search(const int ub) {
if(verbose)
cout << "d depth=" << best_depth() << " iter=" << iter << endl;
}
maximum_positive_tardiness.pop_back();
maximum_tardiness.pop_back();
break;
}
......@@ -476,6 +677,8 @@ void DFSRollout::search(const int ub) {
// branch left
action[i] = domain[i].begin();
commit(*action[i]);
// print_step();
}
// the branch is full
......@@ -487,6 +690,8 @@ void DFSRollout::search(const int ub) {
if(verified)
verify("solution");
// print_sol();
if(best_tardiness == 0) {
if(verbose)
cout << "o solution found\n";
......@@ -494,6 +699,17 @@ void DFSRollout::search(const int ub) {
}
}
if(restart_base and iter >= restart_limit) {
restart_size *= restart_factor;
restart_limit += restart_size;
if(verbose)
cout << "o restart\n";
clear(start_level);
continue;
}
// backtrack
while(sequence.size() >= start_level) {
// undo until the lower bound is lower than the upper bound
......@@ -508,7 +724,9 @@ void DFSRollout::search(const int ub) {
// if there is an action that we haven't tried yet, try it, otherwise backtrack again
if(action[i] != domain[i].end()) {
maximum_tardiness.push_back(std::max(get_tardiness(), compute_distance(*action[i])));
compute_distance(*action[i]);
maximum_tardiness.push_back(std::max(maximum_tardiness.back(), tardiness[*action[i]]));
maximum_positive_tardiness.push_back(std::max(0, maximum_tardiness.back()));
commit(*action[i]);
break;
}
......@@ -524,8 +742,7 @@ void DFSRollout::search(const int ub) {
} else if(iter >= max_iter) {
if(verbose)
cout << "o time out\n";
} else
continue;
} else continue;
break;
}
......
......@@ -4,6 +4,7 @@
// #define DEBUG
// #define STATS
#include <random>
......@@ -31,9 +32,10 @@ public:
void do_op(const int op);
void undo();
void clear();
void clear(const int lvl=0);
void print_step() const;
void print_sol() const;
// the total tour_length of the
int tour_length{0};
......@@ -43,22 +45,50 @@ public:
vector<int> best_sequence;
int best_tardiness;
int best_tardiness{numeric_limits<int>::max()};
int best_depth() { return best_sequence.size(); }
// params
double temperature{0.0005};
double sigmoid_slope{0.001};
bool verbose{true};
bool verified{true};
bool randomized{true};
int restart_base{0};
double restart_factor{1.2};
int max_iter{numeric_limits<int>::max()};
vector<double> avg_travel_time[4];
vector<double> avg_train_time[2];
vector<int> num_att[4];
double get_avg_travel_time(const int op) const;
double get_avg_train_time(const int op) const;
int get_cur_train_time(const int op) const;
double fast_sigmoid(const int t, const double slope=.01) const {
// return .5 * (slope * t / (1 + abs(slope * t))) + .5;
return slope * t / (1 + abs(slope * t));
}
private:
Instance& data;
int start_tour_length{0};
int start_train_length{0};
//
vector<int> maximum_tardiness;
vector<int> maximum_positive_tardiness;
int min_action_tardiness;
int max_action_tardiness;
// the actual sequence of operations
vector<int> sequence;
......@@ -68,12 +98,15 @@ private:
// the current period, for every component
vector<int> period;
vector<int> start_period;
// the latest operation, for every component
vector<int> prev_operation;
vector<int> start_prev_operation;
// the number of operations in the period, for every component
vector<int> num_operation;
vector<int> start_num_operation;
// for every operation, its start time if scheduled, or a lower bound on it if it is a possible actions choice
......@@ -82,6 +115,9 @@ private:
// used to store the distance of the actions
vector<int> distance;
// used to store the tardiness of the actions
vector<int> tardiness;
// used to store the probabilities of the actions
vector<long int> proba;
vector<double> fitnesses;
......@@ -97,11 +133,18 @@ private:
std::mt19937 random_generator;
int get_tardiness() const {
return maximum_tardiness.back();
assert(maximum_positive_tardiness.size() > 0);
return maximum_positive_tardiness.back();
}
// int get_tardiness() const {