A comparison between two expressions: lhs < rhs and friends.
Reduces to a core._Bool when both sides are concrete and comparable, so comparisons feed the logic tier directly — x < 2 and y > 3 needs no new machinery, because the connectives take untyped operands.
Deliberately NOT _ElementWise, unlike _Equation and _EqualityCheck. That marker lets algorithms distribute over both sides, which is why 2 * (x = 1) reduces to 2x = 2 today. For an inequality that rewrite is invalid: multiplying x < 1 through by -1 gives -x < -1, which is false exactly when the original is true, because the direction has to flip. Distributing correctly would require knowing the sign of the multiplier, which in general is not available — so the marker is omitted, per the codebase rule that it may be present only when distribution is valid for every algorithm. It is one word long and both neighbouring node types carry it, so this is written down rather than left to be re-derived.
Not solvable._Solve.eval requires an _Equation, so solve(x < 2, x) stays symbolic on its own; inequality solving would need interval-valued solutions, which the solver has no carrier for.
Fully parenthesised, which _Equation and _EqualityCheck are not — and the difference follows directly from not being _ElementWise.
Fully parenthesised, which _Equation and _EqualityCheck are not — and the difference follows directly from not being _ElementWise.
Those two distribute, so a relation never survives inside a product: 2 * (x = 1) becomes (2 * x) = 1 before it is ever printed. A comparison does survive, so an unparenthesised x < 1 inside one renders as (2.0 * x < 1.0) — which re-parses as (2x) < 1, a different expression. The parentheses are what keep the round-trip invariant, the same reason logic._Connective prints (a and b).