import {
MathematicalArgument,
MathematicalTerm,
MathematicalCondition,
LogicResult
} from '../../types.js';
import {
createMathematicalError,
errorTemplates,
errorSuggestions
} from '../../errorHandler.js';
import { SequencePatternRecognizer } from '../patternRecognition.js';
import { MathematicalEvaluator } from './MathematicalEvaluator.js';
/**
* Mathematical validator
* Handles validation of mathematical expressions and sequences
*/
export class MathematicalValidator {
private patternRecognizer: SequencePatternRecognizer;
private evaluator: MathematicalEvaluator;
constructor() {
this.patternRecognizer = new SequencePatternRecognizer();
this.evaluator = new MathematicalEvaluator();
}
/**
* Validate mathematical input
* @param argument The mathematical argument to validate
* @param variableMap Variable mappings
* @param sequenceMap Sequence mappings
* @returns Validation result
*/
validateMathematical(
argument: MathematicalArgument,
variableMap: Map<string, string> = new Map(),
sequenceMap: Map<string, number[]> = new Map()
): LogicResult {
// Check for sequence patterns from constraints
const sequences = this.extractSequencesFromConstraints(argument.constraints);
const validSequences: string[] = [];
const invalidSequences: string[] = [];
for (const {name, values} of sequences) {
const pattern = this.patternRecognizer.detectPattern(values);
if (pattern && pattern.confidence > 0.8) {
validSequences.push(name);
} else {
invalidSequences.push(name);
}
}
// Check for valid arithmetic
const arithmeticValid = this.validateArithmetic(argument.terms);
const isValid = invalidSequences.length === 0 && arithmeticValid;
// Build explanation with variable and sequence mappings
let explanation = isValid
? 'All mathematical operations and sequences are valid.'
: 'Some mathematical operations or sequences are invalid.';
// Enhanced validation error reporting
if (!isValid) {
if (invalidSequences.length > 0) {
explanation += `\n\nInvalid sequences detected:\n- ${invalidSequences.join('\n- ')}\n`;
explanation += `\n${errorSuggestions.validation.mathematical.insufficientData}`;
}
if (!arithmeticValid) {
explanation += `\n\nInvalid arithmetic operations detected.\n`;
explanation += `${errorSuggestions.validation.mathematical.divisionByZero}`;
}
}
if (variableMap.size > 0 || sequenceMap.size > 0) {
explanation += "\n\nMathematical entities identified:\n";
if (variableMap.size > 0) {
explanation += "\nVariables:\n";
for (const [statement, variable] of variableMap.entries()) {
explanation += `• ${variable}: ${statement}\n`;
}
}
if (sequenceMap.size > 0) {
explanation += "\nSequences:\n";
for (const [name, values] of sequenceMap.entries()) {
explanation += `• ${name}: ${values.join(', ')}\n`;
}
}
}
return {
status: 'success',
message: isValid ? 'Mathematical input is valid.' : 'Mathematical input contains errors.',
details: {
system: 'mathematical',
analysis: {
isValid,
fallacies: isValid ? [] : [
...invalidSequences.map(seq => ({
name: 'Invalid Sequence',
description: `The sequence ${seq} does not follow a recognizable pattern.`,
location: seq
})),
...(!arithmeticValid ? [{
name: 'Invalid Arithmetic',
description: 'The arithmetic operations are invalid.',
location: 'arithmetic'
}] : [])
],
explanation
}
}
};
}
/**
* Validate arithmetic operations
* @param terms Array of mathematical terms
* @returns Boolean indicating if arithmetic is valid
*/
validateArithmetic(terms: MathematicalTerm[]): boolean {
// Enhanced validation - check for division by zero, invalid operations, etc.
for (const term of terms) {
if (term.type === 'operation') {
// Check for division by zero
if (term.operator === '/' && term.operands.length > 1 &&
term.operands[1].type === 'number' && term.operands[1].value === 0) {
throw new Error(errorTemplates.validation.mathematical.divisionByZero);
}
// Check for invalid operands
if (['*', '+', '-', '/'].includes(term.operator) && term.operands.length < 2) {
throw new Error('Invalid number of operands for operation: ' + term.operator);
}
}
}
return true;
}
/**
* Extract sequences from constraints
* @param constraints Array of constraints
* @returns Array of sequences with names and values
*/
extractSequencesFromConstraints(constraints: MathematicalCondition[]): Array<{name: string, values: number[]}> {
const sequences: Array<{name: string, values: number[]}> = [];
for (let i = 0; i < constraints.length; i++) {
const constraint = constraints[i];
if (constraint.type === 'pattern' && Array.isArray(constraint.sequence)) {
const values = constraint.sequence
.filter(term => term.type === 'number')
.map(term => (term as any).value);
if (values.length > 0) {
sequences.push({
name: `Sequence ${i + 1}`,
values
});
}
}
}
return sequences;
}
/**
* Validate a single constraint
* @param constraint The constraint to validate
* @returns Boolean indicating if constraint is valid
*/
validateConstraint(constraint: MathematicalCondition): boolean {
try {
switch (constraint.type) {
case 'equals':
// Check both sides are valid expressions
this.validateTerm(constraint.left);
this.validateTerm(constraint.right);
return true;
case 'compare':
// Check both sides are valid expressions
this.validateTerm(constraint.left);
this.validateTerm(constraint.right);
return true;
case 'range':
// Check value is valid and range makes sense
this.validateTerm(constraint.value);
return constraint.min <= constraint.max;
case 'pattern':
// Check sequence has valid terms
return constraint.sequence.every(term => this.validateTerm(term));
default:
return false;
}
} catch {
return false;
}
}
/**
* Validate a mathematical term
* @param term The term to validate
* @returns Boolean indicating if term is valid
*/
private validateTerm(term: MathematicalTerm): boolean {
switch (term.type) {
case 'number':
return !isNaN(term.value) && isFinite(term.value);
case 'variable':
return term.name.length > 0;
case 'operation':
return term.operands.length >= 2 &&
term.operands.every(op => this.validateTerm(op));
case 'sequence':
return term.name.length > 0 && term.index >= 0;
default:
return false;
}
}
}