|
Download README.md from zeechimp/holo-program: direct link, hf CLI and curl.
- Browser
- Download file 12.7 kB
-
https://huggingface.co/zeechimp/holo-program/resolve/main/README.md
- Command line
-
hf download hf://zeechimp/holo-program/README.md
-
curl -L -o README.md https://huggingface.co/zeechimp/holo-program/resolve/main/README.md
12.7 kB
| language: | |
| - en | |
| license: apache-2.0 | |
| library_name: holo-program | |
| tags: | |
| - memory | |
| - programmable-memory | |
| - membrane-computing | |
| - p-systems | |
| - cryptographic-memory | |
| - keyed-access | |
| - associative-memory | |
| - hyperdimensional-computing | |
| - vector-symbolic-architecture | |
| - numpy | |
| - educational | |
| - research | |
| datasets: [] | |
| metrics: | |
| - chain-execution-accuracy | |
| - membrane-inheritance | |
| - key-separation | |
| pipeline_tag: feature-extraction | |
| # holo-program | |
| **Programs as items, membranes as regions, keys as gates.** | |
| A memory substrate with three stacked layers under one interface. | |
| Programs are stored as key-value items and executed by | |
| unbind-then-classify. Membranes are nested regions with child-to-parent | |
| inheritance and P-systems operations. Cryptographic keying derives item | |
| vectors from a secret; without the key, the trace is noise. Everything | |
| is addressable through a single `ask()` primitive. | |
| The three layers are views of one vector space. The caller does not | |
| specify which layer to search. `ask()` returns heterogeneous hits. | |
| ## What it does | |
| ```python | |
| from holo_program import HoloProgram | |
| prog = HoloProgram(d=2048, key=None) | |
| # Programs as items | |
| prog.add_op("root", "inc", "0", "1") | |
| prog.add_op("root", "inc", "1", "2") | |
| prog.add_op("root", "double", "2", "4") | |
| # Execute a chain | |
| result = prog.run_chain("root", ["inc", "inc", "double"], "0") | |
| # result = {"path": ["0", "1", "2", "4"], "ok": True} | |
| # Membranes with inheritance | |
| prog.add_membrane("alice", parent="root") | |
| prog.store("alice", "alice_lives_in_paris") | |
| prog.query("alice", "alice_lives_in_paris") # ~1.0 | |
| prog.query("root", "alice_lives_in_paris") # ~0.0 | |
| # Keyed access | |
| p_secret = HoloProgram(key="secret") | |
| p_secret.store("root", "classified") | |
| p_wrong = HoloProgram(key="wrong") | |
| p_wrong.membranes["root"].trace = p_secret.membranes["root"].trace.copy() | |
| p_secret.query("root", "classified") # ~1.0 | |
| p_wrong.query("root", "classified") # ~0.0 | |
| # Non-flat query | |
| hits = prog.ask("inc") | |
| # [operation] membrane=root role=op inc(0) -> 1 | |
| # [operation] membrane=root role=op inc(1) -> 2 | |
| ``` | |
| ## Why three layers | |
| Standard memory tools are flat. A vector database accepts an | |
| embedding; a KV cache accepts a key; a graph database accepts a | |
| pattern. Each tool has one interface and one data layer. The user | |
| adapts the problem to the tool. | |
| The substrate here stacks three layers over the same vector space. | |
| Each layer has been built before. The composition is what is new. | |
| A user stores a fact, defines an operation, puts it in a membrane, | |
| and locks it behind a key β all through the same primitives, all | |
| retrievable through the same `ask()` call. | |
| ## Installation | |
| ```bash | |
| pip install numpy | |
| ``` | |
| No other dependencies. Single file, approximately 600 lines. | |
| ## Usage | |
| ### CLI | |
| ```bash | |
| python holo_program.py | |
| python holo_program.py --output results/ | |
| ``` | |
| Runs eight demonstrations and writes a JSON state file. | |
| ### Python | |
| ```python | |
| from holo_program import HoloProgram | |
| prog = HoloProgram(d=2048, key=None, threshold=0.05) | |
| # Membranes | |
| prog.add_membrane("alice", parent="root") | |
| prog.add_membrane("alice_kitchen", parent="alice") | |
| # Storage | |
| prog.store("root", "earth_round") | |
| prog.store("alice", "alice_lives_in_paris") | |
| prog.store("alice_kitchen", "manager_is_bob") | |
| # Operations | |
| prog.add_op("root", "serve", "customer", "coffee") | |
| prog.add_op("alice_kitchen", "brew", "coffee", "ready") | |
| # Execute | |
| result = prog.run_chain("root", ["inc", "inc"], "5") | |
| result = prog.apply("alice_kitchen", "brew", "coffee") # "ready" | |
| # Data-driven walk | |
| walk = prog.run_data_driven("root", "cold") # ["cold", "warm", ...] | |
| # P-systems operations | |
| prog.move("private_note", "alice", "root") | |
| prog.dissolve("alice_kitchen", "alice") | |
| # Non-flat query | |
| hits = prog.ask("coffee", top_k=8) | |
| # Cryptographic layer | |
| commitment = prog.commit("root", "secret_value", salt="random_salt_123") | |
| ok = prog.verify("root", "secret_value", "random_salt_123", commitment) | |
| ``` | |
| ## Results | |
| All results at D=2048, threshold=0.05. Self-test verifies four | |
| primitives before any demonstration: bind/unbind identity, key | |
| separation, projection recovery, and random-key key-value retrieval | |
| (49/50 at 50 superposed pairs). | |
| ### Program execution | |
| Twenty `inc` operations (i β i+1 for i = 0..19), twenty `double` | |
| operations (i β 2i), ten `square` operations (i β iΒ²) stored as | |
| key-value pairs. | |
| | Chain | Start | Path | Result | | |
| |---|---|---|---| | |
| | inc, inc, double | 3 | 3 β 4 β 5 β 10 | correct | | |
| | square, inc | 4 | 4 β 16 β 17 | correct | | |
| | double, inc, inc | 5 | 5 β 10 β 11 β 12 | correct | | |
| | inc, square | 2 | 2 β 3 β 9 | correct | | |
| Single applies: `inc(7) = 8`, `double(7) = 14`, `square(7) = 49`. | |
| The chains compose across different operations. The substrate does not | |
| know which operations exist; it reads the key, retrieves the value, | |
| classifies the out, and passes the result forward. | |
| ### Data-driven execution | |
| State transitions: `cold β warm β hot β boiling β evaporated`. | |
| Starting at `cold` with no predefined chain, the substrate walks by | |
| finding whichever operation matches the current value at each step: | |
| ``` | |
| cold -> warm -> hot -> boiling -> evaporated | |
| steps: 4 | |
| ``` | |
| Starting at `evaporated` (no matching operation), the walk terminates | |
| immediately. | |
| ### Membrane inheritance | |
| Three nested membranes: `root`, `alice`, `alice_kitchen`. | |
| | Query | root | alice | alice_kitchen | | |
| |---|---|---|---| | |
| | earth_round | +1.028 | +1.028 | +1.028 | | |
| | alice_lives_in_paris | +0.023 | +1.004 | +1.004 | | |
| | kitchen_floor_5 | -0.026 | -0.026 | +1.020 | | |
| | manager_is_bob | -0.004 | -0.004 | +1.020 | | |
| The child sees the parent's facts. The parent does not see the child's. | |
| Inheritance is one-way, from child to parent. | |
| ### Movement and dissolution | |
| **Move.** `private_note` stored in `inner`: | |
| | | root | inner | | |
| |---|---|---| | |
| | before | +0.027 | +1.000 | | |
| | after | +1.027 | +1.027 | | |
| The content transferred completely. | |
| **Dissolution.** `middle_fact` in `middle`, then dissolve `middle` into | |
| `root`: | |
| | | root | middle | | |
| |---|---|---| | |
| | before | +0.009 | +1.000 | | |
| | after | +1.009 | (gone) | | |
| Content transferred, membrane removed. | |
| ### Cryptographic keying | |
| Two programs share the same trace. One has the correct key; the other | |
| has a wrong key. | |
| | Candidate | Correct key | Wrong key | | |
| |---|---|---| | |
| | classified_meeting_place | +0.997 | +0.004 | | |
| | classified_meeting_time | +0.997 | -0.007 | | |
| | paris | -0.018 | -0.022 | | |
| | 3pm | -0.028 | +0.034 | | |
| | unrelated_word | -0.028 | +0.010 | | |
| With the correct key, stored items read at +0.997 and non-stored at | |
| near zero. With the wrong key, all items read near zero. The trace | |
| carries no usable signal without the key. | |
| ### Commitment scheme | |
| Commitment = `bind(vector(label), vector(salt))`. Verification: | |
| | Correct (label, salt) | Wrong salt | Wrong label | | |
| |---|---|---| | |
| | True | False | False | | |
| Commitment vector magnitude is exactly 1.0000 (phase-only binding | |
| preserves unit modulus). | |
| ### Unified `ask()` | |
| Five example queries, each returning heterogeneous hits: | |
| | Query | Result | | |
| |---|---| | |
| | `alice` | `[membrane] alice` | | |
| | `alice_lives_in_paris` | `[item] alice sim=+1.004` | | |
| | `coffee` | `[operation] serve(customer) β coffee` in root; `[operation] brew(coffee) β ready` in alice_kitchen | | |
| | `alice_kitchen` | `[membrane] alice_kitchen` | | |
| | `manager_is_bob` | `[item] alice_kitchen sim=+1.020` | | |
| The caller does not specify which layer to search. The substrate | |
| reports what it has. | |
| ### Programs as items | |
| Querying `ask("inc")` returns the two stored `inc` operations. | |
| Querying `ask("3")` returns both the operation where `3` is an | |
| output (`inc(2) β 3`) and the operation where `3` is an input | |
| (`double(3) β 6`). The `role` field distinguishes them. | |
| The same primitive reads items and operations. There is no separate | |
| "program layer" from the caller's perspective. | |
| ## API reference | |
| ### `HoloProgram` | |
| ```python | |
| HoloProgram(d=2048, key=None, threshold=0.05) | |
| ``` | |
| **Membrane management** | |
| - `add_membrane(name, parent="root")` β create a nested membrane. | |
| **Storage** | |
| - `store(membrane, label, weight=1.0)` β store an item. | |
| - `add_op(membrane, op_name, in_val, out_val)` β store an operation. | |
| - `move(label, src, dst)` β transfer an item between membranes. | |
| - `dissolve(child, into)` β merge a child membrane into its parent. | |
| **Execution** | |
| - `apply(membrane, op_name, in_val) -> out_val | None` β single step. | |
| - `run_chain(membrane, ops, start) -> dict` β fixed sequence. | |
| - `run_data_driven(membrane, start, max_steps=20) -> dict` β follow | |
| whichever operation matches at each step. | |
| **Query** | |
| - `query(membrane, label) -> float` β similarity in the membrane's | |
| inheritance chain. | |
| - `ask(query, top_k=8) -> list[dict]` β heterogeneous search across | |
| all membranes and all layers. | |
| **Cryptographic** | |
| - `commit(membrane, label, salt) -> np.ndarray` β generate commitment. | |
| - `verify(membrane, label, salt, commitment) -> bool` β verify. | |
| **Diagnostics** | |
| - `stats() -> dict` β per-membrane counts and magnitudes. | |
| - `save_json(path)` β full state. | |
| ## Design notes | |
| ### Random keys, not structured keys | |
| Operations use fully random keys derived from a hash of `(op_name, | |
| in_val)`, not from a structured binding of role vectors. An earlier | |
| version used `norm(bind(op, op_name) + bind(in, in_val))`, which | |
| produced correlated keys for operations sharing a component. With | |
| twenty `inc` operations, the shared `inc` component made the keys | |
| correlated and cross-talk swamped the signal; only single applies | |
| worked. | |
| The random-key variant removes the cross-talk at the cost of treating | |
| every `(op, in)` pair as structurally distinct. The `op` role is | |
| still used for the value (`bind(out, out_val)`), but not for the key. | |
| ### Parent direction | |
| Inheritance goes from child to parent. A child sees its parent's | |
| facts; a parent does not see its child's facts. This is the natural | |
| direction for a "context" relation: a specific context inherits from | |
| a general one, not the other way around. | |
| ### Keyed codebook | |
| Item vectors are derived from `random_vector(key, label)`. Different | |
| keys produce uncorrelated vectors for the same label. A trace built | |
| with key A, queried with key B, produces similarity near zero because | |
| the two codebooks are independent. | |
| This is access control at the codebook level. Without the key, the | |
| trace is a random superposition of unknown vectors. | |
| ## Limitations | |
| **Programs are not Turing-complete.** Chains and data-driven walks | |
| compose operations. Branching, iteration, and recursion must be | |
| encoded as larger operation sets or implemented outside the substrate. | |
| **No catalysis.** An operation cannot require a third object to be | |
| present. The structure supports it (a catalyst could be a role in the | |
| operation and a check against the local trace) but it is not | |
| implemented. | |
| **No priority.** Multiple applicable operations are returned by | |
| `find_applicable` sorted by similarity. There is no specificity-based | |
| ordering or explicit precedence. | |
| **No timed rules.** Operations have no validity windows. | |
| **No provenance.** The substrate does not track which call produced | |
| which weight. Two sources that store the same fact look identical. | |
| **Keys are not secret against an adversary with the codebook.** The | |
| key separation prevents a wrong-key query from retrieving items. It | |
| does not prevent brute-force matching against the trace if the label | |
| space is small. | |
| **Commitments are not cryptographic.** `bind(vector(label), | |
| vector(salt))` is a hash-like operation in the substrate's algebra. | |
| It is not a cryptographically secure commitment in the formal sense. | |
| It is useful for cooperative verification, not for adversarial | |
| security. | |
| **No cross-membrane queries.** A query goes to one membrane. | |
| `ask()` searches all membranes for the query string, but it does not | |
| propagate the query through the inheritance chain. | |
| **No consolidation.** Traces grow linearly. Long-running stores need | |
| external management. The four-axis tool provides consolidation; it is | |
| not integrated here. | |
| ## Citation | |
| ```bibtex | |
| @misc{holo-program2026, | |
| title = {holo-program: Programs as items, membranes as regions, | |
| keys as gates}, | |
| author = {zeechimp}, | |
| year = {2026}, | |
| note = {A memory substrate with three stacked layers under a | |
| single non-flat interface.} | |
| } | |
| ``` | |
| ## References | |
| - Plate, T. A. "Holographic Reduced Representations." *IEEE Transactions on Neural Networks* 6:3 (1995), 623β641. | |
| - Kanerva, P. "Hyperdimensional Computing." *Cognitive Computation* 1:2 (2009), 139β159. | |
| - PΔun, Gh. "Computing with Membranes." *Journal of Computer and System Sciences* 61:1 (2000), 108β143. | |
| - Gayler, R. W. "Vector Symbolic Architectures Answer Jackendoff's Challenges." *ICCS/ASCS* (2003). | |
| ## License | |
| Apache 2.0 |