PyHierarchicalTsetlinMachineCUDA 0.2.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ole-Christoffer Granmo and the University of Agder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.1
2
+ Name: PyHierarchicalTsetlinMachineCUDA
3
+ Version: 0.2.2
4
+ Summary: Hierarchical Tsetlin Machine Architecture.
5
+ Home-page: https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/
6
+ Author: Ole-Christoffer Granmo
7
+ Author-email: ole.granmo@uia.no
8
+ License: MIT
9
+ Keywords: pattern-recognition cuda machine-learning interpretable-machine-learning rule-based-machine-learning propositional-logic tsetlin-machine regression convolution classification multi-layer
10
+ Provides-Extra: examples
11
+ License-File: LICENSE
12
+
13
+ Hierarchical Tsetlin Machine Architecture.
@@ -0,0 +1,485 @@
1
+ # Copyright (c) 2026 Ole-Christoffer Granmo and the University of Agder
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ code_header = """
22
+ #include <curand_kernel.h>
23
+
24
+ #define INT_SIZE 32ULL
25
+
26
+ #if (LITERALS_PER_LEAF % 32 != 0)
27
+ #define FILTER_HIERARCHICAL (~(0xffffffff << (LITERALS_PER_LEAF % INT_SIZE)))
28
+ #else
29
+ #define FILTER_HIERARCHICAL 0xffffffff
30
+ #endif
31
+
32
+ #define VANILLA_TM 0
33
+
34
+ #define WEIGHTED_TM 1
35
+
36
+ #define COALESCED_TM 2
37
+ """
38
+
39
+ code_update = """
40
+ extern "C"
41
+ {
42
+ // Increment the states of each of those 32 Tsetlin Automata flagged in the active bit vector.
43
+ __device__ inline void inc(unsigned int *ta_state, int chunk, unsigned int active)
44
+ {
45
+ unsigned int carry, carry_next;
46
+ int id = chunk*STATE_BITS;
47
+ carry = active;
48
+ for (int b = 0; b < STATE_BITS; ++b) {
49
+ if (carry == 0)
50
+ break;
51
+
52
+ carry_next = ta_state[id + b] & carry; // Sets carry bits (overflow) passing on to next bit
53
+ ta_state[id + b] = ta_state[id + b] ^ carry; // Performs increments with XOR
54
+ carry = carry_next;
55
+ }
56
+
57
+ if (carry > 0) {
58
+ for (int b = 0; b < STATE_BITS; ++b) {
59
+ ta_state[id + b] |= carry;
60
+ }
61
+ }
62
+ }
63
+
64
+ // Decrement the states of each of those 32 Tsetlin Automata flagged in the active bit vector.
65
+ __device__ inline void dec(unsigned int *ta_state, int chunk, unsigned int active)
66
+ {
67
+ unsigned int carry, carry_next;
68
+ int id = chunk*STATE_BITS;
69
+ carry = active;
70
+ for (int b = 0; b < STATE_BITS; ++b) {
71
+ if (carry == 0)
72
+ break;
73
+ carry_next = (~ta_state[id + b]) & carry; // Sets carry bits (overflow) passing on to next bit
74
+ ta_state[id + b] = ta_state[id + b] ^ carry; // Performs increments with XOR
75
+ carry = carry_next;
76
+ }
77
+
78
+ if (carry > 0) {
79
+ for (int b = 0; b < STATE_BITS; ++b) {
80
+ ta_state[id + b] &= ~carry;
81
+ }
82
+ }
83
+ }
84
+
85
+ __device__ inline void update_clause_weight(curandState *localState, int tm_type, int number_of_outputs, int *clause_weight, int clause_output, int y, int class_sum)
86
+ {
87
+ int target = 1 - 2*(class_sum > y);
88
+
89
+ if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
90
+ return;
91
+ }
92
+
93
+ int sign = (*clause_weight >= 0) - (*clause_weight < 0);
94
+
95
+ int absolute_prediction_error = abs(y - class_sum);
96
+ if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
97
+ if (target*sign > 0) {
98
+ if (clause_output && abs(*clause_weight) < INT_MAX) {
99
+ (*clause_weight) += sign;
100
+ }
101
+ } else if (target*sign < 0 && clause_output) {
102
+ // Type II Feedback
103
+
104
+ (*clause_weight) -= sign;
105
+
106
+ #if FLIP_POLARITY == 0
107
+ if (*clause_weight == 0) {
108
+ *clause_weight += sign;
109
+ }
110
+ #endif
111
+ }
112
+ }
113
+ }
114
+
115
+ __device__ inline void update_component_hierarchy(curandState *localState, int number_of_outputs, int *clause_weight, unsigned int *ta_state, int component_output, int *X, int y, int class_sum)
116
+ {
117
+ int target = 1 - 2*(class_sum > y);
118
+
119
+ if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
120
+ return;
121
+ }
122
+
123
+
124
+ int sign = (*clause_weight >= 0) - (*clause_weight < 0);
125
+
126
+ int absolute_prediction_error = abs(y - class_sum);
127
+ if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
128
+ if (target*sign > 0) {
129
+ // Type I Feedback
130
+ for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
131
+ // Generate random bit values
132
+ unsigned int la_feedback = 0;
133
+ for (int b = 0; b < INT_SIZE; ++b) {
134
+ if (curand_uniform(localState) <= 1.0/S) {
135
+ la_feedback |= (1 << b);
136
+ }
137
+ }
138
+
139
+ if (component_output) {
140
+ #if BOOST_TRUE_POSITIVE_FEEDBACK == 1
141
+ inc(ta_state, ta_chunk, X[ta_chunk]);
142
+ #else
143
+ inc(ta_state, ta_chunk, X[ta_chunk] & (~la_feedback));
144
+ #endif
145
+
146
+ dec(ta_state, ta_chunk, (~X[ta_chunk]) & la_feedback);
147
+ } else {
148
+ dec(ta_state, ta_chunk, la_feedback);
149
+ }
150
+ }
151
+ } else if (target*sign < 0 && component_output) {
152
+ // Type II Feedback
153
+
154
+ for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
155
+ inc(ta_state, ta_chunk, (~X[ta_chunk]) & (~ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]));
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ // Evaluate example
162
+ __global__ void evaluate_leaves(unsigned int *global_ta_state, int *component_weights, int *global_component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_alternatives, int *X, int example)
163
+ {
164
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
165
+ int stride = blockDim.x * gridDim.x;
166
+
167
+ int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
168
+
169
+ // Evaluate each clause component (leaf) in separate threads
170
+ for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
171
+ int component = clause_component % COMPONENTS;
172
+
173
+ // Get state of current clause component
174
+ unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
175
+
176
+ int component_remainder = component;
177
+ int ta_chunk_base = 0;
178
+ int size = 1;
179
+ for (int d = 0; d < depth-1; ++d) {
180
+ int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
181
+ component_remainder = component_remainder / hierarchy_structure_factors[d];
182
+
183
+ if (hierarchy_structure_alternatives[d] == 0) {
184
+ ta_chunk_base += size * depth_d_node_index * TA_CHUNKS_PER_LEAF;
185
+ size *= hierarchy_structure_factors[d];
186
+ }
187
+ }
188
+
189
+ // Evaluate clause component
190
+ int component_output = 1;
191
+ for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF-1; ++ta_chunk) {
192
+ // Compare the TA state of the component (leaf) against the corresponding part of the feature vector
193
+ if ((ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] & Xi[ta_chunk_base + ta_chunk]) != ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]) {
194
+ component_output = 0;
195
+ break;
196
+ }
197
+ }
198
+
199
+ if ((ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & Xi[ta_chunk_base + TA_CHUNKS_PER_LEAF-1] & FILTER_HIERARCHICAL) != (ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & FILTER_HIERARCHICAL)) {
200
+ component_output = 0;
201
+ }
202
+
203
+ global_component_output[clause_component] = component_output;
204
+ }
205
+ }
206
+
207
+ __global__ void evaluate_or_groups(int *child_input, int *or_group_node_output, int number_of_or_group_nodes, int number_of_or_group_addends)
208
+ {
209
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
210
+ int stride = blockDim.x * gridDim.x;
211
+
212
+ // Add up the votes of each OR node child
213
+ for (int or_group_node = index; or_group_node < CLAUSES*number_of_or_group_nodes; or_group_node += stride) {
214
+ // Add OR addends
215
+ int or_group_vote_sum = 0;
216
+ for (int or_addend = 0; or_addend < number_of_or_group_addends; ++or_addend) {
217
+ // Aggregate votes from each child node through addition
218
+ or_group_vote_sum += child_input[or_group_node*number_of_or_group_addends + or_addend];
219
+ //if (child_input[or_group_node*number_of_or_group_addends + or_addend]) {
220
+ // or_group_vote_sum = 1;
221
+ //}
222
+ }
223
+
224
+ // Store or group vote sum as node output
225
+ or_group_node_output[or_group_node] = or_group_vote_sum;
226
+ }
227
+ }
228
+
229
+ __global__ void evaluate_and_groups(int *child_input, int *and_group_node_output, int number_of_and_group_nodes, int number_of_and_group_factors)
230
+ {
231
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
232
+ int stride = blockDim.x * gridDim.x;
233
+
234
+ // Multiply the votes from the children of each AND node
235
+ for (int and_group_node = index; and_group_node < CLAUSES*number_of_and_group_nodes; and_group_node += stride) {
236
+ // Multiply and factors
237
+ int and_group_vote_product = 1;
238
+ for (int and_factor = 0; and_factor < number_of_and_group_factors; ++and_factor) {
239
+ // Aggregate votes from each child node through multiplication
240
+ and_group_vote_product *= child_input[and_group_node*number_of_and_group_factors + and_factor];
241
+ }
242
+
243
+ // Store and group product as node output
244
+ and_group_node_output[and_group_node] = and_group_vote_product;
245
+ }
246
+ }
247
+
248
+ __global__ void propagate_and_group_false_truth_values(int *child_input, int *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
249
+ {
250
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
251
+ int stride = blockDim.x * gridDim.x;
252
+
253
+ // If a group node is false, all children are made false.
254
+ for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
255
+ if (group_node_output[group_node] == 0) {
256
+ for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
257
+ if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
258
+ child_input[group_node*number_of_group_node_children + and_factor] = 0;
259
+ }
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ __global__ void evaluate_or_alternatives(int *child_input, int *or_alternatives_node_output, int number_of_or_alternatives_nodes, int number_of_or_alternatives)
266
+ {
267
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
268
+ int stride = blockDim.x * gridDim.x;
269
+
270
+ // Add up the votes from the children of each OR node
271
+ for (int or_alternatives_node = index; or_alternatives_node < CLAUSES*number_of_or_alternatives_nodes; or_alternatives_node += stride) {
272
+ // Sum up votes from each or alternative
273
+ int or_alternatives_vote_sum = 0;
274
+ for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
275
+ // Aggregate same input or alternatives through summation
276
+ or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
277
+
278
+ //if (child_input[or_alternatives_node * number_of_or_alternatives + or_alternative]) {
279
+ // or_alternatives_vote_sum = 1;
280
+ //}
281
+ }
282
+
283
+ // Store vote sum as node output
284
+ or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
285
+ }
286
+ }
287
+
288
+ __global__ void evaluate_final(int number_of_outputs, int *child_input, int *clause_weights, int *class_sum)
289
+ {
290
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
291
+ int stride = blockDim.x * gridDim.x;
292
+
293
+ // Add up the votes from each clause
294
+ for (int clause = index; clause < CLAUSES; clause += stride) {
295
+ if (child_input[clause]) {
296
+ for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
297
+ int clause_weight = clause_weights[class_id*CLAUSES + clause];
298
+ atomicAdd(&class_sum[class_id], clause_weight * child_input[clause]);
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ // Update state of Tsetlin Automata team
305
+ __global__ void update_hierarchy(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, int *component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_alternatives, int *class_sum, int *X, int *y, int example)
306
+ {
307
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
308
+ int stride = blockDim.x * gridDim.x;
309
+
310
+ /* Copy state to local memory for efficiency */
311
+ curandState localState = state[index];
312
+
313
+ int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
314
+
315
+ // Calculate clause output first
316
+ for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
317
+ int clause = clause_component / COMPONENTS;
318
+ int component = clause_component % COMPONENTS;
319
+
320
+ // Get state of current clause component
321
+ unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
322
+
323
+ int component_remainder = component;
324
+ int ta_chunk_base = 0;
325
+ int size = 1;
326
+ for (int d = 0; d < depth-1; ++d) {
327
+ int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
328
+ component_remainder = component_remainder / hierarchy_structure_factors[d];
329
+
330
+ if (hierarchy_structure_alternatives[d] == 0) {
331
+ ta_chunk_base += size * depth_d_node_index * TA_CHUNKS_PER_LEAF;
332
+ size *= hierarchy_structure_factors[d];
333
+ }
334
+ }
335
+
336
+ for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
337
+ int local_class_sum = class_sum[class_id];
338
+ if (local_class_sum > THRESHOLD) {
339
+ local_class_sum = THRESHOLD;
340
+ } else if (local_class_sum < -THRESHOLD) {
341
+ local_class_sum = -THRESHOLD;
342
+ }
343
+
344
+ update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, component_output[clause_component], &Xi[ta_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
345
+ }
346
+ }
347
+
348
+ state[index] = localState;
349
+ }
350
+
351
+ // Update state of Tsetlin Automata team
352
+ __global__ void update_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, int *clause_output, int *class_sum, int *y, int example)
353
+ {
354
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
355
+ int stride = blockDim.x * gridDim.x;
356
+
357
+ /* Copy state to local memory for efficiency */
358
+ curandState localState = state[index];
359
+
360
+ for (unsigned long long clause = index; clause < CLAUSES; clause += stride) {
361
+ for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
362
+ int local_class_sum = class_sum[class_id];
363
+ if (local_class_sum > THRESHOLD) {
364
+ local_class_sum = THRESHOLD;
365
+ } else if (local_class_sum < -THRESHOLD) {
366
+ local_class_sum = -THRESHOLD;
367
+ }
368
+ update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], clause_output[clause], y[example*number_of_outputs + class_id], local_class_sum);
369
+ }
370
+ }
371
+
372
+ state[index] = localState;
373
+ }
374
+ }
375
+ """
376
+
377
+ code_prepare = """
378
+ extern "C"
379
+ {
380
+ __global__ void prepare_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, int *class_sum)
381
+ {
382
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
383
+ int stride = blockDim.x * gridDim.x;
384
+
385
+ curandState localState = state[index];
386
+
387
+ for (unsigned long long clause = index; clause < CLAUSES; clause += stride) {
388
+ for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
389
+ #if NEGATIVE_CLAUSES == 1
390
+ if (tm_type == COALESCED_TM) {
391
+ clause_weights[class_id*CLAUSES + clause] = 1 - 2 * (curand(&localState) % 2);
392
+ } else {
393
+ clause_weights[class_id*CLAUSES + clause] = 1 - 2 * (clause % 2);
394
+ }
395
+ #else
396
+ clause_weights[class_id*CLAUSES + clause] = 1;
397
+ #endif
398
+ }
399
+ }
400
+
401
+ state[index] = localState;
402
+ }
403
+
404
+ __global__ void prepare_hierarchy(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, int *class_sum)
405
+ {
406
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
407
+ int stride = blockDim.x * gridDim.x;
408
+
409
+ curandState localState = state[index];
410
+
411
+ // Evaluate each clause component (leaf) in separate threads
412
+ for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
413
+ // Get state of current clause component
414
+ unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
415
+ for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
416
+ for (int b = 0; b < STATE_BITS-1; ++b) {
417
+ ta_state[ta_chunk*STATE_BITS + b] = ~0;
418
+ }
419
+ ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] = 0;
420
+ }
421
+ }
422
+
423
+ state[index] = localState;
424
+ }
425
+ }
426
+ """
427
+
428
+ code_encode = """
429
+ #include <curand_kernel.h>
430
+
431
+ extern "C"
432
+ {
433
+ __global__ void prepare_encode_hierarchy(unsigned int *X, unsigned int *encoded_X, int number_of_literal_chunks, int number_of_examples)
434
+ {
435
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
436
+ int stride = blockDim.x * gridDim.x;
437
+
438
+ for (unsigned long long i = index; i < number_of_examples * number_of_literal_chunks; i += stride) {
439
+ encoded_X[i] = 0;
440
+ }
441
+ }
442
+
443
+ __global__ void encode_hierarchy(unsigned int *X, unsigned int *encoded_X, int number_of_features, int number_of_literal_chunks, int number_of_leaves, int number_of_features_per_leaf, int number_of_literal_chunks_per_leaf, int append_negated, int number_of_examples)
444
+ {
445
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
446
+ int stride = blockDim.x * gridDim.x;
447
+
448
+ unsigned int *Xi;
449
+ unsigned int *encoded_Xi;
450
+
451
+ for (unsigned long long i = index; i < number_of_examples; i += stride) {
452
+ Xi = &X[i*number_of_features];
453
+ encoded_Xi = &encoded_X[i*number_of_literal_chunks];
454
+
455
+ for (int j = 0; j < number_of_features / number_of_features_per_leaf; ++j) {
456
+ for (int k = 0; k < number_of_features_per_leaf; ++k) {
457
+ if (Xi[j*number_of_features_per_leaf + k] == 1) {
458
+ int leaf_chunk_nr = k / 32;
459
+ int leaf_chunk_pos = k % 32;
460
+ encoded_Xi[j*number_of_literal_chunks_per_leaf + leaf_chunk_nr] |= (1 << leaf_chunk_pos);
461
+ } else if (append_negated) {
462
+ int leaf_chunk_nr = (k + number_of_features_per_leaf) / 32;
463
+ int leaf_chunk_pos = (k + number_of_features_per_leaf) % 32;
464
+ encoded_Xi[j*number_of_literal_chunks_per_leaf + leaf_chunk_nr] |= (1 << leaf_chunk_pos);
465
+ }
466
+ }
467
+ }
468
+ }
469
+ }
470
+ }
471
+ """
472
+
473
+ code_transform = """
474
+ extern "C"
475
+ {
476
+ // Transform examples
477
+ __global__ void transform(unsigned int *global_ta_state, int *X, int *transformed_X)
478
+ {
479
+ int index = blockIdx.x * blockDim.x + threadIdx.x;
480
+ int stride = blockDim.x * gridDim.x;
481
+
482
+ // To be updated
483
+ }
484
+ }
485
+ """