/**
* Syllogistic Logic Explanation Generator
* Generates detailed explanations for syllogistic logic proofs
* Part of simplified Phase 4d Implementation
*/
import {
SolutionStep
} from '../types.js';
import {
ProofContext
} from '../types-explanations.js';
import { BaseExplanationGenerator } from './BaseExplanationGenerator.js';
/**
* Explanation generator for syllogistic logic.
*/
export class SyllogisticExplanationGenerator extends BaseExplanationGenerator {
// Map of syllogistic figures and moods to their traditional names
private readonly syllogismNames: Record<string, string> = {
'1-AAA': 'Barbara',
'1-EAE': 'Celarent',
'1-AII': 'Darii',
'1-EIO': 'Ferio',
'2-EAE': 'Cesare',
'2-AEE': 'Camestres',
'2-EIO': 'Festino',
'2-AOO': 'Baroco',
'3-AAI': 'Darapti',
'3-IAI': 'Disamis',
'3-AII': 'Datisi',
'3-EAO': 'Felapton',
'3-OAO': 'Bocardo',
'3-EIO': 'Ferison',
'4-AAI': 'Bramantip',
'4-AEE': 'Camenes',
'4-IAI': 'Dimaris',
'4-EAO': 'Fesapo',
'4-EIO': 'Fresison'
};
// Descriptions of syllogistic statement types
private readonly statementTypes: Record<string, string> = {
'A': 'Universal Affirmative (All S are P)',
'E': 'Universal Negative (No S are P)',
'I': 'Particular Affirmative (Some S are P)',
'O': 'Particular Negative (Some S are not P)'
};
// Explanations for syllogistic rules
private readonly ruleExplanations: Record<string, string> = {
'Major Premise': 'The major premise contains the major term (P) and the middle term (M).',
'Minor Premise': 'The minor premise contains the minor term (S) and the middle term (M).',
'Barbara': 'Barbara is a valid syllogistic form in the first figure with the mood AAA (All M are P, All S are M, therefore All S are P).',
'Celarent': 'Celarent is a valid syllogistic form in the first figure with the mood EAE (No M are P, All S are M, therefore No S are P).',
'Simple Conversion': 'In Simple Conversion, the subject and predicate are swapped. It works for E and I statements (No S are P → No P are S; Some S are P → Some P are S).',
'Conversion by Limitation': 'In Conversion by Limitation (or per accidens), a universal statement is converted to a particular statement. It works for A statements (All S are P → Some P are S).',
'Contraposition': 'In Contraposition, both the subject and predicate are replaced by their complements. It works for A and O statements (All S are P → All non-P are non-S; Some S are not P → Some non-P are not non-S).',
'Obversion': 'In Obversion, the quality of the statement (affirmative/negative) is changed, and the predicate is replaced by its complement. It works for all statement types.'
};
// Explanations for conversion rules
private readonly conversionRules: Record<string, string> = {
'Simple Conversion': 'In Simple Conversion, the subject and predicate are swapped. It works for E and I statements (No S are P → No P are S; Some S are P → Some P are S).',
'Conversion by Limitation': 'In Conversion by Limitation (or per accidens), a universal statement is converted to a particular statement. It works for A statements (All S are P → Some P are S).',
'Contraposition': 'In Contraposition, both the subject and predicate are replaced by their complements. It works for A and O statements (All S are P → All non-P are non-S; Some S are not P → Some non-P are not non-S).',
'Obversion': 'In Obversion, the quality of the statement (affirmative/negative) is changed, and the predicate is replaced by its complement. It works for all statement types.'
};
protected getLogicSystemName(): string {
return 'syllogistic logic';
}
protected getRuleExplanations(): Record<string, string> {
// Merge rule explanations and conversion rules
return { ...this.ruleExplanations, ...this.conversionRules };
}
protected getSymbolExplanations(): Record<string, string> {
// Syllogistic logic doesn't use many symbols, mostly statement types
return {
'All': 'Universal quantifier, indicating that the statement applies to every member of the subject class.',
'Some': 'Existential quantifier, indicating that the statement applies to at least one member of the subject class.',
'No': 'Universal negative quantifier, indicating that the statement applies to no members of the subject class.',
'are': 'Copula linking subject and predicate in affirmative statements.',
'are not': 'Negative copula linking subject and predicate in negative statements.'
};
}
protected getSpecificExplanation(step: SolutionStep, context: ProofContext): string {
// For third step (conclusion) in a standard syllogism
if (step.index === 3 && context.previousSteps.length === 2) {
return `The conclusion follows from the major premise (step 1) and the minor premise (step 2) according to the rules of syllogistic inference.`;
}
// For steps involving conversion
if (step.rule.includes('Conversion')) {
return `This step applies the rule of ${step.rule} to the previous step.`;
}
// Default explanation
return `This step follows logically from the previous steps based on syllogistic rules.`;
}
protected generateSystemSpecificVisualization(step: SolutionStep, context: ProofContext): string {
// For syllogistic logic, we would generate Venn or Euler diagrams
// This is a simplified implementation
// Only generate visualizations for conclusion steps
if (step.index <= 2) {
return '';
}
// Create a simple ASCII Venn diagram
return `
┌─────────────┐ ┌─────────────┐
│ │ │ │
│ S │ │ P │
│ ┌─────┼─┼─────┐ │
│ │ │ │ │ │
└───────┤ M ├─┼─────┘ │
│ │ │ │
└─────┴─┘ │
└─────────────┘
`;
}
protected getRuleExample(rule: string): string {
// Check if this is a named syllogism
for (const [key, name] of Object.entries(this.syllogismNames)) {
if (name === rule) {
const [figure, mood] = key.split('-');
return this.getSyllogismExample(figure, mood);
}
}
// Examples for conversion rules
switch (rule) {
case 'Simple Conversion':
return "Example:\nOriginal: No dogs are cats\nConverted: No cats are dogs\n\n";
case 'Conversion by Limitation':
return "Example:\nOriginal: All students are learners\nConverted: Some learners are students\n\n";
case 'Contraposition':
return "Example:\nOriginal: All birds are animals\nConverted: All non-animals are non-birds\n\n";
case 'Obversion':
return "Example:\nOriginal: All dogs are animals\nObverted: No dogs are non-animals\n\n";
default:
return "";
}
}
protected assessRuleDifficulty(rule: string): number {
// Rules involving conversions are moderately difficult
if (rule.includes('Conversion') ||
rule.includes('Contraposition') ||
rule.includes('Obversion')) {
return 3;
}
// Named syllogisms have varying difficulty
for (const [key, name] of Object.entries(this.syllogismNames)) {
if (name === rule) {
const mood = key.split('-')[1];
// Some moods are more complex than others
const complexMoods = ['AOO', 'EAO', 'OAO'];
if (complexMoods.includes(mood)) {
return 4;
}
return 3;
}
}
// Default moderate difficulty
return 2;
}
protected getSystemSpecificDetails(step: SolutionStep, context: ProofContext): string {
let details = '\nIn syllogistic logic, we work with categorical statements relating classes or categories. ';
details += 'Each statement has a form (A, E, I, or O) and relates two terms. ';
if (step.rule.match(/Figure \d/)) {
details += '\n\nThe syllogistic figure determines the arrangement of the middle term (M) in the premises. ';
details += this.getFigureExplanation(step.rule);
}
if (step.rule.match(/[A-Z][A-Z][A-Z]/)) {
details += '\n\nThe syllogistic mood (${step.rule}) indicates the types of statements in the syllogism. ';
details += this.getMoodExplanation(step.rule);
}
return details;
}
protected getPremiseExplanation(step: SolutionStep, context: ProofContext): string {
if (step.index === 1) {
return 'This is the major premise of the syllogism. The major premise contains the major term (P) and the middle term (M).\n\n';
} else if (step.index === 2) {
return 'This is the minor premise of the syllogism. The minor premise contains the minor term (S) and the middle term (M).\n\n';
}
return super.getPremiseExplanation(step, context);
}
protected generateProofStrategy(steps: SolutionStep[], context: ProofContext): string {
// Look for syllogistic figure and mood
let figure = '';
let mood = '';
for (const step of steps) {
if (step.rule.match(/Figure \d/)) {
figure = step.rule;
} else if (step.rule.match(/[A-Z][A-Z][A-Z]/)) {
mood = step.rule;
}
}
if (figure && mood) {
return `This proof uses a syllogism in ${figure} with mood ${mood}. This is also known as the '${this.getSyllogismName(figure, mood)}' form. The proof starts with two premises and derives the conclusion through syllogistic inference.`;
}
// Default strategy description
return `This proof uses syllogistic reasoning to derive a conclusion from the given premises. It applies the rules of syllogistic logic to determine whether the argument is valid or invalid.`;
}
protected generateKeyInsights(steps: SolutionStep[], context: ProofContext): string[] {
const insights: string[] = [];
// Add general insight about syllogistic logic
insights.push(
"Syllogistic logic deals with categorical statements relating classes or categories."
);
// Add insight about the middle term
insights.push(
"In a valid syllogism, the middle term must be distributed in at least one premise."
);
// Add insight about the conclusion
if (steps.length > 2) {
const conclusion = steps[steps.length - 1].statement;
if (conclusion.match(/All|No/)) {
insights.push(
"When the conclusion is universal (All/No), both premises must be universal."
);
}
if (conclusion.match(/No|Some.*not/)) {
insights.push(
"When the conclusion is negative, at least one premise must be negative."
);
}
}
return insights;
}
/**
* Get explanation for a syllogistic figure.
* @param figure The figure designation
* @returns Explanation of the figure
*/
private getFigureExplanation(figure: string): string {
const figureNum = figure.match(/\d/)?.[0] || '';
switch (figureNum) {
case '1':
return `In Figure 1, the middle term is the subject of the major premise and the predicate of the minor premise. This is often the most intuitive figure.`;
case '2':
return `In Figure 2, the middle term is the predicate in both premises. This figure is useful for deriving negative conclusions.`;
case '3':
return `In Figure 3, the middle term is the subject in both premises. This figure typically yields particular conclusions.`;
case '4':
return `In Figure 4, the middle term is the predicate of the major premise and the subject of the minor premise. This is often considered the least intuitive figure.`;
default:
return `The figure of a syllogism determines the position of the middle term in the premises.`;
}
}
/**
* Get explanation for a syllogistic mood.
* @param mood The mood designation
* @returns Explanation of the mood
*/
private getMoodExplanation(mood: string): string {
// Extract the three letters of the mood
const letters = mood.match(/[AEIO]{3}/)?.[0] || '';
if (letters.length === 3) {
return `The mood ${letters} indicates the types of statements in the syllogism:
${this.statementTypes[letters[0]]} (major premise),
${this.statementTypes[letters[1]]} (minor premise), and
${this.statementTypes[letters[2]]} (conclusion).`;
}
return `The mood of a syllogism indicates the types of statements (A, E, I, or O) used in the major premise, minor premise, and conclusion.`;
}
/**
* Get the name of a syllogism based on figure and mood.
* @param figure The figure (or figure number)
* @param mood The mood
* @returns The traditional name of the syllogism
*/
private getSyllogismName(figure: string, mood: string): string {
// Extract figure number if it's in "Figure X" format
const figureNum = figure.match(/\d/)?.[0] || figure;
// Extract mood if it's part of a longer string
const moodLetters = mood.match(/[AEIO]{3}/)?.[0] || mood;
// Look up the name
const key = `${figureNum}-${moodLetters}`;
return this.syllogismNames[key] || 'Unknown syllogism form';
}
/**
* Get example for a named syllogism.
* @param figure The figure number
* @param mood The mood
* @returns Example of the syllogism
*/
private getSyllogismExample(figure: string, mood: string): string {
const name = this.getSyllogismName(figure, mood);
let example = `Example of ${name} (Figure ${figure}, Mood ${mood}):\n`;
// Add specific examples for common syllogisms
const key = `${figure}-${mood}`;
switch (key) {
case '1-AAA': // Barbara
example += 'All humans are mortal.\n';
example += 'All Greeks are humans.\n';
example += 'Therefore, All Greeks are mortal.\n\n';
break;
case '1-EAE': // Celarent
example += 'No reptiles are mammals.\n';
example += 'All snakes are reptiles.\n';
example += 'Therefore, No snakes are mammals.\n\n';
break;
case '1-AII': // Darii
example += 'All flowers are plants.\n';
example += 'Some roses are flowers.\n';
example += 'Therefore, Some roses are plants.\n\n';
break;
case '1-EIO': // Ferio
example += 'No fish are mammals.\n';
example += 'Some animals are fish.\n';
example += 'Therefore, Some animals are not mammals.\n\n';
break;
default:
// Generic example structure
const [majorType, minorType, conclusionType] = mood.split('');
example += `${this.getStatementForm(majorType, 'M', 'P')}\n`;
example += `${this.getStatementForm(minorType, 'S', 'M')}\n`;
example += `Therefore, ${this.getStatementForm(conclusionType, 'S', 'P')}\n\n`;
break;
}
return example;
}
/**
* Get the form of a statement based on type and terms.
* @param type The statement type (A, E, I, O)
* @param subject The subject term
* @param predicate The predicate term
* @returns The form of the statement
*/
private getStatementForm(type: string, subject: string, predicate: string): string {
switch (type) {
case 'A': return `All ${subject} are ${predicate}`;
case 'E': return `No ${subject} are ${predicate}`;
case 'I': return `Some ${subject} are ${predicate}`;
case 'O': return `Some ${subject} are not ${predicate}`;
default: return `Unknown statement type`;
}
}
}