From 5c0a49853aeec089c0b32723cf07e38103289960 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Mon, 9 Feb 2026 02:51:20 +0000 Subject: [PATCH] doc for now, TM_SR_ND --- .gitignore | 4 + developer/authored/DiscreteFunction.py | 61 +++ developer/authored/SymbolSpace.py | 84 ++++ developer/authored/TM.py | 90 ++-- developer/authored/TM_module.c | 425 ++++++++---------- .../TM_module.cpython-311-x86_64-linux-gnu.so | Bin 44280 -> 0 bytes .../TM_module.cpython-311-x86_64-linux-gnu.so | Bin 44280 -> 0 bytes .../temp.linux-x86_64-cpython-311/TM_module.o | Bin 52568 -> 0 bytes developer/authored/example_features.py | 59 +++ developer/authored/example_queries.py | 88 ++++ developer/authored_2026-02-09.tar | Bin 0 -> 40960 bytes document/TM.html | 44 +- 12 files changed, 545 insertions(+), 310 deletions(-) create mode 100755 developer/authored/DiscreteFunction.py create mode 100755 developer/authored/SymbolSpace.py delete mode 100755 developer/authored/TM_module.cpython-311-x86_64-linux-gnu.so delete mode 100755 developer/authored/build/lib.linux-x86_64-cpython-311/TM_module.cpython-311-x86_64-linux-gnu.so delete mode 100644 developer/authored/build/temp.linux-x86_64-cpython-311/TM_module.o create mode 100755 developer/authored/example_features.py create mode 100755 developer/authored/example_queries.py create mode 100644 developer/authored_2026-02-09.tar diff --git a/.gitignore b/.gitignore index ff01a07..7bdb193 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ __pycache__/ *~ *.bak +# build libraires +*.so +*.a + diff --git a/developer/authored/DiscreteFunction.py b/developer/authored/DiscreteFunction.py new file mode 100755 index 0000000..f11ad4d --- /dev/null +++ b/developer/authored/DiscreteFunction.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +from SymbolSpace import SymbolSpace + +# ========================================== +# THE GRAPH (Discrete Function) +# ========================================== + +class DiscreteFunction: + """ + The Knowledge Store. + Supports 'Smart Postings' to Parent Symbols. + """ + def __init__(self): + self._rev = {} # reverse map: Symbol -> Set of Objects + + def _add_posting(self ,sym ,obj): + if sym not in self._rev: self._rev[sym] = set() + self._rev[sym].add(obj) + + def set(self ,obj_sym ,prop_sym): + """ + Assigns a property. Updates indexes for the specific property + AND its namespace (Parent). + """ + # 1. Index Specific (e.g., #105 'Red') + self._add_posting(prop_sym ,obj_sym) + + # 2. Index General (e.g., #50 'Color') + parent = SymbolSpace.get_parent(prop_sym) + if parent: + self._add_posting(parent ,obj_sym) + + def find(self ,sym): + """Returns the set of objects associated with this symbol.""" + return self._rev.get(sym ,set()) + +# --- Work Function --- + +def verify_graph(): + print("--- DiscreteFunction Verification ---") + # 1. Create Symbols + sym_obj = SymbolSpace.alloc() + sym_prop = SymbolSpace.alloc() + sym_parent = SymbolSpace.alloc() + + # 2. Setup Hierarchy + SymbolSpace.set_parent(sym_prop, sym_parent) + + # 3. Set Fact + df = DiscreteFunction() + df.set(sym_obj, sym_prop) + + # 4. Check Smart Posting + print(f"Finding specific property: {len(df.find(sym_prop))} (Expected 1)") + print(f"Finding parent category: {len(df.find(sym_parent))} (Expected 1)") + +def CLI(): + verify_graph() + +if __name__ == "__main__": + CLI() diff --git a/developer/authored/SymbolSpace.py b/developer/authored/SymbolSpace.py new file mode 100755 index 0000000..e363e3e --- /dev/null +++ b/developer/authored/SymbolSpace.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +from collections import deque as FIFO + +class SymbolSpace: + """ + The manager of the Epimetheus integer namespace. + """ + + _counter = 0 + _dealloc_queue = FIFO() + + # HIERARCHY SUPPORT (Added) + _parents = {} # Map: Child_Sym -> Parent_Sym + + class Instance: + """The handle for a symbol.""" + __slots__ = ('_value' ,) + + def __init__(self ,value): + self._value = value + + def __eq__(self ,other): + # Compare value, not identity + if isinstance(other ,SymbolSpace.Instance): return self._value == other._value + return False + + def __hash__(self): + return hash(self._value) + + def __repr__(self): + return f"" + + @classmethod + def alloc(cls) -> 'SymbolSpace.Instance': + val = 0 + if cls._dealloc_queue: + val = cls._dealloc_queue.popleft() + else: + cls._counter += 1 + val = cls._counter + return cls.Instance(val) + + @classmethod + def dealloc(cls ,sym: 'SymbolSpace.Instance'): + val = sym._value + if val == 0: raise ValueError("Null symbol (0) cannot be deallocated.") + + if val == cls._counter: + cls._counter -= 1 + while cls._counter > 0 and cls._counter in cls._dealloc_queue: + cls._dealloc_queue.remove(cls._counter) + cls._counter -= 1 + else: + cls._dealloc_queue.append(val) + + @classmethod + def get_null(cls) -> 'SymbolSpace.Instance': + return cls.Instance(0) + + # --- Hierarchy Methods --- + + @classmethod + def set_parent(cls ,child ,parent): + cls._parents[child] = parent + + @classmethod + def get_parent(cls ,child): + return cls._parents.get(child) + +def verify(): + print(f"Allocating 3 symbols...") + s1 = SymbolSpace.alloc() + s2 = SymbolSpace.alloc() + + # Test Hierarchy + SymbolSpace.set_parent(s2, s1) + assert SymbolSpace.get_parent(s2) == s1 + print("Hierarchy check passed.") + +def CLI(): + verify() + +if __name__ == "__main__": + CLI() diff --git a/developer/authored/TM.py b/developer/authored/TM.py index 3995622..9af7de4 100755 --- a/developer/authored/TM.py +++ b/developer/authored/TM.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 import sys -from enum import Enum ,auto +from enum import Enum, auto try: import TM_module @@ -9,11 +9,11 @@ except ImportError: sys.exit(1) # ========================================== -# 1. Enums +# 1. Enums & Features # ========================================== -LM = "LM" -RM = "RM" +class Features: + APPEND_RIGHT = "aR" class Status(Enum): ABANDONED = auto() @@ -28,73 +28,53 @@ class Topology(Enum): SEGMENT = auto() # ========================================== -# 2. The Machine (Direct Alias) +# 2. The Machine (Factory) # ========================================== -# The Safety Logic is now 100% in C. -# We just alias the type. +# TM is now the Factory Function from the C module TM = TM_module.FastTM # ========================================== -# 3. Status Wrapper +# 3. Status Wrapper (TMS) # ========================================== -class TM2: - def __init__(self ,data_obj=None): +class TMS: + def __init__(self, data_obj=None, features=None): + """ + TMS Constructor. + Args: + data_obj: Initial data container (list). + features: List of feature symbols (e.g. [Features.APPEND_RIGHT]). + """ if data_obj: - self.tm = TM(data_obj) + # Factory Call: C determines the underlying type based on features + self.tm = TM(data_obj, features) self._stat = Status.ACTIVE else: self.tm = None self._stat = Status.EMPTY + # --- Base Methods (SR_ND) --- def r(self): return self.tm.r() - def rn(self ,n_val): return self.tm.rn(n_val) - def w(self ,val_obj): return self.tm.w(val_obj) - def wn(self ,val_obj): return self.tm.wn(val_obj) + def rn(self, n): return self.tm.rn(n) + def w(self, v): return self.tm.w(v) + def wn(self, v): return self.tm.wn(v) def s(self): return self.tm.s() - def sn(self ,n_val): return self.tm.sn(n_val) - def ls(self): return self.tm.ls() - def lsn(self ,n_val): return self.tm.lsn(n_val) - def d(self): return self.tm.d() - def dn(self ,n_val): return self.tm.dn(n_val) - def esd(self): return self.tm.esd() - def esdn(self ,n_val): return self.tm.esdn(n_val) - def aL(self ,val_obj): return self.tm.aL(val_obj) - def aR(self ,val_obj): return self.tm.aR(val_obj) - def e(self): return TM2(self.tm.e()) if not self.empty() else TM2(None) - - def empty(self): return self._stat == Status.EMPTY - def rightmost(self): return True if self.empty() else self.tm.rightmost() - def leftmost(self): return True if self.empty() else self.tm.leftmost() + def sn(self, n): return self.tm.sn(n) + def address(self): return 0 if self.empty() else self.tm.address() - def topology(self): return Topology.NULL if self.empty() else Topology.SEGMENT - -# ========================================== -# 4. Verification -# ========================================== + def len(self): return 0 if self.empty() else self.tm.len() -def CLI(): - print("--- TM Full C-Entanglement Verification ---") + # --- Feature Methods (Delegated) --- + # If the C-Type doesn't have these, Python raises AttributeError. + def aR(self, v): return self.tm.aR(v) - # 1. Setup - t1 = TM2(['A' ,'B' ,'C']) - t2 = t1.e() # Entangle (C handles registration) - - print(f"T1 Addr: {t1.address()}") - print(f"T2 Addr: {t2.address()}") - - # 2. Move T2 to danger zone - t2.s() # T2 on 'B' - print(f"T2 Step -> {t2.r()}") - - # 3. Trigger Entanglement Check (in C) - print("T1 attempting to delete 'B' (esd)...") - try: - t1.esd() # Should fail - except RuntimeError as e: - print(f"Caught C-Level Exception: {e}") - -if __name__ == "__main__": - CLI() + # --- Meta --- + def e(self): + # Cloning preserves the underlying C-Type (and thus features) + return TMS(self.tm.e()) if not self.empty() else TMS(None) + def empty(self): return self._stat == Status.EMPTY + def rightmost(self): return True if self.empty() else self.tm.rightmost() + def leftmost(self): return True if self.empty() else (self.tm.head == 0) + def topology(self): return Topology.NULL if self.empty() else Topology.SEGMENT diff --git a/developer/authored/TM_module.c b/developer/authored/TM_module.c index fefab09..b0e7524 100644 --- a/developer/authored/TM_module.c +++ b/developer/authored/TM_module.c @@ -1,16 +1,18 @@ /* TM_module.c - CPython Extension: Direct List Access + Entanglement Safety - RT Code Format Compliant + CPython Extension: Tape Machine Factory + Implements: + - TM_SR_ND (Base: Step Right, Non-Destructive) + - TM_SR_ND_AR (Feature: Append Right) */ #define PY_SSIZE_T_CLEAN #include #include "structmember.h" -#include /* For offsetof */ +#include /* ========================================================= */ -/* TYPE DEFINITION */ +/* 1. DATA LAYOUT (Shared) */ /* ========================================================= */ typedef struct { @@ -21,317 +23,280 @@ typedef struct { PyObject* weakreflist; /* Required for WeakRefs */ } FastTM; -/* Forward Declaration */ -static PyObject* FastTM_address(FastTM* self); - static void FastTM_dealloc(FastTM* self){ - /* Clear weak references first! */ if( self->weakreflist != NULL ){ PyObject_ClearWeakRefs((PyObject*)self); } - Py_XDECREF(self->tape_obj); Py_XDECREF(self->peer_list); Py_TYPE(self)->tp_free((PyObject*)self); } -/* Helper: Register self into the peer_list. - Uses WeakRef so dead machines don't keep the list alive. -*/ -static int register_entanglement(FastTM* self ,PyObject* existing_peer_list){ +/* Helper: Register Entanglement */ +static int register_entanglement(FastTM* self, PyObject* existing_peer_list){ PyObject* weak_ref = NULL; - if( existing_peer_list ){ - /* Join existing entanglement */ self->peer_list = existing_peer_list; Py_INCREF(self->peer_list); } else { - /* Start new entanglement */ self->peer_list = PyList_New(0); if( !self->peer_list ) return -1; } - - /* Create WeakRef to self */ - weak_ref = PyWeakref_NewRef((PyObject*)self ,NULL); + weak_ref = PyWeakref_NewRef((PyObject*)self, NULL); if( !weak_ref ) return -1; - - /* Add to list */ - if( PyList_Append(self->peer_list ,weak_ref) < 0 ){ + if( PyList_Append(self->peer_list, weak_ref) < 0 ){ Py_DECREF(weak_ref); return -1; } - Py_DECREF(weak_ref); return 0; } -static int FastTM_init(FastTM* self ,PyObject* arg_tuple ,PyObject* kwd_dict){ - PyObject* input_obj = NULL; - - /* Initialize weakref list to NULL */ - self->weakreflist = NULL; - - if( !PyArg_ParseTuple(arg_tuple ,"O" ,&input_obj) ) return -1; - - if( PyObject_TypeCheck(input_obj ,Py_TYPE(self)) ){ - /* CLONE MODE: Entangle with existing TM */ - FastTM* source_tm = (FastTM*)input_obj; - - /* Share Tape */ - self->tape_obj = source_tm->tape_obj; - Py_INCREF(self->tape_obj); - - /* Copy Head */ - self->head = source_tm->head; - - /* Register in shared peer list */ - if( register_entanglement(self ,source_tm->peer_list) < 0 ) return -1; - - } else { - /* NEW MODE: Create from Container */ - if( PyList_Check(input_obj) ){ - self->tape_obj = input_obj; - Py_INCREF(self->tape_obj); - } else { - self->tape_obj = PySequence_List(input_obj); - if( !self->tape_obj ) return -1; - } - - self->head = 0; - - /* Start new peer list */ - if( register_entanglement(self ,NULL) < 0 ) return -1; - } - - return 0; -} - /* ========================================================= */ -/* ENTANGLEMENT SAFETY CHECK */ +/* 2. THE MIXIN LIBRARY (Static C Functions) */ /* ========================================================= */ -/* - Checks if any PEER (other than self) is within the forbidden range. - Range: [start, start + count) - Returns 0 if Safe, -1 if Violation (and sets Exception). -*/ -static int check_safety(FastTM* self ,Py_ssize_t start_idx ,Py_ssize_t count_val){ - Py_ssize_t i; - Py_ssize_t num_peers; - PyObject* ref_item; - PyObject* peer_obj; - FastTM* peer_tm; - Py_ssize_t end_idx = start_idx + count_val; - - num_peers = PyList_Size(self->peer_list); - - for( i = 0; i < num_peers; i++ ){ - ref_item = PyList_GetItem(self->peer_list ,i); /* Borrowed */ - peer_obj = PyWeakref_GetObject(ref_item); /* Borrowed */ - - /* Skip dead objects or self */ - if( peer_obj == Py_None || peer_obj == (PyObject*)self ) continue; - - peer_tm = (FastTM*)peer_obj; - - /* Collision Check */ - if( peer_tm->head >= start_idx && peer_tm->head < end_idx ){ - PyErr_SetString(PyExc_RuntimeError ,"Entanglement Violation: Peer is on target cell"); - return -1; - } - } - return 0; +/* --- Navigation --- */ +static PyObject* mixin_s(FastTM* self){ + self->head++; + Py_RETURN_NONE; } -/* ========================================================= */ -/* METHODS */ -/* ========================================================= */ +static PyObject* mixin_sn(FastTM* self, PyObject* arg_tuple){ + Py_ssize_t n_val; + if( !PyArg_ParseTuple(arg_tuple, "n", &n_val) ) return NULL; + if (n_val < 0) { + PyErr_SetString(PyExc_ValueError, "Machine supports positive steps only."); + return NULL; + } + self->head += n_val; + Py_RETURN_NONE; +} -/* --- Read --- */ -static PyObject* FastTM_r(FastTM* self){ - PyObject* item_obj = PyList_GetItem(self->tape_obj ,self->head); +/* --- I/O --- */ +static PyObject* mixin_r(FastTM* self){ + PyObject* item_obj = PyList_GetItem(self->tape_obj, self->head); if( !item_obj ) return NULL; Py_INCREF(item_obj); return item_obj; } -static PyObject* FastTM_rn(FastTM* self ,PyObject* arg_tuple){ +static PyObject* mixin_rn(FastTM* self, PyObject* arg_tuple){ Py_ssize_t n_val; - if( !PyArg_ParseTuple(arg_tuple ,"n" ,&n_val) ) return NULL; - return PyList_GetSlice(self->tape_obj ,self->head ,self->head + n_val); + if( !PyArg_ParseTuple(arg_tuple, "n", &n_val) ) return NULL; + return PyList_GetSlice(self->tape_obj, self->head, self->head + n_val); } -/* --- Write --- */ -static PyObject* FastTM_w(FastTM* self ,PyObject* val_obj){ +static PyObject* mixin_w(FastTM* self, PyObject* val_obj){ Py_INCREF(val_obj); - if( PyList_SetItem(self->tape_obj ,self->head ,val_obj) < 0 ) return NULL; + if( PyList_SetItem(self->tape_obj, self->head, val_obj) < 0 ) return NULL; Py_RETURN_NONE; } -static PyObject* FastTM_wn(FastTM* self ,PyObject* arg_tuple){ +static PyObject* mixin_wn(FastTM* self, PyObject* arg_tuple){ PyObject* val_list; - if( !PyArg_ParseTuple(arg_tuple ,"O" ,&val_list) ) return NULL; + if( !PyArg_ParseTuple(arg_tuple, "O", &val_list) ) return NULL; Py_ssize_t len_val = PySequence_Size(val_list); - if( PyList_SetSlice(self->tape_obj ,self->head ,self->head + len_val ,val_list) < 0 ) return NULL; + if( PyList_SetSlice(self->tape_obj, self->head, self->head + len_val, val_list) < 0 ) return NULL; Py_RETURN_NONE; } -/* --- Step --- */ -static PyObject* FastTM_s(FastTM* self){ - self->head++; - Py_RETURN_NONE; -} +/* --- Features --- */ -static PyObject* FastTM_sn(FastTM* self ,PyObject* arg_tuple){ - Py_ssize_t n_val; - if( !PyArg_ParseTuple(arg_tuple ,"n" ,&n_val) ) return NULL; - self->head += n_val; +/* Feature: aR (Append Right) */ +static PyObject* mixin_aR(FastTM* self, PyObject* val_obj){ + /* aR typically appends to the END of the tape, + regardless of head position, in non-destructive contexts? + Or at the head? + Standard definition: Append to end of container. */ + if( PyList_Append(self->tape_obj, val_obj) < 0 ) return NULL; Py_RETURN_NONE; } -static PyObject* FastTM_ls(FastTM* self){ - self->head--; - Py_RETURN_NONE; +/* --- Meta --- */ +static PyObject* mixin_e(FastTM* self){ + /* Factory-aware Entanglement: + We call the type's constructor. Since Py_TYPE(self) is the specific + machine type (e.g. TM_SR_ND_AR), the clone will inherit the same features. */ + PyObject* arg_tuple = PyTuple_Pack(1, self); + PyObject* new_obj = PyObject_CallObject((PyObject*)Py_TYPE(self), arg_tuple); + Py_DECREF(arg_tuple); + return new_obj; } -static PyObject* FastTM_lsn(FastTM* self ,PyObject* arg_tuple){ - Py_ssize_t n_val; - if( !PyArg_ParseTuple(arg_tuple ,"n" ,&n_val) ) return NULL; - self->head -= n_val; - Py_RETURN_NONE; +static PyObject* mixin_address(FastTM* self){ + return PyLong_FromSsize_t(self->head); } -/* --- Allocate --- */ -static PyObject* FastTM_aL(FastTM* self ,PyObject* val_obj){ - if( PyList_Insert(self->tape_obj ,0 ,val_obj) < 0 ) return NULL; - self->head++; - Py_RETURN_NONE; +static PyObject* mixin_len(FastTM* self){ + return PyLong_FromSsize_t(PyList_Size(self->tape_obj)); } -static PyObject* FastTM_aR(FastTM* self ,PyObject* val_obj){ - if( PyList_Append(self->tape_obj ,val_obj) < 0 ) return NULL; - Py_RETURN_NONE; +static PyObject* mixin_rightmost(FastTM* self){ + Py_ssize_t len = PyList_Size(self->tape_obj); + if( self->head >= len - 1 ) Py_RETURN_TRUE; + Py_RETURN_FALSE; } -/* --- Delete (Safe) --- */ - -static PyObject* FastTM_d(FastTM* self){ - if( check_safety(self ,self->head ,1) < 0 ) return NULL; - if( PyList_SetSlice(self->tape_obj ,self->head ,self->head + 1 ,NULL) < 0 ) return NULL; - Py_RETURN_NONE; -} +/* ========================================================= */ +/* 3. TYPE DEFINITIONS */ +/* ========================================================= */ -static PyObject* FastTM_dn(FastTM* self ,PyObject* arg_tuple){ - Py_ssize_t n_val; - if( !PyArg_ParseTuple(arg_tuple ,"n" ,&n_val) ) return NULL; +/* Generic Init (Used by all types) */ +static int GenericTM_init(FastTM* self, PyObject* args, PyObject* kwds){ + PyObject* input_obj = NULL; + PyObject* features_obj = NULL; /* Ignored here, consumed by Factory */ - if( check_safety(self ,self->head ,n_val) < 0 ) return NULL; - if( PyList_SetSlice(self->tape_obj ,self->head ,self->head + n_val ,NULL) < 0 ) return NULL; - Py_RETURN_NONE; + if( !PyArg_ParseTuple(args, "O|O", &input_obj, &features_obj) ) return -1; + + if( PyObject_TypeCheck(input_obj, Py_TYPE(self)) ){ + /* Clone/Entangle */ + FastTM* source_tm = (FastTM*)input_obj; + self->tape_obj = source_tm->tape_obj; + Py_INCREF(self->tape_obj); + self->head = source_tm->head; + if( register_entanglement(self, source_tm->peer_list) < 0 ) return -1; + } else { + /* New */ + if( PyList_Check(input_obj) ){ + self->tape_obj = input_obj; + Py_INCREF(self->tape_obj); + } else { + self->tape_obj = PySequence_List(input_obj); + if( !self->tape_obj ) return -1; + } + if (PyList_Size(self->tape_obj) == 0) { + PyErr_SetString(PyExc_ValueError, "First Order TM cannot be empty."); + return -1; + } + self->head = 0; + if( register_entanglement(self, NULL) < 0 ) return -1; + } + return 0; } -static PyObject* FastTM_esd(FastTM* self){ - Py_ssize_t victim = self->head + 1; - if( check_safety(self ,victim ,1) < 0 ) return NULL; - if( PyList_SetSlice(self->tape_obj ,victim ,victim + 1 ,NULL) < 0 ) return NULL; - Py_RETURN_NONE; -} +/* --- Type 1: TM_SR_ND (Base) --- */ +static PyMethodDef TM_SR_ND_methods[] = { + {"r", (PyCFunction)mixin_r, METH_NOARGS, ""}, + {"rn", (PyCFunction)mixin_rn, METH_VARARGS, ""}, + {"w", (PyCFunction)mixin_w, METH_O, ""}, + {"wn", (PyCFunction)mixin_wn, METH_VARARGS, ""}, + {"s", (PyCFunction)mixin_s, METH_NOARGS, ""}, + {"sn", (PyCFunction)mixin_sn, METH_VARARGS, ""}, + {"e", (PyCFunction)mixin_e, METH_NOARGS, ""}, + {"address", (PyCFunction)mixin_address, METH_NOARGS, ""}, + {"len", (PyCFunction)mixin_len, METH_NOARGS, ""}, + {"rightmost", (PyCFunction)mixin_rightmost, METH_NOARGS, ""}, + {NULL} +}; -static PyObject* FastTM_esdn(FastTM* self ,PyObject* arg_tuple){ - Py_ssize_t n_val; - Py_ssize_t start_val; - if( !PyArg_ParseTuple(arg_tuple ,"n" ,&n_val) ) return NULL; - - start_val = self->head + 1; - if( check_safety(self ,start_val ,n_val) < 0 ) return NULL; - if( PyList_SetSlice(self->tape_obj ,start_val ,start_val + n_val ,NULL) < 0 ) return NULL; - Py_RETURN_NONE; -} +static PyTypeObject TM_SR_ND_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "TM_module.TM_SR_ND", + .tp_doc = "Step Right, Non-Destructive", + .tp_basicsize = sizeof(FastTM), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_init = (initproc)GenericTM_init, + .tp_dealloc = (destructor)FastTM_dealloc, + .tp_methods = TM_SR_ND_methods, + .tp_weaklistoffset = offsetof(FastTM, weakreflist) +}; -/* --- Meta --- */ -static PyObject* FastTM_e(FastTM* self){ - PyObject* arg_tuple = PyTuple_Pack(1 ,self); - PyObject* new_obj = PyObject_CallObject((PyObject*)Py_TYPE(self) ,arg_tuple); - Py_DECREF(arg_tuple); - return new_obj; -} +/* --- Type 2: TM_SR_ND_AR (Base + aR) --- */ +static PyMethodDef TM_SR_ND_AR_methods[] = { + /* Copy Base Methods */ + {"r", (PyCFunction)mixin_r, METH_NOARGS, ""}, + {"rn", (PyCFunction)mixin_rn, METH_VARARGS, ""}, + {"w", (PyCFunction)mixin_w, METH_O, ""}, + {"wn", (PyCFunction)mixin_wn, METH_VARARGS, ""}, + {"s", (PyCFunction)mixin_s, METH_NOARGS, ""}, + {"sn", (PyCFunction)mixin_sn, METH_VARARGS, ""}, + {"e", (PyCFunction)mixin_e, METH_NOARGS, ""}, + {"address", (PyCFunction)mixin_address, METH_NOARGS, ""}, + {"len", (PyCFunction)mixin_len, METH_NOARGS, ""}, + {"rightmost", (PyCFunction)mixin_rightmost, METH_NOARGS, ""}, + /* Add Feature */ + {"aR", (PyCFunction)mixin_aR, METH_O, "Append Right"}, + {NULL} +}; -static PyObject* FastTM_address(FastTM* self){ - return PyLong_FromSsize_t(self->head); -} +static PyTypeObject TM_SR_ND_AR_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "TM_module.TM_SR_ND_AR", + .tp_doc = "Step Right, Non-Destructive, Append Right", + .tp_basicsize = sizeof(FastTM), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_init = (initproc)GenericTM_init, + .tp_dealloc = (destructor)FastTM_dealloc, + .tp_methods = TM_SR_ND_AR_methods, + .tp_weaklistoffset = offsetof(FastTM, weakreflist) +}; -static PyObject* FastTM_len(FastTM* self){ - return PyLong_FromSsize_t(PyList_Size(self->tape_obj)); -} +/* ========================================================= */ +/* 4. THE FACTORY */ +/* ========================================================= */ -static PyObject* FastTM_rightmost(FastTM* self){ - Py_ssize_t len = PyList_Size(self->tape_obj); - if( self->head >= len - 1 ) Py_RETURN_TRUE; - Py_RETURN_FALSE; -} +static PyObject* FastTM_Factory(PyObject* self, PyObject* args, PyObject* kwds){ + PyObject* input_obj = NULL; + PyObject* features_obj = NULL; + + if( !PyArg_ParseTuple(args, "O|O", &input_obj, &features_obj) ) return NULL; + + /* Check for "aR" in features */ + int has_aR = 0; + if( features_obj && PyList_Check(features_obj) ){ + Py_ssize_t size = PyList_Size(features_obj); + for( Py_ssize_t i=0; ihead <= 0 ) Py_RETURN_TRUE; - Py_RETURN_FALSE; + /* Select Type */ + PyTypeObject* target_type = has_aR ? &TM_SR_ND_AR_Type : &TM_SR_ND_Type; + + /* Create Instance */ + PyObject* arg_tuple = PyTuple_Pack(2, input_obj, features_obj ? features_obj : Py_None); + PyObject* obj = PyObject_CallObject((PyObject*)target_type, arg_tuple); + Py_DECREF(arg_tuple); + + return obj; } /* ========================================================= */ -/* REGISTRATION */ +/* 5. MODULE INIT */ /* ========================================================= */ -static PyMethodDef FastTM_methods[] = { - {"r" ,(PyCFunction)FastTM_r ,METH_NOARGS ,""} - ,{"rn" ,(PyCFunction)FastTM_rn ,METH_VARARGS ,""} - ,{"w" ,(PyCFunction)FastTM_w ,METH_O ,""} - ,{"wn" ,(PyCFunction)FastTM_wn ,METH_VARARGS ,""} - ,{"s" ,(PyCFunction)FastTM_s ,METH_NOARGS ,""} - ,{"sn" ,(PyCFunction)FastTM_sn ,METH_VARARGS ,""} - ,{"ls" ,(PyCFunction)FastTM_ls ,METH_NOARGS ,""} - ,{"lsn" ,(PyCFunction)FastTM_lsn ,METH_VARARGS ,""} - ,{"aL" ,(PyCFunction)FastTM_aL ,METH_O ,""} - ,{"aR" ,(PyCFunction)FastTM_aR ,METH_O ,""} - ,{"d" ,(PyCFunction)FastTM_d ,METH_NOARGS ,""} - ,{"dn" ,(PyCFunction)FastTM_dn ,METH_VARARGS ,""} - ,{"esd" ,(PyCFunction)FastTM_esd ,METH_NOARGS ,""} - ,{"esdn" ,(PyCFunction)FastTM_esdn ,METH_VARARGS ,""} - ,{"e" ,(PyCFunction)FastTM_e ,METH_NOARGS ,""} - ,{"address" ,(PyCFunction)FastTM_address ,METH_NOARGS ,""} - ,{"len" ,(PyCFunction)FastTM_len ,METH_NOARGS ,""} - ,{"rightmost" ,(PyCFunction)FastTM_rightmost ,METH_NOARGS ,""} - ,{"leftmost" ,(PyCFunction)FastTM_leftmost ,METH_NOARGS ,""} - ,{NULL} -}; - -static PyTypeObject FastTMType = { - PyVarObject_HEAD_INIT(NULL ,0) - .tp_name = "TM_module.FastTM" - ,.tp_doc = "Safe Entangled Tape Machine" - ,.tp_basicsize = sizeof(FastTM) - ,.tp_itemsize = 0 - ,.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - ,.tp_new = PyType_GenericNew - ,.tp_init = (initproc)FastTM_init - ,.tp_dealloc = (destructor)FastTM_dealloc - ,.tp_methods = FastTM_methods - ,.tp_weaklistoffset = offsetof(FastTM ,weakreflist) /* CRITICAL FIX */ +static PyMethodDef module_methods[] = { + {"FastTM", (PyCFunction)FastTM_Factory, METH_VARARGS | METH_KEYWORDS, "TM Factory"}, + {NULL, NULL, 0, NULL} }; static PyModuleDef TM_module = { - PyModuleDef_HEAD_INIT - ,"TM_module" - ,"Fast TM Extension" - ,-1 - ,NULL + PyModuleDef_HEAD_INIT, "TM_module", "Fast TM Extension", -1, module_methods }; PyMODINIT_FUNC PyInit_TM_module(void){ PyObject* m_obj; - if( PyType_Ready(&FastTMType) < 0 ) return NULL; + + if( PyType_Ready(&TM_SR_ND_Type) < 0 ) return NULL; + if( PyType_Ready(&TM_SR_ND_AR_Type) < 0 ) return NULL; m_obj = PyModule_Create(&TM_module); if( !m_obj ) return NULL; - Py_INCREF(&FastTMType); - PyModule_AddObject(m_obj ,"FastTM" ,(PyObject*)&FastTMType); + Py_INCREF(&TM_SR_ND_Type); + Py_INCREF(&TM_SR_ND_AR_Type); + + /* We export the Types if user wants to inspect them, + but primarily they use the FastTM factory. */ + PyModule_AddObject(m_obj, "TM_SR_ND", (PyObject*)&TM_SR_ND_Type); + PyModule_AddObject(m_obj, "TM_SR_ND_AR", (PyObject*)&TM_SR_ND_AR_Type); + return m_obj; } diff --git a/developer/authored/TM_module.cpython-311-x86_64-linux-gnu.so b/developer/authored/TM_module.cpython-311-x86_64-linux-gnu.so deleted file mode 100755 index a19ec17b2932d0d11d13775f885e8716311d4092..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44280 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 Val: {t.r()} (Expected: 20)") + + # 2. Try Append (Should FAIL) + print("Attempting aR()...") + try: + t.aR(99) + print("!! FAIL: aR() succeeded on Base Machine") + except AttributeError: + print(">> SUCCESS: Caught expected AttributeError (Feature missing)") + +def test_ar_machine(): + print("\n--- Test 2: Feature Machine (TM_SR_ND_AR) ---") + data = [10, 20, 30] + + # Feature requested + t = TMS(data, features=[Features.APPEND_RIGHT]) + print(f"Created Feature Machine: {t.len()} items.") + + # 1. Step + t.s() + + # 2. Append (Should WORK) + print("Attempting aR(99)...") + try: + t.aR(99) + print(f">> SUCCESS: aR() completed. New Len: {t.len()}") + + # Verify data + print(f"Tape content (from head): {t.rn(5)}") + except AttributeError as e: + print(f"!! FAIL: {e}") + + # 3. Entanglement Check + print("Entangling...") + t2 = t.e() + print("Attempting aR(100) on Clone...") + try: + t2.aR(100) + print(f">> SUCCESS: Clone inherited aR feature. Len: {t2.len()}") + except AttributeError: + print("!! FAIL: Clone lost the feature!") + +if __name__ == "__main__": + test_base_machine() + test_ar_machine() + diff --git a/developer/authored/example_queries.py b/developer/authored/example_queries.py new file mode 100755 index 0000000..3801579 --- /dev/null +++ b/developer/authored/example_queries.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +from SymbolSpace import SymbolSpace +from Binder import Binder +from DiscreteFunction import DiscreteFunction +from Namespace import DifferentiatedSymbol ,OrderedNamespace + +def example_queries(): + print("--- Epimetheus Architecture Example ---") + + # 1. System Initialization + binder = Binder() + graph = DiscreteFunction() + + # 2. Ontology Definition (The Factories) + Frame = DifferentiatedSymbol("FrameMaterial") + Price = OrderedNamespace("Price") + + # 3. Data Ingestion (Transient Objects) + data_source = [ + ("Bike_A" ,"Carbon" ,3500), + ("Bike_B" ,"Steel" ,800), + ("Bike_C" ,"Alum" ,1200), + ("Bike_D" ,"Carbon" ,1500), + ] + + print(f"Ingesting {len(data_source)} items...") + + # Keep references to prevent GC during ingestion for this example + start_objects = [] + + for label, material, cost in data_source: + # A. Create the Python Object + obj = type("Bike", (), {"label": label})() + start_objects.append(obj) + + # B. Bind: Object -> Symbol + sym_bike = binder.get_symbol(obj) + + # C. Describe: Symbol -> Properties + graph.set(sym_bike ,Frame(material)) + graph.set(sym_bike ,Price(cost)) + + # --------------------------------------------------------- + # Example 1: Exact Query ("Find Carbon Frames") + # --------------------------------------------------------- + print("\n[Example 1] Exact Match: Frame('Carbon')") + + # We ask the Factory for the symbol representing 'Carbon' + sym_carbon = Frame("Carbon") + + # We ask the Graph for entities with that symbol + results = graph.find(sym_carbon) + print(f" -> Found {len(results)} bikes with Carbon frames.") + + # --------------------------------------------------------- + # Example 2: Range Query ("Find Price 1000..2000") + # --------------------------------------------------------- + print("\n[Example 2] Range Match: Price(1000..2000)") + + # Step A: Ask Namespace for symbols in range + # The OrderedNamespace uses bisect to find symbols efficiently + price_symbols = Price.find_range(1000 ,2000) + print(f" -> Namespace identified {len(price_symbols)} relevant price points.") + + # Step B: Ask Graph for objects having ANY of those symbols + matches = set() + for p_sym in price_symbols: + found = graph.find(p_sym) + matches.update(found) + + print(f" -> Graph resolved {len(matches)} bikes in price range.") + + # --------------------------------------------------------- + # Example 3: Hierarchy Query ("Find Priced Things") + # --------------------------------------------------------- + print("\n[Example 3] Hierarchy Match: Has Price") + + # We query the Root Symbol of the Price namespace. + # This works because the Graph automatically 'posts' up to the parent. + # FIXED: Changed .root to .root_symbol to match Namespace.py + all_priced = graph.find(Price.root_symbol) + print(f" -> Found {len(all_priced)} objects that have a price.") + +def CLI(): + example_queries() + +if __name__ == "__main__": + CLI() diff --git a/developer/authored_2026-02-09.tar b/developer/authored_2026-02-09.tar new file mode 100644 index 0000000000000000000000000000000000000000..91a53ef4957b710d98875b130912b8a0b2ebd448 GIT binary patch literal 40960 zcmeHQ{d?L-lFrZk6+QTQ*5JVeaGYE`o7@r`C%*Lu2P8AOY#v1hVQT{tD~UMlZ2tFq z-|B8jV6dHxC%1cxCz%+jySlo*x~jUmai_^;7;3tk#oy_hVbu#$zP5giKNcayasXy6y{GisT?L2<`K-KOWk!A4y&G|o! z!m+BhCjQt=cX@h-Yy@EQA+K$Ej(+?-d2X2@8cJ zn(Y;oebYN}#^GQ(@(SMPzBftKkrP!Q*X~tKv zmrN%RNOeB-M+3+EoT%+>KbVZ%zPDK{0~S!LdY}EIR4*3_8|vAef6%yIRV_>+{uv zI%)UbW)BRoUN{Ly;l(Tiw|~^xKc4G(e017scAU=9%U8V&fKul9S-W+be|-A-_&EQ$ z+j@D@I?eU`I#O(?MpgALJ$2&tFa5w%r9-!$gwaejN4^`EzYbcVM{=gZQ$2L!q<8Yw zT-~V}HmIK?cLEnqm3k-Luf;|46CL-|hU$2MJN5=jbf9j)!;~gjW^y!i_x;&%X%Z!^a9MI5Y<^2Fi^t6j~(_kinv!C^uH&B=N(* z9T_;l$qsIDf?8ol)nqLEDA|c+bFw&iqu9HplWi&x9eCLZfNDLdYE2M4@{qE@NlAm| zvi_ns1vJ=D2j0lLa1)R8I|>4D9ipSz6bXOIdn$r8i2^&fY9!i7Mn-{QVc>jnM@w1; zCH=-gyfV$vm<+$(;i_a`*&cQT`}`U{Zig#?GuD~1bQ@n*r(AC&eSN>?E z4x2~EDhxz+GW~5PN#vhT6HknDSxtk)AEol4paYlRT$z$S*49`L2{JGlH3@q znD-!^_uv+gc%ROj5WRR6OunInnpU^KMe7B~?(uD+fEJeLW*oP3YoAWm$0BEmg3roI zGR%`ahNf1%Qn^g~5`>ACaBnSblw*K z?>ySo@&BV*eP_2p|NqJ3wg3M+aN;^h@oa?mNf?gO@L!&&O6zmt1u>k4LP0zBT=lSw zr_W1J=wj-*74fMOhtsGJ@8@0iyxK3mFThO~sO&RI+)`hD^uj`XZpuh!(jz>E8l zFFwn&B7H*Db0?Y0xu0Pn%@HG*=mTSC*mB_O(_TL@6iD?yWn#5|-^96D|Lc!;cC`K@ z|NErI_#gSd#?Ctazi&P)gZFR?>X_p_KJB+936QDRo`iagH8Ov(!!>>TEEvry3jW3R zfv4jZ|C6{HT?t|ky&!f%7;>mXBGrYn-e(Y^9;y@nvmdBtga9(ZL$s|HwjLttgGHZ5) z@BWeF7YLj_tDdg<75r+?&d&b|3OcV^&4b+MEtSAt(qjLl@c{CS*$sP->2n$E%Y>al z+ENqGi<}W!=&tA~&BLMk*>gX3ykUH;s}slm-#sT$^uEl97#CeT?iE5aBOl;>J46}? zf!e~DSAZOOLpv%vdVibxR)*4n(d~=UIf9>rqX>tu+-QJM5F7~mt_08f;dmSdGBL)U zeqVhG{ekI+Z60Zgv;|WQTjIQyNlbrOk`LR@bLglao+)weq)A36XMg0mkwvUjvYgl| zi--6V;C&IYI=>vW_B*XZ@jthpTfUUpqCH!9o6_FC?!9fdwC9Sh6K5EC-jcDt2rXWD zBV<1IK)MTX4@7PSi5pyuys;O6-PfrCRv@a-jUBW}8_&_El1kZ@_STV)a56;mVz{M9 zIR~7Cqd=;0k|e8m`E&i0p(m-e{X7MSe%IR)iV*AQG)Kv_kI?Fij(LcU&ScC3ZOtba(mE`a4rgHaRN zsz67oIgBgmsAcs>RkOr`ycl7!kj-37JeDE7qNQn9`>CKs=I$0~p`|g1Oa;Dbsgt8$ zj!uz(e9>uk-oiR)rQ27B(?CrA5|ao`);0+%3yi4buOb)=WS_ObLT`}}tCF3|esuo@ ztnU6%3@Q+im1s|$x}SVxlDImRWO>UQk5skQnCq4kyVF(93Ws(CZILv?MeU~aIyE+Wn6AX7f_1OtGyMp)7y z97bfYJ!_(2+l`PeWb0DeucC@Uv7-K<(FbiD))0!#rcX6tj`dE<_zI`IT_=77c;R;(sr>c?j)rN|P(XF||n>Hz#&!HQ^(6PE1~oVa~NJz)H4 zn0R|uvtN42QR0o25a&Fc27_2j2qrIL?)Uv={9I)BwIMZjXwImiAHmfVBa~Zo z41gOaYlqhBk6jk6nk`YJ6>5VV_g#6cec3I_v35W)>)UPE8Eu&DQoe4+fU32OBTp;= zoQ(FY3kQ<~bGmR{CG|@0GZp-d)L$tVW{gTY3$udXfr6PSI`I-$VGmHdWEJ(_Q!kp` zv?h6TM7GB1XHQMBzJdaoA4zM0#15Az3XXOA2C6?ouGm;3UrSZDdD2q*+w81LM|9kW z*n}-}Ly3JSSh(Rrigac6CS6~I%(CWS`RRWw)wKo*iL>T`ca>Tv6U^+xLD#?L9jv)o zU=uoB{>+MMJfr#NM$640H`yYa@y!dX&@nRMKSah*G> zp<2nKSn6dgjTvqnCQG$no5H*b2w%h<7SUfA!#WPR74-Qtr*=ZN!VHf@E6nnc6KJgWL2#K$U z+q(Y()VqJ=_(Whow;?MFt?YXC+>dZ}O4w;lT;wXEY=cy6R=Em_h!!2bhKJW;0tMQH zKUbHq&@|1m6(_!;+O)f{(sxt2*uG_dWJ}Fz9G*Lj`>C~>thfbihYtx!06{* z(ofOYf8FU|yMGVSJCq$6nZBW&-M^1ew1ElTl+}^!jFD~zjifyiN30s0lk9~BJkEdq zcr}QPr)upyiaMr=QT}XUv2Rn-gpzlb1|$yttXvc@V)5)BvLd9wu{z{Ij8+OmIoXEP#Lz?(tFu79lwKBjJ0nnGfl7JTXo=ZEyq?bjEP_K8Zy zLqol}tU!uK>iX(=>$HGYa?ZbHw2HaV7PnVvIg$ufF**S%F4$Q#kop9@T5=qP2xz4h zHd~mQb`+31L{EqF1NGg2A=x?9o=D|FrZi~E=93dbBRj|uaNOIZg=)E6I?&xLa%sAO zb{nqEWjMfo4vGqdKJ+B!0zZz6NDAIK0`oJqIf^%tSivuYO{qMZA*7OMQ|}$qtmX|= zd!~mtKo-gvDi*kggZSNhh!jcsYcYb;2>S2a3`JRo_ORwBt==ny<;~8^E{sX>OGUS5 zq`a&{V0yf1BKI-ZbKFjYddcwhYyU*v}bSJ$SeZP zw!;b^^-2U%L23j-Qbm3?z~&~}XWN^mpbZ$(P<%!z1N#MVpY>WU@{ejRZ4?M#5cb($ zJ2&|)&)oW4E>b4h`rM8EKAlnY;XmQftS@ETf>F3>P_xg5BljXk53XA6!{g@5F0zV; z&DY00^^g3+7tL;quD|UECt7-uD9%d{zK`EW9@M_3H-PuBseXdGwSL(sA3xhRCil)} z*y1(SZe`=xn3uM#QChT}*JAsgDbNv&csLx=U3!L034cjxpmV4QjM=Cxj0O)*q(~Ke z5aCo zc;zRTX>#9G8>0y}^}vUW%uaJK&}vo^ybN)BCtAz(tF7`PMrNroH2bpN_g}W-JO3=* z|L^o1^1(rHFm@9MUV|4`lh4U~^Kbfe^Zq~120VG3*8l82;{N|my|F(3^G&q=+D?V7 ztxgZVDl`z=sNlTyWVv6sx3yKkcK6nneua;!je_KOf&>s18wcjphmxx*=j9Jo)i5vo zV1T~W0``Trwp!S;51D9+*}E$}C-4K9;XXS(eydkMECV=#IG&CYe|y9ec!*MMKUMOo z7uAaTKr>Zx5h;9NWwU%7Vs8nRj^z(JFD}nqd_(|_%)!>ysXN9%9Qgx^t^4k1A3^H} z8IyK1eyHstvi2Y105QGOPv2XoFn)+7Kdu%Y5ni(&g~4nrb2)k4?a{IByAwY_(*5sP z)M4-D09n*idkaKA{8#tv)Ir)T_9A}VKR$9e4P9aAik91aFD)qgo?QH?LZR)Fr% zp89{o`JY+?XFhrUv-YUAvjfFv{a8T5Pgi?)e-8_A+xlPI-AVO-m-WAmS_A*A&;NccGrys|J4v=LpzqTO4*Pfo z`_V{)JrB5zWASTm`WwjmPv0fgfA6!)svAb5wR=7Ze9QX3i(4VA{y%=Q%k%&BdVRhA ze;3(VSpUr`eeL`&4;ku<0q|SJ9%m^Ou=Hcs zRcYYw4*ovE-`(1KfJnwp4R3oV`T(R(9a+f3qE4b9dwn9#(4P7=h51E>&?pRxNMi7K z6B-a=)nq?QB>=Y_Ra)V89_$wPb1m!=PqWl6>6SVaSOG^iQ0uAsQ6G!@U zPu0z&1(G0-EEyrNG_sC^hnsaB#7414@sG5`??9{k*>Ye1}yN18ihK5NZ{LnKmkFM^2_?^FPLsI6E2- zQRdK=GnFf+zmuQ-i|Od2mI76}3J3&#yWx@S=wJsL5k3R-&#IwV@S*@f+UcsLcRM>3 z_2|)ik_oJju2{;A`7Ru+hh zdawrNC2eRqZE;H#03m);7kr~;Qzr3kRs+4zTZ>5%hGXY_4sJFTU8SpJj~t1J4(Bd{ zhI5^dg^E_v^aIim`fJtSs$F!H}$c{0}phbG|M9||sx5Praitz~84& zVGcy=Dry&>AIloFAvDn}23~?1P9dw3fc4a=hXXk0$b*68FsFDg^svX8EfM51+i*;- zh(;c;@H~B5g-I1vldht7mhwdI>C^W)Db0qq(*V?LV11g}V2wy}ro|KcFPDD*l9J3V zuBT6dsKpIkh?xPmgh|>W%hZt=+ec{{vxaG91~ZgeS?-5tyYKB7R?KxZoLSRw&N@Xt z^#MRR-AK++l8za>kz4eKGvP}`7ya^gX>QrYC24Mr5>Du+0?5+JcI4d!nos+^-bc@5z;#5`z}uS|KT9Z z;=lU$jsG6;vOkmmeca&vfQbKU^>zN|dx*t1#D6zNeXYTTr?|_)y@)KOP=~3Xi~3ro ztXYnwz4615Ie61`haQWkSY3CY#vM!Fsv+Ar>&T-NZ+x6n8mCKMQr9uyyUpgNs%*aC z|MoY<<4qcLUhBMi1FnaKJCNmr*Vf?AhU)SPD_YYHG?j&1l>kal3J}KduTerBqM)_} z=zN|us^$U}Yxgw}0Ql3d7%y|gDrk#Gjoc%<@aV3^rX0H36Eu0(i8uj~uZJAaCCuLsN67BL z^}kQvBYa#KPR8Q1RBKXZYnwoI&Y6gL#)IdG)nR+2teiGtA!1&|?+o^WsnF0Yp9B|e z5n`GIoc1%pMY$@U^I@nFN}!v63MJ$8{!=vWEec0CAMyDU?DESwk-mq`z;lltydGXAI;W!@e;aroRA}YQtEbej5-S}zl^yJ}_D(<=X zL<{-_Za#iRZI*}HSL|_UF!Z{yJTn8Mi&kTreSrvP-a#oi$Co31xH)S!R+W&~N}`RN z4&f7?-$3pQ&XafaASBsrxIy9iG5iqS!d0PUb`NI)`-Bjce;d&1w$pqhNR zs}{#)F9Ia-VCs1tKF*G)*HR;Z1(y2}nilp=% zAHwO3-W|D}RG+2=gD5NLibxF9kK?fK!zmc(x~qi82*E6`Z&T7pMOTH&v!7|ehiW6=eUZ4{h z0mL`~^ygK^_&nhKHH!q$cZLqDBrPF;Q3e!dk^+KLr*|vntPEgUw+SAQRKQ--9Jq+w zCmIZ^T3QT^$|lPTp@1mV=RHgd%m^}=<6Yn?X6zv^0j6hs9o+m*{=85W3U~0(zRPO0 z9^}3$kotdlg}LXi0J+Wo+r?%7_WNJ7{|CGOWS#%LZ(c8hca#6uM|K1j2c|x~7j(c2 zGvw^r(cxKo`F*x<&U;{EH*hbQTt!3g{&iSZI!jz=vVyWD^ER&`&u+h;h=P->!Pen4|RyKi>^ZVZ0E4Y8>@e*;~eNR8jy(?Ww1JtT`tyoAxUtKIhwF zXjQ>&s;Dch7|&KSLFTNV#P6g5gGT*e1=w8tlYuo7l|$c}SBW_UGNwUA)DC1moFqZwONqeyxA!-^^tQt^Y=~TpuU`Wu=@}ulhK{w zH0l`HqlLP3d`A|iimM3Z7jZx(ZGuOOlfp|ePRK%?1&Mr{6Sf}_(*q_lCvtg}{>mii z8g0^Hq;HK_HtkYT-rCI}F_>-KyFgcXkszg_ywPj(2Jg>0z_$}&G8ZtDdg#c-mHy0h zp6M(ThnLMDed!N?zQYrxO2rpGj>I;Ls#4r{qw_GpZ#%oSnp`ZAzJI~@sF(IeMcn@X zAB(T|`MNopj`3Di>W#(s2Xo--7W{kC&!$TZ_EljS8ir0 z;p*v3aSqfzOJn&R4Cg3UH5$l>NhgFMxB^mCAWet~@QTQ5$dPe1d%Y! zM#-ut=`3W(L4V1_uD~X!gatry2}g2?0us%5biqhCe9tghb1BU}>X8W8DkCN8kT=d?1Ru+AL(;>BG;GKz3vd!H@@?V0#xBnIV_nE@1dN2Nc}Jg~Q$_ z7ba9*;67%ga5C1)gkR_hXA%e7BnA}qT@>Qx>06x&!UafnD!>P30&X>Bk6CqMNJ7b` z6v;G)h_?!#yRCG3#TPKbTT zt~O03pC`@dQ+ONtrpqhrH9>g2zRRm;*2sm5m zn3TD|4J7$~Vcp<9@@^O4P!->TD2gDz7-?re;aa9;2wcz|@Ugjs+2DJ?@+M7C&O=yK zh@551U_c_QD2v&YdPVMxQqQRKb5WpY%3e(*MOSdWe{%1E%NpRC0&5DaDX^x%ngVMI ztSPXjz?uSU3alxxrofs4YYMC>u%^J80&5DaDX^x%ngVMItSPXjz?uSU3alxxrofs4 OYYMC>u%>`e;C}(nfX83} literal 0 HcmV?d00001 diff --git a/document/TM.html b/document/TM.html index abeead4..ebe8d5b 100644 --- a/document/TM.html +++ b/document/TM.html @@ -51,27 +51,27 @@

- If an operation were permitted to remove the last remaining cell, said first order invariant would be broken and the interface would stop being total. A working TM that supported such a deletion would need status logic that represents the empty state. That status logic would either be embedded inside the TM operations as edge handling, or be represented explicitly as a separate status machine layered above the base TM. Either choice represents a shift in level of analysis being done, and therefore would lead to the construction of a distinct second order tape machine. + If an operation were permitted to remove the last remaining cell of a tape, said first order invariant would be broken and the interface would stop being total. A working TM that supported such a deletion would need status logic that represents the empty state. That status logic would either be embedded inside the TM operations as edge handling, or be represented explicitly as a separate status machine layered above the base TM. Either choice represents a shift in level of analysis being done, and therefore would lead to the construction of a distinct second order tape machine.

- Tape machines that share a tape are said to be entangled. There will be both data and control hazards among entangled machines. Data hazards have to do with one machine writing data being read by another, either unexpectedly, or in the wrong temporal order. Data hazards can lead to incorrectly computed results, but they will not break the machines. In contrast, control hazards lead to broken machines. The principle control hazard is that of one entangled TM deleting a cell that another TM is visiting. That orphans the head of that other machine and leads to a violation of the a tape machine head is always on a valid cell. We leave the data hazard management to the programmer; however, we provide specific features for preventing control hazards. + Tape machines that share a tape are said to be entangled. There will be both data and structure hazards among entangled machines. Data hazards have to do with the misuse of locks or other mistakes in cooperation between machines that cause a machine to read the wrong data. Data hazards can lead to incorrectly computed results, but they will not break the machines. In contrast, structure hazards lead to broken machines. The principle structure hazard is that of one entangled TM deleting a cell that another TM has its head on. That orphans the head of that other machine and leads to a violation of the a tape machine head is always on a valid cell invariant.

- TM machines incorporate various approaches for managing entanglement and avoiding control hazards. These are chosen as features at construction time. In one approach, no methods are placed on the interface that can destroy tape cells. This supports a non-destructive programming paradigm, so such machines are said to be non-destructive. Without destructive operations, entangled machines simply do not have the ability to break each other. In a second approach, the interface is configured so there are no functions for entangling machines in the first place. Each solitary machine can safely perform destructive operations because no other machine shares its tape. As a third approach, each group of entangled machines shares a catalog listing all machines in the group. Caller code can guard operations by querying whether a planned operation is safe before attempting it. This third strategy is called entanglement accounting. During the time of execution of the guard and operation, each tape machine must be able to lockout others from access to the catalog. Yet another approach is for the programmer, compiler, or external function to prove code is safe, which is the same as proving that guard code is not needed. + We leave the data hazard management to the programmer; however, we provide specific features for avoiding structure hazards. + These are selected at TM construction time. In one approach, no methods are placed on the interface that can destroy tape cells. This supports a non-destructive programming paradigm, so such machines are said to be non-destructive. Without destructive operations, entangled machines simply do not have the ability to break each other. In a second approach, the interface is configured so there are no functions for entangling machines in the first place. Each solitary machine can safely perform destructive operations because no other machine shares its tape. As a third approach, each group of entangled machines shares a catalog listing all machines in the group. Caller code can guard operations by querying whether a planned operation is safe before attempting it. This third strategy is called entanglement accounting. During the time of execution of the guard and operation, each tape machine must be able to lockout others from access to the catalog. Yet another approach is for the programmer, compiler, or external function to prove code is safe, which is the same as proving that guard code is not needed. An alternative is to use a compiler that only produces correct code in the first place. This is the approach of correct by construction.

Command language

- The command language is not used directly. It describes the letter patterns used to form TM interface function names. - This approach began with LISP, and its extension is described in the paper "Towards a Better Understanding of CAR, CDR, CADR and the Others". + The command language is not used directly, rather it describes the letter patterns used to form TM interface function names. + Such an approach can be found in LISP language list access function names, and its extension is described in the paper "Towards a Better Understanding of CAR, CDR, CADR and the Others".

- The actual function names found on TM interfaces are listed in later sections of this guide. Reading the source code can also help. - Later we can add a compiler for creating new functions based on this language. Such a compiler would be a function that adds functions to a TM interface. + The actual function names found on TM interfaces are listed in later sections of this guide. The ultimate authority is the source code itself. Later we can add a compiler for creating new functions based on this language. Such a compiler would be a function that adds functions to a TM interface.

@@ -119,7 +119,7 @@

The query command, q, reports head state. With no arg descriptor it returns a boolean value. - With an R arg descriptor it returns true iff the head is on the rightmost cell. + With an R arg descriptor it returns true iff the head is on the rightmost cell. With an I arg descriptor it returns an index.

@@ -221,8 +221,7 @@

Examples

- The example descriptions state effects in the base view. - Effects in the mirror view match the same command without the L prefix. + In these examples, the comments discuss what happens on the base machine. Effects in the mirror view match the same command without the L prefix.

Relative head movement

@@ -243,7 +242,6 @@ LsI(k) and sI(k) cue the head to the same indexed cell. L flips direction and the meaning of R, not the index to cell correspondence. Thus LsI(0) cues the cell with index zero, which is rightmost in the mirror view and leftmost in the base view. - For that reason there is no primitive family for LsI distinct from sI.

Absolute head movement

@@ -266,7 +264,7 @@

- In q, the I arg descriptor selects an index valued result. + The I arg descriptor causes q to return an index. By default q returns a boolean value. In other commands, an I arg descriptor indicates that an index argument is supplied.

@@ -370,7 +368,7 @@

Query primitives

- Query primitives expose the q command. + Query primitives are built from the q command. On the step right only machine, the primitive set covers the boolean query forms. When indexing is enabled as an additional feature, index valued query forms become available.

@@ -381,27 +379,24 @@

If indexing is enabled, the API also exposes index query primitives. - These correspond to the A arg descriptor in the command language. - (If you later rename A to I, this section becomes qI and qIR accordingly.) + These correspond to the I arg descriptor in the command language.

    -
  • qA() returns the current head index. (Command form: qA.)
  • -
  • qAR() returns the index of the selected view rightmost cell. (Command form: qAR.)
  • +
  • qI() returns the current head index. (Command form: qI.)
  • +
  • qIR() returns the index of the selected view rightmost cell. (Command form: qIR.)

Mirror view query forms follow the same rule in the command language. - For example, LqR tests the leftmost of the underlying tape, and LqAR returns its index, typically zero. - In the API, that effect is obtained either by left primitives (for LqR this is lsqR() if such a helper exists), or by explicit equivalences such as “leftmost test” implemented via the leftmost cue or by comparing to a known bound head. - The primitive set stays small, and higher level forms live in friend or workspace layers. + For example, LqR tests the leftmost of the underlying tape, and LqIR returns its index, typically zero.

Entanglement primitives

Entanglement primitives implement the e command. - The entangled machine shares the tape with the original and starts on the same cell. + The entangled machine shares the tape with the original machine and and initially have their head on the same cell. In entanglement accounting configurations, entangled machines also share the group catalog used by guard predicates.

@@ -429,8 +424,7 @@

- In order to maintain these properties, a TM uses inclusive bounds for intervals. - An interval is marked by placing a head on the leftmost cell of the interval, and placing an entangled head on the rightmost cell of the interval. + In order to maintain these properties, a TM uses inclusive bounds for intervals, including intervals of cells, and intervals of indexes.

Contract with the programmer

@@ -447,8 +441,8 @@

    -
  1. When there is a right bound, the caller guarantees they will never command the machine to step beyond the rightmost cell.
  2. -
  3. When there is a left bound, the caller guarantees they will never command the machine to step left of the leftmost cell.
  4. +
  5. When there is a right bound, the caller guarantees that he will never command the machine to step beyond the rightmost cell.
  6. +
  7. When there is a left bound, the caller guarantees that he will never command the machine to step left of the leftmost cell.

-- 2.20.1