2017-02-09 34 views
1

R-用戶,編譯許多嵌套循環:: cppFunction

我想,以評估的近似計算的質量來解決一個組合問題蠻力。爲此,我寫了一個小R函數,它用於變量r輸出一個令人難以置信的醜陋rcpp函數,其中包含r嵌套循環加上一些中斷條件。但是,當r開始變爲20+的範圍時,使用rcpp :: cppFunction編譯函數需要非常長的時間來編譯。 ..

任何解釋爲什麼rcpp編譯爲這個大量的嵌套循環打破?當我使用g ++作爲一個普通的C++程序編譯函數時,它在不到一秒的時間內即可編譯並且運行完美(使用cout而不是Rcout)。

我可能錯過了一些明顯的東西,因爲當我刪除除了最內層的中斷條件之外的所有內容時,它會與rcpp進行精美的編譯。但是,當我也刪除這最後的休息條件,它不會完成編譯... 有什麼建議嗎?

P.S.這是一個r = 20的示例程序,我仍然在等待編譯完成。警告:它很醜,但會自動生成。

cppFunction(' 
int make_tList_rcpp() { 
int r = 20; 
std::cout << std::endl; 
for (int t20=0; t20 <= floor(r/20); t20++) { 
    for (int t19=0; t19 <= floor(r/19); t19++) { 
    for (int t18=0; t18 <= floor(r/18); t18++) { 
    for (int t17=0; t17 <= floor(r/17); t17++) { 
    for (int t16=0; t16 <= floor(r/16); t16++) { 
     for (int t15=0; t15 <= floor(r/15); t15++) { 
     for (int t14=0; t14 <= floor(r/14); t14++) { 
     for (int t13=0; t13 <= floor(r/13); t13++) { 
     for (int t12=0; t12 <= floor(r/12); t12++) { 
      for (int t11=0; t11 <= floor(r/11); t11++) { 
      for (int t10=0; t10 <= floor(r/10); t10++) { 
      for (int t9=0; t9 <= floor(r/9); t9++) { 
      for (int t8=0; t8 <= floor(r/8); t8++) { 
       for (int t7=0; t7 <= floor(r/7); t7++) { 
       for (int t6=0; t6 <= floor(r/6); t6++) { 
       for (int t5=0; t5 <= floor(r/5); t5++) { 
       for (int t4=0; t4 <= floor(r/4); t4++) { 
        for (int t3=0; t3 <= floor(r/3); t3++) { 
        for (int t2=0; t2 <= floor(r/2); t2++) { 
        for (int t1=0; t1 <= floor(r/1); t1++) { 
        if ((1*t1+2*t2+3*t3+4*t4+5*t5+6*t6+7*t7+8*t8+9*t9+10*t10+11*t11+12*t12+13*t13+14*t14+15*t15+16*t16+17*t17+18*t18+19*t19+20*t20) == r) { 
         Rcout << t1 << "," << t2 << "," << t3 << "," << t4 << "," << t5 << "," << t6 << "," << t7 << "," << t8 << "," << t9 << "," << t10 << "," << t11 << "," << t12 << "," << t13 << "," << t14 << "," << t15 << "," << t16 << "," << t17 << "," << t18 << "," << t19 << "," << t20 << std::endl; 
        } 
        if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3+2*t2+1*t1) > r) { 
         break; 
        } 
        } 
        if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3+2*t2) > r) { 
        break; 
        } 
        } 
        if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3) > r) { 
        break; 
        } 
        } 
        if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4) > r) { 
        break; 
        } 
       } 
       if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5) > r) { 
        break; 
       } 
       } 
       if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6) > r) { 
       break; 
       } 
       } 
       if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7) > r) { 
       break; 
       } 
       } 
       if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8) > r) { 
       break; 
       } 
      } 
      if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9) > r) { 
       break; 
      } 
      } 
      if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10) > r) { 
      break; 
      } 
      } 
      if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11) > r) { 
      break; 
      } 
      } 
      if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12) > r) { 
      break; 
      } 
     } 
     if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13) > r) { 
      break; 
     } 
     } 
     if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14) > r) { 
     break; 
     } 
     } 
     if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15) > r) { 
     break; 
     } 
     } 
     if ((20*t20+19*t19+18*t18+17*t17+16*t16) > r) { 
     break; 
     } 
    } 
    if ((20*t20+19*t19+18*t18+17*t17) > r) { 
     break; 
    } 
    } 
    if ((20*t20+19*t19+18*t18) > r) { 
    break; 
    } 
    } 
    if ((20*t20+19*t19) > r) { 
    break; 
    } 
    } 
    if ((20*t20) > r) { 
    break; 
    } 
} 
return(0); 
}') 

正如@spacedman建議的那樣,當使用sourceCpp代替時,這裏有更多的調試信息。寫在給sourceCpp建議進一步的評論,它出現在Linux所以大概在Mac相關的問題工作...:

> sourceCpp(file="foobar.cpp",verbose=TRUE, rebuild=TRUE) 

Generated extern "C" functions 
-------------------------------------------------------- 


#include <Rcpp.h> 
// make_tList_rcpp 
void make_tList_rcpp(); 
RcppExport SEXP sourceCpp_1_make_tList_rcpp() { 
BEGIN_RCPP 
    Rcpp::RNGScope rcpp_rngScope_gen; 
    make_tList_rcpp(); 
    return R_NilValue; 
END_RCPP 
} 

Generated R functions 
------------------------------------------------------- 

`.sourceCpp_1_DLLInfo` <- dyn.load('/private/var/folders/bj/k_b2brs5443bmm8699v5fvxw0000gn/T/RtmpDSa3m8/sourceCpp-x86_64-apple-darwin13.4.0-0.12.9/sourcecpp_a7c1e15e92a/sourceCpp_8.so') 

make_tList_rcpp <- Rcpp:::sourceCppFunction(function() {}, TRUE, `.sourceCpp_1_DLLInfo`, 'sourceCpp_1_make_tList_rcpp') 

rm(`.sourceCpp_1_DLLInfo`) 

Building shared library 
-------------------------------------------------------- 

DIR: /private/var/folders/bj/k_b2brs5443bmm8699v5fvxw0000gn/T/RtmpDSa3m8/sourceCpp-x86_64-apple-darwin13.4.0-0.12.9/sourcecpp_a7c1e15e92a 

/Library/Frameworks/R.framework/Resources/bin/R CMD SHLIB -o 'sourceCpp_8.so' --preclean 'foobar.cpp' 
clang++ -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG -I/usr/local/include -I/usr/local/include/freetype2 -I/opt/X11/include -I"/Users/hoehle/Library/R/3.3/library/Rcpp/include" -I"/Users/hoehle/Sandbox/Blog/_source" -fPIC -Wall -mtune=core2 -g -O2 -c foobar.cpp -o foobar.o 

(而這正是它掛...)

附:這裏是sessionInfo()

R version 3.3.2 (2016-10-31) 
Platform: x86_64-apple-darwin13.4.0 (64-bit) 
Running under: macOS Sierra 10.12.2 

locale: 
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] Rcpp_0.12.9 

loaded via a namespace (and not attached): 
[1] compiler_3.3.2 tools_3.3.2 
+2

可能是最好的嵌套循環永遠 –

+0

自己不能重現這個。上面的'cppfunction'代碼在我的筆記本電腦中以〜1s編譯。 Linux上的Rcpp 0.12.8,R 3.3.1 - 確實堅持一個'verbose = TRUE,rebuild = TRUE'告訴我們更多關於哪部分進程正在堅持? – Spacedman

+0

循環找到所有需要用不等概率解決生日問題的集合 - 請參閱http://www.stat.wisc.edu/sites/default/files/tr591.pdf – mhatsu

回答

6

這編譯和運行所有平臺 Mac系統上。

編輯完成後,我們有一些有用的調試信息。特別是,所使用的標誌:

clang++ -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG -I/usr/local/include -I/usr/local/include/freetype2 -I/opt/X11/include -I"/Users/hoehle/Library/R/3.3/library/Rcpp/include" -I"/Users/hoehle/Sandbox/Blog/_source" -fPIC -Wall -mtune=core2 -g -O2 -c foobar.cpp -o foobar.o 

之所以在MacOS嵌套for循環的問題編譯有關如何clang優化-O2 VS -Os下的嵌套循環。具體而言,存在大約clangv3.0的迴歸,其直接影響優化所述環路的能力。特別是,請參閱:

https://llvm.org/bugs/show_bug.cgi?id=16196

這個問題看起來好像是固定的範圍內3.8。缺點是你必須手動更新到這個編譯器,因爲這個迴歸符合所有macOS機器上的clang版本。您可能只想切換到macOS上的gcc。無論如何,下面的帖子應該有助於通過自制軟件設置相應的編譯器和~/.R/Makevars

http://thecoatlessprofessor.com/programming/openmp-in-r-on-os-x/

您不妨使用sourceCpp()代替cppFunction()作爲後來是爲更簡單的功能。 sourceCpp()函數適用於更復雜的情況。此外,我可能會選擇避免指定int返回類型。使用的

sourceCpp()

# In R 
sourceCpp("path_to/example_comb.cpp") 

文件:example_comb.cpp

#include <Rcpp.h> 

// [[Rcpp::export]] 
void make_tList_rcpp() { 
    int r = 20; 
    std::cout << std::endl; 
    for (int t20=0; t20 <= floor(r/20); t20++) { 
     for (int t19=0; t19 <= floor(r/19); t19++) { 
      for (int t18=0; t18 <= floor(r/18); t18++) { 
       for (int t17=0; t17 <= floor(r/17); t17++) { 
        for (int t16=0; t16 <= floor(r/16); t16++) { 
         for (int t15=0; t15 <= floor(r/15); t15++) { 
          for (int t14=0; t14 <= floor(r/14); t14++) { 
           for (int t13=0; t13 <= floor(r/13); t13++) { 
            for (int t12=0; t12 <= floor(r/12); t12++) { 
             for (int t11=0; t11 <= floor(r/11); t11++) { 
              for (int t10=0; t10 <= floor(r/10); t10++) { 
               for (int t9=0; t9 <= floor(r/9); t9++) { 
                for (int t8=0; t8 <= floor(r/8); t8++) { 
                 for (int t7=0; t7 <= floor(r/7); t7++) { 
                  for (int t6=0; t6 <= floor(r/6); t6++) { 
                   for (int t5=0; t5 <= floor(r/5); t5++) { 
                    for (int t4=0; t4 <= floor(r/4); t4++) { 
                     for (int t3=0; t3 <= floor(r/3); t3++) { 
                      for (int t2=0; t2 <= floor(r/2); t2++) { 
                       for (int t1=0; t1 <= floor(r/1); t1++) { 
                        if ((1*t1+2*t2+3*t3+4*t4+5*t5+6*t6+7*t7+8*t8+9*t9+10*t10+11*t11+12*t12+13*t13+14*t14+15*t15+16*t16+17*t17+18*t18+19*t19+20*t20) == r) { 
                         Rcpp::Rcout << t1 << "," << t2 << "," << t3 << "," << t4 << "," << t5 << "," << t6 << "," << t7 << "," << t8 << "," << t9 << "," << t10 << "," << t11 << "," << t12 << "," << t13 << "," << t14 << "," << t15 << "," << t16 << "," << t17 << "," << t18 << "," << t19 << "," << t20 << std::endl; 
                        } 
                        if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3+2*t2+1*t1) > r) { 
                         break; 
                        } 
                       } 
                       if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3+2*t2) > r) { 
                        break; 
                       } 
                      } 
                      if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4+3*t3) > r) { 
                       break; 
                      } 
                     } 
                     if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5+4*t4) > r) { 
                      break; 
                     } 
                    } 
                    if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6+5*t5) > r) { 
                     break; 
                    } 
                   } 
                   if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7+6*t6) > r) { 
                    break; 
                   } 
                  } 
                  if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8+7*t7) > r) { 
                   break; 
                  } 
                 } 
                 if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9+8*t8) > r) { 
                  break; 
                 } 
                } 
                if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10+9*t9) > r) { 
                 break; 
                } 
               } 
               if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11+10*t10) > r) { 
                break; 
               } 
              } 
              if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12+11*t11) > r) { 
               break; 
              } 
             } 
             if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13+12*t12) > r) { 
              break; 
             } 
            } 
            if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14+13*t13) > r) { 
             break; 
            } 
           } 
           if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15+14*t14) > r) { 
            break; 
           } 
          } 
          if ((20*t20+19*t19+18*t18+17*t17+16*t16+15*t15) > r) { 
           break; 
          } 
         } 
         if ((20*t20+19*t19+18*t18+17*t17+16*t16) > r) { 
          break; 
         } 
        } 
        if ((20*t20+19*t19+18*t18+17*t17) > r) { 
         break; 
        } 
       } 
       if ((20*t20+19*t19+18*t18) > r) { 
        break; 
       } 
      } 
      if ((20*t20+19*t19) > r) { 
       break; 
      } 
     } 
     if ((20*t20) > r) { 
      break; 
     } 
    } 

} 


/*** R 
# Runs automatically in R after compile 
make_tList_rcpp(42) 
*/ 

輸出的功能:

https://gist.github.com/coatless/aa51267dcda82b42622fdc8e6e566ab7

+0

我不得不將Rcout替換爲Rcpp :: Rcout以便它開始編譯。但是,這仍然存在於我的電腦(Mac)的編譯中。然而,當我在Linux上嘗試它時,它似乎工作......奇怪... – mhatsu

+0

似乎這是'clang'的問題。在Rtools工具包和@Spacedman下的上面的編譯罰款設法在Linux下編譯它。給我一點時間思考更多。 – coatless

+0

在答覆中提到的博客文章中嘗試了以下建議:通過修改Makevars以使用通過自制軟件安裝的gcc-4.9(很多警告,但它編譯!) – mhatsu