import type { ClassSchema, MergeSuggestion } from '../../types/auto-group' const THRESHOLD = 0.95 const MIN_CLASS_SIZE = 4 function functionalDependency(rows: string[][], srcIdx: number, dstIdx: number): number { const map = new Map>() for (const row of rows) { const a = row[srcIdx] ?? '' const b = row[dstIdx] ?? '' const set = map.get(a) if (set) set.add(b) else map.set(a, new Set([b])) } if (map.size === 0) return 0 let functional = 0 for (const set of map.values()) if (set.size === 1) functional++ return functional / map.size } export function findMerges(schema: ClassSchema, rows: string[][]): MergeSuggestion[] { if (rows.length < MIN_CLASS_SIZE) return [] const out: MergeSuggestion[] = [] for (let i = 0; i < schema.columns.length - 1; i++) { const a = schema.columns[i] const b = schema.columns[i + 1] if (a.role !== 'factor' && b.role !== 'factor') continue const forward = functionalDependency(rows, a.index, b.index) const backward = functionalDependency(rows, b.index, a.index) if (forward < THRESHOLD || backward < THRESHOLD) continue const merged = new Set(rows.map(r => `${r[a.index] ?? ''}_${r[b.index] ?? ''}`)) if (merged.size < 2) continue out.push({ classKind: schema.classKind, subKind: schema.subKind, columnIndices: [a.index, b.index], proposedName: `Column ${a.index + 1}–${b.index + 1}`, confidence: Math.min(forward, backward), }) } return out }