GeezerVison is showing iris.gecode.dev — Iris
A specification language for structured text formats A program in Iris is a reader spec . It describes one format: which values a file contains, how they are laid out, how they are collected into arrays, and which conditions they must satisfy. Given a reader spec and an input file, Iris either returns the file’s contents as named, typed data or rejects the file with the position and the statement that failed.
Iris began as the instance reader introduced in Gecode 6.5.0, a constraint solver, but any line- and token-oriented text format is a candidate. The same reader spec works in the command-line tool, in a program that embeds an implementation, and in the playground.
A DIMACS CNF file, the reader spec for that format, and the data Iris reads from it.
Reader spec dimacs-cnf.iris format dimacs-cnf
# SATLIB files end with "%" and "0"
{
# the terminating 0 is not stored
}
Point at or focus a part to see how the input, the reader spec, and the data connect. Click to keep a connection; Escape clears it.
All three clauses read; terminating zeros are consumed without being stored.
Examples from the format library Choose a format to see a sample input, its reader spec, and the data Iris reads. The output comes from the Iris command-line tool, run when the site is built.
Zero terminators end each clause and are discarded from the data.
c Hand-made three-variable formula
p cnf 3 3
1 -2 0
2 3 -1 0
-3 0
stop " % " # SATLIB files end with "%" and "0"
line " p cnf {vars: 0 .. gecode.int_max } {clauses: 0 .. }"
list clause: - vars .. vars until 0 # the terminating 0 is not stored
{"iris":"0.1","entries":[{"name":"vars","type":"int","depth":0,"value":3},{"name":"clauses","type":"int","depth":0,"value":3},{"name":"clause","type":"int","depth":2,"value":[[1,-2],[2,3,-1],[-3]]}]}
vars = 3;
clauses = 3;
% clause: array[int] of tuple(array[int] of int)
clause = [([1, -2],), ([2, 3, -1],), ([-3],)];
Read the input Run from the repository root.
$ iris read formats/dimacs-cnf/dimacs-cnf.iris formats/dimacs-cnf/cases/three-variables/input.txt --dzn
vars = 3;
clauses = 3;
% clause: array[int] of tuple(array[int] of int)
clause = [([1, -2],), ([2, 3, -1],), ([-3],)];
Read succeeded
Coordinates remain coordinates; distance construction belongs to the host.
NAME : handmade-euc-2d-five
TYPE : TSP
DIMENSION : 5
EDGE_WEIGHT_TYPE : EUC_2D
NODE_COORD_TYPE : TWOD_COORDS
NODE_COORD_SECTION
1 0 0
2 3 0
3 3 4
4 0 4
5 1.5 2
EOF
" NAME : {name: rest }" optional
" TYPE : {type: word }" optional
" DIMENSION : {n: 2 .. 46340 }"
" EDGE_WEIGHT_TYPE : {edge_weight_type: word }" optional
" EDGE_WEIGHT_FORMAT : {edge_weight_format: word }" optional
" NODE_COORD_TYPE : {node_coord_type: word }" optional
" DISPLAY_DATA_TYPE : {display_data_type: word }" optional
" NODE_COORD_SECTION " optional {
" EDGE_WEIGHT_SECTION " optional {
if ! defined (edge_weight_format) {
let edge_weight_format = " FULL_MATRIX "
weight[n][n]: 0 .. gecode.int_max / n layout edge_weight_format
{"iris":"0.1","entries":[{"name":"name","type":"string","depth":0,"value":"handmade-euc-2d-five"},{"name":"type","type":"string","depth":0,"value":"TSP"},{"name":"n","type":"int","depth":0,"value":5},{"name":"edge_weight_type","type":"string","depth":0,"value":"EUC_2D"},{"name":"node_coord_type","type":"string","depth":0,"value":"TWOD_COORDS"},{"name":"node","type":"int","depth":1,"value":[1,2,3,4,5]},{"name":"x","type":"float","depth":1,"value":[0,3,3,0,1.5]},{"name":"y","type":"float","depth":1,"value":[0,0,4,4,2]}]}
name = "handmade-euc-2d-five";
'type' = "TSP";
n = 5;
edge_weight_type = "EUC_2D";
node_coord_type = "TWOD_COORDS";
node = [1, 2, 3, 4, 5];
x = [0.0, 3.0, 3.0, 0.0, 1.5];
y = [0.0, 0.0, 4.0, 4.0, 2.0];
Read the input Run from the repository root.
$ iris read formats/tsplib/tsplib.iris formats/tsplib/cases/euc-2d-five/input.txt --dzn
name = "handmade-euc-2d-five";
'type' = "TSP";
n = 5;
edge_weight_type = "EUC_2D";
node_coord_type = "TWOD_COORDS";
node = [1, 2, 3, 4, 5];
x = [0.0, 3.0, 3.0, 0.0, 1.5];
y = [0.0, 0.0, 4.0, 4.0, 2.0];
Read succeeded
Row and column clues become ragged arrays, with one array per line.
title "Hand-made X"
width 5
height 5
rows
1,1
1,1
1
1,1
1,1
columns
1,1
1,1
1
1,1
1,1
check height <= 1000000 / width " the board must have at most a million fields "
check size (rows) == height && size (cols) == width
" the numbers of rows and columns differ from the board size "
check count (row) <= 1 || min (row) > 0 " a 0 must be the only clue of its row "
check count (col) <= 1 || min (col) > 0 " a 0 must be the only clue of its column "
check sum (row) + count (row) - 1 <= width " the clues of a row do not fit into the width of the board "
{"iris":"0.1","entries":[{"name":"width","type":"int","depth":0,"value":5},{"name":"height","type":"int","depth":0,"value":5},{"name":"row","type":"int","depth":2,"value":[[1,1],[1,1],[1],[1,1],[1,1]]},{"name":"col","type":"int","depth":2,"value":[[1,1],[1,1],[1],[1,1],[1,1]]}]}
width = 5;
height = 5;
% row: array[int] of tuple(array[int] of int)
row = [([1, 1],), ([1, 1],), ([1],), ([1, 1],), ([1, 1],)];
% col: array[int] of tuple(array[int] of int)
col = [([1, 1],), ([1, 1],), ([1],), ([1, 1],), ([1, 1],)];
Read the input Run from the repository root.
$ iris read formats/nonogram/nonogram.iris formats/nonogram/cases/five-by-five/input.txt --dzn
width = 5;
height = 5;
% row: array[int] of tuple(array[int] of int)
row = [([1, 1],), ([1, 1],), ([1],), ([1, 1],), ([1, 1],)];
% col: array[int] of tuple(array[int] of int)
col = [([1, 1],), ([1, 1],), ([1],), ([1, 1],), ([1, 1],)];
Read succeeded
Each job’s operations yield machine and duration arrays.
# Hand-made JSPLIB style file
# Jobs and machines, then machine-duration pairs
3 3
0 3 2 2 1 4
1 2 0 1 2 3
2 4 1 3 0 2
" 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_machines as steps {
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 "
{"iris":"0.1","entries":[{"name":"n_jobs","type":"int","depth":0,"value":3},{"name":"n_machines","type":"int","depth":0,"value":3},{"name":"machine","type":"int","depth":2,"value":[[0,2,1],[1,0,2],[2,1,0]]},{"name":"duration","type":"int","depth":2,"value":[[3,2,4],[2,1,3],[4,3,2]]}]}
n_jobs = 3;
n_machines = 3;
machine = [| 0, 2, 1
| 1, 0, 2
| 2, 1, 0 |];
duration = [| 3, 2, 4
| 2, 1, 3
| 4, 3, 2 |];
Read the input Run from the repository root.
$ iris read formats/jobshop/jobshop.iris formats/jobshop/cases/jsplib/input.txt --dzn
n_jobs = 3;
n_machines = 3;
machine = [| 0, 2, 1
| 1, 0, 2
| 2, 1, 0 |];
duration = [| 3, 2, 4
| 2, 1, 3
| 4, 3, 2 |];
Read succeeded
Blank cells become zero. Solving the puzzle belongs to the host.
# size=4 box=2x2
1..4
.41.
.14.
4..1
line " # size= {n: 1 .. } box= {box_width: 1 .. } x {box_height: 1 .. }"
cells[n][n]: alphabet " 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0 " blank " . "
check box_width * box_height == n " boxes must tile the grid "
check max (cells) <= n " a value is larger than the size of the grid "
{"iris":"0.1","entries":[{"name":"n","type":"int","depth":0,"value":4},{"name":"box_width","type":"int","depth":0,"value":2},{"name":"box_height","type":"int","depth":0,"value":2},{"name":"cells","type":"int","depth":2,"value":[[1,0,0,4],[0,4,1,0],[0,1,4,0],[4,0,0,1]]}]}
n = 4;
box_width = 2;
box_height = 2;
cells = [| 1, 0, 0, 4
| 0, 4, 1, 0
| 0, 1, 4, 0
| 4, 0, 0, 1 |];
Read the input Run from the repository root.
$ iris read formats/sudoku/sudoku.iris formats/sudoku/cases/four-by-four/input.txt --dzn
n = 4;
box_width = 2;
box_height = 2;
cells = [| 1, 0, 0, 4
| 0, 4, 1, 0
| 0, 1, 4, 0
| 4, 0, 0, 1 |];
Read succeeded
Travel times form a matrix; checks require ordered time windows.
# Hand-made depot and two customers
3
0 2 4
3 0 2
4 3 0
0 20
2 8
5 12
dist[n][n]: 0 .. gecode.int_max / 2 / n
type time = 0 .. gecode.int_max / 2
check node.ready <= node.due " the time window of a node is invalid "
check nodes[ 0 ].ready == 0 " the depot (node 0) must open at time 0 "
{"iris":"0.1","entries":[{"name":"n","type":"int","depth":0,"value":3},{"name":"dist","type":"int","depth":2,"value":[[0,2,4],[3,0,2],[4,3,0]]},{"name":"ready","type":"int","depth":1,"value":[0,2,5]},{"name":"due","type":"int","depth":1,"value":[20,8,12]}]}
n = 3;
dist = [| 0, 2, 4
| 3, 0, 2
| 4, 3, 0 |];
ready = [0, 2, 5];
due = [20, 8, 12];
Read the input Run from the repository root.
$ iris read formats/tsptw/tsptw.iris formats/tsptw/cases/three-nodes/input.txt --dzn
n = 3;
dist = [| 0, 2, 4
| 3, 0, 2
| 4, 3, 0 |];
ready = [0, 2, 5];
due = [20, 8, 12];
Read succeeded
Introduction How a reader spec describes a format, shown on a small file read from the command line.
Read the introduction Format library Reader specs for benchmark formats, with sample inputs, the data they produce, and rejected inputs. Each case can be downloaded.
Browse the formats Command-line tool Check a reader spec, read an input as JSON or MiniZinc data, or list the instances in a file.
CLI documentation