Skip to content

Commit ec19cdd

Browse files
committed
fix: fixed #180
1 parent 8ea4b69 commit ec19cdd

7 files changed

Lines changed: 950 additions & 0 deletions

File tree

POLYNOMIAL_FACTORING.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Polynomial Factoring Implementation (#33)
2+
3+
This document summarizes the polynomial factoring implementation for issue #33 and issue #180.
4+
5+
## Overview
6+
7+
Implemented polynomial factoring algorithms to enable simplification of expressions like `sqrt(x²+2x+1)``|x+1|`.
8+
9+
## Features Implemented
10+
11+
### 1. Perfect Square Trinomial Factoring
12+
13+
Detects and factors patterns like:
14+
- `a² + 2ab + b²``(a+b)²`
15+
- `a² - 2ab + b²``(a-b)²`
16+
17+
Examples:
18+
```typescript
19+
sqrt(x² + 2x + 1) → |x+1|
20+
sqrt(x² - 2x + 1) → |x-1|
21+
sqrt(4x² + 12x + 9) → |2x+3|
22+
sqrt(a² + 2ab + b²) → |a+b|
23+
```
24+
25+
### 2. Difference of Squares Factoring
26+
27+
Detects and factors patterns like:
28+
- `a² - b²``(a-b)(a+b)`
29+
30+
Examples:
31+
```typescript
32+
x² - 4 → (x-2)(x+2)
33+
4x² - 9 → (2x-3)(2x+3)
34+
```
35+
36+
### 3. Quadratic Factoring with Rational Roots
37+
38+
Factors quadratics using the quadratic formula when roots are rational:
39+
- `ax² + bx + c``a(x - r₁)(x - r₂)`
40+
41+
Examples:
42+
```typescript
43+
x² + 5x + 6 → (x+2)(x+3)
44+
x² - 5x + 6 → (x-2)(x-3)
45+
```
46+
47+
Note: Quadratics with irrational roots (like `x² + 2x - 1`) are not factored.
48+
49+
## Integration with sqrt Simplification
50+
51+
The factoring is automatically applied when simplifying square root expressions. Before applying the `sqrt(x²) → |x|` rule, the system now tries to factor the argument:
52+
53+
```typescript
54+
// Before factoring implementation:
55+
sqrt(x² + 2x + 1) → sqrt(x² + 2x + 1) // No simplification
56+
57+
// After factoring implementation:
58+
sqrt(x² + 2x + 1) → |x+1| // Factors to (x+1)², then applies sqrt rule
59+
```
60+
61+
This fixes issue #180.
62+
63+
## API
64+
65+
### Exported Functions
66+
67+
```typescript
68+
import {
69+
factorPerfectSquare,
70+
factorDifferenceOfSquares,
71+
factorQuadratic,
72+
factorPolynomial,
73+
} from '@cortex-js/compute-engine';
74+
75+
// Factor perfect square trinomials
76+
factorPerfectSquare(expr: BoxedExpression): BoxedExpression | null
77+
78+
// Factor difference of squares
79+
factorDifferenceOfSquares(expr: BoxedExpression): BoxedExpression | null
80+
81+
// Factor quadratics with rational roots
82+
factorQuadratic(expr: BoxedExpression, variable: string): BoxedExpression | null
83+
84+
// General polynomial factoring (tries all strategies)
85+
factorPolynomial(expr: BoxedExpression, variable?: string): BoxedExpression
86+
```
87+
88+
### Usage Examples
89+
90+
```typescript
91+
const ce = new ComputeEngine();
92+
93+
// Automatic factoring in sqrt simplification
94+
const expr1 = ce.parse('\\sqrt{x^2 + 2x + 1}').simplify();
95+
console.log(expr1.latex); // \vert x+1\vert
96+
97+
// Manual factoring
98+
import { factorPerfectSquare } from '@cortex-js/compute-engine';
99+
100+
const expr2 = ce.parse('x^2 + 2x + 1');
101+
const factored = factorPerfectSquare(expr2);
102+
console.log(factored?.latex); // (x+1)^2
103+
```
104+
105+
## Implementation Details
106+
107+
### Files Modified
108+
109+
1. **src/compute-engine/boxed-expression/factor.ts**
110+
- Added `factorPerfectSquare()` - detects perfect square trinomials
111+
- Added `factorDifferenceOfSquares()` - detects difference of squares
112+
- Added `factorQuadratic()` - factors using quadratic formula for rational roots
113+
- Added `factorPolynomial()` - general factoring dispatcher
114+
- Added `extractSquareRoot()` - helper to extract square roots safely
115+
116+
2. **src/compute-engine/symbolic/simplify-power.ts**
117+
- Integrated factoring into sqrt simplification
118+
- Added perfect square and difference of squares checks before applying sqrt rules
119+
120+
3. **src/compute-engine/index.ts**
121+
- Exported new factoring functions for public API
122+
123+
### Key Implementation Considerations
124+
125+
1. **No .simplify() calls in factoring functions**
126+
- To avoid infinite recursion, factoring functions don't call `.simplify()` on their results
127+
- However, `.simplify()` is called on individual square roots during extraction, which is safe
128+
- See CLAUDE.md section "Simplification and Recursion Prevention" for details
129+
130+
2. **Handling different representations**
131+
- `4x²` is represented as `Multiply(4, Power(x, 2))`, not `Power(2x, 2)`
132+
- The implementation uses `.sqrt().simplify()` to extract square roots properly
133+
- Handles both symbolic (√x²) and numeric (√4) perfect squares
134+
135+
3. **Irrational root filtering**
136+
- Quadratic factoring checks for radical components in discriminant and roots
137+
- Uses `numericValue.radical` property to detect irrational square roots
138+
- Only factors when roots are provably rational
139+
140+
## Tests
141+
142+
Comprehensive test suite in `test/compute-engine/factor.test.ts`:
143+
- Perfect square trinomial tests (6 tests)
144+
- Difference of squares tests (6 tests)
145+
- Quadratic factoring tests (8 tests)
146+
- General polynomial factoring tests (4 tests)
147+
- Integration with sqrt simplification (8 tests)
148+
- Issue #180 regression tests (3 tests)
149+
150+
All tests passing ✓
151+
152+
## Performance
153+
154+
The factoring algorithms are O(1) for checking patterns:
155+
- Perfect square: O(1) - checks 3 terms
156+
- Difference of squares: O(1) - checks 2 terms
157+
- Quadratic factoring: O(1) - quadratic formula
158+
159+
The algorithms are called during simplification only when needed (sqrt of Add expressions).
160+
161+
## Future Enhancements
162+
163+
Potential improvements not yet implemented:
164+
1. Higher-degree polynomial factoring (cubic, quartic)
165+
2. Factoring over different domains (complex numbers, modular arithmetic)
166+
3. Multivariate polynomial factoring
167+
4. Kronecker's method for general factorization
168+
169+
## Related Issues
170+
171+
- Issue #180: "Factoring before trying to simplify" ✓ Fixed
172+
- Issue #33: "Polynomial Factoring" ✓ Implemented

examples/polynomial-factoring.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Polynomial Factoring Examples
2+
// Demonstrates the new polynomial factoring capabilities
3+
4+
import { ComputeEngine } from '../dist/compute-engine.esm.js';
5+
6+
const ce = new ComputeEngine();
7+
8+
console.log('='.repeat(60));
9+
console.log('POLYNOMIAL FACTORING EXAMPLES');
10+
console.log('='.repeat(60));
11+
12+
console.log('\n1. Perfect Square Trinomials');
13+
console.log('-'.repeat(40));
14+
console.log('sqrt(x² + 2x + 1) =', ce.parse('\\sqrt{x^2 + 2x + 1}').simplify().latex);
15+
console.log('sqrt(x² - 2x + 1) =', ce.parse('\\sqrt{x^2 - 2x + 1}').simplify().latex);
16+
console.log('sqrt(a² + 2ab + b²) =', ce.parse('\\sqrt{a^2 + 2ab + b^2}').simplify().latex);
17+
console.log('sqrt(a² - 2ab + b²) =', ce.parse('\\sqrt{a^2 - 2ab + b^2}').simplify().latex);
18+
19+
console.log('\n2. Perfect Squares with Coefficients');
20+
console.log('-'.repeat(40));
21+
console.log('sqrt(4x² + 12x + 9) =', ce.parse('\\sqrt{4x^2 + 12x + 9}').simplify().latex);
22+
console.log('sqrt(4x² - 12x + 9) =', ce.parse('\\sqrt{4x^2 - 12x + 9}').simplify().latex);
23+
console.log('sqrt(9x² + 6x + 1) =', ce.parse('\\sqrt{9x^2 + 6x + 1}').simplify().latex);
24+
25+
console.log('\n3. Difference of Squares');
26+
console.log('-'.repeat(40));
27+
console.log('sqrt((x² - 4)(x² + 4)) =', ce.parse('\\sqrt{(x^2 - 4)(x^2 + 4)}').simplify().latex);
28+
console.log('sqrt((x - 2)(x + 2)) =', ce.parse('\\sqrt{(x - 2)(x + 2)}').simplify().latex);
29+
30+
console.log('\n4. Non-Perfect Squares (unchanged)');
31+
console.log('-'.repeat(40));
32+
console.log('sqrt(x² + 3x + 1) =', ce.parse('\\sqrt{x^2 + 3x + 1}').simplify().latex);
33+
console.log('sqrt(x² + x + 1) =', ce.parse('\\sqrt{x^2 + x + 1}').simplify().latex);
34+
35+
console.log('\n5. Issue #180 Examples');
36+
console.log('-'.repeat(40));
37+
console.log('Expanded form: sqrt(x² + 2x + 1) =', ce.parse('\\sqrt{x^2+2x+1}').simplify().latex);
38+
console.log('Factored form: sqrt((x+1)²) =', ce.parse('\\sqrt{(x+1)^2}').simplify().latex);
39+
console.log('Both now simplify to: |x+1|');
40+
41+
console.log('\n6. Using the factorPolynomial Function');
42+
console.log('-'.repeat(40));
43+
44+
import {
45+
factorPerfectSquare,
46+
factorDifferenceOfSquares,
47+
factorQuadratic,
48+
factorPolynomial,
49+
} from '../dist/compute-engine.esm.js';
50+
51+
const expr1 = ce.parse('x^2 + 2x + 1');
52+
console.log('x² + 2x + 1 factored:', factorPerfectSquare(expr1)?.latex || 'null');
53+
54+
const expr2 = ce.parse('x^2 - 4');
55+
console.log('x² - 4 factored:', factorDifferenceOfSquares(expr2)?.latex || 'null');
56+
57+
const expr3 = ce.parse('x^2 + 5x + 6');
58+
console.log('x² + 5x + 6 factored:', factorQuadratic(expr3, 'x')?.latex || 'null');
59+
60+
const expr4 = ce.parse('4x^2 + 12x + 9');
61+
console.log('4x² + 12x + 9 factored:', factorPolynomial(expr4)?.latex || 'null');
62+
63+
console.log('\n' + '='.repeat(60));
64+
console.log('All examples completed successfully!');
65+
console.log('='.repeat(60));

examples/polynomial-factoring.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Polynomial Factoring Examples
2+
// Demonstrates the new polynomial factoring capabilities
3+
// Run with: npx tsx examples/polynomial-factoring.ts
4+
5+
import { ComputeEngine } from '../src/compute-engine/index.ts';
6+
import {
7+
factorPerfectSquare,
8+
factorDifferenceOfSquares,
9+
factorQuadratic,
10+
factorPolynomial,
11+
} from '../src/compute-engine/boxed-expression/factor.ts';
12+
13+
const ce = new ComputeEngine();
14+
15+
console.log('='.repeat(60));
16+
console.log('POLYNOMIAL FACTORING EXAMPLES');
17+
console.log('='.repeat(60));
18+
19+
console.log('\n1. Perfect Square Trinomials');
20+
console.log('-'.repeat(40));
21+
console.log('sqrt(x² + 2x + 1) =', ce.parse('\\sqrt{x^2 + 2x + 1}').simplify().latex);
22+
console.log('sqrt(x² - 2x + 1) =', ce.parse('\\sqrt{x^2 - 2x + 1}').simplify().latex);
23+
console.log('sqrt(a² + 2ab + b²) =', ce.parse('\\sqrt{a^2 + 2ab + b^2}').simplify().latex);
24+
console.log('sqrt(a² - 2ab + b²) =', ce.parse('\\sqrt{a^2 - 2ab + b^2}').simplify().latex);
25+
26+
console.log('\n2. Perfect Squares with Coefficients');
27+
console.log('-'.repeat(40));
28+
console.log('sqrt(4x² + 12x + 9) =', ce.parse('\\sqrt{4x^2 + 12x + 9}').simplify().latex);
29+
console.log('sqrt(4x² - 12x + 9) =', ce.parse('\\sqrt{4x^2 - 12x + 9}').simplify().latex);
30+
console.log('sqrt(9x² + 6x + 1) =', ce.parse('\\sqrt{9x^2 + 6x + 1}').simplify().latex);
31+
32+
console.log('\n3. Non-Perfect Squares (unchanged)');
33+
console.log('-'.repeat(40));
34+
console.log('sqrt(x² + 3x + 1) =', ce.parse('\\sqrt{x^2 + 3x + 1}').simplify().latex);
35+
console.log('sqrt(x² + x + 1) =', ce.parse('\\sqrt{x^2 + x + 1}').simplify().latex);
36+
37+
console.log('\n4. Issue #180 Examples');
38+
console.log('-'.repeat(40));
39+
console.log('Expanded form: sqrt(x² + 2x + 1) =', ce.parse('\\sqrt{x^2+2x+1}').simplify().latex);
40+
console.log('Factored form: sqrt((x+1)²) =', ce.parse('\\sqrt{(x+1)^2}').simplify().latex);
41+
console.log('Both now simplify to: |x+1|');
42+
43+
console.log('\n5. Using the factorPolynomial Function');
44+
console.log('-'.repeat(40));
45+
46+
const expr1 = ce.parse('x^2 + 2x + 1');
47+
console.log('x² + 2x + 1 factored:', factorPerfectSquare(expr1)?.latex || 'null');
48+
49+
const expr2 = ce.parse('x^2 - 4');
50+
console.log('x² - 4 factored:', factorDifferenceOfSquares(expr2)?.latex || 'null');
51+
52+
const expr3 = ce.parse('x^2 + 5x + 6');
53+
console.log('x² + 5x + 6 factored:', factorQuadratic(expr3, 'x')?.latex || 'null');
54+
55+
const expr4 = ce.parse('4x^2 + 12x + 9');
56+
console.log('4x² + 12x + 9 factored:', factorPolynomial(expr4)?.latex || 'null');
57+
58+
console.log('\n' + '='.repeat(60));
59+
console.log('All examples completed successfully!');
60+
console.log('='.repeat(60));

0 commit comments

Comments
 (0)