Skip to content

Architecture and reduction

This section explains how Radixor turns textual dictionary input into a compact compiled stemmer and how reduction affects the semantics preserved in the final runtime artifact.

Radixor is easiest to understand when separated into two related concerns:

  • architecture: what structures exist, how data moves through them, and what runtime lookup actually does,
  • reduction semantics: what it means for two subtrees to be considered equivalent and how that choice affects get() and getAll() behavior.

The short version

Radixor does not keep a large flat table of final stems. Instead, it converts dictionary entries into patch commands, stores them in a trie, reduces equivalent subtrees, and freezes the result into an immutable compiled structure.

The preparation and runtime lanes are:

flowchart TB
    accTitle: Preparation and runtime lanes
    accDescr: Preparation derives ranked patch commands from lexical families, builds a mutable trie, reduces it, and freezes an immutable runtime structure. An optional version 7 artifact is a persisted-format boundary rather than a shared memory layout. Runtime looks up specificity-ranked candidates, selects a command, and applies that command to the original token. Contraction changes structural coverage, while semantic reduction merges already-equivalent behavior.

    subgraph PREP[Preparation lane]
        direction LR
        FAMILIES["Lexical families: forms and roots"] --> COMMANDS["Ranked patch commands: stored commands, not stems"]
        COMMANDS --> MUTABLE["Mutable trie: frequency evidence"]
        MUTABLE --> REDUCE["Contraction changes coverage; semantic reduction merges equivalent behavior"]
        REDUCE --> FROZEN["Immutable runtime structure"]
    end

    FROZEN -->|"optional persistence"| V7["Version 7 artifact: persisted format, not shared memory layout"]

    subgraph RUNTIME[Runtime lane]
        direction LR
        TOKEN["Original token"] --> LOOKUP["Lookup specificity-ranked candidates"]
        LOOKUP --> SELECT["Select command"]
        SELECT --> APPLY["Apply selected command to original token"]
    end

    FROZEN -->|"direct in-memory handoff"| LOOKUP
    V7 -->|"load in any supported runtime"| LOOKUP
    TOKEN -.->|"unchanged source for command application"| APPLY

Preparation stores ranked commands rather than final stems. Contraction extends a locally uniform command decision to additional continuations; semantic reduction merges behavior that is already equivalent under the selected reduction contract. An optional version 7 artifact is the cross-runtime persistence boundary, not a shared in-memory layout. At runtime, candidate commands remain specificity-ranked and the selected command is applied to the original token.

All three runtimes follow this conceptual flow. Java materializes an object-based compiled trie and exposes multiple reduction modes. Python (PyO3) implements the production dominant-result profile in Rust and stores its runtime trie in flat arrays. Python-C implements the same compiled-model lookup contract through the CPython C API. The version 7 binary stream is their persistence and interoperability boundary; they do not share an in-memory representation.

For registered Java models, the dictionary is an independently versioned GZip resource discovered through a descriptor and verified before this flow begins. For Python's standard models, this flow runs during package preparation and the installed radixor-models-standard distribution already contains validated compiled version 7 tries. See Model Selection and Loading for Java discovery, Runtime Architecture for component and lookup boundaries, and Stemmer Models for packaging and release boundaries.

Explicit descriptors and stable model IDs now use the same compiled-value path as language defaults. loadCompiled(descriptor, ...) and loadCompiled(modelId, ...) first build with serialized patch commands and then map those values to CompiledPatchCommand while preserving metadata, reduction semantics, and ranked getAll order. Very large inputs can have a high temporary construction peak; PoliMorf is verified in an isolated 6 GiB JVM rather than increasing ordinary test or Gradle daemon heaps.

At runtime, the compiled trie does not directly return the final stem string. It returns one or more stored patch commands for the addressed key, and those commands are then applied to the original input word.

Why this matters

This design gives Radixor several practical properties at once:

  • compact deployable artifacts,
  • deterministic runtime behavior,
  • support for both preferred and multiple candidate results,
  • separation of preparation-time complexity from runtime lookup.

It also explains why a large source dictionary can be transformed into a much smaller compiled artifact without discarding the operational behavior that matters to the caller.

Reading guide

Use the following pages depending on what you need to understand:

  • Architecture explains the data flow, core structures, patch-command lookup model, and why the compiled trie is efficient at runtime.
  • Reduction Semantics explains how subtree equivalence is defined, what ranked, unordered, and dominant reduction preserve, and how those choices affect observable lookup behavior.

For most readers, the best order is:

  1. Architecture
  2. Reduction Semantics