|
| 1 | +#' Detect infeasible if clauses |
| 2 | +#' |
| 3 | +#' Detect if clauses that contradict each other. This is useful to detect if clauses that are not satistifable. |
| 4 | +#' |
| 5 | +#' @param x A validator object. |
| 6 | +#' @param ... Additional arguments passed to `detect_if_clauses`. |
| 7 | +#' @param verbose Logical. If `TRUE`, print the results. |
| 8 | +#' @return A list of contradictions found in the if clauses, or `NULL` if none are found. |
| 9 | +#' @family feasibility |
| 10 | +#' @example ./examples/detect_infeasible_if_rules.R |
| 11 | +#' @export |
| 12 | +detect_infeasible_if_rules <- function(x, ..., verbose = TRUE){ |
| 13 | + res <- detect_if_clauses(x, ...) |
| 14 | + if (length(res) == 0){ |
| 15 | + if (verbose){ |
| 16 | + message("No contradictory if clauses found.") |
| 17 | + } |
| 18 | + return(NULL) |
| 19 | + } |
| 20 | + |
| 21 | + if (verbose){ |
| 22 | + message( |
| 23 | + length(res), |
| 24 | + " contradiction(s) with if clauses found:" |
| 25 | + ) |
| 26 | + for (i in seq_along(res)){ |
| 27 | + cat(sprintf("When %s:\n", names(res)[i])) |
| 28 | + x_c <- x[res[[i]]] |
| 29 | + |
| 30 | + expr <- sapply(x_c$rules, function(r){ |
| 31 | + deparse(r@expr) |
| 32 | + }) |
| 33 | + cat(paste0(" ", res[[i]], ": ", expr, collapse = "\n")) |
| 34 | + cat("\n") |
| 35 | + } |
| 36 | + } |
| 37 | + |
| 38 | + invisible(res) |
| 39 | +} |
| 40 | + |
| 41 | +# Detect if clauses that contradict each other. This is useful to detect if clauses that are not satistifable |
| 42 | +detect_if_clauses <- function(x, ...){ |
| 43 | + x <- check_validator(x) |
| 44 | + is_cond <- is_conditional(x) | is_categorical(x) |
| 45 | + vals <- to_exprs(x) |
| 46 | + |
| 47 | + l <- list() |
| 48 | + for (i in which(is_cond)){ |
| 49 | + cond <- vals[[i]] |
| 50 | + r <- check_condition(cond, x) |
| 51 | + l[names(r)] <- r |
| 52 | + } |
| 53 | + |
| 54 | + l |
| 55 | +} |
| 56 | + |
| 57 | +check_condition <- function(cond_expr, x){ |
| 58 | + clauses <- as_dnf(cond_expr) |
| 59 | + |
| 60 | + # test whether it is an if statement |
| 61 | + if (length(clauses) <= 1){ |
| 62 | + return(NULL) |
| 63 | + } |
| 64 | + # to do for %in statement and replace with multiple "==" |
| 65 | + neg_clauses <- lapply(clauses, invert_or_negate) |
| 66 | + |
| 67 | + l <- list() |
| 68 | + for (neg in neg_clauses){ |
| 69 | + v <- x + do.call(validate::validator, list(.test = neg)) |
| 70 | + if (is_feasible(v)){ |
| 71 | + next |
| 72 | + } |
| 73 | + v1 <- is_contradicted_by(v, ".test") |
| 74 | + l[[deparse(neg)]] <- v1 |
| 75 | + # op <- op_to_s(neg) |
| 76 | + # if (op == "=="){ |
| 77 | + # .values <- list(neg[[3]]) |> setNames(as.character(neg[[2]])) |
| 78 | + # test_rules <- substitute_values(x, .values = .values) |
| 79 | + # v <- detect_infeasible_rules(test_rules) |
| 80 | + # if (is.null(v)){ |
| 81 | + # next |
| 82 | + # } |
| 83 | + # v1 <- is_contradicted_by(test_rules, v) |
| 84 | + # v <- c(v,v1) |
| 85 | + # l[[deparse(neg)]] <- v |
| 86 | + # } |
| 87 | + |
| 88 | + # TODO expand %in% statement here |
| 89 | + } |
| 90 | + l |
| 91 | +} |
0 commit comments