import { FuzzyCompositeTerm } from './FuzzyCompositeTerm.js';
import { FuzzyAND } from './operators/FuzzyAND.js';
import { FuzzyOR } from './operators/FuzzyOR.js';
import { FuzzyVERY } from './operators/FuzzyVERY.js';
import { FuzzyFAIRLY } from './operators/FuzzyFAIRLY.js';
import { Logger } from '../core/Logger.js';
/**
* Class for representing a fuzzy rule. Fuzzy rules are comprised of an antecedent and
* a consequent in the form: IF antecedent THEN consequent.
*
* Compared to ordinary if/else statements with discrete values, the consequent term
* of a fuzzy rule can fire to a matter of degree.
*
* @author {@link https://github.com/Mugen87|Mugen87}
*/
class FuzzyRule {
/**
* Constructs a new fuzzy rule with the given values.
*
* @param {FuzzyTerm} antecedent - Represents the condition of the rule.
* @param {FuzzyTerm} consequence - Describes the consequence if the condition is satisfied.
*/
constructor( antecedent = null, consequence = null ) {
/**
* Represents the condition of the rule.
* @type {?FuzzyTerm}
* @default null
*/
this.antecedent = antecedent;
/**
* Describes the consequence if the condition is satisfied.
* @type {?FuzzyTerm}
* @default null
*/
this.consequence = consequence;
}
/**
* Initializes the consequent term of this fuzzy rule.
*
* @return {FuzzyRule} A reference to this fuzzy rule.
*/
initConsequence() {
this.consequence.clearDegreeOfMembership();
return this;
}
/**
* Evaluates the rule and updates the degree of membership of the consequent term with
* the degree of membership of the antecedent term.
*
* @return {FuzzyRule} A reference to this fuzzy rule.
*/
evaluate() {
this.consequence.updateDegreeOfMembership( this.antecedent.getDegreeOfMembership() );
return this;
}
/**
* Transforms this instance into a JSON object.
*
* @return {Object} The JSON object.
*/
toJSON() {
const json = {};
const antecedent = this.antecedent;
const consequence = this.consequence;
json.type = this.constructor.name;
json.antecedent = ( antecedent instanceof FuzzyCompositeTerm ) ? antecedent.toJSON() : antecedent.uuid;
json.consequence = ( consequence instanceof FuzzyCompositeTerm ) ? consequence.toJSON() : consequence.uuid;
return json;
}
/**
* Restores this instance from the given JSON object.
*
* @param {Object} json - The JSON object.
* @param {Map<String,FuzzySet>} fuzzySets - Maps fuzzy sets to UUIDs.
* @return {FuzzyRule} A reference to this fuzzy rule.
*/
fromJSON( json, fuzzySets ) {
function parseTerm( termJSON ) {
if ( typeof termJSON === 'string' ) {
// atomic term -> FuzzySet
const uuid = termJSON;
return fuzzySets.get( uuid ) || null;
} else {
// composite term
const type = termJSON.type;
let term;
switch ( type ) {
case 'FuzzyAND':
term = new FuzzyAND();
break;
case 'FuzzyOR':
term = new FuzzyOR();
break;
case 'FuzzyVERY':
term = new FuzzyVERY();
break;
case 'FuzzyFAIRLY':
term = new FuzzyFAIRLY();
break;
default:
Logger.error( 'YUKA.FuzzyRule: Unsupported operator type:', type );
return;
}
const termsJSON = termJSON.terms;
for ( let i = 0, l = termsJSON.length; i < l; i ++ ) {
// recursively parse all subordinate terms
term.terms.push( parseTerm( termsJSON[ i ] ) );
}
return term;
}
}
this.antecedent = parseTerm( json.antecedent );
this.consequence = parseTerm( json.consequence );
return this;
}
}
export { FuzzyRule };