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/ARCHITECTURE.MD +366 -0
- package/LICENSE +21 -0
- package/README.md +953 -0
- package/package.json +23 -0
- package/slang-advanced.js +559 -0
- package/slang-basic.js +766 -0
- package/slang-cache.js +519 -0
- package/slang-convertor.js +652 -0
- package/slang-errors.js +454 -0
- package/slang-extended.js +501 -0
- package/slang-helpers.js +284 -0
- package/slang-math.js +3 -0
package/slang-helpers.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLaNg Helper Utilities
|
|
3
|
+
* High-level helpers for common mathematical operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
createTerm,
|
|
8
|
+
createFraction,
|
|
9
|
+
definiteIntegrateFraction,
|
|
10
|
+
expandProduct,
|
|
11
|
+
simplifyFraction,
|
|
12
|
+
evaluateEquation,
|
|
13
|
+
differentiateFraction,
|
|
14
|
+
deepClone
|
|
15
|
+
} from './slang-math.js';
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// EQUATION BUILDERS
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a polynomial from coefficients
|
|
23
|
+
* @param {Array<number>} coeffs - Coefficients from highest to lowest degree
|
|
24
|
+
* @param {string} variable - Variable name (default 'x')
|
|
25
|
+
*
|
|
26
|
+
* Example: polynomial([1, -2, 1], 'x') creates x² - 2x + 1
|
|
27
|
+
*/
|
|
28
|
+
function polynomial(coeffs, variable = 'x') {
|
|
29
|
+
const terms = [];
|
|
30
|
+
const degree = coeffs.length - 1;
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < coeffs.length; i++) {
|
|
33
|
+
const power = degree - i;
|
|
34
|
+
const coeff = coeffs[i];
|
|
35
|
+
|
|
36
|
+
if (coeff === 0) continue;
|
|
37
|
+
|
|
38
|
+
if (power === 0) {
|
|
39
|
+
terms.push(createTerm(coeff));
|
|
40
|
+
} else {
|
|
41
|
+
terms.push(createTerm(coeff, { [variable]: power }));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return [[createFraction(terms, 1)]];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a monomial: coeff * x^px * y^py * z^pz * ...
|
|
50
|
+
*/
|
|
51
|
+
function monomial(coeff, powers = {}) {
|
|
52
|
+
return [[createFraction([createTerm(coeff, powers)], 1)]];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a sum of monomials
|
|
57
|
+
* @param {Array} terms - Array of [coeff, powers] pairs
|
|
58
|
+
*
|
|
59
|
+
* Example: sum([[2, {x:2}], [3, {x:1}], [1, {}]]) creates 2x² + 3x + 1
|
|
60
|
+
*/
|
|
61
|
+
function sum(terms) {
|
|
62
|
+
const slangTerms = terms.map(([coeff, powers]) => createTerm(coeff, powers));
|
|
63
|
+
return [[createFraction(slangTerms, 1)]];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Create a product of polynomials
|
|
68
|
+
* @param {Array} factors - Array of polynomial fractions
|
|
69
|
+
*
|
|
70
|
+
* Example: product([[1+x], [1-x]]) creates (1+x)(1-x)
|
|
71
|
+
*/
|
|
72
|
+
function product(...factors) {
|
|
73
|
+
// Convert each factor array to fraction format
|
|
74
|
+
const fractions = factors.map(factor => {
|
|
75
|
+
if (Array.isArray(factor[0][0]?.numi?.terms)) {
|
|
76
|
+
return factor[0][0]; // Already a fraction
|
|
77
|
+
}
|
|
78
|
+
return createFraction(factor.map(([c, p]) => createTerm(c, p)), 1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return [fractions];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// CALCULATION HELPERS
|
|
86
|
+
// ============================================================================
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Compute definite integral over a rectangular region
|
|
90
|
+
* @param {Object} expr - Expression to integrate
|
|
91
|
+
* @param {Object} bounds - {x: [lower, upper], y: [lower, upper], ...}
|
|
92
|
+
*
|
|
93
|
+
* Example:
|
|
94
|
+
* integralOverRegion(xy, {x: [0, 2], y: [0, 3]})
|
|
95
|
+
* computes ∫₀² ∫₀³ xy dy dx
|
|
96
|
+
*/
|
|
97
|
+
function integralOverRegion(expr, bounds) {
|
|
98
|
+
let result = deepClone(expr);
|
|
99
|
+
|
|
100
|
+
for (let [variable, [lower, upper]] of Object.entries(bounds)) {
|
|
101
|
+
result = definiteIntegrateFraction(result, lower, upper, variable);
|
|
102
|
+
result = simplifyFraction(result);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Compute integral and return numeric value
|
|
110
|
+
*/
|
|
111
|
+
function integralValue(expr, bounds) {
|
|
112
|
+
const result = integralOverRegion(expr, bounds);
|
|
113
|
+
return evaluateEquation([[result]], {});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Compute partial derivative with respect to variable
|
|
118
|
+
* @param {Object} expr - Expression to differentiate
|
|
119
|
+
* @param {string} variable - Variable to differentiate with respect to
|
|
120
|
+
* @param {number} order - Order of derivative (default 1)
|
|
121
|
+
*/
|
|
122
|
+
function partialDerivative(expr, variable, order = 1) {
|
|
123
|
+
let result = deepClone(expr);
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < order; i++) {
|
|
126
|
+
result = differentiateFraction(result, variable);
|
|
127
|
+
result = simplifyFraction(result);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Expand and simplify a product expression
|
|
135
|
+
*/
|
|
136
|
+
function expandAndSimplify(productArray) {
|
|
137
|
+
const expanded = expandProduct(productArray);
|
|
138
|
+
return simplifyFraction(expanded);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Evaluate expression at point
|
|
143
|
+
* @param {Object} expr - Expression in equation format
|
|
144
|
+
* @param {Object} point - {x: value, y: value, ...}
|
|
145
|
+
*/
|
|
146
|
+
function evaluateAt(expr, point) {
|
|
147
|
+
return evaluateEquation([Array.isArray(expr) ? expr : [expr]], point);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// COMMON FORMULAS
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Common mathematical functions as SLaNg expressions
|
|
156
|
+
*/
|
|
157
|
+
const formulas = {
|
|
158
|
+
// Circle area element: r dr dθ
|
|
159
|
+
circleAreaElement: (r = 'r') =>
|
|
160
|
+
[[createFraction([createTerm(1, { [r]: 1 })], 1)]],
|
|
161
|
+
|
|
162
|
+
// Disk of radius R: ∫₀²ᵖ ∫₀ᴿ r dr dθ
|
|
163
|
+
diskArea: (R) => {
|
|
164
|
+
const rdr = formulas.circleAreaElement('r');
|
|
165
|
+
return integralValue(rdr[0][0], { r: [0, R] }) * 2 * Math.PI;
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
// Sphere volume element in spherical coords: r² sin(φ) dr dφ dθ
|
|
169
|
+
// (approximated for polynomial case)
|
|
170
|
+
|
|
171
|
+
// Average value of f over [a,b]: 1/(b-a) ∫ₐᵇ f dx
|
|
172
|
+
average: (expr, variable, a, b) => {
|
|
173
|
+
const integral = definiteIntegrateFraction(expr, a, b, variable);
|
|
174
|
+
const value = evaluateEquation([[integral]], {});
|
|
175
|
+
return value / (b - a);
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// Center of mass (1D): ∫ x·ρ(x) dx / ∫ ρ(x) dx
|
|
179
|
+
centerOfMass1D: (density, variable, a, b) => {
|
|
180
|
+
// Create x * density
|
|
181
|
+
const xDensity = deepClone(density);
|
|
182
|
+
for (let term of xDensity.numi.terms) {
|
|
183
|
+
if (!term.var) term.var = {};
|
|
184
|
+
term.var[variable] = (term.var[variable] || 0) + 1;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const numerator = integralValue(xDensity, { [variable]: [a, b] });
|
|
188
|
+
const denominator = integralValue(density, { [variable]: [a, b] });
|
|
189
|
+
|
|
190
|
+
return numerator / denominator;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// ============================================================================
|
|
195
|
+
// GEOMETRY HELPERS
|
|
196
|
+
// ============================================================================
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Volume under surface z = f(x,y) over region R
|
|
200
|
+
*/
|
|
201
|
+
function volumeUnderSurface(surface, xBounds, yBounds) {
|
|
202
|
+
return integralValue(surface, { x: xBounds, y: yBounds });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Area of region in xy-plane (integrate 1 over region)
|
|
207
|
+
*/
|
|
208
|
+
function areaOfRegion(xBounds, yBounds) {
|
|
209
|
+
const one = createFraction([createTerm(1)], 1);
|
|
210
|
+
return integralValue(one, { x: xBounds, y: yBounds });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// VERIFICATION HELPERS
|
|
215
|
+
// ============================================================================
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Check if integration was done correctly by differentiating
|
|
219
|
+
*/
|
|
220
|
+
function verifyIntegration(original, integrated, variable) {
|
|
221
|
+
const derivative = differentiateFraction(integrated, variable);
|
|
222
|
+
const simplified = simplifyFraction(derivative);
|
|
223
|
+
|
|
224
|
+
// Compare structures (simple comparison)
|
|
225
|
+
return JSON.stringify(simplifyFraction(original)) ===
|
|
226
|
+
JSON.stringify(simplified);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Numerical verification: sample at random points
|
|
231
|
+
*/
|
|
232
|
+
function numericalVerification(expr1, expr2, variables, numSamples = 10) {
|
|
233
|
+
const errors = [];
|
|
234
|
+
|
|
235
|
+
for (let i = 0; i < numSamples; i++) {
|
|
236
|
+
const point = {};
|
|
237
|
+
for (let v of variables) {
|
|
238
|
+
point[v] = Math.random() * 10 - 5; // Random value in [-5, 5]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const val1 = evaluateAt([expr1], point);
|
|
242
|
+
const val2 = evaluateAt([expr2], point);
|
|
243
|
+
const error = Math.abs(val1 - val2);
|
|
244
|
+
|
|
245
|
+
if (error > 1e-10) {
|
|
246
|
+
errors.push({ point, val1, val2, error });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
passed: errors.length === 0,
|
|
252
|
+
errors
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ============================================================================
|
|
257
|
+
// EXPORTS
|
|
258
|
+
// ============================================================================
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
// Builders
|
|
262
|
+
polynomial,
|
|
263
|
+
monomial,
|
|
264
|
+
sum,
|
|
265
|
+
product,
|
|
266
|
+
|
|
267
|
+
// Calculations
|
|
268
|
+
integralOverRegion,
|
|
269
|
+
integralValue,
|
|
270
|
+
partialDerivative,
|
|
271
|
+
expandAndSimplify,
|
|
272
|
+
evaluateAt,
|
|
273
|
+
|
|
274
|
+
// Formulas
|
|
275
|
+
formulas,
|
|
276
|
+
|
|
277
|
+
// Geometry
|
|
278
|
+
volumeUnderSurface,
|
|
279
|
+
areaOfRegion,
|
|
280
|
+
|
|
281
|
+
// Verification
|
|
282
|
+
verifyIntegration,
|
|
283
|
+
numericalVerification
|
|
284
|
+
};
|
package/slang-math.js
ADDED