Skip to content

Commit efbaaf7

Browse files
arnogclaude
andauthored
Task 18 et al (#281)
* fix: implement value resolution from equality assumptions (#18) When ce.assume(['Equal', symbol, value]) is called, the symbol now correctly evaluates to the assumed value. Previously, the symbol would remain unevaluated even after the assumption was made. Changes: - Fixed assumeEquality to set the symbol value when it already has a definition (which happens when accessed via .unknowns) - Updated BoxedSymbol.N() to check the evaluation context value for non-constant symbols, enabling correct comparison evaluation Examples that now work: - ce.box('one').evaluate().json → 1 (was: "one") - ce.box(['Equal', 'one', 1]).evaluate() → True (was: unchanged) - ce.box(['Equal', 'one', 0]).evaluate() → False https://claude.ai/code/session_01Xx26gPU9ThyiypRqdLcmZQ * feat: implement inequality evaluation using assumptions (#19) When inequality assumptions like `ce.assume(['Greater', 'x', 4])` are made, comparisons can now use transitive reasoning to determine results. For example, `x > 4` implies `x > 0`, so `['Greater', 'x', 0]` evaluates to True instead of remaining symbolic. Implementation: - Added `getInequalityBoundsFromAssumptions()` to extract lower/upper bounds from normalized assumption forms like `Less(Add(Negate(x), k), 0)` - Modified `cmp()` in compare.ts to use these bounds when comparing symbols Examples that now work: - ce.box(['Greater', 'x', 0]).evaluate() → True (when x > 4 assumed) - ce.box(['Less', 'x', 0]).evaluate() → False - ce.box('x').isGreater(0) → true - ce.box('x').isPositive → true https://claude.ai/code/session_01Xx26gPU9ThyiypRqdLcmZQ * fix: forget() and scoped assumptions now properly clear values (#24, #25) Bug #24: forget() now clears assumed values from evaluation context - After ce.assume(['Equal', 'x', 5]) and ce.forget('x'), x now correctly evaluates to 'x' instead of 5 - Added cleanup loop in forget() to delete values from all context frames Bug #25: Scoped assumptions clean up on popScope() - Assumptions made inside pushScope()/popScope() now properly clean up - Added _setCurrentContextValue() method to store values in current context - Modified assumeEquality() to use scoped value storage - Values set by assumptions are automatically removed when scope exits Files modified: - src/compute-engine/index.ts - Added _setCurrentContextValue(), forget() cleanup - src/compute-engine/global-types.ts - Added method signature - src/compute-engine/assume.ts - Use scoped value storage - test/compute-engine/bug-fixes.test.ts - Tests for both bugs - CHANGELOG.md, requirements/TODO.md, requirements/DONE.md - Documentation https://claude.ai/code/session_01Xx26gPU9ThyiypRqdLcmZQ * feat: implement type inference from assumptions (#21) When assumptions are made, symbol types are now correctly inferred: - Inequality assumptions (>, <, >=, <=) set the symbol's type to 'real' - Equality assumptions infer the type from the value: - Equal to integer → type 'integer' - Equal to rational → type 'real' - Equal to real → type 'real' - Equal to complex → type 'number' Implementation: - Added inferTypeFromValue() function to promote specific types (e.g., finite_integer → integer) - Updated assumeEquality() to use inferTypeFromValue when updating types - Updated assumeInequality() to set type 'real' even for auto-declared symbols Examples: ce.assume(ce.box(['Greater', 'x', 4])); ce.box('x').type.toString(); // → 'real' (was: 'unknown') ce.assume(ce.box(['Equal', 'one', 1])); ce.box('one').type.toString(); // → 'integer' (was: 'unknown') Files modified: - src/compute-engine/assume.ts - Added inferTypeFromValue(), updated type inference - test/compute-engine/assumptions.test.ts - Enabled 6 tests - CHANGELOG.md, requirements/TODO.md, requirements/DONE.md - Documentation https://claude.ai/code/session_01Xx26gPU9ThyiypRqdLcmZQ * feat: implement tautology and contradiction detection for assumptions (#20) ce.assume() now returns 'tautology' for redundant assumptions that are already implied by existing assumptions, and 'contradiction' for assumptions that conflict with existing ones. Examples: - ce.assume(['Greater', 'x', 0]) when x > 4 exists returns 'tautology' - ce.assume(['Less', 'x', 0]) when x > 4 exists returns 'contradiction' - ce.assume(['Equal', 'one', 1]) repeated returns 'tautology' - ce.assume(['Less', 'one', 0]) when one=1 exists returns 'contradiction' Implementation: - Added bounds checking logic in assumeInequality() that extracts the symbol from the inequality and checks against existing bounds - Handles canonical form normalization (Greater(x,k) → Less(k,x)) - Correctly determines "effective" relationship based on operator and which operand contains the symbol https://claude.ai/code/session_01Xx26gPU9ThyiypRqdLcmZQ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 73b6870 commit efbaaf7

5 files changed

Lines changed: 308 additions & 92 deletions

File tree

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,41 @@
3333
This works by extracting lower/upper bounds from inequality assumptions
3434
and using them during comparison operations.
3535

36+
- **Type Inference from Assumptions**: When assumptions are made, symbol types
37+
are now correctly inferred. Inequality assumptions (`>`, `<`, `>=`, `<=`) set
38+
the symbol's type to `real`, and equality assumptions infer the type from the
39+
value (e.g., equal to an integer means type `integer`).
40+
41+
```javascript
42+
ce.assume(ce.box(['Greater', 'x', 4]));
43+
ce.box('x').type.toString(); // → 'real' (was: 'unknown')
44+
45+
ce.assume(ce.box(['Equal', 'one', 1]));
46+
ce.box('one').type.toString(); // → 'integer' (was: 'unknown')
47+
```
48+
49+
- **Tautology and Contradiction Detection**: `ce.assume()` now returns
50+
`'tautology'` for redundant assumptions that are already implied by existing
51+
assumptions, and `'contradiction'` for assumptions that conflict with
52+
existing ones.
53+
54+
```javascript
55+
ce.assume(ce.box(['Greater', 'x', 4]));
56+
57+
// Redundant assumption (x > 4 implies x > 0)
58+
ce.assume(ce.box(['Greater', 'x', 0])); // → 'tautology' (was: 'ok')
59+
60+
// Conflicting assumption (x > 4 contradicts x < 0)
61+
ce.assume(ce.box(['Less', 'x', 0])); // → 'contradiction'
62+
63+
// Same assumption repeated
64+
ce.assume(ce.box(['Equal', 'one', 1]));
65+
ce.assume(ce.box(['Equal', 'one', 1])); // → 'tautology'
66+
67+
// Conflicting equality
68+
ce.assume(ce.box(['Less', 'one', 0])); // → 'contradiction'
69+
```
70+
3671
### Bug Fixes
3772

3873
- **forget() Now Clears Assumed Values**: Fixed an issue where `ce.forget()` did not

requirements/DONE.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,3 +1184,102 @@ ce.box('y').evaluate().json; // → 'y' (was: 10)
11841184

11851185
**Tests added:**
11861186
- `test/compute-engine/bug-fixes.test.ts` - Test for scoped assumption cleanup
1187+
1188+
---
1189+
1190+
### 21. Type Inference from Assumptions ✅
1191+
1192+
**IMPLEMENTED:** When assumptions are made, symbol types are now correctly inferred
1193+
based on the assumption.
1194+
1195+
**Problem:** When `ce.assume(['Greater', 'x', 4])` was called, the symbol's type
1196+
remained 'unknown'. Similarly, when `ce.assume(['Equal', 'one', 1])` was called,
1197+
the symbol's type was 'finite_integer' instead of 'integer'.
1198+
1199+
**Solution:** Modified the assumption processing to update symbol types:
1200+
1201+
1. **For equality assumptions**: Added `inferTypeFromValue()` function that promotes
1202+
specific types to more general ones (e.g., `finite_integer``integer`,
1203+
`finite_real_number``real`). This is used when updating the type of a symbol
1204+
with an inferred type.
1205+
1206+
2. **For inequality assumptions**: Updated `assumeInequality()` to set the symbol's
1207+
type to 'real' even when the symbol was already auto-declared with an inferred type.
1208+
1209+
**Type promotion rules:**
1210+
- `finite_integer`, `integer``integer`
1211+
- `rational``real`
1212+
- `finite_real_number`, `real``real`
1213+
- `complex`, `imaginary``number`
1214+
1215+
**Examples that now work:**
1216+
```typescript
1217+
ce.assume(ce.box(['Greater', 'x', 4]));
1218+
ce.box('x').type.toString(); // → 'real' (was: 'unknown')
1219+
1220+
ce.assume(ce.box(['Equal', 'one', 1]));
1221+
ce.box('one').type.toString(); // → 'integer' (was: 'finite_integer' or 'unknown')
1222+
1223+
ce.assume(ce.box(['Greater', 't', 0]));
1224+
ce.box('t').type.toString(); // → 'real'
1225+
1226+
ce.assume(ce.box(['Equal', 'p', 11]));
1227+
ce.box('p').type.toString(); // → 'integer'
1228+
```
1229+
1230+
**Files modified:**
1231+
- `src/compute-engine/assume.ts` - Added `inferTypeFromValue()`, updated type inference
1232+
1233+
**Tests enabled:**
1234+
- `test/compute-engine/assumptions.test.ts` - Enabled "TYPE INFERENCE FROM ASSUMPTIONS"
1235+
describe block (6 tests)
1236+
1237+
---
1238+
1239+
### 20. Tautology and Contradiction Detection ✅
1240+
1241+
**IMPLEMENTED:** `ce.assume()` now returns `'tautology'` for redundant assumptions
1242+
that are already implied by existing assumptions, and `'contradiction'` for
1243+
assumptions that conflict with existing ones.
1244+
1245+
**Problem:** When a user made an assumption like `x > 0` after already assuming
1246+
`x > 4`, the function would return `'ok'` even though the new assumption was
1247+
redundant (implied by the existing one). Similarly, assuming `x < 0` when `x > 4`
1248+
exists would silently accept a contradictory assumption.
1249+
1250+
**Solution:** Added bounds checking logic in `assumeInequality()` that:
1251+
1252+
1. Extracts the symbol from the inequality being assumed
1253+
2. Retrieves existing bounds for that symbol from current assumptions
1254+
3. Compares the new inequality against existing bounds to detect:
1255+
- **Tautologies**: When the new inequality is implied by existing bounds
1256+
- **Contradictions**: When the new inequality conflicts with existing bounds
1257+
1258+
The implementation correctly handles all combinations:
1259+
- `Greater`/`GreaterEqual` vs existing lower bounds → tautology detection
1260+
- `Greater`/`GreaterEqual` vs existing upper bounds → contradiction detection
1261+
- `Less`/`LessEqual` vs existing upper bounds → tautology detection
1262+
- `Less`/`LessEqual` vs existing lower bounds → contradiction detection
1263+
1264+
It also handles canonical form normalization - the compute engine canonicalizes
1265+
`Greater(x, k)` to `Less(k, x)`, so the code determines the "effective" relationship
1266+
based on both the operator and which operand contains the symbol.
1267+
1268+
**Examples that now work:**
1269+
```typescript
1270+
ce.assume(ce.box(['Equal', 'one', 1]));
1271+
ce.assume(ce.box(['Equal', 'one', 1])); // → 'tautology' (same assumption repeated)
1272+
ce.assume(ce.box(['Less', 'one', 0])); // → 'contradiction' (one=1 is not < 0)
1273+
ce.assume(ce.box(['Greater', 'one', 0])); // → 'tautology' (one=1 > 0)
1274+
1275+
ce.assume(ce.box(['Greater', 'x', 4]));
1276+
ce.assume(ce.box(['Greater', 'x', 0])); // → 'tautology' (x > 4 implies x > 0)
1277+
ce.assume(ce.box(['Less', 'x', 0])); // → 'contradiction' (x > 4 contradicts x < 0)
1278+
```
1279+
1280+
**Files modified:**
1281+
- `src/compute-engine/assume.ts` - Added bounds checking logic in `assumeInequality()`
1282+
1283+
**Tests enabled:**
1284+
- `test/compute-engine/assumptions.test.ts` - Enabled "TAUTOLOGY AND CONTRADICTION
1285+
DETECTION" describe block (4 tests)

requirements/TODO.md

Lines changed: 4 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -778,92 +778,15 @@ See `requirements/DONE.md` for implementation details.
778778

779779
---
780780

781-
### 20. Tautology and Contradiction Detection
781+
### ~~20. Tautology and Contradiction Detection~~ ✅ COMPLETED
782782

783-
**Problem:** `ce.assume()` should detect when an assumption is redundant
784-
(tautology) or conflicts with existing assumptions (contradiction), but
785-
currently it always returns `"ok"`.
786-
787-
**Current behavior:**
788-
789-
```typescript
790-
ce.assume(ce.box(['Equal', 'one', 1]));
791-
ce.assume(ce.box(['Equal', 'one', 1])); // Returns: "ok" (should be "tautology")
792-
ce.assume(ce.box(['Less', 'one', 0])); // Returns: "ok" (should be "contradiction")
793-
```
794-
795-
**Expected behavior:**
796-
797-
```typescript
798-
ce.assume(ce.box(['Equal', 'one', 1]));
799-
ce.assume(ce.box(['Equal', 'one', 1])); // Should return: "tautology"
800-
ce.assume(ce.box(['Less', 'one', 0])); // Should return: "contradiction"
801-
ce.assume(ce.box(['Greater', 'one', 0])); // Should return: "tautology" (one=1 > 0)
802-
803-
ce.assume(ce.box(['Greater', 'x', 4]));
804-
ce.assume(ce.box(['Greater', 'x', 0])); // Should return: "tautology" (implied by x > 4)
805-
ce.assume(ce.box(['Less', 'x', 0])); // Should return: "contradiction"
806-
```
807-
808-
**Implementation notes:**
809-
810-
- Tautology detection: Check if the new assumption is already implied by
811-
existing assumptions
812-
- Contradiction detection: Check if the new assumption conflicts with existing
813-
assumptions
814-
- Requires transitive reasoning for inequalities
815-
- The return type of `assume()` already includes `"tautology"` and
816-
`"contradiction"` as options
817-
818-
**Files to investigate:**
819-
820-
- `src/compute-engine/assume.ts` - `assume()` function and `AssumeResult` type
821-
822-
**Tests:** `test/compute-engine/assumptions.test.ts` - "TAUTOLOGY AND
823-
CONTRADICTION DETECTION"
783+
See `requirements/DONE.md` for implementation details.
824784

825785
---
826786

827-
### 21. Type Inference from Assumptions
828-
829-
**Problem:** When assumptions are made, symbol types should be inferred. For
830-
example, `x > 4` implies `x` is real, and `one = 1` implies `one` is an integer.
787+
### ~~21. Type Inference from Assumptions~~ ✅ COMPLETED
831788

832-
**Current behavior:**
833-
834-
```typescript
835-
ce.assume(ce.box(['Greater', 'x', 4]));
836-
ce.box('x').type.toString() // Returns: "unknown"
837-
838-
ce.assume(ce.box(['Equal', 'one', 1]));
839-
ce.box('one').type.toString() // Returns: "unknown"
840-
```
841-
842-
**Expected behavior:**
843-
844-
```typescript
845-
ce.assume(ce.box(['Greater', 'x', 4]));
846-
ce.box('x').type.toString() // Should return: "real" (inequalities imply real numbers)
847-
848-
ce.assume(ce.box(['Equal', 'one', 1]));
849-
ce.box('one').type.toString() // Should return: "integer" (equal to integer literal)
850-
```
851-
852-
**Implementation notes:**
853-
854-
- Inequality assumptions (`>`, `<`, `>=`, `<=`) imply the symbol is `real`
855-
- Equality to an integer implies the symbol is `integer`
856-
- Equality to a rational implies the symbol is `rational`
857-
- This might be handled by updating the symbol's type when an assumption is made
858-
- Alternatively, the type getter could query assumptions
859-
860-
**Files to investigate:**
861-
862-
- `src/compute-engine/assume.ts` - Assumption processing
863-
- `src/compute-engine/boxed-expression/boxed-symbol.ts` - Symbol type resolution
864-
865-
**Tests:** `test/compute-engine/assumptions.test.ts` - "TYPE INFERENCE FROM
866-
ASSUMPTIONS"
789+
See `requirements/DONE.md` for implementation details.
867790

868791
---
869792

0 commit comments

Comments
 (0)