Dimensions (guardrail_calculus.dimensions)
The generic dimension-algebra dispatch engine and the symbolic conditional,
built on the kernel's dimensional protocols. Concrete temporal values
(duration_hours, clock_hm, ...) live in
guardrail_calculus.dimension_value_builtins.
For what a dimension declares and what that declaration buys — the derived algebra, the invariants the solver assumes, and how to author one of your own — see Dimensions.
dimensions
The generic dimension-algebra dispatch engine and the symbolic conditional.
Despite the name, this is no longer where concrete dimensioned values live —
roadmap V8 migrated Duration (Stage 2) and ClockTime/TimeExpr (Stage 3), the
last two dimensions with a bespoke Python class, onto the values API
(:mod:guardrail_calculus.dimension_values; their concrete instantiations in
:mod:guardrail_calculus.dimension_value_builtins). What remains is almost
entirely dimension-agnostic: _apply/_realise_rule read a dimensioned
operand's own Dimension.algebra_rules() and dispatch generically, every
dimension's compound expressions share the one generic DimensionExpr — now
as a base, since _realise_rule builds the role subclass the result
dimension's structure calls for (DisplacementExpr/PointExpr, in
dimension_values.py) — and bind_value/DimensionFacade rebind and
dispatch without naming a dimension either.
The exception is a small, genuinely Time/Duration-specific residue —
TimeAlgebraFamily, IfTime, IfDuration, and their
_DIMENSION_FACADES entries — kept here rather than moved to
dimension_values.py because that module already imports _apply/
_DimensionArithmeticMixin from this one at module level; the reverse
import would cycle. This module builds on the import-safe guardrail_kernel
package; it does not import the public guardrail_calculus package itself.
NodeT
module-attribute
NodeT = TypeVar('NodeT')
CondT
module-attribute
CondT = TypeVar('CondT', bound=BoolLike)
ThenT
module-attribute
ThenT = TypeVar('ThenT')
ElseT
module-attribute
ElseT = TypeVar('ElseT')
TimeAlgebraFamily
module-attribute
TimeAlgebraFamily = Literal['guardrail.family.time']
TimeLike
module-attribute
TimeLike = DimensionLike[Literal['Instant']]
DurationLike
module-attribute
DurationLike = DimensionLike[Literal['Duration']]
ExpressionValue
ExpressionValue = (
BoolExpr[Any]
| _ExprNode[Any]
| _IfNode[Any, Any, Any]
| DimensionExpr
| DimensionValue
| PointReference
| BoundPointReference
| Val[Any, Any]
| PointVal[Any, Any]
| _Add
| _Sub
| _Eq
| _Lt
| _Le
| _Gt
| _Ge
| _And
| _Or
| _Not
| _If
| Predicate[Any]
| bool
| int
| float
| str
)
SubjectRef
dataclass
A reference to another subject in the puzzle.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
Path
|
The path to the referenced subject. |
schema_type |
type[T] | None
|
The schema class of the referenced subject. |
Source code in src/guardrail_calculus/dimensions.py
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
path
instance-attribute
path
schema_type
class-attribute
instance-attribute
schema_type = None
DimensionExpr
dataclass
Bases: _ExprNode[NodeT], DimensionIdentity[Any], _ComparisonMechanics, _DimensionArithmeticMixin, DimensionTagged
A generic composite dimension expression (e.g. for user-defined dimensions).
The compound half of the role split's literal/compound axis: the two
concrete compounds every arithmetic result actually is —
DisplacementExpr and PointExpr, in dimension_values.py — derive
from this, which is why it is no longer @final. Scaling is not declared
here: it belongs to the displacement role, and inheriting it on the shared
base is what let point * 2 through.
Attributes:
| Name | Type | Description |
|---|---|---|
node |
NodeT
|
The underlying provenance node. |
label |
str
|
The expression label. |
unit |
str | None
|
Optional unit string. |
Source code in src/guardrail_calculus/dimensions.py
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | |
label
instance-attribute
label
unit
class-attribute
instance-attribute
unit = None
node
node()
The provenance tree this value was built from.
A method rather than a field so the declared node type can be derived
from a value's own type argument by a self-specialised overload -- the
mapping that lets the declaration-only Val/PointVal facades become
real classes. mypy refuses @property stacked on @overload, so a call
is the only form that can carry it.
Source code in src/guardrail_calculus/dimensions.py
504 505 506 507 508 509 510 511 512 513 | |
IfTime
dataclass
Bases: _IfNode[CondT, ThenT, ElseT], DimensionIdentity[Literal['Instant']], DimensionTagged
Symbolic if/then/else conditional returning an instant.
Source code in src/guardrail_calculus/dimensions.py
546 547 548 549 550 551 552 553 554 555 556 557 558 559 | |
IfDuration
dataclass
Bases: _IfNode[CondT, ThenT, ElseT], DimensionIdentity[Literal['Duration']], DimensionTagged
Symbolic if/then/else conditional returning a duration.
Source code in src/guardrail_calculus/dimensions.py
562 563 564 565 566 567 568 569 570 571 572 573 574 575 | |
IfBool
dataclass
Bases: _IfNode[CondT, ThenT, ElseT]
Symbolic if/then/else conditional returning a boolean.
Source code in src/guardrail_calculus/dimensions.py
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | |
IfDimensionExpr
dataclass
Bases: _IfNode[CondT, ThenT, ElseT], DimensionIdentity[Any], DimensionTagged
Symbolic if/then/else conditional returning a generic dimension expression.
Source code in src/guardrail_calculus/dimensions.py
595 596 597 598 599 600 601 602 603 604 605 606 607 608 | |
DimensionFacade
dataclass
The calculus-layer Python types that realise one kernel dimension.
A dimension's kernel descriptor (:class:~guardrail_kernel.dimension_registry.Dimension)
is dialect-agnostic data; it cannot reference these Python classes without
pulling guardrail_calculus into the kernel. This is the single place that
fact is authored instead: one record per dimension, gathering every bespoke
wrapper type that dispatch previously scattered across parallel
name-keyed tables and hardcoded isinstance chains (z3_if's
conditional wrapper, the two subject-ref placeholder forms). A dimension
absent here, or a None field, falls back to the generic
IfDimensionExpr/plain SlotRef — only dimensions needing a
dedicated field's behaviour fill it in.
No field for a bespoke compound-expression wrapper class exists any
more: it was dropped once roadmap V8 migrated the last two dimensions
that ever used one (Duration, Stage 2; Instant, Stage 3) — every
dimension's compounds are the generic DimensionExpr now, unwrapped
unconditionally by _realise_rule and bind_value. The
current-subject/resolved-subject placeholder fields this record once
carried (bound/resolved, filled only by TimePoint/
BoundTimePoint) were dropped the same way once roadmap V12 retired
those classes: every point-structured dimension's placeholders are now
BoundPointReference/PointReference (dimension_values.py),
admitted by symbolic_point_refs_for(dimension) reading the
dimension's own structure — a registry-data-driven policy with
nothing left to register here.
Source code in src/guardrail_calculus/dimensions.py
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | |
if_
class-attribute
instance-attribute
if_ = None
dimension_facade
dimension_facade(name)
The :class:DimensionFacade registered for dimension name.
Returns the shared empty facade (every field None) for a dimension with
no bespoke Python types, so callers need only check the field they want
rather than the presence of the dimension itself.
Source code in src/guardrail_calculus/dimensions.py
657 658 659 660 661 662 663 664 | |
is_dimension_expr
is_dimension_expr(value)
True if value is a compound dimension-expression wrapper.
Covers every current and future compound wrapper (the once-bespoke
DurationExpr/TimeExpr, both since removed by roadmap V8, and the
generic DimensionExpr every migrated and user-authored dimension's
compounds share now) with one dimension-agnostic check, since they all
share :class:_ExprNode for z3 lowering and symbolic equality — for
dispatch that needs "is this some dimension's compound expression"
without naming which dimension.
Source code in src/guardrail_calculus/dimensions.py
667 668 669 670 671 672 673 674 675 676 677 678 | |
provenance_children
provenance_children(value)
The children of an authored expression value; () at a leaf.
Structural traversal dispatches on the node's type. It must not probe
attribute names: a :class:~guardrail_kernel.expressions.SlotRef answers
any non-underscore attribute by extending its path, so an
hasattr-driven walk over a dimensionless slot manufactures
budget.node().node()... until the stack ends rather than stopping at the
leaf.
The vocabulary is closed and small. Provenance nodes expose their own
operands (the shared accessor every binary, unary, conditional and
route-membership node defines); the three wrapper kinds — a
:class:~guardrail_kernel.expressions.Predicate, a dimension expression
(:class:_ExprNode), a symbolic conditional (:class:_IfNode) — each
carry exactly one provenance node, their label/z3 being
derived. Everything else is a leaf: a slot or point reference, a folded
literal, an int, a unit string.
Source code in src/guardrail_calculus/dimensions.py
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | |
z3_if
z3_if(
condition: CondT, then_: ThenT, else_: ElseT
) -> IfTime[CondT, ThenT, ElseT]
z3_if(
condition: CondT, then_: ThenT, else_: ElseT
) -> IfDuration[CondT, ThenT, ElseT]
z3_if(
condition: CondT, then_: ThenT, else_: ElseT
) -> IfBool[CondT, ThenT, ElseT]
z3_if(
condition: CondT, then_: ThenT, else_: ElseT
) -> IfDimensionExpr[CondT, ThenT, ElseT]
z3_if(condition, then_, else_)
Symbolic if/then/else.
Returns then_ when condition is true, else_ otherwise. Chooses among
IfTime, IfDuration,
IfBool, and IfDimensionExpr
by inspecting the types of then_ and else_.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
condition
|
BoolLike
|
The symbolic boolean condition. |
required |
then_
|
object
|
The branch returned if the condition evaluates to true. |
required |
else_
|
object
|
The branch returned if the condition evaluates to false. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
A symbolic branch wrapper. |
Source code in src/guardrail_calculus/dimensions.py
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | |
bind_value
bind_value(value, *, subject_name)
Recursively bind subject-bound placeholders (_.name) in a value.
BoundPointReference (dimension_values.py, roadmap V12) is the one
subject-bound placeholder shape left — family-generic, not named per
dimension, so a direct isinstance check is the whole dispatch; no
per-dimension facade registration is needed for it to work with a future
point-structured dimension either.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
ExpressionValue
|
The value to bind. |
required |
subject_name
|
str
|
The name of the subject to bind to. |
required |
Returns:
| Type | Description |
|---|---|
ExpressionValue
|
The bound object/expression. |
Source code in src/guardrail_calculus/dimensions.py
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 | |
bind_bool_expr
bind_bool_expr(expr, *, subject_name)
Bind subject-bound placeholders in a boolean expression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
BoolExpr[NodeT]
|
The boolean expression. |
required |
subject_name
|
str
|
The subject name to bind to. |
required |
Returns:
| Type | Description |
|---|---|
BoolExpr[Any]
|
The bound expression. |
Source code in src/guardrail_calculus/dimensions.py
895 896 897 898 899 900 901 902 903 904 905 | |