<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 3.4 檢測BLAS和LAPACK數學庫 **NOTE**:*此示例代碼可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-03/recipe-04 中找到,有一個C++示例。該示例在CMake 3.5版(或更高版本)中是有效的,并且已經在GNU/Linux、macOS和Windows上進行過測試。* 許多數據算法嚴重依賴于矩陣和向量運算。例如:矩陣-向量和矩陣-矩陣乘法,求線性方程組的解,特征值和特征向量的計算或奇異值分解。這些操作在代碼庫中非常普遍,因為操作的數據量比較大,因此高效的實現有絕對的必要。幸運的是,有專家庫可用:基本線性代數子程序(BLAS)和線性代數包(LAPACK),為許多線性代數操作提供了標準API。供應商有不同的實現,但都共享API。雖然,用于數學庫底層實現,實際所用的編程語言會隨著時間而變化(Fortran、C、Assembly),但是也都是Fortran調用接口。考慮到調用街擴,本示例中的任務要鏈接到這些庫,并展示如何用不同語言編寫的庫。 ## 準備工作 為了展示數學庫的檢測和連接,我們編譯一個C++程序,將矩陣的維數作為命令行輸入,生成一個隨機的方陣**A**,一個隨機向量**b**,并計算線性系統方程: **Ax = b**。另外,將對向量**b**的進行隨機縮放。這里,需要使用的子程序是BLAS中的DSCAL和LAPACK中的DGESV來求線性方程組的解。示例C++代碼的清單( `linear-algebra.cpp`): ```c++ #include "CxxBLAS.hpp" #include "CxxLAPACK.hpp" #include <iostream> #include <random> #include <vector> int main(int argc, char** argv) { if (argc != 2) { std::cout << "Usage: ./linear-algebra dim" << std::endl; return EXIT_FAILURE; } // Generate a uniform distribution of real number between -1.0 and 1.0 std::random_device rd; std::mt19937 mt(rd()); std::uniform_real_distribution<double> dist(-1.0, 1.0); // Allocate matrices and right-hand side vector int dim = std::atoi(argv[1]); std::vector<double> A(dim * dim); std::vector<double> b(dim); std::vector<int> ipiv(dim); // Fill matrix and RHS with random numbers between -1.0 and 1.0 for (int r = 0; r < dim; r++) { for (int c = 0; c < dim; c++) { A[r + c * dim] = dist(mt); } b[r] = dist(mt); } // Scale RHS vector by a random number between -1.0 and 1.0 C_DSCAL(dim, dist(mt), b.data(), 1); std::cout << "C_DSCAL done" << std::endl; // Save matrix and RHS std::vector<double> A1(A); std::vector<double> b1(b); int info; info = C_DGESV(dim, 1, A.data(), dim, ipiv.data(), b.data(), dim); std::cout << "C_DGESV done" << std::endl; std::cout << "info is " << info << std::endl; double eps = 0.0; for (int i = 0; i < dim; ++i) { double sum = 0.0; for (int j = 0; j < dim; ++j) sum += A1[i + j * dim] * b[j]; eps += std::abs(b1[i] - sum); } std::cout << "check is " << eps << std::endl; return 0; } ``` 使用C++11的隨機庫來生成-1.0到1.0之間的隨機分布。`C_DSCAL`和`C_DGESV`分別是到BLAS和LAPACK庫的接口。為了避免名稱混淆,將在下面來進一步討論CMake模塊: 文件`CxxBLAS.hpp`用`extern "C"`封裝鏈接BLAS: ```c++ #pragma once #include "fc_mangle.h" #include <cstddef> #ifdef __cplusplus extern "C" { #endif extern void DSCAL(int *n, double *alpha, double *vec, int *inc); #ifdef __cplusplus } #endif void C_DSCAL(size_t length, double alpha, double *vec, int inc); ``` 對應的實現文件`CxxBLAS.cpp`: ```c++ #include "CxxBLAS.hpp" #include <climits> // see http://www.netlib.no/netlib/blas/dscal.f void C_DSCAL(size_t length, double alpha, double *vec, int inc) { int big_blocks = (int)(length / INT_MAX); int small_size = (int)(length % INT_MAX); for (int block = 0; block <= big_blocks; block++) { double *vec_s = &vec[block * inc * (size_t)INT_MAX]; signed int length_s = (block == big_blocks) ? small_size : INT_MAX; ::DSCAL(&length_s, &alpha, vec_s, &inc); } } ``` `CxxLAPACK.hpp`和`CxxLAPACK.cpp`為LAPACK調用執行相應的轉換。 ## 具體實施 對應的`CMakeLists.txt`包含以下構建塊: 1. 我們定義了CMake最低版本,項目名稱和支持的語言: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-04 LANGUAGES CXX C Fortran) ``` 2. 使用C++11標準: ```cmake set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` 3. 此外,我們驗證Fortran和C/C++編譯器是否能協同工作,并生成頭文件,這個文件可以處理名稱混亂。兩個功能都由`FortranCInterface`模塊提供: ```cmake include(FortranCInterface) FortranCInterface_VERIFY(CXX) FortranCInterface_HEADER( fc_mangle.h MACRO_NAMESPACE "FC_" SYMBOLS DSCAL DGESV ) ``` 4. 然后,找到BLAS和LAPACK: ```cmake find_package(BLAS REQUIRED) find_package(LAPACK REQUIRED) ``` 5. 接下來,添加一個庫,其中包含BLAS和LAPACK包裝器的源代碼,并鏈接到`LAPACK_LIBRARIES`,其中也包含`BLAS_LIBRARIES`: ```cmake add_library(math "") target_sources(math PRIVATE CxxBLAS.cpp CxxLAPACK.cpp ) target_include_directories(math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) target_link_libraries(math PUBLIC ${LAPACK_LIBRARIES} ) ``` 6. 注意,目標的包含目錄和鏈接庫聲明為`PUBLIC`,因此任何依賴于數學庫的附加目標也將在其包含目錄中。 7. 最后,我們添加一個可執行目標并鏈接`math`: ```cmake add_executable(linear-algebra "") target_sources(linear-algebra PRIVATE linear-algebra.cpp ) target_link_libraries(linear-algebra PRIVATE math ) ``` 8. 配置時,我們可以關注相關的打印輸出: ```shell $ mkdir -p build $ cd build $ cmake .. ... -- Detecting Fortran/C Interface -- Detecting Fortran/C Interface - Found GLOBAL and MODULE mangling -- Verifying Fortran/C Compiler Compatibility -- Verifying Fortran/C Compiler Compatibility - Success ... -- Found BLAS: /usr/lib/libblas.so ... -- A library with LAPACK API found. ... ``` 9. 最后,構建并測試可執行文件: ```shell $ cmake --build . $ ./linear-algebra 1000 C_DSCAL done C_DGESV done info is 0 check is 1.54284e-10 ``` ## 工作原理 `FindBLAS.cmake`和`FindLAPACK.cmake`將在標準位置查找BLAS和LAPACK庫。對于前者,該模塊有`SGEMM`函數的Fortran實現,一般用于單精度矩陣乘積。對于后者,該模塊有`CHEEV`函數的Fortran實現,用于計算復雜厄米矩陣的特征值和特征向量。查找在CMake內部,通過編譯一個小程序來完成,該程序調用這些函數,并嘗試鏈接到候選庫。如果失敗,則表示相應庫不存于系統上。 生成機器碼時,每個編譯器都會處理符號混淆,不幸的是,這種操作并不通用,而與編譯器相關。為了解決這個問題,我們使用`FortranCInterface`模塊( https://cmake.org/cmake/help/v3.5/module/FortranCInterface.html )驗證Fortran和C/C++能否混合編譯,然后生成一個Fortran-C接口頭文件`fc_mangle.h`,這個文件用來解決編譯器性的問題。然后,必須將生成的`fc_mann .h`包含在接口頭文件`CxxBLAS.hpp`和`CxxLAPACK.hpp`中。為了使用`FortranCInterface`,我們需要在`LANGUAGES`列表中添加C和Fortran支持。當然,也可以定義自己的預處理器定義,但是可移植性會差很多。 我們將在第9章中更詳細地討論Fortran和C的互操作性。 **NOTE**:*目前,BLAS和LAPACK的許多實現已經在Fortran外附帶了一層C包裝。這些包裝器多年來已經標準化,稱為CBLAS和LAPACKE。* ## 更多信息 許多算法代碼比較依賴于矩陣代數運算,使用BLAS和LAPACK API的高性能實現就非常重要了。供應商為不同的體系結構和并行環境提供不同的庫,`FindBLAS.cmake`和` FindLAPACK.cmake`可能的無法定位到當前庫。如果發生這種情況,可以通過`-D`選項顯式地從CLI對庫進行設置。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看