import {
MathematicalArgument,
MathematicalCondition,
LogicResult
} from '../../types.js';
import { SequencePatternRecognizer } from '../patternRecognition.js';
/**
* Mathematical visualizer
* Handles visualization of mathematical concepts, patterns, and sequences
*/
export class MathematicalVisualizer {
private patternRecognizer: SequencePatternRecognizer;
constructor() {
this.patternRecognizer = new SequencePatternRecognizer();
}
/**
* Generate visualizations for mathematical input
* @param argument The mathematical argument
* @param variableMap Variable mappings
* @param sequenceMap Sequence mappings
* @returns Visualization result
*/
generateVisualization(
argument: MathematicalArgument,
variableMap: Map<string, string> = new Map(),
sequenceMap: Map<string, number[]> = new Map()
): LogicResult {
// Generate visualizations for sequences
const sequences = this.extractSequencesFromConstraints(argument.constraints);
const visualizations: string[] = [];
for (const {name, values} of sequences) {
const pattern = this.patternRecognizer.detectPattern(values);
if (pattern) {
visualizations.push(this.visualizeSequence(name, values, pattern));
}
}
// Add constraint visualizations
for (const constraint of argument.constraints) {
if (constraint.type !== 'pattern') {
const viz = this.visualizeConstraint(constraint);
if (viz) {
visualizations.push(viz);
}
}
}
// Add variable and sequence mappings
let fullVisualization = visualizations.join('\n\n');
if (variableMap.size > 0 || sequenceMap.size > 0) {
fullVisualization += "\n\nMathematical entities identified:\n";
if (variableMap.size > 0) {
fullVisualization += "\nVariables:\n";
for (const [statement, variable] of variableMap.entries()) {
fullVisualization += `• ${variable}: ${statement}\n`;
}
}
if (sequenceMap.size > 0) {
fullVisualization += "\nSequences:\n";
for (const [name, values] of sequenceMap.entries()) {
fullVisualization += `• ${name}: ${values.join(', ')}\n`;
}
}
}
return {
status: 'success',
message: 'Visualization generated successfully.',
details: {
system: 'mathematical',
visualization: fullVisualization
}
};
}
/**
* Visualize a sequence with its pattern
* @param name Sequence name
* @param values Sequence values
* @param pattern Detected pattern
* @returns Visualization string
*/
private visualizeSequence(name: string, values: number[], pattern: any): string {
const visualization = [`${name}: ${pattern.formula}`];
// Show the sequence with arrows
const sequenceStr = values.map((v, i) => {
if (i === values.length - 1) return v.toString();
const diff = values[i + 1] - v;
return `${v} → (+${diff})`;
}).join(' → ');
visualization.push(`Sequence: ${sequenceStr}`);
// Add pattern details
switch (pattern.type) {
case 'arithmetic':
visualization.push(`Common difference: ${pattern.parameters.difference}`);
break;
case 'geometric':
visualization.push(`Common ratio: ${pattern.parameters.ratio}`);
break;
case 'polynomial':
visualization.push(`Degree: ${pattern.parameters.degree}`);
break;
case 'fibonacci':
visualization.push(`Fibonacci-like sequence`);
break;
}
// Predict next values
const predictions: number[] = [];
let currentSeq = [...values];
for (let i = 0; i < 3; i++) {
const next = this.patternRecognizer.predictNext(currentSeq, pattern);
predictions.push(next);
currentSeq.push(next);
}
visualization.push(`Next 3 values: ${predictions.join(', ')}`);
return visualization.join('\n');
}
/**
* Visualize a constraint
* @param constraint The constraint to visualize
* @returns Visualization string or null
*/
private visualizeConstraint(constraint: MathematicalCondition): string | null {
switch (constraint.type) {
case 'equals':
return `Equation: ${this.termToSimpleString(constraint.left)} = ${this.termToSimpleString(constraint.right)}`;
case 'compare':
const opSymbols: Record<string, string> = {
'<': '<',
'>': '>',
'<=': '≤',
'>=': '≥'
};
return `Inequality: ${this.termToSimpleString(constraint.left)} ${opSymbols[constraint.operator] || constraint.operator} ${this.termToSimpleString(constraint.right)}`;
case 'range':
return `Range: ${constraint.min} ≤ ${this.termToSimpleString(constraint.value)} ≤ ${constraint.max}`;
default:
return null;
}
}
/**
* Convert term to simple string representation
* @param term The term to convert
* @returns String representation
*/
private termToSimpleString(term: any): string {
if (typeof term === 'object' && term.type) {
switch (term.type) {
case 'number':
return term.value.toString();
case 'variable':
return term.name;
case 'operation':
if (term.operands && term.operands.length === 2) {
return `(${this.termToSimpleString(term.operands[0])} ${term.operator} ${this.termToSimpleString(term.operands[1])})`;
}
return 'expr';
default:
return 'term';
}
}
return String(term);
}
/**
* Extract sequences from constraints
* @param constraints Array of constraints
* @returns Array of sequences with names and values
*/
private 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;
}
/**
* Generate ASCII graph for a sequence
* @param values Sequence values
* @param width Graph width in characters
* @returns ASCII graph string
*/
generateASCIIGraph(values: number[], width: number = 40): string[] {
if (values.length === 0) return [];
const min = Math.min(...values);
const max = Math.max(...values);
const range = max - min || 1;
const height = 10;
const graph: string[] = [];
// Create graph lines
for (let h = height; h >= 0; h--) {
let line = '';
const threshold = min + (range * h / height);
for (let i = 0; i < values.length; i++) {
if (values[i] >= threshold) {
line += '█';
} else {
line += ' ';
}
// Add spacing between bars
if (i < values.length - 1) {
line += ' ';
}
}
graph.push(line);
}
// Add x-axis
graph.push('─'.repeat(values.length * 2 - 1));
// Add values
const valueStr = values.map(v => v.toString().substring(0, 1)).join(' ');
graph.push(valueStr);
return graph;
}
}