ccubes-cl/ccubes.cl

287 lines
7.7 KiB
Common Lisp
Raw Normal View History

2025-03-20 19:32:25 +02:00
#ifdef USE_DOUBLE
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
typedef double real;
#define R_ZERO 1e-14
#else
typedef float real;
#define R_ZERO 1e-10
#endif
#define BITS_PER_WORD 32
#define ROW_DIM 0
#define COL_DIM 1
// #pragma OPENCL EXTENSION cl_amd_printf : enable
// #pragma OPENCL EXTENSION cl_khr_select_fprounding_mode : enable
// #pragma OPENCL SELECT_ROUNDING_MODE rtz
#ifdef RANGE_DEBUG
#define RANGE_CHECK(lower, upper, value, str) do { \
if ((value) < (lower) || (value) > (upper)) { \
printf("%s", (str)); \
return; \
} \
} while(0);
#else
#define RANGE_CHECK(lower, upper, value, str)
#endif
unsigned long int
nchoosek(int n, int k)
{
if (k == 0 || k == n) return 1;
if (k == 1) return n;
unsigned long int result = 1;
if (k > n - k) {
k = n - k;
}
for (int i = 0; i < k; i++) {
result = result * (n - i) / (i + 1);
}
return result;
}
/*
*
* PROBLEM: CCubes
*
* INPUT:
* k - current input
* ninputs - number of inputs
* posrows - positive output rows (the ON set)
* negrows - negative output rows (the OFF set)
* pichart_words - words needed per PI chart columns
* implicant_words - words needed per PI representation
* nofvalues (ninputs x 1) - number of values
* nofpi (ninputs x 1) - number of prime implicants
* ON_set (posrows x ninputs) - ON set
* OFF_set (ninputs x negrows) - OFF set
*
* OUTPUT:
* x (n x 1) - solution (L \ b)
*
* NOTE: Both input and output must be allocated before calling this funciton.
*/
__kernel void
ccubes_task(int k, int ninputs,
int posrows,
int negrows,
int pichart_words,
int implicant_words,
__global const real *nofvalues,
__global const real *nofpi,
__global const real *ON_set,
__global const real *OFF_set,
__global const unsigned int *p_implicants_pos,
__global const unsigned int *p_implicants_val,
__global const int *last_index,
__global const int *p_covered,
__global const int *p_pichart_pos,
)
{
/* work-item?: task in nchoosek(ninputs, k) */
/* work-group?: k in 1 to ninputs */
/* total work: tasks in nchoosek for k in 1 to ninputs */
size_t task = get_global_id(0);
int prevfoundPI = 0;
int tempk[k]; /* max is tempk[ninputs] */
int x = 0;
int start_point = task;
// fill the combination for the current task
for (int i = 0; i < k; i++) {
while (nchoosek(ninputs - (x + 1), k - (i + 1)) <= start_point) {
start_point -= nchoosek(ninputs - (x + 1), k - (i + 1));
x++;
}
tempk[i] = x;
x++;
}
// allocate vectors of decimal row numbers for the positive and negative rows
int decpos[posrows];
int decneg[negrows];
// create the vector of multiple bases, useful when calculating the decimal representation
// of a particular combination of columns, for each row
int mbase[k];
mbase[0] = 1; // the first number is _always_ equal to 1, irrespective of the number of values in a certain input
// calculate the vector of multiple bases, for example if we have k = 3 (three inputs) with
// 2, 3 and 2 values then mbase will be [1, 2, 6] from: 1, 1 * 2 = 2, 2 * 3 = 6
for (int i = 1; i < k; i++) {
mbase[i] = mbase[i - 1] * nofvalues[tempk[i - 1]];
}
// calculate decimal numbers, using mbase, fills in decpos and decneg
for (int r = 0; r < posrows; r++) {
decpos[r] = 0;
for (int c = 0; c < k; c++) {
decpos[r] += ON_set[tempk[c] * posrows + r] * mbase[c];
}
}
for (int r = 0; r < negrows; r++) {
decneg[r] = 0;
for (int c = 0; c < k; c++) {
decneg[r] += OFF_set[tempk[c] * negrows + r] * mbase[c];
}
}
int possible_rows[posrows];
bool possible_cover[posrows];
possible_cover[0] = true; // bool flag, to be set with false if found among the OFF set
int found = 0;
// identifies all unique decimal rows, for the selected combination of k inputs
for (int r = 0; r < posrows; r++) {
int prev = 0;
bool unique = true; // bool flag, assume the row is unique
while (prev < found && unique) {
unique = decpos[possible_rows[prev]] != decpos[r];
prev++;
}
if (unique) {
possible_rows[found] = r;
possible_cover[found] = true;
found++;
}
}
if (found > 0) {
// some of the ON set numbers are possible PIs (not found in the OFF set)
int frows[found];
// verify if this is a possible PI
// (if the same decimal number is not found in the OFF set)
for (int i = found - 1; i >= 0; i--) {
int j = 0;
while (j < negrows && possible_cover[i]) {
if (decpos[possible_rows[i]] == decneg[j]) {
possible_cover[i] = false;
found--;
}
j++;
}
if (possible_cover[i]) {
frows[found - i - 1] = possible_rows[i];
}
}
// Rprintf("task: %d; rows: %d\n", task, found);
for (int f = 0; f < found; f++) {
// create a temporary vector of length k, containing the values from the initial ON set
// plus 1 (because 0 now signals a minimization, it becomes 1, and 1 becomes 2 etc.
int tempc[k];
// using bit shifting, store the fixed bits and value bits
unsigned int fixed_bits[implicant_words];
unsigned int value_bits[implicant_words];
for (int i = 0; i < implicant_words; i++) {
fixed_bits[i] = 0U;
value_bits[i] = 0U;
}
for (int c = 0; c < k; c++) {
int value = ON_set[tempk[c] * posrows + frows[f]];
tempc[c] = value + 1;
int word_index = tempk[c] / BITS_PER_WORD;
int bit_index = tempk[c] % BITS_PER_WORD;
fixed_bits[word_index] |= 1U << bit_index;
value_bits[word_index] |= (unsigned int)value << (bit_index * value_bit_width);
}
// check if the current PI is not redundant
bool redundant = false;
int i = 0;
while (i < prevfoundPI && !redundant) {
// /*
// - ck contains the complexity level for each of the previously found non-redundant PIs
// - indx is a matrix containing the indexes of the columns where the values were stored
// - a redundant PI is one for which all values from a previous PI are exactly the same:
// 0 0 1 2 0, let's say previously found PI
// which means a corresponding ck = 2 and a corresponding indx = [3, 4]
// 0 0 1 2 1 is redundant because on both columns 3 and 4 the values are equal
// therefore sumeq = 2 and it will be equal to v = 2 when reaching the complexity level ck = 2
// */
bool is_subset = true; // Assume it's a subset unless proven otherwise
for (int w = 0; w < implicant_words; w++) {
// If the new PI has values on positions outside the existing PIs fixed positions, its not a subset
if ((fixed_bits[w] & p_implicants_pos[i * implicant_words + w]) != p_implicants_pos[i * implicant_words + w]) {
is_subset = false;
break;
}
// then compare the value bits, if one or more values on those positions are different, its not a subset
if ((value_bits[w] & p_implicants_val[i * implicant_words + w]) != p_implicants_val[i * implicant_words + w]) {
is_subset = false;
break;
}
}
redundant = is_subset;
i++;
}
if (redundant) continue;
bool coverage[posrows];
int covsum = 0;
unsigned int pichart_values[pichart_words];
for (int w = 0; w < pichart_words; w++) {
pichart_values[w] = 0U;
}
for (int r = 0; r < posrows; r++) {
coverage[r] = decpos[r] == decpos[frows[f]];
if (coverage[r]) {
int word_index = r / BITS_PER_WORD;
int bit_index = r % BITS_PER_WORD;
pichart_values[word_index] |= (1U << bit_index);
}
covsum += coverage[r];
}
// verify row dominance
int rd = 0;
while (rd < last_index[covsum - 1] && !redundant) {
bool dominated = true;
for (int w = 0; w < pichart_words; w++) {
if ((pichart_values[w] & p_pichart_pos[p_covered[rd] * pichart_words + w]) != pichart_values[w]) {
dominated = false;
break;
}
}
redundant = dominated;
rd++;
}
if (redundant) continue;
}
}
}