Carl
Carl

Reputation: 5779

Identifying source of FALSE

My question is, does there exist a function that, given a logical statement, identifies the source of FALSE (if it is false)?

For example,

x=1; y=1; z=1;
x==1 & y==1 & z==2

Obviously it is the value of z that makes the statement false. In general though, is there a function that let's me identify the variable(s) in a logical statement who's value makes a logical statement false?

Upvotes: 2

Views: 50

Answers (2)

Dason
Dason

Reputation: 61973

I like @julius's answer but there is also the stopifnot function.

x <- 1; y <- 1; z <- 2
stopifnot(x == 1, y == 1, z == 1)
#Error: z == 1 is not TRUE

Not that the result is an error if there are any false statements and nothing if they're all true. It also stops at the first false statement so if you had something like

x <- T; y <- F; z <- F
stopifnot(x, y, z)
#Error: y is not TRUE

you would not be told that z is FALSE in this case.

So the result isn't a logical or an index but instead is either nothing or an error. This doesn't seem desirable but it is useful if the reason you're using it is for checking inputs to a function or something similar where you want to produce an error on invalid inputs and just keep on moving if everything is fine. I mention stopifnot because it seems like this might be the situation you're in. I'm not sure.

Here is a silly example where you might use it. In this case you apparently only want positive numbers as input and reject everything else:

doublePositiveNumber <- function(x){
    stopifnot(is.numeric(x), x >= 0)
    return(2*x)
}

which results in

> doublePositiveNumber("hey")
Error: is.numeric(x) is not TRUE
> doublePositiveNumber(-2)
Error: x >= 0 is not TRUE
> doublePositiveNumber(2)
[1] 4

So here you guarantee you get the inputs you want and produce and error message for the user that hopefully tells them what the issue is.

Upvotes: 1

Julius Vainora
Julius Vainora

Reputation: 48241

Instead of writing x==1 & y==1 & z==2 you could define

cn <- c(x == 1, y == 1, z == 2)

or

cn <- c(x, y, z) == c(1, 1, 2)

and use all(cn). Then

which(!cn)
# [1] 3

gives the source(s) of FALSE.

In general, no, there is no such function that you are looking for, but for different logical statements a similar approach should work, although it might be too lengthy to pursue.

Considering (!(x %in% c(1,2,3)) & y==3) | z %in% c(4,5), we get FALSE if z %in% c(4,5) is FALSE and (!(x %in% c(1,2,3)) & y==3) is FALSE simultaneously. So, if (!(x %in% c(1,2,3)) & y==3) | z %in% c(4,5) returns FALSE, we are sure about z and still need to check x and y, so that the list of problematic variables can be obtained as follows:

if(!((!(x %in% c(1,2,3)) & y==3) | z %in% c(4,5)))
  c("x", "y", "z")[c(x %in% c(1,2,3), !y == 3, TRUE)]
# [1] "x" "y" "z"

or

a <- !(x %in% c(1,2,3))
b <- y == 3
c <- z %in% c(4,5)
if(!((a & b) | c))
  c("x", "y", "z")[c(!a, !b, TRUE)]
# [1] "x" "y" "z"

Upvotes: 3

Related Questions