import { BaseLogicSystem } from './base.js';
import { FuzzyParser } from '../parsers/fuzzyParser.js';
import { FuzzyValidator } from '../validators/fuzzyValidator.js';
import { LogicResult, FuzzyFormula, SolutionStep, InputFormat } from '../types.js';
import { Loggers } from '../utils/logger.js';
const logger = Loggers.systems.fuzzy;
export class FuzzyLogicSystem extends BaseLogicSystem {
private parser: FuzzyParser;
private validator: FuzzyValidator;
constructor() {
super();
this.parser = new FuzzyParser();
this.validator = new FuzzyValidator();
}
validate(input: string, format: InputFormat): LogicResult {
try {
// Parse the formula
const formula = this.parser.parse(input);
// Extract variables and provide example inputs
const variables = this.extractVariables(formula);
const exampleInputs = this.generateExampleInputs(variables);
// Evaluate with example inputs
const result = this.validator.evaluate(formula, exampleInputs);
return {
system: 'fuzzy',
message: `Fuzzy expression evaluated to degree: ${result.toFixed(3)}`,
details: {
system: 'fuzzy',
formalizedInput: input,
analysis: {
isValid: true,
fallacies: [],
explanation: this.generateExplanation(formula, exampleInputs, result)
}
},
status: 'success' as const
} as LogicResult;
} catch (error) {
logger.error('Error validating fuzzy logic:', error);
return {
code: 'FUZZY_VALIDATION_ERROR',
message: error instanceof Error ? error.message : 'Failed to validate fuzzy expression',
system: 'fuzzy',
status: 'error' as const,
details: {
system: 'fuzzy'
}
} as LogicResult;
}
}
formalize(input: string, format: InputFormat): LogicResult {
try {
const formula = this.parser.parse(input);
const formalized = this.formulaToString(formula);
return {
system: 'fuzzy',
message: 'Input formalized successfully.',
details: {
system: 'fuzzy',
formalizedInput: formalized,
originalInput: input
},
status: 'success' as const
} as LogicResult;
} catch (error) {
logger.error('Error formalizing fuzzy logic:', error);
return {
code: 'FUZZY_FORMALIZATION_ERROR',
message: error instanceof Error ? error.message : 'Failed to formalize fuzzy input',
system: 'fuzzy',
status: 'error' as const,
details: {
system: 'fuzzy'
}
} as LogicResult;
}
}
visualize(input: string, format: InputFormat): LogicResult {
try {
const formula = this.parser.parse(input);
let visualization = '';
// Check if we're visualizing a fuzzy set
if (formula.type === 'atom' && formula.atom) {
const sets = this.validator.getAvailableSets();
if (sets.includes(formula.atom.toLowerCase())) {
visualization = this.validator.visualizeFuzzySet(formula.atom);
} else {
visualization = this.generateFormulaVisualization(formula);
}
} else {
visualization = this.generateFormulaVisualization(formula);
}
return {
system: 'fuzzy',
message: 'Visualization generated successfully.',
details: {
system: 'fuzzy',
formalizedInput: input,
visualization
},
status: 'success' as const
} as LogicResult;
} catch (error) {
logger.error('Error visualizing fuzzy logic:', error);
return {
code: 'FUZZY_VISUALIZATION_ERROR',
message: error instanceof Error ? error.message : 'Failed to visualize fuzzy expression',
system: 'fuzzy',
status: 'error' as const,
details: {
system: 'fuzzy'
}
} as LogicResult;
}
}
solve(input: string, format: InputFormat): LogicResult {
try {
const formula = this.parser.parse(input);
const steps = this.generateFuzzyInference(formula);
return {
system: 'fuzzy',
message: 'Fuzzy inference completed successfully.',
details: {
system: 'fuzzy',
formalizedInput: input,
solution: {
steps,
conclusion: 'Fuzzy inference process completed.'
}
},
status: 'success' as const
} as LogicResult;
} catch (error) {
logger.error('Error solving fuzzy logic:', error);
return {
code: 'FUZZY_SOLVING_ERROR',
message: error instanceof Error ? error.message : 'Failed to solve fuzzy expression',
system: 'fuzzy',
status: 'error' as const,
details: {
system: 'fuzzy'
}
} as LogicResult;
}
}
private extractVariables(formula: FuzzyFormula): Set<string> {
const variables = new Set<string>();
const extract = (f: FuzzyFormula) => {
if (f.type === 'atom' && f.atom) {
if (f.atom.includes('_IS_')) {
const [variable, _] = f.atom.split('_IS_');
variables.add(variable);
} else if (!f.degree) {
variables.add(f.atom);
}
} else if (f.operands) {
f.operands.forEach(op => extract(op));
}
};
extract(formula);
return variables;
}
private generateExampleInputs(variables: Set<string>): Map<string, number> {
const inputs = new Map<string, number>();
// Generate fuzzy membership degrees (0-1 range) based on variable names
for (const variable of variables) {
if (variable.toLowerCase().includes('temperature')) {
inputs.set(variable, 0.7); // Moderately high temperature
} else if (variable.toLowerCase().includes('speed')) {
inputs.set(variable, 0.8); // High speed
} else if (variable.toLowerCase().includes('height')) {
inputs.set(variable, 0.6); // Above average height
} else if (variable.toLowerCase().includes('hot')) {
inputs.set(variable, 0.85); // Very hot
} else if (variable.toLowerCase().includes('cold')) {
inputs.set(variable, 0.2); // Slightly cold
} else if (variable.toLowerCase().includes('warm')) {
inputs.set(variable, 0.65); // Warm
} else {
inputs.set(variable, 0.5); // Default fuzzy value (completely ambiguous)
}
}
return inputs;
}
private formulaToString(formula: FuzzyFormula): string {
switch (formula.type) {
case 'atom':
if (formula.degree !== undefined) {
return `${formula.atom}(${formula.degree})`;
}
return formula.atom || '';
case 'hedged':
if (formula.operands && formula.operands.length > 0) {
return `${formula.hedge} ${this.formulaToString(formula.operands[0])}`;
}
return '';
case 'compound':
if (formula.operator === 'NOT' && formula.operands && formula.operands.length > 0) {
return `NOT ${this.formulaToString(formula.operands[0])}`;
}
if (formula.operands && formula.operands.length >= 2) {
return `(${this.formulaToString(formula.operands[0])} ${formula.operator} ${this.formulaToString(formula.operands[1])})`;
}
return '';
default:
return '';
}
}
private generateExplanation(
formula: FuzzyFormula,
inputs: Map<string, number>,
result: number
): string {
let explanation = 'Fuzzy Logic Evaluation:\n\n';
// Show inputs
if (inputs.size > 0) {
explanation += 'Input values:\n';
inputs.forEach((value, variable) => {
explanation += ` ${variable} = ${value}\n`;
});
explanation += '\n';
}
// Explain the formula
explanation += `Formula: ${this.formulaToString(formula)}\n`;
explanation += `Result: ${result.toFixed(3)}\n\n`;
// Explain fuzzy operations
if (formula.type === 'compound' && formula.operator) {
switch (formula.operator) {
case 'AND':
explanation += 'Fuzzy AND uses the minimum operator.\n';
break;
case 'OR':
explanation += 'Fuzzy OR uses the maximum operator.\n';
break;
case 'NOT':
explanation += 'Fuzzy NOT uses the complement (1 - value).\n';
break;
case 'IMPLIES':
explanation += 'Fuzzy implication uses Lukasiewicz implication: min(1, 1 - a + b).\n';
break;
}
}
if (formula.type === 'hedged' && formula.hedge) {
explanation += `\nHedge "${formula.hedge}" modifies the membership degree:\n`;
switch (formula.hedge) {
case 'very':
explanation += ' very(x) = x²\n';
break;
case 'somewhat':
explanation += ' somewhat(x) = √x\n';
break;
case 'slightly':
explanation += ' slightly(x) = x^0.75\n';
break;
case 'extremely':
explanation += ' extremely(x) = x³\n';
break;
}
}
return explanation;
}
private generateFormulaVisualization(formula: FuzzyFormula): string {
let viz = 'Fuzzy Logic Visualization\n';
viz += '========================\n\n';
viz += `Formula: ${this.formulaToString(formula)}\n\n`;
// Show evaluation for different input values
viz += 'Evaluation for sample inputs:\n';
viz += '┌────────────┬────────────┐\n';
viz += '│ Input │ Output │\n';
viz += '├────────────┼────────────┤\n';
for (let i = 0; i <= 10; i++) {
const value = i / 10;
const inputs = new Map<string, number>();
// Set all variables to this value
const variables = this.extractVariables(formula);
variables.forEach(v => inputs.set(v, value));
const result = this.validator.evaluate(formula, inputs);
viz += `│ ${value.toFixed(1).padEnd(10)} │ ${result.toFixed(3).padEnd(10)} │\n`;
}
viz += '└────────────┴────────────┘\n\n';
// Add fuzzy sets info
viz += 'Available Fuzzy Sets:\n';
const sets = this.validator.getAvailableSets();
sets.forEach(set => {
viz += ` - ${set}\n`;
});
return viz;
}
private generateFuzzyInference(formula: FuzzyFormula): SolutionStep[] {
const steps: SolutionStep[] = [];
let index = 1;
steps.push({
index: index++,
statement: `Given fuzzy expression: ${this.formulaToString(formula)}`,
rule: 'Given',
justification: 'Initial fuzzy expression'
});
// Extract variables and generate inputs
const variables = this.extractVariables(formula);
const inputs = this.generateExampleInputs(variables);
// Show input values
if (inputs.size > 0) {
let inputsStr = 'Input values:\n';
inputs.forEach((value, variable) => {
inputsStr += ` ${variable} = ${value}`;
});
steps.push({
index: index++,
statement: inputsStr,
rule: 'Inputs',
justification: 'Initial fuzzy variable values'
});
}
// Perform step-by-step evaluation
const evaluationSteps = this.evaluateWithSteps(formula, inputs, index);
steps.push(...evaluationSteps);
index += evaluationSteps.length;
// Final result
const result = this.validator.evaluate(formula, inputs);
steps.push({
index: index++,
statement: `Final result: ${result.toFixed(3)}`,
rule: 'Result',
justification: `Fuzzy degree of truth: ${this.interpretDegree(result)}`
});
return steps;
}
private evaluateWithSteps(
formula: FuzzyFormula,
inputs: Map<string, number>,
startIndex: number
): SolutionStep[] {
const steps: SolutionStep[] = [];
let index = startIndex;
// Recursively evaluate and explain
const evaluate = (f: FuzzyFormula, prefix: string = ''): number => {
if (f.type === 'atom') {
if (f.degree !== undefined) {
return f.degree;
}
const value = inputs.get(f.atom || '') || 0.5;
steps.push({
index: index++,
statement: `${prefix}Evaluate ${f.atom} = ${value.toFixed(3)}`,
rule: 'Variable Lookup',
justification: `Input value for ${f.atom}`
});
return value;
}
if (f.type === 'hedged' && f.hedge && f.operands && f.operands.length > 0) {
const operandValue = evaluate(f.operands[0], prefix + ' ');
let result: number;
switch (f.hedge) {
case 'very':
result = operandValue * operandValue;
break;
case 'somewhat':
result = Math.sqrt(operandValue);
break;
case 'slightly':
result = Math.pow(operandValue, 0.75);
break;
case 'extremely':
result = Math.pow(operandValue, 3);
break;
default:
result = operandValue;
}
steps.push({
index: index++,
statement: `${prefix}Apply hedge "${f.hedge}": ${operandValue.toFixed(3)} → ${result.toFixed(3)}`,
rule: 'Linguistic Hedge',
justification: this.getHedgeExplanation(f.hedge)
});
return result;
}
if (f.type === 'compound' && f.operator && f.operands) {
if (f.operator === 'NOT' && f.operands.length > 0) {
const operandValue = evaluate(f.operands[0], prefix + ' ');
const result = 1 - operandValue;
steps.push({
index: index++,
statement: `${prefix}Apply NOT: 1 - ${operandValue.toFixed(3)} = ${result.toFixed(3)}`,
rule: 'Fuzzy NOT',
justification: this.getFuzzyOperatorExplanation('NOT')
});
return result;
}
if (f.operands.length >= 2) {
const left = evaluate(f.operands[0], prefix + ' ');
const right = evaluate(f.operands[1], prefix + ' ');
let result: number;
let operation: string;
switch (f.operator) {
case 'AND':
result = Math.min(left, right);
operation = `min(${left.toFixed(3)}, ${right.toFixed(3)}) = ${result.toFixed(3)}`;
break;
case 'OR':
result = Math.max(left, right);
operation = `max(${left.toFixed(3)}, ${right.toFixed(3)}) = ${result.toFixed(3)}`;
break;
case 'IMPLIES':
result = Math.min(1, 1 - left + right);
operation = `min(1, 1 - ${left.toFixed(3)} + ${right.toFixed(3)}) = ${result.toFixed(3)}`;
break;
default:
result = 0;
operation = 'unknown';
}
steps.push({
index: index++,
statement: `${prefix}Apply ${f.operator}: ${operation}`,
rule: `Fuzzy ${f.operator}`,
justification: this.getFuzzyOperatorExplanation(f.operator)
});
return result;
}
}
return 0.5; // Default
};
evaluate(formula);
return steps;
}
private interpretDegree(degree: number): string {
if (degree >= 0.9) return 'very true';
if (degree >= 0.7) return 'mostly true';
if (degree >= 0.5) return 'more true than false';
if (degree >= 0.3) return 'more false than true';
if (degree >= 0.1) return 'mostly false';
return 'very false';
}
private getFuzzyOperatorExplanation(operator: string): string {
switch (operator) {
case 'AND':
return 'min(a, b) - takes the minimum value';
case 'OR':
return 'max(a, b) - takes the maximum value';
case 'NOT':
return '1 - a - complement of the value';
case 'IMPLIES':
return 'min(1, 1 - a + b) - Lukasiewicz implication';
default:
return 'Unknown operator';
}
}
private getHedgeExplanation(hedge: string): string {
switch (hedge) {
case 'very':
return 'Intensification: squares the membership value';
case 'somewhat':
return 'Dilution: takes the square root of membership';
case 'slightly':
return 'Mild dilution: raises to power 0.75';
case 'extremely':
return 'Strong intensification: cubes the membership';
default:
return 'Modifies membership degree';
}
}
}