lqft-python-engine 0.3.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.3.0
4
- Summary: LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)
3
+ Version: 0.5.0
4
+ Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
@@ -11,28 +11,27 @@
11
11
  #include <stdint.h>
12
12
 
13
13
  /**
14
- * LQFT C-Engine - V5.0 (Active ARC Deletion & Full CRUD)
14
+ * LQFT C-Engine - V0.5.0 (Native Disk Persistence)
15
15
  * Architect: Parjad Minooei
16
16
  * * CHANGE LOG:
17
- * - Implemented Automatic Reference Counting (ARC).
18
- * - Added cascading `decref` for immediate RAM reclamation on deletion.
19
- * - Added Open-Addressing Tombstones to the Global Registry.
20
- * - Resolved all GCC -Wsign-compare warnings for production-grade builds.
17
+ * - Implemented Binary Serialization (save_to_disk).
18
+ * - Implemented O(1) Cold Start Deserialization (load_from_disk).
19
+ * - DAG Pointer Reconstruction Logic.
21
20
  */
22
21
 
23
22
  #define BIT_PARTITION 5
24
23
  #define MAX_BITS 64
25
24
  #define MASK 0x1F
26
25
  #define REGISTRY_SIZE 8000009
27
- #define TOMBSTONE ((LQFTNode*)1) // Special pointer for freed registry slots
26
+ #define TOMBSTONE ((LQFTNode*)1)
28
27
 
29
28
  typedef struct LQFTNode {
30
29
  void* value;
31
30
  uint64_t key_hash;
32
31
  struct LQFTNode* children[32];
33
32
  char struct_hash[17];
34
- uint64_t full_hash_val; // Cached for O(1) registry removal
35
- int ref_count; // Tracks active branch dependencies
33
+ uint64_t full_hash_val;
34
+ int ref_count;
36
35
  } LQFTNode;
37
36
 
38
37
  static LQFTNode** registry = NULL;
@@ -43,7 +42,7 @@ const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
43
42
  const uint64_t FNV_PRIME = 1099511628211ULL;
44
43
 
45
44
  // -------------------------------------------------------------------
46
- // Core Hashing & Memory Utilities
45
+ // Utilities
47
46
  // -------------------------------------------------------------------
48
47
  uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
49
48
  const uint8_t* p = (const uint8_t*)data;
@@ -77,32 +76,23 @@ LQFTNode* create_node(void* value, uint64_t key_hash) {
77
76
  node->value = value;
78
77
  node->key_hash = key_hash;
79
78
  node->full_hash_val = 0;
80
- node->ref_count = 0; // Starts at 0 until adopted by a parent
79
+ node->ref_count = 0;
81
80
  for (int i = 0; i < 32; i++) node->children[i] = NULL;
82
81
  return node;
83
82
  }
84
83
 
85
84
  // -------------------------------------------------------------------
86
- // Active ARC Deletion Logic
85
+ // Memory Management (ARC)
87
86
  // -------------------------------------------------------------------
88
87
  void decref(LQFTNode* node) {
89
88
  if (!node) return;
90
-
91
89
  node->ref_count--;
92
-
93
- // If no branches point to this node anymore, obliterate it.
94
90
  if (node->ref_count <= 0) {
95
- // 1. Cascade destruction to children
96
91
  for (int i = 0; i < 32; i++) {
97
- if (node->children[i]) {
98
- decref(node->children[i]);
99
- }
92
+ if (node->children[i]) decref(node->children[i]);
100
93
  }
101
-
102
- // 2. Remove from global registry (Replace with Tombstone)
103
94
  uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
104
95
  uint32_t start_idx = idx;
105
-
106
96
  while (registry[idx] != NULL) {
107
97
  if (registry[idx] == node) {
108
98
  registry[idx] = TOMBSTONE;
@@ -111,16 +101,171 @@ void decref(LQFTNode* node) {
111
101
  idx = (idx + 1) % REGISTRY_SIZE;
112
102
  if (idx == start_idx) break;
113
103
  }
114
-
115
- // 3. Physically free memory back to the OS
116
104
  if (node->value) free(node->value);
117
105
  free(node);
118
106
  physical_node_count--;
119
107
  }
120
108
  }
121
109
 
110
+ static PyObject* method_free_all(PyObject* self, PyObject* args) {
111
+ if (registry != NULL) {
112
+ for (int i = 0; i < REGISTRY_SIZE; i++) {
113
+ if (registry[i] != NULL && registry[i] != TOMBSTONE) {
114
+ if (registry[i]->value) free(registry[i]->value);
115
+ free(registry[i]);
116
+ }
117
+ registry[i] = NULL;
118
+ }
119
+ free(registry);
120
+ registry = NULL;
121
+ }
122
+ physical_node_count = 0;
123
+ global_root = NULL;
124
+ Py_RETURN_NONE;
125
+ }
126
+
127
+ // -------------------------------------------------------------------
128
+ // Disk Persistence (Binary Serialization)
129
+ // -------------------------------------------------------------------
130
+ static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
131
+ const char* filepath;
132
+ if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
133
+ if (!registry) Py_RETURN_NONE;
134
+
135
+ FILE* fp = fopen(filepath, "wb");
136
+ if (!fp) return PyErr_SetFromErrno(PyExc_IOError);
137
+
138
+ // Header: Magic Bytes, Count, Global Root Hash
139
+ char magic[4] = "LQFT";
140
+ fwrite(magic, 1, 4, fp);
141
+ fwrite(&physical_node_count, sizeof(int), 1, fp);
142
+ uint64_t root_hash = global_root ? global_root->full_hash_val : 0;
143
+ fwrite(&root_hash, sizeof(uint64_t), 1, fp);
144
+
145
+ // Dump Nodes
146
+ for (int i = 0; i < REGISTRY_SIZE; i++) {
147
+ LQFTNode* node = registry[i];
148
+ if (node != NULL && node != TOMBSTONE) {
149
+ fwrite(&node->full_hash_val, sizeof(uint64_t), 1, fp);
150
+ fwrite(&node->key_hash, sizeof(uint64_t), 1, fp);
151
+ fwrite(node->struct_hash, 1, 17, fp);
152
+ fwrite(&node->ref_count, sizeof(int), 1, fp);
153
+
154
+ // Payload
155
+ int has_val = (node->value != NULL) ? 1 : 0;
156
+ fwrite(&has_val, sizeof(int), 1, fp);
157
+ if (has_val) {
158
+ int v_len = (int)strlen((char*)node->value);
159
+ fwrite(&v_len, sizeof(int), 1, fp);
160
+ fwrite(node->value, 1, v_len, fp);
161
+ }
162
+
163
+ // Children pointers (saved as full_hash_val references)
164
+ uint64_t child_refs[32] = {0};
165
+ for (int c = 0; c < 32; c++) {
166
+ if (node->children[c]) child_refs[c] = node->children[c]->full_hash_val;
167
+ }
168
+ fwrite(child_refs, sizeof(uint64_t), 32, fp);
169
+ }
170
+ }
171
+
172
+ fclose(fp);
173
+ Py_RETURN_TRUE;
174
+ }
175
+
176
+ LQFTNode* find_in_registry(uint64_t full_hash) {
177
+ if (full_hash == 0) return NULL;
178
+ uint32_t idx = full_hash % REGISTRY_SIZE;
179
+ uint32_t start_idx = idx;
180
+ while (registry[idx] != NULL) {
181
+ if (registry[idx] != TOMBSTONE && registry[idx]->full_hash_val == full_hash) {
182
+ return registry[idx];
183
+ }
184
+ idx = (idx + 1) % REGISTRY_SIZE;
185
+ if (idx == start_idx) break;
186
+ }
187
+ return NULL;
188
+ }
189
+
190
+ static PyObject* method_load_from_disk(PyObject* self, PyObject* args) {
191
+ const char* filepath;
192
+ if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
193
+
194
+ FILE* fp = fopen(filepath, "rb");
195
+ if (!fp) return PyErr_SetFromErrno(PyExc_IOError);
196
+
197
+ char magic[5] = {0};
198
+ fread(magic, 1, 4, fp);
199
+ if (strcmp(magic, "LQFT") != 0) {
200
+ fclose(fp);
201
+ PyErr_SetString(PyExc_ValueError, "Invalid LQFT binary file format.");
202
+ return NULL;
203
+ }
204
+
205
+ // Clear current state safely
206
+ method_free_all(self, NULL);
207
+ init_registry();
208
+
209
+ int total_nodes;
210
+ uint64_t root_hash;
211
+ fread(&total_nodes, sizeof(int), 1, fp);
212
+ fread(&root_hash, sizeof(uint64_t), 1, fp);
213
+
214
+ // Parallel array to store child hashes for Pass 2 (Pointer Reconstruction)
215
+ uint64_t* all_child_refs = (uint64_t*)malloc(total_nodes * 32 * sizeof(uint64_t));
216
+ LQFTNode** loaded_nodes = (LQFTNode**)malloc(total_nodes * sizeof(LQFTNode*));
217
+
218
+ // PASS 1: Read physical nodes into memory
219
+ for (int i = 0; i < total_nodes; i++) {
220
+ LQFTNode* node = create_node(NULL, 0);
221
+ fread(&node->full_hash_val, sizeof(uint64_t), 1, fp);
222
+ fread(&node->key_hash, sizeof(uint64_t), 1, fp);
223
+ fread(node->struct_hash, 1, 17, fp);
224
+ fread(&node->ref_count, sizeof(int), 1, fp);
225
+
226
+ int has_val;
227
+ fread(&has_val, sizeof(int), 1, fp);
228
+ if (has_val) {
229
+ int v_len;
230
+ fread(&v_len, sizeof(int), 1, fp);
231
+ char* val_str = (char*)malloc(v_len + 1);
232
+ fread(val_str, 1, v_len, fp);
233
+ val_str[v_len] = '\0';
234
+ node->value = val_str;
235
+ }
236
+
237
+ fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
238
+
239
+ // Insert directly into registry
240
+ uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
241
+ while (registry[idx] != NULL) idx = (idx + 1) % REGISTRY_SIZE;
242
+ registry[idx] = node;
243
+
244
+ loaded_nodes[i] = node;
245
+ physical_node_count++;
246
+ }
247
+
248
+ // PASS 2: Pointer Reconstruction (Relinking the DAG)
249
+ for (int i = 0; i < total_nodes; i++) {
250
+ for (int c = 0; c < 32; c++) {
251
+ uint64_t target_hash = all_child_refs[i * 32 + c];
252
+ if (target_hash != 0) {
253
+ loaded_nodes[i]->children[c] = find_in_registry(target_hash);
254
+ }
255
+ }
256
+ }
257
+
258
+ global_root = find_in_registry(root_hash);
259
+
260
+ free(all_child_refs);
261
+ free(loaded_nodes);
262
+ fclose(fp);
263
+
264
+ Py_RETURN_TRUE;
265
+ }
266
+
122
267
  // -------------------------------------------------------------------
123
- // Merkle-DAG Deduplication
268
+ // Merkle-DAG Core (Standard Operations)
124
269
  // -------------------------------------------------------------------
125
270
  LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
126
271
  if (!init_registry()) return NULL;
@@ -148,26 +293,23 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
148
293
  uint32_t start_idx = idx;
149
294
  int first_tombstone = -1;
150
295
 
151
- // Search registry (Skipping Tomestones)
152
296
  while (registry[idx] != NULL) {
153
297
  if (registry[idx] == TOMBSTONE) {
154
298
  if (first_tombstone == -1) first_tombstone = (int)idx;
155
299
  } else if (registry[idx]->full_hash_val == full_hash && strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
156
- if (value) free(value); // Free duplicate string payload
300
+ if (value) free(value);
157
301
  return registry[idx];
158
302
  }
159
303
  idx = (idx + 1) % REGISTRY_SIZE;
160
304
  if (idx == start_idx) break;
161
305
  }
162
306
 
163
- // Create a physical new node if identity doesn't exist
164
307
  LQFTNode* new_node = create_node(value, key_hash);
165
308
  if (!new_node) return NULL;
166
309
 
167
310
  if (children) {
168
311
  for (int i = 0; i < 32; i++) {
169
312
  new_node->children[i] = children[i];
170
- // Anchor the child to this new parent
171
313
  if (children[i]) children[i]->ref_count++;
172
314
  }
173
315
  }
@@ -175,8 +317,6 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
175
317
  strcpy(new_node->struct_hash, lookup_hash);
176
318
  new_node->full_hash_val = full_hash;
177
319
 
178
- // Insert into registry (Reusing tombstones if possible)
179
- // SYSTEM FIX: Explicitly cast first_tombstone to uint32_t to match idx
180
320
  uint32_t insert_idx = (first_tombstone != -1) ? (uint32_t)first_tombstone : idx;
181
321
  registry[insert_idx] = new_node;
182
322
  physical_node_count++;
@@ -184,62 +324,6 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
184
324
  return new_node;
185
325
  }
186
326
 
187
- // -------------------------------------------------------------------
188
- // Python Wrapper API
189
- // -------------------------------------------------------------------
190
- static PyObject* method_delete(PyObject* self, PyObject* args) {
191
- unsigned long long h;
192
- if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
193
- if (!global_root) Py_RETURN_NONE;
194
-
195
- LQFTNode* path_nodes[20];
196
- uint32_t path_segs[20];
197
- int path_len = 0;
198
- LQFTNode* curr = global_root;
199
- int bit_depth = 0;
200
-
201
- while (curr != NULL && curr->value == NULL) {
202
- uint32_t segment = (h >> bit_depth) & MASK;
203
- path_nodes[path_len] = curr;
204
- path_segs[path_len] = segment;
205
- path_len++;
206
- curr = curr->children[segment];
207
- bit_depth += BIT_PARTITION;
208
- }
209
-
210
- // Key not found, abort
211
- if (curr == NULL || curr->key_hash != h) Py_RETURN_NONE;
212
-
213
- LQFTNode* old_root = global_root;
214
- LQFTNode* new_sub_node = NULL;
215
-
216
- for (int i = path_len - 1; i >= 0; i--) {
217
- LQFTNode* p_node = path_nodes[i];
218
- uint32_t segment = path_segs[i];
219
- LQFTNode* new_children[32];
220
- int has_other_children = 0;
221
-
222
- // SYSTEM FIX: Use uint32_t for j to safely compare with segment
223
- for (uint32_t j = 0; j < 32; j++) {
224
- if (j == segment) new_children[j] = new_sub_node;
225
- else {
226
- new_children[j] = p_node->children[j];
227
- if (new_children[j]) has_other_children = 1;
228
- }
229
- }
230
-
231
- if (!has_other_children && i > 0) new_sub_node = NULL;
232
- else new_sub_node = get_canonical(NULL, 0, new_children);
233
- }
234
-
235
- // Anchor new root and release the old one
236
- global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
237
- if (global_root) global_root->ref_count++;
238
- if (old_root) decref(old_root); // Trigger Active Deletion Cascade
239
-
240
- Py_RETURN_NONE;
241
- }
242
-
243
327
  static PyObject* method_insert(PyObject* self, PyObject* args) {
244
328
  unsigned long long h;
245
329
  char* val_str;
@@ -313,10 +397,9 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
313
397
  }
314
398
  }
315
399
 
316
- // Anchor new root and release the old one
317
400
  global_root = new_sub_node;
318
401
  global_root->ref_count++;
319
- if (old_root) decref(old_root); // Trigger Active Deletion Cascade
402
+ if (old_root) decref(old_root);
320
403
 
321
404
  Py_RETURN_NONE;
322
405
  }
@@ -338,20 +421,53 @@ static PyObject* method_search(PyObject* self, PyObject* args) {
338
421
  Py_RETURN_NONE;
339
422
  }
340
423
 
341
- static PyObject* method_free_all(PyObject* self, PyObject* args) {
342
- if (registry != NULL) {
343
- for (int i = 0; i < REGISTRY_SIZE; i++) {
344
- if (registry[i] != NULL && registry[i] != TOMBSTONE) {
345
- if (registry[i]->value) free(registry[i]->value);
346
- free(registry[i]);
424
+ static PyObject* method_delete(PyObject* self, PyObject* args) {
425
+ unsigned long long h;
426
+ if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
427
+ if (!global_root) Py_RETURN_NONE;
428
+
429
+ LQFTNode* path_nodes[20];
430
+ uint32_t path_segs[20];
431
+ int path_len = 0;
432
+ LQFTNode* curr = global_root;
433
+ int bit_depth = 0;
434
+
435
+ while (curr != NULL && curr->value == NULL) {
436
+ uint32_t segment = (h >> bit_depth) & MASK;
437
+ path_nodes[path_len] = curr;
438
+ path_segs[path_len] = segment;
439
+ path_len++;
440
+ curr = curr->children[segment];
441
+ bit_depth += BIT_PARTITION;
442
+ }
443
+
444
+ if (curr == NULL || curr->key_hash != h) Py_RETURN_NONE;
445
+
446
+ LQFTNode* old_root = global_root;
447
+ LQFTNode* new_sub_node = NULL;
448
+
449
+ for (int i = path_len - 1; i >= 0; i--) {
450
+ LQFTNode* p_node = path_nodes[i];
451
+ uint32_t segment = path_segs[i];
452
+ LQFTNode* new_children[32];
453
+ int has_other_children = 0;
454
+
455
+ for (uint32_t j = 0; j < 32; j++) {
456
+ if (j == segment) new_children[j] = new_sub_node;
457
+ else {
458
+ new_children[j] = p_node->children[j];
459
+ if (new_children[j]) has_other_children = 1;
347
460
  }
348
- registry[i] = NULL;
349
461
  }
350
- free(registry);
351
- registry = NULL;
462
+
463
+ if (!has_other_children && i > 0) new_sub_node = NULL;
464
+ else new_sub_node = get_canonical(NULL, 0, new_children);
352
465
  }
353
- physical_node_count = 0;
354
- global_root = NULL;
466
+
467
+ global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
468
+ if (global_root) global_root->ref_count++;
469
+ if (old_root) decref(old_root);
470
+
355
471
  Py_RETURN_NONE;
356
472
  }
357
473
 
@@ -361,13 +477,14 @@ static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
361
477
 
362
478
  static PyMethodDef LQFTMethods[] = {
363
479
  {"insert", method_insert, METH_VARARGS, "Insert key-value"},
364
- {"delete", method_delete, METH_VARARGS, "Active ARC Delete key"},
480
+ {"delete", method_delete, METH_VARARGS, "Delete key"},
365
481
  {"search", method_search, METH_VARARGS, "Search key"},
366
- {"get_metrics", method_get_metrics, METH_VARARGS, "Get engine stats"},
482
+ {"save_to_disk", method_save_to_disk, METH_VARARGS, "Serialize to .bin"},
483
+ {"load_from_disk", method_load_from_disk, METH_VARARGS, "Deserialize from .bin"},
484
+ {"get_metrics", method_get_metrics, METH_VARARGS, "Get stats"},
367
485
  {"free_all", method_free_all, METH_VARARGS, "Total memory wipe"},
368
486
  {NULL, NULL, 0, NULL}
369
487
  };
370
488
 
371
489
  static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
372
-
373
490
  PyMODINIT_FUNC PyInit_lqft_c_engine(void) { return PyModule_Create(&lqftmodule); }
@@ -2,6 +2,7 @@ import hashlib
2
2
  import weakref
3
3
  import psutil
4
4
  import os
5
+ import json
5
6
 
6
7
  # ---------------------------------------------------------
7
8
  # LEGACY PURE PYTHON LQFT (For reference/fallback)
@@ -104,9 +105,8 @@ class LQFT:
104
105
  if bit_depth >= self.max_bits: break
105
106
  return None
106
107
 
107
-
108
108
  # ---------------------------------------------------------
109
- # ADAPTIVE ENTERPRISE ENGINE (v0.3.0)
109
+ # ADAPTIVE ENTERPRISE ENGINE (v0.5.0 - Disk Persistence)
110
110
  # ---------------------------------------------------------
111
111
  try:
112
112
  import lqft_c_engine
@@ -115,62 +115,74 @@ except ImportError:
115
115
  C_ENGINE_READY = False
116
116
 
117
117
  class AdaptiveLQFT:
118
- """
119
- A polymorphic, heuristic-driven data structure wrapper.
120
- - Scale < threshold: Acts as an ultra-lightweight C-Hash (Python Dict).
121
- - Scale > threshold: Automatically migrates to the Native C-Engine LQFT
122
- for Merkle-DAG deduplication and folding.
123
- """
124
118
  def __init__(self, migration_threshold=50000):
125
119
  self.threshold = migration_threshold
126
120
  self.size = 0
127
121
  self.is_native = False
128
122
  self._light_store = {}
129
123
 
130
- # --- Systems Architecture: Process Memory Limit ---
131
124
  self.auto_purge_enabled = True
132
- # Instead of global OS RAM, we set a hard cap for THIS specific process.
133
- self.max_memory_mb = 1000.0 # 1 Gigabyte Limit
125
+ self.max_memory_mb = 1000.0
134
126
  self.total_ops = 0
135
127
  self._process = psutil.Process(os.getpid())
136
128
 
137
129
  def _validate_type(self, key, value=None):
138
- """Strict type guarding to prevent arbitrary objects from bleeding into C-Memory."""
139
130
  if not isinstance(key, str):
140
131
  raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
141
132
  if value is not None and not isinstance(value, str):
142
133
  raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
143
134
 
144
135
  def _get_64bit_hash(self, key):
145
- """Generates a 64-bit unsigned hash for the C-Engine."""
146
136
  return int(hashlib.md5(key.encode()).hexdigest()[:16], 16)
147
137
 
138
+ def set_auto_purge_threshold(self, threshold: float):
139
+ self.purge_threshold = threshold
140
+
148
141
  def purge(self):
149
- """Manual Purge Override to instantly free RAM."""
150
142
  current_mb = self._process.memory_info().rss / (1024 * 1024)
151
143
  if current_mb >= self.max_memory_mb:
152
144
  print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded {self.max_memory_mb} MB limit (Currently {current_mb:.1f} MB). Auto-Purging!")
153
145
  self.clear()
154
146
 
147
+ # --- Phase 1: Native Disk Persistence ---
148
+ def save_to_disk(self, filepath: str):
149
+ """Serializes the engine state to disk (O(1) Time context scaling)."""
150
+ if not self.is_native:
151
+ with open(filepath, 'w') as f:
152
+ json.dump(self._light_store, f)
153
+ else:
154
+ lqft_c_engine.save_to_disk(filepath)
155
+
156
+ def load_from_disk(self, filepath: str):
157
+ """Instantly reconstructs C-Pointers from a binary file."""
158
+ if not os.path.exists(filepath):
159
+ raise FileNotFoundError(f"Missing LQFT database file: {filepath}")
160
+
161
+ if not self.is_native:
162
+ # Check if it's a C-Engine binary file (magic bytes "LQFT")
163
+ with open(filepath, 'rb') as f:
164
+ if f.read(4) == b'LQFT':
165
+ self._migrate_to_native()
166
+ lqft_c_engine.load_from_disk(filepath)
167
+ return
168
+ with open(filepath, 'r') as f:
169
+ self._light_store = json.load(f)
170
+ self.size = len(self._light_store)
171
+ else:
172
+ lqft_c_engine.load_from_disk(filepath)
173
+
155
174
  def _migrate_to_native(self):
156
- """The 'Curve Flip' mechanism: moves all data to the Heavy Engine."""
157
175
  if not C_ENGINE_READY:
158
- print("[!] Warning: C-Engine missing. Staying in lightweight mode.")
159
- self.threshold = float('inf') # Prevent continuous upgrade attempts
176
+ self.threshold = float('inf')
160
177
  return
161
-
162
178
  for key, val in self._light_store.items():
163
179
  h = self._get_64bit_hash(key)
164
180
  lqft_c_engine.insert(h, val)
165
-
166
181
  self._light_store.clear()
167
182
  self.is_native = True
168
183
 
169
184
  def insert(self, key, value):
170
- # 1. Type Guard (Blocks the Poison Pill test)
171
185
  self._validate_type(key, value)
172
-
173
- # 2. Performance Safety: Process Memory Check
174
186
  self.total_ops += 1
175
187
  if self.auto_purge_enabled and self.total_ops % 5000 == 0:
176
188
  current_mb = self._process.memory_info().rss / (1024 * 1024)
@@ -181,7 +193,6 @@ class AdaptiveLQFT:
181
193
  if key not in self._light_store:
182
194
  self.size += 1
183
195
  self._light_store[key] = value
184
-
185
196
  if self.size >= self.threshold:
186
197
  self._migrate_to_native()
187
198
  else:
@@ -190,7 +201,6 @@ class AdaptiveLQFT:
190
201
 
191
202
  def remove(self, key):
192
203
  self._validate_type(key)
193
-
194
204
  if not self.is_native:
195
205
  if key in self._light_store:
196
206
  del self._light_store[key]
@@ -204,7 +214,6 @@ class AdaptiveLQFT:
204
214
 
205
215
  def search(self, key):
206
216
  self._validate_type(key)
207
-
208
217
  if not self.is_native:
209
218
  return self._light_store.get(key, None)
210
219
  else:
@@ -224,10 +233,8 @@ class AdaptiveLQFT:
224
233
  return {"physical_nodes": 0}
225
234
 
226
235
  def __del__(self):
227
- try:
228
- self.clear()
229
- except:
230
- pass
236
+ try: self.clear()
237
+ except: pass
231
238
 
232
239
  def status(self):
233
240
  return {
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.3.0
4
- Summary: LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)
3
+ Version: 0.5.0
4
+ Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
@@ -27,8 +27,8 @@ lqft_extension = Extension(
27
27
 
28
28
  setup(
29
29
  name="lqft-python-engine",
30
- version="0.3.0",
31
- description="LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)",
30
+ version="0.5.0",
31
+ description="LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)",
32
32
  long_description=long_description,
33
33
  long_description_content_type="text/markdown",
34
34
  author="Parjad Minooei",