with one click
add-propagator
Skill to add a propagator to NuCS.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Skill to add a propagator to NuCS.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | add-propagator |
| description | Skill to add a propagator to NuCS. |
A propagator is a constraint enforced by domain filtering. Adding one means:
ALG_* idname is snake_case, derived from the constraint (e.g. abs_eq, sum_leq_c). Suffix _c means a constant
parameter is involved.domains and parameters carry:
domains is an NDArray of shape (n, 2) — one (MIN, MAX) row per variable, in a fixed order chosen by you.parameters is a 1-D NDArray of ints (may be empty). Use it for constants, coefficients, or table data.compute_domains_name docstring — callers rely on it.nucs/propagators/name_propagator.pyThe file must contain three functions and the standard copyright header (use the skill add-header).
Reference: nucs/propagators/abs_eq_propagator.py is the minimal template.
def get_complexity_name(n: int, parameters: NDArray) -> int:
# Not jitted. Return an int estimate of work per call.
# Used to order propagators in the queue — relative magnitude matters, not units.
...
@njit(cache=True)
def get_triggers_name(n: int, variable: int, parameters: NDArray) -> int:
# Return an EVENT_MASK_* constant from nucs.constants for the given variable index.
# Controls when this propagator wakes up after another propagator filters that variable.
...
@njit(cache=True)
def compute_domains_name(domains: NDArray, parameters: NDArray) -> int:
# Mutate domains in place. Return PROP_INCONSISTENCY, PROP_CONSISTENCY, or PROP_ENTAILMENT.
# Use domains[i][MIN] and domains[i][MAX]; never reassign domains[i] = ....
...
Rules for the jitted functions:
domains in place.
After each tightening, check if domains[i][MIN] > domains[i][MAX]: return PROP_INCONSISTENCY.PROP_ENTAILMENT only when the constraint can never be violated again
(rare; safe to return PROP_CONSISTENCY if unsure).nucs/propagators/propagators.pyAdd the import alongside the others, then append a registration line.
The ALG_* lines are ordered alphabetically by id — keep that.
from nucs.propagators.name_propagator import compute_domains_name, get_complexity_name, get_triggers_name
...
ALG_NAME = register_propagator(get_triggers_name, get_complexity_name, compute_domains_name)
The returned id is the propagator's index; never hardcode it.
tests/propagators/test_name.pyFollow the PropagatorTest pattern (see tests/propagators/test_abs_eq.py):
class TestName(PropagatorTest):
@pytest.mark.parametrize(
"domains,parameters,consistency_result,expected_domains",
[
([(lo, hi), ...], [param, ...], PROP_CONSISTENCY, [[lo, hi], ...]),
# one row per case: boundary, inconsistency, entailment, no-change
],
)
def test_compute_domains(self, domains, parameters, consistency_result, expected_domains) -> None:
self.assert_compute_domains(compute_domains_name, domains, parameters, consistency_result, expected_domains)
Cover at minimum: a pruning case, an inconsistency case, and a no-op case where the input is already tight.
./scripts/bash/style.sh
NUMBA_CACHE_DIR=.numba/cache PYTHONPATH=. pytest tests/propagators/test_name.py
For debugging the propagator logic interactively,
run with NUMBA_DISABLE_JIT=1 so tracebacks land in your Python source.
Add the propagator to docs/source/reference/reference_propagators.rst
(the .. autofunction:: list is ordered alphabetically by module name — keep that).
If the propagator exists to support a MiniZinc/FlatZinc constraint, also connect it in nucs/fzn/:
BUILTINS dict in nucs/fzn/builtins.py, keyed by the FlatZinc builtin name. Its handler
resolves the args (model.var_index_of / var_list_of / int_list_of / const_of) and calls
model.problem.add_propagator(ALG_NAME, variables, parameters).nucs/fzn/share/minizinc/nucs/ (see fzn_all_different_int.mzn), and key the dispatch entry on the fzn_* (or
custom)
predicate name that file produces.Verify end-to-end with tests/fzn/ and, when minizinc is installed, minizinc --solver nucs.