hdlib 2.1.0__py3-none-any.whl
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.
- hdlib/__init__.py +16 -0
- hdlib/arithmetic/__init__.py +265 -0
- hdlib/arithmetic/quantum.py +1257 -0
- hdlib/model/__init__.py +12 -0
- hdlib/model/classification.py +1719 -0
- hdlib/model/clustering.py +172 -0
- hdlib/model/graph.py +764 -0
- hdlib/model/regression.py +306 -0
- hdlib/space.py +864 -0
- hdlib/vector.py +608 -0
- hdlib-2.1.0.data/scripts/chopin2.py +473 -0
- hdlib-2.1.0.dist-info/METADATA +137 -0
- hdlib-2.1.0.dist-info/RECORD +16 -0
- hdlib-2.1.0.dist-info/WHEEL +5 -0
- hdlib-2.1.0.dist-info/licenses/LICENSE +21 -0
- hdlib-2.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
"""Implementation of chopin2 ML model with hdlib."""
|
|
3
|
+
|
|
4
|
+
__author__ = ("Fabio Cumbo (fabio.cumbo@gmail.com)")
|
|
5
|
+
|
|
6
|
+
__version__ = "1.1.1"
|
|
7
|
+
__date__ = "Nov 7, 2025"
|
|
8
|
+
|
|
9
|
+
import argparse as ap
|
|
10
|
+
import contextlib
|
|
11
|
+
import errno
|
|
12
|
+
import os
|
|
13
|
+
import statistics
|
|
14
|
+
import time
|
|
15
|
+
from typing import List, Tuple
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from sklearn.metrics import accuracy_score, confusion_matrix, f1_score, matthews_corrcoef, precision_score, recall_score
|
|
19
|
+
from tabulate import tabulate
|
|
20
|
+
|
|
21
|
+
from hdlib.model import ClassificationModel
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def read_params():
|
|
25
|
+
"""Read and test the input arguments.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
argparse.ArgumentParser
|
|
30
|
+
The ArgumentParser object
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
p = ap.ArgumentParser(
|
|
34
|
+
prog="chopin2",
|
|
35
|
+
description="chopin2 powered by hdlib",
|
|
36
|
+
formatter_class=ap.ArgumentDefaultsHelpFormatter,
|
|
37
|
+
)
|
|
38
|
+
p.add_argument(
|
|
39
|
+
"--input",
|
|
40
|
+
type=os.path.abspath,
|
|
41
|
+
required=True,
|
|
42
|
+
help="Path to the input matrix",
|
|
43
|
+
)
|
|
44
|
+
p.add_argument(
|
|
45
|
+
"--fieldsep",
|
|
46
|
+
type=str,
|
|
47
|
+
default="\t",
|
|
48
|
+
help="Input field separator",
|
|
49
|
+
)
|
|
50
|
+
p.add_argument(
|
|
51
|
+
"--dimensionality",
|
|
52
|
+
type=int,
|
|
53
|
+
default=10000,
|
|
54
|
+
help="Vectors dimensionality",
|
|
55
|
+
)
|
|
56
|
+
p.add_argument(
|
|
57
|
+
"--levels",
|
|
58
|
+
type=int,
|
|
59
|
+
required=True,
|
|
60
|
+
help="Number of HD levels",
|
|
61
|
+
)
|
|
62
|
+
p.add_argument(
|
|
63
|
+
"--kfolds",
|
|
64
|
+
type=int,
|
|
65
|
+
default=0,
|
|
66
|
+
help="Number of folds for cross-validating the classification model",
|
|
67
|
+
)
|
|
68
|
+
p.add_argument(
|
|
69
|
+
"--test-percentage",
|
|
70
|
+
type=float,
|
|
71
|
+
default=0.0,
|
|
72
|
+
dest="test_percentage",
|
|
73
|
+
help="Percentage of data points for defining the test set",
|
|
74
|
+
)
|
|
75
|
+
p.add_argument(
|
|
76
|
+
"--feature-selection",
|
|
77
|
+
type=str.lower,
|
|
78
|
+
choices=["forward", "backward"],
|
|
79
|
+
dest="feature_selection",
|
|
80
|
+
help="Run the feature selection and report a ranking of features based on their importance",
|
|
81
|
+
)
|
|
82
|
+
p.add_argument(
|
|
83
|
+
"--retrain",
|
|
84
|
+
type=int,
|
|
85
|
+
default=0,
|
|
86
|
+
help="Number of retraining iterations",
|
|
87
|
+
)
|
|
88
|
+
p.add_argument(
|
|
89
|
+
"--threshold",
|
|
90
|
+
type=float,
|
|
91
|
+
default=0.6,
|
|
92
|
+
help="Threshold on the accuracy score. Used in conjunction with --feature-selection",
|
|
93
|
+
)
|
|
94
|
+
p.add_argument(
|
|
95
|
+
"--uncertainty",
|
|
96
|
+
type=float,
|
|
97
|
+
default=5.0,
|
|
98
|
+
help="Uncertainty percentage. Used in conjunction with --feature-selection",
|
|
99
|
+
)
|
|
100
|
+
p.add_argument(
|
|
101
|
+
"--nproc",
|
|
102
|
+
type=int,
|
|
103
|
+
default=1,
|
|
104
|
+
help="Make it parallel when possible",
|
|
105
|
+
)
|
|
106
|
+
p.add_argument(
|
|
107
|
+
"--output",
|
|
108
|
+
type=os.path.abspath,
|
|
109
|
+
default=None,
|
|
110
|
+
help="Path to the output file (full path). If not specified, output is printed to stdout",
|
|
111
|
+
)
|
|
112
|
+
p.add_argument(
|
|
113
|
+
"-v",
|
|
114
|
+
"--version",
|
|
115
|
+
action="version",
|
|
116
|
+
version="chopin2 (hdlib) version {} ({})".format(__version__, __date__),
|
|
117
|
+
help="Print the tool version and exit",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return p.parse_args()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def load_dataset(filepath: os.path.abspath, sep: str="\t") -> Tuple[List[str], List[List[float]], List[str]]:
|
|
124
|
+
"""Load the input numerical dataset.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
filepath : str
|
|
129
|
+
Path to the input dataset.
|
|
130
|
+
sep : str
|
|
131
|
+
Filed separator for the input dataset.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
tuple
|
|
136
|
+
A tuple with a list of sample IDs, a list of features, a list of lists with the
|
|
137
|
+
actual numerical data (floats), and a list with class labels.
|
|
138
|
+
|
|
139
|
+
Raises
|
|
140
|
+
------
|
|
141
|
+
FileNotFoundError
|
|
142
|
+
If the input file does not exist.
|
|
143
|
+
ValueError
|
|
144
|
+
If the input dataset does not contain number only.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
if not os.path.isfile(filepath):
|
|
148
|
+
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), filepath)
|
|
149
|
+
|
|
150
|
+
samples = list()
|
|
151
|
+
content = list()
|
|
152
|
+
classes = list()
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
with open(filepath) as infile:
|
|
156
|
+
# Trip the first and last column out
|
|
157
|
+
features = infile.readline().rstrip().split(sep)[1:-1]
|
|
158
|
+
|
|
159
|
+
for line in infile:
|
|
160
|
+
line = line.strip()
|
|
161
|
+
|
|
162
|
+
if line and not line.startswith("#"):
|
|
163
|
+
line_split = line.split(sep)
|
|
164
|
+
|
|
165
|
+
# Add sample ID
|
|
166
|
+
samples.append(line_split[0])
|
|
167
|
+
|
|
168
|
+
row_data = [float(value) for value in line_split[1:-1]]
|
|
169
|
+
|
|
170
|
+
# Add row
|
|
171
|
+
content.append(row_data)
|
|
172
|
+
|
|
173
|
+
# Take track of the class
|
|
174
|
+
classes.append(line_split[-1])
|
|
175
|
+
|
|
176
|
+
except ValueError as e:
|
|
177
|
+
raise Exception("The input dataset must contain numbers only!").with_traceback(e.__traceback__)
|
|
178
|
+
|
|
179
|
+
return samples, features, content, classes
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def percentage_split(labels: List[str], percentage: float, seed: int=0) -> List[int]:
|
|
183
|
+
"""Given list of classes as appear in the original dataset and a percentage number, split a dataset and
|
|
184
|
+
report the indices of the selected data points.
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
labels : list
|
|
189
|
+
List of class labels as they appear in the original dataset.
|
|
190
|
+
percentage : float
|
|
191
|
+
Percentage of points to split out of the original dataset.
|
|
192
|
+
seed : int
|
|
193
|
+
Random seed for reproducing the same results.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
list
|
|
198
|
+
A list with the indices of selected points.
|
|
199
|
+
|
|
200
|
+
Raises
|
|
201
|
+
------
|
|
202
|
+
ValueError
|
|
203
|
+
- if the input `percentage` is lower than or equal to 0.0 or greater than 100.0;
|
|
204
|
+
- if the input `seed` is not an integer number.
|
|
205
|
+
|
|
206
|
+
Examples
|
|
207
|
+
--------
|
|
208
|
+
>>> from hdlib.parser import percentage_split
|
|
209
|
+
>>> labels = [1, 2, 2, 2, 1, 1, 1, 1, 2, 2]
|
|
210
|
+
>>> percentage_split(labels, 20.0, seed=0)
|
|
211
|
+
[6, 9]
|
|
212
|
+
|
|
213
|
+
Consider a dataset with 10 data points, select 20% of the points (2 points in this case),
|
|
214
|
+
and report their indices in the original dataset.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
if percentage <= 0.0 or percentage > 100.0:
|
|
218
|
+
raise ValueError("Percentage must be greater than 0 and lower than or equal to 100")
|
|
219
|
+
|
|
220
|
+
if not isinstance(seed, int):
|
|
221
|
+
raise ValueError("The input seed must be an integer number")
|
|
222
|
+
|
|
223
|
+
unique_labels = list(set(labels))
|
|
224
|
+
|
|
225
|
+
if len(unique_labels) < 2:
|
|
226
|
+
raise ValueError("The list of class labels must contain at least two unique lables")
|
|
227
|
+
|
|
228
|
+
rand = np.random.default_rng(seed=seed)
|
|
229
|
+
|
|
230
|
+
selection = list()
|
|
231
|
+
|
|
232
|
+
for label in unique_labels:
|
|
233
|
+
# Get a specific percentage of the data points for a specific class
|
|
234
|
+
select_points = percentage * labels.count(label) / 100.0
|
|
235
|
+
|
|
236
|
+
# Retrieve the indices of the samples under a specific class in the original dataset
|
|
237
|
+
indices = [pos for pos, val in enumerate(labels) if val == label]
|
|
238
|
+
|
|
239
|
+
# Finally subsample the list of indices according to the specific percentage
|
|
240
|
+
selection.extend([indices[i] for i in rand.choice(len(indices), int(select_points), replace=False)])
|
|
241
|
+
|
|
242
|
+
return sorted(selection)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def chopin2():
|
|
246
|
+
"""Domain-agnostic supervised learning with hyperdimensional computing.
|
|
247
|
+
|
|
248
|
+
Notes
|
|
249
|
+
-----
|
|
250
|
+
chopin2 is available in GitHub at https://github.com/cumbof/chopin2 and its ML model is described
|
|
251
|
+
in the following scientific article:
|
|
252
|
+
|
|
253
|
+
Cumbo F, Cappelli E, Weitschek E.
|
|
254
|
+
A brain-inspired hyperdimensional computing approach for classifying massive dna methylation data of cancer
|
|
255
|
+
Algorithms. 2020 Sep 17;13(9):233
|
|
256
|
+
https://doi.org/10.3390/a13090233
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
# Load command line parameters
|
|
260
|
+
args = read_params()
|
|
261
|
+
|
|
262
|
+
if args.feature_selection and args.kfolds == 0:
|
|
263
|
+
raise Exception("The --feature-selection option can only be used in conjunction with --kfolds")
|
|
264
|
+
|
|
265
|
+
if args.kfolds == 0 and args.test_percentage == 0.0:
|
|
266
|
+
raise Exception(
|
|
267
|
+
(
|
|
268
|
+
"Please use --kfolds if you want to cross-validate your model. "
|
|
269
|
+
"Otherwise, use --test-percentage to specify the percentage of data points for the test set. "
|
|
270
|
+
"Use --help for other options"
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
if args.nproc < 1:
|
|
275
|
+
args.nproc = os.cpu_count()
|
|
276
|
+
|
|
277
|
+
# Load the input matrix
|
|
278
|
+
print("Loading dataset")
|
|
279
|
+
|
|
280
|
+
_, features, content, classes = load_dataset(args.input, sep=args.fieldsep)
|
|
281
|
+
|
|
282
|
+
class_labels = sorted(list(set(classes)))
|
|
283
|
+
|
|
284
|
+
print("Points: {}; Features {}; Classes {}".format(len(content), len(features), len(class_labels)))
|
|
285
|
+
|
|
286
|
+
# Initialise the model
|
|
287
|
+
print("Building the HD model")
|
|
288
|
+
|
|
289
|
+
model = ClassificationModel(size=args.dimensionality, levels=args.levels, vtype="bipolar")
|
|
290
|
+
|
|
291
|
+
if args.feature_selection:
|
|
292
|
+
print("Selecting features.. This may take a while\n")
|
|
293
|
+
|
|
294
|
+
# Run the feature selection
|
|
295
|
+
importances, scores, best_importance, count_models = model.stepwise_regression(
|
|
296
|
+
content,
|
|
297
|
+
features,
|
|
298
|
+
classes,
|
|
299
|
+
method=args.feature_selection,
|
|
300
|
+
cv=args.kfolds,
|
|
301
|
+
distance_method="cosine",
|
|
302
|
+
retrain=args.retrain,
|
|
303
|
+
n_jobs=args.nproc,
|
|
304
|
+
metric="accuracy",
|
|
305
|
+
threshold=args.threshold,
|
|
306
|
+
uncertainty=args.uncertainty
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# Print features in ascending order on their score
|
|
310
|
+
table = [["Feature", "Importance"]]
|
|
311
|
+
|
|
312
|
+
for feature in sorted(importances.keys(), key=lambda f: importances[f]):
|
|
313
|
+
table.append([feature, importances[feature]])
|
|
314
|
+
|
|
315
|
+
print(tabulate(table, headers="firstrow", tablefmt="simple"))
|
|
316
|
+
|
|
317
|
+
print()
|
|
318
|
+
|
|
319
|
+
# Also print the score for each importance level
|
|
320
|
+
table = [["Importance", "Score (accuracy)"]]
|
|
321
|
+
|
|
322
|
+
for imp in sorted(scores.keys()):
|
|
323
|
+
table.append([imp, "{:.4f}".format(scores[imp])])
|
|
324
|
+
|
|
325
|
+
print(tabulate(table, headers="firstrow", tablefmt="simple"))
|
|
326
|
+
|
|
327
|
+
print("\nBest importance: {}".format(best_importance))
|
|
328
|
+
|
|
329
|
+
# Select features based on the best importance
|
|
330
|
+
if args.feature_selection == "backward":
|
|
331
|
+
selected_features = [feature for feature in importances if importances[feature] <= best_importance]
|
|
332
|
+
|
|
333
|
+
elif args.feature_selection == "forward":
|
|
334
|
+
selected_features = [feature for feature in importances if importances[feature] >= best_importance]
|
|
335
|
+
|
|
336
|
+
print("Selected features: {}\n".format(len(selected_features)))
|
|
337
|
+
|
|
338
|
+
# Also print the score for each importance level
|
|
339
|
+
table = [["Features"]]
|
|
340
|
+
|
|
341
|
+
for feature in selected_features:
|
|
342
|
+
table.append([feature])
|
|
343
|
+
|
|
344
|
+
print(tabulate(table, headers="firstrow", tablefmt="simple"))
|
|
345
|
+
|
|
346
|
+
print("\nTotal ML models: {}".format(count_models))
|
|
347
|
+
|
|
348
|
+
# Replace features with their positions in the original list of features
|
|
349
|
+
selected_features = [features.index(feature) for feature in selected_features]
|
|
350
|
+
|
|
351
|
+
print("\nBuilding a model with the selected features only")
|
|
352
|
+
|
|
353
|
+
# Reshape content by considering the selected features only
|
|
354
|
+
content = [[value for position, value in enumerate(sample) if position in selected_features] for sample in content]
|
|
355
|
+
|
|
356
|
+
# Fit the model
|
|
357
|
+
model.fit(content, classes)
|
|
358
|
+
|
|
359
|
+
if args.kfolds > 0:
|
|
360
|
+
# Predict in cross-validation
|
|
361
|
+
print("Cross-validating model with {} folds\n".format(args.kfolds))
|
|
362
|
+
|
|
363
|
+
predictions = model.cross_val_predict(
|
|
364
|
+
content,
|
|
365
|
+
classes,
|
|
366
|
+
cv=args.kfolds,
|
|
367
|
+
distance_method="cosine",
|
|
368
|
+
retrain=args.retrain,
|
|
369
|
+
n_jobs=args.nproc
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
elif args.test_percentage > 0.0:
|
|
373
|
+
# Predict with a percentage-split
|
|
374
|
+
print("Percentage-split: training={}% test={}%\n".format(100.0 - args.test_percentage, args.test_percentage))
|
|
375
|
+
|
|
376
|
+
test_indices = percentage_split(classes, args.test_percentage)
|
|
377
|
+
|
|
378
|
+
predictions = [
|
|
379
|
+
model.predict(
|
|
380
|
+
test_indices,
|
|
381
|
+
distance_method="cosine",
|
|
382
|
+
retrain=args.retrain
|
|
383
|
+
)
|
|
384
|
+
]
|
|
385
|
+
|
|
386
|
+
# For each prediction, compute the Accuracy, F1, Precision, Recall, AUC
|
|
387
|
+
accuracy_scores = list()
|
|
388
|
+
f1_scores = list()
|
|
389
|
+
precision_scores = list()
|
|
390
|
+
recall_scores = list()
|
|
391
|
+
mcc_scores = list()
|
|
392
|
+
|
|
393
|
+
retraining_iterations = list()
|
|
394
|
+
error_rates = list()
|
|
395
|
+
|
|
396
|
+
print("Class labels: {}\n".format(class_labels))
|
|
397
|
+
|
|
398
|
+
for fold, (y_indices, y_pred, _, retrainings, error_rate, _) in enumerate(predictions):
|
|
399
|
+
# Produce the confusion matrix for each fold
|
|
400
|
+
print("Fold {} ({} retrainings)".format(fold + 1, retrainings))
|
|
401
|
+
retraining_iterations.append(retrainings)
|
|
402
|
+
|
|
403
|
+
print("\tError rate: {}".format(error_rate))
|
|
404
|
+
error_rates.append(error_rate)
|
|
405
|
+
|
|
406
|
+
y_true = [classes[position] for position in y_indices]
|
|
407
|
+
|
|
408
|
+
fold_accuracy = accuracy_score(y_true, y_pred)
|
|
409
|
+
print("\tAccuracy: {}".format("{:.4f}".format(fold_accuracy)))
|
|
410
|
+
accuracy_scores.append(fold_accuracy)
|
|
411
|
+
|
|
412
|
+
fold_f1 = f1_score(y_true, y_pred, average="weighted")
|
|
413
|
+
print("\tF1: {}".format("{:.4f}".format(fold_f1)))
|
|
414
|
+
f1_scores.append(fold_f1)
|
|
415
|
+
|
|
416
|
+
fold_precision = precision_score(y_true, y_pred, average="weighted")
|
|
417
|
+
print("\tPrecision: {}".format("{:.4f}".format(fold_precision)))
|
|
418
|
+
precision_scores.append(fold_precision)
|
|
419
|
+
|
|
420
|
+
fold_recall = recall_score(y_true, y_pred, average="weighted")
|
|
421
|
+
print("\tRecall: {}".format("{:.4f}".format(fold_recall)))
|
|
422
|
+
recall_scores.append(fold_recall)
|
|
423
|
+
|
|
424
|
+
fold_mcc = matthews_corrcoef(y_true, y_pred)
|
|
425
|
+
print("\tMatthews Corr. Coeff.: {}".format("{:.4f}".format(fold_mcc)))
|
|
426
|
+
mcc_scores.append(fold_mcc)
|
|
427
|
+
|
|
428
|
+
print("\tConfusion Matrix:")
|
|
429
|
+
if len(class_labels) > 2:
|
|
430
|
+
for row in confusion_matrix(y_true, y_pred, labels=class_labels):
|
|
431
|
+
print("\t\t{}".format(row))
|
|
432
|
+
|
|
433
|
+
else:
|
|
434
|
+
tn, fp, fn, tp = confusion_matrix(y_true, y_pred, labels=class_labels).ravel()
|
|
435
|
+
|
|
436
|
+
print("\t\tTN: {}".format(tn))
|
|
437
|
+
print("\t\tFP: {}".format(fp))
|
|
438
|
+
print("\t\tFN: {}".format(fn))
|
|
439
|
+
print("\t\tTP: {}".format(tp))
|
|
440
|
+
|
|
441
|
+
print()
|
|
442
|
+
|
|
443
|
+
for score_label, score_values in zip(
|
|
444
|
+
["Retrainings", "Error Rate", "Accuracy", "F1", "Precision", "Recall", "Matthews Corr. Coeff."],
|
|
445
|
+
[retraining_iterations, error_rates, accuracy_scores, f1_scores, precision_scores, recall_scores, mcc_scores]
|
|
446
|
+
):
|
|
447
|
+
print(
|
|
448
|
+
"{}: {:.4f}{}".format(
|
|
449
|
+
score_label,
|
|
450
|
+
statistics.mean(score_values),
|
|
451
|
+
" ({:.4f} stdev)".format(statistics.stdev(score_values)) if len(score_values) > 1 else ""
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
if __name__ == "__main__":
|
|
457
|
+
# Pre-parse --output only so redirection is set up before full argument parsing
|
|
458
|
+
_pre = ap.ArgumentParser(add_help=False)
|
|
459
|
+
_pre.add_argument("--output", default=None)
|
|
460
|
+
_output_arg, _ = _pre.parse_known_args()
|
|
461
|
+
|
|
462
|
+
t0 = time.time()
|
|
463
|
+
|
|
464
|
+
if _output_arg.output:
|
|
465
|
+
with open(_output_arg.output, "w") as _outfile, contextlib.redirect_stdout(_outfile):
|
|
466
|
+
chopin2()
|
|
467
|
+
t1 = time.time()
|
|
468
|
+
print("Total elapsed time: {}s".format(int(t1 - t0)))
|
|
469
|
+
print("Output written to: {}".format(_output_arg.output))
|
|
470
|
+
else:
|
|
471
|
+
chopin2()
|
|
472
|
+
t1 = time.time()
|
|
473
|
+
print("Total elapsed time: {}s".format(int(t1 - t0)))
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hdlib
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: Hyperdimensional Computing Library for building Vector Symbolic Architectures in Python
|
|
5
|
+
Author-email: Fabio Cumbo <fabio.cumbo@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/cumbof/hdlib
|
|
8
|
+
Project-URL: Issues, https://github.com/cumbof/hdlib/issues
|
|
9
|
+
Project-URL: Source, https://github.com/cumbof/hdlib
|
|
10
|
+
Project-URL: Wiki, https://github.com/cumbof/hdlib/wiki
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: mthree>=3.0.0
|
|
24
|
+
Requires-Dist: numpy>=2.3.4
|
|
25
|
+
Requires-Dist: qiskit>=2.2.1
|
|
26
|
+
Requires-Dist: qiskit-aer>=0.17.2
|
|
27
|
+
Requires-Dist: qiskit-ibm-runtime>=0.42.0
|
|
28
|
+
Requires-Dist: scikit-learn>=1.7.2
|
|
29
|
+
Requires-Dist: scipy>=1.16.2
|
|
30
|
+
Requires-Dist: tabulate>=0.9.0
|
|
31
|
+
Provides-Extra: examples
|
|
32
|
+
Requires-Dist: qiskit_machine_learning>=0.8.4; extra == "examples"
|
|
33
|
+
Provides-Extra: test
|
|
34
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
37
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# hdlib
|
|
42
|
+
|
|
43
|
+
Hyperdimensional Computing Library for building Vector-Symbolic Architectures in Python 3.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
[](https://doi.org/10.21105/joss.05704)
|
|
47
|
+
[](https://doi.org/10.5281/zenodo.7996502)
|
|
48
|
+
|
|
49
|
+
Vector-Symbolic Architectures (VSA, a.k.a. Hyperdimensional Computing) is an emergent computing paradigm that works by combining vectors in a high-dimensional space for representing and processing information. This approach recently shown promise in various domains for dealing with different kind of computational problems, including artificial intelligence, cognitive science, robotics, natural language processing, bioinformatics, medical informatics, cheminformatics, and internet of things among other scientific disciplines.
|
|
50
|
+
|
|
51
|
+
Here we present _hdlib_, a Python library for designing Vector-Symbolic Architectures. It is distributed under the MIT license as a Python package through PyPI and Conda on the _conda-forge_ channel.
|
|
52
|
+
|
|
53
|
+
GitHub releases are also available on Zenodo at [https://doi.org/10.5281/zenodo.7996502](https://doi.org/10.5281/zenodo.7996502).
|
|
54
|
+
|
|
55
|
+
Please refer to the official [Wiki](https://github.com/cumbof/hdlib/wiki) for any information about the implemented modules and how to use the library.
|
|
56
|
+
|
|
57
|
+
Here is the table of content:
|
|
58
|
+
|
|
59
|
+
- [Getting started](https://github.com/cumbof/hdlib/wiki/Getting-started)
|
|
60
|
+
- [Installing `hdlib`](https://github.com/cumbof/hdlib/wiki/Getting-started#installing-hdlib)
|
|
61
|
+
- [Dependencies](https://github.com/cumbof/hdlib/wiki/Getting-started#dependencies)
|
|
62
|
+
- [Vector-Symbolic Architectures](https://github.com/cumbof/hdlib/wiki/Vector-Symbolic-Architectures)
|
|
63
|
+
- [Hyperdimensional Vectors and Space](https://github.com/cumbof/hdlib/wiki/Vector-Symbolic-Architectures#hyperdimensional-vectors-and-space)
|
|
64
|
+
- [Arithmetic operations](https://github.com/cumbof/hdlib/wiki/Vector-Symbolic-Architectures#arithmetic-operations)
|
|
65
|
+
- [Examples](https://github.com/cumbof/hdlib/wiki/Examples)
|
|
66
|
+
- [What is the Dollar of Mexico?](https://github.com/cumbof/hdlib/wiki/Examples#what-is-the-dollar-of-mexico)
|
|
67
|
+
- [Classification Model](https://github.com/cumbof/hdlib/wiki/Examples#classification-model)
|
|
68
|
+
- [Stepwise Feature Selection](https://github.com/cumbof/hdlib/wiki/Examples#stepwise-feature-selection)
|
|
69
|
+
- [Graph Encoding](https://github.com/cumbof/hdlib/wiki/Examples#graph-encoding)
|
|
70
|
+
- [Regression Model](https://github.com/cumbof/hdlib/wiki/Examples#regression-model)
|
|
71
|
+
- [Clustering](https://github.com/cumbof/hdlib/wiki/Examples#clustering)
|
|
72
|
+
- [Support and contributions](https://github.com/cumbof/hdlib/wiki/Support-and-contributions)
|
|
73
|
+
|
|
74
|
+
## Agent Skills
|
|
75
|
+
|
|
76
|
+
Want to use `hdlib` with an LLM coding assistant? The [**hdlib-skills**](https://github.com/cumbof/hdlib-skills) repository provides a collection of [Agent Skills](https://github.com/cumbof/hdlib-skills) that teach LLM agents how to use the library effectively.
|
|
77
|
+
|
|
78
|
+
The skills cover foundational concepts (vectors, space, arithmetic, and distance operations), machine learning models (classification, clustering, regression, graph encoding, and feature selection), quantum hyperdimensional computing, and common usage patterns (analogical reasoning, data encoding, and troubleshooting).
|
|
79
|
+
|
|
80
|
+
They are compatible with any tool that supports the Agent Skills standard. See the [hdlib-skills](https://github.com/cumbof/hdlib-skills) repository for installation and usage instructions.
|
|
81
|
+
|
|
82
|
+
## Credits
|
|
83
|
+
|
|
84
|
+
Please credit our work in your manuscript by citing:
|
|
85
|
+
|
|
86
|
+
```bibtex
|
|
87
|
+
@article{cumbo2023hdlib,
|
|
88
|
+
title = {hdlib: A python library for designing Vector-Symbolic Architectures},
|
|
89
|
+
author = {Cumbo, Fabio and Weitschek, Emanuel and Blankenberg, Daniel},
|
|
90
|
+
journal = {Journal of Open Source Software},
|
|
91
|
+
volume = {8},
|
|
92
|
+
number = {89},
|
|
93
|
+
pages = {5704},
|
|
94
|
+
year = {2023},
|
|
95
|
+
doi = {10.21105/joss.05704}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@misc{cumbo2026hdlib,
|
|
99
|
+
title = {hdlib 2.0: Extending Machine Learning Capabilities of Vector-Symbolic Architectures},
|
|
100
|
+
author = {Fabio Cumbo and Kabir Dhillon and Daniel Blankenberg},
|
|
101
|
+
year = {2026},
|
|
102
|
+
eprint = {2601.02509},
|
|
103
|
+
archivePrefix = {arXiv},
|
|
104
|
+
primaryClass = {cs.LG},
|
|
105
|
+
url = {https://arxiv.org/abs/2601.02509}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Other publications
|
|
110
|
+
|
|
111
|
+
`hdlib` has been cited in the following selected publications. If you have used our library in your research, we would love to hear from you!
|
|
112
|
+
|
|
113
|
+
> Cumbo et al., (2020). A brain-inspired hyperdimensional computing approach for classifying massive DNA methylation data of cancer. _Algorithms_, 13(9), 233. https://doi.org/10.3390/a13090233
|
|
114
|
+
>
|
|
115
|
+
> Cumbo et al., (2025). Feature selection with vector-symbolic architectures: a case study on microbial profiles of shotgun metagenomic samples of colorectal cancer. _Briefings in Bioinformatics_, 26(2), bbaf177. https://doi.org/10.1093/bib/bbaf177
|
|
116
|
+
>
|
|
117
|
+
> Joshi et al., (2025). Large-scale classification of metagenomic samples: a comparative analysis of classical machine learning techniques vs a novel brain-inspired hyperdimensional computing approach. _bioRxiv_, 2025-07. https://doi.org/10.1101/2025.07.06.663394
|
|
118
|
+
>
|
|
119
|
+
> Cumbo et al., (2025). Hyperdimensional computing in biomedical sciences: a brief review. _PeerJ Computer Science_, 11, e2885. https://doi.org/10.7717/peerj-cs.2885
|
|
120
|
+
>
|
|
121
|
+
> Cumbo et al., (2026). A novel Vector-Symbolic Architecture for graph encoding and its application to viral pangenome-based species classification. _BioData Mining_, 2026-05. https://doi.org/10.1186/s13040-026-00561-1
|
|
122
|
+
>
|
|
123
|
+
> Cumbo et al., (2026). Quantum Hyperdimensional Computing: a foundational paradigm for quantum neuromorphic architectures. _npj Unconventional Computing_, 3(1), 21. https://doi.org/10.1038/s44335-026-00064-6
|
|
124
|
+
>
|
|
125
|
+
> Cumbo et al., (2026). Designing vector-symbolic architectures for biomedical applications: ten tips and common pitfalls. _PeerJ Computer Science_, 12, e3682. https://doi.org/10.7717/peerj-cs.3682
|
|
126
|
+
>
|
|
127
|
+
> Cumbo et al., (2026). Predicting the toxicity of chemical compounds via Hyperdimensional Computing. _Molecular Informatics_, 45(9), e70052. https://doi.org/10.1002/minf.70052
|
|
128
|
+
|
|
129
|
+
## Support and contributions
|
|
130
|
+
|
|
131
|
+
Long-term discussion and bug reports are maintained via [GitHub Issues](https://github.com/cumbof/hdlib/issues), while code review is managed via [GitHub Pull Requests](https://github.com/cumbof/hdlib/pulls).
|
|
132
|
+
|
|
133
|
+
Please, (i) be sure that there are no existing issues/PR concerning the same bug or improvement before opening a new issue/PR; (ii) write a clear and concise description of what the bug/PR is about; (iii) specifying the list of steps to reproduce the behavior in addition to versions and other technical details is highly recommended.
|
|
134
|
+
|
|
135
|
+
For additional information about how to contribute, please visit the [CONTRIBUTING](https://github.com/cumbof/hdlib/blob/main/CONTRIBUTING.md) section.
|
|
136
|
+
|
|
137
|
+
Copyright © 2025 [Fabio Cumbo](https://github.com/cumbof). See [LICENSE](https://github.com/cumbof/hdlib/blob/main/LICENSE) for additional details.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
hdlib/__init__.py,sha256=g9mnTtKKnjq9rCSPMUxNMMZiGPlGnsHnU85XjvlIYJg,971
|
|
2
|
+
hdlib/space.py,sha256=n_lugViNaEEba4_YxwiKvCE08dBwkYi9hRgjY6TQRsY,27851
|
|
3
|
+
hdlib/vector.py,sha256=FVM-u3ZsVshnYxntwHBbeGjzD3-Jkfqu0TYWHRrQKV8,19522
|
|
4
|
+
hdlib/arithmetic/__init__.py,sha256=8hsuBDcZaTOu3DlOxkq_YEczItPOw1pWYVFWYbcWvKU,8631
|
|
5
|
+
hdlib/arithmetic/quantum.py,sha256=hOI1CTDTUpzYlm-k7ClSmJQPY_8P89sf1nPoVTtrpPE,47178
|
|
6
|
+
hdlib/model/__init__.py,sha256=IgKxeCkbsafRHxyAc9VBBMwc0mknIeKHEC-9nMgrEzs,480
|
|
7
|
+
hdlib/model/classification.py,sha256=MZmCcd30EOsGVDnTA_yJm7EzM2f-FtEVxOkni2znzL8,65676
|
|
8
|
+
hdlib/model/clustering.py,sha256=SRrszF-4jehb-qM4wUh5CZt1VdVGUVRyF-1BTOEZ_x8,6054
|
|
9
|
+
hdlib/model/graph.py,sha256=SQm-3tHlZV6kVHJU2F5CLGd_EZqr5MA-lYKSWDTHy-w,29029
|
|
10
|
+
hdlib/model/regression.py,sha256=ZuPMc2aNaQnt2htTCwN06hgDERysN5_JsvElLHISFWo,12187
|
|
11
|
+
hdlib-2.1.0.data/scripts/chopin2.py,sha256=fQfqZFdoiv3mutM3PMrsKSPu9HsaPO5ZUg8tpZE-tZ0,15163
|
|
12
|
+
hdlib-2.1.0.dist-info/licenses/LICENSE,sha256=xkysxBzIkuF29D7Bx4jMZ0gHs9lXByEH68cGA-Q9SyA,1068
|
|
13
|
+
hdlib-2.1.0.dist-info/METADATA,sha256=YeWGbICKb2F-HY6wiBAAeY5yiSRJxL3nikXrdCTB3dk,8627
|
|
14
|
+
hdlib-2.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
15
|
+
hdlib-2.1.0.dist-info/top_level.txt,sha256=v-fN9sWXMqxwB1KBgCMT7oEj3MLsuiQMgV6BI6VIZ3c,6
|
|
16
|
+
hdlib-2.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Fabio Cumbo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hdlib
|