Tangram — subsystem

← All subsystems

Tangram

Find the tuples that fit

Choose · forbid · prefer · every answer is a branch

A solver. Every other subsystem asks which tuples are there; Tangram asks which tuples could be. You say what may be chosen, what is forbidden and what is preferred, and Tangram searches for a set of tuples that fits, then commits it to a branch, where you can look at it before anything is merged.

-- every shift gets two people from the staff
choose ROTA(shift: s, person: p)
  for each SHIFT(id: s)
  exactly 2 from STAFF(name: p).

-- nobody works two shifts on the same day
forbid ROTA(shift: a, person: p) and ROTA(shift: b, person: p)
   and SHIFT(id: a, day: d) and SHIFT(id: b, day: d) and a != b.

-- juniors take as few nights as possible
prefer fewest ROTA(shift: s, person: p) and NIGHT(id: s) and JUNIOR(name: p).

solve into rota-week-41.

Why a tangram

A tangram is seven flat pieces and a silhouette. The puzzle never tells you where a piece goes, only what the finished shape must be: every piece used, none overlapping, the outline filled. Tangram programs are written the same way. They describe the shape of an answer, never the steps to find it.

Choose, forbid, prefer

Formulas are built from the same atoms as Aleph’s, ROTA(shift: s, person: p), joined with and, or, not and comparisons. Around them, four statements:

StatementSays
choose R(…) for each … exactly n from …the tuples the solver may add; also at least n and at most n
forbid φno answer may make φ true
prefer fewest φ, prefer most φrank the answers by how many ways φ holds
solve into bsearch, and commit the best answer to branch b

choose is the only statement that makes tuples. Everything else narrows the answers down or ranks them, so a Tangram program reads as a list of everything that has to be true.

Every answer is a branch

solve forks the branch it runs on, writes the chosen tuples into it and commits. The answer is not a printout: it is the database as it would be, which every subsystem can read, and which nobody else sees until it is merged.

-- three good rotas, to compare side by side
solve 3 into rota-options.

That makes rota-options/1, /2 and /3. Prolly trees make comparing them cheap, the difference between two answers is a branch diff, and the one you want is merged like any other branch.

Why every search ends

Before it searches, Tangram grounds the program: it replaces every variable with the values the relations actually hold. Relations are finite, so there are finitely many tuples choose could add, and finitely many answers to look through. Every search ends.

Some searches are long, because the problems are hard. within bounds the time and commits the best answer found so far, and every solve records whether its answer was proven best:

solve into rota-week-41 within 30s.

Constraints you already wrote

A commit that breaks an Aleph require, a Sakura integrity rule or a key would be refused, so Tangram reads all of them as forbid before it starts. An answer that could never be merged is never offered.

In the same runtime

The relations a program chooses from are anyone’s. STAFF can be a pureSQL view, NIGHT a Dandelion bundle and JUNIOR a Sol relation, and each solve leaves a tuple in SOLUTION:

-- from pureSQL: which rotas were proven best, and what they cost
SELECT BRANCH, COST, PROVEN FROM SOLUTION ORDER BY COST;

A pureSQL session on rota-week-41 reads ROTA like any other relation, and a Shoji window opened there shows the week’s rota as a form a manager can correct by hand before the merge.