2022-05-23 11:43:42 +02:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
// Code generated by jFuzzyLogic
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
function ruleAccumulationMethod_max(defuzzifierValue, valueToAggregate) {
|
|
|
|
return (defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate);
|
|
|
|
}
|
|
|
|
|
|
|
|
function ruleActivationMethod_min(degreeOfSupport, membership) {
|
|
|
|
return (degreeOfSupport < membership ? degreeOfSupport : membership);
|
|
|
|
}
|
|
|
|
|
|
|
|
function ruleConnectionMethod_and(antecedent1, antecedent2) {
|
|
|
|
return (antecedent1 < antecedent2 ? antecedent1 : antecedent2);
|
|
|
|
}
|
|
|
|
|
|
|
|
function ruleConnectionMethod_or(antecedent1, antecedent2) {
|
|
|
|
return (antecedent1 > antecedent2 ? antecedent1 : antecedent2);
|
|
|
|
}
|
|
|
|
|
|
|
|
class FunctionBlock_tipper {
|
|
|
|
|
|
|
|
// VAR_INPUT
|
|
|
|
food;
|
|
|
|
service;
|
|
|
|
|
|
|
|
// VAR_OUTPUT
|
|
|
|
tip;
|
|
|
|
|
|
|
|
// FUZZIFY food
|
|
|
|
food_delicious;
|
|
|
|
food_rancid;
|
|
|
|
|
|
|
|
// FUZZIFY service
|
|
|
|
service_excellent;
|
|
|
|
service_good;
|
|
|
|
service_poor;
|
|
|
|
|
|
|
|
// DEFUZZIFY tip
|
|
|
|
defuzzify_tip;
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
constructor() {
|
|
|
|
this.tip = 0.0;
|
|
|
|
this.defuzzify_tip = new Array(1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate function block
|
|
|
|
calc() {
|
|
|
|
this.reset();
|
|
|
|
this.fuzzify();
|
|
|
|
this.calc_No1();
|
|
|
|
this.defuzzify();
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULEBLOCK No1
|
|
|
|
calc_No1() {
|
|
|
|
// RULE 1 : IF (service IS poor) OR (food IS rancid) THEN tip IS cheap;
|
|
|
|
let degreeOfSupport_1 = 1.0 * (ruleConnectionMethod_or(this.service_poor, this.food_rancid));
|
|
|
|
if (degreeOfSupport_1 > 0) {
|
|
|
|
for (let i = 0; i < 1000; i++) {
|
|
|
|
let x = 0.0 + i * 0.03;
|
|
|
|
let membership = this.membership_tip_cheap(x);
|
|
|
|
let y = ruleActivationMethod_min(degreeOfSupport_1 , membership);
|
|
|
|
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULE 2 : IF service IS good THEN tip IS average;
|
|
|
|
let degreeOfSupport_2 = 1.0 * (this.service_good);
|
|
|
|
if (degreeOfSupport_2 > 0) {
|
|
|
|
for (let i = 0; i < 1000; i++) {
|
|
|
|
let x = 0.0 + i * 0.03;
|
|
|
|
let membership = this.membership_tip_average(x);
|
|
|
|
let y = ruleActivationMethod_min(degreeOfSupport_2 , membership);
|
|
|
|
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULE 3 : IF (service IS excellent) AND (food IS delicious) THEN tip IS generous;
|
|
|
|
let degreeOfSupport_3 = 1.0 * (ruleConnectionMethod_and(this.service_excellent, this.food_delicious));
|
|
|
|
if (degreeOfSupport_3 > 0) {
|
|
|
|
for (let i = 0; i < 1000; i++) {
|
|
|
|
let x = 0.0 + i * 0.03;
|
|
|
|
let membership = this.membership_tip_generous(x);
|
|
|
|
let y = ruleActivationMethod_min(degreeOfSupport_3 , membership);
|
|
|
|
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Defuzzify
|
|
|
|
defuzzify() {
|
|
|
|
let sum_tip = 0.0;
|
|
|
|
let wsum_tip = 0.0;
|
|
|
|
let x;
|
|
|
|
for (let i = 0; i < 1000; i++) {
|
|
|
|
x = 0.0 + i * 0.03;
|
|
|
|
sum_tip += this.defuzzify_tip[i];
|
|
|
|
wsum_tip += x * this.defuzzify_tip[i];
|
|
|
|
}
|
2022-07-27 19:11:50 +02:00
|
|
|
if (sum_tip == 0) {
|
|
|
|
sum_tip = 1.0;
|
|
|
|
}
|
2022-05-23 11:43:42 +02:00
|
|
|
this.tip = wsum_tip / sum_tip;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fuzzify all variables
|
|
|
|
fuzzify() {
|
|
|
|
this.food_delicious = this.membership_food_delicious(this.food);
|
|
|
|
this.food_rancid = this.membership_food_rancid(this.food);
|
|
|
|
this.service_excellent = this.membership_service_excellent(this.service);
|
|
|
|
this.service_good = this.membership_service_good(this.service);
|
|
|
|
this.service_poor = this.membership_service_poor(this.service);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Membership functions
|
|
|
|
membership_food_delicious(x) {
|
|
|
|
if (x <= 7.0) return 0.0;
|
|
|
|
if (x > 9.0) return 1.0;
|
|
|
|
if (x <= 9.0) return 0.0 + (1.0 - 0.0) * ((x - 7.0) / (9.0 - 7.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_food_rancid(x) {
|
|
|
|
if (x <= 0.0) return 1.0;
|
|
|
|
if (x > 3.0) return 0.0;
|
|
|
|
if (x <= 1.0) return 1.0 + (1.0 - 1.0) * ((x - 0.0) / (1.0 - 0.0));
|
|
|
|
if (x <= 3.0) return 1.0 + (0.0 - 1.0) * ((x - 1.0) / (3.0 - 1.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_service_excellent(x) {
|
|
|
|
if (x <= 6.0) return 0.0;
|
|
|
|
if (x > 9.0) return 1.0;
|
|
|
|
if (x <= 9.0) return 0.0 + (1.0 - 0.0) * ((x - 6.0) / (9.0 - 6.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_service_good(x) {
|
|
|
|
if (x <= 1.0) return 0.0;
|
|
|
|
if (x > 9.0) return 0.0;
|
|
|
|
if (x <= 4.0) return 0.0 + (1.0 - 0.0) * ((x - 1.0) / (4.0 - 1.0));
|
|
|
|
if (x <= 6.0) return 1.0 + (1.0 - 1.0) * ((x - 4.0) / (6.0 - 4.0));
|
|
|
|
if (x <= 9.0) return 1.0 + (0.0 - 1.0) * ((x - 6.0) / (9.0 - 6.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_service_poor(x) {
|
|
|
|
if (x <= 0.0) return 1.0;
|
|
|
|
if (x > 4.0) return 0.0;
|
|
|
|
if (x <= 4.0) return 1.0 + (0.0 - 1.0) * ((x - 0.0) / (4.0 - 0.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_tip_average(x) {
|
|
|
|
if (x <= 10.0) return 0.0;
|
|
|
|
if (x > 20.0) return 0.0;
|
|
|
|
if (x <= 15.0) return 0.0 + (1.0 - 0.0) * ((x - 10.0) / (15.0 - 10.0));
|
|
|
|
if (x <= 20.0) return 1.0 + (0.0 - 1.0) * ((x - 15.0) / (20.0 - 15.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_tip_cheap(x) {
|
|
|
|
if (x <= 0.0) return 0.0;
|
|
|
|
if (x > 10.0) return 0.0;
|
|
|
|
if (x <= 5.0) return 0.0 + (1.0 - 0.0) * ((x - 0.0) / (5.0 - 0.0));
|
|
|
|
if (x <= 10.0) return 1.0 + (0.0 - 1.0) * ((x - 5.0) / (10.0 - 5.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
membership_tip_generous(x) {
|
|
|
|
if (x <= 20.0) return 0.0;
|
|
|
|
if (x > 30.0) return 0.0;
|
|
|
|
if (x <= 25.0) return 0.0 + (1.0 - 0.0) * ((x - 20.0) / (25.0 - 20.0));
|
|
|
|
if (x <= 30.0) return 1.0 + (0.0 - 1.0) * ((x - 25.0) / (30.0 - 25.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Print
|
|
|
|
print() {
|
|
|
|
console.log("Function block tipper:\n");
|
|
|
|
console.log(" Input %s: %f\n", "food" , this.food);
|
|
|
|
console.log(" %s: %f\n", "food_delicious" , this.food_delicious);
|
|
|
|
console.log(" %s: %f\n", "food_rancid" , this.food_rancid);
|
|
|
|
console.log(" Input %s: %f\n", "service" , this.service);
|
|
|
|
console.log(" %s: %f\n", "service_excellent" , this.service_excellent);
|
|
|
|
console.log(" %s: %f\n", "service_good" , this.service_good);
|
|
|
|
console.log(" %s: %f\n", "service_poor" , this.service_poor);
|
|
|
|
console.log(" Output %s: %f\n", "tip" , this.tip);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset output
|
|
|
|
reset() {
|
|
|
|
for (let i = 0 ; i < 1000; i++) {
|
|
|
|
this.defuzzify_tip[i] = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
function main(food, service) {
|
|
|
|
// Create function blocks
|
|
|
|
const tipper = new FunctionBlock_tipper();
|
|
|
|
|
|
|
|
// Parse input
|
|
|
|
tipper.food = food;
|
|
|
|
tipper.service = service;
|
|
|
|
|
|
|
|
// Calculate
|
|
|
|
tipper.calc();
|
|
|
|
|
|
|
|
// Show results
|
|
|
|
tipper.print();
|
2022-07-27 13:51:24 +02:00
|
|
|
|
|
|
|
return [tipper.tip];
|
2022-05-23 11:43:42 +02:00
|
|
|
}
|