slangmath 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/slang-basic.js ADDED
@@ -0,0 +1,766 @@
1
+ /**
2
+ * SLaNg (Saad Language for Analytical Numerics and Geometry) - Math Library
3
+ * Enhanced with full denominator support and improved calculus operations
4
+ *
5
+ */
6
+
7
+ // ============================================================================
8
+ // DEEP COPY UTILITIES
9
+ // ============================================================================
10
+
11
+ /**
12
+ * Deep clone an equation to avoid mutation
13
+ */
14
+ function deepClone(obj) {
15
+ return JSON.parse(JSON.stringify(obj));
16
+ }
17
+
18
+ // ============================================================================
19
+ // TERM CREATION UTILITIES
20
+ // ============================================================================
21
+
22
+ /**
23
+ * Create a term with coefficient and optional variables
24
+ * @param {number} coeff - Coefficient
25
+ * @param {Object} vars - Variables object like {x: 2, y: 1}
26
+ */
27
+ function createTerm(coeff, vars = {}) {
28
+ const term = { coeff };
29
+ if (Object.keys(vars).length > 0) {
30
+ term.var = { ...vars };
31
+ }
32
+ return term;
33
+ }
34
+
35
+ /**
36
+ * Create a fraction with polynomial numerator and denominator
37
+ * @param {Array} numiTerms - Array of terms for numerator
38
+ * @param {Array|number} denoTerms - Array of terms for denominator OR simple number
39
+ *
40
+ *: Full support for polynomial denominators
41
+ */
42
+ function createFraction(numiTerms, denoTerms = 1) {
43
+ const fraction = {
44
+ numi: { terms: deepClone(numiTerms) }
45
+ };
46
+
47
+ // Support both old (number) and new (polynomial) denominators
48
+ if (typeof denoTerms === 'number') {
49
+ fraction.deno = denoTerms;
50
+ } else if (Array.isArray(denoTerms)) {
51
+ fraction.deno = { terms: deepClone(denoTerms) };
52
+ } else if (denoTerms.terms) {
53
+ fraction.deno = { terms: deepClone(denoTerms.terms) };
54
+ }
55
+
56
+ return fraction;
57
+ }
58
+
59
+ /**
60
+ * Check if denominator is a simple number
61
+ */
62
+ function hasSimpleDenominator(fraction) {
63
+ return typeof fraction.deno === 'number';
64
+ }
65
+
66
+ /**
67
+ * Get GCD of two numbers for simplification
68
+ */
69
+ function gcd(a, b) {
70
+ a = Math.abs(a);
71
+ b = Math.abs(b);
72
+ while (b) {
73
+ [a, b] = [b, a % b];
74
+ }
75
+ return a || 1;
76
+ }
77
+
78
+ // ============================================================================
79
+ // EVALUATION FUNCTIONS
80
+ // ============================================================================
81
+
82
+ /**
83
+ * Evaluate a term at given variable values
84
+ * @param {Object} term - A single term
85
+ * @param {Object} values - Variable values like {x: 2, y: 3}
86
+ */
87
+ function evaluateTerm(term, values) {
88
+ let result = term.coeff;
89
+
90
+ if (term.var) {
91
+ for (let [variable, power] of Object.entries(term.var)) {
92
+ if (values[variable] === undefined) {
93
+ throw new Error(`Variable ${variable} not provided`);
94
+ }
95
+ result *= Math.pow(values[variable], power);
96
+ }
97
+ }
98
+
99
+ return result;
100
+ }
101
+
102
+ /**
103
+ * Evaluate polynomial (array of terms)
104
+ */
105
+ function evaluatePolynomial(polynomial, values) {
106
+ let sum = 0;
107
+ for (let term of polynomial.terms) {
108
+ sum += evaluateTerm(term, values);
109
+ }
110
+ return sum;
111
+ }
112
+
113
+ /**
114
+ * Evaluate a fraction (numerator / denominator)
115
+ *: Supports polynomial denominators
116
+ */
117
+ function evaluateFraction(fraction, values) {
118
+ const numeratorSum = evaluatePolynomial(fraction.numi, values);
119
+
120
+ if (hasSimpleDenominator(fraction)) {
121
+ return numeratorSum / fraction.deno;
122
+ } else {
123
+ const denominatorSum = evaluatePolynomial(fraction.deno, values);
124
+ return numeratorSum / denominatorSum;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Evaluate a product (array of fractions multiplied together)
130
+ */
131
+ function evaluateProduct(product, values) {
132
+ let result = 1;
133
+ for (let fraction of product) {
134
+ result *= evaluateFraction(fraction, values);
135
+ }
136
+ return result;
137
+ }
138
+
139
+ /**
140
+ * Evaluate entire equation (sum of products)
141
+ */
142
+ function evaluateEquation(equation, values) {
143
+ let result = 0;
144
+ for (let product of equation) {
145
+ result += evaluateProduct(product, values);
146
+ }
147
+ return result;
148
+ }
149
+
150
+ // ============================================================================
151
+ // INTEGRATION FUNCTIONS - ENHANCED
152
+ // ============================================================================
153
+
154
+ /**
155
+ * Integrate a single term with respect to a variable
156
+ * Power rule: ∫ c*x^n dx = c/(n+1) * x^(n+1)
157
+ */
158
+ function integrateTerm(term, indvar) {
159
+ const newTerm = deepClone(term);
160
+
161
+ // Get current power of the variable (0 if not present)
162
+ const power = newTerm.var?.[indvar] ?? 0;
163
+
164
+ // Check for special case: x^(-1) -> ln|x| (not handled symbolically yet)
165
+ if (power === -1) {
166
+ throw new Error('Integration of 1/x requires logarithm (not yet implemented)');
167
+ }
168
+
169
+ // Apply power rule
170
+ newTerm.coeff = newTerm.coeff / (power + 1);
171
+
172
+ // Increment power
173
+ if (!newTerm.var) {
174
+ newTerm.var = {};
175
+ }
176
+ newTerm.var[indvar] = power + 1;
177
+
178
+ return newTerm;
179
+ }
180
+
181
+ /**
182
+ * Integrate a polynomial
183
+ */
184
+ function integratePolynomial(polynomial, indvar) {
185
+ return {
186
+ terms: polynomial.terms.map(term => integrateTerm(term, indvar))
187
+ };
188
+ }
189
+
190
+ /**
191
+ * Integrate a fraction
192
+ *: Improved handling of different denominator types
193
+ */
194
+ function integrateFraction(fraction, indvar) {
195
+ if (hasSimpleDenominator(fraction)) {
196
+ // Simple case: polynomial / constant
197
+ return {
198
+ numi: integratePolynomial(fraction.numi, indvar),
199
+ deno: fraction.deno
200
+ };
201
+ } else {
202
+ // Complex case: polynomial / polynomial
203
+ // This requires more advanced techniques
204
+
205
+ // Check if it's a simple substitution case
206
+ if (isSimpleSubstitutionCase(fraction, indvar)) {
207
+ return integrateBySubstitution(fraction, indvar);
208
+ }
209
+
210
+ // Otherwise, try partial fractions or numerical methods
211
+ throw new Error(
212
+ 'Integration of complex rational functions requires partial fractions or numerical methods. ' +
213
+ 'Use numericalIntegrateFraction() instead.'
214
+ );
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Check if fraction can be integrated by simple substitution
220
+ * e.g., ∫ 2x/(x²+1) dx where numerator is derivative of denominator
221
+ */
222
+ function isSimpleSubstitutionCase(fraction, indvar) {
223
+ if (hasSimpleDenominator(fraction)) return false;
224
+
225
+ // Differentiate denominator
226
+ const denoDeriv = differentiatePolynomial(fraction.deno, indvar);
227
+
228
+ // Check if numerator is a constant multiple of denominator derivative
229
+ if (fraction.numi.terms.length !== denoDeriv.terms.length) return false;
230
+
231
+ // More sophisticated check would go here
232
+ return false; // Conservative for now
233
+ }
234
+
235
+ /**
236
+ * Definite integration of a term
237
+ * Evaluates ∫[lower to upper] term dx
238
+ */
239
+ function definiteIntegrateTerm(term, lower, upper, indvar) {
240
+ const integratedTerm = integrateTerm(term, indvar);
241
+
242
+ // Get power of integration variable in the integrated term
243
+ const intPower = integratedTerm.var?.[indvar] ?? 0;
244
+
245
+ // Calculate the coefficient multiplier from bounds
246
+ const upperValue = Math.pow(upper, intPower);
247
+ const lowerValue = Math.pow(lower, intPower);
248
+ const boundsDiff = upperValue - lowerValue;
249
+
250
+ // Create result term
251
+ const resultTerm = deepClone(integratedTerm);
252
+ resultTerm.coeff = resultTerm.coeff * boundsDiff;
253
+
254
+ // Remove the integration variable
255
+ if (resultTerm.var) {
256
+ delete resultTerm.var[indvar];
257
+ if (Object.keys(resultTerm.var).length === 0) {
258
+ delete resultTerm.var;
259
+ }
260
+ }
261
+
262
+ return resultTerm;
263
+ }
264
+
265
+ /**
266
+ * Definite integration of a polynomial
267
+ */
268
+ function definiteIntegratePolynomial(polynomial, lower, upper, indvar) {
269
+ return {
270
+ terms: polynomial.terms.map(term =>
271
+ definiteIntegrateTerm(term, lower, upper, indvar)
272
+ )
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Definite integration of a fraction
278
+ *: Better handling for different denominator types
279
+ */
280
+ function definiteIntegrateFraction(fraction, lower, upper, indvar) {
281
+ if (hasSimpleDenominator(fraction)) {
282
+ // Simple case
283
+ return {
284
+ numi: definiteIntegratePolynomial(fraction.numi, lower, upper, indvar),
285
+ deno: fraction.deno
286
+ };
287
+ } else {
288
+ // For polynomial denominators, use numerical integration
289
+ return numericalIntegrateFraction(fraction, lower, upper, indvar);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Numerical integration using Simpson's rule (more accurate than rectangles)
295
+ *: Enhanced numerical integration
296
+ */
297
+ function numericalIntegrateFraction(fraction, lower, upper, indvar, numSteps = 1000) {
298
+ // Simpson's rule requires even number of steps
299
+ if (numSteps % 2 !== 0) numSteps++;
300
+
301
+ const h = (upper - lower) / numSteps;
302
+ let sum = 0;
303
+
304
+ // Simpson's rule: h/3 * [f(x0) + 4*f(x1) + 2*f(x2) + 4*f(x3) + ... + f(xn)]
305
+ for (let i = 0; i <= numSteps; i++) {
306
+ const x = lower + i * h;
307
+ const point = { [indvar]: x };
308
+ const value = evaluateFraction(fraction, point);
309
+
310
+ if (i === 0 || i === numSteps) {
311
+ sum += value;
312
+ } else if (i % 2 === 1) {
313
+ sum += 4 * value;
314
+ } else {
315
+ sum += 2 * value;
316
+ }
317
+ }
318
+
319
+ const result = (h / 3) * sum;
320
+
321
+ // Return as a constant term
322
+ return {
323
+ numi: { terms: [createTerm(result)] },
324
+ deno: 1
325
+ };
326
+ }
327
+
328
+ // ============================================================================
329
+ // DIFFERENTIATION FUNCTIONS - ENHANCED
330
+ // ============================================================================
331
+
332
+ /**
333
+ * Differentiate a term with respect to a variable
334
+ * Power rule: d/dx(c*x^n) = c*n*x^(n-1)
335
+ */
336
+ function differentiateTerm(term, indvar) {
337
+ const newTerm = deepClone(term);
338
+
339
+ // Get current power
340
+ const power = newTerm.var?.[indvar];
341
+
342
+ // If variable not present, derivative is 0
343
+ if (power === undefined) {
344
+ return createTerm(0);
345
+ }
346
+
347
+ // Apply power rule
348
+ newTerm.coeff = newTerm.coeff * power;
349
+
350
+ // Decrease power
351
+ if (power === 1) {
352
+ delete newTerm.var[indvar];
353
+ if (Object.keys(newTerm.var).length === 0) {
354
+ delete newTerm.var;
355
+ }
356
+ } else {
357
+ newTerm.var[indvar] = power - 1;
358
+ }
359
+
360
+ return newTerm;
361
+ }
362
+
363
+ /**
364
+ * Differentiate a polynomial
365
+ */
366
+ function differentiatePolynomial(polynomial, indvar) {
367
+ return {
368
+ terms: polynomial.terms
369
+ .map(term => differentiateTerm(term, indvar))
370
+ .filter(term => term.coeff !== 0)
371
+ };
372
+ }
373
+
374
+ /**
375
+ * Differentiate a fraction using quotient rule
376
+ *: Full quotient rule for polynomial denominators
377
+ *
378
+ * d/dx[f/g] = (f'g - fg') / g²
379
+ */
380
+ function differentiateFraction(fraction, indvar) {
381
+ if (hasSimpleDenominator(fraction)) {
382
+ // Simple case: just differentiate numerator, keep constant denominator
383
+ return {
384
+ numi: differentiatePolynomial(fraction.numi, indvar),
385
+ deno: fraction.deno
386
+ };
387
+ } else {
388
+ // Quotient rule for polynomial denominator
389
+ const f = fraction.numi;
390
+ const g = fraction.deno;
391
+
392
+ const fPrime = differentiatePolynomial(f, indvar);
393
+ const gPrime = differentiatePolynomial(g, indvar);
394
+
395
+ // f' * g
396
+ const fPrimeTimesG = multiplyPolynomials(fPrime, g);
397
+
398
+ // f * g'
399
+ const fTimesGPrime = multiplyPolynomials(f, gPrime);
400
+
401
+ // f'g - fg'
402
+ const numerator = subtractPolynomials(fPrimeTimesG, fTimesGPrime);
403
+
404
+ // g²
405
+ const denominator = multiplyPolynomials(g, g);
406
+
407
+ return {
408
+ numi: numerator,
409
+ deno: denominator
410
+ };
411
+ }
412
+ }
413
+
414
+ // ============================================================================
415
+ // POLYNOMIAL ARITHMETIC -
416
+ // ============================================================================
417
+
418
+ /**
419
+ * Add two polynomials
420
+ */
421
+ function addPolynomials(poly1, poly2) {
422
+ return {
423
+ terms: [...poly1.terms, ...poly2.terms]
424
+ };
425
+ }
426
+
427
+ /**
428
+ * Subtract two polynomials
429
+ */
430
+ function subtractPolynomials(poly1, poly2) {
431
+ const negatedPoly2 = {
432
+ terms: poly2.terms.map(t => ({ ...deepClone(t), coeff: -t.coeff }))
433
+ };
434
+ return addPolynomials(poly1, negatedPoly2);
435
+ }
436
+
437
+ /**
438
+ * Multiply two terms together
439
+ */
440
+ function multiplyTerms(term1, term2) {
441
+ const result = {
442
+ coeff: term1.coeff * term2.coeff
443
+ };
444
+
445
+ // Combine variables (add exponents for same variable)
446
+ const vars = {};
447
+
448
+ if (term1.var) {
449
+ for (let [v, pow] of Object.entries(term1.var)) {
450
+ vars[v] = pow;
451
+ }
452
+ }
453
+
454
+ if (term2.var) {
455
+ for (let [v, pow] of Object.entries(term2.var)) {
456
+ vars[v] = (vars[v] || 0) + pow;
457
+ }
458
+ }
459
+
460
+ if (Object.keys(vars).length > 0) {
461
+ result.var = vars;
462
+ }
463
+
464
+ return result;
465
+ }
466
+
467
+ /**
468
+ * Multiply two polynomials
469
+ *: Essential for quotient rule
470
+ */
471
+ function multiplyPolynomials(poly1, poly2) {
472
+ const resultTerms = [];
473
+
474
+ for (let term1 of poly1.terms) {
475
+ for (let term2 of poly2.terms) {
476
+ resultTerms.push(multiplyTerms(term1, term2));
477
+ }
478
+ }
479
+
480
+ return { terms: resultTerms };
481
+ }
482
+
483
+ // ============================================================================
484
+ // SIMPLIFICATION FUNCTIONS - ENHANCED
485
+ // ============================================================================
486
+
487
+ /**
488
+ * Combine like terms in a polynomial
489
+ */
490
+ function simplifyPolynomial(polynomial) {
491
+ const termMap = new Map();
492
+
493
+ for (let term of polynomial.terms) {
494
+ const varKey = term.var ? JSON.stringify(term.var) : 'constant';
495
+
496
+ if (termMap.has(varKey)) {
497
+ termMap.get(varKey).coeff += term.coeff;
498
+ } else {
499
+ termMap.set(varKey, deepClone(term));
500
+ }
501
+ }
502
+
503
+ // Filter out zero terms and sort for consistency
504
+ const simplifiedTerms = Array.from(termMap.values())
505
+ .filter(term => Math.abs(term.coeff) > 1e-10)
506
+ .sort((a, b) => {
507
+ // Sort by total degree (descending)
508
+ const degreeA = a.var ? Object.values(a.var).reduce((sum, p) => sum + p, 0) : 0;
509
+ const degreeB = b.var ? Object.values(b.var).reduce((sum, p) => sum + p, 0) : 0;
510
+ return degreeB - degreeA;
511
+ });
512
+
513
+ return { terms: simplifiedTerms };
514
+ }
515
+
516
+ /**
517
+ * Simplify a fraction
518
+ *: Enhanced to handle polynomial denominators
519
+ */
520
+ function simplifyFraction(fraction) {
521
+ const simplifiedNumi = simplifyPolynomial(fraction.numi);
522
+
523
+ if (hasSimpleDenominator(fraction)) {
524
+ // Try to simplify constant denominator with GCD
525
+ if (simplifiedNumi.terms.length > 0) {
526
+ const coeffs = simplifiedNumi.terms.map(t => t.coeff);
527
+ const numGCD = coeffs.reduce((a, b) => gcd(a, b));
528
+ const denoGCD = gcd(numGCD, fraction.deno);
529
+
530
+ if (denoGCD > 1) {
531
+ return {
532
+ numi: {
533
+ terms: simplifiedNumi.terms.map(t => ({
534
+ ...deepClone(t),
535
+ coeff: t.coeff / denoGCD
536
+ }))
537
+ },
538
+ deno: fraction.deno / denoGCD
539
+ };
540
+ }
541
+ }
542
+
543
+ return {
544
+ numi: simplifiedNumi,
545
+ deno: fraction.deno
546
+ };
547
+ } else {
548
+ // Simplify both numerator and denominator
549
+ const simplifiedDeno = simplifyPolynomial(fraction.deno);
550
+
551
+ // TODO: Factor and cancel common factors
552
+ return {
553
+ numi: simplifiedNumi,
554
+ deno: simplifiedDeno
555
+ };
556
+ }
557
+ }
558
+
559
+ /**
560
+ * Simplify an entire product
561
+ */
562
+ function simplifyProduct(product) {
563
+ return product.map(fraction => simplifyFraction(fraction));
564
+ }
565
+
566
+ /**
567
+ * Simplify entire equation
568
+ */
569
+ function simplifyEquation(equation) {
570
+ return equation.map(product => simplifyProduct(product));
571
+ }
572
+
573
+ // ============================================================================
574
+ // EXPANSION FUNCTIONS
575
+ // ============================================================================
576
+
577
+ /**
578
+ * Expand product of two fractions (both with simple denominators)
579
+ * (a + b)(c + d) = ac + ad + bc + bd
580
+ */
581
+ function expandFractions(frac1, frac2) {
582
+ const numi1 = frac1.numi;
583
+ const numi2 = frac2.numi;
584
+
585
+ const expandedNumi = multiplyPolynomials(numi1, numi2);
586
+
587
+ // Handle denominators
588
+ let newDeno;
589
+ if (hasSimpleDenominator(frac1) && hasSimpleDenominator(frac2)) {
590
+ newDeno = frac1.deno * frac2.deno;
591
+ } else if (hasSimpleDenominator(frac1) && !hasSimpleDenominator(frac2)) {
592
+ newDeno = multiplyPolynomialByConstant(frac2.deno, frac1.deno);
593
+ } else if (!hasSimpleDenominator(frac1) && hasSimpleDenominator(frac2)) {
594
+ newDeno = multiplyPolynomialByConstant(frac1.deno, frac2.deno);
595
+ } else {
596
+ newDeno = multiplyPolynomials(frac1.deno, frac2.deno);
597
+ }
598
+
599
+ return simplifyFraction({
600
+ numi: expandedNumi,
601
+ deno: newDeno
602
+ });
603
+ }
604
+
605
+ /**
606
+ * Multiply polynomial by constant
607
+ */
608
+ function multiplyPolynomialByConstant(polynomial, constant) {
609
+ return {
610
+ terms: polynomial.terms.map(t => ({ ...deepClone(t), coeff: t.coeff * constant }))
611
+ };
612
+ }
613
+
614
+ /**
615
+ * Expand a product into a single fraction
616
+ */
617
+ function expandProduct(product) {
618
+ if (product.length === 0) {
619
+ return createFraction([createTerm(1)]);
620
+ }
621
+
622
+ let result = product[0];
623
+
624
+ for (let i = 1; i < product.length; i++) {
625
+ result = expandFractions(result, product[i]);
626
+ }
627
+
628
+ return result;
629
+ }
630
+
631
+ // ============================================================================
632
+ // DISPLAY FUNCTIONS
633
+ // ============================================================================
634
+
635
+ /**
636
+ * Convert term to readable string
637
+ */
638
+ function termToString(term) {
639
+ let str = '';
640
+
641
+ // Handle coefficient
642
+ if (term.coeff === 0) return '0';
643
+ if (Math.abs(term.coeff - 1) < 1e-10 && term.var) {
644
+ str = '';
645
+ } else if (Math.abs(term.coeff + 1) < 1e-10 && term.var) {
646
+ str = '-';
647
+ } else {
648
+ str = term.coeff.toString();
649
+ }
650
+
651
+ // Handle variables
652
+ if (term.var) {
653
+ const varStr = Object.entries(term.var)
654
+ .map(([variable, power]) => {
655
+ if (power === 1) return variable;
656
+ return `${variable}^${power}`;
657
+ })
658
+ .join('*');
659
+ str += (str && str !== '-' ? '*' : '') + varStr;
660
+ }
661
+
662
+ return str || term.coeff.toString();
663
+ }
664
+
665
+ /**
666
+ * Convert polynomial to readable string
667
+ */
668
+ function polynomialToString(polynomial) {
669
+ if (!polynomial.terms || polynomial.terms.length === 0) return '0';
670
+
671
+ return polynomial.terms.map((term, i) => {
672
+ const termStr = termToString(term);
673
+ if (i === 0) return termStr;
674
+ if (term.coeff >= 0) return '+ ' + termStr;
675
+ return termStr; // Negative sign already in termStr
676
+ }).join(' ');
677
+ }
678
+
679
+ /**
680
+ * Convert fraction to readable string
681
+ */
682
+ function fractionToString(fraction) {
683
+ const numi = polynomialToString(fraction.numi);
684
+
685
+ if (hasSimpleDenominator(fraction)) {
686
+ if (fraction.deno === 1) {
687
+ return `(${numi})`;
688
+ }
689
+ return `(${numi})/${fraction.deno}`;
690
+ } else {
691
+ const deno = polynomialToString(fraction.deno);
692
+ return `(${numi})/(${deno})`;
693
+ }
694
+ }
695
+
696
+ /**
697
+ * Convert product to readable string
698
+ */
699
+ function productToString(product) {
700
+ return product.map(fractionToString).join(' * ');
701
+ }
702
+
703
+ /**
704
+ * Convert equation to readable string
705
+ */
706
+ function equationToString(equation) {
707
+ return equation.map(productToString).join(' + ');
708
+ }
709
+
710
+ // ============================================================================
711
+ // EXPORTS
712
+ // ============================================================================
713
+
714
+ export {
715
+ // Utilities
716
+ deepClone,
717
+ createTerm,
718
+ createFraction,
719
+ hasSimpleDenominator,
720
+ gcd,
721
+
722
+ // Evaluation
723
+ evaluateTerm,
724
+ evaluatePolynomial,
725
+ evaluateFraction,
726
+ evaluateProduct,
727
+ evaluateEquation,
728
+
729
+ // Integration
730
+ integrateTerm,
731
+ integratePolynomial,
732
+ integrateFraction,
733
+ definiteIntegrateTerm,
734
+ definiteIntegratePolynomial,
735
+ definiteIntegrateFraction,
736
+ numericalIntegrateFraction,
737
+
738
+ // Differentiation
739
+ differentiateTerm,
740
+ differentiatePolynomial,
741
+ differentiateFraction,
742
+
743
+ // Polynomial Arithmetic
744
+ addPolynomials,
745
+ subtractPolynomials,
746
+ multiplyTerms,
747
+ multiplyPolynomials,
748
+ multiplyPolynomialByConstant,
749
+
750
+ // Simplification
751
+ simplifyPolynomial,
752
+ simplifyFraction,
753
+ simplifyProduct,
754
+ simplifyEquation,
755
+
756
+ // Expansion
757
+ expandFractions,
758
+ expandProduct,
759
+
760
+ // Display
761
+ termToString,
762
+ polynomialToString,
763
+ fractionToString,
764
+ productToString,
765
+ equationToString
766
+ };