PyHierarchicalTsetlinMachineCUDA 0.3.1__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.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/kernels.py +62 -153
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/tm.py +37 -44
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/utils.py +30 -8
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/PKG-INFO +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/README.md +2 -2
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/setup.py +1 -1
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/LICENSE +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/__init__.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA/tools.py +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/SOURCES.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/dependency_links.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/requires.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → PyHierarchicalTsetlinMachineCUDA-0.3.2}/PyHierarchicalTsetlinMachineCUDA.egg-info/top_level.txt +0 -0
- {PyHierarchicalTsetlinMachineCUDA-0.3.1 → 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) {
|
|
@@ -328,50 +313,29 @@ code_update = """
|
|
|
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
|
-
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
|
-
}
|
|
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;
|
|
349
319
|
}
|
|
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
|
-
}
|
|
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;
|
|
360
324
|
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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];
|
|
367
331
|
}
|
|
368
332
|
}
|
|
369
|
-
|
|
333
|
+
}
|
|
370
334
|
|
|
371
335
|
// Skip node if "turned off" (-1)
|
|
372
336
|
if (group_node_output[group_node] != -1) {
|
|
373
337
|
int selected_child;
|
|
374
|
-
if (
|
|
338
|
+
if (group_node_output[group_node] > 0) {
|
|
375
339
|
int random_child_value = curand(&localState) % child_input_sum;
|
|
376
340
|
child_input_sum = 0;
|
|
377
341
|
for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
|
|
@@ -405,39 +369,15 @@ code_update = """
|
|
|
405
369
|
|
|
406
370
|
// Add up the votes from the children of each OR node
|
|
407
371
|
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
|
-
}
|
|
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
|
+
}
|
|
437
378
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
#endif
|
|
379
|
+
// Store vote sum as node output
|
|
380
|
+
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
|
|
441
381
|
}
|
|
442
382
|
}
|
|
443
383
|
|
|
@@ -458,41 +398,18 @@ code_update = """
|
|
|
458
398
|
int stride = blockDim.x * gridDim.x;
|
|
459
399
|
|
|
460
400
|
// 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
401
|
|
|
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) {
|
|
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
|
|
491
406
|
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause] * clause_output[clause]);
|
|
492
|
-
|
|
493
|
-
|
|
407
|
+
#else
|
|
408
|
+
atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause]);
|
|
409
|
+
#endif
|
|
410
|
+
}
|
|
494
411
|
}
|
|
495
|
-
|
|
412
|
+
}
|
|
496
413
|
}
|
|
497
414
|
|
|
498
415
|
__global__ void rescale_final(int number_of_outputs, float *clause_output_max, float *class_sum)
|
|
@@ -571,11 +488,7 @@ code_update = """
|
|
|
571
488
|
local_class_sum = -THRESHOLD;
|
|
572
489
|
}
|
|
573
490
|
|
|
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
|
|
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);
|
|
579
492
|
}
|
|
580
493
|
}
|
|
581
494
|
|
|
@@ -600,11 +513,7 @@ code_update = """
|
|
|
600
513
|
local_class_sum = -THRESHOLD;
|
|
601
514
|
}
|
|
602
515
|
|
|
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
|
|
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);
|
|
608
517
|
}
|
|
609
518
|
}
|
|
610
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
|
|
|
@@ -127,7 +130,9 @@ class CommonTsetlinMachine():
|
|
|
127
130
|
#define S %f
|
|
128
131
|
#define THRESHOLD %d
|
|
129
132
|
#define Q %f
|
|
130
|
-
#define
|
|
133
|
+
#define BINARY_INFERENCE %d
|
|
134
|
+
#define CONSTANT_UPDATE_P %d
|
|
135
|
+
#define AND_GROUP_NORMALIZATION %d
|
|
131
136
|
|
|
132
137
|
#define AND_GROUP %d
|
|
133
138
|
#define AND_ALTERNATIVES %d
|
|
@@ -136,8 +141,8 @@ class CommonTsetlinMachine():
|
|
|
136
141
|
|
|
137
142
|
#define NEGATIVE_CLAUSES %d
|
|
138
143
|
#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
|
-
|
|
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
|
+
|
|
141
146
|
mod_prepare = SourceModule(parameters + kernels.code_header + kernels.code_prepare, no_extern_c=True)
|
|
142
147
|
self.prepare_weights = mod_prepare.get_function("prepare_weights")
|
|
143
148
|
self.prepare_hierarchy = mod_prepare.get_function("prepare_hierarchy")
|
|
@@ -329,15 +334,6 @@ class CommonTsetlinMachine():
|
|
|
329
334
|
self.clause_output_max[:] = np.finfo(np.float32).min
|
|
330
335
|
cuda.memcpy_htod(self.clause_output_max_gpu, self.clause_output_max)
|
|
331
336
|
|
|
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
337
|
# Adds up the votes from each clause (hierarchy root)
|
|
342
338
|
self.evaluate_final.prepared_call(
|
|
343
339
|
self.grid,
|
|
@@ -348,15 +344,6 @@ class CommonTsetlinMachine():
|
|
|
348
344
|
self.class_sum_gpu
|
|
349
345
|
)
|
|
350
346
|
|
|
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
347
|
def _fit(self, X, encoded_Y):
|
|
361
348
|
if self.number_of_features_hierarchy != X.shape[1]:
|
|
362
349
|
print("The number of features spanned by hierarchy does not align with the input data.")
|
|
@@ -445,15 +432,18 @@ class CommonTsetlinMachine():
|
|
|
445
432
|
encoded_X_hierarchy_test_gpu = cuda.mem_alloc(int(number_of_examples * self.number_of_literal_chunks * 4))
|
|
446
433
|
self.encode_X(X, encoded_X_hierarchy_test_gpu)
|
|
447
434
|
|
|
448
|
-
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)
|
|
449
436
|
|
|
450
437
|
for e in range(number_of_examples):
|
|
451
438
|
self.evaluate_hierarchy(encoded_X_hierarchy_test_gpu, e)
|
|
452
439
|
|
|
453
440
|
cuda.memcpy_dtoh(self.class_sum, self.class_sum_gpu)
|
|
454
|
-
class_sum[:, e] = self.class_sum
|
|
441
|
+
class_sum[:, e] = self.class_sum
|
|
455
442
|
|
|
456
|
-
|
|
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)
|
|
457
447
|
|
|
458
448
|
return class_sum
|
|
459
449
|
|
|
@@ -500,7 +490,7 @@ class CommonTsetlinMachine():
|
|
|
500
490
|
continue
|
|
501
491
|
|
|
502
492
|
n_children = self.hierarchy_structure[level][1]
|
|
503
|
-
is_alt =
|
|
493
|
+
is_alt = self.hierarchy_structure[level][0] in (OR_ALTERNATIVES, AND_ALTERNATIVES)
|
|
504
494
|
for child_pos in range(n_children):
|
|
505
495
|
child_id = node_id * n_children + child_pos
|
|
506
496
|
if is_alt:
|
|
@@ -599,12 +589,12 @@ class CommonTsetlinMachine():
|
|
|
599
589
|
if self.ta_action(i, j, k):
|
|
600
590
|
if (not self.append_negated) or k < self.number_of_literals_per_leaf // 2:
|
|
601
591
|
if print_ta_state:
|
|
602
|
-
l.append("x%d
|
|
592
|
+
l.append("x%d[%d]" % (feature_base + k, self.ta_state(i, j, k)))
|
|
603
593
|
else:
|
|
604
594
|
l.append("x%d" % (feature_base + k,))
|
|
605
595
|
else:
|
|
606
596
|
if print_ta_state:
|
|
607
|
-
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)))
|
|
608
598
|
else:
|
|
609
599
|
l.append("¬x%d" % (feature_base + k - self.number_of_literals_per_leaf // 2,))
|
|
610
600
|
|
|
@@ -658,9 +648,9 @@ class CommonTsetlinMachine():
|
|
|
658
648
|
|
|
659
649
|
|
|
660
650
|
class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
661
|
-
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):
|
|
662
652
|
self.negative_clauses = 1
|
|
663
|
-
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)
|
|
664
654
|
|
|
665
655
|
def fit(self, X, Y):
|
|
666
656
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -684,12 +674,12 @@ class MultiOutputTsetlinMachine(CommonTsetlinMachine):
|
|
|
684
674
|
return (self.score(X) >= 0).astype(np.uint32).transpose()
|
|
685
675
|
|
|
686
676
|
class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
687
|
-
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):
|
|
688
678
|
self.negative_clauses = 1
|
|
689
679
|
self.tm_type = COALESCED_TM
|
|
690
680
|
self.flip_polarity = 1
|
|
691
681
|
|
|
692
|
-
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)
|
|
693
683
|
|
|
694
684
|
def fit(self, X, Y):
|
|
695
685
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -716,12 +706,15 @@ class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
|
|
|
716
706
|
return np.argmax(self.score(X), axis=0)
|
|
717
707
|
|
|
718
708
|
class MultiClassTsetlinMachine:
|
|
719
|
-
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):
|
|
720
710
|
self.number_of_clauses = number_of_clauses
|
|
721
711
|
self.T = T
|
|
722
712
|
self.s = s
|
|
723
713
|
self.q = q
|
|
724
|
-
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
|
|
725
718
|
self.weighted_clauses = weighted_clauses
|
|
726
719
|
self.hierarchy_structure = hierarchy_structure
|
|
727
720
|
self.boost_true_positive_feedback = boost_true_positive_feedback
|
|
@@ -739,7 +732,7 @@ class MultiClassTsetlinMachine:
|
|
|
739
732
|
if not self.configured:
|
|
740
733
|
self.tms = []
|
|
741
734
|
for i in range(self.number_of_outputs):
|
|
742
|
-
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))
|
|
743
736
|
|
|
744
737
|
self.configured = True
|
|
745
738
|
|
|
@@ -760,7 +753,7 @@ class MultiClassTsetlinMachine:
|
|
|
760
753
|
return
|
|
761
754
|
|
|
762
755
|
def score(self, X):
|
|
763
|
-
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)
|
|
764
757
|
for i in range(self.number_of_outputs):
|
|
765
758
|
class_sums[i,:] = self.tms[i].score(X)
|
|
766
759
|
|
|
@@ -790,7 +783,7 @@ class MultiClassTsetlinMachine:
|
|
|
790
783
|
|
|
791
784
|
def print_hierarchy(self, print_ta_state=False):
|
|
792
785
|
for i in range(self.number_of_outputs):
|
|
793
|
-
print("
|
|
786
|
+
print("\nCLASS %d\n" % (i,))
|
|
794
787
|
self.tms[i].print_hierarchy(print_ta_state = print_ta_state)
|
|
795
788
|
|
|
796
789
|
def load(self, state_dict: dict):
|
|
@@ -805,7 +798,7 @@ class MultiClassTsetlinMachine:
|
|
|
805
798
|
self.configured = True
|
|
806
799
|
|
|
807
800
|
class TsetlinMachine(CommonTsetlinMachine):
|
|
808
|
-
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):
|
|
809
802
|
self.negative_clauses = 1
|
|
810
803
|
self.flip_polarity = 0
|
|
811
804
|
|
|
@@ -814,7 +807,7 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
814
807
|
else:
|
|
815
808
|
self.tm_type = VANILLA_TM
|
|
816
809
|
|
|
817
|
-
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)
|
|
818
811
|
|
|
819
812
|
def fit(self, X, Y):
|
|
820
813
|
X = X.reshape(X.shape[0], X.shape[1], 1)
|
|
@@ -838,11 +831,11 @@ class TsetlinMachine(CommonTsetlinMachine):
|
|
|
838
831
|
return (self.score(X) >= 0).astype(np.int32)
|
|
839
832
|
|
|
840
833
|
class RegressionTsetlinMachine(CommonTsetlinMachine):
|
|
841
|
-
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):
|
|
842
835
|
self.negative_clauses = 0
|
|
843
836
|
self.flip_polarity = 0
|
|
844
837
|
|
|
845
|
-
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)
|
|
846
839
|
|
|
847
840
|
def fit(self, X, Y):
|
|
848
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
|