Skip to content

Commit e4396b8

Browse files
committed
Add the Golomb ruler example
1 parent 8ae9df4 commit e4396b8

File tree

4 files changed

+320
-0
lines changed

4 files changed

+320
-0
lines changed

_layouts/default.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ <h4>Example programs</h4>
4242
<li><a href="/examples/knights-tour">Knights tour</a></li>
4343
<li><a href="/examples/eight-queens">Eight queens</a></li>
4444
<li><a href="/examples/disjoint-rectangles">Disjoint rectangles</a></li>
45+
<li><a href="/examples/golomb-ruler">Golomb ruler</a></li>
4546
<li><a href="/examples/self-enumerating-pangram">Self-enumerating pangram</a></li>
4647
<li><a href="/examples/power-concatenation">Power concatenation</a></li>
4748
<li><a target="_blank" href="http://makercasts.org/articles/gchq-christmas-puzzle">Nonogram (article)</a></li>

compiled/golomb-ruler.json

Lines changed: 216 additions & 0 deletions
Large diffs are not rendered by default.

examples/golomb-ruler.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
title: "Examples: Golomb ruler"
3+
header: /examples
4+
layout: default
5+
---
6+
# Golomb ruler
7+
8+
The following program finds
9+
[Golomb rulers](https://en.wikipedia.org/wiki/Golomb_ruler).
10+
11+
```sentient
12+
{% include_relative golomb-ruler.snt %}```
13+
14+
By repeatedly adjusting the limit based on the result of the previous run,
15+
Sentient can find the optimal ruler, which is thought to be an
16+
[NP-hard](https://en.wikipedia.org/wiki/NP-hardness) problem.
17+
18+
## How does it work?
19+
20+
We [declare](../syntax/declaration) an array of integers for the 'ruler' and a
21+
single integer for the 'limit'. We specify [invariants](../syntax/invariant) for
22+
each property as described in the
23+
[Wikipedia article](https://en.wikipedia.org/wiki/Golomb_ruler). We use
24+
Sentient's [method syntax](../syntax/function#method-syntax) to simplify the
25+
high-level code in the 'main' function.
26+
27+
The 'distances' function iterates through pairs of marks on the ruler with
28+
['eachCombination'](../library/array#eachCombination). It
29+
[pushes](../library/array#push) the difference between marks onto an array. The
30+
'ascending?' function iterates through [consecutive](../library/array#eachCons)
31+
elements to check if the element on the left is less than the right. The '&&='
32+
syntax is shorthand for 'a = a && b'.
33+
34+
We then specify that rulers must begin at zero (a common convention) and
35+
eliminate translated solutions by enforcing the smaller of the first and last
36+
distances must be on the left. More generally, this technique is known as
37+
[symmetry breaking](https://en.wikipedia.org/wiki/Symmetry-breaking_constraints).
38+
The final invariant lets us limit our search to rulers shorter than a given
39+
length.
40+
41+
## CLI example
42+
43+
Here is an example of running this program with the
44+
[command-line interface](../cli/overview):
45+
46+
```bash
47+
sentient --run golomb-ruler.json --assign '{ limit: 19 }' --number 0
48+
49+
# standard output:
50+
{"limit":19,"ruler":[0,1,8,11,13,17]}
51+
{"limit":19,"ruler":[0,1,4,10,12,17]}
52+
{"limit":19,"ruler":[0,1,3,8,12,18]}
53+
{"limit":19,"ruler":[0,2,6,7,15,18]}
54+
{"limit":19,"ruler":[0,1,5,7,15,18]}
55+
{"limit":19,"ruler":[0,1,8,12,14,17]}
56+
{"limit":19,"ruler":[0,1,3,8,14,18]}
57+
{"limit":19,"ruler":[0,1,4,10,15,17]}
58+
{}
59+
```
60+
61+
This finds [all rulers](../cli/number) with a length shorter than 19.

examples/golomb-ruler.snt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
function main () {
2+
array6<int> ruler;
3+
int limit;
4+
5+
invariant ruler.distances.uniq?;
6+
invariant ruler.ascending?;
7+
invariant ruler.first.zero?;
8+
invariant ruler.firstDist < ruler.lastDist;
9+
invariant ruler.last < limit;
10+
11+
expose ruler, limit;
12+
};
13+
14+
function distances (ruler) {
15+
arr = [];
16+
17+
ruler.eachCombination(2, function^ (pair) {
18+
arr = arr.push(pair.last - pair.first);
19+
});
20+
21+
return arr;
22+
};
23+
24+
function ascending? (ruler) {
25+
asc = true;
26+
27+
ruler.eachCons(2, function^ (pair) {
28+
asc &&= pair.first < pair.last;
29+
});
30+
31+
return asc;
32+
};
33+
34+
function firstDist (ruler) {
35+
return ruler[1] - ruler[0];
36+
};
37+
38+
function lastDist (ruler) {
39+
return ruler[ruler.length - 1] - ruler[ruler.length - 2];
40+
};
41+
42+
main();

0 commit comments

Comments
 (0)