2017-07-31 56 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