@@ -402,35 +402,31 @@ describe('EL-5: Non-enumerable domains stay symbolic', () => {
402402 expect ( result . isNaN ) . not . toBe ( true ) ;
403403 } ) ;
404404
405- test ( 'sum over NonNegativeIntegers (infinite set) stays symbolic' , ( ) => {
406- const expr = ce . box ( [ 'Sum' , 'n' , [ 'Element' , 'n' , 'NonNegativeIntegers' ] ] ) ;
407- const result = expr . evaluate ( ) ;
408- expect ( result . operator ) . toBe ( 'Sum' ) ;
409- expect ( result . isNaN ) . not . toBe ( true ) ;
410- } ) ;
405+ // EL-4: NonNegativeIntegers and PositiveIntegers can be converted to Limits
406+ // and will iterate (capped at MAX_ITERATION), so they evaluate to numbers
407+ // Other infinite sets (Integers, Reals) that can't be iterated stay symbolic
411408
412409 test ( 'sum over Integers (infinite set) stays symbolic' , ( ) => {
410+ // Integers is bidirectional, cannot be converted to forward iteration
413411 const expr = ce . box ( [ 'Sum' , 'n' , [ 'Element' , 'n' , 'Integers' ] ] ) ;
414412 const result = expr . evaluate ( ) ;
415413 expect ( result . operator ) . toBe ( 'Sum' ) ;
416414 expect ( result . isNaN ) . not . toBe ( true ) ;
417415 } ) ;
418416
419417 test ( 'sum over Reals (infinite set) stays symbolic' , ( ) => {
418+ // Reals is non-countable, cannot be iterated
420419 const expr = ce . box ( [ 'Sum' , 'x' , [ 'Element' , 'x' , 'Reals' ] ] ) ;
421420 const result = expr . evaluate ( ) ;
422421 expect ( result . operator ) . toBe ( 'Sum' ) ;
423422 expect ( result . isNaN ) . not . toBe ( true ) ;
424423 } ) ;
425424
426- test ( 'product over PositiveIntegers (infinite set) stays symbolic' , ( ) => {
427- const expr = ce . box ( [
428- 'Product' ,
429- 'k' ,
430- [ 'Element' , 'k' , 'PositiveIntegers' ] ,
431- ] ) ;
425+ test ( 'sum over NegativeIntegers (infinite set) stays symbolic' , ( ) => {
426+ // NegativeIntegers goes in the negative direction, can't be forward iterated
427+ const expr = ce . box ( [ 'Sum' , 'n' , [ 'Element' , 'n' , 'NegativeIntegers' ] ] ) ;
432428 const result = expr . evaluate ( ) ;
433- expect ( result . operator ) . toBe ( 'Product ' ) ;
429+ expect ( result . operator ) . toBe ( 'Sum ' ) ;
434430 expect ( result . isNaN ) . not . toBe ( true ) ;
435431 } ) ;
436432
@@ -451,6 +447,54 @@ describe('EL-5: Non-enumerable domains stay symbolic', () => {
451447 } ) ;
452448} ) ;
453449
450+ describe ( 'EL-4: Infinite series with Element notation' , ( ) => {
451+ // EL-4: NonNegativeIntegers and PositiveIntegers are converted to Limits form
452+ // and iterated (capped at MAX_ITERATION), behaving like traditional bounds notation
453+
454+ test ( 'sum over NonNegativeIntegers evaluates (converges to partial sum)' , ( ) => {
455+ // Sum n from 0 to MAX_ITERATION - should give a numeric result (triangular number approximation)
456+ // Note: This test verifies the behavior change, not the exact value
457+ const expr = ce . box ( [ 'Sum' , 'n' , [ 'Element' , 'n' , 'NonNegativeIntegers' ] ] ) ;
458+ const result = expr . evaluate ( ) ;
459+ // Should be a Number, not remain as Sum
460+ expect ( result . isNumber ) . toBe ( true ) ;
461+ expect ( result . operator ) . not . toBe ( 'Sum' ) ;
462+ expect ( result . isNaN ) . not . toBe ( true ) ;
463+ } , 15000 ) ; // Allow 15 seconds for iteration
464+
465+ test ( 'product over PositiveIntegers evaluates (converges to partial product)' , ( ) => {
466+ // Product k from 1 to MAX_ITERATION - should give a numeric result
467+ const expr = ce . box ( [
468+ 'Product' ,
469+ 'k' ,
470+ [ 'Element' , 'k' , 'PositiveIntegers' ] ,
471+ ] ) ;
472+ const result = expr . evaluate ( ) ;
473+ // Should be a Number, not remain as Product
474+ expect ( result . isNumber ) . toBe ( true ) ;
475+ expect ( result . operator ) . not . toBe ( 'Product' ) ;
476+ expect ( result . isNaN ) . not . toBe ( true ) ;
477+ } , 15000 ) ; // Allow 15 seconds for iteration
478+
479+ test ( 'convergent series over NonNegativeIntegers gives reasonable approximation' , ( ) => {
480+ // Sum 1/n^2 from 1 to infinity approaches π²/6 ≈ 1.6449
481+ // Using PositiveIntegers to avoid division by zero
482+ const expr = ce . box ( [
483+ 'Sum' ,
484+ [ 'Power' , 'n' , - 2 ] ,
485+ [ 'Element' , 'n' , 'PositiveIntegers' ] ,
486+ ] ) ;
487+ const result = expr . evaluate ( ) ;
488+ expect ( result . isNumber ) . toBe ( true ) ;
489+ // Should be close to π²/6 ≈ 1.6449
490+ // .re gives us the numeric value as a number
491+ const value = result . re ;
492+ expect ( typeof value ) . toBe ( 'number' ) ;
493+ expect ( value ) . toBeGreaterThan ( 1.6 ) ;
494+ expect ( value ) . toBeLessThan ( 1.7 ) ;
495+ } , 30000 ) ; // Allow 30 seconds for this computation
496+ } ) ;
497+
454498describe ( 'PRODUCT' , ( ) => {
455499 test ( 'k is an Integer (as the index) and used a a Number (in the fraction)' , ( ) => {
456500 expect ( evaluate ( `\\prod_{k=1}^{10}\\frac{k}{2}` ) ) . toMatchInlineSnapshot (
0 commit comments