PyHierarchicalTsetlinMachineCUDA 0.3.1__tar.gz → 0.3.3__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.
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA/kernels.py +81 -154
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA/tm.py +60 -44
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA/utils.py +30 -8
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA.egg-info/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/README.md +2 -2
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/setup.py +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/LICENSE +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA/__init__.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA/tools.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA.egg-info/SOURCES.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA.egg-info/dependency_links.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA.egg-info/requires.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/PyHierarchicalTsetlinMachineCUDA.egg-info/top_level.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.3}/setup.cfg +0 -0
|
@@ -41,6 +41,21 @@ code_header = """
|
|
|
41
41
|
code_update = """
|
|
42
42
|
extern "C"
|
|
43
43
|
{
|
|
44
|
+
|
|
45
|
+
// Counts number of include actions for a given clause component
|
|
46
|
+
__device__ inline int number_of_include_actions(unsigned int *ta_state)
|
|
47
|
+
{
|
|
48
|
+
int number_of_include_actions = 0;
|
|
49
|
+
for (int k = 0; k < TA_CHUNKS_PER_LEAF-1; ++k) {
|
|
50
|
+
unsigned int ta_pos = k*STATE_BITS + STATE_BITS-1;
|
|
51
|
+
number_of_include_actions += __popc(ta_state[ta_pos]);
|
|
52
|
+
}
|
|
53
|
+
unsigned int ta_pos = (TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS-1;
|
|
54
|
+
number_of_include_actions += __popc(ta_state[ta_pos] & FILTER_HIERARCHICAL);
|
|
55
|
+
|
|
56
|
+
return(number_of_include_actions);
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
// Increment the states of each of those 32 Tsetlin Automata flagged in the active bit vector.
|
|
45
60
|
__device__ inline void inc(unsigned int *ta_state, int chunk, unsigned int active)
|
|
46
61
|
{
|
|
@@ -94,8 +109,14 @@ code_update = """
|
|
|
94
109
|
|
|
95
110
|
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
96
111
|
|
|
97
|
-
float
|
|
98
|
-
if
|
|
112
|
+
float update_probability;
|
|
113
|
+
#if CONSTANT_UPDATE_P == 1
|
|
114
|
+
update_probability = 1.0;
|
|
115
|
+
#else
|
|
116
|
+
update_probability = fabsf(y - class_sum)/(2*THRESHOLD);
|
|
117
|
+
#endif
|
|
118
|
+
|
|
119
|
+
if (curand_uniform(localState) <= update_probability) {
|
|
99
120
|
if (target*sign > 0) {
|
|
100
121
|
if (clause_output && abs(*clause_weight) < INT_MAX) {
|
|
101
122
|
(*clause_weight) += sign;
|
|
@@ -124,10 +145,19 @@ code_update = """
|
|
|
124
145
|
|
|
125
146
|
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
126
147
|
|
|
127
|
-
float
|
|
128
|
-
if
|
|
148
|
+
float update_probability;
|
|
149
|
+
#if CONSTANT_UPDATE_P == 1
|
|
150
|
+
update_probability = 1.0;
|
|
151
|
+
#else
|
|
152
|
+
update_probability = fabsf(y - class_sum)/(2*THRESHOLD);
|
|
153
|
+
#endif
|
|
154
|
+
|
|
155
|
+
if (curand_uniform(localState) <= update_probability) {
|
|
129
156
|
if (target*sign > 0) {
|
|
130
157
|
// Type I Feedback
|
|
158
|
+
|
|
159
|
+
int included_literals = number_of_include_actions(ta_state);
|
|
160
|
+
|
|
131
161
|
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
|
|
132
162
|
// Generate random bit values
|
|
133
163
|
unsigned int la_feedback = 0;
|
|
@@ -137,7 +167,7 @@ code_update = """
|
|
|
137
167
|
}
|
|
138
168
|
}
|
|
139
169
|
|
|
140
|
-
if (component_output) {
|
|
170
|
+
if (component_output && included_literals <= LITERAL_BUDGET) {
|
|
141
171
|
#if BOOST_TRUE_POSITIVE_FEEDBACK == 1
|
|
142
172
|
inc(ta_state, ta_chunk, X[ta_chunk]);
|
|
143
173
|
#else
|
|
@@ -199,31 +229,19 @@ code_update = """
|
|
|
199
229
|
|
|
200
230
|
// Evaluate clause component
|
|
201
231
|
|
|
202
|
-
|
|
203
|
-
float component_output = 0;
|
|
204
|
-
#else
|
|
205
|
-
float component_output = 1;
|
|
206
|
-
#endif
|
|
232
|
+
float component_output = 1;
|
|
207
233
|
|
|
208
234
|
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF-1; ++ta_chunk) {
|
|
209
235
|
// Compare the TA state of the component (leaf) against the corresponding part of the feature vector
|
|
210
236
|
if ((ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] & Xi[feature_chunk_base + ta_chunk]) != ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]) {
|
|
211
|
-
|
|
212
|
-
component_output = NEG_INFINITY;
|
|
213
|
-
#else
|
|
214
|
-
component_output = 0;
|
|
215
|
-
#endif
|
|
237
|
+
component_output = 0;
|
|
216
238
|
|
|
217
239
|
break;
|
|
218
240
|
}
|
|
219
241
|
}
|
|
220
242
|
|
|
221
243
|
if ((ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & Xi[feature_chunk_base + TA_CHUNKS_PER_LEAF-1] & FILTER_HIERARCHICAL) != (ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & FILTER_HIERARCHICAL)) {
|
|
222
|
-
|
|
223
|
-
component_output = NEG_INFINITY;
|
|
224
|
-
#else
|
|
225
|
-
component_output = 0;
|
|
226
|
-
#endif
|
|
244
|
+
component_output = 0;
|
|
227
245
|
}
|
|
228
246
|
|
|
229
247
|
global_component_output[clause_component] = component_output;
|
|
@@ -262,17 +280,12 @@ code_update = """
|
|
|
262
280
|
for (int and_group_node = index; and_group_node < CLAUSES*number_of_and_group_nodes; and_group_node += stride) {
|
|
263
281
|
// Multiply and factors
|
|
264
282
|
|
|
265
|
-
|
|
266
|
-
float and_group_vote_product = 0;
|
|
267
|
-
#else
|
|
268
|
-
float and_group_vote_product = 1;
|
|
269
|
-
#endif
|
|
270
|
-
|
|
283
|
+
float and_group_vote_product = 1;
|
|
271
284
|
for (int and_factor = 0; and_factor < number_of_and_group_factors; ++and_factor) {
|
|
272
285
|
// Aggregate votes from each child node through multiplication
|
|
273
286
|
|
|
274
|
-
#if
|
|
275
|
-
|
|
287
|
+
#if AND_GROUP_NORMALIZATION == 1
|
|
288
|
+
and_group_vote_product *= powf(child_input[and_group_node*number_of_and_group_factors + and_factor], 1.0/number_of_and_group_factors);
|
|
276
289
|
#else
|
|
277
290
|
and_group_vote_product *= child_input[and_group_node*number_of_and_group_factors + and_factor];
|
|
278
291
|
#endif
|
|
@@ -289,24 +302,14 @@ code_update = """
|
|
|
289
302
|
int stride = blockDim.x * gridDim.x;
|
|
290
303
|
|
|
291
304
|
// If a group node is false, all children are made false.
|
|
292
|
-
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
child_input[group_node*number_of_group_node_children + and_factor] = NEG_INFINITY;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
#else
|
|
302
|
-
if (group_node_output[group_node] == 0) {
|
|
303
|
-
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
304
|
-
if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
|
|
305
|
-
child_input[group_node*number_of_group_node_children + and_factor] = 0;
|
|
306
|
-
}
|
|
305
|
+
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
306
|
+
if (group_node_output[group_node] == 0) {
|
|
307
|
+
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
308
|
+
if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
|
|
309
|
+
child_input[group_node*number_of_group_node_children + and_factor] = 0;
|
|
307
310
|
}
|
|
308
311
|
}
|
|
309
|
-
|
|
312
|
+
}
|
|
310
313
|
|
|
311
314
|
if (group_node_output[group_node] == -1) {
|
|
312
315
|
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
@@ -328,50 +331,29 @@ code_update = """
|
|
|
328
331
|
|
|
329
332
|
// If a group node is false, all children are made false.
|
|
330
333
|
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
child_input[group_node*number_of_group_node_children + or_addend] = -1;
|
|
335
|
-
}
|
|
336
|
-
} else if (group_node_output[group_node] == NEG_INFINITY) {
|
|
337
|
-
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
338
|
-
if (child_input[group_node*number_of_group_node_children + or_addend] >= 0) {
|
|
339
|
-
child_input[group_node*number_of_group_node_children + or_addend] = NEG_INFINITY;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
} else {
|
|
343
|
-
child_input_sum = 0;
|
|
344
|
-
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
345
|
-
if (child_input[group_node*number_of_group_node_children + or_addend] >= 0) {
|
|
346
|
-
child_input_sum += np.exp2f(child_input[group_node*number_of_group_node_children + or_addend]); // Needs normalization
|
|
347
|
-
}
|
|
348
|
-
}
|
|
334
|
+
if (group_node_output[group_node] == -1) {
|
|
335
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
336
|
+
child_input[group_node*number_of_group_node_children + or_addend] = -1;
|
|
349
337
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
child_input[group_node*number_of_group_node_children + or_addend] =
|
|
354
|
-
}
|
|
355
|
-
} else if (group_node_output[group_node] == 0) {
|
|
356
|
-
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
357
|
-
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
358
|
-
child_input[group_node*number_of_group_node_children + or_addend] = 0;
|
|
359
|
-
}
|
|
338
|
+
} else if (group_node_output[group_node] == 0) {
|
|
339
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
340
|
+
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
341
|
+
child_input[group_node*number_of_group_node_children + or_addend] = 0;
|
|
360
342
|
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
child_input_sum = 0;
|
|
346
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
347
|
+
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
348
|
+
child_input_sum += child_input[group_node*number_of_group_node_children + or_addend];
|
|
367
349
|
}
|
|
368
350
|
}
|
|
369
|
-
|
|
351
|
+
}
|
|
370
352
|
|
|
371
353
|
// Skip node if "turned off" (-1)
|
|
372
354
|
if (group_node_output[group_node] != -1) {
|
|
373
355
|
int selected_child;
|
|
374
|
-
if (
|
|
356
|
+
if (group_node_output[group_node] > 0) {
|
|
375
357
|
int random_child_value = curand(&localState) % child_input_sum;
|
|
376
358
|
child_input_sum = 0;
|
|
377
359
|
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
@@ -405,39 +387,15 @@ code_update = """
|
|
|
405
387
|
|
|
406
388
|
// Add up the votes from the children of each OR node
|
|
407
389
|
for (int or_alternatives_node = index; or_alternatives_node < CLAUSES*number_of_or_alternatives_nodes; or_alternatives_node += stride) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (or_alternatives_vote_max != NEG_INFINITY) {
|
|
417
|
-
// Sum up votes from each or alternative
|
|
418
|
-
float or_alternatives_vote_sum = 0;
|
|
419
|
-
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
420
|
-
// Aggregates or alternatives through summation
|
|
421
|
-
|
|
422
|
-
or_alternatives_vote_sum += exp2f(child_input[or_alternatives_node * number_of_or_alternatives + or_alternative] - or_alternatives_vote_max);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Store vote sum as node output
|
|
426
|
-
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_max + log2f(or_alternatives_vote_sum);
|
|
427
|
-
} else {
|
|
428
|
-
or_alternatives_node_output[or_alternatives_node] = NEG_INFINITY;
|
|
429
|
-
}
|
|
430
|
-
#else
|
|
431
|
-
// Sum up votes from each or alternative
|
|
432
|
-
int or_alternatives_vote_sum = 0;
|
|
433
|
-
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
434
|
-
// Aggregate same input or alternatives through summation
|
|
435
|
-
or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
|
|
436
|
-
}
|
|
390
|
+
// Sum up votes from each or alternative
|
|
391
|
+
int or_alternatives_vote_sum = 0;
|
|
392
|
+
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
393
|
+
// Aggregate same input or alternatives through summation
|
|
394
|
+
or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
|
|
395
|
+
}
|
|
437
396
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
#endif
|
|
397
|
+
// Store vote sum as node output
|
|
398
|
+
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
|
|
441
399
|
}
|
|
442
400
|
}
|
|
443
401
|
|
|
@@ -458,41 +416,18 @@ code_update = """
|
|
|
458
416
|
int stride = blockDim.x * gridDim.x;
|
|
459
417
|
|
|
460
418
|
// Add up the votes from each clause
|
|
461
|
-
#if LOG_SCALE == 1
|
|
462
|
-
// Add up the votes from each clause
|
|
463
|
-
for (int class_id = index; class_id < number_of_outputs; class_id += stride) {
|
|
464
|
-
float clause_output_max = NEG_INFINITY;
|
|
465
|
-
for (int clause = 0; clause < CLAUSES; ++clause) {
|
|
466
|
-
if (clause_output[clause] > clause_output_max) {
|
|
467
|
-
clause_output_max = clause_output[clause];
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
419
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
if (log2f(fabs(weighted_clause_output_sum)) + clause_output_max >= log2f(THRESHOLD)) {
|
|
478
|
-
float sign = (1 - 2 * (weighted_clause_output_sum < 0));
|
|
479
|
-
class_sum[class_id] = sign*THRESHOLD;
|
|
480
|
-
} else {
|
|
481
|
-
class_sum[class_id] = weighted_clause_output_sum * exp2f(clause_output_max);
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
class_sum[class_id] = 0;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
#else
|
|
488
|
-
for (int clause = index; clause < CLAUSES; clause += stride) {
|
|
489
|
-
if (clause_output[clause]) {
|
|
490
|
-
for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
420
|
+
for (int clause = index; clause < CLAUSES; clause += stride) {
|
|
421
|
+
if (clause_output[clause]) {
|
|
422
|
+
for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
423
|
+
#if BINARY_INFERENCE == 0
|
|
491
424
|
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause] * clause_output[clause]);
|
|
492
|
-
|
|
493
|
-
|
|
425
|
+
#else
|
|
426
|
+
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause]);
|
|
427
|
+
#endif
|
|
428
|
+
}
|
|
494
429
|
}
|
|
495
|
-
|
|
430
|
+
}
|
|
496
431
|
}
|
|
497
432
|
|
|
498
433
|
__global__ void rescale_final(int number_of_outputs, float *clause_output_max, float *class_sum)
|
|
@@ -571,11 +506,7 @@ code_update = """
|
|
|
571
506
|
local_class_sum = -THRESHOLD;
|
|
572
507
|
}
|
|
573
508
|
|
|
574
|
-
|
|
575
|
-
update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, component_output[clause_component] != NEG_INFINITY, &Xi[feature_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
|
|
576
|
-
#else
|
|
577
|
-
update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, component_output[clause_component] > 0, &Xi[feature_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
|
|
578
|
-
#endif
|
|
509
|
+
update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, component_output[clause_component] > 0, &Xi[feature_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
|
|
579
510
|
}
|
|
580
511
|
}
|
|
581
512
|
|
|
@@ -600,11 +531,7 @@ code_update = """
|
|
|
600
531
|
local_class_sum = -THRESHOLD;
|
|
601
532
|
}
|
|
602
533
|
|
|
603
|
-
|
|
604
|
-
update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], clause_output[clause] != NEG_INFINITY, y[example*number_of_outputs + class_id], local_class_sum);
|
|
605
|
-
#else
|
|
606
|
-
update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], clause_output[clause] > 0, y[example*number_of_outputs + class_id], local_class_sum);
|
|
607
|
-
#endif
|
|
534
|
+
update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], clause_output[clause] > 0, y[example*number_of_outputs + class_id], local_class_sum);
|
|
608
535
|
}
|
|
609
536
|
}
|
|
610
537
|
|
|
@@ -25,7 +25,7 @@ import PyHierarchicalTsetlinMachineCUDA.kernels as kernels
|
|
|
25
25
|
|
|
26
26
|
import pycuda.curandom as curandom
|
|
27
27
|
import pycuda.driver as cuda
|
|
28
|
-
import pycuda.
|
|
28
|
+
import pycuda.autoprimaryctx
|
|
29
29
|
from pycuda.compiler import SourceModule
|
|
30
30
|
from pycuda import gpuarray
|
|
31
31
|
from pycuda.gpuarray import GPUArray
|
|
@@ -44,13 +44,17 @@ COALESCED_TM = 2
|
|
|
44
44
|
|
|
45
45
|
class CommonTsetlinMachine():
|
|
46
46
|
|
|
47
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
47
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, literal_budget=None, no_clipping=False, constant_update_p=0, binary_inference=False, and_group_normalization=False, hierarchy_structure=None, boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
|
|
48
48
|
self.number_of_clauses = number_of_clauses
|
|
49
49
|
self.number_of_state_bits = number_of_state_bits
|
|
50
|
-
self.T =
|
|
50
|
+
self.T = float(T)
|
|
51
51
|
self.s = s
|
|
52
52
|
self.q = q
|
|
53
|
-
self.
|
|
53
|
+
self.literal_budget = literal_budget
|
|
54
|
+
self.no_clipping = no_clipping
|
|
55
|
+
self.constant_update_p = constant_update_p
|
|
56
|
+
self.binary_inference = binary_inference
|
|
57
|
+
self.and_group_normalization = and_group_normalization
|
|
54
58
|
self.hierarchy_structure = hierarchy_structure
|
|
55
59
|
self.depth = len(hierarchy_structure)
|
|
56
60
|
|
|
@@ -89,6 +93,9 @@ class CommonTsetlinMachine():
|
|
|
89
93
|
self.number_of_literals_per_leaf = self.number_of_features_per_leaf
|
|
90
94
|
self.number_of_literal_chunks_per_leaf = int((self.number_of_literals_per_leaf - 1) / 32 + 1)
|
|
91
95
|
|
|
96
|
+
if self.literal_budget == None:
|
|
97
|
+
self.literal_budget = self.number_of_literals_per_leaf
|
|
98
|
+
|
|
92
99
|
# Calculates the number of literal chunks for the full hierarchy
|
|
93
100
|
self.hierarchy_size[0] = self.number_of_literal_chunks_per_leaf * self.hierarchy_size[1]
|
|
94
101
|
|
|
@@ -127,7 +134,10 @@ class CommonTsetlinMachine():
|
|
|
127
134
|
#define S %f
|
|
128
135
|
#define THRESHOLD %d
|
|
129
136
|
#define Q %f
|
|
130
|
-
#define
|
|
137
|
+
#define LITERAL_BUDGET %d
|
|
138
|
+
#define BINARY_INFERENCE %d
|
|
139
|
+
#define CONSTANT_UPDATE_P %d
|
|
140
|
+
#define AND_GROUP_NORMALIZATION %d
|
|
131
141
|
|
|
132
142
|
#define AND_GROUP %d
|
|
133
143
|
#define AND_ALTERNATIVES %d
|
|
@@ -136,8 +146,8 @@ class CommonTsetlinMachine():
|
|
|
136
146
|
|
|
137
147
|
#define NEGATIVE_CLAUSES %d
|
|
138
148
|
#define FLIP_POLARITY %d
|
|
139
|
-
""" % (self.number_of_clauses, self.depth, self.hierarchy_size[1], self.number_of_ta_teams, self.number_of_literals_per_leaf, self.number_of_literal_chunks_per_leaf, self.number_of_literal_chunks, self.number_of_state_bits, self.boost_true_positive_feedback, self.s, self.T, self.q, self.
|
|
140
|
-
|
|
149
|
+
""" % (self.number_of_clauses, self.depth, self.hierarchy_size[1], self.number_of_ta_teams, self.number_of_literals_per_leaf, self.number_of_literal_chunks_per_leaf, self.number_of_literal_chunks, self.number_of_state_bits, self.boost_true_positive_feedback, self.s, self.T, self.q, self.literal_budget, self.binary_inference, self.constant_update_p, self.and_group_normalization, AND_GROUP, AND_ALTERNATIVES, OR_GROUP, OR_ALTERNATIVES, self.negative_clauses, self.flip_polarity)
|
|
150
|
+
|
|
141
151
|
mod_prepare = SourceModule(parameters + kernels.code_header + kernels.code_prepare, no_extern_c=True)
|
|
142
152
|
self.prepare_weights = mod_prepare.get_function("prepare_weights")
|
|
143
153
|
self.prepare_hierarchy = mod_prepare.get_function("prepare_hierarchy")
|
|
@@ -329,15 +339,6 @@ class CommonTsetlinMachine():
|
|
|
329
339
|
self.clause_output_max[:] = np.finfo(np.float32).min
|
|
330
340
|
cuda.memcpy_htod(self.clause_output_max_gpu, self.clause_output_max)
|
|
331
341
|
|
|
332
|
-
# if self.log_scale:
|
|
333
|
-
# self.max_clause_output.prepared_call(
|
|
334
|
-
# self.grid,
|
|
335
|
-
# self.block,
|
|
336
|
-
# np.int32(self.number_of_outputs),
|
|
337
|
-
# self.hierarchy_votes[self.depth-1],
|
|
338
|
-
# self.clause_output_max_gpu
|
|
339
|
-
# )
|
|
340
|
-
|
|
341
342
|
# Adds up the votes from each clause (hierarchy root)
|
|
342
343
|
self.evaluate_final.prepared_call(
|
|
343
344
|
self.grid,
|
|
@@ -348,15 +349,6 @@ class CommonTsetlinMachine():
|
|
|
348
349
|
self.class_sum_gpu
|
|
349
350
|
)
|
|
350
351
|
|
|
351
|
-
# if self.log_scale:
|
|
352
|
-
# self.rescale_final.prepared_call(
|
|
353
|
-
# self.grid,
|
|
354
|
-
# self.block,
|
|
355
|
-
# np.int32(self.number_of_outputs),
|
|
356
|
-
# self.clause_output_max_gpu,
|
|
357
|
-
# self.class_sum_gpu
|
|
358
|
-
# )
|
|
359
|
-
|
|
360
352
|
def _fit(self, X, encoded_Y):
|
|
361
353
|
if self.number_of_features_hierarchy != X.shape[1]:
|
|
362
354
|
print("The number of features spanned by hierarchy does not align with the input data.")
|
|
@@ -445,15 +437,18 @@ class CommonTsetlinMachine():
|
|
|
445
437
|
encoded_X_hierarchy_test_gpu = cuda.mem_alloc(int(number_of_examples * self.number_of_literal_chunks * 4))
|
|
446
438
|
self.encode_X(X, encoded_X_hierarchy_test_gpu)
|
|
447
439
|
|
|
448
|
-
class_sum = np.ascontiguousarray(np.zeros((self.number_of_outputs, number_of_examples))).astype(np.
|
|
440
|
+
class_sum = np.ascontiguousarray(np.zeros((self.number_of_outputs, number_of_examples))).astype(np.float32)
|
|
449
441
|
|
|
450
442
|
for e in range(number_of_examples):
|
|
451
443
|
self.evaluate_hierarchy(encoded_X_hierarchy_test_gpu, e)
|
|
452
444
|
|
|
453
445
|
cuda.memcpy_dtoh(self.class_sum, self.class_sum_gpu)
|
|
454
|
-
class_sum[:, e] = self.class_sum
|
|
446
|
+
class_sum[:, e] = self.class_sum
|
|
455
447
|
|
|
456
|
-
|
|
448
|
+
if self.no_clipping:
|
|
449
|
+
class_sum = class_sum.reshape((self.number_of_outputs, number_of_examples))
|
|
450
|
+
else:
|
|
451
|
+
class_sum = np.clip(class_sum.reshape((self.number_of_outputs, number_of_examples)), -self.T, self.T)
|
|
457
452
|
|
|
458
453
|
return class_sum
|
|
459
454
|
|
|
@@ -500,7 +495,7 @@ class CommonTsetlinMachine():
|
|
|
500
495
|
continue
|
|
501
496
|
|
|
502
497
|
n_children = self.hierarchy_structure[level][1]
|
|
503
|
-
is_alt =
|
|
498
|
+
is_alt = self.hierarchy_structure[level][0] in (OR_ALTERNATIVES, AND_ALTERNATIVES)
|
|
504
499
|
for child_pos in range(n_children):
|
|
505
500
|
child_id = node_id * n_children + child_pos
|
|
506
501
|
if is_alt:
|
|
@@ -599,12 +594,12 @@ class CommonTsetlinMachine():
|
|
|
599
594
|
if self.ta_action(i, j, k):
|
|
600
595
|
if (not self.append_negated) or k < self.number_of_literals_per_leaf // 2:
|
|
601
596
|
if print_ta_state:
|
|
602
|
-
l.append("x%d
|
|
597
|
+
l.append("x%d[%d]" % (feature_base + k, self.ta_state(i, j, k)))
|
|
603
598
|
else:
|
|
604
599
|
l.append("x%d" % (feature_base + k,))
|
|
605
600
|
else:
|
|
606
601
|
if print_ta_state:
|
|
607
|
-
l.append("¬x%d
|
|
602
|
+
l.append("¬x%d[%d]" % (feature_base + k - self.number_of_literals_per_leaf // 2, self.ta_state(i, j, k)))
|
|
608
603
|
else:
|
|
609
604
|
l.append("¬x%d" % (feature_base + k - self.number_of_literals_per_leaf // 2,))
|
|
610
605
|
|
|
@@ -658,9 +653,9 @@ class CommonTsetlinMachine():
|
|
|
658
653
|
|
|
659
654
|
|
|
660
655
|
class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
661
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
656
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, literal_budget=None, no_clipping=False, constant_update_p=0, binary_inference=False, and_group_normalization=False, boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
|
|
662
657
|
self.negative_clauses = 1
|
|
663
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
658
|
+
super().__init__(number_of_clauses, T, s, q=q, literal_budget=literal_budget, no_clipping=no_clipping, constant_update_p=constant_update_p, binary_inference=binary_inference, and_group_normalization=and_group_normalization, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
|
|
664
659
|
|
|
665
660
|
def fit(self, X, Y):
|
|
666
661
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -684,12 +679,29 @@ class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
|
684
679
|
return (self.score(X) >= 0).astype(np.uint32).transpose()
|
|
685
680
|
|
|
686
681
|
class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
687
|
-
def __init__(
|
|
682
|
+
def __init__(
|
|
683
|
+
self, number_of_clauses,
|
|
684
|
+
T,
|
|
685
|
+
s,
|
|
686
|
+
q=1.0,
|
|
687
|
+
literal_budget=None,
|
|
688
|
+
no_clipping=False,
|
|
689
|
+
constant_update_p=0,
|
|
690
|
+
binary_inference=False,
|
|
691
|
+
and_group_normalization=False,
|
|
692
|
+
hierarchy_structure=((AND_GROUP, 1)),
|
|
693
|
+
boost_true_positive_feedback=1,
|
|
694
|
+
number_of_state_bits=8,
|
|
695
|
+
append_negated=True,
|
|
696
|
+
grid=(16*13,1,1),
|
|
697
|
+
block=(128,1,1),
|
|
698
|
+
seed=None
|
|
699
|
+
):
|
|
688
700
|
self.negative_clauses = 1
|
|
689
701
|
self.tm_type = COALESCED_TM
|
|
690
702
|
self.flip_polarity = 1
|
|
691
703
|
|
|
692
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
704
|
+
super().__init__(number_of_clauses, T, s, q=q, literal_budget=literal_budget, no_clipping=no_clipping, constant_update_p=constant_update_p, binary_inference=binary_inference, and_group_normalization=and_group_normalization, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
|
|
693
705
|
|
|
694
706
|
def fit(self, X, Y):
|
|
695
707
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -716,12 +728,16 @@ class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
|
716
728
|
return np.argmax(self.score(X), axis=0)
|
|
717
729
|
|
|
718
730
|
class MultiClassTsetlinMachine:
|
|
719
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
731
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, literal_budget=None, no_clipping=False, constant_update_p=0, binary_inference=False, and_group_normalization=False, weighted_clauses=False, hierarchy_structure=((AND_GROUP, 1)), boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
|
|
720
732
|
self.number_of_clauses = number_of_clauses
|
|
721
733
|
self.T = T
|
|
722
734
|
self.s = s
|
|
723
735
|
self.q = q
|
|
724
|
-
self.
|
|
736
|
+
self.literal_budget = literal_budget
|
|
737
|
+
self.no_clipping = no_clipping
|
|
738
|
+
self.constant_update_p = constant_update_p
|
|
739
|
+
self.binary_inference = binary_inference
|
|
740
|
+
self.and_group_normalization = and_group_normalization
|
|
725
741
|
self.weighted_clauses = weighted_clauses
|
|
726
742
|
self.hierarchy_structure = hierarchy_structure
|
|
727
743
|
self.boost_true_positive_feedback = boost_true_positive_feedback
|
|
@@ -739,7 +755,7 @@ class MultiClassTsetlinMachine:
|
|
|
739
755
|
if not self.configured:
|
|
740
756
|
self.tms = []
|
|
741
757
|
for i in range(self.number_of_outputs):
|
|
742
|
-
self.tms.append(TsetlinMachine(self.number_of_clauses, self.T, self.s, q=self.q,
|
|
758
|
+
self.tms.append(TsetlinMachine(self.number_of_clauses, self.T, self.s, q=self.q, literal_budget=self.literal_budget, no_clipping=self.no_clipping, constant_update_p=self.constant_update_p, binary_inference=self.binary_inference, and_group_normalization=self.and_group_normalization, weighted_clauses=self.weighted_clauses, hierarchy_structure=self.hierarchy_structure, boost_true_positive_feedback=self.boost_true_positive_feedback, number_of_state_bits=self.number_of_state_bits, append_negated=self.append_negated, grid=self.grid, block=self.block, seed=self.seed+i))
|
|
743
759
|
|
|
744
760
|
self.configured = True
|
|
745
761
|
|
|
@@ -760,7 +776,7 @@ class MultiClassTsetlinMachine:
|
|
|
760
776
|
return
|
|
761
777
|
|
|
762
778
|
def score(self, X):
|
|
763
|
-
class_sums = np.empty((self.number_of_outputs, X.shape[0]), dtype=np.
|
|
779
|
+
class_sums = np.empty((self.number_of_outputs, X.shape[0]), dtype=np.float32)
|
|
764
780
|
for i in range(self.number_of_outputs):
|
|
765
781
|
class_sums[i,:] = self.tms[i].score(X)
|
|
766
782
|
|
|
@@ -790,7 +806,7 @@ class MultiClassTsetlinMachine:
|
|
|
790
806
|
|
|
791
807
|
def print_hierarchy(self, print_ta_state=False):
|
|
792
808
|
for i in range(self.number_of_outputs):
|
|
793
|
-
print("
|
|
809
|
+
print("\nCLASS %d\n" % (i,))
|
|
794
810
|
self.tms[i].print_hierarchy(print_ta_state = print_ta_state)
|
|
795
811
|
|
|
796
812
|
def load(self, state_dict: dict):
|
|
@@ -805,7 +821,7 @@ class MultiClassTsetlinMachine:
|
|
|
805
821
|
self.configured = True
|
|
806
822
|
|
|
807
823
|
class TsetlinMachine(CommonTsetlinMachine):
|
|
808
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
824
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, literal_budget=None, no_clipping=False, constant_update_p=0, binary_inference=False, and_group_normalization=False, weighted_clauses=False, hierarchy_structure=((AND_GROUP, 1)), boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
|
|
809
825
|
self.negative_clauses = 1
|
|
810
826
|
self.flip_polarity = 0
|
|
811
827
|
|
|
@@ -814,7 +830,7 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
814
830
|
else:
|
|
815
831
|
self.tm_type = VANILLA_TM
|
|
816
832
|
|
|
817
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
833
|
+
super().__init__(number_of_clauses, T, s, q=q, literal_budget=literal_budget, no_clipping=no_clipping, constant_update_p=constant_update_p, binary_inference=binary_inference, and_group_normalization=and_group_normalization, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
|
|
818
834
|
|
|
819
835
|
def fit(self, X, Y):
|
|
820
836
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -838,11 +854,11 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
838
854
|
return (self.score(X) >= 0).astype(np.int32)
|
|
839
855
|
|
|
840
856
|
class RegressionTsetlinMachine(CommonTsetlinMachine):
|
|
841
|
-
def __init__(self, number_of_clauses, T, s,
|
|
857
|
+
def __init__(self, number_of_clauses, T, s, literal_budget=None, and_group_normalization=False, hierarchy_structure=((AND_GROUP, 1)), boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
|
|
842
858
|
self.negative_clauses = 0
|
|
843
859
|
self.flip_polarity = 0
|
|
844
860
|
|
|
845
|
-
super().__init__(number_of_clauses, T, s,
|
|
861
|
+
super().__init__(number_of_clauses, T, s, literal_budget=literal_budget, and_group_normalization=and_group_normalization, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
|
|
846
862
|
|
|
847
863
|
def fit(self, X, Y):
|
|
848
864
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -3,17 +3,31 @@ from collections import deque
|
|
|
3
3
|
import networkx as nx
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
|
-
from .tm import OR_ALTERNATIVES, CommonTsetlinMachine
|
|
6
|
+
from .tm import AND_ALTERNATIVES, AND_GROUP, OR_ALTERNATIVES, OR_GROUP, CommonTsetlinMachine
|
|
7
7
|
|
|
8
|
+
DEFAULT_NODE_TYPE_LABELS: dict[int, str] = {
|
|
9
|
+
AND_GROUP: ' ∧* ',
|
|
10
|
+
AND_ALTERNATIVES: ' ∧ ',
|
|
11
|
+
OR_GROUP: ' ∨* ',
|
|
12
|
+
OR_ALTERNATIVES: ' ∨ ',
|
|
13
|
+
}
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
|
|
16
|
+
def make_hierarchy_graph(
|
|
17
|
+
G: nx.Graph,
|
|
18
|
+
hier: list[tuple[int, int]],
|
|
19
|
+
node_type_labels: dict[int, str] | None = None,
|
|
20
|
+
):
|
|
10
21
|
"""Create Graph from the hierarchy."""
|
|
22
|
+
node_type_labels = {**DEFAULT_NODE_TYPE_LABELS, **(node_type_labels or {})}
|
|
23
|
+
|
|
11
24
|
# BFS
|
|
12
25
|
q = deque()
|
|
13
26
|
q.append((len(hier), 0)) # (level, idx)
|
|
14
27
|
while q:
|
|
15
28
|
level, idx = q.popleft()
|
|
16
|
-
|
|
29
|
+
op = hier[level - 1][0]
|
|
30
|
+
G.add_node((level, idx), label=node_type_labels.get(op, op), op=op)
|
|
17
31
|
if level == 1:
|
|
18
32
|
continue
|
|
19
33
|
branching = hier[level - 1][1]
|
|
@@ -29,6 +43,7 @@ def clause_to_nx(
|
|
|
29
43
|
negation_prefix: str = '¬',
|
|
30
44
|
clause_literals: np.ndarray | None = None,
|
|
31
45
|
ta_to_fid_mapping=None,
|
|
46
|
+
node_type_labels: dict[int, str] | None = None,
|
|
32
47
|
):
|
|
33
48
|
"""
|
|
34
49
|
Create a networkx Graph for a single clause.
|
|
@@ -39,6 +54,7 @@ def clause_to_nx(
|
|
|
39
54
|
`negation_prefix`: Prefix for negated features (default: '¬').
|
|
40
55
|
`clause_literals`: Optional pre-extracted literals for the clause, must have shape (n_components, literals_per_component). If None, literals will be extracted from the model.
|
|
41
56
|
`ta_to_fid_mapping`: Optional mapping from (component_id, literal_id) to feature_id. If None, it will be obtained from the model.
|
|
57
|
+
`node_type_labels`: Optional dict overriding the display symbol for one or more hierarchy node types (`AND_GROUP`/`AND_ALTERNATIVES`/`OR_GROUP`/`OR_ALTERNATIVES`). Merged over `DEFAULT_NODE_TYPE_LABELS`; unset keys fall back to the default.
|
|
42
58
|
"""
|
|
43
59
|
|
|
44
60
|
assert tm.hierarchy_structure is not None, (
|
|
@@ -62,7 +78,7 @@ def clause_to_nx(
|
|
|
62
78
|
lits_per_comp = tm.number_of_literals_per_leaf
|
|
63
79
|
|
|
64
80
|
G = nx.Graph()
|
|
65
|
-
make_hierarchy_graph(G, tm.hierarchy_structure)
|
|
81
|
+
make_hierarchy_graph(G, tm.hierarchy_structure, node_type_labels)
|
|
66
82
|
|
|
67
83
|
feat_per_comp = lits_per_comp // 2 if tm.append_negated else lits_per_comp
|
|
68
84
|
|
|
@@ -95,6 +111,7 @@ def clause_bank_to_nx(
|
|
|
95
111
|
tm: CommonTsetlinMachine,
|
|
96
112
|
feature_names: list[str] | None = None,
|
|
97
113
|
negation_prefix: str = '¬',
|
|
114
|
+
node_type_labels: dict[int, str] | None = None,
|
|
98
115
|
):
|
|
99
116
|
"""
|
|
100
117
|
Create a networkx Graph for the entire clause bank.
|
|
@@ -102,15 +119,18 @@ def clause_bank_to_nx(
|
|
|
102
119
|
`tm`: The model.
|
|
103
120
|
`feature_names`: Optional list of feature names for labeling. If None, defaults to 'x0', 'x1', ...
|
|
104
121
|
`negation_prefix`: Prefix for negated features (default: '¬').
|
|
122
|
+
`node_type_labels`: Optional dict overriding the display symbol for one or more hierarchy node types. Merged over `DEFAULT_NODE_TYPE_LABELS`; unset keys fall back to the default.
|
|
105
123
|
"""
|
|
124
|
+
node_type_labels = {**DEFAULT_NODE_TYPE_LABELS, **(node_type_labels or {})}
|
|
125
|
+
|
|
106
126
|
literals = tm.get_literals()
|
|
107
127
|
ta_to_fid = tm.map_ta_id_to_feature_id()
|
|
108
128
|
G = nx.Graph()
|
|
109
129
|
cb_root = 'CB_ROOT'
|
|
110
|
-
G.add_node(cb_root, label=OR_ALTERNATIVES, op=OR_ALTERNATIVES)
|
|
130
|
+
G.add_node(cb_root, label=node_type_labels.get(OR_ALTERNATIVES, OR_ALTERNATIVES), op=OR_ALTERNATIVES)
|
|
111
131
|
for ci in range(tm.number_of_clauses):
|
|
112
132
|
clause_G = clause_to_nx(
|
|
113
|
-
tm, ci, feature_names, negation_prefix, literals[ci], ta_to_fid
|
|
133
|
+
tm, ci, feature_names, negation_prefix, literals[ci], ta_to_fid, node_type_labels
|
|
114
134
|
)
|
|
115
135
|
mapping = {node: (ci, node) for node in clause_G.nodes}
|
|
116
136
|
G = nx.compose(G, nx.relabel_nodes(clause_G, mapping))
|
|
@@ -124,6 +144,7 @@ def active_path_graph(
|
|
|
124
144
|
X: np.ndarray,
|
|
125
145
|
feature_names: list[str] | None = None,
|
|
126
146
|
negation_prefix: str = '¬',
|
|
147
|
+
node_type_labels: dict[int, str] | None = None,
|
|
127
148
|
):
|
|
128
149
|
"""
|
|
129
150
|
Show the activated path, and vote calculation for a single sample `X`.
|
|
@@ -132,6 +153,7 @@ def active_path_graph(
|
|
|
132
153
|
`X`: A single sample with shape (n_features,).
|
|
133
154
|
`feature_names`: Optional list of feature names for labeling. If None, defaults to 'x0', 'x1', ...
|
|
134
155
|
`negation_prefix`: Prefix for negated features (default: '¬').
|
|
156
|
+
`node_type_labels`: Optional dict overriding the display symbol for one or more hierarchy node types. Merged over `DEFAULT_NODE_TYPE_LABELS`; unset keys fall back to the default.
|
|
135
157
|
Returns:
|
|
136
158
|
A list of networkx Graphs for each clause, with 'active' and 'vote' attributes on nodes and edges, and class sums for each class.
|
|
137
159
|
"""
|
|
@@ -139,7 +161,7 @@ def active_path_graph(
|
|
|
139
161
|
|
|
140
162
|
hierarchy_votes, class_sums = tm.calc_hierarchy_votes(X.reshape(1, -1))
|
|
141
163
|
hierarchy_votes = hierarchy_votes[0]
|
|
142
|
-
class_sums = class_sums[0]
|
|
164
|
+
class_sums = class_sums[:, 0]
|
|
143
165
|
|
|
144
166
|
literals = tm.get_literals()
|
|
145
167
|
ta_to_fid = tm.map_ta_id_to_feature_id()
|
|
@@ -147,7 +169,7 @@ def active_path_graph(
|
|
|
147
169
|
feat_per_comp = lits_per_comp // 2 if tm.append_negated else lits_per_comp
|
|
148
170
|
|
|
149
171
|
G = [
|
|
150
|
-
clause_to_nx(tm, ci, feature_names, negation_prefix, literals[ci], ta_to_fid)
|
|
172
|
+
clause_to_nx(tm, ci, feature_names, negation_prefix, literals[ci], ta_to_fid, node_type_labels)
|
|
151
173
|
for ci in range(tm.number_of_clauses)
|
|
152
174
|
]
|
|
153
175
|
for ci in range(tm.number_of_clauses):
|
|
@@ -11,7 +11,7 @@ or
|
|
|
11
11
|
git clone git@github.com:cair/PyHierarchicalTsetlinMachineCUDA.git
|
|
12
12
|
cd PyHierarchicalTsetlinMachineCUDA
|
|
13
13
|
python ./setup.py sdist
|
|
14
|
-
pip install dist/PyHierarchicalTsetlinMachineCUDA-0.
|
|
14
|
+
pip install dist/PyHierarchicalTsetlinMachineCUDA-0.3.1.tar.gz
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Examples
|
|
@@ -79,7 +79,7 @@ CLAUSE 1: (((((x0 ∧ x1) ∨ (x0 ∧ x1) ∨ (¬x0 ∧ ¬x1)) ∧ ((x3 ∧ x4)
|
|
|
79
79
|
### Hex Demo
|
|
80
80
|
|
|
81
81
|
<p align="center">
|
|
82
|
-
<img width="60%" src="https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/blob/
|
|
82
|
+
<img width="60%" src="https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/blob/main/figures/Hex-board-11x11.png">
|
|
83
83
|
</p>
|
|
84
84
|
<p align="center">
|
|
85
85
|
Source: https://en.wikipedia.org/wiki/Hex_(board_game)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|