skeleton of early tardy jobshop
This commit is contained in:
190
examples/cpp/jobshop_earlytardy.cc
Normal file
190
examples/cpp/jobshop_earlytardy.cc
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright 2010-2012 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// This model implements a simple jobshop problem.
|
||||
//
|
||||
// A jobshop is a standard scheduling problem where you must schedule a
|
||||
// set of jobs on a set of machines. Each job is a sequence of tasks
|
||||
// (a task can only start when the preceding task finished), each of
|
||||
// which occupies a single specific machine during a specific
|
||||
// duration. Therefore, a job is simply given by a sequence of pairs
|
||||
// (machine id, duration).
|
||||
|
||||
// The objective is to minimize the 'makespan', which is the duration
|
||||
// between the start of the first task (across all machines) and the
|
||||
// completion of the last task (across all machines).
|
||||
//
|
||||
// This will be modelled by sets of intervals variables (see class
|
||||
// IntervalVar in constraint_solver/constraint_solver.h), one per
|
||||
// task, representing the [start_time, end_time] of the task. Tasks
|
||||
// in the same job will be linked by precedence constraints. Tasks on
|
||||
// the same machine will be covered by Sequence constraints.
|
||||
//
|
||||
// Search will then be applied on the sequence constraints.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "cpp/jobshop_earlytardy.h"
|
||||
|
||||
DEFINE_string(
|
||||
data_file,
|
||||
"",
|
||||
"Required: input file description the scheduling problem to solve, "
|
||||
"in our jssp format:\n"
|
||||
" - the first line is \"instance <instance name>\"\n"
|
||||
" - the second line is \"<number of jobs> <number of machines>\"\n"
|
||||
" - then one line per job, with a single space-separated "
|
||||
"list of \"<machine index> <duration>\"\n"
|
||||
"note: jobs with one task are not supported");
|
||||
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms, 0 means no limit.");
|
||||
|
||||
namespace operations_research {
|
||||
void EtJobShop(const EtJobShopData& data) {
|
||||
Solver solver("et_jobshop");
|
||||
const int machine_count = data.machine_count();
|
||||
const int job_count = data.job_count();
|
||||
const int horizon = data.horizon();
|
||||
|
||||
// ----- Creates all Intervals and vars -----
|
||||
|
||||
// Stores all tasks attached interval variables per job.
|
||||
std::vector<std::vector<IntervalVar*> > jobs_to_tasks(job_count);
|
||||
// machines_to_tasks stores the same interval variables as above, but
|
||||
// grouped my machines instead of grouped by jobs.
|
||||
std::vector<std::vector<IntervalVar*> > machines_to_tasks(machine_count);
|
||||
|
||||
// Creates all individual interval variables.
|
||||
for (int job_id = 0; job_id < job_count; ++job_id) {
|
||||
const Job& job = data.GetJob(job_id);
|
||||
const std::vector<Task>& tasks = job.all_tasks;
|
||||
for (int task_index = 0; task_index < tasks.size(); ++task_index) {
|
||||
const Task& task = tasks[task_index];
|
||||
CHECK_EQ(job_id, task.job_id);
|
||||
const string name = StringPrintf("J%dM%dI%dD%d",
|
||||
task.job_id,
|
||||
task.machine_id,
|
||||
task_index,
|
||||
task.duration);
|
||||
IntervalVar* const one_task =
|
||||
solver.MakeFixedDurationIntervalVar(0,
|
||||
horizon,
|
||||
task.duration,
|
||||
false,
|
||||
name);
|
||||
jobs_to_tasks[task.job_id].push_back(one_task);
|
||||
machines_to_tasks[task.machine_id].push_back(one_task);
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Creates model -----
|
||||
|
||||
// Creates precedences inside jobs.
|
||||
for (int job_id = 0; job_id < job_count; ++job_id) {
|
||||
const int task_count = jobs_to_tasks[job_id].size();
|
||||
for (int task_index = 0; task_index < task_count - 1; ++task_index) {
|
||||
IntervalVar* const t1 = jobs_to_tasks[job_id][task_index];
|
||||
IntervalVar* const t2 = jobs_to_tasks[job_id][task_index + 1];
|
||||
Constraint* const prec =
|
||||
solver.MakeIntervalVarRelation(t2, Solver::STARTS_AFTER_END, t1);
|
||||
solver.AddConstraint(prec);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds disjunctive constraints on unary resources.
|
||||
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
|
||||
solver.AddConstraint(
|
||||
solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
|
||||
}
|
||||
|
||||
// Creates sequences variables on machines. A sequence variable is a
|
||||
// dedicated variable whose job is to sequence interval variables.
|
||||
std::vector<SequenceVar*> all_sequences;
|
||||
for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
|
||||
const string name = StringPrintf("Machine_%d", machine_id);
|
||||
SequenceVar* const sequence =
|
||||
solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
|
||||
all_sequences.push_back(sequence);
|
||||
}
|
||||
|
||||
// Creates array of end_times of jobs.
|
||||
std::vector<IntVar*> all_ends;
|
||||
for (int job_id = 0; job_id < job_count; ++job_id) {
|
||||
const int task_count = jobs_to_tasks[job_id].size();
|
||||
IntervalVar* const task = jobs_to_tasks[job_id][task_count - 1];
|
||||
all_ends.push_back(task->EndExpr()->Var());
|
||||
}
|
||||
|
||||
// Objective: minimize the makespan (maximum end times of all tasks)
|
||||
// of the problem.
|
||||
IntVar* const objective_var = solver.MakeMax(all_ends)->Var();
|
||||
OptimizeVar* const objective_monitor = solver.MakeMinimize(objective_var, 1);
|
||||
|
||||
// ----- Search monitors and decision builder -----
|
||||
|
||||
// This decision builder will rank all tasks on all machines.
|
||||
DecisionBuilder* const sequence_phase =
|
||||
solver.MakePhase(all_sequences, Solver::SEQUENCE_DEFAULT);
|
||||
|
||||
// After the ranking of tasks, the schedule is still loose and any
|
||||
// task can be postponed at will. But, because the problem is now a PERT
|
||||
// (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique),
|
||||
// we can schedule each task at its earliest start time. This is
|
||||
// conveniently done by fixing the objective variable to its
|
||||
// minimum value.
|
||||
DecisionBuilder* const obj_phase =
|
||||
solver.MakePhase(objective_var,
|
||||
Solver::CHOOSE_FIRST_UNBOUND,
|
||||
Solver::ASSIGN_MIN_VALUE);
|
||||
|
||||
// The main decision builder (ranks all tasks, then fixes the
|
||||
// objective_variable).
|
||||
DecisionBuilder* const main_phase =
|
||||
solver.Compose(sequence_phase, obj_phase);
|
||||
|
||||
// Search log.
|
||||
const int kLogFrequency = 1000000;
|
||||
SearchMonitor* const search_log =
|
||||
solver.MakeSearchLog(kLogFrequency, objective_monitor);
|
||||
|
||||
SearchLimit* limit = NULL;
|
||||
if (FLAGS_time_limit_in_ms > 0) {
|
||||
limit = solver.MakeTimeLimit(FLAGS_time_limit_in_ms);
|
||||
}
|
||||
|
||||
// Search.
|
||||
solver.Solve(main_phase, search_log, objective_monitor, limit);
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
static const char kUsage[] =
|
||||
"Usage: see flags.\nThis program runs a simple job shop optimization "
|
||||
"output besides the debug LOGs of the solver.";
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::SetUsageMessage(kUsage);
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
if (FLAGS_data_file.empty()) {
|
||||
LOG(FATAL) << "Please supply a data file with --data_file=";
|
||||
}
|
||||
operations_research::EtJobShopData data;
|
||||
data.Load(FLAGS_data_file);
|
||||
operations_research::EtJobShop(data);
|
||||
return 0;
|
||||
}
|
||||
111
examples/cpp/jobshop_earlytardy.h
Normal file
111
examples/cpp/jobshop_earlytardy.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2010-2012 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// This model implements a simple jobshop problem.
|
||||
//
|
||||
// A jobshop is a standard scheduling problem where you must schedule
|
||||
// a set of jobs on a set of machines. Each job is a sequence of
|
||||
// tasks (a task can only start when the preceding task finished),
|
||||
// each of which occupies a single specific machine during a specific
|
||||
// duration. Therefore, a job is a sequence of pairs (machine id,
|
||||
// duration), along with a release data (minimum start date of the
|
||||
// first task of the job, and due data (end time of the last job) with
|
||||
// a tardiness linear penalty.
|
||||
|
||||
// The objective is to minimize the 'makespan', which is the duration
|
||||
// between the start of the first task (across all machines) and the
|
||||
// completion of the last task (across all machines).
|
||||
//
|
||||
// This will be modelled by sets of intervals variables (see class
|
||||
// IntervalVar in constraint_solver/constraint_solver.h), one per
|
||||
// task, representing the [start_time, end_time] of the task. Tasks
|
||||
// in the same job will be linked by precedence constraints. Tasks on
|
||||
// the same machine will be covered by Sequence constraints.
|
||||
|
||||
#ifndef OR_TOOLS_EXAMPLES_JOBSHOP_EARLYTARDY_H_
|
||||
#define OR_TOOLS_EXAMPLES_JOBSHOP_EARLYTARDY_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/integral_types.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/strtoint.h"
|
||||
#include "base/file.h"
|
||||
#include "base/filelinereader.h"
|
||||
#include "base/split.h"
|
||||
|
||||
namespace operations_research {
|
||||
struct Task {
|
||||
Task(int j, int m, int d) : job_id(j), machine_id(m), duration(d) {}
|
||||
int job_id;
|
||||
int machine_id;
|
||||
int duration;
|
||||
};
|
||||
|
||||
struct Job {
|
||||
Job(int r, int d, int ew, int tw)
|
||||
: release_date(r),
|
||||
due_date(d),
|
||||
earlyness_weight(ew),
|
||||
tardiness_weight(tw) {}
|
||||
int release_date;
|
||||
int due_date;
|
||||
int earlyness_weight;
|
||||
int tardiness_weight;
|
||||
std::vector<Task> all_tasks;
|
||||
};
|
||||
|
||||
class EtJobShopData {
|
||||
public:
|
||||
EtJobShopData()
|
||||
: machine_count_(0),
|
||||
job_count_(0),
|
||||
horizon_(0) {}
|
||||
|
||||
~EtJobShopData() {}
|
||||
|
||||
void Load(const string& filename) {
|
||||
|
||||
}
|
||||
// The number of machines in the jobshop.
|
||||
int machine_count() const { return machine_count_; }
|
||||
|
||||
// The number of jobs in the jobshop.
|
||||
int job_count() const { return job_count_; }
|
||||
|
||||
// The name of the jobshop instance.
|
||||
const string& name() const { return name_; }
|
||||
|
||||
// The horizon of the workshop (the sum of all durations), which is
|
||||
// a trivial upper bound of the optimal make_span.
|
||||
int horizon() const { return horizon_; }
|
||||
|
||||
// Returns the tasks of a job, ordered by precedence.
|
||||
const Job& GetJob(int job_id) const {
|
||||
return all_jobs_[job_id];
|
||||
}
|
||||
|
||||
private:
|
||||
string name_;
|
||||
int machine_count_;
|
||||
int job_count_;
|
||||
int horizon_;
|
||||
std::vector<Job> all_jobs_;
|
||||
};
|
||||
} // namespace operations_research
|
||||
#endif OR_TOOLS_EXAMPLES_JOBSHOP_EARLYTARDY_H_
|
||||
|
||||
@@ -672,6 +672,12 @@ $(OBJ_DIR)/jobshop_ls.$O:$(EX_DIR)/cpp/jobshop_ls.cc $(SRC_DIR)/constraint_solve
|
||||
$(BIN_DIR)/jobshop_ls$E: $(CP_DEPS) $(OBJ_DIR)/jobshop_ls.$O
|
||||
$(CCC) $(CFLAGS) $(OBJ_DIR)/jobshop_ls.$O $(CP_LNK) $(LDFLAGS) $(EXEOUT)jobshop_ls$E
|
||||
|
||||
$(OBJ_DIR)/jobshop_earlytardy.$O:$(EX_DIR)/cpp/jobshop_earlytardy.cc $(SRC_DIR)/constraint_solver/constraint_solver.h $(EX_DIR)/cpp/jobshop_earlytardy.h
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/jobshop_earlytardy.cc $(OBJ_OUT)jobshop_earlytardy.$O
|
||||
|
||||
$(BIN_DIR)/jobshop_earlytardy$E: $(CP_DEPS) $(OBJ_DIR)/jobshop_earlytardy.$O
|
||||
$(CCC) $(CFLAGS) $(OBJ_DIR)/jobshop_earlytardy.$O $(CP_LNK) $(LDFLAGS) $(EXEOUT)jobshop_earlytardy$E
|
||||
|
||||
$(OBJ_DIR)/magic_square.$O:$(EX_DIR)/cpp/magic_square.cc $(SRC_DIR)/constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c $(EX_DIR)$Scpp/magic_square.cc $(OBJ_OUT)magic_square.$O
|
||||
|
||||
|
||||
Reference in New Issue
Block a user