2017-07-31 55 views
2

我正在使用Mathematica生成方程作为C代码(使用CForm [])方程导出为一个字符串和R.使用将C代码转换为R代码:解析以将R中的C函数(pow(a,b)更改为^ b)

例如,导入R作为一个字符串中的CForm []输出看起来是这样的:

"Tau * Power(Omega * (-(R * Gamma) + R),(Tau + R))" 

我的问题是如何最好地转换将上面的C代码写入如下的R表达式中:

Tau * (Omega * (-(R * Gamma) + R))^(Tau + R) 

继约数学转换代码成R代码(Convert Mathematica equations into R code)先前的帖子一个建议,我知道,一个合理的事情做的是重新定义电源()的函数,即,:

Power <- function(a,b) {a^b} 

但是,通过一系列的测试,我发现,评价这是在形式的表达式:

eval(parse(text="Tau * (Omega * (-(R * Gamma) + R))^(Tau + R)")) 

是(快约4倍于我的MAC)的速度远远超过限定功率()的函数和评估的替代如下:

eval(parse(text="Tau * Power(Omega * (-(R * Gamma) + R),(Tau + R))")) 

这似乎是一个复杂的模式匹配问题,但我找不到任何解决方案。我很欣赏任何建议。

+3

这不是标准的C代码,甚至不是一个表达式。 – Olaf

+0

我提供的第一个代码是Mathematica的CForm []输出的一部分,作为字符串导入到R中。其余全部是R代码。谢谢。 – TK2013

+0

@Olaf是对的。这不是标准的C代码。不要相信'CForm []'将Mathematica表达式转换为C ...看看[this](https://mathematica.stackexchange.com/questions/46844/real-and-or-improved-cform-的表达式) –

回答

2

有多种问题在这里:

  1. 你的方程是标准C代码。来自Mathematica的CForm[]不会将您的代码转换为正确的C语法。也许你可以关注this answer并用SymbolicC来解决这部分问题
  2. 你的问题更多的是关于从语言A到语言B的解析。正如在评论中提到的@Olaf:你可能会更好或者使用一个真正的C函数和来自R调用或手动转换它,这取决于你做这个

多久不过,按你的请求(如果我正确理解你想达到的目的)和教育目的;这里的中,我们将用R转换你的“伪C”字符串,并创建一个内联cfunction()

注意一个例子:这是没有意思的意图是优雅或实用的,但总的思路应该希望能帮助你起步


假设下面的公式:

v1 <- "4 * Power(Omega * (-(R * Gamma) + R),(Tau + R))" 

摘自原始字符串的所有变量和函数

n1 <- stringi::stri_extract_all_words(v1)[[1]] 

创建的“功能重新编写”一个名为向量(如果没有他们,没有NUMERICS一个子集)

newFunc <- c("Power" = "pow") 
n2 <- setdiff(n1, names(newFunc)) 
n3 <- n2[is.na(as.numeric(n2))] 

构建替换列表养活gsubfn()。对于这个例子的目的,我们用新的取代旧的功能和包装asReal()周围的变量

toreplace <- setNames(
    as.list(c(newFunc, paste0("asReal(", n3, ")"))), 
    c(names(newFunc), n3) 
) 

v2 <- gsubfn::gsubfn(paste(names(toreplace), collapse = "|"), toreplace, v1) 

然后,您可以通过这个新的字符串到cfunction() R中执行

#install.packages("inline") 
library(inline) 
foo <- cfunction(
    sig = setNames(rep("integer", length(n3)), n3), 
    body = paste0(
    "SEXP result = PROTECT(allocVector(REALSXP, 1)); 
    REAL(result)[0] = ", v2, "; 
    UNPROTECT(1); 
    return result;" 
) 
) 

这应该是比使用eval(parse("..."))^或限定Power()函数更快

Tau = 21; Omega = 22; R = 42; Gamma = 34 
Power <- function(x,y) {x^y} 

microbenchmark::microbenchmark(
    C = foo(Omega, R, Gamma, Tau), 
    R1 = eval(parse(text="4 * ((Omega * (-(R * Gamma) + R))^(Tau + R))")), 
    R2 = eval(parse(text="4 * Power(Omega * (-(R * Gamma) + R),(Tau + R))")), 
    times = 10L 
) 

#Unit: microseconds 
# expr  min  lq  mean median  uq  max neval 
# C 1.233 2.194 5.9555 2.9955 3.302 34.194 10 
# R1 190.012 202.781 230.5187 218.1035 243.891 337.209 10 
# R2 189.162 191.798 374.5778 207.6875 225.078 1868.746 10 
+0

谢谢Steven给出一个简洁的答案!后续问题:我意识到如果字符向量中存在数字元素,则foo函数无法构造。例如,'v1 < - “4 * Power(Omega *( - (R * Gamma)+ R),(Tau + R))”'。你能指出为什么这可能是一个问题吗?谢谢。 – TK2013

+0

@ TK2013问题出现在'foo()'函数的'sig = ...'中。你正在创建一个带有“4”=“整数”的命名向量'n2'(这是不正确的)。我编辑了这个帖子来说明这一点。 –

+1

谢谢史蒂芬,你的回答很好。 – TK2013