流行的大型C++數值計算程序使用什麼數據結構來處理高維動態數組(矩陣)?
如CFD計算程序裡面需要存儲各個物理量在空間場的分布。FORTRAN 90以後的版本對動態高維數組的分配、銷毀和定址都非常方便。但是C++裡面貌似沒有很方便的高維數組的現成的數據結構?那目前流行的大型C++數值計算程序通常使用什麼數據結構來處理高維動態數組(矩陣)?了解不多,多謝指教!
謝邀。
如果只是要一個方便的介面,用std::array或者std::vector加上自定義的宏把i,j,k...下標映射到對應的一位坐標就行了。封裝的好一點的庫有boost multiarray,blitz++,eigen的tensor模塊等等。但是這種簡單做法在性能上有一些瓶頸。比如c++編譯器的自動向量化部分對使用[ ]定址的std vector有時候會失效,導致無法利用sse、avx等等指令集,速度可能會大受影響。有時候需要手工加上#pragma omp simd等等語句要求編譯器使用simd指令。Fortran在這方面由於是語言內置,編譯器自動優化通常工作良好。很多人印象里的fortran比c++快常常是因為這個編譯器自動優化工作比較好的原因。
具有完善優化支持的多維數組寫起來並不是很容易的事情,所幸很多輪子已經造好了。這裡提兩個例子:libflatarray(Highly Efficient Multi-Dimensional Arrays for C++)和Kokkos(kokkos)。前者還具有struct-of-array等等優化。Kokkos更龐大,相當於multiarray + intel Tbb + cuda thrust,並且已經用於很多高性能計算的生產代碼。
幾乎忘記了,以前我寫過一個比較丑的多維數組封裝的索引器,用來進行多維編號與一維編號的轉換。
C++ - 悲催的科學匠人 - 冷水"s blog
但是後來自己也沒有用過。看看哪位大神說說怎麼改寫為更加優雅的形式呢?
=====================================================
1 造輪子
實際是用一個1D數組,自己實現多維指標與一維指標之間的轉換。類似
IJK2ID(arrayrange,i,j,k,id);
rho = w[id];
我自己就這麼搞。好處是可以一次申請一段連續空間。看到法宇航的elsa也是這麼搞的。其實這麼y一個簡單的指針配上幾個宏操作,反而簡單高效。但是缺點是總是要先搞指標轉換。封裝成class可以在形式上避免用戶做轉換。但是寫各種介面比較麻煩。
可以考慮用多維指針預存各維起點地址。比如要搞成一個w[2][50]的數組,可以這麼搞
data = new double[100];
w = new (double*)[2];
w[0] = data;
w[1] = data+50;
w[0][23] = 1.0;
...
不過這樣在更高維下很繁瑣,必須封裝才行。所以我不喜歡。
2 std:array,std:vector嵌套,boost的多維數組
沒用過,不知道怎麼一次性構造連續存儲空間,但是看起來比較笨。把簡單的array搞成複雜的封裝,俺內心是抗拒的。
其實動態多維數組是很實用的東西。可惜C/C++沒有提供底層支持。個人覺得各種封裝只是在打花里胡哨的補丁而已。
以上論述充滿了個人偏見,要噴就噴。
eigen 不知道符不符合題主需求
這個問題一下就讓我想到我現在在用的師兄寫的c++code, 他定義了自己的數據結構,基於多動態多維指針數組,加入維數,封裝成類,加上介面,簡直就成了Matlab ,特別好用,Orz
將單元、節點等使用類定義,變數用一維動態數組根據數組長度分配。係數矩陣是稀疏矩陣,不會直接按照二維存儲,應該通過壓縮,使用一維數組存儲。
單單是存儲和讀取的話opencv的Mat就很爽了啊,支持從array, vector構造,重載的oprator&>&>直接就能輸出查看數據。如果在意計算的話在內部寫個介面直接調用Mat內部迭代器,什麼計算都能實現了。覺得只能實數域不爽,模板泛型擴展到任何數域也是很方便的。
vector和array混著用
動態數組盡量少用,尤其是vector這些,內存開銷太大。
矩陣計算可以看一看PETSc
其實沒多少流行的大型C++數值計算庫,多數常用的數值計算庫是C介面的,比如MKL,OpenBlas,FFT,這些直接用指針了。
C++的一般是每個庫自己實現一套,比如OpenCV。推薦閱讀:
※人工智慧對傳統氣象行業的影響、未來的前景如何?
※如何申請科研用超算資源?
※有限元法中,如果知道四邊形單元四個節點的應力,如何求單元內任意一位置的應力?
※用數值模擬行星運動,很難得到穩定解?