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.
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/PKG-INFO +2 -2
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_engine.c +245 -152
- lqft_python_engine-0.7.0/lqft_engine.py +109 -0
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/SOURCES.txt +0 -1
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/top_level.txt +0 -1
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/setup.py +3 -3
- lqft_python_engine-0.5.0/lqft_engine.py +0 -244
- lqft_python_engine-0.5.0/pure_python_ds.py +0 -139
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/LICENSE.md +0 -0
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/pyproject.toml +0 -0
- {lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LQFT Engine: Native
|
|
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.
|
|
33
|
+
* LQFT C-Engine - V0.6.0 (Hardware Concurrency)
|
|
15
34
|
* Architect: Parjad Minooei
|
|
16
35
|
* * CHANGE LOG:
|
|
17
|
-
* - Implemented
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
fwrite(&
|
|
150
|
-
|
|
151
|
-
fwrite(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
206
|
+
fclose(fp);
|
|
169
207
|
}
|
|
170
208
|
}
|
|
209
|
+
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
210
|
+
Py_END_ALLOW_THREADS
|
|
171
211
|
|
|
172
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
291
|
+
fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
|
|
238
292
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
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
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
447
|
-
|
|
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
|
-
|
|
450
|
-
|
|
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
|
-
|
|
464
|
-
|
|
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
|
-
|
|
468
|
-
|
|
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) {
|
|
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.
|
|
4
|
-
Summary: LQFT Engine: Native
|
|
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
|
|
@@ -27,15 +27,15 @@ lqft_extension = Extension(
|
|
|
27
27
|
|
|
28
28
|
setup(
|
|
29
29
|
name="lqft-python-engine",
|
|
30
|
-
version="0.
|
|
31
|
-
description="LQFT Engine: Native
|
|
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",
|
|
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
|
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.5.0 → lqft_python_engine-0.7.0}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|