* Assume `symbol ∈ setExpr`, decomposing structured sets into independent * stored facts plus type refinements ("shallow saturation", design §3.2): * * | Set shape | Action | * |---|---| * | primitive number set (ℂ, ℝ, ℤ…) | type refinement (historical behavior) | * | `Range(a, b)` | `integer`
( ce: ComputeEngine, symbol: string, setExpr: Expression )
| 816 | if (r === 'ok') sawOk = true; |
| 817 | } |
| 818 | return sawOk ? 'ok' : 'tautology'; |
| 819 | } |
| 820 | |
| 821 | let op = ''; |
| 822 | let lhs: Expression; |
| 823 | let rhs: Expression; |
| 824 | if (proposition.operator === 'Less') { |
| 825 | lhs = proposition.op1; |
| 826 | rhs = proposition.op2; |
| 827 | op = '<'; |
| 828 | } else if (proposition.operator === 'LessEqual') { |
| 829 | lhs = proposition.op1; |
| 830 | rhs = proposition.op2; |
| 831 | op = '<='; |
| 832 | } else if (proposition.operator === 'Greater') { |
| 833 | lhs = proposition.op2; |
| 834 | rhs = proposition.op1; |
| 835 | op = '<'; |
| 836 | } else if (proposition.operator === 'GreaterEqual') { |
| 837 | lhs = proposition.op2; |
| 838 | rhs = proposition.op1; |
| 839 | op = '<='; |
| 840 | } |
| 841 | if (!op) return 'internal-error'; |
| 842 | // The proposition is boxed `{ form: 'raw' }` (engine-assumptions.ts), so its |
| 843 | // operands are non-canonical. Arithmetic (`.sub()`, and the `.neg()` it calls) |
| 844 | // must run on canonical operands — otherwise a canonical `Negate` ends up |
| 845 | // wrapping a non-canonical symbol, tripping the `isCanonical` assert in |
| 846 | // `BoxedSymbol.toNumericValue` once the difference is numerically compared. |
| 847 | const p = lhs!.canonical.sub(rhs!.canonical); |
| 848 | |
| 849 | // Case 2 |
| 850 | const result = ce.expr([op === '<' ? 'Less' : 'LessEqual', p, 0]).evaluate(); |
| 851 | |
| 852 | if (isSymbol(result, 'True')) return 'tautology'; |
| 853 | if (isSymbol(result, 'False')) return 'contradiction'; |
| 854 | |
| 855 | const unknowns = result.unknowns; |
| 856 | if (unknowns.length === 0) return 'not-a-predicate'; |
| 857 | |
| 858 | // |
| 859 | // Part-subject inequalities (design §4.2), e.g. `Re(s) > 1` normalized to |
| 860 | // `Less(1 - Real(s), 0)`: the normalized lhs is ±Part(x) plus an optional |
| 861 | // numeric constant, where Part ∈ {Real, Imaginary, Abs, Argument}. |
| 862 | // |
| 863 | const normalizedLhs = isFunction(result) ? result.op1 : undefined; |
| 864 | const partSubject = |
| 865 | normalizedLhs !== undefined ? partBoundSubject(normalizedLhs) : undefined; |
| 866 | if (partSubject !== undefined) { |
| 867 | const newBounds = boundsFromNormalizedInequality(result, partSubject); |
| 868 | |
| 869 | // Bounds-level tautology/contradiction check against existing bounds on |
| 870 | // the *same* subject (design §4.3; cross-subject consistency is out of |
| 871 | // scope). |
| 872 | if (newBounds !== undefined) { |
| 873 | const existing = boundsForCurrentDefinition(ce, partSubject); |
| 874 | const status = checkBoundsAgainst(existing, newBounds); |
| 875 | if (status !== undefined) return status; |
no test coverage detected