tiny-essentials 1.25.4 → 1.25.5

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.
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var e={d:(t,r)=>{for(var a in r)e.o(r,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:r[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{FuzzySet:()=>s,MamdaniInferenceSystem:()=>u,defuzzifyCentroid:()=>a,trapezoid:()=>n});const r=e=>{if(!Array.isArray(e))throw new TypeError("Parameter 'sets' must be an array.");if(!e.every(e=>e instanceof s))throw new TypeError("All elements in the array must be instances of FuzzySet.")},a=(e,t,a=.5)=>{i(e,"object","defuzzifyCentroid.fuzzyOutput");for(const t in e)i(e[t],"number",`fuzzyOutput['${t}']`);r(t),i(a,"number","defuzzifyCentroid.step");let n=0,s=0;for(let r=0;r<=100;r+=a){let a=0;t.forEach(t=>{const n=e[t.name]||0,i=Math.min(n,t.calculate(r));a=Math.max(a,i)}),n+=r*a,s+=a}return 0===s?0:n/s},n=(e,t,r,a,n)=>{if(e<=t||e>=n)return 0;if(e>=r&&e<=a)return 1;const i=t===r?1:(e-t)/(r-t),s=a===n?1:(n-e)/(n-a),u=Math.max(0,Math.min(i,1,s));return isNaN(u)?0:u},i=(e,t,r)=>{if(typeof e!==t)throw new TypeError(`Parameter '${r}' must be a ${t}.`)};class s{static trapezoid(e,t,r,a,i){return n(e,t,r,a,i)}#e="";#t=0;#r=0;#a=0;#n=0;get name(){return this.#e}set name(e){i(e,"string","FuzzySet.name"),this.#e=e}get a(){return this.#t}set a(e){i(e,"number","FuzzySet.a"),this.#t=e}get b(){return this.#r}set b(e){i(e,"number","FuzzySet.b"),this.#r=e}get c(){return this.#a}set c(e){i(e,"number","FuzzySet.c"),this.#a=e}get d(){return this.#n}set d(e){i(e,"number","FuzzySet.d"),this.#n=e}constructor(e,t,r,a,n){this.name=e,this.a=t,this.b=r,this.c=a,this.d=n}calculate(e){return i(e,"number","calculate.x"),s.trapezoid(e,this.#t,this.#r,this.#a,this.#n)}}class u{#i=new Map;addVariable(e,t){i(e,"string","addVariable.name"),r(t),this.#i.set(e,t)}removeVariable(e){return i(e,"string","removeVariable.name"),this.#i.delete(e)}getVariable(e){i(e,"string","getVariable.name");const t=this.#i.get(e);if(!t)throw new Error(`Linguistic variable '${e}' not found in the inference system.`);return[...t]}hasVariable(e){return i(e,"string","hasVariable.name"),this.#i.has(e)}fuzzify(e,t){i(e,"string","fuzzify.varName"),i(t,"number","fuzzify.value");const r=this.#i.get(e)||[],a={};return r.forEach(e=>{a[e.name]=e.calculate(t)}),a}}window.TinyMaInSys=t})();
package/dist/v1/index.cjs CHANGED
@@ -50,6 +50,7 @@ var TinyColorValidator = require('./libs/TinyColorValidator.cjs');
50
50
  var TinyAnalogClock = require('./libs/TinyAnalogClock.cjs');
51
51
  var TinyTextDiffer = require('./libs/TinyTextDiffer.cjs');
52
52
  var TinyArrayComparator = require('./libs/TinyArrayComparator.cjs');
53
+ var TinyMamdaniInferenceSystem = require('./libs/TinyMamdaniInferenceSystem.cjs');
53
54
 
54
55
 
55
56
 
@@ -181,3 +182,7 @@ exports.TinyColorValidator = TinyColorValidator;
181
182
  exports.TinyAnalogClock = TinyAnalogClock;
182
183
  exports.TinyTextDiffer = TinyTextDiffer;
183
184
  exports.TinyArrayComparator = TinyArrayComparator;
185
+ exports.FuzzySet = TinyMamdaniInferenceSystem.FuzzySet;
186
+ exports.MamdaniInferenceSystem = TinyMamdaniInferenceSystem.MamdaniInferenceSystem;
187
+ exports.defuzzifyCentroid = TinyMamdaniInferenceSystem.defuzzifyCentroid;
188
+ exports.trapezoid = TinyMamdaniInferenceSystem.trapezoid;
@@ -1,3 +1,5 @@
1
+ import { FuzzySet } from './libs/TinyMamdaniInferenceSystem.mjs';
2
+ import { MamdaniInferenceSystem } from './libs/TinyMamdaniInferenceSystem.mjs';
1
3
  import TinyArrayComparator from './libs/TinyArrayComparator.mjs';
2
4
  import TinyTextDiffer from './libs/TinyTextDiffer.mjs';
3
5
  import TinyAnalogClock from './libs/TinyAnalogClock.mjs';
@@ -37,6 +39,8 @@ import TinyRateLimiter from './libs/TinyRateLimiter.mjs';
37
39
  import ColorSafeStringify from './libs/ColorSafeStringify.mjs';
38
40
  import TinyPromiseQueue from './libs/TinyPromiseQueue.mjs';
39
41
  import TinyLevelUp from './libs/TinyLevelUp.mjs';
42
+ import { defuzzifyCentroid } from './libs/TinyMamdaniInferenceSystem.mjs';
43
+ import { trapezoid } from './libs/TinyMamdaniInferenceSystem.mjs';
40
44
  import { diffArrayList } from './basics/array.mjs';
41
45
  import { diffStrings } from './basics/text.mjs';
42
46
  import { breakdownDuration } from './basics/clock.mjs';
@@ -126,5 +130,5 @@ import { getTimeDuration } from './basics/clock.mjs';
126
130
  import { shuffleArray } from './basics/array.mjs';
127
131
  import { toTitleCase } from './basics/text.mjs';
128
132
  import { toTitleCaseLowerFirst } from './basics/text.mjs';
129
- export { TinyArrayComparator, TinyTextDiffer, TinyAnalogClock, TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
133
+ export { FuzzySet, MamdaniInferenceSystem, TinyArrayComparator, TinyTextDiffer, TinyAnalogClock, TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, defuzzifyCentroid, trapezoid, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
130
134
  //# sourceMappingURL=index.d.mts.map
package/dist/v1/index.mjs CHANGED
@@ -48,7 +48,8 @@ import TinyColorValidator from './libs/TinyColorValidator.mjs';
48
48
  import TinyAnalogClock from './libs/TinyAnalogClock.mjs';
49
49
  import TinyTextDiffer from './libs/TinyTextDiffer.mjs';
50
50
  import TinyArrayComparator from './libs/TinyArrayComparator.mjs';
51
+ import { FuzzySet, MamdaniInferenceSystem, trapezoid, defuzzifyCentroid, } from './libs/TinyMamdaniInferenceSystem.mjs';
51
52
  // import TinyHtmlElems from './libs/TinyHtml/index.mjs';
52
- export { TinyArrayComparator, TinyTextDiffer, TinyAnalogClock,
53
+ export { FuzzySet, MamdaniInferenceSystem, TinyArrayComparator, TinyTextDiffer, TinyAnalogClock,
53
54
  // TinyHtmlElems,
54
- TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
55
+ TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, defuzzifyCentroid, trapezoid, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
@@ -0,0 +1,273 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Internal helper to validate an array of FuzzySets.
5
+ * @param {FuzzySet[]} sets
6
+ */
7
+ const validateFuzzySets = (sets) => {
8
+ if (!Array.isArray(sets)) {
9
+ throw new TypeError("Parameter 'sets' must be an array.");
10
+ }
11
+ if (!sets.every((set) => set instanceof FuzzySet)) {
12
+ throw new TypeError('All elements in the array must be instances of FuzzySet.');
13
+ }
14
+ };
15
+
16
+ /**
17
+ * Performs defuzzification using the Centroid (Center of Gravity) method.
18
+ * @param {Object.<string, number>} fuzzyOutput - Results from rule evaluation.
19
+ * @param {FuzzySet[]} outputSets - The sets defining the output range.
20
+ * @param {number} [step=0.5] - Resolution of the integral approximation.
21
+ * @returns {number} The crisp output value.
22
+ */
23
+ const defuzzifyCentroid = (fuzzyOutput, outputSets, step = 0.5) => {
24
+ validateType(fuzzyOutput, 'object', 'defuzzifyCentroid.fuzzyOutput');
25
+
26
+ for (const outputName in fuzzyOutput) {
27
+ validateType(fuzzyOutput[outputName], 'number', `fuzzyOutput['${outputName}']`);
28
+ }
29
+
30
+ validateFuzzySets(outputSets);
31
+ validateType(step, 'number', 'defuzzifyCentroid.step');
32
+
33
+ /** @type {number} - Accumulated weighted area for centroid */
34
+ let totalAreaWeighted = 0;
35
+ /** @type {number} - Accumulated total area */
36
+ let totalArea = 0;
37
+
38
+ // Numerical integration (Centroid approximation)
39
+ for (let i = 0; i <= 100; i += step) {
40
+ /** @type {number} - Maximum membership found at point x(i) */
41
+ let maxMembershipAtX = 0;
42
+
43
+ outputSets.forEach((set) => {
44
+ /** @type {number} - Rule strength applied to the output set */
45
+ const strength = fuzzyOutput[set.name] || 0;
46
+ /** @type {number} - Cut or scale the output set membership */
47
+ const membership = Math.min(strength, set.calculate(i));
48
+
49
+ maxMembershipAtX = Math.max(maxMembershipAtX, membership);
50
+ });
51
+
52
+ totalAreaWeighted += i * maxMembershipAtX;
53
+ totalArea += maxMembershipAtX;
54
+ }
55
+
56
+ return totalArea === 0 ? 0 : totalAreaWeighted / totalArea;
57
+ };
58
+
59
+ /**
60
+ * Utility to calculate fuzzy membership using a trapezoidal shape safely.
61
+ * @param {number} value - The input value to check.
62
+ * @param {number} a - Start of the rise.
63
+ * @param {number} b - End of the rise (start of plateau).
64
+ * @param {number} c - Start of the fall (end of plateau).
65
+ * @param {number} d - End of the fall.
66
+ * @returns {number} Degree of membership [0, 1].
67
+ */
68
+ const trapezoid = (value, a, b, c, d) => {
69
+ // If the value is completely outside the outer bounds, return 0 immediately (Performance optimization)
70
+ if (value <= a || value >= d) return 0;
71
+ // If the value is entirely within the plateau, return 1 immediately
72
+ if (value >= b && value <= c) return 1;
73
+
74
+ /** @type {number} - Safely calculate rising slope */
75
+ const rise = a === b ? 1 : (value - a) / (b - a);
76
+
77
+ /** @type {number} - Safely calculate falling slope */
78
+ const fall = c === d ? 1 : (d - value) / (d - c);
79
+
80
+ /** @type {number} - Internal value clamping between 0 and 1 */
81
+ const membership = Math.max(0, Math.min(rise, 1, fall));
82
+
83
+ return isNaN(membership) ? 0 : membership;
84
+ };
85
+
86
+ /**
87
+ * Utility to validate types and throw formatted errors, preventing code repetition.
88
+ * @param {any} value - The value to evaluate.
89
+ * @param {string} expectedType - The expected data type.
90
+ * @param {string} paramName - The name of the parameter for the error message.
91
+ */
92
+ const validateType = (value, expectedType, paramName) => {
93
+ if (typeof value !== expectedType) {
94
+ throw new TypeError(`Parameter '${paramName}' must be a ${expectedType}.`);
95
+ }
96
+ };
97
+
98
+ /**
99
+ * Represents a single Membership Function (Trapezoidal).
100
+ */
101
+ class FuzzySet {
102
+ /**
103
+ * Utility to calculate fuzzy membership using a trapezoidal shape.
104
+ * @param {number} value - The input value to check.
105
+ * @param {number} a - Start of the rise.
106
+ * @param {number} b - End of the rise (start of plateau).
107
+ * @param {number} c - Start of the fall (end of plateau).
108
+ * @param {number} d - End of the fall.
109
+ * @returns {number} Degree of membership [0, 1].
110
+ */
111
+ static trapezoid(value, a, b, c, d) {
112
+ return trapezoid(value, a, b, c, d);
113
+ }
114
+
115
+ /** @type {string} - Internal name of the fuzzy set */
116
+ #name = '';
117
+ /** @type {number} - Internal left foot coordinate */
118
+ #a = 0;
119
+ /** @type {number} - Internal left shoulder coordinate */
120
+ #b = 0;
121
+ /** @type {number} - Internal right shoulder coordinate */
122
+ #c = 0;
123
+ /** @type {number} - Internal right foot coordinate */
124
+ #d = 0;
125
+
126
+ get name() {
127
+ return this.#name;
128
+ }
129
+ set name(value) {
130
+ validateType(value, 'string', 'FuzzySet.name');
131
+ this.#name = value;
132
+ }
133
+
134
+ get a() {
135
+ return this.#a;
136
+ }
137
+ set a(value) {
138
+ validateType(value, 'number', 'FuzzySet.a');
139
+ this.#a = value;
140
+ }
141
+
142
+ get b() {
143
+ return this.#b;
144
+ }
145
+ set b(value) {
146
+ validateType(value, 'number', 'FuzzySet.b');
147
+ this.#b = value;
148
+ }
149
+
150
+ get c() {
151
+ return this.#c;
152
+ }
153
+ set c(value) {
154
+ validateType(value, 'number', 'FuzzySet.c');
155
+ this.#c = value;
156
+ }
157
+
158
+ get d() {
159
+ return this.#d;
160
+ }
161
+ set d(value) {
162
+ validateType(value, 'number', 'FuzzySet.d');
163
+ this.#d = value;
164
+ }
165
+
166
+ /**
167
+ * @param {string} name - Name of the set (e.g., "Hot").
168
+ * @param {number} a - Left foot.
169
+ * @param {number} b - Left shoulder.
170
+ * @param {number} c - Right shoulder.
171
+ * @param {number} d - Right feet.
172
+ */
173
+ constructor(name, a, b, c, d) {
174
+ this.name = name;
175
+ this.a = a;
176
+ this.b = b;
177
+ this.c = c;
178
+ this.d = d;
179
+ }
180
+
181
+ /**
182
+ * Calculates the membership degree.
183
+ * @param {number} x - Crisp input.
184
+ * @returns {number}
185
+ */
186
+ calculate(x) {
187
+ validateType(x, 'number', 'calculate.x');
188
+ return FuzzySet.trapezoid(x, this.#a, this.#b, this.#c, this.#d);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * The Inference Engine handles linguistic variables and defuzzification.
194
+ */
195
+ class MamdaniInferenceSystem {
196
+ /** @type {Map<string, FuzzySet[]>} - Storage for linguistic variables */
197
+ #variables = new Map();
198
+
199
+ /**
200
+ * Registers a linguistic variable and its sets.
201
+ * @param {string} name - Variable name (e.g., "temperature").
202
+ * @param {FuzzySet[]} sets - Array of fuzzy sets.
203
+ */
204
+ addVariable(name, sets) {
205
+ validateType(name, 'string', 'addVariable.name');
206
+ validateFuzzySets(sets);
207
+ this.#variables.set(name, sets);
208
+ }
209
+
210
+ /**
211
+ * Removes a linguistic variable.
212
+ * @param {string} name - Variable name (e.g., "temperature").
213
+ * @returns {boolean} True if the element was successfully removed.
214
+ */
215
+ removeVariable(name) {
216
+ validateType(name, 'string', 'removeVariable.name');
217
+ return this.#variables.delete(name);
218
+ }
219
+
220
+ /**
221
+ * Gets a linguistic variable and its sets.
222
+ * @param {string} name - Variable name (e.g., "temperature").
223
+ * @returns {FuzzySet[]}
224
+ */
225
+ getVariable(name) {
226
+ validateType(name, 'string', 'getVariable.name');
227
+
228
+ /** @type {FuzzySet[] | undefined} - Attempted fetch from map */
229
+ const result = this.#variables.get(name);
230
+
231
+ if (!result)
232
+ throw new Error(`Linguistic variable '${name}' not found in the inference system.`);
233
+
234
+ return [...result];
235
+ }
236
+
237
+ /**
238
+ * Checks if a linguistic variable exists.
239
+ * @param {string} name - Variable name (e.g., "temperature").
240
+ * @returns {boolean}
241
+ */
242
+ hasVariable(name) {
243
+ validateType(name, 'string', 'hasVariable.name');
244
+ return this.#variables.has(name);
245
+ }
246
+
247
+ /**
248
+ * Fuzzifies a crisp input into a map of memberships.
249
+ * @param {string} varName
250
+ * @param {number} value
251
+ * @returns {Object.<string, number>}
252
+ */
253
+ fuzzify(varName, value) {
254
+ validateType(varName, 'string', 'fuzzify.varName');
255
+ validateType(value, 'number', 'fuzzify.value');
256
+
257
+ /** @type {FuzzySet[]} - The sets associated with the variable */
258
+ const sets = this.#variables.get(varName) || [];
259
+ /** @type {Object.<string, number>} - The fuzzified results dictionary */
260
+ const results = {};
261
+
262
+ sets.forEach((set) => {
263
+ results[set.name] = set.calculate(value);
264
+ });
265
+
266
+ return results;
267
+ }
268
+ }
269
+
270
+ exports.FuzzySet = FuzzySet;
271
+ exports.MamdaniInferenceSystem = MamdaniInferenceSystem;
272
+ exports.defuzzifyCentroid = defuzzifyCentroid;
273
+ exports.trapezoid = trapezoid;
@@ -0,0 +1,84 @@
1
+ export function defuzzifyCentroid(fuzzyOutput: {
2
+ [x: string]: number;
3
+ }, outputSets: FuzzySet[], step?: number): number;
4
+ export function trapezoid(value: number, a: number, b: number, c: number, d: number): number;
5
+ /**
6
+ * Represents a single Membership Function (Trapezoidal).
7
+ */
8
+ export class FuzzySet {
9
+ /**
10
+ * Utility to calculate fuzzy membership using a trapezoidal shape.
11
+ * @param {number} value - The input value to check.
12
+ * @param {number} a - Start of the rise.
13
+ * @param {number} b - End of the rise (start of plateau).
14
+ * @param {number} c - Start of the fall (end of plateau).
15
+ * @param {number} d - End of the fall.
16
+ * @returns {number} Degree of membership [0, 1].
17
+ */
18
+ static trapezoid(value: number, a: number, b: number, c: number, d: number): number;
19
+ /**
20
+ * @param {string} name - Name of the set (e.g., "Hot").
21
+ * @param {number} a - Left foot.
22
+ * @param {number} b - Left shoulder.
23
+ * @param {number} c - Right shoulder.
24
+ * @param {number} d - Right feet.
25
+ */
26
+ constructor(name: string, a: number, b: number, c: number, d: number);
27
+ set name(value: string);
28
+ get name(): string;
29
+ set a(value: number);
30
+ get a(): number;
31
+ set b(value: number);
32
+ get b(): number;
33
+ set c(value: number);
34
+ get c(): number;
35
+ set d(value: number);
36
+ get d(): number;
37
+ /**
38
+ * Calculates the membership degree.
39
+ * @param {number} x - Crisp input.
40
+ * @returns {number}
41
+ */
42
+ calculate(x: number): number;
43
+ #private;
44
+ }
45
+ /**
46
+ * The Inference Engine handles linguistic variables and defuzzification.
47
+ */
48
+ export class MamdaniInferenceSystem {
49
+ /**
50
+ * Registers a linguistic variable and its sets.
51
+ * @param {string} name - Variable name (e.g., "temperature").
52
+ * @param {FuzzySet[]} sets - Array of fuzzy sets.
53
+ */
54
+ addVariable(name: string, sets: FuzzySet[]): void;
55
+ /**
56
+ * Removes a linguistic variable.
57
+ * @param {string} name - Variable name (e.g., "temperature").
58
+ * @returns {boolean} True if the element was successfully removed.
59
+ */
60
+ removeVariable(name: string): boolean;
61
+ /**
62
+ * Gets a linguistic variable and its sets.
63
+ * @param {string} name - Variable name (e.g., "temperature").
64
+ * @returns {FuzzySet[]}
65
+ */
66
+ getVariable(name: string): FuzzySet[];
67
+ /**
68
+ * Checks if a linguistic variable exists.
69
+ * @param {string} name - Variable name (e.g., "temperature").
70
+ * @returns {boolean}
71
+ */
72
+ hasVariable(name: string): boolean;
73
+ /**
74
+ * Fuzzifies a crisp input into a map of memberships.
75
+ * @param {string} varName
76
+ * @param {number} value
77
+ * @returns {Object.<string, number>}
78
+ */
79
+ fuzzify(varName: string, value: number): {
80
+ [x: string]: number;
81
+ };
82
+ #private;
83
+ }
84
+ //# sourceMappingURL=TinyMamdaniInferenceSystem.d.mts.map
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Internal helper to validate an array of FuzzySets.
3
+ * @param {FuzzySet[]} sets
4
+ */
5
+ const validateFuzzySets = (sets) => {
6
+ if (!Array.isArray(sets)) {
7
+ throw new TypeError("Parameter 'sets' must be an array.");
8
+ }
9
+ if (!sets.every((set) => set instanceof FuzzySet)) {
10
+ throw new TypeError('All elements in the array must be instances of FuzzySet.');
11
+ }
12
+ };
13
+ /**
14
+ * Performs defuzzification using the Centroid (Center of Gravity) method.
15
+ * @param {Object.<string, number>} fuzzyOutput - Results from rule evaluation.
16
+ * @param {FuzzySet[]} outputSets - The sets defining the output range.
17
+ * @param {number} [step=0.5] - Resolution of the integral approximation.
18
+ * @returns {number} The crisp output value.
19
+ */
20
+ export const defuzzifyCentroid = (fuzzyOutput, outputSets, step = 0.5) => {
21
+ validateType(fuzzyOutput, 'object', 'defuzzifyCentroid.fuzzyOutput');
22
+ for (const outputName in fuzzyOutput) {
23
+ validateType(fuzzyOutput[outputName], 'number', `fuzzyOutput['${outputName}']`);
24
+ }
25
+ validateFuzzySets(outputSets);
26
+ validateType(step, 'number', 'defuzzifyCentroid.step');
27
+ /** @type {number} - Accumulated weighted area for centroid */
28
+ let totalAreaWeighted = 0;
29
+ /** @type {number} - Accumulated total area */
30
+ let totalArea = 0;
31
+ // Numerical integration (Centroid approximation)
32
+ for (let i = 0; i <= 100; i += step) {
33
+ /** @type {number} - Maximum membership found at point x(i) */
34
+ let maxMembershipAtX = 0;
35
+ outputSets.forEach((set) => {
36
+ /** @type {number} - Rule strength applied to the output set */
37
+ const strength = fuzzyOutput[set.name] || 0;
38
+ /** @type {number} - Cut or scale the output set membership */
39
+ const membership = Math.min(strength, set.calculate(i));
40
+ maxMembershipAtX = Math.max(maxMembershipAtX, membership);
41
+ });
42
+ totalAreaWeighted += i * maxMembershipAtX;
43
+ totalArea += maxMembershipAtX;
44
+ }
45
+ return totalArea === 0 ? 0 : totalAreaWeighted / totalArea;
46
+ };
47
+ /**
48
+ * Utility to calculate fuzzy membership using a trapezoidal shape safely.
49
+ * @param {number} value - The input value to check.
50
+ * @param {number} a - Start of the rise.
51
+ * @param {number} b - End of the rise (start of plateau).
52
+ * @param {number} c - Start of the fall (end of plateau).
53
+ * @param {number} d - End of the fall.
54
+ * @returns {number} Degree of membership [0, 1].
55
+ */
56
+ export const trapezoid = (value, a, b, c, d) => {
57
+ // If the value is completely outside the outer bounds, return 0 immediately (Performance optimization)
58
+ if (value <= a || value >= d)
59
+ return 0;
60
+ // If the value is entirely within the plateau, return 1 immediately
61
+ if (value >= b && value <= c)
62
+ return 1;
63
+ /** @type {number} - Safely calculate rising slope */
64
+ const rise = a === b ? 1 : (value - a) / (b - a);
65
+ /** @type {number} - Safely calculate falling slope */
66
+ const fall = c === d ? 1 : (d - value) / (d - c);
67
+ /** @type {number} - Internal value clamping between 0 and 1 */
68
+ const membership = Math.max(0, Math.min(rise, 1, fall));
69
+ return isNaN(membership) ? 0 : membership;
70
+ };
71
+ /**
72
+ * Utility to validate types and throw formatted errors, preventing code repetition.
73
+ * @param {any} value - The value to evaluate.
74
+ * @param {string} expectedType - The expected data type.
75
+ * @param {string} paramName - The name of the parameter for the error message.
76
+ */
77
+ const validateType = (value, expectedType, paramName) => {
78
+ if (typeof value !== expectedType) {
79
+ throw new TypeError(`Parameter '${paramName}' must be a ${expectedType}.`);
80
+ }
81
+ };
82
+ /**
83
+ * Represents a single Membership Function (Trapezoidal).
84
+ */
85
+ class FuzzySet {
86
+ /**
87
+ * Utility to calculate fuzzy membership using a trapezoidal shape.
88
+ * @param {number} value - The input value to check.
89
+ * @param {number} a - Start of the rise.
90
+ * @param {number} b - End of the rise (start of plateau).
91
+ * @param {number} c - Start of the fall (end of plateau).
92
+ * @param {number} d - End of the fall.
93
+ * @returns {number} Degree of membership [0, 1].
94
+ */
95
+ static trapezoid(value, a, b, c, d) {
96
+ return trapezoid(value, a, b, c, d);
97
+ }
98
+ /** @type {string} - Internal name of the fuzzy set */
99
+ #name = '';
100
+ /** @type {number} - Internal left foot coordinate */
101
+ #a = 0;
102
+ /** @type {number} - Internal left shoulder coordinate */
103
+ #b = 0;
104
+ /** @type {number} - Internal right shoulder coordinate */
105
+ #c = 0;
106
+ /** @type {number} - Internal right foot coordinate */
107
+ #d = 0;
108
+ get name() {
109
+ return this.#name;
110
+ }
111
+ set name(value) {
112
+ validateType(value, 'string', 'FuzzySet.name');
113
+ this.#name = value;
114
+ }
115
+ get a() {
116
+ return this.#a;
117
+ }
118
+ set a(value) {
119
+ validateType(value, 'number', 'FuzzySet.a');
120
+ this.#a = value;
121
+ }
122
+ get b() {
123
+ return this.#b;
124
+ }
125
+ set b(value) {
126
+ validateType(value, 'number', 'FuzzySet.b');
127
+ this.#b = value;
128
+ }
129
+ get c() {
130
+ return this.#c;
131
+ }
132
+ set c(value) {
133
+ validateType(value, 'number', 'FuzzySet.c');
134
+ this.#c = value;
135
+ }
136
+ get d() {
137
+ return this.#d;
138
+ }
139
+ set d(value) {
140
+ validateType(value, 'number', 'FuzzySet.d');
141
+ this.#d = value;
142
+ }
143
+ /**
144
+ * @param {string} name - Name of the set (e.g., "Hot").
145
+ * @param {number} a - Left foot.
146
+ * @param {number} b - Left shoulder.
147
+ * @param {number} c - Right shoulder.
148
+ * @param {number} d - Right feet.
149
+ */
150
+ constructor(name, a, b, c, d) {
151
+ this.name = name;
152
+ this.a = a;
153
+ this.b = b;
154
+ this.c = c;
155
+ this.d = d;
156
+ }
157
+ /**
158
+ * Calculates the membership degree.
159
+ * @param {number} x - Crisp input.
160
+ * @returns {number}
161
+ */
162
+ calculate(x) {
163
+ validateType(x, 'number', 'calculate.x');
164
+ return FuzzySet.trapezoid(x, this.#a, this.#b, this.#c, this.#d);
165
+ }
166
+ }
167
+ /**
168
+ * The Inference Engine handles linguistic variables and defuzzification.
169
+ */
170
+ class MamdaniInferenceSystem {
171
+ /** @type {Map<string, FuzzySet[]>} - Storage for linguistic variables */
172
+ #variables = new Map();
173
+ /**
174
+ * Registers a linguistic variable and its sets.
175
+ * @param {string} name - Variable name (e.g., "temperature").
176
+ * @param {FuzzySet[]} sets - Array of fuzzy sets.
177
+ */
178
+ addVariable(name, sets) {
179
+ validateType(name, 'string', 'addVariable.name');
180
+ validateFuzzySets(sets);
181
+ this.#variables.set(name, sets);
182
+ }
183
+ /**
184
+ * Removes a linguistic variable.
185
+ * @param {string} name - Variable name (e.g., "temperature").
186
+ * @returns {boolean} True if the element was successfully removed.
187
+ */
188
+ removeVariable(name) {
189
+ validateType(name, 'string', 'removeVariable.name');
190
+ return this.#variables.delete(name);
191
+ }
192
+ /**
193
+ * Gets a linguistic variable and its sets.
194
+ * @param {string} name - Variable name (e.g., "temperature").
195
+ * @returns {FuzzySet[]}
196
+ */
197
+ getVariable(name) {
198
+ validateType(name, 'string', 'getVariable.name');
199
+ /** @type {FuzzySet[] | undefined} - Attempted fetch from map */
200
+ const result = this.#variables.get(name);
201
+ if (!result)
202
+ throw new Error(`Linguistic variable '${name}' not found in the inference system.`);
203
+ return [...result];
204
+ }
205
+ /**
206
+ * Checks if a linguistic variable exists.
207
+ * @param {string} name - Variable name (e.g., "temperature").
208
+ * @returns {boolean}
209
+ */
210
+ hasVariable(name) {
211
+ validateType(name, 'string', 'hasVariable.name');
212
+ return this.#variables.has(name);
213
+ }
214
+ /**
215
+ * Fuzzifies a crisp input into a map of memberships.
216
+ * @param {string} varName
217
+ * @param {number} value
218
+ * @returns {Object.<string, number>}
219
+ */
220
+ fuzzify(varName, value) {
221
+ validateType(varName, 'string', 'fuzzify.varName');
222
+ validateType(value, 'number', 'fuzzify.value');
223
+ /** @type {FuzzySet[]} - The sets associated with the variable */
224
+ const sets = this.#variables.get(varName) || [];
225
+ /** @type {Object.<string, number>} - The fuzzified results dictionary */
226
+ const results = {};
227
+ sets.forEach((set) => {
228
+ results[set.name] = set.calculate(value);
229
+ });
230
+ return results;
231
+ }
232
+ }
233
+ export { FuzzySet, MamdaniInferenceSystem };
package/docs/v1/README.md CHANGED
@@ -63,6 +63,7 @@ This folder contains the core scripts we have worked on so far. Each file is a m
63
63
  * 📝 **[TinyTextDiffer](./libs/TinyTextDiffer.md)** — A granular text comparison utility using the LCS algorithm to detect additions, deletions, and unchanged segments between multiple history versions, returning a clean, parseable diff structure.
64
64
  * 🕒 **[TinyAnalogClock](./libs/TinyAnalogClock.md)** — A lightweight analog clock engine for managing time-based rotations, supporting custom offsets, smooth transitions, and easy binding to CSS variables rendering.
65
65
  * 🔍 **[TinyArrayComparator](./libs/TinyArrayComparator.md)** — A lightweight, highly optimized JavaScript utility class designed to compare two arrays and efficiently detect which items were **added** or **deleted**.
66
+ * 🧠 **[TinyMamdaniInferenceSystem](./libs/TinyMamdaniInferenceSystem.md)** — A implementation of a Mamdani Inference System, allowing you to model logic using trapezoidal membership functions.
66
67
 
67
68
  ### 3. **`fileManager/`**
68
69
  * 📁 **[Main](./fileManager/main.md)** — A Node.js file/directory utility module with support for JSON, backups, renaming, size analysis, and more.