lqft-python-engine 0.1.3__tar.gz → 0.1.7__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,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.1.3
3
+ Version: 0.1.7
4
4
  Summary: Log-Quantum Fractal Tree: Pattern-Aware Deduplicating Data Structure
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
- Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Operating System :: OS Independent
12
11
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
12
  Requires-Python: >=3.8
14
13
  Description-Content-Type: text/markdown
15
14
  License-File: LICENSE.md
15
+ Requires-Dist: psutil
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: description
@@ -20,6 +20,7 @@ Dynamic: description-content-type
20
20
  Dynamic: home-page
21
21
  Dynamic: license
22
22
  Dynamic: license-file
23
+ Dynamic: requires-dist
23
24
  Dynamic: requires-python
24
25
  Dynamic: summary
25
26
 
@@ -11,30 +11,29 @@
11
11
  #include <stdint.h>
12
12
 
13
13
  /**
14
- * LQFT C-Engine (Log-Quantum Fractal Tree) - V4.1 (Master Build)
14
+ * LQFT C-Engine - V4.3 (Dynamic Registry Build)
15
15
  * Architect: Parjad Minooei
16
- * * MAJOR FIX 1: Upgraded to 64-bit FNV-1a structural hashing (solves 32-bit collisions).
17
- * * MAJOR FIX 2: Added Segment Indexing `[i]` to branch hashing (solves Ghost Sibling merges).
18
- * * MAJOR FIX 3: Capped MAX_BITS to 64 to prevent Undefined Behavior bit-shifts.
16
+ * * BUGFIX: Added missing 'search' method to the native export table.
17
+ * * MEMORY: Moved Registry to HEAP (Dynamic) for zero-footprint reclamation.
19
18
  */
20
19
 
21
20
  #define BIT_PARTITION 5
22
- #define MAX_BITS 64 // 64-bit integer hashes passed from Python
21
+ #define MAX_BITS 64
23
22
  #define MASK 0x1F
24
- #define REGISTRY_SIZE 8000009 // 8 Million prime slots to guarantee massive headroom
23
+ #define REGISTRY_SIZE 8000009
25
24
 
26
25
  typedef struct LQFTNode {
27
26
  void* value;
28
27
  uint64_t key_hash;
29
28
  struct LQFTNode* children[32];
30
- char struct_hash[17]; // 16 Hex chars + 1 Null terminator for 64-bit hash
29
+ char struct_hash[17];
31
30
  } LQFTNode;
32
31
 
33
- LQFTNode* registry[REGISTRY_SIZE];
34
- int physical_node_count = 0;
35
- LQFTNode* global_root = NULL;
32
+ // Registry is now a pointer allocated on the HEAP to allow full OS reclamation
33
+ static LQFTNode** registry = NULL;
34
+ static int physical_node_count = 0;
35
+ static LQFTNode* global_root = NULL;
36
36
 
37
- // Upgraded to 64-bit FNV-1a Hash to prevent structural collisions at massive scales
38
37
  uint64_t fnv1a_64(const char* str) {
39
38
  uint64_t hash = 14695981039346656037ULL;
40
39
  while (*str) {
@@ -44,8 +43,27 @@ uint64_t fnv1a_64(const char* str) {
44
43
  return hash;
45
44
  }
46
45
 
46
+ char* portable_strdup(const char* s) {
47
+ if (!s) return NULL;
48
+ #ifdef _WIN32
49
+ return _strdup(s);
50
+ #else
51
+ return strdup(s);
52
+ #endif
53
+ }
54
+
55
+ static int init_registry() {
56
+ if (registry == NULL) {
57
+ // Use calloc to initialize all pointer slots to NULL safely
58
+ registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
59
+ if (registry == NULL) return 0;
60
+ }
61
+ return 1;
62
+ }
63
+
47
64
  LQFTNode* create_node(void* value, uint64_t key_hash) {
48
65
  LQFTNode* node = (LQFTNode*)malloc(sizeof(LQFTNode));
66
+ if (!node) return NULL;
49
67
  node->value = value;
50
68
  node->key_hash = key_hash;
51
69
  for (int i = 0; i < 32; i++) node->children[i] = NULL;
@@ -53,6 +71,8 @@ LQFTNode* create_node(void* value, uint64_t key_hash) {
53
71
  }
54
72
 
55
73
  LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
74
+ if (!init_registry()) return NULL;
75
+
56
76
  char buffer[8192] = { 0 };
57
77
  if (value != NULL) {
58
78
  sprintf(buffer, "leaf:%s:%llu", (char*)value, (unsigned long long)key_hash);
@@ -61,23 +81,21 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
61
81
  for (int i = 0; i < 32; i++) {
62
82
  if (children && children[i]) {
63
83
  char seg_buf[32];
64
- // FIX: Adding [%d] prevents identically hashed children in different slots from merging
65
84
  sprintf(seg_buf, "[%d]%s", i, children[i]->struct_hash);
66
85
  strcat(buffer, seg_buf);
67
86
  }
68
87
  }
69
88
  }
70
89
 
71
- // 64-bit structural hash formatting
72
90
  uint64_t full_hash = fnv1a_64(buffer);
73
91
  char lookup_hash[17];
74
92
  sprintf(lookup_hash, "%016llx", (unsigned long long)full_hash);
75
93
  uint32_t idx = full_hash % REGISTRY_SIZE;
76
94
 
77
- // Linear Probing logic
78
95
  uint32_t start_idx = idx;
79
96
  while (registry[idx] != NULL) {
80
97
  if (strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
98
+ if (value) free(value);
81
99
  return registry[idx];
82
100
  }
83
101
  idx = (idx + 1) % REGISTRY_SIZE;
@@ -85,6 +103,7 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
85
103
  }
86
104
 
87
105
  LQFTNode* new_node = create_node(value, key_hash);
106
+ if (!new_node) return NULL;
88
107
  if (children) {
89
108
  for (int i = 0; i < 32; i++) new_node->children[i] = children[i];
90
109
  }
@@ -94,24 +113,33 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
94
113
  return new_node;
95
114
  }
96
115
 
97
- char* portable_strdup(const char* s) {
98
- if (!s) return NULL;
99
- #ifdef _WIN32
100
- return _strdup(s);
101
- #else
102
- return strdup(s);
103
- #endif
116
+ static PyObject* method_free_all(PyObject* self, PyObject* args) {
117
+ int freed_count = 0;
118
+ if (registry != NULL) {
119
+ for (int i = 0; i < REGISTRY_SIZE; i++) {
120
+ if (registry[i] != NULL) {
121
+ if (registry[i]->value) free(registry[i]->value);
122
+ free(registry[i]);
123
+ registry[i] = NULL;
124
+ freed_count++;
125
+ }
126
+ }
127
+ // Dynamic reclamation: Free the registry array itself
128
+ free(registry);
129
+ registry = NULL;
130
+ }
131
+ physical_node_count = 0;
132
+ global_root = NULL;
133
+ return PyLong_FromLong(freed_count);
104
134
  }
105
135
 
106
- // --- PYTHON API BRIDGE ---
107
-
108
136
  static PyObject* method_insert(PyObject* self, PyObject* args) {
109
137
  unsigned long long h;
110
138
  char* val_str;
111
139
  if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
112
140
 
113
141
  if (!global_root) {
114
- for (int i = 0; i < REGISTRY_SIZE; i++) registry[i] = NULL;
142
+ if (!init_registry()) return PyErr_NoMemory();
115
143
  global_root = get_canonical(NULL, 0, NULL);
116
144
  }
117
145
 
@@ -122,7 +150,6 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
122
150
  LQFTNode* curr = global_root;
123
151
  int bit_depth = 0;
124
152
 
125
- // 1. Traversal
126
153
  while (curr != NULL && curr->value == NULL) {
127
154
  uint32_t segment = (h >> bit_depth) & MASK;
128
155
  path_nodes[path_len] = curr;
@@ -137,16 +164,14 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
137
164
  bit_depth += BIT_PARTITION;
138
165
  }
139
166
 
140
- // 2. Node Update / Collision Logic
141
167
  LQFTNode* new_sub_node = NULL;
142
-
143
168
  if (curr == NULL) {
144
169
  new_sub_node = get_canonical(portable_strdup(val_str), h, NULL);
145
170
  } else if (curr->key_hash == h) {
146
171
  new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
147
172
  } else {
148
173
  unsigned long long old_h = curr->key_hash;
149
- char* old_val = (char*)curr->value;
174
+ char* old_val = portable_strdup((char*)curr->value);
150
175
  int temp_depth = bit_depth;
151
176
 
152
177
  while (temp_depth < MAX_BITS) {
@@ -154,30 +179,23 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
154
179
  uint32_t s_new = (h >> temp_depth) & MASK;
155
180
 
156
181
  if (s_old != s_new) {
157
- LQFTNode* c_old = get_canonical(portable_strdup(old_val), old_h, curr->children);
182
+ LQFTNode* c_old = get_canonical(old_val, old_h, curr->children);
158
183
  LQFTNode* c_new = get_canonical(portable_strdup(val_str), h, NULL);
159
-
160
184
  LQFTNode* new_children[32] = {NULL};
161
185
  new_children[s_old] = c_old;
162
186
  new_children[s_new] = c_new;
163
-
164
187
  new_sub_node = get_canonical(NULL, 0, new_children);
165
188
  break;
166
189
  } else {
167
- path_nodes[path_len] = NULL; // Marker for split
190
+ path_nodes[path_len] = NULL;
168
191
  path_segs[path_len] = s_old;
169
192
  path_len++;
170
193
  temp_depth += BIT_PARTITION;
171
194
  }
172
195
  }
173
-
174
- // Absolute Hash Collision (Rare)
175
- if (new_sub_node == NULL) {
176
- new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
177
- }
196
+ if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
178
197
  }
179
198
 
180
- // 3. Iterative Back-Propagation
181
199
  for (int i = path_len - 1; i >= 0; i--) {
182
200
  if (path_nodes[i] == NULL) {
183
201
  LQFTNode* new_children[32] = {NULL};
@@ -200,22 +218,24 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
200
218
  static PyObject* method_search(PyObject* self, PyObject* args) {
201
219
  unsigned long long h;
202
220
  if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
203
- if (!global_root) { Py_RETURN_NONE; }
221
+
222
+ if (!global_root || registry == NULL) {
223
+ Py_RETURN_NONE;
224
+ }
204
225
 
205
226
  LQFTNode* curr = global_root;
206
227
  int bit_depth = 0;
207
228
 
208
- while (curr != NULL) {
209
- if (curr->value != NULL) {
210
- if (curr->key_hash == h) return PyUnicode_FromString((char*)curr->value);
211
- Py_RETURN_NONE;
212
- }
229
+ while (curr != NULL && curr->value == NULL) {
213
230
  uint32_t segment = (h >> bit_depth) & MASK;
214
- if (curr->children[segment] == NULL) { Py_RETURN_NONE; }
215
231
  curr = curr->children[segment];
216
232
  bit_depth += BIT_PARTITION;
217
- if (bit_depth >= MAX_BITS) break;
218
233
  }
234
+
235
+ if (curr != NULL && curr->key_hash == h) {
236
+ return PyUnicode_FromString((char*)curr->value);
237
+ }
238
+
219
239
  Py_RETURN_NONE;
220
240
  }
221
241
 
@@ -224,16 +244,13 @@ static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
224
244
  }
225
245
 
226
246
  static PyMethodDef LQFTMethods[] = {
227
- {"insert", method_insert, METH_VARARGS, "Insert into C LQFT"},
228
- {"search", method_search, METH_VARARGS, "Search C LQFT"},
229
- {"get_metrics", method_get_metrics, METH_VARARGS, "Get memory metrics"},
247
+ {"insert", method_insert, METH_VARARGS, "Insert"},
248
+ {"search", method_search, METH_VARARGS, "Search"},
249
+ {"get_metrics", method_get_metrics, METH_VARARGS, "Metrics"},
250
+ {"free_all", method_free_all, METH_VARARGS, "Reclaim"},
230
251
  {NULL, NULL, 0, NULL}
231
252
  };
232
253
 
233
- static struct PyModuleDef lqftmodule = {
234
- PyModuleDef_HEAD_INIT, "lqft_c_engine", "LQFT Performance Engine", -1, LQFTMethods
235
- };
254
+ static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
236
255
 
237
- PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
238
- return PyModule_Create(&lqftmodule);
239
- }
256
+ PyMODINIT_FUNC PyInit_lqft_c_engine(void) { return PyModule_Create(&lqftmodule); }
@@ -138,7 +138,6 @@ class AdaptiveLQFT:
138
138
  self.threshold = float('inf') # Prevent continuous upgrade attempts
139
139
  return
140
140
 
141
- # print("\n[⚙️] AdaptiveLQFT: Threshold reached. Migrating to Native C-Engine...")
142
141
  for key, val in self._light_store.items():
143
142
  h = self._get_64bit_hash(key)
144
143
  lqft_c_engine.insert(h, val)
@@ -149,16 +148,16 @@ class AdaptiveLQFT:
149
148
 
150
149
  def insert(self, key, value):
151
150
  if not self.is_native:
152
- # Phase 1: Small Data Operations (Lightning fast, $O(N)$ Space)
151
+ # Phase 1: Small Data Operations
153
152
  if key not in self._light_store:
154
153
  self.size += 1
155
154
  self._light_store[key] = value
156
155
 
157
- # Check if we need to upgrade to the big guns
156
+ # Check for migration threshold
158
157
  if self.size >= self.threshold:
159
158
  self._migrate_to_native()
160
159
  else:
161
- # Phase 2: Massive Data Operations ($O(Entropy)$ Space Folding)
160
+ # Phase 2: Massive Data Operations (Native C-Heap)
162
161
  h = self._get_64bit_hash(key)
163
162
  lqft_c_engine.insert(h, value)
164
163
 
@@ -169,6 +168,28 @@ class AdaptiveLQFT:
169
168
  h = self._get_64bit_hash(key)
170
169
  return lqft_c_engine.search(h)
171
170
 
171
+ def clear(self):
172
+ """
173
+ Memory Reclamation: Manually trigger C-level heap cleanup.
174
+ In the Adaptive model, this handles both the Python dict and the C-Registry.
175
+ """
176
+ self._light_store.clear()
177
+ self.size = 0
178
+ if C_ENGINE_READY:
179
+ return lqft_c_engine.free_all()
180
+ return 0
181
+
182
+ def __del__(self):
183
+ """
184
+ Finalizer: Reclaims unmanaged C memory when the Python object is deleted.
185
+ Crucial for preventing memory leaks in long-running systems.
186
+ """
187
+ try:
188
+ self.clear()
189
+ except:
190
+ # Silence errors during late interpreter shutdown/garbage collection
191
+ pass
192
+
172
193
  def status(self):
173
194
  """Returns the current state of the engine."""
174
195
  return {
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.1.3
3
+ Version: 0.1.7
4
4
  Summary: Log-Quantum Fractal Tree: Pattern-Aware Deduplicating Data Structure
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
7
7
  License: MIT
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
- Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Operating System :: OS Independent
12
11
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
12
  Requires-Python: >=3.8
14
13
  Description-Content-Type: text/markdown
15
14
  License-File: LICENSE.md
15
+ Requires-Dist: psutil
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: description
@@ -20,6 +20,7 @@ Dynamic: description-content-type
20
20
  Dynamic: home-page
21
21
  Dynamic: license
22
22
  Dynamic: license-file
23
+ Dynamic: requires-dist
23
24
  Dynamic: requires-python
24
25
  Dynamic: summary
25
26
 
@@ -1,9 +1,11 @@
1
1
  LICENSE.md
2
2
  lqft_engine.c
3
3
  lqft_engine.py
4
+ pure_python_ds.py
4
5
  pyproject.toml
5
6
  setup.py
6
7
  lqft_python_engine.egg-info/PKG-INFO
7
8
  lqft_python_engine.egg-info/SOURCES.txt
8
9
  lqft_python_engine.egg-info/dependency_links.txt
10
+ lqft_python_engine.egg-info/requires.txt
9
11
  lqft_python_engine.egg-info/top_level.txt
@@ -1,2 +1,3 @@
1
1
  lqft_c_engine
2
2
  lqft_engine
3
+ pure_python_ds
@@ -0,0 +1,139 @@
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
@@ -13,7 +13,7 @@ if os.name == 'nt':
13
13
  else:
14
14
  extra_compile_args = ['-O3']
15
15
 
16
- # Load README for PyPI long_description (Bulletproof File Check)
16
+ # Load README for PyPI long_description
17
17
  long_description = "Log-Quantum Fractal Tree Engine"
18
18
  if os.path.exists("readme.md"):
19
19
  with open("readme.md", "r", encoding="utf-8") as fh:
@@ -31,7 +31,7 @@ lqft_extension = Extension(
31
31
 
32
32
  setup(
33
33
  name="lqft-python-engine",
34
- version="0.1.3", # Bumped version for clean PyPI upload
34
+ version="0.1.7",
35
35
  description="Log-Quantum Fractal Tree: Pattern-Aware Deduplicating Data Structure",
36
36
  long_description=long_description,
37
37
  long_description_content_type="text/markdown",
@@ -39,13 +39,12 @@ setup(
39
39
  url="https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-",
40
40
  ext_modules=[lqft_extension],
41
41
  packages=find_packages(),
42
- py_modules=["lqft_engine"],
43
- install_requires=[],
44
- license="MIT",
42
+ py_modules=["lqft_engine", "pure_python_ds"],
43
+ install_requires=['psutil'],
44
+ license="MIT",
45
45
  classifiers=[
46
46
  "Programming Language :: Python :: 3",
47
47
  "Programming Language :: Python :: 3.12",
48
- "License :: OSI Approved :: MIT License",
49
48
  "Operating System :: OS Independent",
50
49
  "Topic :: Software Development :: Libraries :: Python Modules",
51
50
  ],