42void JsspParser::SetJobs(
int job_count) {
43 CHECK_GT(job_count, 0);
44 declared_job_count_ = job_count;
45 problem_.clear_jobs();
46 for (
int i = 0; i < job_count; ++i) {
47 problem_.add_jobs()->set_name(absl::StrCat(
"J", i));
51void JsspParser::SetMachines(
int machine_count) {
52 CHECK_GT(machine_count, 0);
53 declared_machine_count_ = machine_count;
54 problem_.clear_machines();
55 for (
int i = 0; i < machine_count; ++i) {
56 problem_.add_machines()->set_name(absl::StrCat(
"M", i));
66 if (absl::EndsWith(filename,
"fjs")) {
68 }
else if (absl::EndsWith(filename,
".txt")) {
76 const std::string problem_name(
file::Stem(filename));
77 problem_.set_name(problem_name);
83 switch (problem_type_) {
85 ProcessJsspLine(
line);
89 ProcessTaillardLine(
line);
93 ProcessFlexibleLine(
line);
97 ProcessSdstLine(
line);
101 ProcessTardinessLine(
line);
105 ProcessPssLine(
line);
109 ProcessEarlyTardyLine(
line);
113 LOG(FATAL) <<
"Should not be here.";
121void JsspParser::ProcessJsspLine(
const std::string&
line) {
122 const std::vector<std::string> words =
123 absl::StrSplit(
line,
' ', absl::SkipEmpty());
124 switch (parser_state_) {
126 if (words.size() == 2 && words[0] ==
"instance") {
127 problem_.set_name(words[1]);
129 current_job_index_ = 0;
130 }
else if (words.size() == 1 && words[0] ==
"1") {
132 }
else if (words.size() == 2) {
133 SetJobs(strtoint32(words[0]));
134 SetMachines(strtoint32(words[1]));
141 if (words.size() == 2) {
142 SetJobs(strtoint32(words[0]));
143 SetMachines(strtoint32(words[1]));
144 problem_.set_makespan_cost_per_time_unit(1L);
150 CHECK_GE(words.size(), declared_machine_count_ * 2);
151 Job*
const job = problem_.mutable_jobs(current_job_index_);
152 for (
int i = 0;
i < declared_machine_count_; ++
i) {
153 const int machine_id = strtoint32(words[2 * i]);
154 const int64_t duration = strtoint64(words[2 * i + 1]);
155 Task*
const task = job->add_tasks();
156 task->add_machine(machine_id);
157 task->add_duration(duration);
159 if (words.size() == declared_machine_count_ * 2 + 3) {
161 const int due_date = strtoint32(words[declared_machine_count_ * 2]);
162 const int early_cost =
163 strtoint32(words[declared_machine_count_ * 2 + 1]);
164 const int late_cost =
165 strtoint32(words[declared_machine_count_ * 2 + 2]);
166 job->set_early_due_date(due_date);
167 job->set_late_due_date(due_date);
168 job->set_earliness_cost_per_time_unit(early_cost);
169 job->set_lateness_cost_per_time_unit(late_cost);
171 current_job_index_++;
172 if (current_job_index_ == declared_job_count_) {
173 parser_state_ =
DONE;
178 LOG(FATAL) <<
"Should not be here with state " << parser_state_;
183void JsspParser::ProcessTaillardLine(
const std::string&
line) {
184 const std::vector<std::string> words =
185 absl::StrSplit(
line,
' ', absl::SkipEmpty());
187 switch (parser_state_) {
189 if (words.size() == 2) {
190 problem_type_ =
SDST;
191 ProcessSdstLine(
line);
193 }
else if (words.size() == 3) {
195 ProcessTardinessLine(
line);
198 if (words.size() == 1 && strtoint32(words[0]) > 0) {
200 SetJobs(strtoint32(words[0]));
205 CHECK_EQ(1, words.size());
206 SetMachines(strtoint32(words[0]));
207 problem_.set_makespan_cost_per_time_unit(1L);
212 CHECK_EQ(1, words.size());
213 const int seed = strtoint32(words[0]);
214 problem_.set_seed(seed);
219 ABSL_FALLTHROUGH_INTENDED;
221 CHECK_EQ(1, words.size());
222 current_job_index_ = strtoint32(words[0]);
227 CHECK_EQ(1, words.size());
232 CHECK_EQ(declared_machine_count_, words.size());
233 Job*
const job = problem_.mutable_jobs(current_job_index_);
234 for (
int i = 0;
i < declared_machine_count_; ++
i) {
235 const int64_t duration = strtoint64(words[i]);
236 Task*
const task = job->add_tasks();
237 task->add_machine(i);
238 task->add_duration(duration);
241 current_job_index_ == declared_job_count_ - 1 ?
DONE :
JOB_READ;
245 LOG(FATAL) <<
"Should not be here with state " << parser_state_;
249void JsspParser::ProcessFlexibleLine(
const std::string&
line) {
250 const std::vector<std::string> words =
251 absl::StrSplit(
line,
' ', absl::SkipEmpty());
252 switch (parser_state_) {
254 CHECK_GE(words.size(), 2);
255 SetJobs(strtoint32(words[0]));
256 SetMachines(strtoint32(words[1]));
257 problem_.set_makespan_cost_per_time_unit(1L);
262 const int operations_count = strtoint32(words[0]);
264 Job*
const job = problem_.mutable_jobs(current_job_index_);
265 for (
int operation = 0; operation < operations_count; ++operation) {
266 const int alternatives_count = strtoint32(words[
index++]);
267 Task*
const task = job->add_tasks();
268 for (
int alt = 0; alt < alternatives_count; alt++) {
270 const int machine_id = strtoint32(words[
index++]) - 1;
271 const int64_t duration = strtoint64(words[
index++]);
272 task->add_machine(machine_id);
273 task->add_duration(duration);
276 CHECK_LE(
index, words.size());
277 current_job_index_++;
278 if (current_job_index_ == declared_job_count_) {
279 parser_state_ =
DONE;
284 LOG(FATAL) <<
"Should not be here with state " << parser_state_;
288void JsspParser::ProcessSdstLine(
const std::string&
line) {
289 const std::vector<std::string> words =
290 absl::StrSplit(
line,
' ', absl::SkipEmpty());
291 switch (parser_state_) {
293 if (words.size() == 2) {
294 SetJobs(strtoint32(words[0]));
295 SetMachines(strtoint32(words[1]));
296 problem_.set_makespan_cost_per_time_unit(1L);
298 current_machine_index_ = 0;
303 CHECK_EQ(words.size(), declared_machine_count_ * 2);
304 Job*
const job = problem_.mutable_jobs(current_job_index_);
305 for (
int i = 0;
i < declared_machine_count_; ++
i) {
306 const int machine_id = strtoint32(words[2 * i]);
307 const int64_t duration = strtoint64(words[2 * i + 1]);
308 Task*
const task = job->add_tasks();
309 task->add_machine(machine_id);
310 task->add_duration(duration);
312 current_job_index_++;
313 if (current_job_index_ == declared_job_count_) {
319 CHECK_EQ(1, words.size());
320 CHECK_EQ(
"SSD", words[0]);
325 CHECK_EQ(1, words.size());
326 CHECK_EQ(words[0], absl::StrCat(
"M", current_machine_index_)) <<
line;
327 current_job_index_ = 0;
332 CHECK_EQ(declared_job_count_, words.size());
333 Machine*
const machine =
334 problem_.mutable_machines(current_machine_index_);
335 for (
const std::string&
w : words) {
336 const int64_t t = strtoint64(
w);
337 machine->mutable_transition_time_matrix()->add_transition_time(t);
339 if (++current_job_index_ == declared_job_count_) {
340 parser_state_ = ++current_machine_index_ == declared_machine_count_
347 LOG(FATAL) <<
"Should not be here with state " << parser_state_
348 <<
"with line " <<
line;
353void JsspParser::ProcessTardinessLine(
const std::string&
line) {
354 const std::vector<std::string> words =
355 absl::StrSplit(
line,
' ', absl::SkipEmpty());
356 switch (parser_state_) {
358 CHECK_EQ(3, words.size());
359 SetJobs(strtoint32(words[0]));
360 SetMachines(strtoint32(words[1]));
362 current_job_index_ = 0;
366 CHECK_GE(words.size(), 6);
367 Job*
const job = problem_.mutable_jobs(current_job_index_);
368 const int64_t est = strtoint64(words[0]);
370 job->mutable_earliest_start()->set_value(est);
372 job->set_late_due_date(strtoint64(words[1]));
373 const double weight = std::stod(words[2]);
374 const int64_t tardiness =
static_cast<int64_t
>(
375 round(
weight * absl::GetFlag(FLAGS_jssp_scaling_up_factor)));
376 job->set_lateness_cost_per_time_unit(tardiness);
377 const int num_operations = strtoint32(words[3]);
378 for (
int i = 0;
i < num_operations; ++
i) {
379 const int machine_id = strtoint32(words[4 + 2 * i]) - 1;
380 const int64_t duration = strtoint64(words[5 + 2 * i]);
381 Task*
const task = job->add_tasks();
382 task->add_machine(machine_id);
383 task->add_duration(duration);
385 current_job_index_++;
386 if (current_job_index_ == declared_job_count_) {
388 bool all_integral =
true;
389 for (
const Job& job : problem_.jobs()) {
390 if (job.lateness_cost_per_time_unit() %
391 absl::GetFlag(FLAGS_jssp_scaling_up_factor) !=
393 all_integral =
false;
398 for (Job& job : *problem_.mutable_jobs()) {
399 job.set_lateness_cost_per_time_unit(
400 job.lateness_cost_per_time_unit() /
401 absl::GetFlag(FLAGS_jssp_scaling_up_factor));
404 problem_.mutable_scaling_factor()->set_value(
405 1.0L / absl::GetFlag(FLAGS_jssp_scaling_up_factor));
407 parser_state_ =
DONE;
412 LOG(FATAL) <<
"Should not be here with state " << parser_state_
413 <<
"with line " <<
line;
418void JsspParser::ProcessPssLine(
const std::string&
line) {
419 const std::vector<std::string> words =
420 absl::StrSplit(
line,
' ', absl::SkipEmpty());
421 switch (parser_state_) {
423 problem_.set_makespan_cost_per_time_unit(1L);
424 CHECK_EQ(1, words.size());
425 SetJobs(strtoint32(words[0]));
430 CHECK_EQ(1, words.size());
431 SetMachines(strtoint32(words[0]));
433 current_job_index_ = 0;
437 CHECK_EQ(1, words.size());
438 CHECK_EQ(declared_machine_count_, strtoint32(words[0]));
439 if (++current_job_index_ == declared_job_count_) {
441 current_job_index_ = 0;
442 current_machine_index_ = 0;
447 CHECK_EQ(4, words.size());
448 CHECK_EQ(0, strtoint32(words[2]));
449 CHECK_EQ(0, strtoint32(words[3]));
450 const int machine_id = strtoint32(words[0]) - 1;
451 const int duration = strtoint32(words[1]);
452 Job*
const job = problem_.mutable_jobs(current_job_index_);
453 Task*
const task = job->add_tasks();
454 task->add_machine(machine_id);
455 task->add_duration(duration);
456 if (++current_machine_index_ == declared_machine_count_) {
457 current_machine_index_ = 0;
458 if (++current_job_index_ == declared_job_count_) {
459 current_job_index_ = -1;
460 current_machine_index_ = 0;
462 transition_index_ = 0;
463 for (
int m = 0; m < declared_machine_count_; ++m) {
464 Machine*
const machine = problem_.mutable_machines(m);
465 for (
int i = 0;
i < declared_job_count_ * declared_job_count_;
467 machine->mutable_transition_time_matrix()->add_transition_time(0);
475 CHECK_EQ(1, words.size());
476 const int index = transition_index_++;
477 const int size = declared_job_count_ * declared_machine_count_ + 1;
480 if (t1 == 0 || t2 == 0) {
483 const int item1 = t1 - 1;
484 const int item2 = t2 - 1;
485 const int job1 = item1 / declared_machine_count_;
486 const int task1 = item1 % declared_machine_count_;
487 const int m1 = problem_.jobs(job1).tasks(task1).machine(0);
488 const int job2 = item2 / declared_machine_count_;
489 const int task2 = item2 % declared_machine_count_;
490 const int m2 = problem_.jobs(job2).tasks(task2).machine(0);
494 const int transition = strtoint32(words[0]);
495 Machine*
const machine = problem_.mutable_machines(m1);
496 machine->mutable_transition_time_matrix()->set_transition_time(
497 job1 * declared_job_count_ + job2, transition);
498 if (transition_index_ ==
size *
size) {
499 parser_state_ =
DONE;
504 LOG(FATAL) <<
"Should not be here with state " << parser_state_
505 <<
"with line " <<
line;
510void JsspParser::ProcessEarlyTardyLine(
const std::string&
line) {
511 const std::vector<std::string> words =
512 absl::StrSplit(
line,
' ', absl::SkipEmpty());
513 switch (parser_state_) {
515 CHECK_EQ(words.size(), declared_machine_count_ * 2 + 3);
516 Job*
const job = problem_.mutable_jobs(current_job_index_);
517 for (
int i = 0;
i < declared_machine_count_; ++
i) {
518 const int machine_id = strtoint32(words[2 * i]);
519 const int64_t duration = strtoint64(words[2 * i + 1]);
520 Task*
const task = job->add_tasks();
521 task->add_machine(machine_id);
522 task->add_duration(duration);
525 const int due_date = strtoint32(words[declared_machine_count_ * 2]);
526 const int early_cost = strtoint32(words[declared_machine_count_ * 2 + 1]);
527 const int late_cost = strtoint32(words[declared_machine_count_ * 2 + 2]);
528 job->set_early_due_date(due_date);
529 job->set_late_due_date(due_date);
530 job->set_earliness_cost_per_time_unit(early_cost);
531 job->set_lateness_cost_per_time_unit(late_cost);
532 current_job_index_++;
533 if (current_job_index_ == declared_job_count_) {
534 parser_state_ =
DONE;
539 LOG(FATAL) <<
"Should not be here with state " << parser_state_;
544int JsspParser::strtoint32(absl::string_view word) {
546 CHECK(absl::SimpleAtoi(word, &result));
550int64_t JsspParser::strtoint64(absl::string_view word) {
552 CHECK(absl::SimpleAtoi(word, &result));