import { LogicalSystem } from '../types.js';
/**
* Type of logical content in the input
*/
export type LogicalContentType = 'mathematical' | 'logical' | 'mixed' | 'unknown';
/**
* Processing context for natural language processing
*/
export interface ProcessingContext {
detectedSystem: LogicalSystem;
confidence: number;
entities: string[];
patterns: string[];
}
/**
* Natural language processor for detecting input type and extracting context
*/
export class NaturalLanguageProcessor {
/**
* Preprocess the input to detect type and extract context
* @param input Raw input text
* @returns Processed result with type and context
*/
preprocess(input: string): {
type: LogicalContentType;
processedInput: string;
context: ProcessingContext;
} {
// Analyze input to determine type
const type = this.detectContentType(input);
// Initialize context
const context: ProcessingContext = {
detectedSystem: 'auto',
confidence: 0,
entities: [],
patterns: []
};
// Preprocess based on type
let processedInput = input;
switch (type) {
case 'mathematical':
processedInput = this.preprocessMathematical(input, context);
break;
case 'logical':
processedInput = this.preprocessLogical(input, context);
break;
case 'mixed':
processedInput = this.preprocessMixed(input, context);
break;
default:
// Default preprocessing
context.detectedSystem = 'auto';
context.confidence = 0.5;
}
return {
type,
processedInput,
context
};
}
/**
* Detect the type of logical content in the input
* @param input Input text
* @returns Detected content type
*/
private detectContentType(input: string): LogicalContentType {
const text = input.toLowerCase();
// Regular expressions for detecting different types
const mathPatterns = [
/\d+\s*,\s*\d+/, // Number sequences like "1, 2, 3"
/[+\-*/=<>]/, // Mathematical operators
/\b(equation|formula|solve|find|calculate|compute)\b/,
/\b(next|sequence|pattern|series)\b/,
/\b\d+\b/ // Contains numbers
];
const logicalPatterns = [
/\b(if|then|implies|therefore|conclusion|premise|argument)\b/,
/\b(all|some|no|none|every|any)\b/,
/\b(and|or|not|nor|xor)\b/,
/\b(valid|invalid|fallacy|syllogism|proposition)\b/,
/[∀∃∧∨¬→↔⊕]/ // Logical symbols
];
// Count pattern matches
const mathCount = mathPatterns.filter(pattern => pattern.test(text)).length;
const logicalCount = logicalPatterns.filter(pattern => pattern.test(text)).length;
// Determine type based on counts
if (mathCount > 0 && logicalCount === 0) {
return 'mathematical';
} else if (mathCount === 0 && logicalCount > 0) {
return 'logical';
} else if (mathCount > 0 && logicalCount > 0) {
return 'mixed';
} else {
// No clear indicators, check for additional clues
if (/\b(true|false)\b/.test(text)) {
return 'logical';
} else if (/\b(equals|plus|minus|times|divided by)\b/.test(text)) {
return 'mathematical';
}
// Default to unknown
return 'unknown';
}
}
/**
* Preprocess mathematical input
* @param input Raw input
* @param context Processing context
* @returns Preprocessed input
*/
private preprocessMathematical(input: string, context: ProcessingContext): string {
context.detectedSystem = 'mathematical';
context.confidence = 0.8;
// Extract entities (numbers, operations, etc.)
const numberMatches = Array.from(input.matchAll(/\b\d+\b/g));
const variables = Array.from(input.matchAll(/\b([a-zA-Z])\b(?!\()/g)).map(m => m[0]);
// Extract numbers
context.entities = [
...numberMatches.map(m => m[0]),
...variables
];
// Extract patterns
if (/\b(next|sequence|pattern|series)\b/.test(input)) {
context.patterns.push('sequence-detection');
}
if (/\b(solve|equation|equals|formula)\b/.test(input)) {
context.patterns.push('equation-solving');
}
return input;
}
/**
* Preprocess logical input
* @param input Raw input
* @param context Processing context
* @returns Preprocessed input
*/
private preprocessLogical(input: string, context: ProcessingContext): string {
// Determine logical system
if (/\b(all|some|no|none|every|any)\b/.test(input.toLowerCase())) {
context.detectedSystem = 'syllogistic';
context.confidence = 0.8;
} else if (/[∀∃]/.test(input) || /\b(for all|there exists|for any|for some)\b/.test(input.toLowerCase())) {
context.detectedSystem = 'predicate';
context.confidence = 0.8;
} else {
context.detectedSystem = 'propositional';
context.confidence = 0.7;
}
// Extract entities (statements, variables, etc.)
const statements = this.extractStatements(input);
context.entities = statements;
// Extract patterns
if (/\b(if|then|implies)\b/.test(input.toLowerCase())) {
context.patterns.push('conditional');
}
if (/\b(and|or|not|nor)\b/.test(input.toLowerCase())) {
context.patterns.push('connective');
}
if (/\b(all|some|no|none|every|any)\b/.test(input.toLowerCase())) {
context.patterns.push('quantifier');
}
if (/\b(therefore|thus|hence|so)\b/.test(input.toLowerCase())) {
context.patterns.push('inference');
}
return input;
}
/**
* Preprocess mixed logical and mathematical input
* @param input Raw input
* @param context Processing context
* @returns Preprocessed input
*/
private preprocessMixed(input: string, context: ProcessingContext): string {
// For mixed content, combine preprocessing from both
// but set system to auto for optimal detection
const mathContext: ProcessingContext = {
detectedSystem: 'auto',
confidence: 0,
entities: [],
patterns: []
};
const logicalContext: ProcessingContext = {
detectedSystem: 'auto',
confidence: 0,
entities: [],
patterns: []
};
this.preprocessMathematical(input, mathContext);
this.preprocessLogical(input, logicalContext);
// Merge contexts
context.detectedSystem = 'auto'; // Let the system decide
context.confidence = 0.6;
context.entities = [...mathContext.entities, ...logicalContext.entities];
context.patterns = [...mathContext.patterns, ...logicalContext.patterns];
return input;
}
/**
* Extract logical statements from input
* @param input Input text
* @returns Array of statements
*/
private extractStatements(input: string): string[] {
const statements: string[] = [];
// Split by common delimiters
const sentenceSplitter = /[.;,]/;
const parts = input.split(sentenceSplitter);
for (const part of parts) {
const trimmed = part.trim();
if (trimmed.length > 0) {
// Extract clauses that might be statements
if (/\b(if|then|and|or|not|all|some|no)\b/i.test(trimmed)) {
statements.push(trimmed);
} else if (trimmed.length >= 3) {
// Any substantial clause might be a statement
statements.push(trimmed);
}
}
}
return statements;
}
}