lqft-python-engine 0.5.0__tar.gz → 0.7.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.5.0
4
- Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
3
+ Version: 0.7.0
4
+ Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
@@ -10,13 +10,32 @@
10
10
  #include <string.h>
11
11
  #include <stdint.h>
12
12
 
13
+ // --- PHASE 2: CROSS-PLATFORM HARDWARE LOCKS ---
14
+ #ifdef _WIN32
15
+ #include <windows.h>
16
+ typedef SRWLOCK lqft_rwlock_t;
17
+ #define LQFT_RWLOCK_INIT(lock) InitializeSRWLock(lock)
18
+ #define LQFT_RWLOCK_RDLOCK(lock) AcquireSRWLockShared(lock)
19
+ #define LQFT_RWLOCK_WRLOCK(lock) AcquireSRWLockExclusive(lock)
20
+ #define LQFT_RWLOCK_UNLOCK_RD(lock) ReleaseSRWLockShared(lock)
21
+ #define LQFT_RWLOCK_UNLOCK_WR(lock) ReleaseSRWLockExclusive(lock)
22
+ #else
23
+ #include <pthread.h>
24
+ typedef pthread_rwlock_t lqft_rwlock_t;
25
+ #define LQFT_RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
26
+ #define LQFT_RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
27
+ #define LQFT_RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
28
+ #define LQFT_RWLOCK_UNLOCK_RD(lock) pthread_rwlock_unlock(lock)
29
+ #define LQFT_RWLOCK_UNLOCK_WR(lock) pthread_rwlock_unlock(lock)
30
+ #endif
31
+
13
32
  /**
14
- * LQFT C-Engine - V0.5.0 (Native Disk Persistence)
33
+ * LQFT C-Engine - V0.6.0 (Hardware Concurrency)
15
34
  * Architect: Parjad Minooei
16
35
  * * CHANGE LOG:
17
- * - Implemented Binary Serialization (save_to_disk).
18
- * - Implemented O(1) Cold Start Deserialization (load_from_disk).
19
- * - DAG Pointer Reconstruction Logic.
36
+ * - Implemented SRWLOCK / pthread_rwlock for true multi-core utilization.
37
+ * - Bypassed Python GIL using Py_BEGIN_ALLOW_THREADS.
38
+ * - Fixed Macro brace expansions for thread safe early returns.
20
39
  */
21
40
 
22
41
  #define BIT_PARTITION 5
@@ -37,6 +56,8 @@ typedef struct LQFTNode {
37
56
  static LQFTNode** registry = NULL;
38
57
  static int physical_node_count = 0;
39
58
  static LQFTNode* global_root = NULL;
59
+ static lqft_rwlock_t engine_lock; // The Master Hardware Lock
60
+ static int lock_initialized = 0;
40
61
 
41
62
  const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
42
63
  const uint64_t FNV_PRIME = 1099511628211ULL;
@@ -63,6 +84,10 @@ char* portable_strdup(const char* s) {
63
84
  }
64
85
 
65
86
  static int init_registry() {
87
+ if (!lock_initialized) {
88
+ LQFT_RWLOCK_INIT(&engine_lock);
89
+ lock_initialized = 1;
90
+ }
66
91
  if (registry == NULL) {
67
92
  registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
68
93
  if (registry == NULL) return 0;
@@ -108,6 +133,8 @@ void decref(LQFTNode* node) {
108
133
  }
109
134
 
110
135
  static PyObject* method_free_all(PyObject* self, PyObject* args) {
136
+ Py_BEGIN_ALLOW_THREADS
137
+ LQFT_RWLOCK_WRLOCK(&engine_lock);
111
138
  if (registry != NULL) {
112
139
  for (int i = 0; i < REGISTRY_SIZE; i++) {
113
140
  if (registry[i] != NULL && registry[i] != TOMBSTONE) {
@@ -121,6 +148,9 @@ static PyObject* method_free_all(PyObject* self, PyObject* args) {
121
148
  }
122
149
  physical_node_count = 0;
123
150
  global_root = NULL;
151
+ LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
152
+ Py_END_ALLOW_THREADS
153
+
124
154
  Py_RETURN_NONE;
125
155
  }
126
156
 
@@ -130,46 +160,56 @@ static PyObject* method_free_all(PyObject* self, PyObject* args) {
130
160
  static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
131
161
  const char* filepath;
132
162
  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;
163
+
164
+ int success = 1;
165
+
166
+ // Release GIL, Lock Engine for Writing
167
+ Py_BEGIN_ALLOW_THREADS
168
+ LQFT_RWLOCK_WRLOCK(&engine_lock);
169
+
170
+ if (!registry) {
171
+ success = 0;
172
+ } else {
173
+ FILE* fp = fopen(filepath, "wb");
174
+ if (!fp) {
175
+ success = 0;
176
+ } else {
177
+ char magic[4] = "LQFT";
178
+ fwrite(magic, 1, 4, fp);
179
+ fwrite(&physical_node_count, sizeof(int), 1, fp);
180
+ uint64_t root_hash = global_root ? global_root->full_hash_val : 0;
181
+ fwrite(&root_hash, sizeof(uint64_t), 1, fp);
182
+
183
+ for (int i = 0; i < REGISTRY_SIZE; i++) {
184
+ LQFTNode* node = registry[i];
185
+ if (node != NULL && node != TOMBSTONE) {
186
+ fwrite(&node->full_hash_val, sizeof(uint64_t), 1, fp);
187
+ fwrite(&node->key_hash, sizeof(uint64_t), 1, fp);
188
+ fwrite(node->struct_hash, 1, 17, fp);
189
+ fwrite(&node->ref_count, sizeof(int), 1, fp);
190
+
191
+ int has_val = (node->value != NULL) ? 1 : 0;
192
+ fwrite(&has_val, sizeof(int), 1, fp);
193
+ if (has_val) {
194
+ int v_len = (int)strlen((char*)node->value);
195
+ fwrite(&v_len, sizeof(int), 1, fp);
196
+ fwrite(node->value, 1, v_len, fp);
197
+ }
198
+
199
+ uint64_t child_refs[32] = {0};
200
+ for (int c = 0; c < 32; c++) {
201
+ if (node->children[c]) child_refs[c] = node->children[c]->full_hash_val;
202
+ }
203
+ fwrite(child_refs, sizeof(uint64_t), 32, fp);
204
+ }
167
205
  }
168
- fwrite(child_refs, sizeof(uint64_t), 32, fp);
206
+ fclose(fp);
169
207
  }
170
208
  }
209
+ LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
210
+ Py_END_ALLOW_THREADS
171
211
 
172
- fclose(fp);
212
+ if (!success) return PyErr_SetFromErrno(PyExc_IOError);
173
213
  Py_RETURN_TRUE;
174
214
  }
175
215
 
@@ -191,75 +231,93 @@ static PyObject* method_load_from_disk(PyObject* self, PyObject* args) {
191
231
  const char* filepath;
192
232
  if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
193
233
 
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
- }
234
+ int success = 1;
235
+ int format_error = 0;
204
236
 
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
- }
237
+ Py_BEGIN_ALLOW_THREADS
238
+ LQFT_RWLOCK_WRLOCK(&engine_lock);
239
+
240
+ FILE* fp = fopen(filepath, "rb");
241
+ if (!fp) {
242
+ success = 0;
243
+ } else {
244
+ char magic[5] = {0};
245
+ fread(magic, 1, 4, fp);
246
+ if (strcmp(magic, "LQFT") != 0) {
247
+ fclose(fp);
248
+ format_error = 1;
249
+ success = 0;
250
+ } else {
251
+ // Internal clear
252
+ if (registry != NULL) {
253
+ for (int i = 0; i < REGISTRY_SIZE; i++) {
254
+ if (registry[i] != NULL && registry[i] != TOMBSTONE) {
255
+ if (registry[i]->value) free(registry[i]->value);
256
+ free(registry[i]);
257
+ }
258
+ registry[i] = NULL;
259
+ }
260
+ }
261
+ physical_node_count = 0;
262
+ global_root = NULL;
263
+ init_registry();
264
+
265
+ int total_nodes;
266
+ uint64_t root_hash;
267
+ fread(&total_nodes, sizeof(int), 1, fp);
268
+ fread(&root_hash, sizeof(uint64_t), 1, fp);
269
+
270
+ uint64_t* all_child_refs = (uint64_t*)malloc(total_nodes * 32 * sizeof(uint64_t));
271
+ LQFTNode** loaded_nodes = (LQFTNode**)malloc(total_nodes * sizeof(LQFTNode*));
272
+
273
+ for (int i = 0; i < total_nodes; i++) {
274
+ LQFTNode* node = create_node(NULL, 0);
275
+ fread(&node->full_hash_val, sizeof(uint64_t), 1, fp);
276
+ fread(&node->key_hash, sizeof(uint64_t), 1, fp);
277
+ fread(node->struct_hash, 1, 17, fp);
278
+ fread(&node->ref_count, sizeof(int), 1, fp);
279
+
280
+ int has_val;
281
+ fread(&has_val, sizeof(int), 1, fp);
282
+ if (has_val) {
283
+ int v_len;
284
+ fread(&v_len, sizeof(int), 1, fp);
285
+ char* val_str = (char*)malloc(v_len + 1);
286
+ fread(val_str, 1, v_len, fp);
287
+ val_str[v_len] = '\0';
288
+ node->value = val_str;
289
+ }
236
290
 
237
- fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
291
+ fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
238
292
 
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
- }
293
+ uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
294
+ while (registry[idx] != NULL) idx = (idx + 1) % REGISTRY_SIZE;
295
+ registry[idx] = node;
296
+ loaded_nodes[i] = node;
297
+ physical_node_count++;
298
+ }
247
299
 
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);
300
+ for (int i = 0; i < total_nodes; i++) {
301
+ for (int c = 0; c < 32; c++) {
302
+ uint64_t target_hash = all_child_refs[i * 32 + c];
303
+ if (target_hash != 0) loaded_nodes[i]->children[c] = find_in_registry(target_hash);
304
+ }
254
305
  }
306
+
307
+ global_root = find_in_registry(root_hash);
308
+ free(all_child_refs);
309
+ free(loaded_nodes);
310
+ fclose(fp);
255
311
  }
256
312
  }
313
+ LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
314
+ Py_END_ALLOW_THREADS
257
315
 
258
- global_root = find_in_registry(root_hash);
259
-
260
- free(all_child_refs);
261
- free(loaded_nodes);
262
- fclose(fp);
316
+ if (format_error) {
317
+ PyErr_SetString(PyExc_ValueError, "Invalid LQFT binary file format.");
318
+ return NULL;
319
+ }
320
+ if (!success) return PyErr_SetFromErrno(PyExc_IOError);
263
321
 
264
322
  Py_RETURN_TRUE;
265
323
  }
@@ -329,8 +387,15 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
329
387
  char* val_str;
330
388
  if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
331
389
 
390
+ // Copy the string before dropping the GIL to prevent memory corruption
391
+ char* val_copy = portable_strdup(val_str);
392
+
393
+ // Bypass GIL & Lock Engine (Exclusive Write Lock)
394
+ Py_BEGIN_ALLOW_THREADS
395
+ LQFT_RWLOCK_WRLOCK(&engine_lock);
396
+
332
397
  if (!global_root) {
333
- if (!init_registry()) return PyErr_NoMemory();
398
+ init_registry();
334
399
  global_root = get_canonical(NULL, 0, NULL);
335
400
  global_root->ref_count++;
336
401
  }
@@ -354,9 +419,9 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
354
419
 
355
420
  LQFTNode* new_sub_node = NULL;
356
421
  if (curr == NULL) {
357
- new_sub_node = get_canonical(portable_strdup(val_str), h, NULL);
422
+ new_sub_node = get_canonical(portable_strdup(val_copy), h, NULL);
358
423
  } else if (curr->key_hash == h) {
359
- new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
424
+ new_sub_node = get_canonical(portable_strdup(val_copy), h, curr->children);
360
425
  } else {
361
426
  unsigned long long old_h = curr->key_hash;
362
427
  char* old_val = portable_strdup((char*)curr->value);
@@ -366,7 +431,7 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
366
431
  uint32_t s_new = (h >> temp_depth) & MASK;
367
432
  if (s_old != s_new) {
368
433
  LQFTNode* c_old = get_canonical(old_val, old_h, curr->children);
369
- LQFTNode* c_new = get_canonical(portable_strdup(val_str), h, NULL);
434
+ LQFTNode* c_new = get_canonical(portable_strdup(val_copy), h, NULL);
370
435
  LQFTNode* new_children[32] = {NULL};
371
436
  new_children[s_old] = c_old;
372
437
  new_children[s_new] = c_new;
@@ -379,7 +444,7 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
379
444
  temp_depth += BIT_PARTITION;
380
445
  }
381
446
  }
382
- if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
447
+ if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_copy), h, curr->children);
383
448
  }
384
449
 
385
450
  for (int i = path_len - 1; i >= 0; i--) {
@@ -400,6 +465,10 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
400
465
  global_root = new_sub_node;
401
466
  global_root->ref_count++;
402
467
  if (old_root) decref(old_root);
468
+
469
+ free(val_copy);
470
+ LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
471
+ Py_END_ALLOW_THREADS
403
472
 
404
473
  Py_RETURN_NONE;
405
474
  }
@@ -407,66 +476,86 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
407
476
  static PyObject* method_search(PyObject* self, PyObject* args) {
408
477
  unsigned long long h;
409
478
  if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
410
- if (!global_root) Py_RETURN_NONE;
411
479
 
412
- LQFTNode* curr = global_root;
413
- int bit_depth = 0;
414
- while (curr != NULL && curr->value == NULL) {
415
- uint32_t segment = (h >> bit_depth) & MASK;
416
- curr = curr->children[segment];
417
- bit_depth += BIT_PARTITION;
480
+ char* result_str = NULL;
481
+
482
+ // Bypass GIL & Lock Engine (Shared Read Lock - Multiple threads can enter simultaneously!)
483
+ Py_BEGIN_ALLOW_THREADS
484
+ LQFT_RWLOCK_RDLOCK(&engine_lock);
485
+
486
+ if (global_root) {
487
+ LQFTNode* curr = global_root;
488
+ int bit_depth = 0;
489
+ while (curr != NULL && curr->value == NULL) {
490
+ uint32_t segment = (h >> bit_depth) & MASK;
491
+ curr = curr->children[segment];
492
+ bit_depth += BIT_PARTITION;
493
+ }
494
+ if (curr != NULL && curr->key_hash == h) {
495
+ result_str = (char*)curr->value;
496
+ }
418
497
  }
419
498
 
420
- if (curr != NULL && curr->key_hash == h) return PyUnicode_FromString((char*)curr->value);
499
+ LQFT_RWLOCK_UNLOCK_RD(&engine_lock);
500
+ Py_END_ALLOW_THREADS
501
+
502
+ if (result_str) return PyUnicode_FromString(result_str);
421
503
  Py_RETURN_NONE;
422
504
  }
423
505
 
424
506
  static PyObject* method_delete(PyObject* self, PyObject* args) {
425
507
  unsigned long long h;
426
508
  if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
427
- if (!global_root) Py_RETURN_NONE;
428
509
 
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;
510
+ Py_BEGIN_ALLOW_THREADS
511
+ LQFT_RWLOCK_WRLOCK(&engine_lock);
512
+
513
+ if (global_root) {
514
+ LQFTNode* path_nodes[20];
515
+ uint32_t path_segs[20];
516
+ int path_len = 0;
517
+ LQFTNode* curr = global_root;
518
+ int bit_depth = 0;
519
+
520
+ while (curr != NULL && curr->value == NULL) {
521
+ uint32_t segment = (h >> bit_depth) & MASK;
522
+ path_nodes[path_len] = curr;
523
+ path_segs[path_len] = segment;
524
+ path_len++;
525
+ curr = curr->children[segment];
526
+ bit_depth += BIT_PARTITION;
527
+ }
445
528
 
446
- LQFTNode* old_root = global_root;
447
- LQFTNode* new_sub_node = NULL;
529
+ if (curr != NULL && curr->key_hash == h) {
530
+ LQFTNode* old_root = global_root;
531
+ LQFTNode* new_sub_node = NULL;
532
+
533
+ for (int i = path_len - 1; i >= 0; i--) {
534
+ LQFTNode* p_node = path_nodes[i];
535
+ uint32_t segment = path_segs[i];
536
+ LQFTNode* new_children[32];
537
+ int has_other_children = 0;
538
+
539
+ for (uint32_t j = 0; j < 32; j++) {
540
+ if (j == segment) new_children[j] = new_sub_node;
541
+ else {
542
+ new_children[j] = p_node->children[j];
543
+ if (new_children[j]) has_other_children = 1;
544
+ }
545
+ }
448
546
 
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;
547
+ if (!has_other_children && i > 0) new_sub_node = NULL;
548
+ else new_sub_node = get_canonical(NULL, 0, new_children);
460
549
  }
461
- }
462
550
 
463
- if (!has_other_children && i > 0) new_sub_node = NULL;
464
- else new_sub_node = get_canonical(NULL, 0, new_children);
551
+ global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
552
+ if (global_root) global_root->ref_count++;
553
+ if (old_root) decref(old_root);
554
+ }
465
555
  }
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);
556
+
557
+ LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
558
+ Py_END_ALLOW_THREADS
470
559
 
471
560
  Py_RETURN_NONE;
472
561
  }
@@ -487,4 +576,8 @@ static PyMethodDef LQFTMethods[] = {
487
576
  };
488
577
 
489
578
  static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
490
- PyMODINIT_FUNC PyInit_lqft_c_engine(void) { return PyModule_Create(&lqftmodule); }
579
+ PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
580
+ LQFT_RWLOCK_INIT(&engine_lock);
581
+ lock_initialized = 1;
582
+ return PyModule_Create(&lqftmodule);
583
+ }
@@ -0,0 +1,109 @@
1
+ import hashlib
2
+ import psutil
3
+ import os
4
+ import sys
5
+
6
+ # ---------------------------------------------------------
7
+ # STRICT NATIVE ENTERPRISE ENGINE (v0.7.0)
8
+ # ---------------------------------------------------------
9
+ # Architect: Parjad Minooei
10
+ # Status: Pure Python fallback removed. Strict C-Core interface.
11
+
12
+ try:
13
+ import lqft_c_engine
14
+ except ImportError:
15
+ print("\n[!] CRITICAL FATAL ERROR: Native C-Engine not found.")
16
+ print("[!] The LQFT is now a strictly native database. Pure Python fallback is disabled.")
17
+ print("[!] Run: python setup.py build_ext --inplace\n")
18
+ sys.exit(1)
19
+
20
+ class LQFT:
21
+ def __init__(self):
22
+ self.is_native = True
23
+ self.auto_purge_enabled = True
24
+ self.max_memory_mb = 1000.0
25
+ self.total_ops = 0
26
+ self._process = psutil.Process(os.getpid())
27
+
28
+ def _validate_type(self, key, value=None):
29
+ if not isinstance(key, str):
30
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
31
+ if value is not None and not isinstance(value, str):
32
+ raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
33
+
34
+ def _get_64bit_hash(self, key):
35
+ return int(hashlib.md5(key.encode()).hexdigest()[:16], 16)
36
+
37
+ def set_auto_purge_threshold(self, threshold: float):
38
+ self.max_memory_mb = threshold
39
+
40
+ def purge(self):
41
+ current_mb = self._process.memory_info().rss / (1024 * 1024)
42
+ print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded limit (Currently {current_mb:.1f} MB). Auto-Purging!")
43
+ self.clear()
44
+
45
+ # --- Native Disk Persistence ---
46
+ def save_to_disk(self, filepath: str):
47
+ lqft_c_engine.save_to_disk(filepath)
48
+
49
+ def load_from_disk(self, filepath: str):
50
+ if not os.path.exists(filepath):
51
+ raise FileNotFoundError(f"Missing LQFT database file: {filepath}")
52
+ lqft_c_engine.load_from_disk(filepath)
53
+
54
+ # --- Core Operations ---
55
+ def insert(self, key, value):
56
+ self._validate_type(key, value)
57
+ self.total_ops += 1
58
+
59
+ # Memory Circuit Breaker
60
+ if self.auto_purge_enabled and self.total_ops % 5000 == 0:
61
+ current_mb = self._process.memory_info().rss / (1024 * 1024)
62
+ if current_mb >= self.max_memory_mb:
63
+ self.purge()
64
+
65
+ h = self._get_64bit_hash(key)
66
+ lqft_c_engine.insert(h, value)
67
+
68
+ def remove(self, key):
69
+ self._validate_type(key)
70
+ h = self._get_64bit_hash(key)
71
+ lqft_c_engine.delete(h)
72
+
73
+ def delete(self, key):
74
+ self.remove(key)
75
+
76
+ def search(self, key):
77
+ self._validate_type(key)
78
+ h = self._get_64bit_hash(key)
79
+ return lqft_c_engine.search(h)
80
+
81
+ # --- Pythonic Syntactic Sugar ---
82
+ def __setitem__(self, key, value):
83
+ self.insert(key, value)
84
+
85
+ def __getitem__(self, key):
86
+ res = self.search(key)
87
+ if res is None:
88
+ raise KeyError(key)
89
+ return res
90
+
91
+ def clear(self):
92
+ return lqft_c_engine.free_all()
93
+
94
+ def get_stats(self):
95
+ return lqft_c_engine.get_metrics()
96
+
97
+ def __del__(self):
98
+ try: self.clear()
99
+ except: pass
100
+
101
+ def status(self):
102
+ return {
103
+ "mode": "Strict Native C-Engine",
104
+ "items": lqft_c_engine.get_metrics().get('physical_nodes', 0),
105
+ "threshold": "DISABLED (Pure Hardware Mode)"
106
+ }
107
+
108
+ # Alias mapping so older benchmark scripts don't crash
109
+ AdaptiveLQFT = LQFT
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.5.0
4
- Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
3
+ Version: 0.7.0
4
+ Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
@@ -1,7 +1,6 @@
1
1
  LICENSE.md
2
2
  lqft_engine.c
3
3
  lqft_engine.py
4
- pure_python_ds.py
5
4
  pyproject.toml
6
5
  setup.py
7
6
  lqft_python_engine.egg-info/PKG-INFO
@@ -1,3 +1,2 @@
1
1
  lqft_c_engine
2
2
  lqft_engine
3
- pure_python_ds
@@ -27,15 +27,15 @@ lqft_extension = Extension(
27
27
 
28
28
  setup(
29
29
  name="lqft-python-engine",
30
- version="0.5.0",
31
- description="LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)",
30
+ version="0.7.0",
31
+ description="LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)",
32
32
  long_description=long_description,
33
33
  long_description_content_type="text/markdown",
34
34
  author="Parjad Minooei",
35
35
  url="https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-",
36
36
  ext_modules=[lqft_extension],
37
37
  packages=find_packages(),
38
- py_modules=["lqft_engine", "pure_python_ds"],
38
+ py_modules=["lqft_engine"],
39
39
  install_requires=['psutil'],
40
40
  license="MIT",
41
41
  classifiers=[
@@ -1,244 +0,0 @@
1
- import hashlib
2
- import weakref
3
- import psutil
4
- import os
5
- import json
6
-
7
- # ---------------------------------------------------------
8
- # LEGACY PURE PYTHON LQFT (For reference/fallback)
9
- # ---------------------------------------------------------
10
- class LQFTNode:
11
- __slots__ = ['children', 'value', 'key_hash', 'struct_hash', '__weakref__']
12
- _registry = weakref.WeakValueDictionary()
13
- _null_cache = {}
14
-
15
- def __init__(self, value=None, children=None, key_hash=None):
16
- self.value = value
17
- self.key_hash = key_hash
18
- self.children = children or {}
19
- self.struct_hash = self._calculate_struct_hash()
20
-
21
- def _calculate_struct_hash(self):
22
- child_sigs = tuple(sorted([(k, v.struct_hash) for k, v in self.children.items()]))
23
- k_identity = str(self.key_hash) if self.key_hash is not None else ""
24
- data = f"v:{self.value}|k:{k_identity}|c:{child_sigs}".encode()
25
- return hashlib.md5(data).hexdigest()
26
-
27
- @classmethod
28
- def get_canonical(cls, value, children, key_hash=None):
29
- if children == {}: children = None
30
- child_sigs = tuple(sorted([(k, v.struct_hash) for k, v in (children or {}).items()]))
31
- k_identity = str(key_hash) if key_hash is not None else ""
32
- lookup_hash = hashlib.md5(f"v:{value}|k:{k_identity}|c:{child_sigs}".encode()).hexdigest()
33
- if lookup_hash in cls._registry: return cls._registry[lookup_hash]
34
- new_node = cls(value, children, key_hash)
35
- cls._registry[lookup_hash] = new_node
36
- return new_node
37
-
38
- @classmethod
39
- def get_null(cls):
40
- if 'null' not in cls._null_cache:
41
- cls._null_cache['null'] = cls.get_canonical(None, None, None)
42
- return cls._null_cache['null']
43
-
44
- class LQFT:
45
- def __init__(self, bit_partition=5, max_bits=256):
46
- self.partition = bit_partition
47
- self.max_bits = max_bits
48
- self.mask = (1 << bit_partition) - 1
49
- self.root = LQFTNode.get_null()
50
-
51
- def _get_hash(self, key):
52
- return int(hashlib.sha256(str(key).encode()).hexdigest(), 16)
53
-
54
- def insert(self, key, value):
55
- h = self._get_hash(key)
56
- null_node = LQFTNode.get_null()
57
- path, curr, bit_depth = [], self.root, 0
58
-
59
- while curr is not null_node and curr.value is None:
60
- segment = (h >> bit_depth) & self.mask
61
- path.append((curr, segment))
62
- if segment not in curr.children:
63
- curr = null_node
64
- break
65
- curr = curr.children[segment]
66
- bit_depth += self.partition
67
-
68
- new_sub_node = None
69
- if curr is null_node:
70
- new_sub_node = LQFTNode.get_canonical(value, None, h)
71
- elif curr.key_hash == h:
72
- new_sub_node = LQFTNode.get_canonical(value, curr.children, h)
73
- else:
74
- old_h, old_val, temp_depth = curr.key_hash, curr.value, bit_depth
75
- while temp_depth < self.max_bits:
76
- s_old, s_new = (old_h >> temp_depth) & self.mask, (h >> temp_depth) & self.mask
77
- if s_old != s_new:
78
- c_old = LQFTNode.get_canonical(old_val, None, old_h)
79
- c_new = LQFTNode.get_canonical(value, None, h)
80
- new_sub_node = LQFTNode.get_canonical(None, {s_old: c_old, s_new: c_new}, None)
81
- break
82
- else:
83
- path.append(("split", s_old))
84
- temp_depth += self.partition
85
- if new_sub_node is None:
86
- new_sub_node = LQFTNode.get_canonical(value, curr.children, h)
87
-
88
- for entry in reversed(path):
89
- if entry[0] == "split":
90
- new_sub_node = LQFTNode.get_canonical(None, {entry[1]: new_sub_node}, None)
91
- else:
92
- p_node, segment = entry
93
- new_children = dict(p_node.children)
94
- new_children[segment] = new_sub_node
95
- new_sub_node = LQFTNode.get_canonical(p_node.value, new_children, p_node.key_hash)
96
- self.root = new_sub_node
97
-
98
- def search(self, key):
99
- h, curr, null_node, bit_depth = self._get_hash(key), self.root, LQFTNode.get_null(), 0
100
- while curr is not null_node:
101
- if curr.value is not None: return curr.value if curr.key_hash == h else None
102
- segment = (h >> bit_depth) & self.mask
103
- if segment not in curr.children: return None
104
- curr, bit_depth = curr.children[segment], bit_depth + self.partition
105
- if bit_depth >= self.max_bits: break
106
- return None
107
-
108
- # ---------------------------------------------------------
109
- # ADAPTIVE ENTERPRISE ENGINE (v0.5.0 - Disk Persistence)
110
- # ---------------------------------------------------------
111
- try:
112
- import lqft_c_engine
113
- C_ENGINE_READY = True
114
- except ImportError:
115
- C_ENGINE_READY = False
116
-
117
- class AdaptiveLQFT:
118
- def __init__(self, migration_threshold=50000):
119
- self.threshold = migration_threshold
120
- self.size = 0
121
- self.is_native = False
122
- self._light_store = {}
123
-
124
- self.auto_purge_enabled = True
125
- self.max_memory_mb = 1000.0
126
- self.total_ops = 0
127
- self._process = psutil.Process(os.getpid())
128
-
129
- def _validate_type(self, key, value=None):
130
- if not isinstance(key, str):
131
- raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
132
- if value is not None and not isinstance(value, str):
133
- raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
134
-
135
- def _get_64bit_hash(self, key):
136
- return int(hashlib.md5(key.encode()).hexdigest()[:16], 16)
137
-
138
- def set_auto_purge_threshold(self, threshold: float):
139
- self.purge_threshold = threshold
140
-
141
- def purge(self):
142
- current_mb = self._process.memory_info().rss / (1024 * 1024)
143
- if current_mb >= self.max_memory_mb:
144
- print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded {self.max_memory_mb} MB limit (Currently {current_mb:.1f} MB). Auto-Purging!")
145
- self.clear()
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
-
174
- def _migrate_to_native(self):
175
- if not C_ENGINE_READY:
176
- self.threshold = float('inf')
177
- return
178
- for key, val in self._light_store.items():
179
- h = self._get_64bit_hash(key)
180
- lqft_c_engine.insert(h, val)
181
- self._light_store.clear()
182
- self.is_native = True
183
-
184
- def insert(self, key, value):
185
- self._validate_type(key, value)
186
- self.total_ops += 1
187
- if self.auto_purge_enabled and self.total_ops % 5000 == 0:
188
- current_mb = self._process.memory_info().rss / (1024 * 1024)
189
- if current_mb >= self.max_memory_mb:
190
- self.purge()
191
-
192
- if not self.is_native:
193
- if key not in self._light_store:
194
- self.size += 1
195
- self._light_store[key] = value
196
- if self.size >= self.threshold:
197
- self._migrate_to_native()
198
- else:
199
- h = self._get_64bit_hash(key)
200
- lqft_c_engine.insert(h, value)
201
-
202
- def remove(self, key):
203
- self._validate_type(key)
204
- if not self.is_native:
205
- if key in self._light_store:
206
- del self._light_store[key]
207
- self.size -= 1
208
- else:
209
- h = self._get_64bit_hash(key)
210
- lqft_c_engine.delete(h)
211
-
212
- def delete(self, key):
213
- self.remove(key)
214
-
215
- def search(self, key):
216
- self._validate_type(key)
217
- if not self.is_native:
218
- return self._light_store.get(key, None)
219
- else:
220
- h = self._get_64bit_hash(key)
221
- return lqft_c_engine.search(h)
222
-
223
- def clear(self):
224
- self._light_store.clear()
225
- self.size = 0
226
- if C_ENGINE_READY:
227
- return lqft_c_engine.free_all()
228
- return 0
229
-
230
- def get_stats(self):
231
- if self.is_native and C_ENGINE_READY:
232
- return lqft_c_engine.get_metrics()
233
- return {"physical_nodes": 0}
234
-
235
- def __del__(self):
236
- try: self.clear()
237
- except: pass
238
-
239
- def status(self):
240
- return {
241
- "mode": "Native Merkle-DAG" if self.is_native else "Lightweight C-Hash",
242
- "items": self.size if not self.is_native else lqft_c_engine.get_metrics().get('physical_nodes', self.size),
243
- "threshold": self.threshold
244
- }
@@ -1,139 +0,0 @@
1
- import struct
2
-
3
- # ---------------------------------------------------------
4
- # 1. DETERMINISTIC HASHING (FNV-1a 64-bit)
5
- # ---------------------------------------------------------
6
- def fnv1a_64(key: str) -> int:
7
- """Generates a strict 64-bit deterministic hash for O(1) routing."""
8
- hval = 0xcbf29ce484222325
9
- fnv_prime = 0x100000001b3
10
- for byte in key.encode('utf-8'):
11
- hval ^= byte
12
- hval = (hval * fnv_prime) & 0xFFFFFFFFFFFFFFFF
13
- return hval
14
-
15
- def combine_hashes(hashes: list) -> int:
16
- """Combines child Merkle hashes to generate a parent's structural hash."""
17
- hval = 0
18
- for h in hashes:
19
- if h is not None:
20
- hval ^= h
21
- hval = (hval * 0x100000001b3) & 0xFFFFFFFFFFFFFFFF
22
- return hval
23
-
24
- # ---------------------------------------------------------
25
- # 2. GLOBAL C-REGISTRY MOCK (Structural Folding)
26
- # ---------------------------------------------------------
27
- # Maps a Merkle Hash -> Physical Node Instance
28
- NODE_REGISTRY = {}
29
-
30
- class LQFTNode:
31
- """A fixed 32-way routing node."""
32
- __slots__ = ('children', 'value', 'merkle_hash')
33
-
34
- def __init__(self, value=None):
35
- self.children = [None] * 32
36
- self.value = value
37
- self.merkle_hash = None
38
-
39
- def get_deduplicated_node(node: LQFTNode) -> LQFTNode:
40
- """
41
- The core of O(Σ) Space Complexity.
42
- If a node with this exact structure exists, return the existing memory pointer.
43
- Otherwise, register this new node.
44
- """
45
- # Calculate structural Merkle Hash
46
- child_hashes = [c.merkle_hash if c else None for c in node.children]
47
- base_hash = fnv1a_64(str(node.value)) if node.value is not None else 0
48
- node.merkle_hash = (base_hash ^ combine_hashes(child_hashes)) & 0xFFFFFFFFFFFFFFFF
49
-
50
- # Structural Folding (Deduplication)
51
- if node.merkle_hash in NODE_REGISTRY:
52
- return NODE_REGISTRY[node.merkle_hash]
53
-
54
- NODE_REGISTRY[node.merkle_hash] = node
55
- return node
56
-
57
- # ---------------------------------------------------------
58
- # 3. THE LQFT ARCHITECTURE (Strictly Iterative)
59
- # ---------------------------------------------------------
60
- class LQFT:
61
- def __init__(self):
62
- self.root = get_deduplicated_node(LQFTNode())
63
-
64
- def insert(self, key: str, value: any):
65
- """
66
- O(1) Insertion. Capped at exactly 13 hops.
67
- STRICTLY ITERATIVE. NO RECURSION ALLOWED.
68
- """
69
- key_hash = fnv1a_64(key)
70
-
71
- # Step 1: Iterative Traversal Down
72
- # We store the path to allow bottom-up Merkle folding without recursion
73
- path_stack = []
74
- current = self.root
75
-
76
- for level in range(13): # Fixed 64-bit space (13 chunks of 5 bits)
77
- index = (key_hash >> (level * 5)) & 0x1F # Mask 5 bits
78
- path_stack.append((current, index))
79
-
80
- if current.children[index] is None:
81
- current = LQFTNode() # Create empty node for routing
82
- else:
83
- current = current.children[index]
84
-
85
- # Step 2: Create the Leaf Node
86
- new_leaf = LQFTNode(value=value)
87
- current = get_deduplicated_node(new_leaf)
88
-
89
- # Step 3: Iterative Bottom-Up Folding (Copy-on-Write)
90
- while path_stack:
91
- parent_node, index = path_stack.pop()
92
-
93
- # Create a copy of the parent to ensure immutability/versioning
94
- new_parent = LQFTNode()
95
- new_parent.children = list(parent_node.children) # Copy references
96
- new_parent.children[index] = current # Attach the new folded child
97
-
98
- # Deduplicate the new parent
99
- current = get_deduplicated_node(new_parent)
100
-
101
- # The final deduplicated node becomes the new root
102
- self.root = current
103
-
104
- def search(self, key: str) -> any:
105
- """O(1) Search. Guaranteed max 13 hops. Iterative."""
106
- key_hash = fnv1a_64(key)
107
- current = self.root
108
-
109
- for level in range(13):
110
- index = (key_hash >> (level * 5)) & 0x1F
111
- current = current.children[index]
112
- if current is None:
113
- return None # Key not found
114
-
115
- # FIXED: This return statement is now outside the loop!
116
- return current.value
117
-
118
- # Make it easy to use like standard Python Dicts
119
- def __setitem__(self, key, value):
120
- self.insert(key, value)
121
-
122
- def __getitem__(self, key):
123
- res = self.search(key)
124
- if res is None:
125
- raise KeyError(key)
126
- return res
127
-
128
- # ---------------------------------------------------------
129
- # 4. EASY API (The "Heapify" Equivalent)
130
- # ---------------------------------------------------------
131
- def build_lqft(iterable) -> LQFT:
132
- """
133
- Instantiates and builds an LQFT in O(1) interface time.
134
- Usage: tree = build_lqft([("user1", "dataA"), ("user2", "dataB")])
135
- """
136
- tree = LQFT()
137
- for key, value in iterable:
138
- tree.insert(key, value)
139
- return tree