3.1

Domains and Narrowing

Possibility spaces, bitmask refinement. The alchemical purification of silver.

Lab

Domains and Narrowing -- Brief ☧

Deep version -> | Lab -> | Back to Unification ->


Q: Imagine a goldsmith receives a chunk of raw ore. Inside that ore

there might be gold, silver, copper, tin, lead, or worthless dross. Before

he tests anything, what could be hiding in there?

A: Any of those six substances, right? We just don't know yet. That

set of remaining possibilities is what we call the ore's domain:

{gold, silver, copper, tin, lead, dross}.

Q: OK, so the goldsmith heats the ore and skims off the dross. Now

what's left?

A: {gold, silver, copper, tin, lead}. See what happened? The domain

got smaller -- it narrowed. That's really the heart of constraint

solving: each step removes something that can't be part of the answer.

Q: That makes sense for a goldsmith, but how does a computer do this

kind of refining?

A: Think of each possibility as a single bit in a number. Six substances

means six bits. Removing something is just clearing its bit -- and we can

do that with a simple AND operation using a bitmask:

Raw ore:     111111  (gold=0, silver=1, copper=2, tin=3, lead=4, dross=5)
Not dross:   011111  (constraint: bit 5 cleared)
AND:         011111  -> dross removed, five remain

Not lead:    101111
AND:         001111  -> four remain

Pure metals: 000011  (only gold and silver survive all refinement)

Each constraint is just a mask, and applying it is a single AND instruction.

That's why this approach is blazingly fast.

Q: What if the domain becomes 000000? All zeros?

A: Then nothing survives -- every possibility has been ruled out. The

constraints are unsatisfiable. It's like demanding something that is

both pure gold AND worthless dross at the same time. Contradiction. Failure.

The solver knows to stop and report "no solution exists."

Domain Sizes in Our Hardware

Domain TypeCapacityRepresentationUse Case
BitVec64Chirho64 valuesSingle u64Fast, small problems
Hierarchical4kChirho4,096 values64 x 64 bitsMedium scale
Hierarchical256kChirho262,144 values64 x 64 x 64Large (FPGA deployed)

The takeaway from this table is that domain size is a design choice, and each

level comes with a tradeoff. BitVec64Chirho fits in a single CPU register and

performs intersection in a single clock cycle -- but 64 possible values is only

enough for small problems like the "three tribal leaders" example above. When you

need to represent thousands or hundreds of thousands of possible values (think of

assigning medical codes, scheduling across large datasets, or mapping a complex

graph), you reach for Hierarchical4kChirho or Hierarchical256kChirho. These

use a layered structure -- like a refiner who first checks the broad category of

an ore before examining individual grains -- so they can skip large sections of

empty space efficiently.

On our FPGA, the Hierarchical256kChirho is the workhorse. It lives in HBM

(High Bandwidth Memory) and uses a three-level summary structure that lets the

hardware skip over groups of impossible values without even reading them. This

is the difference between testing every grain of ore one at a time versus first

checking the color of the slag -- the hierarchical structure saves enormous

amounts of work.

The Core Insight

With those details in mind, we can distill the entire domain-narrowing approach

into three simple ideas:

Domain = the set of values a variable might take
Constraint = removes impossible values (AND with a mask)
Solving = refine until each variable has one value or none

Every topic that follows in this module builds on this foundation. Propagators

(next topic) are the mechanism that applies constraints to domains. Lattices

give us the mathematical guarantee that the narrowing process always terminates.

And fixpoint is the name for the moment when no further narrowing is possible --

the silver is pure.

Learn more about domain hierarchy

Related: Bitmasks | Propagators | Lattices


Soli Deo Gloria

Self-Check 1/4

Domain narrowing removes:

Lab

Domains and Narrowing — Python Lab