Skip to content

3. Read job shop records and checks

A job shop input gives a job count and a machine count. Each job then has one operation per machine. An operation is a pair: machine number and duration. Machine numbers start at 0.

Build on repeats and sections. All commands run from the repository root.

Use an outer repeat for jobs and an inner repeat for operations. as jobs names the list of job records; each job names an individual job for later checks. The inner names play the same roles for operations.

site/examples/tutorial/jobshop-records.iris
n_jobs: 1..
n_machines: 1..
repeat n_jobs as jobs {
each job
repeat n_machines as steps {
each step
machine: 0..<n_machines
duration: 0..
}
}
site/examples/tutorial/jobshop.txt
2 2
0 3 1 2
1 4 0 1
Terminal window
iris read site/examples/tutorial/jobshop-records.iris site/examples/tutorial/jobshop.txt --dzn
n_jobs = 2;
n_machines = 2;
machine = [| 0, 1
  | 1, 0 |];
duration = [| 3, 2
  | 4, 1 |];

Each repeat adds one array level. machine and duration therefore have depth 2. Row 0 holds job 0’s operations; row 1 holds job 1’s. The names jobs, job, steps and step describe records and create no data entries.

0..<n_machines excludes its upper bound; 0.. admits nonnegative durations. Ordinary numeric reads cross line breaks, so the pairs need not be laid out on physical job lines. See logical records.

The range admits each machine number on its own. To require that a job uses every machine exactly once, also check that its machine numbers are distinct: with exactly n_machines operations, all in range, distinct numbers cover every machine.

site/examples/tutorial/jobshop-checks.iris
n_jobs: 1..
n_machines: 1..
check n_jobs <= (gecode.int_max - 2) / 2 / n_machines "there are too many jobs and machines"
repeat n_jobs as jobs {
each job
repeat n_machines as steps {
each step
machine: 0..<n_machines
duration: 0..
}
}
check distinct(job.machine) "a job uses a machine twice; each job must use every machine once"
check sum(j in jobs: sum(j.duration)) <= gecode.int_max "the total duration is too large"
site/examples/tutorial/jobshop.txt
2 2
0 3 1 2
1 4 0 1
Terminal window
iris read site/examples/tutorial/jobshop-checks.iris site/examples/tutorial/jobshop.txt --dzn
n_jobs = 2;
n_machines = 2;
machine = [| 0, 1
  | 1, 0 |];
duration = [| 3, 2
  | 4, 1 |];

check distinct(job.machine) ranges over jobs. Within one job, job.machine is the array of its machine numbers. The final check uses a comprehension to sum durations across all jobs, then compares the total with Gecode’s integer limit. The early count check is the library’s bound on the job/machine product.

A duplicate machine is in range but fails the record check:

site/examples/guides/jobshop-invalid.txt
2 2
0 3 0 2
1 4 0 1
Terminal window
iris read site/examples/tutorial/jobshop-checks.iris site/examples/guides/jobshop-invalid.txt --dzn
site/examples/guides/jobshop-invalid.txt:2:1: check failed for record 1 of 'jobs': a job uses a machine twice; each job must use every machine once
     2 | 0 3 0 2
       | ^
spec: site/examples/tutorial/jobshop-checks.iris:12

The diagnostic names the first job and points at the position where that job’s record started. This is E-CHECK-FAILED. See the records and checks guide and the Specification’s record access and failure witnesses.

Real OR-Library and JSPLIB files include descriptions, separators and sometimes several named instances. The library wraps the reader in instances, skips # and +++ comments, and uses sections skip other to find the counts. The count arm is last: its body reads the jobs, then sections end before the next instance’s header.

formats/jobshop/jobshop.iris
format jobshop
comment "#" "+++"
instances {
sections skip other {
"instance {name:word}" optional
"{n_jobs:1..} {n_machines:1..}" last {
check n_jobs <= (gecode.int_max - 2) / 2 / n_machines "there are too many jobs and machines"
repeat n_jobs as jobs {
each job
repeat n_machines as steps {
each step
machine: 0..<n_machines
duration: 0..
}
}
}
}
check distinct(job.machine) "a job uses a machine twice; each job must use every machine once"
check sum(j in jobs: sum(j.duration)) <= gecode.int_max "the total duration is too large"
}
formats/jobshop/cases/or-library/input.txt
Hand-made OR-Library style file
+++++++++++++++++++++++++++++
instance handmade-or
+++++++++++++++++++++++++++++
Three jobs on three machines
3 3
0 2 1 3 2 1
1 1 2 4 0 2
2 3 0 1 1 2
Terminal window
iris read formats/jobshop/jobshop.iris formats/jobshop/cases/or-library/input.txt --dzn --param instance=handmade-or
name = "handmade-or";
n_jobs = 3;
n_machines = 3;
machine = [| 0, 1, 2
  | 1, 2, 0
  | 2, 0, 1 |];
duration = [| 2, 3, 1
  | 1, 4, 2
  | 3, 1, 2 |];

The instance parameter selects handmade-or by name. An instances block must be the final statement, so the checks stay inside it. Use the several instances guide for catalogs and selection rules.

You now have the complete job shop library reader. Use the guides to adapt these structures to another format, and check and read samples as you make changes.