Browse documentation
Docs/Language

Spatial layout constraints

LAYOUT computes bounded numerical rectangle placements. Validated profiles include finite resizing, quarter-turn choices, indexed families, coupled components, preferences and scoped…

Spatial layout constraints

LAYOUT computes bounded numerical rectangle placements. Validated profiles include finite resizing, quarter-turn choices, indexed families, coupled components, preferences and scoped checking and investigation. The bound value is an ordinary calculation result, evaluated through Grid's existing LP/MIP solver functions when resolved. It starts no job and changes no other cells.

floorplan = LAYOUT
  RECTANGLE kitchen SIZE 4 BY 3
  RECTANGLE dining SIZE 5 BY 4
  REQUIRE kitchen LEFT OF dining
  REQUIRE kitchen TOUCHES dining
END

placement_status = floorplan.status
kitchen_x = floorplan.rectangles.kitchen.x
dining_x = floorplan.rectangles.dining.x

LAYOUT floorplan … END is an equivalent declaration spelling. Formatting preserves the authored header. A source-free owning artifact retains rectangle declarations and requirements and can render them back to source.

Reusable definitions

Parentheses select an inert definition. Definitions can appear in modules, lexical DO blocks and function bodies. Calling one computes a placement through the ordinary callable and compiled path:

office = LAYOUT(width, depth)
  COORDINATES local IN m
  RECTANGLE room SIZE width BY depth
END

input room_width = 400cm
west = office(3m AS depth, room_width AS width)
east = office(6m, 4m)

LAYOUT office(width, depth) … END is equivalent. LAYOUT() declares a zero-argument definition. An unused definition performs no solve, including when its body would require the optional integer solver. Independent calls have independent inputs and results. Forward calls, named arguments using value AS parameter, and explicit partial application such as office(_, 3m) use the declared parameter order. Unknown or duplicate argument names refuse. Consume a partial in expression scope, for example 400cm >> office(_, 3m). The ordinary rule against storing callable values in workbook cells also applies to layout definitions.

This profile accepts at most 64 scalar formals. In a unitless layout every formal requires a finite untagged number; in a length-valued frame every formal requires a compatible length, except an explicit dimensionless COEFFICIENT formal in the affine profile below. Validation includes unused formals. Shapes and entity structure remain fixed at admission. Local preceding immutable numeric values may be captured; inputs, state, default values, cells and rule-written values must be passed as explicit arguments. Mutable dependencies through aliases also refuse.

Definitions can be imported with ordinary USE aliases or exposures. Immutable module values and transitive pure helpers retain their defining bindings, including through re-exports. Module lookup uses the completed declarations; local initializers retain the bindings visible where they were written. A later local binding cannot change an earlier helper's capture.

Pure DEFINE, LAMBDA and arrow helpers can compute dimensions, pins, bounds and relation operands. They accept immutable finite numeric or length captures and fixed-shape arrays. Every captured array element is checked, including unread elements and values canceled by arithmetic. Immutable helper captures are shared within each operation; solve, CHECK and QUERY each capture their own current inputs. Expansion retains the 64-level, 10,000-capture-entry and 1,000,000-work limits.

A factory can also accept an ordinary pure numeric callback and capture it in a unitless layout. The callback requires an admitted callable declaration with numeric arguments, a numeric result and finite numeric captures. Its actual callable and capture identities participate in the input contract, including when a changed callback produces equal geometry. This callback profile supports numeric arithmetic, numeric local bindings and its admitted scalar math functions. Unsupported bodies or captures refuse at operation ingress; conditional, array-valued, length-valued and higher-order callback contracts are outside this profile.

Return or partially apply closures in expression scope. A returned wrapper can retain both a layout call and its CHECK companion, as the composed office example shows. Bind QUERY's literal name and mode before transporting a query closure. ARGS, BODY and FUNCTION inspect local declaration metadata without solving.

Reusable composition has completed its correctness and performance checks. Shaped formal parameters and coupled components use the bounded profile below. Owning templates rename the definition, its formals and named-call arguments together. Results retain grid.layout.v1 unless validation is explicitly selected below. Validated definitions can declare numerical questions. See the reusable layout example.

Shaped parameters and coupled components

This bounded profile is implemented.

Declare an array formal's fixed shape before using ordinary INDEX reads:

input A20 = [2, 3]

room = LAYOUT(widths)
  PARAMETER widths SHAPE 1 BY 2
  VALIDATE EXACT
  BOUNDS (0, 0) TO (20, 20)
  RECTANGLE desk SIZE INDEX(widths, 1, 1) BY 2
END

placement = room(A20)
checked = room.CHECK(placement, A20)

Every entry must satisfy the declared shape and numeric contract, including unread entries. In a length-valued frame the entries are compatible lengths; an explicit COEFFICIENT formal instead carries untagged factors. Coefficient entries have magnitude at most 1,000,000. Shapes use positive literal row and column counts, with at most 10,000 declared entries in one definition. They provide numeric data, never structural entity keys. Immutable key aliases retain the bindings visible in their initializers; a same-spelled numeric formal cannot borrow a module key domain. CHECK and QUERY reserve their own argument names for array formals as well as scalar ones. Reusable module definitions require explicit live arguments for arrays and scalars.

A reusable layout with finite BOUNDS can expose named region or anchor interfaces with EXPOSE desk AS work and EXPOSE door.LEFT AS entry. Instantiate it inside a parent with COMPONENT west USING office(2) AT 0, 0 ROTATE 90. Translation uses the parent's coordinate dimension. Rotation is fixed at 0, 90, 180 or 270 degrees counterclockwise about the local origin. Both declarations use the same coordinate unit and validation policy: EXACT throughout, or the identical authored constant absolute allowance with zero relative allowance. This profile refuses dynamic allowances, nonzero relative allowances and differently authored unit literals even when they are equivalent.

All instances participate in one coupled solve. Their rectangles, pins, child bounds and hard constraints remain mandatory. Use west.work.RIGHT to refer to an exposed region's world anchor, or west.entry for a named anchor. After rotation, named edge/center interfaces identify the corresponding world axis and width/height interfaces identify the corresponding world extent. Private entity names cannot substitute for exposed interfaces. Source value rename preserves the separate rectangle, component and interface namespaces. Imports and ordinary lexical aliases retain their defining blueprints. The coupled office example combines two independent instances and an aisle between them.

Coupled results use grid.layout.v5. Their components vector retains each ordered path, blueprint identity, transform to its immediate parent, entity handles and declared interfaces. Transforms use VECTOR(x, y, rotation_degrees) in the stated working unit. Entity geometry is in the coupled root frame. CHECK rejects altered published component metadata; an explicit grid.layout.candidate.v2 may supply geometry without presentation metadata. QUERY uses the complete coupled hard set and retains its existing evidence rules. Composition does not solve children or export executable blueprints.

Existing rectangle, requirement, row, variable, capture and work limits apply to the complete expansion. This profile additionally bounds the combined instance tree to 128 instances, depth 64, 128-byte paths and 10,000 membership/interface entries. Structural changes require readmission; numeric edits reuse the admitted structure.

Indexed rectangles

An indexed declaration expands one immutable typed domain at admission:

people = [1, 2]
deskWidths = [2, 3]

office = LAYOUT(extraWidth)
  VALIDATE ABSOLUTE 0.000001 RELATIVE 0
  BOUNDS (0, 0) TO (20, 20)
  RECTANGLE desk[person IN people] SIZE INDEX(deskWidths, 1, person) + extraWidth BY 2
  REQUIRE aisle: desk[1] LEFT OF desk[2] GAP AT LEAST 1
END

placed = office(0)
checked = office.CHECK(placed, 0)

The first profile supports one axis per family. Domains are nonempty constant rows or columns containing unique exact integer, text or symbol keys of one kind, in authored order. Text and symbol keys cannot contain control characters. Keys are limited to 128 bytes; integer magnitude is at most 9,007,199,254,740,991. The binder applies only inside that rectangle's operands and cannot shadow an entity or an active formal. Numeric operands retain the existing scalar, length and fixed-shape array contracts. Entity references select constant typed keys; missing, wrong-kind and dynamic keys refuse.

Indexed layouts require VALIDATE and return grid.layout.v3. Each entity adds family and key, whose kind is number, text or symbol and whose value retains the actual key. Numeric owner-local id remains the coverage handle. CHECK verifies the admitted family/key mapping as well as identities and geometry. Explicit indexed candidates and QUERY witnesses use grid.layout.candidate.v2; validation origins and QUERY domains retain keyed metadata. Unindexed v1/v2 contracts remain unchanged.

Numeric dimension edits reuse the admitted structure. Changed membership or domain order requires source/owning readmission and changes definition/frame identity even at equal cardinality and geometry. Input overrides do not expand families. Input, mutable and dynamic Frame domains refuse; a new finite immutable key snapshot requires readmission. The 128-rectangle limit counts all expanded families and scalar rectangles together. CHECK and QUERY use that same expansion. See the indexed metric example.

Typed anchors and affine requirements

Validated layouts with explicit finite BOUNDS also accept scalar equations and inequalities over their declared rectangles:

office = LAYOUT(clearance, alignmentScale)
  COORDINATES local IN m
  COEFFICIENT alignmentScale
  VALIDATE ABSOLUTE 0.000001m RELATIVE 0
  BOUNDS (-10m, -10m) TO (20m, 20m)
  RECTANGLE first SIZE 2m BY 2m
  RECTANGLE second SIZE 3m BY 4m
  REQUIRE level: first.CENTER_Y = alignmentScale * second.CENTER_Y
  REQUIRE passage: first.RIGHT + clearance <= second.LEFT
  REQUIRE maximum: second.LEFT - first.RIGHT <= 3m
END

placed = office(100cm, 1)
checked = office.CHECK(placed, 1m, 1)

LEFT, RIGHT, BOTTOM, TOP, CENTER_X, CENTER_Y, WIDTH and HEIGHT are length-valued anchors in a dimensioned frame. Constant typed keys also select indexed anchors, for example desk[1].RIGHT. They refer to the owning declaration's actual entities; ordinary records and same-spelled values cannot impersonate them. Ordinary value and formal renames preserve entity references. Entity renaming retains the closed-key refusal of the preceding profiles.

COEFFICIENT name explicitly selects a declared formal's dimensionless numeric contract. Other formals retain their length contract, including unused inputs. Coefficients and constants must be finite with magnitude at most 1,000,000. Compatible quantities normalize before arithmetic. Incompatible dimensions, products of unknown anchors, anchor denominators, nonlinear anchor functions, strict comparisons and chained comparisons refuse. Requirements support =, <= and >= and share the named SOLVE affine arithmetic rules. A fixed dimension used as a coefficient must be supplied separately as a numeric parameter.

The selected result is grid.layout.v4. Entities retain their owner-local id, name and geometry, plus the v3 family/key fields (blank for scalar entities). CHECK accepts the v4 result or grid.layout.candidate.v2 with the same metadata. Older result contracts remain unchanged for layouts without affine requirements.

CHECK evaluates exact binary-rational residuals from the admitted coefficients, constants and actual geometry independently of the solver's rounded fixed-size row folding. A positive tolerated residual remains visible. Directional QUERY uses every hard affine requirement; its certificates use outward bounds, and uncertain evidence remains explicit. An affine equality is not a new QUERY predicate. The existing 1,000-requirement limit combines relation and affine clauses; each affine requirement has at most 512 anchor terms. All expansion, row, variable, coefficient and capture limits still apply.

See the affine example for independent CHECK and a necessary aisle query.

Validated placements and CHECK

Add VALIDATE EXACT, or VALIDATE ABSOLUTE length RELATIVE fraction, to select grid.layout.v2. Both tolerance operands are required. The absolute allowance uses the layout's working unit; the relative allowance is dimensionless. Omit the clause to preserve the existing v1 result.

office = LAYOUT(width)
  COORDINATES local IN m
  VALIDATE ABSOLUTE 0.000001m RELATIVE 0
  RECTANGLE room SIZE width BY 3m
END

placement = office(400cm)
checked = office.CHECK(placement, 4m)

The v2 result includes definition_id, input_id, frame, an entities vector, validation, and the original solver report and status. Each entity has a stable declaration-order integer id, its display name, and tagged x, y, width and height. entities replaces v1's name-keyed rectangles record. An independently invalid candidate appears only in diagnostic_candidate; entities is blank. Infeasibility has no usable placement. Validation never changes the backend's termination status or promotes an unfinished search to an optimum.

office.CHECK(candidate, ...inputs) returns grid.layout.validation.v1 without searching or requiring the solver backend. A reactive layout without formal parameters also has name.CHECK(candidate). Named calls follow ordinary parameter rules; candidate is reserved in a validated declaration. Checking an old placement against changed inputs refuses its identity, even if the input was unused or cancelled by arithmetic. Compatible units normalize before input identity; all captured array cells and their shape participate.

CHECK accepts a v2 placement or an explicit native record with schema "grid.layout.candidate.v1", matching definition_id, input_id, frame, and an entities vector. Each entity must supply its admitted id and all four geometry fields; names are optional labels. A CHECK report includes the expected identities and frame even when a supplied candidate does not match. These identities describe content; copying them does not bypass geometric checking.

The validator checks finite coordinates, complete entity coverage, fixed sizes, origin domains, pins, bounds, and every supported relation. Fixed dimensions and identity are exact. Geometric checks preserve exact binary-rational residuals and allowances, along with authored origins. EXACT allows no violation of the normalized numeric operands; an approximate solver result may therefore fail that policy. An explicit allowance is absolute + relative * scale, using involved sizes and clearances rather than absolute position. A tolerated positive residual remains visible. This is checked geometry, not a proof of optimality, necessity, or impossibility.

See the validated placement example for current versus stale input checks.

Numerical questions

A validated definition can declare a named directional question without adding it as a requirement. Call its QUERY companion to ask whether that relation is possible, necessary or excluded by the hard constraints:

office = LAYOUT(clearance)
  VALIDATE EXACT
  BOUNDS (0, 0) TO (12, 8)
  RECTANGLE desk SIZE 3 BY 2
  RECTANGLE cabinet SIZE 2 BY 1
  REQUIRE desk LEFT OF cabinet
  QUERY walkway: desk LEFT OF cabinet GAP AT LEAST clearance
END

possible = office.QUERY("walkway", "MAY", RECORD(), 1)
necessary = office.QUERY("walkway", "MUST", RECORD(), 1)
excluded = office.QUERY("walkway", "CANNOT", RECORD(), 20)
Mode Question over feasible placements
MAY Does any placement satisfy the declared relation?
MUST Does every placement satisfy it?
CANNOT Is the relation excluded from every placement?

This profile supports LEFT OF, RIGHT OF, ABOVE and BELOW questions, with an optional nonnegative GAP AT LEAST operand. The omitted gap is zero. Hard requirements may use directional minimum/maximum gaps, WITHIN and the typed affine requirements above. Contact, shared-edge and non-overlap requirements are outside this query profile. Use LAYOUT() for a definition with no inputs. QUERY requires VALIDATE and a callable parameter list; up to 64 query names are allowed, each at most 128 bytes and unique ignoring ASCII case.

The companion takes query_name, query_mode, query_options, then the definition's inputs. Name and mode must be literal strings; matching ignores ASCII case. These three parameter names are reserved in the definition and its captures. Named arguments follow ordinary callable rules. A partial call must already bind its literal name and mode, for example 1 >> office.QUERY("walkway", "MAY", RECORD(), _). Definition and reflection reads perform no search. Numeric input edits recompute query evidence.

Pass an empty native record for default options, or provide these fields:

Option Default Accepted range
solves 2 Integer 0–2
iterations 2,000 Integer 0–1,000,000 shared across native stages
verification_work 1,000,000 Integer 1–1,000,000 exact-check work units

Unknown fields and invalid counts refuse. These limits bound computational effort; they are not a wall-clock deadline. Query execution requires the solver capability, including when solves is zero. Zero solves or iterations return an undetermined query without native runs. An insufficient exact-check work allowance refuses the operation instead of publishing unverified evidence.

The result has schema grid.layout.query.v1. Its status is holds, does_not_hold, undetermined or infeasible_base. Insufficient evidence stays undetermined; an infeasible base does not make MUST or CANNOT true. Inspect the status explicitly instead of treating the result as a Boolean. evidence distinguishes checked geometry, verified certificates, complete native solver results and incomplete search. termination, runs, budgets and work retain the search outcome and charged effort.

base_witness is an independently checked feasible placement. witness satisfies the declared relation; counterexample violates it, regardless of mode. Thus a witness refutes CANNOT and a counterexample refutes MUST. Available Unindexed placements use grid.layout.candidate.v1; indexed placements use grid.layout.candidate.v2. Both can be passed to their owner's CHECK with the same definition inputs. Invalid native points are diagnostic-only. A verified bound is separate from a checked placement; residual bounds use exact integer numerator/denominator strings.

Search may check one additional midpoint between a valid base placement and an invalid extremum. midpoint_probe identifies that proposal and its two source candidates. Original native points remain unchanged; the proposal must pass every exact geometry check before it can become a witness. This uses the same verification budget and adds no solver call.

Claims concern the admitted finite hard feasible set, independently of the placement objective. origin_domains exposes each entity's admitted coordinate limits. Without BOUNDS these are the existing derived finite domains, so the claim does not extend to an unbounded plane. Query comparisons are exact on the normalized operands and always use zero tolerance, even when the placement definition allows a numerical validation tolerance. Definition, input, query and frame identities accompany the result; prior results supply no implicit evidence.

See the numerical query example for length-valued questions and rechecking a MAY witness.

Finite sizing and discrete placement

A rectangle can have finite size domains and an optional aspect interval:

RECTANGLE panel SIZE 2m TO 6m BY 2m TO 4m ASPECT 1 TO 2
RECTANGLE door SIZE 4m BY 2m ORIENT {0,90}
OBSTACLE pillar SIZE 2m BY 4m AT 9m,6m
NONOVERLAP desks
NONOVERLAP desks WITH pillar

WIDTH, HEIGHT and anchors use the selected physical size. Aspect constraints remain affine; variable-by-variable products refuse. Orientation uses exact selectors from the stated finite domain. Obstacles participate only in the explicitly declared separation requirements. Non-overlap permits touching; positive clearances must be declared separately. Integer choices fail closed when the selected solver lacks MIP. CHECK needs no solver and checks the actual coordinates, sizes, orientations and every hard requirement independently.

Arrangements, choices, snapping and distances

ARRANGE ROW desks GAP aisle
MIRROR CENTERS desks ABOUT X 10m
SNAP desks STEP 50cm AT (0m,0m)
CHOICE route: enabled AND ((first.RIGHT <= second.LEFT) OR (first.TOP <= second.BOTTOM))
DISTANCE access: MANHATTAN (first.CENTER_X,first.CENTER_Y) TO (second.CENTER_X,second.CENTER_Y) AT MOST 12m

Rows and columns use the immutable family order. Equal spacing and mirror clauses add affine constraints; they do not move pins or imply non-overlap. enabled must be Boolean. All raw operands retain their type, finiteness and unit checks, including operands in an inactive branch. Strict inequality and negated geometric inequalities refuse in this bounded choice profile.

SNAP uses a positive length step and explicit finite origin. It checks the returned world coordinates against the grid equation. MANHATTAN and CHEBYSHEV distances support AT MOST, AT LEAST and EXACTLY over the two stated anchors. Lower and exact distances retain complete sign alternatives; a free epigraph variable cannot establish a lower distance. Euclidean distance is outside this affine profile.

The complete hard set is shared by solve, CHECK and directional QUERY. QUERY ignores soft objectives when answering feasibility questions. Combined component, indexed, pair and choice expansion is counted before copying. Existing limits remain: 128 rectangles, 1,000 requirements, 64 combined choice branches, 1,000 solver columns, 10,000 rows and 1,000,000 sparse coefficients. Snap integer-domain admission retains its separate 250,000-work reservation.

Preferences and explicit prior placement

PREFER near_entry PRIORITY 1 SCALE 1m: work.LEFT = target
PREFER aisle_side PRIORITY 2 SCALE 1m WEIGHT 2: work.LEFT >= 15m
MINIMIZE low PRIORITY 3 SCALE 1m: work.BOTTOM

Preferences never relax REQUIRE. Equality measures absolute deviation; inequality measures one-sided nonnegative violation. Every scale and weight must be finite and positive. A scale has the objective's dimension and makes the reported cost dimensionless. Up to 128 terms and 16 priority levels share the existing model limits. Levels run lexicographically with actual native status and completed/unfinished evidence. A checked hard-feasible point is required before a completed level can protect its value for the next level. Huge weights do not approximate priorities.

prior = office(old_target)
request = RECORD("schema","grid.layout.movement.v1",
                 "matching","exact","scale",1m)
revised = office.MOVE(prior,request,new_target)

MOVE adds a final normalized Manhattan objective over entity origins after all authored preference levels. It requires exact owner/frame/typed-entity coverage; the prior input identity may differ. Missing, duplicate, changed or nonfinite entities refuse. No prior result is read from an ambient cache. The optional weight is positive; iterations is an integer from 0 through 2,000. All levels share the operation's iteration allowance and one 1,000,000-work independent geometry verification budget. Publication consumes the checked point without restarting that budget. A failed backend status is preserved.

Priority results use grid.layout.v10, with geometry_schema identifying the underlying v2–v9 geometry profile and an objectives vector of level evidence. Without preferences or MOVE the existing geometry result schema is retained.

Native local regions

region = office.REGION(placement,entity_id,inputs)
converted = target.TRANSFORM(region,
  RECORD("schema","grid.layout.transform.v1",
         "source_frame_id",region.frame.id,"target_frame_id",target_frame,
         "x",2m,"y",0m,"rotation",90),target_inputs)

REGION independently CHECKs the current placement and exports one immutable grid.layout.region.v1 native record. It retains source/input/frame identities, the owner-local entity and typed key, component path, working unit and a closed five-vertex native ring. Component coordinates use the coupled root frame. An endpoint that cannot be represented exactly as a native coordinate refuses. Reading ordinary layout coordinates allocates no polygons.

Native topology accepts same-frame local regions and reuses the existing native polygon validity and relation classifier. Local/EPSG mixtures and unrelated local frames refuse. TRANSFORM explicitly binds both frame identities, compatible units, finite translation and one quarter rotation from 0, 90, 180 or 270 degrees. Its content identity binds the recorded transform; a digest does not replace geometry validity. These calls do not add ambient predicate facts.

Conflicts and immutable repairs

Validated results retain source-group provenance. Display labels do not grant origin authority. Explicit bounded analysis is separate from ordinary solving:

conflict = office.CONFLICT(
  RECORD("schema","grid.layout.conflict-request.v1",
         "solves",32,"iterations",2000),inputs)

grid.layout.conflict.v1 retains whole authored groups, attempted removals, backend outcomes and its fixed context. The affine profile can remove pins and authored bounds over the finite numerical admission context. Discrete bounds, dimensions and poses remain fixed context and are stated in the report. Existing limits are 64 members without MIP and 256 with MIP, with at most 2,000 reserved native iterations. Incomplete, cancelled, unavailable and numerical outcomes do not establish a removable group or irreducibility. Native infeasibility is not an exact infeasibility certificate; irreducibility is not minimum cardinality.

REPAIR takes grid.layout.repair-request.v1: current baseline definition/input/ frame identities, up to eight permitted numeric edit domains, their expected old values, finite candidate values, minimum/maximum, positive compatible scales, positive weights and priority levels. Domains name explicit pins, dimensions, bounds or supported clearance/affine leaves using owner-local handles and source groups. It counts the combined variants before expansion and refuses more than 64. Optional solve/iteration/verification allowances can lower the retained limits; top_k is from 1 through 8.

repairs = office.REPAIR(request,inputs)
checked = office.CHECK_REPAIR(proposal,request,inputs)

Proposals revise numeric leaves of the expanded admitted hard set. They do not re-evaluate original source parameters or change structural membership. Each immutable grid.layout.repair-proposal.v1 binds the current baseline, permissions, typed edits, hypothetical revised identity, normalized lexicographic change cost, actual candidate and complete independent geometry check. Unedited hard constraints remain mandatory. CHECK_REPAIR reconstructs the permitted revision and checks it without search; supplied validation flags grant no authority. Forged costs, changed origins, stale baselines and out-of-domain edits refuse. Partial search does not establish optimality or a complete top-k list. Generating or inspecting a proposal applies nothing. Applying it requires explicit source readmission.

Coordinates and relationships

Coordinates describe each rectangle's lower-left corner; x increases to the right and y increases upward. By default, sizes are positive finite numbers in one common, unitless coordinate system. Dimensions and explicit coordinates may be pure numeric expressions over preceding constants and inputs. Each supplied dimension, pin or bound must have magnitude at most 1,000,000. An optional AT x, y fixes the lower-left corner, for example RECTANGLE room SIZE 10 BY 8 AT 2, 3.

Without explicit bounds, coordinates are nonnegative. BOUNDS (min_x, min_y) TO (max_x, max_y) permits signed coordinates and contains every rectangle in that closed box. The minima must not exceed the maxima. A valid box that is too small, or a pin outside it, produces an infeasible result.

input room_width = 4
input entrance_x = -3

floorplan = LAYOUT
  BOUNDS (-10, -10) TO (20, 20)
  RECTANGLE kitchen SIZE room_width + 1 BY 3 AT entrance_x, -2
  RECTANGLE dining SIZE 5 BY 4
  REQUIRE aisle: kitchen LEFT OF dining
  REQUIRE joint: kitchen TOUCHES dining
END

Input edits recompute the placement and the finite constants used for binary choices. Text, booleans, blanks, nonfinite numbers and invalid sizes produce an error instead of stale coordinates. Unitless layouts also reject tagged inputs. Loose arithmetic coercion does not bypass these checks. Fixed-shape numeric arrays may supply values through INDEX; the complete admitted array is validated, including unread cells. Random, effectful and user-defined function calls are outside this parameter profile.

Length units

COORDINATES local IN m selects a length unit for the whole layout. Compatible unit literals and typed scalar inputs convert before placement arithmetic. Sizes, pins and bounds all require lengths in this mode, including zero (0m). A bare number remains a scalar; it can multiply a length but cannot stand for one. Use (value INTO unit:m) to explicitly construct a length from a scalar. Custom length units declared with UNIT use the same registry and follow owning-template renaming. A case-sensitive SI working prefix whose meaning changes when a public tag is lowercased requires a lowercase custom alias, for example UNIT megametre = 1000000m. It is rejected rather than mislabeled.

input room_width = 400cm

floorplan = LAYOUT
  COORDINATES local IN m
  RECTANGLE kitchen SIZE room_width + 50cm BY 3m AT 0m, 0m
END

A later input value of 5m produces a width of 5.5m. An untagged 5, 5s, text or a nonfinite quantity refuses the calculation. Raw scalar factors also reject tags, text, booleans and blanks before loose arithmetic can coerce them. The 1,000,000 coordinate and dimension limit applies after conversion into the working unit. Public coordinates and sizes retain that unit tag; frame.kind is "local" and frame.unit is the authored unit name.

Addition/subtraction and MIN, MAX, SUM require compatible dimensions. Multiplication, division and bounded literal integer powers combine dimensions; the final size or coordinate must be a length. ABS preserves dimensions. Other numeric functions require scalar arguments: for example, round a ratio against an explicit length and multiply the result by that length. Use typed external scalar bindings or write compatible-length arithmetic inside LAYOUT; an external formula whose ordinary evaluation erased its tag is not silently reinterpreted. Pure helper calls follow the reusable-definition contracts above; fixed component frames follow the R3c component contract.

Fixed-shape arrays may contain compatible quantities and supply dimensions through INDEX(array, row, column). Positions must be constant positive integers inside the admitted shape. An array must have one physical dimension throughout; it cannot mix lengths with times or untagged numbers. Numeric factor arrays remain separate untagged arrays. Tag each quantity, not the array container.

input room_sizes = [400cm, 3m; 2m, 300cm]

floorplan = LAYOUT
  COORDINATES local IN m
  RECTANGLE kitchen SIZE INDEX(room_sizes, 1, 1) BY INDEX(room_sizes, 1, 2)
  RECTANGLE dining SIZE INDEX(room_sizes, 2, 1) BY INDEX(room_sizes, 2, 2)
  REQUIRE kitchen LEFT OF dining
END

Every captured array element is validated and converted, including unread cells and reads cancelled by arithmetic. Edits may change compatible units and values; changed shapes, missing tags, incompatible dimensions and nonfinite values refuse the calculation. Captured arrays are bounded to 1,000 arrays and 1,000,000 cells in total, with at most 256 distinct unit spellings per quantity array.

Relationships

Requirement Meaning
a LEFT OF b a.x + a.width <= b.x
a RIGHT OF b b.x + b.width <= a.x
a BELOW b a.y + a.height <= b.y
a ABOVE b b.y + b.height <= a.y
a TOUCHES b Boundaries intersect and interiors do not overlap; corner contact counts.
a SHARES EDGE WITH b LENGTH AT LEAST length A common boundary segment has at least the positive requested length; a corner does not count.
a DOES NOT OVERLAP b Interiors are disjoint; boundary contact is allowed.
a WITHIN b All of a lies within b, including its boundary.
a INSIDE b Compatibility spelling of WITHIN; it differs from proper containment in qualitative predicates.

Rectangles have no implicit relationship. State non-overlap explicitly when needed. Requirements may refer to rectangles declared later in the same block. Names are case-insensitive for binding and must be unique within the layout. They do not declare ordinary module cells. The result preserves each rectangle's authored name as its record key.

An optional identifier before a colon labels a requirement, as aisle and joint do above. Labels must be unique, case-insensitively, within the block. They appear on its generated solver rows and do not create module bindings.

Directional requirements accept a minimum gap, maximum gap, or both:

REQUIRE aisle: kitchen LEFT OF dining GAP AT LEAST 1m AT MOST 2m
REQUIRE reach: storage ABOVE counter GAP AT MOST 50cm
REQUIRE wall_space: kitchen WITHIN enclosure MARGIN 20cm
REQUIRE joint: counter SHARES EDGE WITH storage LENGTH AT LEAST 1m

These clauses belong inside a layout with the named rectangles. Gaps measure the distance between the facing edges on the selected axis. Omitting the minimum means zero; it does not permit overlap. MARGIN applies the same inset to all four sides of inclusive containment. Gaps and margins are nonnegative; a shared-edge minimum must be positive. Every operand is bounded to 1,000,000 in the working unit and uses the same reactive scalar/array validation as sizes. A gap minimum above its maximum is an invalid parameter. An otherwise valid margin or contact length that cannot fit produces an infeasible placement. Without explicit bounds, finite coordinate extents include minimum gaps.

Directional and containment requirements are affine. Contact with an authored direction uses that direction and checks overlap of the perpendicular intervals. Contact or non-overlap without a direction uses binary choices in the existing MIP backend. An unavailable MIP backend returns invalid_problem with an explanation; it never substitutes the continuous relaxation.

Inspecting published evidence

WHY reads the current committed layout value and its retained source origins. Resolve the requested cell explicitly before inspection. A missing or cold resident value refuses inspection; WHY does not solve, refresh or rehydrate a layout. Other cells retain ordinary provenance behavior, including unknown function names that resemble private layout kernels.

Results and limits

A legacy unvalidated result has schema: "grid.layout.v1", status, rectangles, and report. Each rectangle record contains x, y, width, and height. report retains the native solver status, labels and diagnostics. An infeasible problem has status: "infeasible" and blank rectangles. Invalid solver ingress propagates an error. A solver result with an incumbent retains the solver's actual status; inspect it before treating the placement as optimal.

Without an authored objective, the objective minimizes the sum of rectangle origins, choosing a compact placement near the origin. It does not optimize floor area. Multiple optimal placements may exist; clients should depend on the relationships, not a particular tie choice. Coordinates follow the existing solver's numerical tolerances.

Validated profiles use the versioned entity/validation records described above. Numerical convergence alone does not establish a usable placement: exact size domains or equality constraints can reject an approximate incumbent, including one just outside an endpoint. Inspect validation and diagnostic geometry as well as backend status. CHECK preserves supplied coordinates; it does not clip or repair them to pass validation.

Admission allows at most 128 rectangles, 1,000 requirements, 1,000 expanded solver variables, 10,000 rows and 1,000,000 coefficients. Finite bounds and conditional-row constants derive from validated sizes, pins and explicit bounds. Arbitrary-angle rotation, general polygons as layout decision variables, strict geometric inequalities, cell targets, assignment modifiers and decorated result bindings are outside the bounded profile and refuse. The supported discrete orientation, fixed component transforms and scaled objectives are described above. Use ordinary SOLVE for other numerical models.

See the fixed layout example and reactive signed layout, and metric layout. The metric array layout uses a fixed width/height table for both rooms. The clearance example combines a bounded aisle, wall margins and a service edge.