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.
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/PKG-INFO +2 -2
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_engine.c +219 -102
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_engine.py +36 -29
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/setup.py +2 -2
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/LICENSE.md +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/pure_python_ds.py +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/pyproject.toml +0 -0
- {lqft_python_engine-0.3.0 → lqft_python_engine-0.5.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:
|
|
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 -
|
|
14
|
+
* LQFT C-Engine - V0.5.0 (Native Disk Persistence)
|
|
15
15
|
* Architect: Parjad Minooei
|
|
16
16
|
* * CHANGE LOG:
|
|
17
|
-
* - Implemented
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
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)
|
|
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;
|
|
35
|
-
int ref_count;
|
|
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
|
-
//
|
|
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;
|
|
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
|
-
//
|
|
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
|
|
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);
|
|
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);
|
|
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*
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
|
|
351
|
-
|
|
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
|
-
|
|
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, "
|
|
480
|
+
{"delete", method_delete, METH_VARARGS, "Delete key"},
|
|
365
481
|
{"search", method_search, METH_VARARGS, "Search key"},
|
|
366
|
-
{"
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
4
|
-
Summary: LQFT Engine:
|
|
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.
|
|
31
|
-
description="LQFT Engine:
|
|
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",
|
|
File without changes
|
{lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.3.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|