es6-fuzz 4.0.1 → 5.0.1
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/Readme.md +3 -4
- package/docs/CHANGELOG.md +30 -20
- package/jsdoc.json +0 -1
- package/lib/curve/grade.js +7 -0
- package/lib/curve/reverse-grade.js +6 -1
- package/lib/curve/sigmoid.js +13 -7
- package/lib/curve/trapezoid.js +25 -2
- package/lib/curve/triangle.js +27 -0
- package/lib/logic.js +0 -2
- package/package.json +6 -6
- package/test/curve/constant.test.js +15 -0
- package/test/{shape-fuzzy-function-test.js → curve/fuzzy-function.test.js} +2 -1
- package/test/{shape-grade-test.js → curve/grade.test.js} +9 -1
- package/test/{shape-reverse-grade-test.js → curve/reverse-grade.test.js} +9 -1
- package/test/curve/shape.test.js +30 -0
- package/test/{shape-sigmoid-test.js → curve/sigmoid/sigmoid-basic.test.js} +3 -13
- package/test/curve/sigmoid/sigmoid-center-behavior.test.js +66 -0
- package/test/curve/sigmoid/sigmoid-slope.test.js +15 -0
- package/test/curve/trapezoid/trapezoid-basic.test.js +54 -0
- package/test/curve/trapezoid/trapezoid-bounds.test.js +30 -0
- package/test/{shape-triangle-test.js → curve/triangle.test.js} +2 -1
- package/test/edge-cases/constant-edge-values.test.js +56 -0
- package/test/edge-cases/fuzzy-function-edge-cases.test.js +71 -0
- package/test/edge-cases/grade-edge-cases.test.js +42 -0
- package/test/edge-cases/reverse-grade-edge-cases.test.js +42 -0
- package/test/edge-cases/shapes-large-values.test.js +78 -0
- package/test/edge-cases/shapes-negative-values.test.js +75 -0
- package/test/edge-cases/sigmoid-edge-cases.test.js +70 -0
- package/test/edge-cases/trapezoid-special-cases.test.js +94 -0
- package/test/edge-cases/triangle-degenerate-cases.test.js +62 -0
- package/test/error-handling/empty-rules-handling.test.js +25 -0
- package/test/error-handling/es6-class-instantiation.test.js +52 -0
- package/test/error-handling/fuzzy-function-validation.test.js +66 -0
- package/test/error-handling/invalid-chaining-sequences.test.js +40 -0
- package/test/error-handling/logic-validation.test.js +78 -0
- package/test/error-handling/property-immutability.test.js +29 -0
- package/test/error-handling/shape-constructor-validation.test.js +70 -0
- package/test/{example-test.js → example.test.js} +1 -0
- package/test/init-called.test.js +1 -0
- package/test/integration/and-or-not-combinations.test.js +42 -0
- package/test/integration/complex-logic-chains.test.js +85 -0
- package/test/integration/edge-case-combinations.test.js +55 -0
- package/test/integration/mixing-shape-types.test.js +44 -0
- package/test/integration/performance-many-rules.test.js +42 -0
- package/test/integration/real-world-scenarios.test.js +50 -0
- package/test/integration/state-management.test.js +47 -0
- package/test/js-bool.test.js +2 -1
- package/test/logic/attack-rage-calculation.test.js +22 -0
- package/test/logic/behaves-like-number.test.js +22 -0
- package/test/logic/interface.test.js +20 -0
- package/test/logic/not-operation.test.js +17 -0
- package/test/constant-test.js +0 -13
- package/test/logic-test.js +0 -66
- package/test/shape-test.js +0 -16
- package/test/shape-trapezoid-test.js +0 -25
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const FuzzyFunction = require('../../lib/curve/fuzzy-function');
|
|
5
|
+
|
|
6
|
+
describe('FuzzyFunction edge cases', function() {
|
|
7
|
+
describe('functions returning values outside [0,1]', function() {
|
|
8
|
+
describe('function returning > 1 for x > 0.5', function() {
|
|
9
|
+
const func1 = new FuzzyFunction(x => x * 2);
|
|
10
|
+
|
|
11
|
+
it('should return valid value for x=0.3', function() {
|
|
12
|
+
assert.equal(func1.fuzzify(0.3), 0.6);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should return exactly 1 for x=0.5', function() {
|
|
16
|
+
assert.equal(func1.fuzzify(0.5), 1);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should throw error for x=0.7', function() {
|
|
20
|
+
assert.throws(() => func1.fuzzify(0.7), /fuzzified result must be smaller than 1/);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('function returning < 0 for x < 1', function() {
|
|
25
|
+
const func2 = new FuzzyFunction(x => x - 1);
|
|
26
|
+
|
|
27
|
+
it('should throw error for x=0.5', function() {
|
|
28
|
+
assert.throws(() => func2.fuzzify(0.5), /fuzzified result must be smaller than 1/);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should return exactly 0 for x=1', function() {
|
|
32
|
+
assert.equal(func2.fuzzify(1), 0);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should throw error for x=0.8', function() {
|
|
36
|
+
assert.throws(() => func2.fuzzify(0.8), /fuzzified result must be smaller than 1/);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('complex mathematical functions', function() {
|
|
42
|
+
const sinFunc = new FuzzyFunction(x => (Math.sin(x) + 1) / 2);
|
|
43
|
+
|
|
44
|
+
it('should return 0.5 for x=0', function() {
|
|
45
|
+
assert(sinFunc.fuzzify(0) === 0.5);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should return 1 for x=PI/2', function() {
|
|
49
|
+
assert(sinFunc.fuzzify(Math.PI / 2) === 1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should return 0 for x=3*PI/2', function() {
|
|
53
|
+
assert(sinFunc.fuzzify(3 * Math.PI / 2) === 0);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('functions that throw errors', function() {
|
|
58
|
+
const errorFunc = new FuzzyFunction(x => {
|
|
59
|
+
if (x < 0) throw new Error('Negative input');
|
|
60
|
+
return x;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return valid value for x=0.5', function() {
|
|
64
|
+
assert.equal(errorFunc.fuzzify(0.5), 0.5);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should throw error for negative input', function() {
|
|
68
|
+
assert.throws(() => errorFunc.fuzzify(-1), /Negative input/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Grade = require('../../lib/curve/grade');
|
|
5
|
+
|
|
6
|
+
describe('Grade edge cases', function() {
|
|
7
|
+
describe('vertical grade (x0=x1)', function() {
|
|
8
|
+
const grade = new Grade(5, 5);
|
|
9
|
+
|
|
10
|
+
it('should return 0 for value before x0', function() {
|
|
11
|
+
assert.equal(grade.fuzzify(4.9), 0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return 1 for value at x0=x1', function() {
|
|
15
|
+
assert.equal(grade.fuzzify(5), 1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return 1 for value after x1', function() {
|
|
19
|
+
assert.equal(grade.fuzzify(5.1), 1);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return 1 for very large value', function() {
|
|
23
|
+
assert.equal(grade.fuzzify(100), 1);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('very steep grade', function() {
|
|
28
|
+
const grade = new Grade(5, 5.0001);
|
|
29
|
+
|
|
30
|
+
it('should return 0 for value before x0', function() {
|
|
31
|
+
assert.equal(grade.fuzzify(4.9), 0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return greater than 0.4 for value at midpoint', function() {
|
|
35
|
+
assert(grade.fuzzify(5.00005) > 0.4);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return 1 for value well after x1', function() {
|
|
39
|
+
assert.equal(grade.fuzzify(5.1), 1);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const ReverseGrade = require('../../lib/curve/reverse-grade');
|
|
5
|
+
|
|
6
|
+
describe('ReverseGrade edge cases', function() {
|
|
7
|
+
describe('vertical reverse grade (x0=x1)', function() {
|
|
8
|
+
const reverseGrade = new ReverseGrade(5, 5);
|
|
9
|
+
|
|
10
|
+
it('should return 1 for value before x0', function() {
|
|
11
|
+
assert.equal(reverseGrade.fuzzify(4.9), 1);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return 1 for value at x0=x1', function() {
|
|
15
|
+
assert.equal(reverseGrade.fuzzify(5), 1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return 0 for value after x1', function() {
|
|
19
|
+
assert.equal(reverseGrade.fuzzify(5.1), 0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return 0 for very large value', function() {
|
|
23
|
+
assert.equal(reverseGrade.fuzzify(100), 0);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('very steep reverse grade', function() {
|
|
28
|
+
const reverseGrade = new ReverseGrade(5, 5.0001);
|
|
29
|
+
|
|
30
|
+
it('should return 1 for value before x0', function() {
|
|
31
|
+
assert.equal(reverseGrade.fuzzify(4.9), 1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return less than 0.6 for value at midpoint', function() {
|
|
35
|
+
assert(reverseGrade.fuzzify(5.00005) < 0.6);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return 0 for value well after x1', function() {
|
|
39
|
+
assert.equal(reverseGrade.fuzzify(5.1), 0);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Triangle = require('../../lib/curve/triangle');
|
|
5
|
+
const Trapezoid = require('../../lib/curve/trapezoid');
|
|
6
|
+
const Grade = require('../../lib/curve/grade');
|
|
7
|
+
const ReverseGrade = require('../../lib/curve/reverse-grade');
|
|
8
|
+
const Sigmoid = require('../../lib/curve/sigmoid');
|
|
9
|
+
|
|
10
|
+
describe('Shapes with very large x values', function() {
|
|
11
|
+
describe('Infinity handling', function() {
|
|
12
|
+
const triangle = new Triangle(0, 10, 20);
|
|
13
|
+
const trapezoid = new Trapezoid(0, 10, 20, 30);
|
|
14
|
+
const grade = new Grade(0, 10);
|
|
15
|
+
const reverseGrade = new ReverseGrade(0, 10);
|
|
16
|
+
const sigmoid = new Sigmoid(10, 1);
|
|
17
|
+
|
|
18
|
+
it('should return 0 for triangle with positive Infinity', function() {
|
|
19
|
+
assert.equal(triangle.fuzzify(Infinity), 0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return 0 for triangle with negative Infinity', function() {
|
|
23
|
+
assert.equal(triangle.fuzzify(-Infinity), 0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return 0 for trapezoid with positive Infinity', function() {
|
|
27
|
+
assert.equal(trapezoid.fuzzify(Infinity), 0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return 0 for trapezoid with negative Infinity', function() {
|
|
31
|
+
assert.equal(trapezoid.fuzzify(-Infinity), 0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return 1 for grade with positive Infinity', function() {
|
|
35
|
+
assert.equal(grade.fuzzify(Infinity), 1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return 0 for grade with negative Infinity', function() {
|
|
39
|
+
assert.equal(grade.fuzzify(-Infinity), 0);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return 0 for reverseGrade with positive Infinity', function() {
|
|
43
|
+
assert.equal(reverseGrade.fuzzify(Infinity), 0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return 1 for reverseGrade with negative Infinity', function() {
|
|
47
|
+
assert.equal(reverseGrade.fuzzify(-Infinity), 1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should return 1 for sigmoid with positive Infinity', function() {
|
|
51
|
+
assert.equal(sigmoid.fuzzify(Infinity), 1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return 0 for sigmoid with negative Infinity', function() {
|
|
55
|
+
assert.equal(sigmoid.fuzzify(-Infinity), 0);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('very large numbers', function() {
|
|
60
|
+
const triangle = new Triangle(0, 1e10, 2e10);
|
|
61
|
+
|
|
62
|
+
it('should return 0 for value at x0', function() {
|
|
63
|
+
assert.equal(triangle.fuzzify(0), 0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return 1 for value at x1', function() {
|
|
67
|
+
assert.equal(triangle.fuzzify(1e10), 1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should return 0 for value at x2', function() {
|
|
71
|
+
assert.equal(triangle.fuzzify(2e10), 0);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should return 0.5 for value at midpoint', function() {
|
|
75
|
+
assert.equal(triangle.fuzzify(1.5e10), 0.5);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Triangle = require('../../lib/curve/triangle');
|
|
5
|
+
const Trapezoid = require('../../lib/curve/trapezoid');
|
|
6
|
+
|
|
7
|
+
describe('Shapes with negative x values', function() {
|
|
8
|
+
describe('triangle with negative x values', function() {
|
|
9
|
+
const triangle = new Triangle(-10, -5, 0);
|
|
10
|
+
|
|
11
|
+
it('should return 0 for value far before x0', function() {
|
|
12
|
+
assert.equal(triangle.fuzzify(-15), 0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should return 0 for value at x0', function() {
|
|
16
|
+
assert.equal(triangle.fuzzify(-10), 0);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return 0.5 for value at midpoint of left slope', function() {
|
|
20
|
+
assert.equal(triangle.fuzzify(-7.5), 0.5);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should return 1 for value at x1', function() {
|
|
24
|
+
assert.equal(triangle.fuzzify(-5), 1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return 0.5 for value at midpoint of right slope', function() {
|
|
28
|
+
assert.equal(triangle.fuzzify(-2.5), 0.5);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should return 0 for value at x2', function() {
|
|
32
|
+
assert.equal(triangle.fuzzify(0), 0);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return 0 for value after x2', function() {
|
|
36
|
+
assert.equal(triangle.fuzzify(5), 0);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('trapezoid with negative x values', function() {
|
|
41
|
+
const trapezoid = new Trapezoid(-20, -15, -5, 0);
|
|
42
|
+
|
|
43
|
+
it('should return 0 for value before x0', function() {
|
|
44
|
+
assert.equal(trapezoid.fuzzify(-25), 0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should return 0 for value at x0', function() {
|
|
48
|
+
assert.equal(trapezoid.fuzzify(-20), 0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return 0.5 for value at midpoint of left slope', function() {
|
|
52
|
+
assert.equal(trapezoid.fuzzify(-17.5), 0.5);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should return 1 for value at x1', function() {
|
|
56
|
+
assert.equal(trapezoid.fuzzify(-15), 1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should return 1 for value in middle plateau', function() {
|
|
60
|
+
assert.equal(trapezoid.fuzzify(-10), 1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return 1 for value at x2', function() {
|
|
64
|
+
assert.equal(trapezoid.fuzzify(-5), 1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should return 0.5 for value at midpoint of right slope', function() {
|
|
68
|
+
assert.equal(trapezoid.fuzzify(-2.5), 0.5);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should return 0 for value at x3', function() {
|
|
72
|
+
assert.equal(trapezoid.fuzzify(0), 0);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Sigmoid = require('../../lib/curve/sigmoid');
|
|
5
|
+
|
|
6
|
+
describe('Sigmoid edge cases', function() {
|
|
7
|
+
describe('zero slope (becomes step function)', function() {
|
|
8
|
+
const sigmoid = new Sigmoid(5, 0);
|
|
9
|
+
|
|
10
|
+
it('should return 0 for value before center', function() {
|
|
11
|
+
assert.equal(sigmoid.fuzzify(4.9), 0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return 0.5 for value at center', function() {
|
|
15
|
+
assert.equal(sigmoid.fuzzify(5), 0.5);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return 1 for value after center', function() {
|
|
19
|
+
assert.equal(sigmoid.fuzzify(5.1), 1);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('very small slope (near step function)', function() {
|
|
24
|
+
const sigmoid = new Sigmoid(5, 0.0001);
|
|
25
|
+
|
|
26
|
+
it('should return near 0 for value slightly before center', function() {
|
|
27
|
+
assert(sigmoid.fuzzify(4.99) < 0.01);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return 0.5 for value at center', function() {
|
|
31
|
+
assert(sigmoid.fuzzify(5) === 0.5);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return near 1 for value slightly after center', function() {
|
|
35
|
+
assert(sigmoid.fuzzify(5.01) > 0.99);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('very large slope (near constant 0.5)', function() {
|
|
40
|
+
const sigmoid = new Sigmoid(5, 10000);
|
|
41
|
+
|
|
42
|
+
it('should return approximately 0.5 for value far left', function() {
|
|
43
|
+
assert(Math.abs(sigmoid.fuzzify(0) - 0.5) < 0.1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return 0.5 for value at center', function() {
|
|
47
|
+
assert(sigmoid.fuzzify(5) === 0.5);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should return approximately 0.5 for value far right', function() {
|
|
51
|
+
assert(Math.abs(sigmoid.fuzzify(10) - 0.5) < 0.1);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('negative slope', function() {
|
|
56
|
+
const sigmoid = new Sigmoid(5, -1);
|
|
57
|
+
|
|
58
|
+
it('should return greater than 0.5 for value before center', function() {
|
|
59
|
+
assert(sigmoid.fuzzify(3) > 0.5);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should return 0.5 for value at center', function() {
|
|
63
|
+
assert(sigmoid.fuzzify(5) === 0.5);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return less than 0.5 for value after center', function() {
|
|
67
|
+
assert(sigmoid.fuzzify(7) < 0.5);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Trapezoid = require('../../lib/curve/trapezoid');
|
|
5
|
+
|
|
6
|
+
describe('Trapezoid special cases', function() {
|
|
7
|
+
describe('square trapezoid (x1=x2)', function() {
|
|
8
|
+
const trapezoid = new Trapezoid(0, 5, 5, 10);
|
|
9
|
+
|
|
10
|
+
it('should return 0 for value before x0', function() {
|
|
11
|
+
assert.equal(trapezoid.fuzzify(-1), 0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return 0 for value at x0', function() {
|
|
15
|
+
assert.equal(trapezoid.fuzzify(0), 0);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return 0.5 for value at midpoint of left slope', function() {
|
|
19
|
+
assert.equal(trapezoid.fuzzify(2.5), 0.5);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return 1 for value at x1=x2', function() {
|
|
23
|
+
assert.equal(trapezoid.fuzzify(5), 1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return 0.5 for value at midpoint of right slope', function() {
|
|
27
|
+
assert.equal(trapezoid.fuzzify(7.5), 0.5);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return 0 for value at x3', function() {
|
|
31
|
+
assert.equal(trapezoid.fuzzify(10), 0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return 0 for value after x3', function() {
|
|
35
|
+
assert.equal(trapezoid.fuzzify(11), 0);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('degenerate trapezoid (x0=x1 and x2=x3)', function() {
|
|
40
|
+
const trapezoid = new Trapezoid(5, 5, 10, 10);
|
|
41
|
+
|
|
42
|
+
it('should return 0 for value before x0', function() {
|
|
43
|
+
assert.equal(trapezoid.fuzzify(4.9), 0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return 1 for value at x0=x1', function() {
|
|
47
|
+
assert.equal(trapezoid.fuzzify(5), 1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should return 1 for value in middle', function() {
|
|
51
|
+
assert.equal(trapezoid.fuzzify(7.5), 1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return 1 for value at x2=x3', function() {
|
|
55
|
+
assert.equal(trapezoid.fuzzify(10), 1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should return 0 for value after x3', function() {
|
|
59
|
+
assert.equal(trapezoid.fuzzify(10.1), 0);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('very narrow trapezoid (x1 and x2 very close)', function() {
|
|
64
|
+
const trapezoid = new Trapezoid(0, 4.999, 5.001, 10);
|
|
65
|
+
|
|
66
|
+
it('should return 1 for value at center', function() {
|
|
67
|
+
assert.equal(trapezoid.fuzzify(5), 1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should return approximately 1 for value at x1', function() {
|
|
71
|
+
assert(Math.abs(trapezoid.fuzzify(4.999) - 1) < 0.01);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should return approximately 1 for value at x2', function() {
|
|
75
|
+
assert(Math.abs(trapezoid.fuzzify(5.001) - 1) < 0.01);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('all points equal (degenerate to point)', function() {
|
|
80
|
+
const trapezoid = new Trapezoid(5, 5, 5, 5);
|
|
81
|
+
|
|
82
|
+
it('should return 0 for value before the point', function() {
|
|
83
|
+
assert.equal(trapezoid.fuzzify(4.9), 0);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should return 1 for value at the point', function() {
|
|
87
|
+
assert.equal(trapezoid.fuzzify(5), 1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should return 0 for value after the point', function() {
|
|
91
|
+
assert.equal(trapezoid.fuzzify(5.1), 0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Triangle = require('../../lib/curve/triangle');
|
|
5
|
+
|
|
6
|
+
describe('Triangle degenerate cases', function() {
|
|
7
|
+
describe('triangle with all points equal (x0=x1=x2)', function() {
|
|
8
|
+
const triangle = new Triangle(5, 5, 5);
|
|
9
|
+
|
|
10
|
+
it('should return 0 for value before the point', function() {
|
|
11
|
+
assert.equal(triangle.fuzzify(4.9), 0);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return 1 for value at the point', function() {
|
|
15
|
+
assert.equal(triangle.fuzzify(5), 1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return 0 for value after the point', function() {
|
|
19
|
+
assert.equal(triangle.fuzzify(5.1), 0);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('triangle with x0=x1 (right angle left)', function() {
|
|
24
|
+
const triangle = new Triangle(5, 5, 10);
|
|
25
|
+
|
|
26
|
+
it('should return 0 for value before x0', function() {
|
|
27
|
+
assert.equal(triangle.fuzzify(4.9), 0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return 1 for value at x0=x1', function() {
|
|
31
|
+
assert.equal(triangle.fuzzify(5), 1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return 0.5 for value at midpoint', function() {
|
|
35
|
+
assert.equal(triangle.fuzzify(7.5), 0.5);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return 0 for value at x2', function() {
|
|
39
|
+
assert.equal(triangle.fuzzify(10), 0);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('triangle with x1=x2 (right angle right)', function() {
|
|
44
|
+
const triangle = new Triangle(0, 5, 5);
|
|
45
|
+
|
|
46
|
+
it('should return 0 for value at x0', function() {
|
|
47
|
+
assert.equal(triangle.fuzzify(0), 0);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should return 0.5 for value at midpoint', function() {
|
|
51
|
+
assert.equal(triangle.fuzzify(2.5), 0.5);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return 1 for value at x1=x2', function() {
|
|
55
|
+
assert.equal(triangle.fuzzify(5), 1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should return 0 for value after x2', function() {
|
|
59
|
+
assert.equal(triangle.fuzzify(5.1), 0);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Logic = require('../../lib/logic');
|
|
5
|
+
|
|
6
|
+
describe('Empty rules array handling', function() {
|
|
7
|
+
describe('defuzzify with no rules', function() {
|
|
8
|
+
const logic = new Logic();
|
|
9
|
+
logic.initCalled = true;
|
|
10
|
+
logic.rules = [];
|
|
11
|
+
const result = logic.defuzzify(5);
|
|
12
|
+
|
|
13
|
+
it('should return defuzzified as none', function() {
|
|
14
|
+
assert.equal(result.defuzzified, 'none');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should return fuzzified as 0', function() {
|
|
18
|
+
assert.equal(result.fuzzified, 0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return empty rules array', function() {
|
|
22
|
+
assert.deepEqual(result.rules, []);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const Logic = require('../../lib/logic');
|
|
5
|
+
const Triangle = require('../../lib/curve/triangle');
|
|
6
|
+
const Trapezoid = require('../../lib/curve/trapezoid');
|
|
7
|
+
const Grade = require('../../lib/curve/grade');
|
|
8
|
+
const ReverseGrade = require('../../lib/curve/reverse-grade');
|
|
9
|
+
const Sigmoid = require('../../lib/curve/sigmoid');
|
|
10
|
+
const Constant = require('../../lib/curve/constant');
|
|
11
|
+
const FuzzyFunction = require('../../lib/curve/fuzzy-function');
|
|
12
|
+
const Shape = require('../../lib/curve/shape');
|
|
13
|
+
|
|
14
|
+
describe('ES6 class instantiation', function() {
|
|
15
|
+
describe('shapes without new keyword', function() {
|
|
16
|
+
it('should throw error when calling Triangle without new', function() {
|
|
17
|
+
assert.throws(() => Triangle(0, 5, 10), /Class constructor .* cannot be invoked without 'new'/);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should throw error when calling Trapezoid without new', function() {
|
|
21
|
+
assert.throws(() => Trapezoid(0, 5, 10, 15), /Class constructor .* cannot be invoked without 'new'/);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should throw error when calling Grade without new', function() {
|
|
25
|
+
assert.throws(() => Grade(0, 10), /Class constructor .* cannot be invoked without 'new'/);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should throw error when calling ReverseGrade without new', function() {
|
|
29
|
+
assert.throws(() => ReverseGrade(0, 10), /Class constructor .* cannot be invoked without 'new'/);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should throw error when calling Sigmoid without new', function() {
|
|
33
|
+
assert.throws(() => Sigmoid(5, 1), /Class constructor .* cannot be invoked without 'new'/);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should throw error when calling Constant without new', function() {
|
|
37
|
+
assert.throws(() => Constant(0.5), /Class constructor .* cannot be invoked without 'new'/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should throw error when calling Shape without new', function() {
|
|
41
|
+
assert.throws(() => Shape(0, 5, 10, 15), /Class constructor .* cannot be invoked without 'new'/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should throw error when calling FuzzyFunction without new', function() {
|
|
45
|
+
assert.throws(() => FuzzyFunction(x => x), /Class constructor .* cannot be invoked without 'new'/);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should throw error when calling Logic without new', function() {
|
|
49
|
+
assert.throws(() => Logic(), /Class constructor .* cannot be invoked without 'new'/);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { describe, it } = require('node:test');
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const FuzzyFunction = require('../../lib/curve/fuzzy-function');
|
|
5
|
+
|
|
6
|
+
describe('FuzzyFunction validation', function() {
|
|
7
|
+
describe('invalid callback types', function() {
|
|
8
|
+
it('should throw TypeError when callback is string', function() {
|
|
9
|
+
assert.throws(() => {
|
|
10
|
+
const func = new FuzzyFunction('not a function');
|
|
11
|
+
func.fuzzify(5);
|
|
12
|
+
}, TypeError);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should throw TypeError when callback is null', function() {
|
|
16
|
+
assert.throws(() => {
|
|
17
|
+
const func = new FuzzyFunction(null);
|
|
18
|
+
func.fuzzify(5);
|
|
19
|
+
}, TypeError);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should throw TypeError when callback is undefined', function() {
|
|
23
|
+
assert.throws(() => {
|
|
24
|
+
const func = new FuzzyFunction(undefined);
|
|
25
|
+
func.fuzzify(5);
|
|
26
|
+
}, TypeError);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('callback returns non-number types', function() {
|
|
31
|
+
it('should throw error when callback returns string', function() {
|
|
32
|
+
const func = new FuzzyFunction(() => 'string');
|
|
33
|
+
assert.throws(() => func.fuzzify(5), /fuzzified result must be smaller than 1/);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return null when callback returns null', function() {
|
|
37
|
+
const func = new FuzzyFunction(() => null);
|
|
38
|
+
assert.equal(func.fuzzify(5), null);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should throw error when callback returns undefined', function() {
|
|
42
|
+
const func = new FuzzyFunction(() => undefined);
|
|
43
|
+
assert.throws(() => func.fuzzify(5), /fuzzified result must be smaller than 1/);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('callback with conditional returns', function() {
|
|
48
|
+
const func = new FuzzyFunction(x => {
|
|
49
|
+
if (x < 0) return -1; // Invalid
|
|
50
|
+
if (x > 1) return 2; // Invalid
|
|
51
|
+
return x; // Valid for [0,1]
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return valid value for input 0.5', function() {
|
|
55
|
+
assert.equal(func.fuzzify(0.5), 0.5);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw error for negative input', function() {
|
|
59
|
+
assert.throws(() => func.fuzzify(-1), /fuzzified result must be smaller than 1/);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should throw error for input greater than 1', function() {
|
|
63
|
+
assert.throws(() => func.fuzzify(2), /fuzzified result must be smaller than 1/);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|