Merge HEAD on Github from AD.

This commit is contained in:
Paul Irofti 2025-03-28 02:12:10 +02:00
parent 879f44d6a4
commit 909f1fdef5
13 changed files with 349 additions and 184 deletions

View file

@ -10,7 +10,7 @@ Authors@R: c(
URL: https://github.com/dusadrian/IEEE URL: https://github.com/dusadrian/IEEE
BugReports: https://github.com/dusadrian/IEEE/issues BugReports: https://github.com/dusadrian/IEEE/issues
Depends: R (>= 3.6.0) Depends: R (>= 3.6.0)
Imports: LogicOpt, Matrix, gurobi Imports: admisc, LogicOpt, lpSolve, Matrix, gurobi
Description: An extensive set of functions to perform Qualitative Comparative Analysis: Description: An extensive set of functions to perform Qualitative Comparative Analysis:
crisp sets ('csQCA'), temporal ('tQCA'), multi-value ('mvQCA') crisp sets ('csQCA'), temporal ('tQCA'), multi-value ('mvQCA')
and fuzzy sets ('fsQCA'), using a GUI - graphical user interface. and fuzzy sets ('fsQCA'), using a GUI - graphical user interface.

View file

@ -1,7 +1,10 @@
importFrom("gurobi", "gurobi") importFrom("gurobi", "gurobi")
importFrom("lpSolve", "lp")
importFrom("Matrix", "Matrix") importFrom("Matrix", "Matrix")
importFrom("utils", "tail") importFrom("utils", "tail")
importFrom("LogicOpt", "logicopt") importFrom("LogicOpt", "logicopt")
importFrom("admisc", "recode", "export", "tryCatchWEM")
export(compare)
export(gendat) export(gendat)
export(make_infile) export(make_infile)
export(solvechart) export(solvechart)

90
R/compare.R Normal file
View file

@ -0,0 +1,90 @@
compare <- function(
iter = 1:10,
ncols = 21:27,
nrows = 25:35,
file = "results.csv",
espresso = TRUE,
avg = 1
) {
on.exit({
suppressWarnings(sink())
})
for (nc in ncols) {
for (nr in nrows) {
for (i in iter) {
dat <- gendat(i, nc, nr)
make_infile(dat)
## $ sudo port install espresso
# lo <- system("espresso -Dexact -o eqntott infile.esp", intern = TRUE)[1]
if (espresso) {
etc <- admisc::tryCatchWEM(
es_time <- system.time(
elo <- LogicOpt::logicopt(esp_file = "infile.esp")
)
)
}
ctc <- admisc::tryCatchWEM({
cc_time <- NULL
for (ii in seq(avg)) {
cc_time <- c(
cc_time,
system.time(
cc <- .Call("CCubes", dat, PACKAGE = "IEEE")
)[3]
)
}
})
if (is.null(ctc)) {
colnames(cc) <- colnames(dat)[-nc]
if (espresso) {
soles <- apply(
elo[[1]][, -nc], 1,
function(x) {
x <- x[x != "-"]
names(x)[x == 0] <- paste("!", names(x)[x == 0], sep = "")
return(c(paste(names(x), collapse = "&"), length(x)))
}
)
}
solcc <- apply(cc, 1, function(x) {
x <- x[x > 0] - 1
names(x)[x == 0] <- paste("!", names(x)[x == 0], sep = "")
return(c(paste(names(x), collapse = "&"), length(x)))
})
sink(file, append = TRUE)
cat(
sprintf(
"%s, %s, %s, %s, %s, %s%s, %s%s\n",
i, nc, nr,
round(es_time[3], 3),
round(min(cc_time), 3),
ifelse(
espresso,
paste0("\"(", paste(soles[1, ], collapse = ") + ("), ")\", "),
""
),
paste0("\"(", paste(solcc[1, ], collapse = ") + ("), ")\""),
ifelse(
espresso,
paste(paste(soles[2, ], collapse = ""), ", ", sep = ""),
""
),
paste(solcc[2, ], collapse = "")
)
)
sink()
} else {
cat(sprintf("i: %s, nc: %s, nr: %s\n", i, nc, nr))
}
}
}
}
}

View file

@ -1,6 +1,6 @@
gendat <- function(i, ncols, nrows) { gendat <- function(iter, ncols, nrows) {
set.seed(i * nrows * ncols) set.seed(iter * nrows * ncols)
# all configurations BUT the outcome have to be unique # all configurations BUT the outcome have to be unique
dat <- unique( dat <- unique(

View file

@ -48,7 +48,6 @@
value <- value[seq(PIs)] value <- value[seq(PIs)]
} }
# cat("Saving the PI chart to a file\n")
# admisc::export( # admisc::export(
# as.data.frame(t(x)), # as.data.frame(t(x)),
# file = paste("pic", sample(5000, 1), ".csv", sep = ""), # file = paste("pic", sample(5000, 1), ".csv", sep = ""),

41
man/compare.Rd Normal file
View file

@ -0,0 +1,41 @@
\name{compare}
\alias{compare}
\title{Compare CCubes results against Espresso}
\description{
Compare CCubes results against Espresso
}
\usage{
compare(
iter = 1:10,
ncols = 21:27,
nrows = 25:35,
file = "results.csv",
espresso = TRUE,
avg = FALSE
)
}
\arguments{
\item{iter}{Iterator}
\item{ncols}{Number of columns}
\item{nrows}{Number of rows}
\item{file}{Character, name / path to the file where results are written}
\item{espresso}{Boolean, also write Espresso results}
\item{avg}{Numeric, number of runs to average results over}
}
\author{
Adrian Dusa
}
\examples{
\dontrun{
compare(1, 7, 15)
}
}
\keyword{functions}

33
man/gendat.Rd Normal file
View file

@ -0,0 +1,33 @@
\name{gendat}
\alias{gendat}
\title{Generate a binary matrix}
\description{
Generate a random binary matrix for testing purposes.
}
\usage{
gendat(iter, ncols, nrows)
}
\arguments{
\item{iter}{Iterator}
\item{ncols}{Number of columns}
\item{nrows}{Number of rows}
}
\value{
A matrix containing binary values.
}
\author{
Adrian Dusa
}
\examples{
gendat(1, 7, 15)
}
\keyword{functions}

39
man/make_infile.Rd Normal file
View file

@ -0,0 +1,39 @@
\name{make_infile}
\alias{make_infile}
\title{Create an infile for espresso}
\description{
Create a text file containing the data for the expresso minimizer.
}
\usage{
make_infile(dat, espname = "infile.esp", copy = FALSE, ...)
}
\arguments{
\item{dat}{A binary matrix}
\item{espname}{Name of the text file}
\item{copy}{Logical, copy the file with a different name.}
\item{...}{Other arguments.}
}
\details{
Different iterations generate different versions of the data.
They are all temporarily saved into \dQuote{infile.esp} unless
the argument \code{copy} is activated, which copies the infile
into a file with a name containing the iterator, the number of
columns and the number of rows.
}
\author{
Adrian Dusa
}
\examples{
dat <- gendat(1, 7, 15)
make_infile(dat)
}
\keyword{functions}

43
man/solvechart.Rd Normal file
View file

@ -0,0 +1,43 @@
\name{solvechart}
\alias{solvechart}
\title{Find the minimum for a prime implicants chart}
\description{
Solve a PI chart using a minimum number of prime implicants.
}
\usage{
solvechart(x, ...)
}
\arguments{
\item{x}{A binary matrix.}
\item{...}{Other arguments.}
}
\details{
A PI chart, in this package, is a binary matrix containing the prime implicants on the columns
and the observed positive minterms on the rows.
}
\value{
A vector of binary values
}
\author{
Adrian Dusa
}
\examples{
set.seed(12345)
x <- matrix(
sample(0:1, prob = c(0.65, 0.35), size = 35, replace = TRUE),
nrow = 5
)
solvechart(x)
}
\keyword{functions}

View file

@ -1,6 +1,6 @@
#include <R.h>
#include <R_ext/RS.h> #include <R_ext/RS.h>
#include <R_ext/Boolean.h> #include <R_ext/Boolean.h>
#include <R.h>
#include <Rinternals.h> #include <Rinternals.h>
#include <Rmath.h> #include <Rmath.h>
#include <R_ext/Rdynload.h> #include <R_ext/Rdynload.h>
@ -24,11 +24,10 @@
#include "config.h" #include "config.h"
#include "logging.h" #include "logging.h"
// $ export BITS_PER_WORD=32 in the Terminal, before running R
SEXP CCubes(SEXP tt) { SEXP CCubes(SEXP tt) {
// $ export BITS_PER_WORD=32 in the Terminal, before running R
// 32 bits per word, in bit shifting representation // 32 bits per word, in bit shifting representation
char *bits_per_word = getenv("BITS_PER_WORD"); // Read from the PATH char *bits_per_word = getenv("BITS_PER_WORD"); // Read from the PATH
int BITS_PER_WORD = bits_per_word ? atoi(bits_per_word) : 32; int BITS_PER_WORD = bits_per_word ? atoi(bits_per_word) : 32;
@ -36,9 +35,15 @@ SEXP CCubes(SEXP tt) {
BITS_PER_WORD = 32; // Default to 32 BITS_PER_WORD = 32; // Default to 32
} }
// $ export PRINT_INFO=1 in the Terminal, before running R // $ export PRINT_INFO=true in the Terminal, before running R
char *print_info = getenv("PRINT_INFO"); // Read from the PATH char *print_info = getenv("PRINT_INFO"); // Read from the PATH
Rboolean PRINT_INFO = print_info && print_info[0] == '1'; Rboolean PRINT_INFO = print_info && (
strcmp(print_info, "1") == 0 ||
strcmp(print_info, "TRUE") == 0 ||
strcmp(print_info, "true") == 0 ||
strcmp(print_info, "T") == 0 ||
strcmp(print_info, "t") == 0
);
int multiplier = 0; int multiplier = 0;
struct timeval start, end; struct timeval start, end;
@ -112,12 +117,18 @@ SEXP CCubes(SEXP tt) {
} }
} }
int value_bit_width = 0; int bits_needed = ceil(log2(max_value)); // Compute the necessary bits
while (max_value > 0) { int value_bit_width = 1;
max_value >>= 1; // Shift right until no bits remain while (value_bit_width < bits_needed) {
value_bit_width++; value_bit_width *= 2; // Round up to the next power of 2
} }
if (value_bit_width > BITS_PER_WORD) {
BITS_PER_WORD = value_bit_width; // Adjust the bits per word
}
int value_bit_mask = (1U << value_bit_width) - 1U;
// calculate the number of values (biggest number) for each input // calculate the number of values (biggest number) for each input
int nofvalues[ninputs]; int nofvalues[ninputs];
int nofpi[ninputs]; int nofpi[ninputs];
@ -146,10 +157,10 @@ SEXP CCubes(SEXP tt) {
int estimPI = 250000; int estimPI = 250000;
// the index of the PIs, in descending order of their number of covered ON-set minterms // the index of the PIs, in descending order of their number of covered ON-set minterms
int *p_covered = R_Calloc(estimPI, int); int *p_covered = (int *) R_Calloc(estimPI, int);
// many PIs will have the same coverage, but they don't necessarily cover the same minterms // many PIs will have the same coverage, but they don't necessarily cover the same minterms
// to employ row dominance when solving the PI chart, we need to compare the coverage of the // to employ row dominance when solving the coverage matrix, we need to compare the coverage of the
// current PI with the coverage of the previous PIs. If this PI survives the comparison, its // current PI with the coverage of the previous PIs. If this PI survives the comparison, its
// coverage has to be added in the p_covered vector, and its order in the p_covered // coverage has to be added in the p_covered vector, and its order in the p_covered
// vector, at the last index of the PI coverage with the same number of minterms // vector, at the last index of the PI coverage with the same number of minterms
@ -158,9 +169,9 @@ SEXP CCubes(SEXP tt) {
// p_pichart = malloc(estimPI * posrows * sizeof(int)); // p_pichart = malloc(estimPI * posrows * sizeof(int));
// memset(p_pichart, false, estimPI * posrows * sizeof(int)); // memset(p_pichart, false, estimPI * posrows * sizeof(int));
int *p_pichart = (int *) R_Calloc(estimPI * posrows, int); int *p_pichart = (int *) R_Calloc(estimPI * posrows, int);
// prefixing (int *) prefills in all values with 0s // prefixing (int *) before R_Calloc() prefills all values with 0s
int pichart_words = (posrows + BITS_PER_WORD - 1) / BITS_PER_WORD; // Words needed per PI chart columns int pichart_words = (posrows + BITS_PER_WORD - 1) / BITS_PER_WORD; // Words needed per coverage matrix columns
unsigned int *p_pichart_pos = (unsigned int *) R_Calloc(estimPI * pichart_words, unsigned int); unsigned int *p_pichart_pos = (unsigned int *) R_Calloc(estimPI * pichart_words, unsigned int);
int implicant_words = (ninputs + BITS_PER_WORD - 1) / BITS_PER_WORD; // Words needed per PI representation int implicant_words = (ninputs + BITS_PER_WORD - 1) / BITS_PER_WORD; // Words needed per PI representation
unsigned int *p_implicants_pos = (unsigned int *) R_Calloc(estimPI * implicant_words, unsigned int); unsigned int *p_implicants_pos = (unsigned int *) R_Calloc(estimPI * implicant_words, unsigned int);
@ -168,15 +179,14 @@ SEXP CCubes(SEXP tt) {
int prevfoundPI = 0; // the number of previously found PIs int prevfoundPI = 0; // the number of previously found PIs
int foundPI = 0; int foundPI = 0;
int prevsolmin = 0; // the minimum number of PIs that solve the PI chart int prevsolmin = 0; // the previous (level k - 1), minimum number of PIs to solve the coverage matrix
int solmin = 0; int solmin = 0;
// the positions of the PIs solving the PI chart // the positions of the PIs solving the coverage matrix
// a vector which can never be lengthier than the number of ON minterms (posrows) // this vector can never be lengthier than the number of ON minterms (posrows)
int previndices[posrows]; int previndices[posrows];
int indices[posrows]; int indices[posrows];
for (int i = 0; i < posrows; i++) { for (int i = 0; i < posrows; i++) {
previndices[i] = 0; previndices[i] = 0;
indices[i] = 0; indices[i] = 0;
@ -200,6 +210,11 @@ SEXP CCubes(SEXP tt) {
} }
int n_tasks = nchoosek(ninputs, k); int n_tasks = nchoosek(ninputs, k);
if (n_tasks == 0) {
// overflow, too many tasks
return (R_NilValue);
}
int n_tasks_batch = 512; int n_tasks_batch = 512;
for (int task = 0; task < n_tasks; task+=n_tasks_batch) { for (int task = 0; task < n_tasks; task+=n_tasks_batch) {
/* adjust if batch size is larger than total job size */ /* adjust if batch size is larger than total job size */
@ -277,22 +292,22 @@ SEXP CCubes(SEXP tt) {
#pragma omp parallel for schedule(dynamic) #pragma omp parallel for schedule(dynamic)
#endif #endif
for (int task = 0; task < nchoosek(ninputs, k); task++) { for (int task = 0; task < n_tasks; task++) {
int tempk[k]; int tempk[k];
int x = 0; int x = 0;
int start_point = task; int combination = task;
// fill the combination for the current task // fill the combination for the current task / combination number
for (int i = 0; i < k; i++) { for (int i = 0; i < k; i++) {
while (nchoosek(ninputs - (x + 1), k - (i + 1)) <= start_point) { while (nchoosek(ninputs - (x + 1), k - (i + 1)) <= combination) {
start_point -= nchoosek(ninputs - (x + 1), k - (i + 1)); combination -= nchoosek(ninputs - (x + 1), k - (i + 1));
x++; x++;
} }
tempk[i] = x; tempk[i] = x;
x++; x++;
} }
// allocate vectors of decimal row numbers for the positive and negative rows // allocate vectors of decimal numbers for the ON-set and OFF-set rows
int decpos[posrows]; int decpos[posrows];
int decneg[negrows]; int decneg[negrows];
@ -326,7 +341,7 @@ SEXP CCubes(SEXP tt) {
int possible_rows[posrows]; int possible_rows[posrows];
Rboolean possible_cover[posrows]; Rboolean possible_cover[posrows];
possible_cover[0] = true; // Rboolean flag, to be set with false if found among the OFF set possible_cover[0] = true; // boolean flag, to be set with false if found among the OFF set
int found = 0; int found = 0;
@ -370,7 +385,6 @@ SEXP CCubes(SEXP tt) {
for (int f = 0; f < found; f++) { for (int f = 0; f < found; f++) {
// create a temporary vector of length k, containing the values from the initial ON set // 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. // plus 1 (because 0 now signals a minimization, it becomes 1, and 1 becomes 2 etc.
int tempc[k]; int tempc[k];
@ -388,11 +402,11 @@ SEXP CCubes(SEXP tt) {
int value = ON_set[tempk[c] * posrows + frows[f]]; int value = ON_set[tempk[c] * posrows + frows[f]];
tempc[c] = value + 1; tempc[c] = value + 1;
int word_index = tempk[c] / BITS_PER_WORD; int word_index = tempk[c] / (BITS_PER_WORD / value_bit_width);
int bit_index = tempk[c] % BITS_PER_WORD; int bit_index = (tempk[c] % (BITS_PER_WORD / value_bit_width)) * value_bit_width;
fixed_bits[word_index] |= 1U << bit_index; fixed_bits[word_index] |= (value_bit_mask << bit_index);
value_bits[word_index] |= (unsigned int)value << (bit_index * value_bit_width); value_bits[word_index] |= ((unsigned int)value << bit_index);
} }
// check if the current PI is not redundant // check if the current PI is not redundant
@ -414,13 +428,15 @@ SEXP CCubes(SEXP tt) {
for (int w = 0; w < implicant_words; w++) { 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 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]) { unsigned int index_mask = p_implicants_pos[i * implicant_words + w];
if ((fixed_bits[w] & index_mask) != index_mask) {
is_subset = false; is_subset = false;
break; break;
} }
// then compare the value bits, if one or more values on those positions are different, its not a subset // 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]) { if ((value_bits[w] & index_mask) != (p_implicants_val[i * implicant_words + w] & index_mask)) {
is_subset = false; is_subset = false;
break; break;
} }
@ -479,7 +495,6 @@ SEXP CCubes(SEXP tt) {
#pragma omp critical #pragma omp critical
#endif #endif
{ {
// push the PI information to the global arrays // push the PI information to the global arrays
for (int i = foundPI; i > last_index[covsum - 1]; i--) { for (int i = foundPI; i > last_index[covsum - 1]; i--) {
@ -497,7 +512,7 @@ SEXP CCubes(SEXP tt) {
p_implicants_val[implicant_words * foundPI + w] = value_bits[w]; p_implicants_val[implicant_words * foundPI + w] = value_bits[w];
} }
// populate the PI chart // populate the coverage matrix
for (int r = 0; r < posrows; r++) { for (int r = 0; r < posrows; r++) {
for (int w = 0; w < pichart_words; w++) { for (int w = 0; w < pichart_words; w++) {
p_pichart_pos[foundPI * pichart_words + w] = pichart_values[w]; p_pichart_pos[foundPI * pichart_words + w] = pichart_values[w];
@ -510,21 +525,20 @@ SEXP CCubes(SEXP tt) {
// when needed, increase allocated memory // when needed, increase allocated memory
if (foundPI / estimPI > 0.9) { if (foundPI / estimPI > 0.9) {
int old_size = estimPI;
estimPI += 100000; estimPI += 100000;
p_pichart = R_Realloc(p_pichart, posrows * estimPI, int); p_pichart = R_Realloc(p_pichart, posrows * estimPI, int);
p_pichart_pos = R_Realloc(p_pichart_pos, estimPI, unsigned int); p_pichart_pos = R_Realloc(p_pichart_pos, pichart_words * estimPI, unsigned int);
p_implicants_val = R_Realloc(p_implicants_val, ninputs * estimPI, unsigned int); p_implicants_val = R_Realloc(p_implicants_val, implicant_words * estimPI, unsigned int);
p_implicants_pos = R_Realloc(p_implicants_pos, ninputs * estimPI, unsigned int); p_implicants_pos = R_Realloc(p_implicants_pos, implicant_words * estimPI, unsigned int);
p_covered = R_Realloc(p_covered, estimPI, int); p_covered = R_Realloc(p_covered, estimPI, int);
for (unsigned int i = old_size; i < posrows * estimPI; i++) { for (unsigned int i = foundPI; i < posrows * estimPI; i++) {
p_pichart[i] = 0; p_pichart[i] = 0;
} }
for (unsigned int i = old_size; i < estimPI; i++) { for (unsigned int i = foundPI; i < pichart_words * estimPI; i++) {
p_pichart_pos[i] = 0U; p_pichart_pos[i] = 0U;
} }
for (unsigned int i = old_size; i < ninputs * estimPI; i++) { for (unsigned int i = foundPI; i < implicant_words * estimPI; i++) {
p_implicants_val[i] = 0U; p_implicants_val[i] = 0U;
p_implicants_pos[i] = 0U; p_implicants_pos[i] = 0U;
} }
@ -565,7 +579,6 @@ SEXP CCubes(SEXP tt) {
if (ON_set_covered) { if (ON_set_covered) {
// Rprintf("posrows: %d; foundPI: %d\n", posrows, foundPI); // Rprintf("posrows: %d; foundPI: %d\n", posrows, foundPI);
if (PRINT_INFO) { if (PRINT_INFO) {
gettimeofday(&end, NULL); // End time gettimeofday(&end, NULL); // End time
elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1e6; elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1e6;
@ -573,8 +586,6 @@ SEXP CCubes(SEXP tt) {
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
} }
SEXP pic = PROTECT(allocMatrix(INTSXP, posrows, foundPI)); SEXP pic = PROTECT(allocMatrix(INTSXP, posrows, foundPI));
for (long long unsigned int i = 0; i < posrows * foundPI; i++) { for (long long unsigned int i = 0; i < posrows * foundPI; i++) {
INTEGER(pic)[i] = p_pichart[i]; INTEGER(pic)[i] = p_pichart[i];
@ -599,13 +610,12 @@ SEXP CCubes(SEXP tt) {
} }
UNPROTECT(5); UNPROTECT(5);
// Rprintf("solution minima: %d\n", solmin); // Rprintf("solution minima: %d\n", solmin);
if (PRINT_INFO) { if (PRINT_INFO) {
gettimeofday(&end, NULL); gettimeofday(&end, NULL);
elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1e6; elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1e6;
Rprintf("Time spent solving the PI chart: %f sec.\n", elapsed_time); Rprintf("Time spent solving the coverage matrix: %f sec.\n", elapsed_time);
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
} }
@ -643,7 +653,7 @@ SEXP CCubes(SEXP tt) {
} }
} }
// printf("solmin: %d\n", solmin); // Rprintf("solmin: %d\n", solmin);
if (PRINT_INFO) { if (PRINT_INFO) {
Rprintf("--- END ---\n"); Rprintf("--- END ---\n");
} }
@ -654,11 +664,13 @@ SEXP CCubes(SEXP tt) {
for (int c = 0; c < solmin; c++) { for (int c = 0; c < solmin; c++) {
for (int r = 0; r < ninputs; r++) { for (int r = 0; r < ninputs; r++) {
unsigned int value = 0; unsigned int value = 0;
int word_index = r / BITS_PER_WORD; // Word index within the implicant int word_index = r / (BITS_PER_WORD / value_bit_width); // Word index within the implicant
int bit_index = r % BITS_PER_WORD; // Bit position within the word int bit_index = (r % (BITS_PER_WORD / value_bit_width)) * value_bit_width; // Bit position within the word
if (p_implicants_pos[indices[c] * implicant_words + word_index] & (1U << bit_index)) { // (1U << bit_index) is just as good
value = 1U + ((p_implicants_val[indices[c] * implicant_words + word_index] >> (bit_index * value_bit_width)) & ((1U << value_bit_width) - 1U)); if (p_implicants_pos[indices[c] * implicant_words + word_index] & (value_bit_mask << bit_index)) {
value = (p_implicants_val[indices[c] * implicant_words + word_index] >> bit_index) & value_bit_mask;
value++; // 0 indicates a minimization, so we increment the value
} }
p_sol[r * solmin + c] = value; // transposed p_sol[r * solmin + c] = value; // transposed
@ -677,13 +689,12 @@ SEXP CCubes(SEXP tt) {
return (sol); return (sol);
} }
long long unsigned int nchoosek( long long unsigned int nchoosek(
int n, int n,
int k int k
) { ) {
if (k > n) return 0;
if (k == 0 || k == n) return 1; if (k == 0 || k == n) return 1;
if (k == 1) return n;
long long unsigned int result = 1; long long unsigned int result = 1;
@ -692,7 +703,21 @@ long long unsigned int nchoosek(
} }
for (int i = 0; i < k; i++) { for (int i = 0; i < k; i++) {
result = result * (n - i) / (i + 1); // result = result * (n - i) / (i + 1);
// Check for potential overflow before multiplication
if (result > ULLONG_MAX / (n - i)) {
return 0; // Indicate overflow
}
result *= (n - i);
// Check for potential overflow before division
if (result % (i + 1) != 0) {
return 0; // Indicate overflow
}
result /= (i + 1);
} }
return result; return result;

View file

@ -147,12 +147,12 @@ ccubes_task(int k,
int tempk[NINPUTS]; /* max is tempk[ninputs] */ int tempk[NINPUTS]; /* max is tempk[ninputs] */
int x = 0; int x = 0;
int start_point = task; int combination = task;
// fill the combination for the current task // fill the combination for the current task
for (int i = 0; i < k; i++) { for (int i = 0; i < k; i++) {
while (nchoosek(NINPUTS - (x + 1), k - (i + 1)) <= start_point) { while (nchoosek(NINPUTS - (x + 1), k - (i + 1)) <= combination) {
start_point -= nchoosek(NINPUTS - (x + 1), k - (i + 1)); combination -= nchoosek(NINPUTS - (x + 1), k - (i + 1));
x++; x++;
} }
tempk[i] = x; tempk[i] = x;
@ -255,11 +255,11 @@ ccubes_task(int k,
int value = ON_set[tempk[c] * POSROWS + frows[f]]; int value = ON_set[tempk[c] * POSROWS + frows[f]];
tempc[c] = value + 1; tempc[c] = value + 1;
int word_index = tempk[c] / BITS_PER_WORD; int word_index = tempk[c] / (BITS_PER_WORD / value_bit_width);
int bit_index = tempk[c] % BITS_PER_WORD; int bit_index = (tempk[c] % (BITS_PER_WORD / value_bit_width)) * value_bit_width;
fixed_bits[word_index] |= 1U << bit_index; fixed_bits[word_index] |= (value_bit_mask << bit_index);
value_bits[word_index] |= (unsigned int)value << (bit_index * VALUE_BIT_WIDTH); value_bits[word_index] |= ((unsigned int)value << bit_index);
} }
// check if the current PI is not redundant // check if the current PI is not redundant
@ -281,13 +281,15 @@ ccubes_task(int k,
for (int w = 0; w < IMPLICANT_WORDS; w++) { 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 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]) { unsigned int index_mask = p_implicants_pos[i * implicant_words + w];
if ((fixed_bits[w] & index_mask) != index_mask) {
is_subset = false; is_subset = false;
break; break;
} }
// then compare the value bits, if one or more values on those positions are different, its not a subset // 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]) { if ((value_bits[w] & index_mask) != (p_implicants_val[i * implicant_words + w] & index_mask)) {
is_subset = false; is_subset = false;
break; break;
} }

View file

@ -1,100 +0,0 @@
#include <R_ext/Boolean.h>
#include "row_dominance.h"
void row_dominance(
int p_pichart[],
int p_implicants[],
int *p_ck,
int pirows,
unsigned int *foundPI,
int ninputs
) {
unsigned int picols = *foundPI;
// int* survcols = (int *) R_Calloc (picols, int);
// for (int i = 0; i < picols; i++) {
// survcols[i] = true;
// }
Rboolean survcols[picols];
int colsums[picols];
int sortcol[picols];
int temp;
for (unsigned int c = 0; c < picols; c++) {
colsums[c] = 0;
for (int r = 0; r < pirows; r++) {
colsums[c] += p_pichart[c * pirows + r];
}
sortcol[c] = c;
survcols[c] = true;
}
for (unsigned int c1 = 0; c1 < picols; c1++) {
for (unsigned int c2 = c1 + 1; c2 < picols; c2++) {
if (colsums[sortcol[c1]] < colsums[sortcol[c2]]) {
temp = sortcol[c1];
sortcol[c1] = sortcol[c2];
sortcol[c2] = temp;
}
}
}
for (unsigned int c1 = 0; c1 < picols; c1++) {
if (survcols[sortcol[c1]]) {
for (unsigned int c2 = c1 + 1; c2 < picols; c2++) {
if (survcols[sortcol[c2]]) {
if (colsums[sortcol[c1]] > colsums[sortcol[c2]]) {
Rboolean itcovers = true; // assume it's covered
int r = 0;
while (r < pirows && itcovers) {
if (p_pichart[sortcol[c2] * pirows + r]) {
itcovers = p_pichart[sortcol[c1] * pirows + r];
}
r++;
}
if (itcovers) {
survcols[sortcol[c2]] = false;
--(*foundPI);
}
}
}
}
}
}
if (*foundPI < picols) {
// move (overwrite) all surviving columns towards the beginning
int s = 0;
for (unsigned int c = 0; c < picols; c++) {
if (survcols[c]) {
for (int r = 0; r < pirows; r++) {
p_pichart[s * pirows + r] = p_pichart[c * pirows + r];
}
for (int r = 0; r < ninputs; r++) {
p_implicants[s * ninputs + r] = p_implicants[c * ninputs + r];
}
// same with the vector positions
p_ck[s] = p_ck[c];
s++;
}
}
}
return;
}

View file

@ -1,10 +0,0 @@
#include <stdbool.h>
void row_dominance(
int p_pichart[],
int p_implicants[],
int *p_ck,
int pirows,
unsigned int *foundPI,
int ninputs
);