如何检查R中的函数是否是常量函数?

时间:2015-05-21 16:29:20

标签: r function constants

一个R函数传递给我,它在Real Line的某个区间定义并返回一个数值。 有没有办法检查功能是否恒定?

示例功能:

f1<-function(x) {11}
f2<-function(x) {x+2}
f3<-function(x) {1+1}
f4<-function(x) {return(3)}

我正在寻找一个测试,它会说f1,f3,f4是常数函数,但f2不是。有任何想法吗?

修改

弗兰克和格雷戈尔(编辑:和迈克尔劳伦斯的第二个解决方案)解决方案完全适用于上面给出的所有4个测试用例(Marat&#39 s和迈克尔没有对所有4个案件进行工作。所以已有解决方案。但如果您能找到一个解决方案,并为以下3个测试功能提供正确的答案,那么还有额外的奖励积分:

f5 <- function(x) ifelse(x == 5.46512616432116, 0, 1)
f6 <- function(x) ifelse(x == 5.46512616432116, 0, 0)
f7 <- function(x) {x - x}

5 个答案:

答案 0 :(得分:11)

尝试functionBody

> is.numeric(functionBody(f1)[[2]])
[1] TRUE

> is.numeric(functionBody(f2)[[2]])
[1] FALSE

答案 1 :(得分:5)

此函数测试f的参数是否用作数字:

is_using_argasnumber <- function(f) 
  grepl("non-numeric argument",try(f("Hello World!"),silent=TRUE))

<强>示例:

is_using_argasnumber(function(x)1+1)        # FALSE
is_using_argasnumber(function(x)"guffaw")   # FALSE
is_using_argasnumber(function(x)sqrt(x+2))  # TRUE

如果你需要测试数学函数是否是常数,你需要特殊的工具来理解并简化公式。

一般性。

  • 对具有多个参数的函数没有意义。
  • 如果使用不同的R本地化,...
    • 我建议替换或添加正则表达式,例如"(non-numeric argument)|(argument non numérique)"。不幸的是,据我所知,R不使用或公开“错误代码”,这将允许语言不变的解释try结果。
    • OP提出的一个替代方案是简单地检查是否存在任何错误,但我认为如果被测试的函数有任何虚假的可能性会产生太多的误报:

is_breaking_withargascharacter <- function(f)
  inherits(try(f("Hello World!"),silent=TRUE),'try-error')

答案 2 :(得分:5)

这些基于代码的测试很聪明,很有趣,但到目前为止,我认为“尝试一堆数字”的方法可能是一个更强大的测试,取决于你可能获得的功能类型以及你是否关心更多关于身份证明中的I型或II型错误。

在你的问题中,你说

  

是在Real Line的某个时间间隔上定义的

因此,我们假设我们知道感兴趣的领域。在该域上采样一些点,并测试您的功能。

n = 1e5
test = runif(n, min = 0, max = 5)
results = f(test) # sapply(test, f) if f isn't vectorized

# test for constancy
all(results == results[1]) # or all(diff(results) == 0) or however else

任何真正常量函数的函数都会通过这个测试,无论多么病态 - 对于目前为止建议的任何其他方法都不行。但是,使用我在评论中留下的示例(或任何此类内容)来愚弄测试很容易

f3 = function(x) ifelse(x == 5.46512616432116, 0, 1)

答案 3 :(得分:5)

这会处理明确return,缺少{甚至空{ }等案例:

evaluatesToConstant <- function(b) {
    if (is(b, "{")) {
        if (length(b) > 2L)
            return(FALSE)
        if (length(b) == 1L)
            last <- NULL
        else last <- b[[2L]]
    } else {
        last <- b
    }
    if (is.call(last) && last[[1L]] == quote(return)) {
        last <- last[[2L]]
    }
    !is.language(last)
}
evaluatesToConstant(functionBody(fun))

这是另一种非常聪明的方法,但它可以被欺骗。假设给定常量参数,它将假定任何原始函数将返回相同的值。只要符号在函数内定义,它也允许使用符号。但由于符号可以在定义之前引用,也可以在嵌套范围内定义,因此启发式不安全。无论如何,这是:

evaluatesToConstant <- function(expr, allowDefinitions=FALSE) {
    vars <- all.vars(expr)
    calls <- setdiff(all.names(expr), vars)
    funs <- mget(calls, parent.frame(), mode="function", inherits=TRUE)
    defined <- if (allowDefinitions)
                   rapply(as.list(expr),
                          function(x) as.character(substitute(x)[[2L]]), "<-",
                          how="unlist")
    length(setdiff(vars, defined)) == 0L &&
        all(vapply(funs, is.primitive, logical(1L)))
}

应为TRUE

evaluatesToConstant(functionBody(function(x) { foo <- 1 + 1; foo }), TRUE)

答案 4 :(得分:3)

如果你假装该功能是&#34; mathworld&#34;相反,问题的答案是递归不可判断的。