00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <cstdio>
00036 #include <cstdlib>
00037
00038 #include "base/commandlineflags.h"
00039 #include "base/commandlineflags.h"
00040 #include "base/integral_types.h"
00041 #include "base/logging.h"
00042 #include "base/stringprintf.h"
00043 #include "constraint_solver/constraint_solver.h"
00044 #include "cpp/jobshop.h"
00045
00046 DEFINE_string(
00047 data_file,
00048 "",
00049 "Required: input file description the scheduling problem to solve, "
00050 "in our jssp format:\n"
00051 " - the first line is \"instance <instance name>\"\n"
00052 " - the second line is \"<number of jobs> <number of machines>\"\n"
00053 " - then one line per job, with a single space-separated "
00054 "list of \"<machine index> <duration>\"\n"
00055 "note: jobs with one task are not supported");
00056 DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms, 0 means no limit.");
00057
00058 namespace operations_research {
00059 void Jobshop(const JobShopData& data) {
00060 Solver solver("jobshop");
00061 const int machine_count = data.machine_count();
00062 const int job_count = data.job_count();
00063 const int horizon = data.horizon();
00064
00065
00066
00067
00068 std::vector<std::vector<IntervalVar*> > jobs_to_tasks(job_count);
00069
00070
00071 std::vector<std::vector<IntervalVar*> > machines_to_tasks(machine_count);
00072
00073
00074 for (int job_id = 0; job_id < job_count; ++job_id) {
00075 const std::vector<JobShopData::Task>& tasks = data.TasksOfJob(job_id);
00076 for (int task_index = 0; task_index < tasks.size(); ++task_index) {
00077 const JobShopData::Task& task = tasks[task_index];
00078 CHECK_EQ(job_id, task.job_id);
00079 const string name = StringPrintf("J%dM%dI%dD%d",
00080 task.job_id,
00081 task.machine_id,
00082 task_index,
00083 task.duration);
00084 IntervalVar* const one_task =
00085 solver.MakeFixedDurationIntervalVar(0,
00086 horizon,
00087 task.duration,
00088 false,
00089 name);
00090 jobs_to_tasks[task.job_id].push_back(one_task);
00091 machines_to_tasks[task.machine_id].push_back(one_task);
00092 }
00093 }
00094
00095
00096
00097
00098 for (int job_id = 0; job_id < job_count; ++job_id) {
00099 const int task_count = jobs_to_tasks[job_id].size();
00100 for (int task_index = 0; task_index < task_count - 1; ++task_index) {
00101 IntervalVar* const t1 = jobs_to_tasks[job_id][task_index];
00102 IntervalVar* const t2 = jobs_to_tasks[job_id][task_index + 1];
00103 Constraint* const prec =
00104 solver.MakeIntervalVarRelation(t2, Solver::STARTS_AFTER_END, t1);
00105 solver.AddConstraint(prec);
00106 }
00107 }
00108
00109
00110 for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
00111 solver.AddConstraint(
00112 solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
00113 }
00114
00115
00116
00117 std::vector<SequenceVar*> all_sequences;
00118 for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
00119 const string name = StringPrintf("Machine_%d", machine_id);
00120 SequenceVar* const sequence =
00121 solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
00122 all_sequences.push_back(sequence);
00123 }
00124
00125
00126 std::vector<IntVar*> all_ends;
00127 for (int job_id = 0; job_id < job_count; ++job_id) {
00128 const int task_count = jobs_to_tasks[job_id].size();
00129 IntervalVar* const task = jobs_to_tasks[job_id][task_count - 1];
00130 all_ends.push_back(task->EndExpr()->Var());
00131 }
00132
00133
00134
00135 IntVar* const objective_var = solver.MakeMax(all_ends)->Var();
00136 OptimizeVar* const objective_monitor = solver.MakeMinimize(objective_var, 1);
00137
00138
00139
00140
00141 DecisionBuilder* const sequence_phase =
00142 solver.MakePhase(all_sequences, Solver::SEQUENCE_DEFAULT);
00143
00144
00145
00146
00147
00148
00149
00150 DecisionBuilder* const obj_phase =
00151 solver.MakePhase(objective_var,
00152 Solver::CHOOSE_FIRST_UNBOUND,
00153 Solver::ASSIGN_MIN_VALUE);
00154
00155
00156
00157 DecisionBuilder* const main_phase =
00158 solver.Compose(sequence_phase, obj_phase);
00159
00160
00161 const int kLogFrequency = 1000000;
00162 SearchMonitor* const search_log =
00163 solver.MakeSearchLog(kLogFrequency, objective_monitor);
00164
00165 SearchLimit* limit = NULL;
00166 if (FLAGS_time_limit_in_ms > 0) {
00167 limit = solver.MakeTimeLimit(FLAGS_time_limit_in_ms);
00168 }
00169
00170
00171 solver.Solve(main_phase, search_log, objective_monitor, limit);
00172 }
00173 }
00174
00175 static const char kUsage[] =
00176 "Usage: see flags.\nThis program runs a simple job shop optimization "
00177 "output besides the debug LOGs of the solver.";
00178
00179 int main(int argc, char **argv) {
00180 google::SetUsageMessage(kUsage);
00181 google::ParseCommandLineFlags(&argc, &argv, true);
00182 if (FLAGS_data_file.empty()) {
00183 LOG(FATAL) << "Please supply a data file with --data_file=";
00184 }
00185 operations_research::JobShopData data;
00186 data.Load(FLAGS_data_file);
00187 operations_research::Jobshop(data);
00188 return 0;
00189 }