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-cache.js ADDED
@@ -0,0 +1,519 @@
1
+ /**
2
+ * SLaNg Performance Optimization and Caching System
3
+ * Provides caching, memoization, and performance monitoring
4
+ */
5
+
6
+ // ============================================================================
7
+ // CACHE IMPLEMENTATION
8
+ // ============================================================================
9
+
10
+ /**
11
+ * LRU Cache implementation for expression caching
12
+ */
13
+ class LRUCache {
14
+ constructor(maxSize = 1000) {
15
+ this.maxSize = maxSize;
16
+ this.cache = new Map();
17
+ this.hits = 0;
18
+ this.misses = 0;
19
+ }
20
+
21
+ get(key) {
22
+ if (this.cache.has(key)) {
23
+ // Move to end (most recently used)
24
+ const value = this.cache.get(key);
25
+ this.cache.delete(key);
26
+ this.cache.set(key, value);
27
+ this.hits++;
28
+ return value;
29
+ }
30
+ this.misses++;
31
+ return null;
32
+ }
33
+
34
+ set(key, value) {
35
+ if (this.cache.has(key)) {
36
+ this.cache.delete(key);
37
+ } else if (this.cache.size >= this.maxSize) {
38
+ // Remove least recently used (first item)
39
+ const firstKey = this.cache.keys().next().value;
40
+ this.cache.delete(firstKey);
41
+ }
42
+ this.cache.set(key, value);
43
+ }
44
+
45
+ has(key) {
46
+ return this.cache.has(key);
47
+ }
48
+
49
+ clear() {
50
+ this.cache.clear();
51
+ this.hits = 0;
52
+ this.misses = 0;
53
+ }
54
+
55
+ getStats() {
56
+ const total = this.hits + this.misses;
57
+ return {
58
+ size: this.cache.size,
59
+ maxSize: this.maxSize,
60
+ hits: this.hits,
61
+ misses: this.misses,
62
+ hitRate: total > 0 ? (this.hits / total * 100).toFixed(2) + '%' : '0%'
63
+ };
64
+ }
65
+ }
66
+
67
+ // ============================================================================
68
+ // PERFORMANCE MONITORING
69
+ // ============================================================================
70
+
71
+ /**
72
+ * Performance monitor for tracking operation metrics
73
+ */
74
+ class PerformanceMonitor {
75
+ constructor() {
76
+ this.operations = new Map();
77
+ this.globalStats = {
78
+ totalOperations: 0,
79
+ totalTime: 0,
80
+ averageTime: 0
81
+ };
82
+ }
83
+
84
+ startOperation(name) {
85
+ const startTime = performance.now();
86
+ this.operations.set(name, {
87
+ startTime,
88
+ endTime: null,
89
+ duration: null
90
+ });
91
+ return startTime;
92
+ }
93
+
94
+ endOperation(name) {
95
+ const operation = this.operations.get(name);
96
+ if (operation) {
97
+ operation.endTime = performance.now();
98
+ operation.duration = operation.endTime - operation.startTime;
99
+
100
+ // Update global stats
101
+ this.globalStats.totalOperations++;
102
+ this.globalStats.totalTime += operation.duration;
103
+ this.globalStats.averageTime = this.globalStats.totalTime / this.globalStats.totalOperations;
104
+
105
+ return operation.duration;
106
+ }
107
+ return null;
108
+ }
109
+
110
+ getOperationStats(name) {
111
+ return this.operations.get(name);
112
+ }
113
+
114
+ getGlobalStats() {
115
+ return { ...this.globalStats };
116
+ }
117
+
118
+ clear() {
119
+ this.operations.clear();
120
+ this.globalStats = {
121
+ totalOperations: 0,
122
+ totalTime: 0,
123
+ averageTime: 0
124
+ };
125
+ }
126
+ }
127
+
128
+ // ============================================================================
129
+ // MEMOIZATION
130
+ // ============================================================================
131
+
132
+ /**
133
+ * Memoization decorator for functions
134
+ */
135
+ export function memoize(fn, options = {}) {
136
+ const {
137
+ cacheSize = 100,
138
+ keyGenerator = (...args) => JSON.stringify(args),
139
+ ttl = null // Time to live in milliseconds
140
+ } = options;
141
+
142
+ const cache = new LRUCache(cacheSize);
143
+ const timestamps = new Map();
144
+
145
+ return function(...args) {
146
+ const key = keyGenerator(...args);
147
+
148
+ // Check TTL if specified
149
+ if (ttl && timestamps.has(key)) {
150
+ const age = Date.now() - timestamps.get(key);
151
+ if (age > ttl) {
152
+ cache.delete(key);
153
+ timestamps.delete(key);
154
+ }
155
+ }
156
+
157
+ // Check cache
158
+ const cached = cache.get(key);
159
+ if (cached !== null) {
160
+ return cached;
161
+ }
162
+
163
+ // Compute and cache
164
+ const result = fn.apply(this, args);
165
+ cache.set(key, result);
166
+ timestamps.set(key, Date.now());
167
+
168
+ return result;
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Async memoization for promise-based functions
174
+ */
175
+ export function memoizeAsync(fn, options = {}) {
176
+ const {
177
+ cacheSize = 100,
178
+ keyGenerator = (...args) => JSON.stringify(args),
179
+ ttl = null
180
+ } = options;
181
+
182
+ const cache = new LRUCache(cacheSize);
183
+ const timestamps = new Map();
184
+ const pending = new Map();
185
+
186
+ return async function(...args) {
187
+ const key = keyGenerator(...args);
188
+
189
+ // Check if already pending
190
+ if (pending.has(key)) {
191
+ return pending.get(key);
192
+ }
193
+
194
+ // Check cache
195
+ const cached = cache.get(key);
196
+ if (cached !== null) {
197
+ return cached;
198
+ }
199
+
200
+ // Check TTL
201
+ if (ttl && timestamps.has(key)) {
202
+ const age = Date.now() - timestamps.get(key);
203
+ if (age > ttl) {
204
+ cache.delete(key);
205
+ timestamps.delete(key);
206
+ }
207
+ }
208
+
209
+ // Create and cache promise
210
+ const promise = fn.apply(this, args).then(result => {
211
+ cache.set(key, result);
212
+ timestamps.set(key, Date.now());
213
+ pending.delete(key);
214
+ return result;
215
+ }).catch(error => {
216
+ pending.delete(key);
217
+ throw error;
218
+ });
219
+
220
+ pending.set(key, promise);
221
+ return promise;
222
+ };
223
+ }
224
+
225
+ // ============================================================================
226
+ // CACHED CONVERTER FUNCTIONS
227
+ // ============================================================================
228
+
229
+ // Global cache instances
230
+ export const latexToSlangCache = new LRUCache(500);
231
+ export const slangToLatexCache = new LRUCache(500);
232
+ export const validationCache = new LRUCache(200);
233
+ export const complexityCache = new LRUCache(200);
234
+
235
+ // Performance monitor
236
+ export const performanceMonitor = new PerformanceMonitor();
237
+
238
+ /**
239
+ * Cached LaTeX to SLaNg conversion
240
+ */
241
+ export function cachedLatexToSlang(latex, options = {}) {
242
+ const key = `latex2slang:${JSON.stringify(latex)}:${JSON.stringify(options)}`;
243
+
244
+ performanceMonitor.startOperation('latexToSlang');
245
+
246
+ const cached = latexToSlangCache.get(key);
247
+ if (cached !== null) {
248
+ performanceMonitor.endOperation('latexToSlang');
249
+ return cached;
250
+ }
251
+
252
+ // Import here to avoid circular dependencies
253
+ import('./slang-convertor.js').then(({ latexToSlang }) => {
254
+ try {
255
+ const result = latexToSlang(latex, options);
256
+ latexToSlangCache.set(key, result);
257
+ performanceMonitor.endOperation('latexToSlang');
258
+ return result;
259
+ } catch (error) {
260
+ performanceMonitor.endOperation('latexToSlang');
261
+ throw error;
262
+ }
263
+ });
264
+ }
265
+
266
+ /**
267
+ * Cached SLaNg to LaTeX conversion
268
+ */
269
+ export function cachedSlangToLatex(slang, options = {}) {
270
+ const key = `slang2latex:${JSON.stringify(slang)}:${JSON.stringify(options)}`;
271
+
272
+ performanceMonitor.startOperation('slangToLatex');
273
+
274
+ const cached = slangToLatexCache.get(key);
275
+ if (cached !== null) {
276
+ performanceMonitor.endOperation('slangToLatex');
277
+ return cached;
278
+ }
279
+
280
+ import('./slang-convertor.js').then(({ slangToLatex }) => {
281
+ try {
282
+ const result = slangToLatex(slang, options);
283
+ slangToLatexCache.set(key, result);
284
+ performanceMonitor.endOperation('slangToLatex');
285
+ return result;
286
+ } catch (error) {
287
+ performanceMonitor.endOperation('slangToLatex');
288
+ throw error;
289
+ }
290
+ });
291
+ }
292
+
293
+ /**
294
+ * Cached validation
295
+ */
296
+ export function cachedValidation(latex, options = {}) {
297
+ const key = `validate:${JSON.stringify(latex)}:${JSON.stringify(options)}`;
298
+
299
+ performanceMonitor.startOperation('validateLatex');
300
+
301
+ const cached = validationCache.get(key);
302
+ if (cached !== null) {
303
+ performanceMonitor.endOperation('validateLatex');
304
+ return cached;
305
+ }
306
+
307
+ import('./slang-convertor.js').then(({ validateLatex }) => {
308
+ try {
309
+ const result = validateLatex(latex, options);
310
+ validationCache.set(key, result);
311
+ performanceMonitor.endOperation('validateLatex');
312
+ return result;
313
+ } catch (error) {
314
+ performanceMonitor.endOperation('validateLatex');
315
+ throw error;
316
+ }
317
+ });
318
+ }
319
+
320
+ /**
321
+ * Cached complexity calculation
322
+ */
323
+ export function cachedComplexity(slang) {
324
+ const key = `complexity:${JSON.stringify(slang)}`;
325
+
326
+ performanceMonitor.startOperation('getExpressionComplexity');
327
+
328
+ const cached = complexityCache.get(key);
329
+ if (cached !== null) {
330
+ performanceMonitor.endOperation('getExpressionComplexity');
331
+ return cached;
332
+ }
333
+
334
+ import('./slang-convertor.js').then(({ getExpressionComplexity }) => {
335
+ try {
336
+ const result = getExpressionComplexity(slang);
337
+ complexityCache.set(key, result);
338
+ performanceMonitor.endOperation('getExpressionComplexity');
339
+ return result;
340
+ } catch (error) {
341
+ performanceMonitor.endOperation('getExpressionComplexity');
342
+ throw error;
343
+ }
344
+ });
345
+ }
346
+
347
+ // ============================================================================
348
+ // BATCH PROCESSING OPTIMIZATIONS
349
+ // ============================================================================
350
+
351
+ /**
352
+ * Optimized batch processing with parallel execution
353
+ */
354
+ export async function optimizedBatchProcess(items, processor, options = {}) {
355
+ const {
356
+ batchSize = 10,
357
+ maxConcurrency = 4,
358
+ useCache = true,
359
+ progressCallback = null
360
+ } = options;
361
+
362
+ const results = [];
363
+ const startTime = performance.now();
364
+
365
+ // Process in batches with controlled concurrency
366
+ for (let i = 0; i < items.length; i += batchSize) {
367
+ const batch = items.slice(i, i + batchSize);
368
+
369
+ const batchPromises = batch.map(async (item, batchIndex) => {
370
+ const globalIndex = i + batchIndex;
371
+
372
+ try {
373
+ const result = await processor(item);
374
+ return { index: globalIndex, success: true, result };
375
+ } catch (error) {
376
+ return { index: globalIndex, success: false, error: error.message };
377
+ }
378
+ });
379
+
380
+ // Wait for current batch to complete
381
+ const batchResults = await Promise.all(batchPromises);
382
+ results.push(...batchResults);
383
+
384
+ // Progress callback
385
+ if (progressCallback) {
386
+ const progress = ((i + batchSize) / items.length) * 100;
387
+ progressCallback(Math.min(progress, 100), results);
388
+ }
389
+ }
390
+
391
+ const endTime = performance.now();
392
+ const duration = endTime - startTime;
393
+
394
+ return {
395
+ results,
396
+ stats: {
397
+ totalItems: items.length,
398
+ successful: results.filter(r => r.success).length,
399
+ failed: results.filter(r => !r.success).length,
400
+ duration: duration.toFixed(2) + 'ms',
401
+ averageTime: (duration / items.length).toFixed(2) + 'ms'
402
+ }
403
+ };
404
+ }
405
+
406
+ // ============================================================================
407
+ // PERFORMANCE UTILITIES
408
+ // ============================================================================
409
+
410
+ /**
411
+ * Get comprehensive performance statistics
412
+ */
413
+ export function getPerformanceStats() {
414
+ return {
415
+ caches: {
416
+ latexToSlang: latexToSlangCache.getStats(),
417
+ slangToLatex: slangToLatexCache.getStats(),
418
+ validation: validationCache.getStats(),
419
+ complexity: complexityCache.getStats()
420
+ },
421
+ operations: performanceMonitor.getGlobalStats(),
422
+ memory: getMemoryUsage()
423
+ };
424
+ }
425
+
426
+ /**
427
+ * Get memory usage statistics
428
+ */
429
+ function getMemoryUsage() {
430
+ if (typeof performance !== 'undefined' && performance.memory) {
431
+ return {
432
+ used: formatBytes(performance.memory.usedJSHeapSize),
433
+ total: formatBytes(performance.memory.totalJSHeapSize),
434
+ limit: formatBytes(performance.memory.jsHeapSizeLimit)
435
+ };
436
+ }
437
+ return null;
438
+ }
439
+
440
+ /**
441
+ * Format bytes to human readable format
442
+ */
443
+ function formatBytes(bytes) {
444
+ if (bytes === 0) return '0 Bytes';
445
+ const k = 1024;
446
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
447
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
448
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
449
+ }
450
+
451
+ /**
452
+ * Clear all caches
453
+ */
454
+ export function clearAllCaches() {
455
+ latexToSlangCache.clear();
456
+ slangToLatexCache.clear();
457
+ validationCache.clear();
458
+ complexityCache.clear();
459
+ performanceMonitor.clear();
460
+ }
461
+
462
+ /**
463
+ * Optimize cache sizes based on usage patterns
464
+ */
465
+ export function optimizeCacheSizes() {
466
+ const stats = getPerformanceStats();
467
+
468
+ // Adjust cache sizes based on hit rates
469
+ if (parseFloat(stats.caches.latexToSlang.hitRate) > 80) {
470
+ latexToSlangCache.maxSize = Math.min(latexToSlangCache.maxSize * 1.5, 1000);
471
+ } else if (parseFloat(stats.caches.latexToSlang.hitRate) < 30) {
472
+ latexToSlangCache.maxSize = Math.max(latexToSlangCache.maxSize * 0.7, 100);
473
+ }
474
+
475
+ // Similar optimization for other caches
476
+ if (parseFloat(stats.caches.slangToLatex.hitRate) > 80) {
477
+ slangToLatexCache.maxSize = Math.min(slangToLatexCache.maxSize * 1.5, 1000);
478
+ } else if (parseFloat(stats.caches.slangToLatex.hitRate) < 30) {
479
+ slangToLatexCache.maxSize = Math.max(slangToLatexCache.maxSize * 0.7, 100);
480
+ }
481
+ }
482
+
483
+ // ============================================================================
484
+ // PERFORMANCE DECORATOR
485
+ // ============================================================================
486
+
487
+ /**
488
+ * Performance monitoring decorator
489
+ */
490
+ export function withPerformanceMonitoring(fn, name = fn.name) {
491
+ return function(...args) {
492
+ performanceMonitor.startOperation(name);
493
+ try {
494
+ const result = fn.apply(this, args);
495
+
496
+ // Handle both sync and async results
497
+ if (result && typeof result.then === 'function') {
498
+ return result.finally(() => {
499
+ performanceMonitor.endOperation(name);
500
+ });
501
+ } else {
502
+ performanceMonitor.endOperation(name);
503
+ return result;
504
+ }
505
+ } catch (error) {
506
+ performanceMonitor.endOperation(name);
507
+ throw error;
508
+ }
509
+ };
510
+ }
511
+
512
+ // ============================================================================
513
+ // EXPORTS
514
+ // ============================================================================
515
+
516
+ export {
517
+ LRUCache,
518
+ PerformanceMonitor
519
+ };