~spidernet/PermutationFlowShopScheduling

f78dba8070caeeefe16cc4ef4345712462dfa3db — Gabriele Venturato 1 year, 9 months ago 1751de3
[LocalSearch] Finished and tested
M LocalSearch/include/FP_Basics.hh => LocalSearch/include/FP_Basics.hh +2 -1
@@ 14,9 14,10 @@ class FP_State {
  size_t operator[](unsigned i) const { return schedule[i]; }
  size_t& operator[](unsigned i) { return schedule[i]; }
  /*void reset();*/
  void ComputeTimes(size_t job = 0);
  void ComputeTimes(size_t job_index = 0);
  size_t getEndTime(size_t j, size_t m) const { return end_times[j][m]; }
  size_t getSchedule(size_t j) const {return schedule[j]; }
  size_t getScheduleIndex(size_t job) const;

 protected:
  const FP_Input& in;

M LocalSearch/src/FP_Basics.cc => LocalSearch/src/FP_Basics.cc +10 -2
@@ 13,6 13,8 @@ FP_State::FP_State(const FP_Input& my_in) : in(my_in) {

FP_State& FP_State::operator=(const FP_State& st) {
  schedule = st.schedule;
  start_times = st.start_times;
  end_times = st.end_times;
  return *this;
}



@@ 31,10 33,10 @@ ostream& operator<<(ostream& os, const FP_State& st) {
  return os;
}

void FP_State::ComputeTimes(size_t job) {
void FP_State::ComputeTimes(size_t job_index) {
  size_t j;
  for (size_t m = 0; m < in.getMachines(); ++m) {
    for (size_t i = job; i < in.getJobs(); ++i) {
    for (size_t i = job_index; i < in.getJobs(); ++i) {
      j = schedule[i];
      if (m == 0 && i == 0) {
        start_times[j][m] = max<size_t>(0, in.getReleaseDate(schedule[0]));


@@ 50,6 52,12 @@ void FP_State::ComputeTimes(size_t job) {
  }
}

size_t FP_State::getScheduleIndex(size_t job) const {
  long d = distance(schedule.begin(), find(schedule.begin(), schedule.end(), job));
  if (d >= 0) return static_cast<size_t >(d);
  else throw logic_error("Negative vector index");
}

SwapJobs::SwapJobs(size_t i, size_t j) {
  p1 = i;
  p2 = j;

M LocalSearch/src/FP_Data.cc => LocalSearch/src/FP_Data.cc +3 -1
@@ 136,8 136,10 @@ ostream& operator<<(ostream& os, const FP_Output& out) {
}

istream& operator>>(istream& is, FP_Output& out) {
  char c;
  is >> c;
  for (size_t i = 0; i < out.in.getJobs(); ++i) {
    is >> out.schedule[i];
    is >> out.schedule[i] >> c;
  }
  return is;
}
\ No newline at end of file

M LocalSearch/src/FP_Helpers.cc => LocalSearch/src/FP_Helpers.cc +44 -49
@@ 43,7 43,7 @@ int Makespan::ComputeCost(const FP_State& st) const {
}

void Makespan::PrintViolations(const FP_State& st, ostream& os) const {
  os << "Makespan is " << ComputeCost(st);
  os << "Makespan is " << ComputeCost(st) << endl;
}

int Tardiness::ComputeCost(const FP_State& st) const {


@@ 67,7 67,7 @@ void Tardiness::PrintViolations(const FP_State& st, ostream& os) const {
    if (in.getDueDates(j) != -1) {
      if (static_cast<size_t>(in.getDueDates(j)) < st.getEndTime(j, in.getMachines()-1)) {
        os << "Tardiness of job " << j << " is " << (st.getEndTime(j, in.getMachines()-1) - in.getDueDates(j)) *
          in.getWeight(j);
          in.getWeight(j) << endl;
      }
    }
  }


@@ 79,25 79,6 @@ void Tardiness::PrintViolations(const FP_State& st, ostream& os) const {

// initial move builder
void SwapJobsNeighborhoodExplorer::RandomMove(const FP_State& st, SwapJobs& mv) const {
  /*mv.p1 = Random::Uniform<size_t>(0, in.getJobs() - 1);
  size_t a[2], c;

  a[0] = Random::Uniform<size_t>(0, mv.p1 - 1);
  a[1] = Random::Uniform<size_t>(mv.p1 + 1, in.getJobs() - 1);

  if (mv.p1 == 0) {
    c = 1;
  } else if (mv.p2 == in.getJobs()-1) {
    c = 0;
  } else {
    c = Random::Uniform<size_t>(0, 1);
  }

  mv.p2 = a[c];

  // keep always p1 < p2
  if (mv.p1 > mv.p2) swap(mv.p1, mv.p2);*/

  mv.p1 = Random::Uniform<size_t>(0, in.getJobs() - 1);
  mv.p2 = Random::Uniform<size_t>(0, in.getJobs() - 2);
  if (mv.p2 >= mv.p1)


@@ 113,12 94,10 @@ bool SwapJobsNeighborhoodExplorer::FeasibleMove(const FP_State& st, const SwapJo

// update the state according to the move
void SwapJobsNeighborhoodExplorer::MakeMove(FP_State& st, const SwapJobs& mv) const {
  if (mv.p1 < mv.p2) {
    swap(st[mv.p1], st[mv.p2]);
    st.ComputeTimes(mv.p1);
  } else {
    cerr << "ASS" << endl;
  }
  size_t idp1 = st.getScheduleIndex(mv.p1);
  size_t idp2 = st.getScheduleIndex(mv.p2);
  swap(st[idp1], st[idp2]);
  st.ComputeTimes( min<size_t>(idp1, idp2) );
}

void SwapJobsNeighborhoodExplorer::FirstMove(const FP_State& st, SwapJobs& mv) const {


@@ 142,53 121,69 @@ bool SwapJobsNeighborhoodExplorer::NextMove(const FP_State& st, SwapJobs& mv) co
int SwapJobsDeltaMakespan::ComputeDeltaCost(const FP_State& st, const SwapJobs& mv) const {
  int future_makespan = 0;
  int current_makespan = static_cast<int>(st.getEndTime(st.getSchedule( in.getJobs()-1 ), in.getMachines()-1));
  size_t idp1 = st.getScheduleIndex(mv.p1);
  size_t idp2 = st.getScheduleIndex(mv.p2);
  size_t sidx = min<size_t>(idp1,idp2);
  vector<size_t> new_schedule;
  for (size_t j = 0; j < in.getJobs(); ++j) {
    new_schedule.push_back(st.getSchedule(j));
  }
  swap(new_schedule[idp1],new_schedule[idp2]);

  // retrieve starting time from current state
  size_t start_time;
  if (mv.p1 == 0) {
  if (sidx == 0) {
    // if swapping job 0, start time is 0 (take care of release date later)
    start_time = 0;
  } else {
    start_time = st.getEndTime(st.getSchedule(mv.p1-1), 0);
    start_time = st.getEndTime(st.getSchedule(sidx-1), 0);
  }

  vector<vector<size_t>> s_times, e_times;
  s_times.resize(in.getJobs(), vector<size_t>(in.getMachines()));
  e_times.resize(in.getJobs(), vector<size_t>(in.getMachines()));

  if (mv.p1) {
  if (sidx) {
    for (size_t m = 0; m < in.getMachines(); ++m) {
      e_times[mv.p1-1][m] = st.getEndTime(mv.p1-1,m);
      e_times[st.getSchedule(sidx-1)][m] = st.getEndTime(st.getSchedule(sidx-1),m);
    }
  }

  size_t j;
  for (size_t m = 0; m < in.getMachines(); ++m) {
    for (size_t i = mv.p1; i < in.getJobs(); ++i) {
      j = st.getSchedule(i);
    for (size_t i = sidx; i < in.getJobs(); ++i) {
      j = new_schedule[i];
      if (m == 0 && i == 0) {
        s_times[j][m] = max<size_t>(start_time, in.getReleaseDate(st.getSchedule(0)));
        s_times[j][m] = max<size_t>(start_time, in.getReleaseDate(new_schedule[0]));
      } else if (m == 0) {
        s_times[j][m] = max<size_t>(e_times[st.getSchedule(i-1)][m], in.getReleaseDate(j));
        s_times[j][m] = max<size_t>(e_times[new_schedule[i-1]][m], in.getReleaseDate(j));
      } else if (i == 0) {
        s_times[j][m] = e_times[j][m-1];
      } else {
        s_times[j][m] = max<size_t>(e_times[st.getSchedule(i-1)][m], e_times[j][m-1]);
        s_times[j][m] = max<size_t>(e_times[new_schedule[i-1]][m], e_times[j][m-1]);
      }
      e_times[j][m] = s_times[j][m] + in.getDuration(j,m);
    }
  }

  future_makespan = static_cast<int>(e_times[st.getSchedule( in.getJobs()-1 )][in.getMachines()-1]);
  future_makespan = static_cast<int>(e_times[new_schedule[in.getJobs()-1]][in.getMachines()-1]);

  return future_makespan - current_makespan;
}

int SwapJobsDeltaTardiness::ComputeDeltaCost(const FP_State& st, const SwapJobs& mv) const {
  int partial_future_tardiness = 0, partial_current_tardiness = 0;
  size_t idp1 = st.getScheduleIndex(mv.p1);
  size_t idp2 = st.getScheduleIndex(mv.p2);
  size_t sidx = min<size_t>(idp1,idp2);
  vector<size_t> new_schedule;
  for (size_t j = 0; j < in.getJobs(); ++j) {
    new_schedule.push_back(st.getSchedule(j));
  }
  swap(new_schedule[idp1],new_schedule[idp2]);

  size_t j;
  for (size_t i = mv.p1; i < in.getJobs(); ++i) {
  for (size_t i = sidx; i < in.getJobs(); ++i) {
    j = st.getSchedule(i);
    if (in.getDueDates(j) != -1) {
      if (static_cast<size_t>(in.getDueDates(j)) < st.getEndTime(j, in.getMachines()-1)) {


@@ 199,41 194,41 @@ int SwapJobsDeltaTardiness::ComputeDeltaCost(const FP_State& st, const SwapJobs&

  // retrieve starting time from current state
  size_t start_time;
  if (mv.p1 == 0) {
  if (sidx == 0) {
    // if swapping job 0, start time is 0 (take care of release date later)
    start_time = 0;
  } else {
    start_time = st.getEndTime(st.getSchedule(mv.p1-1), 0);
    start_time = st.getEndTime(st.getSchedule(sidx-1), 0);
  }

  vector<vector<size_t>> s_times, e_times;
  s_times.resize(in.getJobs(), vector<size_t>(in.getMachines()));
  e_times.resize(in.getJobs(), vector<size_t>(in.getMachines()));

  if (mv.p1) {
  if (sidx) {
    for (size_t m = 0; m < in.getMachines(); ++m) {
      e_times[mv.p1-1][m] = st.getEndTime(mv.p1-1,m);
      e_times[st.getSchedule(sidx-1)][m] = st.getEndTime(st.getSchedule(sidx-1),m);
    }
  }

  for (size_t m = 0; m < in.getMachines(); ++m) {
    for (size_t i = mv.p1; i < in.getJobs(); ++i) {
      j = st.getSchedule(i);
    for (size_t i = sidx; i < in.getJobs(); ++i) {
      j = new_schedule[i];
      if (m == 0 && i == 0) {
        s_times[j][m] = max<size_t>(start_time, in.getReleaseDate(st.getSchedule(0)));
        s_times[j][m] = max<size_t>(start_time, in.getReleaseDate(new_schedule[0]));
      } else if (m == 0) {
        s_times[j][m] = max<size_t>(e_times[st.getSchedule(i-1)][m], in.getReleaseDate(j));
        s_times[j][m] = max<size_t>(e_times[new_schedule[i-1]][m], in.getReleaseDate(j));
      } else if (i == 0) {
        s_times[j][m] = e_times[j][m-1];
      } else {
        s_times[j][m] = max<size_t>(e_times[st.getSchedule(i-1)][m], e_times[j][m-1]);
        s_times[j][m] = max<size_t>(e_times[new_schedule[i-1]][m], e_times[j][m-1]);
      }
      e_times[j][m] = s_times[j][m] + in.getDuration(j,m);
    }
  }

  for (size_t i = mv.p1; i < in.getJobs(); ++i) {
    j = st.getSchedule(i);
  for (size_t i = sidx; i < in.getJobs(); ++i) {
    j = new_schedule[i];
    if (in.getDueDates(j) != -1) {
      if (static_cast<size_t>(in.getDueDates(j)) < e_times[j][in.getMachines()-1]) {
        partial_future_tardiness += (e_times[j][in.getMachines()-1] - in.getDueDates(j)) * in.getWeight(j);

M LocalSearch/src/FP_Main.cc => LocalSearch/src/FP_Main.cc +7 -6
@@ 58,7 58,7 @@ int main(int argc, const char* argv[]) {
  Tester<FP_Input, FP_Output, FP_State> tester(in, FP_sm, FP_om);
  MoveTester<FP_Input, FP_Output, FP_State, SwapJobs> swap_move_test(in, FP_sm, FP_om, FP_nhe, "SwapJobs move", tester);

  SimpleLocalSearch<FP_Input, FP_Output, FP_State> FP_solver(in, FP_sm, FP_om, "XYZ solver");
  SimpleLocalSearch<FP_Input, FP_Output, FP_State> FP_solver(in, FP_sm, FP_om, "FP solver");
  if (!CommandLineParameters::Parse(argc, argv, true, false)) return 1;

  if (!method.IsSet()) {  // If no search method is set -> enter in the tester


@@ 67,16 67,17 @@ int main(int argc, const char* argv[]) {
    else
      tester.RunMainMenu();
  } else {
    if (method == string("SA")) {
    if (method == string("SwapJobsSimulatedAnnealing")) {
      FP_solver.SetRunner(FP_sa);
    } else if (method == string("HC")) {
    } else if (method == string("SwapJobsHillClimbing")) {
      FP_solver.SetRunner(FP_hc);
    } else  // if (method.GetValue() == string("SD"))
    {
    } else if (method == string("SwapJobsSteepestDescent")) {
      FP_solver.SetRunner(FP_sd);
    } else {
      FP_solver.SetRunner(FP_ts);
    }
    auto result = FP_solver.Solve();
    // result is a tuple: 0: solutio, 1: number of violations, 2: total cost, 3: computing time
    // result is a tuple: 0: solution, 1: number of violations, 2: total cost, 3: computing time
    FP_Output out = result.output;
    if (output_file.IsSet()) {  // write the output on the file passed in the command line
      ofstream os(static_cast<string>(output_file).c_str());