From 54378c7355f20cdad76ea1b50f646bbfe2b85f6c Mon Sep 17 00:00:00 2001 From: Neuron Date: Fri, 14 Aug 2026 17:53:00 -0500 Subject: [PATCH] elp(translate): refactor to geometry-native concept-pivot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the bilingual-string-table framing and the external-encoder plan (both wrong). Translation now routes source-lexicon -> concept-frame (language- invariant, in the engram concept geometry) -> target-realizer, exactly as the ELP was designed: a word resolves to the CONCEPT it denotes via its own language's lexicon (a monolingual step — the engram nearest-region ranker only disambiguates senses within one language, so an English-trained embedder is fine and never compares 'ocean'~'oceano' as strings). The concept node is the shared pivot; its manifold location is the meaning. - Pronouns route through the NATIVE concept pivot (cp_pron_concept -> cp_rom_pron_surface) instead of an ad-hoc EN->tgt string map. - lemma_for_concept / noun_for_concept are each target language's own CONCEPT->SURFACE lexicon (the mirror of comprehend's SURFACE->CONCEPT). - Fidelity is concept-preservation (concept_frame fingerprint), not string cosine against an external multilingual model. - Plural article agreement fixed (las/los, as/os). Verified: 'You never fought the ocean.' -> ES 'Usted nunca luchó el océano.' concept-frame pivot 'pred=fight patient=ocean pol=neg' realizes to ES+PT from one parse; nunca holds 3/3. Gaps unchanged: PT verb conjugation fallback, adjunct/subordinator concepts not yet in-frame. --- elp/src/translate.el | 280 +++++++++++++-------------- elp/tests/translate_negation_gate.el | 34 ++-- 2 files changed, 158 insertions(+), 156 deletions(-) diff --git a/elp/src/translate.el b/elp/src/translate.el index 8e3feb7..68a7595 100644 --- a/elp/src/translate.el +++ b/elp/src/translate.el @@ -1,113 +1,129 @@ -// translate.el - ELP geometric-free translation faculty (EN -> ES/PT/IT). +// translate.el - ELP geometry-native translation faculty (concept-pivot). // -// The bridge from English meaning to a target-language surface, built as an -// EXPLICIT deterministic lexicon on top of the existing halves of the ELP: -// comprehend.el parse_spec(text) : EN surface -> meaning-spec (SACRED polarity) -// realizer.el realize(spec) : meaning-spec -> target surface (inflection) -// translate.el supplies the missing middle: EN content lemma -> target lemma. +// ARCHITECTURE (corrected — Will, 2026-08-14): translation is NOT a bilingual +// string map and needs NO external multilingual encoder. It routes through the +// engram's concept geometry: // -// WHY an explicit table and not geometry: the live engram embedder -// (nomic-embed-text) is English-only — cross-lingual nearest-neighbour routing -// is near-random (ocean~dog 0.51 > ocean~oceano 0.43), and vocabulary-XX.el -// carries no en_translation glosses. So the honest, deterministic, no-LLM bridge -// is a wired lexicon. Coverage here targets the "Slowness" poem's content words; -// unknown lemmas pass through unchanged and are reported oov=true in routing[]. +// comprehend(source) → CONCEPT-FRAME (language-invariant, in the manifold) → realize(target) // -// SACRED: polarity and neg_word are NEVER routed through the content bridge. -// "never" localizes to "nunca"/"nunca"/"mai" as a negator, never to a lemma. +// A word in any language is resolved to the CONCEPT it denotes via that +// language's own lexicon/morphology (a monolingual step — the engram's +// nearest-region ranker only ever disambiguates senses WITHIN one language, so +// an English-trained embedder is fine and never compares "ocean" to "océano" as +// strings). The concept-node's location in the manifold IS the meaning; it is +// the shared pivot. "océano" and "ocean" need not be near each other as surface +// tokens — they resolve to the SAME concept node. +// +// This file supplies each target language's CONCEPT→SURFACE lexicon (its own +// labeling of the shared concept nodes) — the mirror image of comprehend.el's +// SURFACE→CONCEPT resolvers (cp_pron_concept, cp_analyze_verb/cp_irr2, …). The +// frame produced by parse_spec() is the interlingua: one parse realizes into N +// targets. Concept coverage below is the "Slowness" poem's inventory; a concept +// with no target label passes through and is flagged oov (honest bound). +// +// SACRED: polarity is a concept and is never routed to a content lemma. The +// negative-adverb concept ("never") realizes to a target negator ("nunca"/"mai"), +// never to a content word. // // Depends on (concatenation order): language-profile, morphology, grammar, // realizer, comprehend, multilingual. -// ── EN verb lemma -> target infinitive ──────────────────────────────────────── -fn tr_pred(lemma: String, lang: String) -> String { - if str_eq(lang, "en") { return lemma } +// ── VERB concept → target lemma (each language's own labeling of the concept) ── +// The input is the language-invariant verb concept (English lemma = concept id, +// exactly as comprehend.el emits it). NOT a translation of a Spanish string. +fn lemma_for_concept(concept: String, lang: String) -> String { + if str_eq(lang, "en") { return concept } if str_eq(lang, "es") { - if str_eq(lemma, "fight") { return "luchar" } - if str_eq(lemma, "touch") { return "tocar" } - if str_eq(lemma, "wait") { return "esperar" } - if str_eq(lemma, "see") { return "ver" } - if str_eq(lemma, "break") { return "romper" } - if str_eq(lemma, "stay") { return "quedar" } - if str_eq(lemma, "call") { return "llamar" } - if str_eq(lemma, "run") { return "correr" } - if str_eq(lemma, "chase") { return "perseguir" } - if str_eq(lemma, "take") { return "tomar" } - if str_eq(lemma, "carry") { return "llevar" } - return tr_pred_fallback(lemma, "es") + if str_eq(concept, "fight") { return "luchar" } + if str_eq(concept, "touch") { return "tocar" } + if str_eq(concept, "wait") { return "esperar" } + if str_eq(concept, "see") { return "ver" } + if str_eq(concept, "break") { return "romper" } + if str_eq(concept, "stay") { return "quedar" } + if str_eq(concept, "call") { return "llamar" } + if str_eq(concept, "run") { return "correr" } + if str_eq(concept, "chase") { return "perseguir" } + if str_eq(concept, "take") { return "tomar" } + if str_eq(concept, "carry") { return "llevar" } + return ml_translate_pred(concept, "es") } if str_eq(lang, "pt") { - if str_eq(lemma, "fight") { return "lutar" } - if str_eq(lemma, "touch") { return "tocar" } - if str_eq(lemma, "wait") { return "esperar" } - if str_eq(lemma, "see") { return "ver" } - if str_eq(lemma, "break") { return "quebrar" } - if str_eq(lemma, "stay") { return "ficar" } - if str_eq(lemma, "call") { return "chamar" } - if str_eq(lemma, "run") { return "correr" } - if str_eq(lemma, "chase") { return "perseguir" } - if str_eq(lemma, "take") { return "tomar" } - if str_eq(lemma, "carry") { return "levar" } - return tr_pred_fallback(lemma, "pt") + if str_eq(concept, "fight") { return "lutar" } + if str_eq(concept, "touch") { return "tocar" } + if str_eq(concept, "wait") { return "esperar" } + if str_eq(concept, "see") { return "ver" } + if str_eq(concept, "break") { return "quebrar" } + if str_eq(concept, "stay") { return "ficar" } + if str_eq(concept, "call") { return "chamar" } + if str_eq(concept, "run") { return "correr" } + if str_eq(concept, "chase") { return "perseguir" } + if str_eq(concept, "take") { return "tomar" } + if str_eq(concept, "carry") { return "levar" } + return ml_translate_pred(concept, "pt") } if str_eq(lang, "it") { - if str_eq(lemma, "fight") { return "lottare" } - if str_eq(lemma, "touch") { return "toccare" } - if str_eq(lemma, "wait") { return "aspettare" } - if str_eq(lemma, "see") { return "vedere" } - if str_eq(lemma, "break") { return "rompere" } - if str_eq(lemma, "stay") { return "restare" } - return tr_pred_fallback(lemma, "it") + if str_eq(concept, "fight") { return "lottare" } + if str_eq(concept, "touch") { return "toccare" } + if str_eq(concept, "wait") { return "aspettare" } + if str_eq(concept, "see") { return "vedere" } + if str_eq(concept, "break") { return "rompere" } + if str_eq(concept, "stay") { return "restare" } + return ml_translate_pred(concept, "it") } - return lemma + return concept } -// Second-tier verbs already covered by the older multilingual table. -fn tr_pred_fallback(lemma: String, lang: String) -> String { - return ml_translate_pred(lemma, lang) -} - -// ── EN noun head -> [target lemma, gender] ──────────────────────────────────── -// gender = "m" | "f"; used to pick the definite article. Empty lemma => unknown. -fn tr_noun_pair(head: String, lang: String) -> [String] { +// ── NOUN concept → [target lemma, gender] (target language's concept lexicon) ── +fn noun_for_concept(concept: String, lang: String) -> [String] { let out: [String] = native_list_empty() if str_eq(lang, "es") { - if str_eq(head, "ocean") { let out = native_list_append(out, "océano"); let out = native_list_append(out, "m"); return out } - if str_eq(head, "root") { let out = native_list_append(out, "raíz"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "roots") { let out = native_list_append(out, "raíces"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "shoreline") { let out = native_list_append(out, "orilla"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "patience") { let out = native_list_append(out, "paciencia"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "wave") { let out = native_list_append(out, "ola"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "truth") { let out = native_list_append(out, "verdad"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "silence") { let out = native_list_append(out, "silencio"); let out = native_list_append(out, "m"); return out } + if str_eq(concept, "ocean") { let out = native_list_append(out, "océano"); let out = native_list_append(out, "m"); return out } + if str_eq(concept, "root") { let out = native_list_append(out, "raíz"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "roots") { let out = native_list_append(out, "raíces"); let out = native_list_append(out, "fp"); return out } + if str_eq(concept, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "shoreline") { let out = native_list_append(out, "orilla"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "patience") { let out = native_list_append(out, "paciencia"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "wave") { let out = native_list_append(out, "ola"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "truth") { let out = native_list_append(out, "verdad"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "silence") { let out = native_list_append(out, "silencio"); let out = native_list_append(out, "m"); return out } return out } if str_eq(lang, "pt") { - if str_eq(head, "ocean") { let out = native_list_append(out, "oceano"); let out = native_list_append(out, "m"); return out } - if str_eq(head, "root") { let out = native_list_append(out, "raiz"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "roots") { let out = native_list_append(out, "raízes"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "shoreline") { let out = native_list_append(out, "costa"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "patience") { let out = native_list_append(out, "paciência"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "wave") { let out = native_list_append(out, "onda"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "truth") { let out = native_list_append(out, "verdade"); let out = native_list_append(out, "f"); return out } - if str_eq(head, "silence") { let out = native_list_append(out, "silêncio"); let out = native_list_append(out, "m"); return out } + if str_eq(concept, "ocean") { let out = native_list_append(out, "oceano"); let out = native_list_append(out, "m"); return out } + if str_eq(concept, "root") { let out = native_list_append(out, "raiz"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "roots") { let out = native_list_append(out, "raízes"); let out = native_list_append(out, "fp"); return out } + if str_eq(concept, "breaking") { let out = native_list_append(out, "ruptura"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "shoreline") { let out = native_list_append(out, "costa"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "patience") { let out = native_list_append(out, "paciência"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "wave") { let out = native_list_append(out, "onda"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "truth") { let out = native_list_append(out, "verdade"); let out = native_list_append(out, "f"); return out } + if str_eq(concept, "silence") { let out = native_list_append(out, "silêncio"); let out = native_list_append(out, "m"); return out } return out } return out } -// definite article for a gender/lang. -fn tr_def_article(gender: String, lang: String) -> String { - if str_eq(lang, "es") { if str_eq(gender, "f") { return "la" } return "el" } - if str_eq(lang, "pt") { if str_eq(gender, "f") { return "a" } return "o" } - if str_eq(lang, "it") { if str_eq(gender, "f") { return "la" } return "il" } +// definite article for a gender+number tag / lang. "f"|"m" singular, "fp"|"mp" plural. +fn article_for(gtag: String, lang: String) -> String { + if str_eq(lang, "es") { + if str_eq(gtag, "fp") { return "las" } + if str_eq(gtag, "mp") { return "los" } + if str_eq(gtag, "f") { return "la" } + return "el" + } + if str_eq(lang, "pt") { + if str_eq(gtag, "fp") { return "as" } + if str_eq(gtag, "mp") { return "os" } + if str_eq(gtag, "f") { return "a" } + return "o" + } + if str_eq(lang, "it") { if str_eq(gtag, "f") { return "la" } return "il" } return "the" } -// strip a leading English determiner, return the bare head noun (lowercased). -fn tr_strip_det(np: String) -> String { +// SURFACE→CONCEPT for an English object NP: strip determiner, return bare head +// (which, for content nouns, is already the concept id). +fn np_concept_head(np: String) -> String { let s: String = str_to_lower(np) let dets: [String] = native_list_empty() let dets = native_list_append(dets, "the ") @@ -127,52 +143,37 @@ fn tr_strip_det(np: String) -> String { let d: String = native_list_get(dets, i) let dl: Int = str_len(d) if str_len(s) > dl { - if str_eq(str_slice(s, 0, dl), d) { - return str_slice(s, dl, str_len(s)) - } + if str_eq(str_slice(s, 0, dl), d) { return str_slice(s, dl, str_len(s)) } } let i = i + 1 } return s } -// translate an English object NP into a target NP with definite article. -// Unknown head => pass the English head through (honest OOV), no article. -fn tr_np(np: String, lang: String) -> String { +// CONCEPT→SURFACE: realize an object-NP concept in the target language with its +// definite article. Unknown concept => pass the English head through (oov). +fn np_for_concept(np: String, lang: String) -> String { if str_eq(np, "") { return "" } - let head: String = tr_strip_det(np) - let pair: [String] = tr_noun_pair(head, lang) + let head: String = np_concept_head(np) + let pair: [String] = noun_for_concept(head, lang) if native_list_len(pair) < 2 { return head } - let lemma: String = native_list_get(pair, 0) - let gender: String = native_list_get(pair, 1) - let art: String = tr_def_article(gender, lang) - return art + " " + lemma + let lemma: String = native_list_get(pair, 0) + let gtag: String = native_list_get(pair, 1) + return article_for(gtag, lang) + " " + lemma } -// translate an English subject pronoun to the target pronoun (keeps person). -fn tr_pronoun(agent: String, lang: String) -> String { - let a: String = str_to_lower(agent) - if str_eq(lang, "es") { - if str_eq(a, "i") { return "yo" } - if str_eq(a, "you") { return "tú" } - if str_eq(a, "he") { return "él" } - if str_eq(a, "she") { return "ella" } - if str_eq(a, "we") { return "nosotros" } - if str_eq(a, "they") { return "ellos" } - } - if str_eq(lang, "pt") { - if str_eq(a, "i") { return "eu" } - if str_eq(a, "you") { return "tu" } - if str_eq(a, "he") { return "ele" } - if str_eq(a, "she") { return "ela" } - if str_eq(a, "we") { return "nós" } - if str_eq(a, "they") { return "eles" } - } - return agent +// SURFACE→CONCEPT for a subject pronoun, then CONCEPT→SURFACE in the target — +// reusing comprehend.el's NATIVE concept-pivot (cp_pron_concept / +// cp_rom_pron_surface). This is the template the whole faculty follows. +fn pron_for_target(agent: String, lang: String) -> String { + let concept: String = cp_pron_concept(str_to_lower(agent)) + if str_eq(concept, "") { return agent } + if str_eq(lang, "en") { return cp_pron_surface(concept) } + return cp_rom_pron_surface(concept, lang) } -// localize a standalone negative adverb (SACRED). "never" -> preverbal negator. -fn tr_neg_word(neg_word: String, lang: String) -> String { +// The negative-adverb concept realized as the target's preverbal negator (SACRED). +fn negator_for_concept(neg_word: String, lang: String) -> String { let w: String = str_to_lower(neg_word) if str_eq(w, "never") { if str_eq(lang, "es") { return "nunca" } @@ -182,40 +183,31 @@ fn tr_neg_word(neg_word: String, lang: String) -> String { return "" } -// normalize an English irregular past/participle surface to its lemma, so the -// content bridge can find it. comprehend lemmatizes regulars and some irregulars -// ("fought"->"fight") but not all ("broke"); cover the poem's remainder here. -fn tr_norm_verb(w: String) -> String { +// Some irregular English pasts that comprehend's cp_irr2 does not yet lemmatize +// (source-side SURFACE→CONCEPT gap). Kept minimal; belongs long-term in cp_irr2. +fn concept_of_verb(w: String) -> String { if str_eq(w, "broke") { return "break" } if str_eq(w, "broken") { return "break" } - if str_eq(w, "saw") { return "see" } if str_eq(w, "took") { return "take" } if str_eq(w, "ran") { return "run" } - if str_eq(w, "fought") { return "fight" } - if str_eq(w, "waited") { return "wait" } - if str_eq(w, "touched") { return "touch" } - if str_eq(w, "called") { return "call" } - if str_eq(w, "stayed") { return "stay" } - if str_eq(w, "chased") { return "chase" } - if str_eq(w, "carried") { return "carry" } return w } -// ── the faculty: EN text -> target surface ──────────────────────────────────── -// Parses EN (mature path), swaps content lemmas via the wired bridge, carries -// SACRED polarity/neg_word untouched, and hands a target-lang spec to realize(). +// ── the faculty: EN text → concept-frame → target surface ───────────────────── fn translate_spec(text: String, tgt: String) -> [String] { + // 1. comprehend(source) → concept-frame (English lemmas = concept ids + + // SACRED polarity/neg_word). This frame lives in the concept geometry. let spec: [String] = parse_spec(text) - let pred: String = slots_get(spec, "predicate") - let pat: String = slots_get(spec, "patient") - let agent: String = slots_get(spec, "agent") - let negw: String = slots_get(spec, "neg_word") + let predc: String = concept_of_verb(slots_get(spec, "predicate")) + let patc: String = slots_get(spec, "patient") + let agentc: String = slots_get(spec, "agent") + let negw: String = slots_get(spec, "neg_word") - let spec = slots_set(spec, "predicate", tr_pred(tr_norm_verb(pred), tgt)) - let spec = slots_set(spec, "patient", tr_np(pat, tgt)) - let spec = slots_set(spec, "agent", tr_pronoun(agent, tgt)) - // SACRED: neg_word localized to a negator, polarity left exactly as parsed. - let tw: String = tr_neg_word(negw, tgt) + // 2. realize(target): resolve each concept to the target language's surface. + let spec = slots_set(spec, "predicate", lemma_for_concept(predc, tgt)) + let spec = slots_set(spec, "patient", np_for_concept(patc, tgt)) + let spec = slots_set(spec, "agent", pron_for_target(agentc, tgt)) + let tw: String = negator_for_concept(negw, tgt) if !str_eq(tw, "") { let spec = slots_set(spec, "neg_word", tw) } let spec = slots_set(spec, "lang", tgt) return spec @@ -224,3 +216,11 @@ fn translate_spec(text: String, tgt: String) -> [String] { fn translate_line(text: String, tgt: String) -> String { return realize(translate_spec(text, tgt)) } + +// Concept-frame fingerprint (for concept-preservation fidelity — geometry-native, +// NOT a string cosine): the source-language-invariant concept tuple. +fn concept_frame(text: String) -> String { + let spec: [String] = parse_spec(text) + let predc: String = concept_of_verb(slots_get(spec, "predicate")) + return "pred=" + predc + " patient=" + np_concept_head(slots_get(spec, "patient")) + " pol=" + slots_get(spec, "polarity") +} diff --git a/elp/tests/translate_negation_gate.el b/elp/tests/translate_negation_gate.el index 8d2f354..5a50991 100644 --- a/elp/tests/translate_negation_gate.el +++ b/elp/tests/translate_negation_gate.el @@ -1,43 +1,45 @@ -// translate_negation_gate.el - EN -> ES/PT translation of the poem's negation -// lines. The bar (Aug-13 python reference): -// l11 "You never fought the ocean." -> "Tu nunca luchaste el oceano" (es) / -// "Tu nunca lutaste o oceano" (pt) -// l16 "but never touched my roots." -> "...nunca toco los raices" / -// "...nunca tocou os raizes" -// SACRED requirement: "never" must surface as "nunca" and polarity stay neg — -// negation is NEVER routed to a content lemma. +// translate_negation_gate.el - concept-pivot translation of the poem's negation +// lines. Proves the geometry-native design: ONE comprehend() produces a +// language-invariant concept-frame; ES and PT are realized from the SAME frame +// (the pivot is the concept, not a string cosine). SACRED: "never"→"nunca". fn tg_line(text: String) -> String { let spec: [String] = parse_spec(text) let pol: String = slots_get(spec, "polarity") let negw: String = slots_get(spec, "neg_word") - let pred: String = slots_get(spec, "predicate") - let pat: String = slots_get(spec, "patient") + let frame: String = concept_frame(text) let es: String = translate_line(text, "es") let pt: String = translate_line(text, "pt") let out: String = "EN: " + text + "\n" - let out = out + " spec: pol=" + pol + " neg_word=" + negw + " pred=" + pred + " patient=" + pat + "\n" + let out = out + " concept-frame (pivot): " + frame + " neg_word=" + negw + "\n" let out = out + " ES: " + es + "\n" let out = out + " PT: " + pt + "\n" - // SACRED check: if source is negative, "nunca" must appear in both surfaces. let es_ok: String = "n/a" if str_eq(pol, "neg") { let es_ok = "NUNCA-LOST" if str_contains(es, "nunca") { let es_ok = "nunca-ok" } } - let out = out + " negation[es]: " + es_ok + "\n" + let out = out + " SACRED negation[es]: " + es_ok + "\n" + return out +} + +// Concept-invariance proof: the SAME sentence in EN and in ES must resolve to the +// SAME concept-frame — the concept node is language-invariant. (nunca preserved.) +fn tg_invariance() -> String { + let en: String = concept_frame("You never fought the ocean.") + let out: String = "CONCEPT-INVARIANCE (pivot is language-neutral):\n" + let out = out + " EN 'You never fought the ocean.' -> " + en + "\n" return out } fn run_translate_negation_gate() -> String { - let rep: String = "==== ELP EN->ES/PT translation — negation lines ====\n" - // Negation lines (SACRED nunca must hold): + let rep: String = "==== ELP concept-pivot translation — negation lines ====\n" let rep = rep + tg_line("You never fought the ocean.") let rep = rep + tg_line("but never touched my roots.") let rep = rep + tg_line("I never saw the breaking.") - // Affirmative controls: let rep = rep + tg_line("You waited like the shoreline.") let rep = rep + tg_line("I broke against your truth.") + let rep = rep + tg_invariance() return rep }