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/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "slangmath",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "🎯 **Advanced Symbolic Mathematics with Comprehensive LaTeX Conversion & Extended Function Support**",
|
|
5
|
+
"main": "slang-advanced.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"test": "tests"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/SENODROOM/SLaNg.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/SENODROOM/SLaNg/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/SENODROOM/SLaNg#readme"
|
|
23
|
+
}
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLaNg Extended Math Library
|
|
3
|
+
* Advanced features for symbolic mathematics
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
deepClone,
|
|
8
|
+
createTerm,
|
|
9
|
+
createFraction,
|
|
10
|
+
definiteIntegrateFraction,
|
|
11
|
+
integrateFraction,
|
|
12
|
+
differentiateFraction,
|
|
13
|
+
simplifyFraction,
|
|
14
|
+
evaluateEquation,
|
|
15
|
+
multiplyTerms,
|
|
16
|
+
expandProduct
|
|
17
|
+
} from './slang-math.js';
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// PRODUCT RULE & QUOTIENT RULE FOR DIFFERENTIATION
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Product Rule: d/dx[f·g] = f'·g + f·g'
|
|
25
|
+
* Takes a product array [f, g, h, ...] and differentiates it
|
|
26
|
+
*/
|
|
27
|
+
function productRuleDifferentiate(productArray, indvar) {
|
|
28
|
+
if (productArray.length === 0) return createFraction([createTerm(0)], 1);
|
|
29
|
+
if (productArray.length === 1) {
|
|
30
|
+
return differentiateFraction(productArray[0], indvar);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// For each factor, create a term where that factor is differentiated
|
|
34
|
+
// and all others remain the same
|
|
35
|
+
const resultTerms = [];
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < productArray.length; i++) {
|
|
38
|
+
const diffFactor = differentiateFraction(productArray[i], indvar);
|
|
39
|
+
|
|
40
|
+
// Multiply this differentiated factor with all the others
|
|
41
|
+
let product = diffFactor;
|
|
42
|
+
for (let j = 0; j < productArray.length; j++) {
|
|
43
|
+
if (i !== j) {
|
|
44
|
+
product = expandFractions(product, productArray[j]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Add to result
|
|
49
|
+
for (let term of product.numi.terms) {
|
|
50
|
+
resultTerms.push(term);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return simplifyFraction({ numi: { terms: resultTerms }, deno: 1 });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Helper to expand two fractions (used in product rule)
|
|
59
|
+
*/
|
|
60
|
+
function expandFractions(frac1, frac2) {
|
|
61
|
+
if (frac1.deno !== 1 || frac2.deno !== 1) {
|
|
62
|
+
throw new Error('Expansion only works for deno=1');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const expandedTerms = [];
|
|
66
|
+
|
|
67
|
+
for (let term1 of frac1.numi.terms) {
|
|
68
|
+
for (let term2 of frac2.numi.terms) {
|
|
69
|
+
expandedTerms.push(multiplyTerms(term1, term2));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return simplifyFraction({
|
|
74
|
+
numi: { terms: expandedTerms },
|
|
75
|
+
deno: 1
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Quotient Rule: d/dx[f/g] = (f'·g - f·g') / g²
|
|
81
|
+
* Takes numerator and denominator fractions
|
|
82
|
+
*/
|
|
83
|
+
function quotientRuleDifferentiate(numerator, denominator, indvar) {
|
|
84
|
+
const fPrime = differentiateFraction(numerator, indvar);
|
|
85
|
+
const gPrime = differentiateFraction(denominator, indvar);
|
|
86
|
+
|
|
87
|
+
// f' * g
|
|
88
|
+
const fPrimeTimesG = expandFractions(fPrime, denominator);
|
|
89
|
+
|
|
90
|
+
// f * g'
|
|
91
|
+
const fTimesGPrime = expandFractions(numerator, gPrime);
|
|
92
|
+
|
|
93
|
+
// f' * g - f * g'
|
|
94
|
+
const numeratorResult = {
|
|
95
|
+
numi: {
|
|
96
|
+
terms: [
|
|
97
|
+
...fPrimeTimesG.numi.terms,
|
|
98
|
+
...fTimesGPrime.numi.terms.map(t => ({
|
|
99
|
+
...deepClone(t),
|
|
100
|
+
coeff: -t.coeff
|
|
101
|
+
}))
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
deno: 1
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// g²
|
|
108
|
+
const gSquared = expandFractions(denominator, denominator);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
numerator: simplifyFraction(numeratorResult),
|
|
112
|
+
denominator: gSquared,
|
|
113
|
+
note: 'Result is (numerator)/(denominator)'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// CHAIN RULE
|
|
119
|
+
// ============================================================================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Chain Rule: d/dx[f(g(x))] = f'(g(x)) · g'(x)
|
|
123
|
+
* This is a simplified version for polynomial compositions
|
|
124
|
+
*/
|
|
125
|
+
function chainRuleDifferentiate(outer, inner, indvar) {
|
|
126
|
+
// For now, handles simple cases like (ax + b)^n
|
|
127
|
+
// More complex cases require symbolic substitution
|
|
128
|
+
|
|
129
|
+
const innerDerivative = differentiateFraction(inner, indvar);
|
|
130
|
+
|
|
131
|
+
// This is simplified - full chain rule needs more work
|
|
132
|
+
return {
|
|
133
|
+
outer,
|
|
134
|
+
inner,
|
|
135
|
+
innerDerivative,
|
|
136
|
+
note: 'Multiply outer derivative (evaluated at inner) by inner derivative'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// INTEGRATION BY PARTS
|
|
142
|
+
// ============================================================================
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Integration by Parts: ∫ u dv = uv - ∫ v du
|
|
146
|
+
* @param {Object} u - First function
|
|
147
|
+
* @param {Object} dv - Second function (to be integrated)
|
|
148
|
+
* @param {string} indvar - Integration variable
|
|
149
|
+
*/
|
|
150
|
+
function integrationByParts(u, dv, indvar) {
|
|
151
|
+
// du = differentiate u
|
|
152
|
+
const du = differentiateFraction(u, indvar);
|
|
153
|
+
|
|
154
|
+
// v = integrate dv
|
|
155
|
+
const v = integrateFraction(dv, indvar);
|
|
156
|
+
|
|
157
|
+
// u * v
|
|
158
|
+
const uTimesV = expandFractions(u, v);
|
|
159
|
+
|
|
160
|
+
// v * du (for the ∫ v du term)
|
|
161
|
+
const vTimesDu = expandFractions(v, du);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
uTimesV,
|
|
165
|
+
integralOfVdu: vTimesDu,
|
|
166
|
+
note: 'Result is uv - ∫(v·du). You need to integrate the second term.'
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ============================================================================
|
|
171
|
+
// PARTIAL FRACTION DECOMPOSITION (SIMPLE CASES)
|
|
172
|
+
// ============================================================================
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Partial fraction decomposition for simple rational functions
|
|
176
|
+
* Currently handles: A/(x-a) + B/(x-b) forms
|
|
177
|
+
*/
|
|
178
|
+
function partialFractionDecomposition(numerator, denominator) {
|
|
179
|
+
// This is a placeholder for more complex implementation
|
|
180
|
+
// Real implementation would factor denominator and solve for coefficients
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
note: 'Partial fraction decomposition - advanced feature',
|
|
184
|
+
numerator,
|
|
185
|
+
denominator,
|
|
186
|
+
message: 'Factor denominator into (x-a)(x-b)... and solve for coefficients'
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ============================================================================
|
|
191
|
+
// TAYLOR SERIES EXPANSION
|
|
192
|
+
// ============================================================================
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Generate Taylor series expansion around a point
|
|
196
|
+
* f(x) ≈ f(a) + f'(a)(x-a) + f''(a)(x-a)²/2! + ...
|
|
197
|
+
*
|
|
198
|
+
* @param {Object} func - Function to expand
|
|
199
|
+
* @param {string} variable - Variable name
|
|
200
|
+
* @param {number} center - Point to expand around
|
|
201
|
+
* @param {number} order - Number of terms
|
|
202
|
+
*/
|
|
203
|
+
function taylorSeries(func, variable, center = 0, order = 5) {
|
|
204
|
+
const terms = [];
|
|
205
|
+
let currentDerivative = deepClone(func);
|
|
206
|
+
|
|
207
|
+
for (let n = 0; n < order; n++) {
|
|
208
|
+
// Evaluate derivative at center point
|
|
209
|
+
const value = evaluateEquation([[currentDerivative]], { [variable]: center });
|
|
210
|
+
|
|
211
|
+
// Calculate factorial
|
|
212
|
+
const factorial = (n === 0) ? 1 : Array.from({ length: n }, (_, i) => i + 1).reduce((a, b) => a * b);
|
|
213
|
+
|
|
214
|
+
// Create term: f^(n)(a) / n! * (x - a)^n
|
|
215
|
+
if (Math.abs(value) > 1e-10) {
|
|
216
|
+
if (n === 0) {
|
|
217
|
+
terms.push(createTerm(value));
|
|
218
|
+
} else {
|
|
219
|
+
// For (x - center)^n, we need to handle this carefully
|
|
220
|
+
// Simplified: just create x^n term with adjusted coefficient
|
|
221
|
+
terms.push(createTerm(value / factorial, { [variable]: n }));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Get next derivative
|
|
226
|
+
if (n < order - 1) {
|
|
227
|
+
currentDerivative = differentiateFraction(currentDerivative, variable);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
series: createFraction(terms, 1),
|
|
233
|
+
center,
|
|
234
|
+
order,
|
|
235
|
+
note: `Taylor series around ${variable}=${center} up to order ${order - 1}`
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// LIMITS (SIMPLE CASES)
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Compute limit as variable approaches a value
|
|
245
|
+
* Uses direct substitution for simple cases
|
|
246
|
+
*/
|
|
247
|
+
function computeLimit(expr, variable, approaches) {
|
|
248
|
+
// Try direct substitution first
|
|
249
|
+
try {
|
|
250
|
+
const value = evaluateEquation([[expr]], { [variable]: approaches });
|
|
251
|
+
|
|
252
|
+
if (isFinite(value)) {
|
|
253
|
+
return {
|
|
254
|
+
value,
|
|
255
|
+
method: 'direct substitution',
|
|
256
|
+
exists: true
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
} catch (e) {
|
|
260
|
+
// Direct substitution failed
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Try approaching from both sides
|
|
264
|
+
const epsilon = 1e-6;
|
|
265
|
+
const leftValue = evaluateEquation([[expr]], { [variable]: approaches - epsilon });
|
|
266
|
+
const rightValue = evaluateEquation([[expr]], { [variable]: approaches + epsilon });
|
|
267
|
+
|
|
268
|
+
if (Math.abs(leftValue - rightValue) < 1e-8) {
|
|
269
|
+
return {
|
|
270
|
+
value: (leftValue + rightValue) / 2,
|
|
271
|
+
method: 'two-sided approach',
|
|
272
|
+
exists: true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
value: null,
|
|
278
|
+
leftLimit: leftValue,
|
|
279
|
+
rightLimit: rightValue,
|
|
280
|
+
method: 'limits differ',
|
|
281
|
+
exists: false
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ============================================================================
|
|
286
|
+
// CRITICAL POINTS & OPTIMIZATION
|
|
287
|
+
// ============================================================================
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Find critical points where f'(x) = 0
|
|
291
|
+
* Uses numerical method for polynomial roots
|
|
292
|
+
*/
|
|
293
|
+
function findCriticalPoints(func, variable, searchRange = [-10, 10], numSamples = 1000) {
|
|
294
|
+
const derivative = differentiateFraction(func, variable);
|
|
295
|
+
const criticalPoints = [];
|
|
296
|
+
|
|
297
|
+
const [min, max] = searchRange;
|
|
298
|
+
const step = (max - min) / numSamples;
|
|
299
|
+
|
|
300
|
+
let prevValue = evaluateEquation([[derivative]], { [variable]: min });
|
|
301
|
+
|
|
302
|
+
for (let i = 1; i <= numSamples; i++) {
|
|
303
|
+
const x = min + i * step;
|
|
304
|
+
const currValue = evaluateEquation([[derivative]], { [variable]: x });
|
|
305
|
+
|
|
306
|
+
// Sign change indicates root
|
|
307
|
+
if (prevValue * currValue < 0) {
|
|
308
|
+
// Refine with bisection
|
|
309
|
+
let left = x - step;
|
|
310
|
+
let right = x;
|
|
311
|
+
|
|
312
|
+
for (let j = 0; j < 20; j++) {
|
|
313
|
+
const mid = (left + right) / 2;
|
|
314
|
+
const midValue = evaluateEquation([[derivative]], { [variable]: mid });
|
|
315
|
+
|
|
316
|
+
if (Math.abs(midValue) < 1e-8) {
|
|
317
|
+
criticalPoints.push(mid);
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (midValue * evaluateEquation([[derivative]], { [variable]: left }) < 0) {
|
|
322
|
+
right = mid;
|
|
323
|
+
} else {
|
|
324
|
+
left = mid;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
prevValue = currValue;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
criticalPoints,
|
|
334
|
+
derivative,
|
|
335
|
+
note: 'Points where f\'(x) = 0'
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Second derivative test for local extrema
|
|
341
|
+
*/
|
|
342
|
+
function secondDerivativeTest(func, variable, point) {
|
|
343
|
+
const firstDeriv = differentiateFraction(func, variable);
|
|
344
|
+
const secondDeriv = differentiateFraction(firstDeriv, variable);
|
|
345
|
+
|
|
346
|
+
const fValue = evaluateEquation([[func]], { [variable]: point });
|
|
347
|
+
const fDoublePrime = evaluateEquation([[secondDeriv]], { [variable]: point });
|
|
348
|
+
|
|
349
|
+
let type;
|
|
350
|
+
if (fDoublePrime > 0) {
|
|
351
|
+
type = 'local minimum';
|
|
352
|
+
} else if (fDoublePrime < 0) {
|
|
353
|
+
type = 'local maximum';
|
|
354
|
+
} else {
|
|
355
|
+
type = 'inconclusive (may be inflection point)';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
point,
|
|
360
|
+
functionValue: fValue,
|
|
361
|
+
secondDerivative: fDoublePrime,
|
|
362
|
+
type
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ============================================================================
|
|
367
|
+
// CURVE SKETCHING
|
|
368
|
+
// ============================================================================
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Analyze function for curve sketching
|
|
372
|
+
*/
|
|
373
|
+
function analyzeCurve(func, variable, range = [-10, 10]) {
|
|
374
|
+
const firstDeriv = differentiateFraction(func, variable);
|
|
375
|
+
const secondDeriv = differentiateFraction(firstDeriv, variable);
|
|
376
|
+
|
|
377
|
+
// Find critical points
|
|
378
|
+
const { criticalPoints } = findCriticalPoints(func, variable, range);
|
|
379
|
+
|
|
380
|
+
// Test each critical point
|
|
381
|
+
const extrema = criticalPoints.map(pt =>
|
|
382
|
+
secondDerivativeTest(func, variable, pt)
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
// Find inflection points (where f'' = 0)
|
|
386
|
+
const { criticalPoints: inflectionPoints } = findCriticalPoints(firstDeriv, variable, range);
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
criticalPoints,
|
|
390
|
+
extrema,
|
|
391
|
+
inflectionPoints,
|
|
392
|
+
firstDerivative: firstDeriv,
|
|
393
|
+
secondDerivative: secondDeriv
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ============================================================================
|
|
398
|
+
// ARC LENGTH
|
|
399
|
+
// ============================================================================
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Compute arc length of curve y = f(x) from a to b
|
|
403
|
+
* L = ∫ₐᵇ √(1 + (f'(x))²) dx
|
|
404
|
+
*
|
|
405
|
+
* Note: This uses numerical integration since √ is not polynomial
|
|
406
|
+
*/
|
|
407
|
+
function arcLength(func, variable, a, b, numSteps = 1000) {
|
|
408
|
+
const derivative = differentiateFraction(func, variable);
|
|
409
|
+
|
|
410
|
+
let totalLength = 0;
|
|
411
|
+
const step = (b - a) / numSteps;
|
|
412
|
+
|
|
413
|
+
for (let i = 0; i < numSteps; i++) {
|
|
414
|
+
const x = a + i * step;
|
|
415
|
+
const dydx = evaluateEquation([[derivative]], { [variable]: x });
|
|
416
|
+
const integrand = Math.sqrt(1 + dydx * dydx);
|
|
417
|
+
totalLength += integrand * step;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return {
|
|
421
|
+
length: totalLength,
|
|
422
|
+
interval: [a, b],
|
|
423
|
+
method: 'numerical integration',
|
|
424
|
+
note: 'Arc length = ∫√(1 + (dy/dx)²) dx'
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ============================================================================
|
|
429
|
+
// SURFACE AREA OF REVOLUTION
|
|
430
|
+
// ============================================================================
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Surface area when y=f(x) is revolved around x-axis
|
|
434
|
+
* SA = 2π ∫ₐᵇ y√(1 + (dy/dx)²) dx
|
|
435
|
+
*/
|
|
436
|
+
function surfaceAreaOfRevolution(func, variable, a, b, numSteps = 1000) {
|
|
437
|
+
const derivative = differentiateFraction(func, variable);
|
|
438
|
+
|
|
439
|
+
let totalArea = 0;
|
|
440
|
+
const step = (b - a) / numSteps;
|
|
441
|
+
|
|
442
|
+
for (let i = 0; i < numSteps; i++) {
|
|
443
|
+
const x = a + i * step;
|
|
444
|
+
const y = evaluateEquation([[func]], { [variable]: x });
|
|
445
|
+
const dydx = evaluateEquation([[derivative]], { [variable]: x });
|
|
446
|
+
const integrand = y * Math.sqrt(1 + dydx * dydx);
|
|
447
|
+
totalArea += integrand * step;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
surfaceArea: 2 * Math.PI * totalArea,
|
|
452
|
+
interval: [a, b],
|
|
453
|
+
method: 'numerical integration',
|
|
454
|
+
note: 'Surface area = 2π ∫ y√(1 + (dy/dx)²) dx'
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// GRADIENT & DIRECTIONAL DERIVATIVE
|
|
460
|
+
// ============================================================================
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Compute gradient ∇f = (∂f/∂x, ∂f/∂y, ∂f/∂z, ...)
|
|
464
|
+
*/
|
|
465
|
+
function gradient(func, variables) {
|
|
466
|
+
const grad = {};
|
|
467
|
+
|
|
468
|
+
for (let variable of variables) {
|
|
469
|
+
grad[variable] = differentiateFraction(func, variable);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
gradient: grad,
|
|
474
|
+
note: 'Gradient vector ∇f with components for each variable'
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Directional derivative of f in direction of vector v
|
|
480
|
+
* D_v f = ∇f · v
|
|
481
|
+
*/
|
|
482
|
+
function directionalDerivative(func, variables, point, direction) {
|
|
483
|
+
const grad = gradient(func, variables);
|
|
484
|
+
|
|
485
|
+
// Evaluate gradient at point
|
|
486
|
+
const gradAtPoint = {};
|
|
487
|
+
for (let variable of variables) {
|
|
488
|
+
gradAtPoint[variable] = evaluateEquation([[grad.gradient[variable]]], point);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Dot product with direction vector
|
|
492
|
+
let dotProduct = 0;
|
|
493
|
+
for (let variable of variables) {
|
|
494
|
+
dotProduct += gradAtPoint[variable] * direction[variable];
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
directionalDerivative: dotProduct,
|
|
499
|
+
gradientAtPoint: gradAtPoint,
|
|
500
|
+
direction,
|
|
501
|
+
point,
|
|
502
|
+
note: 'D_v f = ∇f · v'
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ============================================================================
|
|
507
|
+
// LAGRANGE MULTIPLIERS (SIMPLE CASE)
|
|
508
|
+
// ============================================================================
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Find constrained optimization using Lagrange multipliers
|
|
512
|
+
* Optimize f(x,y) subject to g(x,y) = 0
|
|
513
|
+
*
|
|
514
|
+
* This is a simplified version that sets up the system
|
|
515
|
+
*/
|
|
516
|
+
function lagrangeMultipliers(objective, constraint, variables) {
|
|
517
|
+
const gradF = gradient(objective, variables);
|
|
518
|
+
const gradG = gradient(constraint, variables);
|
|
519
|
+
|
|
520
|
+
return {
|
|
521
|
+
objectiveGradient: gradF,
|
|
522
|
+
constraintGradient: gradG,
|
|
523
|
+
note: 'Solve: ∇f = λ∇g and g = 0',
|
|
524
|
+
system: 'Set up system of equations where each component satisfies ∂f/∂x = λ∂g/∂x'
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// ============================================================================
|
|
529
|
+
// EXPORTS
|
|
530
|
+
// ============================================================================
|
|
531
|
+
|
|
532
|
+
export {
|
|
533
|
+
// Differentiation rules
|
|
534
|
+
productRuleDifferentiate,
|
|
535
|
+
quotientRuleDifferentiate,
|
|
536
|
+
chainRuleDifferentiate,
|
|
537
|
+
|
|
538
|
+
// Integration techniques
|
|
539
|
+
integrationByParts,
|
|
540
|
+
partialFractionDecomposition,
|
|
541
|
+
|
|
542
|
+
// Series & limits
|
|
543
|
+
taylorSeries,
|
|
544
|
+
computeLimit,
|
|
545
|
+
|
|
546
|
+
// Optimization
|
|
547
|
+
findCriticalPoints,
|
|
548
|
+
secondDerivativeTest,
|
|
549
|
+
analyzeCurve,
|
|
550
|
+
|
|
551
|
+
// Geometry
|
|
552
|
+
arcLength,
|
|
553
|
+
surfaceAreaOfRevolution,
|
|
554
|
+
|
|
555
|
+
// Multivariable
|
|
556
|
+
gradient,
|
|
557
|
+
directionalDerivative,
|
|
558
|
+
lagrangeMultipliers
|
|
559
|
+
};
|