PyHierarchicalTsetlinMachineCUDA 0.3.0__tar.gz → 0.3.2__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.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/kernels.py +74 -157
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/tm.py +37 -52
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/utils.py +30 -8
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/README.md +2 -2
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/setup.py +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/LICENSE +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/__init__.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/tools.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/SOURCES.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/dependency_links.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/requires.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/top_level.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.0 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/setup.cfg +0 -0
|
@@ -94,8 +94,14 @@ code_update = """
|
|
|
94
94
|
|
|
95
95
|
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
96
96
|
|
|
97
|
-
float
|
|
98
|
-
if
|
|
97
|
+
float update_probability;
|
|
98
|
+
#if CONSTANT_UPDATE_P == 1
|
|
99
|
+
update_probability = 1.0;
|
|
100
|
+
#else
|
|
101
|
+
update_probability = fabsf(y - class_sum)/(2*THRESHOLD);
|
|
102
|
+
#endif
|
|
103
|
+
|
|
104
|
+
if (curand_uniform(localState) <= update_probability) {
|
|
99
105
|
if (target*sign > 0) {
|
|
100
106
|
if (clause_output && abs(*clause_weight) < INT_MAX) {
|
|
101
107
|
(*clause_weight) += sign;
|
|
@@ -124,8 +130,14 @@ code_update = """
|
|
|
124
130
|
|
|
125
131
|
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
126
132
|
|
|
127
|
-
float
|
|
128
|
-
if
|
|
133
|
+
float update_probability;
|
|
134
|
+
#if CONSTANT_UPDATE_P == 1
|
|
135
|
+
update_probability = 1.0;
|
|
136
|
+
#else
|
|
137
|
+
update_probability = fabsf(y - class_sum)/(2*THRESHOLD);
|
|
138
|
+
#endif
|
|
139
|
+
|
|
140
|
+
if (curand_uniform(localState) <= update_probability) {
|
|
129
141
|
if (target*sign > 0) {
|
|
130
142
|
// Type I Feedback
|
|
131
143
|
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
|
|
@@ -199,31 +211,19 @@ code_update = """
|
|
|
199
211
|
|
|
200
212
|
// Evaluate clause component
|
|
201
213
|
|
|
202
|
-
|
|
203
|
-
float component_output = 0;
|
|
204
|
-
#else
|
|
205
|
-
float component_output = 1;
|
|
206
|
-
#endif
|
|
214
|
+
float component_output = 1;
|
|
207
215
|
|
|
208
216
|
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF-1; ++ta_chunk) {
|
|
209
217
|
// Compare the TA state of the component (leaf) against the corresponding part of the feature vector
|
|
210
218
|
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
|
|
219
|
+
component_output = 0;
|
|
216
220
|
|
|
217
221
|
break;
|
|
218
222
|
}
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
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
|
|
226
|
+
component_output = 0;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
global_component_output[clause_component] = component_output;
|
|
@@ -262,17 +262,12 @@ code_update = """
|
|
|
262
262
|
for (int and_group_node = index; and_group_node < CLAUSES*number_of_and_group_nodes; and_group_node += stride) {
|
|
263
263
|
// Multiply and factors
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
float and_group_vote_product = 0;
|
|
267
|
-
#else
|
|
268
|
-
float and_group_vote_product = 1;
|
|
269
|
-
#endif
|
|
270
|
-
|
|
265
|
+
float and_group_vote_product = 1;
|
|
271
266
|
for (int and_factor = 0; and_factor < number_of_and_group_factors; ++and_factor) {
|
|
272
267
|
// Aggregate votes from each child node through multiplication
|
|
273
268
|
|
|
274
|
-
#if
|
|
275
|
-
|
|
269
|
+
#if AND_GROUP_NORMALIZATION == 1
|
|
270
|
+
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
271
|
#else
|
|
277
272
|
and_group_vote_product *= child_input[and_group_node*number_of_and_group_factors + and_factor];
|
|
278
273
|
#endif
|
|
@@ -289,24 +284,14 @@ code_update = """
|
|
|
289
284
|
int stride = blockDim.x * gridDim.x;
|
|
290
285
|
|
|
291
286
|
// 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
|
-
}
|
|
287
|
+
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
288
|
+
if (group_node_output[group_node] == 0) {
|
|
289
|
+
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
290
|
+
if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
|
|
291
|
+
child_input[group_node*number_of_group_node_children + and_factor] = 0;
|
|
307
292
|
}
|
|
308
293
|
}
|
|
309
|
-
|
|
294
|
+
}
|
|
310
295
|
|
|
311
296
|
if (group_node_output[group_node] == -1) {
|
|
312
297
|
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
@@ -321,63 +306,50 @@ code_update = """
|
|
|
321
306
|
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
322
307
|
int stride = blockDim.x * gridDim.x;
|
|
323
308
|
|
|
324
|
-
int
|
|
309
|
+
int child_input_sum;
|
|
325
310
|
|
|
326
311
|
/* Copy state to local memory for efficiency */
|
|
327
312
|
curandState localState = state[index];
|
|
328
313
|
|
|
329
314
|
// If a group node is false, all children are made false.
|
|
330
315
|
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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;
|
|
337
|
-
}
|
|
338
|
-
} else if (group_node_output[group_node] == NEG_INFINITY) {
|
|
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] = NEG_INFINITY;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
} else {
|
|
345
|
-
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
346
|
-
if (child_input[group_node*number_of_group_node_children + or_addend] >= 0) {
|
|
347
|
-
non_zero_children[number_of_non_zero_children] = or_addend;
|
|
348
|
-
number_of_non_zero_children++;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
316
|
+
if (group_node_output[group_node] == -1) {
|
|
317
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
318
|
+
child_input[group_node*number_of_group_node_children + or_addend] = -1;
|
|
351
319
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
child_input[group_node*number_of_group_node_children + or_addend] =
|
|
356
|
-
}
|
|
357
|
-
} else if (group_node_output[group_node] == 0) {
|
|
358
|
-
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
359
|
-
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
360
|
-
child_input[group_node*number_of_group_node_children + or_addend] = 0;
|
|
361
|
-
}
|
|
320
|
+
} else if (group_node_output[group_node] == 0) {
|
|
321
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
322
|
+
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
323
|
+
child_input[group_node*number_of_group_node_children + or_addend] = 0;
|
|
362
324
|
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
child_input_sum = 0;
|
|
328
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
329
|
+
if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
|
|
330
|
+
child_input_sum += child_input[group_node*number_of_group_node_children + or_addend];
|
|
369
331
|
}
|
|
370
332
|
}
|
|
371
|
-
|
|
333
|
+
}
|
|
372
334
|
|
|
335
|
+
// Skip node if "turned off" (-1)
|
|
373
336
|
if (group_node_output[group_node] != -1) {
|
|
374
337
|
int selected_child;
|
|
375
|
-
if (
|
|
376
|
-
|
|
338
|
+
if (group_node_output[group_node] > 0) {
|
|
339
|
+
int random_child_value = curand(&localState) % child_input_sum;
|
|
340
|
+
child_input_sum = 0;
|
|
341
|
+
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
342
|
+
child_input_sum += child_input[group_node*number_of_group_node_children + or_addend];
|
|
343
|
+
if (child_input_sum > random_child_value) {
|
|
344
|
+
selected_child = or_addend;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
377
348
|
} else {
|
|
378
349
|
selected_child = curand(&localState) % number_of_group_node_children;
|
|
379
350
|
}
|
|
380
351
|
|
|
352
|
+
// "Turn off" the sub-hierarchies that were not selected
|
|
381
353
|
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
382
354
|
if (selected_child != or_addend) {
|
|
383
355
|
child_input[group_node*number_of_group_node_children + or_addend] = -1;
|
|
@@ -397,39 +369,15 @@ code_update = """
|
|
|
397
369
|
|
|
398
370
|
// Add up the votes from the children of each OR node
|
|
399
371
|
for (int or_alternatives_node = index; or_alternatives_node < CLAUSES*number_of_or_alternatives_nodes; or_alternatives_node += stride) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (or_alternatives_vote_max != NEG_INFINITY) {
|
|
409
|
-
// Sum up votes from each or alternative
|
|
410
|
-
float or_alternatives_vote_sum = 0;
|
|
411
|
-
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
412
|
-
// Aggregates or alternatives through summation
|
|
413
|
-
|
|
414
|
-
or_alternatives_vote_sum += exp2f(child_input[or_alternatives_node * number_of_or_alternatives + or_alternative] - or_alternatives_vote_max);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// Store vote sum as node output
|
|
418
|
-
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_max + log2f(or_alternatives_vote_sum);
|
|
419
|
-
} else {
|
|
420
|
-
or_alternatives_node_output[or_alternatives_node] = NEG_INFINITY;
|
|
421
|
-
}
|
|
422
|
-
#else
|
|
423
|
-
// Sum up votes from each or alternative
|
|
424
|
-
int or_alternatives_vote_sum = 0;
|
|
425
|
-
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
426
|
-
// Aggregate same input or alternatives through summation
|
|
427
|
-
or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
|
|
428
|
-
}
|
|
372
|
+
// Sum up votes from each or alternative
|
|
373
|
+
int or_alternatives_vote_sum = 0;
|
|
374
|
+
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
375
|
+
// Aggregate same input or alternatives through summation
|
|
376
|
+
or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
|
|
377
|
+
}
|
|
429
378
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
#endif
|
|
379
|
+
// Store vote sum as node output
|
|
380
|
+
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
|
|
433
381
|
}
|
|
434
382
|
}
|
|
435
383
|
|
|
@@ -450,41 +398,18 @@ code_update = """
|
|
|
450
398
|
int stride = blockDim.x * gridDim.x;
|
|
451
399
|
|
|
452
400
|
// Add up the votes from each clause
|
|
453
|
-
#if LOG_SCALE == 1
|
|
454
|
-
// Add up the votes from each clause
|
|
455
|
-
for (int class_id = index; class_id < number_of_outputs; class_id += stride) {
|
|
456
|
-
float clause_output_max = NEG_INFINITY;
|
|
457
|
-
for (int clause = 0; clause < CLAUSES; ++clause) {
|
|
458
|
-
if (clause_output[clause] > clause_output_max) {
|
|
459
|
-
clause_output_max = clause_output[clause];
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (clause_output_max != NEG_INFINITY) {
|
|
464
|
-
float weighted_clause_output_sum = 0;
|
|
465
|
-
for (int clause = 0; clause < CLAUSES; ++clause) {
|
|
466
|
-
weighted_clause_output_sum += clause_weights[class_id*CLAUSES + clause] * exp2f(clause_output[clause] - clause_output_max);
|
|
467
|
-
}
|
|
468
401
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
class_sum[class_id] = weighted_clause_output_sum * exp2f(clause_output_max);
|
|
474
|
-
}
|
|
475
|
-
} else {
|
|
476
|
-
class_sum[class_id] = 0;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
#else
|
|
480
|
-
for (int clause = index; clause < CLAUSES; clause += stride) {
|
|
481
|
-
if (clause_output[clause]) {
|
|
482
|
-
for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
402
|
+
for (int clause = index; clause < CLAUSES; clause += stride) {
|
|
403
|
+
if (clause_output[clause]) {
|
|
404
|
+
for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
405
|
+
#if BINARY_INFERENCE == 0
|
|
483
406
|
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause] * clause_output[clause]);
|
|
484
|
-
|
|
485
|
-
|
|
407
|
+
#else
|
|
408
|
+
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause]);
|
|
409
|
+
#endif
|
|
410
|
+
}
|
|
486
411
|
}
|
|
487
|
-
|
|
412
|
+
}
|
|
488
413
|
}
|
|
489
414
|
|
|
490
415
|
__global__ void rescale_final(int number_of_outputs, float *clause_output_max, float *class_sum)
|
|
@@ -563,11 +488,7 @@ code_update = """
|
|
|
563
488
|
local_class_sum = -THRESHOLD;
|
|
564
489
|
}
|
|
565
490
|
|
|
566
|
-
|
|
567
|
-
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);
|
|
568
|
-
#else
|
|
569
|
-
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);
|
|
570
|
-
#endif
|
|
491
|
+
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);
|
|
571
492
|
}
|
|
572
493
|
}
|
|
573
494
|
|
|
@@ -592,11 +513,7 @@ code_update = """
|
|
|
592
513
|
local_class_sum = -THRESHOLD;
|
|
593
514
|
}
|
|
594
515
|
|
|
595
|
-
|
|
596
|
-
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);
|
|
597
|
-
#else
|
|
598
|
-
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);
|
|
599
|
-
#endif
|
|
516
|
+
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);
|
|
600
517
|
}
|
|
601
518
|
}
|
|
602
519
|
|
|
@@ -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,16 @@ 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, 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.no_clipping = no_clipping
|
|
54
|
+
self.constant_update_p = constant_update_p
|
|
55
|
+
self.binary_inference = binary_inference
|
|
56
|
+
self.and_group_normalization = and_group_normalization
|
|
54
57
|
self.hierarchy_structure = hierarchy_structure
|
|
55
58
|
self.depth = len(hierarchy_structure)
|
|
56
59
|
|
|
@@ -97,12 +100,6 @@ class CommonTsetlinMachine():
|
|
|
97
100
|
if self.hierarchy_structure[d][0] != OR_GROUP: # OR_GROUP reuses the same TA
|
|
98
101
|
self.number_of_ta_teams = self.hierarchy_structure[self.depth - d - 1][1] * self.number_of_ta_teams
|
|
99
102
|
|
|
100
|
-
# Identifies the larget number of OR_GROUP children (for allocating local memory)
|
|
101
|
-
self.max_number_of_or_group_children = 0
|
|
102
|
-
for d in range(1, self.depth):
|
|
103
|
-
if self.hierarchy_structure[d][0] == OR_GROUP and self.max_number_of_or_group_children < self.hierarchy_structure[d][1]:
|
|
104
|
-
self.max_number_of_or_group_children = self.hierarchy_structure[d][1]
|
|
105
|
-
|
|
106
103
|
# Calculates number of literal chunks overall for the feature vector (ignores OR- and AND alternatives)
|
|
107
104
|
self.number_of_literal_chunks = self.number_of_literal_chunks_per_leaf
|
|
108
105
|
for d in range(self.depth - 1, 0, -1):
|
|
@@ -133,19 +130,19 @@ class CommonTsetlinMachine():
|
|
|
133
130
|
#define S %f
|
|
134
131
|
#define THRESHOLD %d
|
|
135
132
|
#define Q %f
|
|
136
|
-
#define
|
|
133
|
+
#define BINARY_INFERENCE %d
|
|
134
|
+
#define CONSTANT_UPDATE_P %d
|
|
135
|
+
#define AND_GROUP_NORMALIZATION %d
|
|
137
136
|
|
|
138
137
|
#define AND_GROUP %d
|
|
139
138
|
#define AND_ALTERNATIVES %d
|
|
140
139
|
#define OR_GROUP %d
|
|
141
140
|
#define OR_ALTERNATIVES %d
|
|
142
141
|
|
|
143
|
-
#define MAX_NUMBER_OF_OR_GROUP_CHILDREN %d
|
|
144
|
-
|
|
145
142
|
#define NEGATIVE_CLAUSES %d
|
|
146
143
|
#define FLIP_POLARITY %d
|
|
147
|
-
""" % (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.
|
|
148
|
-
|
|
144
|
+
""" % (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.binary_inference, self.constant_update_p, self.and_group_normalization, AND_GROUP, AND_ALTERNATIVES, OR_GROUP, OR_ALTERNATIVES, self.negative_clauses, self.flip_polarity)
|
|
145
|
+
|
|
149
146
|
mod_prepare = SourceModule(parameters + kernels.code_header + kernels.code_prepare, no_extern_c=True)
|
|
150
147
|
self.prepare_weights = mod_prepare.get_function("prepare_weights")
|
|
151
148
|
self.prepare_hierarchy = mod_prepare.get_function("prepare_hierarchy")
|
|
@@ -337,15 +334,6 @@ class CommonTsetlinMachine():
|
|
|
337
334
|
self.clause_output_max[:] = np.finfo(np.float32).min
|
|
338
335
|
cuda.memcpy_htod(self.clause_output_max_gpu, self.clause_output_max)
|
|
339
336
|
|
|
340
|
-
# if self.log_scale:
|
|
341
|
-
# self.max_clause_output.prepared_call(
|
|
342
|
-
# self.grid,
|
|
343
|
-
# self.block,
|
|
344
|
-
# np.int32(self.number_of_outputs),
|
|
345
|
-
# self.hierarchy_votes[self.depth-1],
|
|
346
|
-
# self.clause_output_max_gpu
|
|
347
|
-
# )
|
|
348
|
-
|
|
349
337
|
# Adds up the votes from each clause (hierarchy root)
|
|
350
338
|
self.evaluate_final.prepared_call(
|
|
351
339
|
self.grid,
|
|
@@ -356,15 +344,6 @@ class CommonTsetlinMachine():
|
|
|
356
344
|
self.class_sum_gpu
|
|
357
345
|
)
|
|
358
346
|
|
|
359
|
-
# if self.log_scale:
|
|
360
|
-
# self.rescale_final.prepared_call(
|
|
361
|
-
# self.grid,
|
|
362
|
-
# self.block,
|
|
363
|
-
# np.int32(self.number_of_outputs),
|
|
364
|
-
# self.clause_output_max_gpu,
|
|
365
|
-
# self.class_sum_gpu
|
|
366
|
-
# )
|
|
367
|
-
|
|
368
347
|
def _fit(self, X, encoded_Y):
|
|
369
348
|
if self.number_of_features_hierarchy != X.shape[1]:
|
|
370
349
|
print("The number of features spanned by hierarchy does not align with the input data.")
|
|
@@ -453,15 +432,18 @@ class CommonTsetlinMachine():
|
|
|
453
432
|
encoded_X_hierarchy_test_gpu = cuda.mem_alloc(int(number_of_examples * self.number_of_literal_chunks * 4))
|
|
454
433
|
self.encode_X(X, encoded_X_hierarchy_test_gpu)
|
|
455
434
|
|
|
456
|
-
class_sum = np.ascontiguousarray(np.zeros((self.number_of_outputs, number_of_examples))).astype(np.
|
|
435
|
+
class_sum = np.ascontiguousarray(np.zeros((self.number_of_outputs, number_of_examples))).astype(np.float32)
|
|
457
436
|
|
|
458
437
|
for e in range(number_of_examples):
|
|
459
438
|
self.evaluate_hierarchy(encoded_X_hierarchy_test_gpu, e)
|
|
460
439
|
|
|
461
440
|
cuda.memcpy_dtoh(self.class_sum, self.class_sum_gpu)
|
|
462
|
-
class_sum[:, e] = self.class_sum
|
|
441
|
+
class_sum[:, e] = self.class_sum
|
|
463
442
|
|
|
464
|
-
|
|
443
|
+
if self.no_clipping:
|
|
444
|
+
class_sum = class_sum.reshape((self.number_of_outputs, number_of_examples))
|
|
445
|
+
else:
|
|
446
|
+
class_sum = np.clip(class_sum.reshape((self.number_of_outputs, number_of_examples)), -self.T, self.T)
|
|
465
447
|
|
|
466
448
|
return class_sum
|
|
467
449
|
|
|
@@ -508,7 +490,7 @@ class CommonTsetlinMachine():
|
|
|
508
490
|
continue
|
|
509
491
|
|
|
510
492
|
n_children = self.hierarchy_structure[level][1]
|
|
511
|
-
is_alt =
|
|
493
|
+
is_alt = self.hierarchy_structure[level][0] in (OR_ALTERNATIVES, AND_ALTERNATIVES)
|
|
512
494
|
for child_pos in range(n_children):
|
|
513
495
|
child_id = node_id * n_children + child_pos
|
|
514
496
|
if is_alt:
|
|
@@ -607,12 +589,12 @@ class CommonTsetlinMachine():
|
|
|
607
589
|
if self.ta_action(i, j, k):
|
|
608
590
|
if (not self.append_negated) or k < self.number_of_literals_per_leaf // 2:
|
|
609
591
|
if print_ta_state:
|
|
610
|
-
l.append("x%d
|
|
592
|
+
l.append("x%d[%d]" % (feature_base + k, self.ta_state(i, j, k)))
|
|
611
593
|
else:
|
|
612
594
|
l.append("x%d" % (feature_base + k,))
|
|
613
595
|
else:
|
|
614
596
|
if print_ta_state:
|
|
615
|
-
l.append("¬x%d
|
|
597
|
+
l.append("¬x%d[%d]" % (feature_base + k - self.number_of_literals_per_leaf // 2, self.ta_state(i, j, k)))
|
|
616
598
|
else:
|
|
617
599
|
l.append("¬x%d" % (feature_base + k - self.number_of_literals_per_leaf // 2,))
|
|
618
600
|
|
|
@@ -666,9 +648,9 @@ class CommonTsetlinMachine():
|
|
|
666
648
|
|
|
667
649
|
|
|
668
650
|
class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
669
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
651
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, 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):
|
|
670
652
|
self.negative_clauses = 1
|
|
671
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
653
|
+
super().__init__(number_of_clauses, T, s, q=q, 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)
|
|
672
654
|
|
|
673
655
|
def fit(self, X, Y):
|
|
674
656
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -692,12 +674,12 @@ class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
|
692
674
|
return (self.score(X) >= 0).astype(np.uint32).transpose()
|
|
693
675
|
|
|
694
676
|
class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
695
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
677
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, no_clipping=False, constant_update_p=0, binary_inference=False, 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):
|
|
696
678
|
self.negative_clauses = 1
|
|
697
679
|
self.tm_type = COALESCED_TM
|
|
698
680
|
self.flip_polarity = 1
|
|
699
681
|
|
|
700
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
682
|
+
super().__init__(number_of_clauses, T, s, q=q, 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)
|
|
701
683
|
|
|
702
684
|
def fit(self, X, Y):
|
|
703
685
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -724,12 +706,15 @@ class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
|
724
706
|
return np.argmax(self.score(X), axis=0)
|
|
725
707
|
|
|
726
708
|
class MultiClassTsetlinMachine:
|
|
727
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
709
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, 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):
|
|
728
710
|
self.number_of_clauses = number_of_clauses
|
|
729
711
|
self.T = T
|
|
730
712
|
self.s = s
|
|
731
713
|
self.q = q
|
|
732
|
-
self.
|
|
714
|
+
self.no_clipping = no_clipping
|
|
715
|
+
self.constant_update_p = constant_update_p
|
|
716
|
+
self.binary_inference = binary_inference
|
|
717
|
+
self.and_group_normalization = and_group_normalization
|
|
733
718
|
self.weighted_clauses = weighted_clauses
|
|
734
719
|
self.hierarchy_structure = hierarchy_structure
|
|
735
720
|
self.boost_true_positive_feedback = boost_true_positive_feedback
|
|
@@ -747,7 +732,7 @@ class MultiClassTsetlinMachine:
|
|
|
747
732
|
if not self.configured:
|
|
748
733
|
self.tms = []
|
|
749
734
|
for i in range(self.number_of_outputs):
|
|
750
|
-
self.tms.append(TsetlinMachine(self.number_of_clauses, self.T, self.s, q=self.q,
|
|
735
|
+
self.tms.append(TsetlinMachine(self.number_of_clauses, self.T, self.s, q=self.q, 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))
|
|
751
736
|
|
|
752
737
|
self.configured = True
|
|
753
738
|
|
|
@@ -768,7 +753,7 @@ class MultiClassTsetlinMachine:
|
|
|
768
753
|
return
|
|
769
754
|
|
|
770
755
|
def score(self, X):
|
|
771
|
-
class_sums = np.empty((self.number_of_outputs, X.shape[0]), dtype=np.
|
|
756
|
+
class_sums = np.empty((self.number_of_outputs, X.shape[0]), dtype=np.float32)
|
|
772
757
|
for i in range(self.number_of_outputs):
|
|
773
758
|
class_sums[i,:] = self.tms[i].score(X)
|
|
774
759
|
|
|
@@ -798,7 +783,7 @@ class MultiClassTsetlinMachine:
|
|
|
798
783
|
|
|
799
784
|
def print_hierarchy(self, print_ta_state=False):
|
|
800
785
|
for i in range(self.number_of_outputs):
|
|
801
|
-
print("
|
|
786
|
+
print("\nCLASS %d\n" % (i,))
|
|
802
787
|
self.tms[i].print_hierarchy(print_ta_state = print_ta_state)
|
|
803
788
|
|
|
804
789
|
def load(self, state_dict: dict):
|
|
@@ -813,7 +798,7 @@ class MultiClassTsetlinMachine:
|
|
|
813
798
|
self.configured = True
|
|
814
799
|
|
|
815
800
|
class TsetlinMachine(CommonTsetlinMachine):
|
|
816
|
-
def __init__(self, number_of_clauses, T, s, q=1.0,
|
|
801
|
+
def __init__(self, number_of_clauses, T, s, q=1.0, 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):
|
|
817
802
|
self.negative_clauses = 1
|
|
818
803
|
self.flip_polarity = 0
|
|
819
804
|
|
|
@@ -822,7 +807,7 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
822
807
|
else:
|
|
823
808
|
self.tm_type = VANILLA_TM
|
|
824
809
|
|
|
825
|
-
super().__init__(number_of_clauses, T, s, q=q,
|
|
810
|
+
super().__init__(number_of_clauses, T, s, q=q, 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)
|
|
826
811
|
|
|
827
812
|
def fit(self, X, Y):
|
|
828
813
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -846,11 +831,11 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
846
831
|
return (self.score(X) >= 0).astype(np.int32)
|
|
847
832
|
|
|
848
833
|
class RegressionTsetlinMachine(CommonTsetlinMachine):
|
|
849
|
-
def __init__(self, number_of_clauses, T, s,
|
|
834
|
+
def __init__(self, number_of_clauses, T, s, 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):
|
|
850
835
|
self.negative_clauses = 0
|
|
851
836
|
self.flip_polarity = 0
|
|
852
837
|
|
|
853
|
-
super().__init__(number_of_clauses, T, s,
|
|
838
|
+
super().__init__(number_of_clauses, T, s, 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)
|
|
854
839
|
|
|
855
840
|
def fit(self, X, Y):
|
|
856
841
|
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
|