mpi4py 進(jìn)階之 scalapy

上一篇中我們非常簡要地介紹了 ScaLAPACK 軟件。雖然 ScaLAPACK 在設(shè)計(jì)上作了很多工作使其方法接口與 LAPACK 盡量保持一致,但是直接使用 Fortran 或 C 語言按照上一篇中介紹的步驟使用 ScaLAPACK 仍然是一件比較麻煩和容易出錯(cuò)的事情,就好比我們使用 numpy.linalgscipy.linalg (在底層調(diào)用 BLAS 和 LAPACK)中的相關(guān)函數(shù)比直接調(diào)用 BLAS 和 LAPACK 中的相關(guān)例程要容易和方便的多,我們也希望使用一個(gè) Python 包裝之后的 ScaLAPACK,下面我們就將介紹這樣一個(gè)工具 scalapy。

為什么使用 scalapy

numpy.linalgscipy.linalg 中提供了非常豐富且易用的線性代數(shù)計(jì)算函數(shù),能夠滿足我們大多數(shù)的線性代數(shù)運(yùn)算需求,為什么還要使用 ScaLAPACK 和 scalapy 呢?對(duì)規(guī)模不是很大的線性代數(shù)問題一般沒必要使用 ScaLAPACK 和 scalapy,但是對(duì)比較大規(guī)模甚至很大規(guī)模的線性代數(shù)問題,比如超過 5000 × 5000 的矩陣運(yùn)算,ScaLAPACK 和 scalapy 的優(yōu)勢(shì)就能顯現(xiàn)了。對(duì)如此大規(guī)模的線性代數(shù)問題,你會(huì)發(fā)現(xiàn) numpy.linalg 或 scipy.linalg 中的函數(shù)可能會(huì)計(jì)算的比較慢,因?yàn)?numpy.linalg 或 scipy.linalg 都不是分布式內(nèi)存的計(jì)算工具,因此其只能利用單臺(tái)機(jī)器的計(jì)算能力。同時(shí),受制于單臺(tái)機(jī)器可用內(nèi)存的大小,所能解決問題的規(guī)模也會(huì)受到限制,不然就會(huì)超過內(nèi)存的大小而導(dǎo)致程序崩潰。另外如果 numpy.linalg 或 scipy.linalg 使用的是 32 位的 LAPACK/BlAS 庫,即使單臺(tái)機(jī)器的內(nèi)存充足,所能計(jì)算的問題的規(guī)模也會(huì)受到限制,比如矩陣元素的數(shù)目不能超過一個(gè) 32 位整型數(shù)所能表示的最大整數(shù) 2147483647,因此可計(jì)算的最大方塊矩陣大小為 46340 × 46340,超過就會(huì)出錯(cuò)。對(duì)這些情況,ScaLAPACK 和 scalapy 就能幫上忙了,因?yàn)樗鼈兪欠植际絻?nèi)存的計(jì)算工具,因此可以把計(jì)算分布到多臺(tái)機(jī)器(如集群或超級(jí)計(jì)算機(jī)上),以充分利用多臺(tái)機(jī)器的強(qiáng)大計(jì)算能力和更大的總內(nèi)存空間來加快問題的求解或者解決某些在單臺(tái)機(jī)器上無法完成的計(jì)算任務(wù)。

下載與安裝 scalapy

軟件依賴

  • MPI 實(shí)現(xiàn),目前支持 OpenMPI,IntelMPI 和 MPICH;
  • ScaLAPACK 庫, Netlib 和 Intel MKL 的 ScaLAPACK 都支持;
  • Python 2.7, 3.2 或更新版本;
  • numpy;
  • mpi4py;
  • Cython;
  • f2py (可單獨(dú)安裝,或使用較新版本的 numpy 中包含的 f2py)。

安裝

前往 https://github.com/jrs65/scalapy 下載 scalapy??梢灾苯酉螺d .zip 格式的壓縮包,并解壓,或者使用 git 將該軟件 clone 到本地:

$ git clone https://github.com/jrs65/scalapy.git

進(jìn)入軟件頂層目錄,使用以下命令進(jìn)行安裝:

$ python setup.py install [--user]

主要方法接口

scalapy 的核心成分 —— core 模塊

core 模塊提供了 1 個(gè)全局函數(shù) initmpi 和 4 個(gè)類 ProcessContext,DistributedMatrix,ScalapyException 和 ScalapackException,下面分別進(jìn)行介紹。

函數(shù) initmpi

全局的 scalapy 初始化函數(shù),一般會(huì)首先調(diào)用。

initmpi(gridshape, block_shape=[32, 32])

使用 scalapy 之前的初始化工作,會(huì)初始化一個(gè)全局的進(jìn)程網(wǎng)格上下文 _context (為我們下面將要介紹的 ProcessContext 對(duì)象),和一個(gè)全局的塊狀循環(huán)分布的塊大小 _block_shape。gridshape 是一個(gè)二元數(shù)組指定初始化的進(jìn)程網(wǎng)格的大小為 gridshape[0] × gridshape[1], block_shape 也是一個(gè)二元數(shù)組指定全局塊狀循環(huán)分布的塊大小,一般設(shè)置成 [16, 16],[32, 32] 或 [64, 64] 能獲得比較高的計(jì)算性能,塊的行和列也可以設(shè)置成不同大小。

注意:調(diào)用 initmpi 初始化的全局 ProcessContext 對(duì)象的通信子為 mpi4py.MPI.COMM_WORLD,如果需要使用其它的通信子,則必須手動(dòng)使用(下面將會(huì)介紹的) ProcessContext 的構(gòu)造函數(shù)來初始化一個(gè) ProcessContext 對(duì)象。

類 ProcessContext

ProcessContext 對(duì)象存儲(chǔ)有關(guān) MPI/BLACS 進(jìn)程的相關(guān)信息,這些信息會(huì)被(后面將會(huì)介紹的) DistributedMatrix 所使用。

方法

__init__(self, grid_shape, comm=None)

構(gòu)造函數(shù),以一個(gè)指定的進(jìn)程網(wǎng)格大小 grid_shape 和一個(gè) MPI 通信子 comm 創(chuàng)建一個(gè) ProcessContext 對(duì)象。grid_shape 是一個(gè)二元數(shù)組指定初始化的進(jìn)程網(wǎng)格的大小為 grid_shape[0] × grid_shape[1], comm 如果為 None,則會(huì)使用 mpi4py.MPI.COMM_WORLD。

屬性

grid_shape

所創(chuàng)建的進(jìn)程網(wǎng)格的 shape,為一個(gè)二元 tuple。

grid_position

本進(jìn)程在進(jìn)程網(wǎng)格中的位置,為一個(gè)二元 tuple。

mpi_comm

此 ProcessContext 對(duì)象所使用的 MPI 通信子。

blacs_context

BLACS context 句柄。

all_grid_positions

一個(gè) shape 為 (mpi_comm_size, 2) 的數(shù)組,其第 i 行是第 i 個(gè)進(jìn)程在進(jìn)程網(wǎng)格中的位置。

all_mpi_ranks

一個(gè) shape 為 (grid_shape[0], grid_shape[1]) 的整數(shù)數(shù)組,all_mpi_ranks[i, j] 給出進(jìn)程網(wǎng)格位置 (i, j) 上的進(jìn)程的 rank。

類 DistributedMatrix

一個(gè)以塊狀循環(huán)的方式分布在多個(gè) MPI 進(jìn)程組成的一個(gè)進(jìn)程網(wǎng)格上的分布式矩陣。塊狀循環(huán)分布矩陣是 ScaLAPACK 相關(guān)例程內(nèi)部所使用的數(shù)據(jù)分布形式。

DistributedMatrix 分布在各個(gè)進(jìn)程上的數(shù)據(jù)為基本的 numpy (2維)數(shù)組,下面是 DistributedMatrix 中使用的 ScaLAPACK 數(shù)據(jù)類型與 numpy 類型和 mpi4py 類型的對(duì)照表:

numpy 類型 MPI 類型 ScaLAPACK 類型 說明
np.float32 MPI.FLOAT 'S' 單精度浮點(diǎn)數(shù)
np.float64 MPI.DOUBLE 'D' 雙精度浮點(diǎn)數(shù)
np.complex64 MPI.COMPLEX 'C' 單精度復(fù)數(shù)
np.complex128 MPI.COMPLEX16 'Z' 雙精度復(fù)數(shù)

DistributedMatrix 提供了類似 numpy 數(shù)組的切片操作,但不同于 numpy 數(shù)組的是,DistributedMatrix 的一個(gè)切片會(huì)完全復(fù)制原分布矩陣對(duì)應(yīng)的數(shù)據(jù)而創(chuàng)建一個(gè)新的 DistributedMatrix,而不是返回原矩陣對(duì)應(yīng)數(shù)據(jù)的一個(gè)視圖。

主要方法

def __init__(self, global_shape, dtype=np.float64, block_shape=None, context=None)

構(gòu)造函數(shù),初始化一個(gè)空的 DistributedMatrix。global_shape 為所創(chuàng)建的 DistributedMatrix 的整體矩陣 shape,dtype 為其數(shù)據(jù)類型,目前只支持 np.float32、np.float64、np.complex64 和 np.complex128,block_shape 是塊狀循環(huán)分布的塊的大小,如果為 None,會(huì)使用由 initmpi 函數(shù)所初始化的全局 _block_shape,context 為一個(gè) ProcessContext 對(duì)象,如果為 None,則會(huì)使用由 initmpi 函數(shù)所初始化的全局 _context。

empty_like(cls, mat)

創(chuàng)建并返回一個(gè)與 DistributedMatrix mat 具有同樣屬性的空 DistributedMatrix。

empty_trans(cls, mat)

創(chuàng)建并返回一個(gè) global_shape 為 DistributedMatrix mat 的轉(zhuǎn)置(即交換其行和列)的 global_shape,但其它屬性相同的空 DistributedMatrix。

identity(cls, n, dtype=np.float64, block_shape=None, context=None)

創(chuàng)建并返回一個(gè) global_shape 為 (n, n) 的單位矩陣(即其對(duì)角元素全為 1.0,其它元素都為 0)。參數(shù) dtypeblock_shapecontext 與 __init__ 中的對(duì)應(yīng)參數(shù)同。

copy(self)

返回當(dāng)前 DistributedMatrix 的一個(gè)(深)復(fù)制,即每個(gè)進(jìn)程的本地子數(shù)據(jù)都會(huì)進(jìn)行復(fù)制。

row_indices(self)

返回本進(jìn)程所持有的數(shù)據(jù)在當(dāng)前 DistributedMatrix 中整體的行指標(biāo)。

col_indices(self)

返回本進(jìn)程所持有的數(shù)據(jù)在當(dāng)前 DistributedMatrix 中整體的列指標(biāo)。

indices(self, full=True)

返回本進(jìn)程所持有的數(shù)據(jù)在當(dāng)前 DistributedMatrix 中整體的行和列指標(biāo)(一個(gè)由 numpy 數(shù)組組成的二元 tuple)。full 如果為 True,則會(huì)返回行和列廣播后的矩陣,如果為 False,則只返回行和列的指標(biāo)數(shù)組,其結(jié)果類似于 numpy.mgrid 和 numpy.ogrid 的區(qū)別。

可以使用其返回值非常容易地創(chuàng)建依賴于元素坐標(biāo)的 DistributedMatrix,比如創(chuàng)建一個(gè)整體為 Mij = i + j 的 DistributedMatrix,可以這樣操作:

...

dm = DistributedMatrix((100, 100))
rows, cols = dm.indices()
dm.local_array[:] = rows + cols
local_diagonal_indices(self, allow_non_square=False)

返回一個(gè)由 1d numpy 數(shù)組組成的三元 tuple (global_index, local_row_index, local_column_index) 以表明本進(jìn)程所持有的子數(shù)據(jù)位于 (local_row_index, local_column_index) 的元素是整體矩陣的第 global_index 行(或)列的對(duì)角元素。allow_non_square 指明是否必須是方塊矩陣。

可以使用其返回值非常容易地操作該 DistributedMatrix 的對(duì)角項(xiàng),比如要完成運(yùn)算 Mij += i2 * δij,可以這樣操作:

...

dm = DistributedMatrix((100, 100))
gi, lri, lci = dm.local_diagonal_indices()
dm.local_array[lri, lci] += gi**2
trace(self)

返回矩陣的跡(即對(duì)角元素的和),每個(gè)進(jìn)程都會(huì)返回同樣的結(jié)果。

from_global_array(cls, mat, rank=None, block_shape=None, context=None)

由一個(gè)整體的矩陣 mat 創(chuàng)建并返回一個(gè) DistributedMatrix。mat 為一個(gè) 2d numpy 數(shù)組,rank 如果為 None,假定每個(gè)進(jìn)程都擁有相同的 mat,故只需從進(jìn)程本地的 mat 中提取對(duì)應(yīng)的數(shù)據(jù),否則只會(huì)從 rank 指定的進(jìn)程的 mat 中提取數(shù)據(jù)并分發(fā)給給個(gè)進(jìn)程,以創(chuàng)建一個(gè) DistributedMatrix。參數(shù) block_shapecontex 同 initmpi 中對(duì)應(yīng)的參數(shù)。

to_global_array(self, rank=None)

將該 DistributedMatrix 轉(zhuǎn)換為一個(gè)整體的 numpy 數(shù)組并返回。如果 rank 為 None,則所以進(jìn)程都會(huì)返回相同的整體數(shù)組,否則只有 rank 對(duì)應(yīng)的進(jìn)程會(huì)返回整體數(shù)組,其它進(jìn)程返回 None。

from_file(cls, filename, global_shape, dtype, block_shape=None, context=None, order='F', displacement=0)

從指定文件 filename 中讀取數(shù)據(jù)創(chuàng)建并返回一個(gè) DistributedMatrix。注意文件中存放的是一個(gè)整體的數(shù)據(jù)矩陣而不是塊狀循環(huán)分布后的數(shù)據(jù),該函數(shù)會(huì)在內(nèi)部完成數(shù)據(jù)分布任務(wù)。global_shape 是一個(gè)二元數(shù)組指定整體矩陣的 shape,dtypeblock_shape he contex 同 initmpi 中對(duì)應(yīng)的參數(shù),order 指明文件中數(shù)據(jù)的排列方式,可以為 'F'(默認(rèn)值) 或 'C',前者是 Fortran 的排列方式,即按照列優(yōu)先的方式排列,后者是 C 的排列方式,解按照行優(yōu)先的方式排列,displacement 指明從文件中開始讀取數(shù)據(jù)的位置。

to_file(self, filename, order='F', displacement=0)

將該 DistributedMatrix 中的數(shù)據(jù)寫入到文件 filename 中。注意寫入到文件中的數(shù)據(jù)是按照整體矩陣中元素的順序排列的,而不是按照塊狀循環(huán)分布后的元素順序。order 可選 'F' 或 'C',指明寫入文件中的數(shù)據(jù)矩陣的排列方式(列優(yōu)先或行優(yōu)先),displacement 指明在文件中的起始寫入位置。

redistribute(self, block_shape=None, context=None)

將該 DistributedMatrix 按照新指定的 block_shapecontext 重新分布,返回新創(chuàng)建的 DistributedMatrix。block_shape 如果為 None,會(huì)使用由 initmpi 函數(shù)所初始化的全局 _block_shape,context 如果為 None,則會(huì)使用由 initmpi 函數(shù)所初始化的全局 _context。注意:新指定的 context 必須和該 DistributedMatrix 的 ProcessContext 具有相同的 MPI 通信子。

transpose(self):

返回該 DistributedMatrix 的轉(zhuǎn)置(一個(gè)新的 DistributedMatrix,其整體矩陣為原整體矩陣行和列交換后的結(jié)果)。也可以通過屬性 T 獲取。

conj(self)

返回該 DistributedMatrix 的復(fù)共軛矩陣(元素的實(shí)部相同,虛部反號(hào)),如果該 DistributedMatrix 的元素為實(shí)數(shù)(dtype 為 np.float32 或 np.float64),則返回的矩陣為原矩陣自身,如果其元素為復(fù)數(shù)(dtype 為 np.complex64 或 np.complex128),則會(huì)返回一個(gè)新的 DistributedMatrix。也可以通過屬性 C 獲取。

hconj(self)

返回該 DistributedMatrix 的厄密共軛(即轉(zhuǎn)置后的復(fù)共軛),為一個(gè)新的 DistributedMatrix。也可以通過屬性 H 獲取。

屬性

local_array

該 DistributedMatrix 分布在本進(jìn)程上的子數(shù)組,為一個(gè) numpy 數(shù)組。

desc

ScaLAPACK array descriptor,為一個(gè)整數(shù) numpy 數(shù)組。

context

該 DistributedMatrix 的 ProcessContext 對(duì)象。

dtype

該 DistributedMatrix 數(shù)據(jù)的 numpy 類型,見前面的類型對(duì)照表。

mpi_dtype

該 DistributedMatrix 數(shù)據(jù)的 MPI 類型,見前面的類型對(duì)照表。

sc_dtype

該 DistributedMatrix 數(shù)據(jù)的 ScaLAPACK 類型,見前面的類型對(duì)照表。

global_shape

該 DistributedMatrix 的整體矩陣 shape。

local_shape

該 DistributedMatrix 分布在本進(jìn)程上的子數(shù)組的 shape。

block_shape

該 DistributedMatrix 塊狀循環(huán)分布的塊大小。

T

該 DistributedMatrix 的轉(zhuǎn)置。

C

該 DistributedMatrix 的復(fù)共軛。

H

該 DistributedMatrix 的厄密共軛。

類 ScalapyException

scalapy 軟件包自身產(chǎn)生的異常。

類 ScalapackException

調(diào)用 ScaLAPACK 過程中產(chǎn)生的異常。

scalapy 的計(jì)算例程 —— routines 模塊

routines 模塊提供了若干用于分布式內(nèi)存線性代數(shù)運(yùn)算的函數(shù),這些函數(shù)在底層調(diào)用 ScaLAPACK 的相關(guān)例程完成其工作,但是其提供了與 numpy.linalgscipy.linalg 一致的函數(shù)名和使用接口,因此非常方便易用。目前其提供的函數(shù)非常有限,但是常用的都已提供,下面分別對(duì)其進(jìn)行介紹。

dot(A, B, transA='N', transB='N')

矩陣相乘,返回一個(gè)新的 DistributedMatrix。AB 都是 DistributedMatrix,transAtransB 可以取值 'N','T' 或者 'C':'N' 表示用矩陣本身做運(yùn)算,'T' 表示用矩陣的轉(zhuǎn)置(行和列交換后的結(jié)果)做運(yùn)算,'C' 表示用矩陣的厄密共軛(轉(zhuǎn)置后復(fù)共軛)做運(yùn)算。

inv(A, overwrite_a=True)

計(jì)算 A 的逆矩陣,A 是一個(gè)方塊(行數(shù)和列數(shù)相同) DistributedMatrix,如果 overwrite_a 為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持。返回由 A 的逆矩陣(也是一個(gè) DistributedMatrix)和一個(gè) numpy 數(shù)組組成的二元 tuple,該數(shù)組提供一些額外信息,一般不用關(guān)注。

triinv(A, lower=False, unit_triangular=False, overwrite_a=True)

計(jì)算并返回一個(gè)三角矩陣 A 的逆矩陣,返回結(jié)果為一個(gè) DistributedMatrix。三角矩陣分為上三角矩陣和下三角矩陣,上三角矩陣是指對(duì)角線和對(duì)角線上方的元素非零,而對(duì)角線下方的元素都為零的矩陣;下三角矩陣是指對(duì)角線和對(duì)角線下方的元素非零,而對(duì)角線上方的元素都為零的矩陣。參數(shù) A 是一個(gè) DistributedMatrix,lower 如果為 True,會(huì)使用 A 的下三角部分做計(jì)算,其對(duì)角線以上部分會(huì)被忽略,如果為 False,則會(huì)使用 A 的上三角部分做計(jì)算,其對(duì)角線以下部分會(huì)被忽略,unit_triangular 如果為 True,表明 A 的對(duì)角元素全為 1,否則表明 A 的對(duì)角元素不全為 1,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持。

pinv(A, overwrite_a=True)

計(jì)算并返回 A(Moore-Penrose)廣義逆矩陣,返回結(jié)果為一個(gè) DistributedMatrix。A 是一個(gè) DistributedMatrix,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持。注意:此方法要求 A 是一個(gè)滿秩矩陣。

pinv2(A, overwrite_a=True, cond=None, rcond=None, return_rank=False, check_finite=True)

計(jì)算并返回 A(Moore-Penrose)廣義逆矩陣。此方法不同于 pinv 在于它是調(diào)用(下面為介紹的) svd 函數(shù)來計(jì)算 A 的廣義逆的,因此不要求 A 必須是一個(gè)滿秩矩陣。A 是一個(gè) DistributedMatrix,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持。cond he rcond 如果非 None 設(shè)置奇異值的截?cái)嚅撝担∮?rcond*largest_singular_value 或者 cond*largest_singular_value 的奇異值會(huì)被截?cái)酁?0,否則會(huì)使用合適的機(jī)器精度對(duì)奇異值進(jìn)行截?cái)唷?code>return_rank 如果為 True,該函數(shù)會(huì)返回由 A 的廣義逆矩陣和 A 的有效秩(即經(jīng)過截?cái)嗪蠓橇愕钠娈愔档膫€(gè)數(shù))組成的二元 tuple,否則只返回 A 的廣義逆矩陣。check_finite 指明是否首先檢查 A 中所有元素都是有限數(shù)值然后再進(jìn)行計(jì)算。

cholesky(A, lower=False, overwrite_a=False, zero_triangle=True)

計(jì)算對(duì)稱或厄密矩陣 ACholesky 分解。參數(shù) A 是一個(gè) DistributedMatrix,lower 如果為 True,會(huì)計(jì)算分解 A = U*U,其中 U 是一個(gè)上三角矩陣,最后返回 U,如果為 False,則會(huì)計(jì)算分解 A = LL*,其中 L 是一個(gè)下三角矩陣,最后返回 L,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持,zero_triangle 如果為 True,則返回的 U 或者 L 中應(yīng)該為 0 的元素會(huì)被顯式填充為 0,因?yàn)樵谟?jì)算過程中 ScaLAPACK 的相關(guān)例程會(huì)忽略對(duì)那些元素的操作,因此返回的結(jié)果那些元素可能并不為 0。

lu(A, overwrite_a=True)

計(jì)算方塊矩陣 ALU 分解。此方法計(jì)算的分解形式為 A = P L U,其中 P 是一個(gè)置換矩陣,L 是一個(gè)對(duì)角元素都為 1 的下三角矩陣,U是一個(gè)上三角矩陣。A 是一個(gè) DistributedMatrix,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持。返回由一個(gè) DistributedMatrix 和一個(gè) numpy 數(shù)組組成的二元 tuple,分解因子 L 和 U 分布存儲(chǔ)在該 DistributedMatrix 的下三角和上三角部分,但是 L 的對(duì)角元素(全為 1)沒有存儲(chǔ),在返回的 numpy 數(shù)組中包含轉(zhuǎn)置的相關(guān)信息。

eigh(A, B=None, lower=True, eigvals_only=False, overwrite_a=True, overwrite_b=True, type_=1, eigbounds=None, eigvals=None)

求解對(duì)稱或厄密矩陣的本征值(或廣義本征值)問題。A 為一個(gè)實(shí)對(duì)稱或者復(fù)厄密 DistributedMatrix,B 如果非 None,應(yīng)該是一個(gè)實(shí)對(duì)稱或者復(fù)厄密的正定 DistributedMatrix,否則會(huì)使用單位矩陣,lower 如果為 True,會(huì)使用 A 的下三角部分做計(jì)算,其對(duì)角線以上部分會(huì)被忽略,如果為 False,則會(huì)使用 A 的上三角部分做計(jì)算,其對(duì)角線以下部分會(huì)被忽略,eigvals_only 如果為 False,會(huì)計(jì)算和返回本征值(一個(gè) numpy 數(shù)組,每個(gè)進(jìn)程都會(huì)是同樣都結(jié)果,包含所有本征值)及本征向量矩陣(一個(gè) DistributedMatrix),如果為 True,則只會(huì)計(jì)算和返回本征值數(shù)組,overwrite_aoverwrite_b)指明是否允許在計(jì)算過程中破壞原矩陣 AB),如果為 False,會(huì)使用原矩陣的一個(gè)復(fù)制,因此會(huì)使用更多的內(nèi)存,type_ 指明計(jì)算類型(見下面的說明),eigbounds 如果非 None,應(yīng)該是一個(gè)二元 tuple (vl, vu),指定只計(jì)算處于下限 vl 和上限 vu 之間的本征值和本征向量,eigvals 如果非 None,應(yīng)該是一個(gè)二元 tuple (lo, hi),指定只計(jì)算第 lo 到第 hi (包含第 hi)個(gè)本征值及本征向量。

type_ 可取值 1, 2 或 3,分別對(duì)應(yīng)求解下面的問題:

  • type_ = 1: A v[:,i] = w[i] B v[:,i]
  • type_ = 2: A B v[:,i] = w[i] v[:,i]
  • type_ = 3: B A v[:,i] = w[i] v[:,i]
svd(A, overwrite_a=True, compute_u=True, compute_v=True)

計(jì)算 A奇異值分解。分解形式為 A = U * np.diag(s) * V*,U 和 V 都是幺正(或?qū)嵳唬┚仃?,s 是一個(gè) 1d numpy 數(shù)組包含從大到小排列的奇異值。A 是一個(gè) DistributedMatrix,overwrite_a 如果為 True,則 A 中的數(shù)據(jù)會(huì)在計(jì)算過程中被破壞掉,如果為 False,則運(yùn)算中會(huì)使用 A 的一個(gè)復(fù)制,因此 A 中的數(shù)據(jù)會(huì)得到保持,compute_ucompute_v)指明是否返回 U (V*),如果都返回,結(jié)果為一個(gè)三元 tuple (U, s, V*),其中 U 和 V* 都是 DistributedMatrix,s 是一個(gè) 1d numpy 數(shù)組(所有進(jìn)程都會(huì)返回同樣的結(jié)果),如果不返回 U 或者 V*,結(jié)果為一個(gè)二元 tuple (U, s) 或者 (s, V*),如果 U 和 V* 都不返回,則結(jié)果為 s。

transpose(A)

計(jì)算并返回 A 的轉(zhuǎn)置。A 是一個(gè) DistributedMatrix。

conj(A)

計(jì)算并返回 A 的復(fù)共軛。A 是一個(gè) DistributedMatrix。

hconj(A)

計(jì)算并返回 A 的厄密共軛。A 是一個(gè) DistributedMatrix。

使用步驟

使用 scalapy 的步驟和上一篇中介紹的使用 ScaLAPACK 的步驟基本一致:

  1. 初始化進(jìn)程網(wǎng)格;
    可以調(diào)用 initmpi 函數(shù)初始化一個(gè)全局的 ProcessContext 對(duì)象或者由 ProcessContext 的構(gòu)造函數(shù)手動(dòng)初始化一個(gè) ProcessContext 對(duì)象。

  2. 將數(shù)據(jù)創(chuàng)建為一個(gè) DistributedMatrix,這會(huì)將數(shù)據(jù)(矩陣或向量)按照塊狀循環(huán)方式分布到進(jìn)程網(wǎng)格上;
    可以采用多種方式將數(shù)據(jù)創(chuàng)建為 DistributedMatrix,如可以調(diào)用 DistributedMatrix.from_global_array 由一個(gè)整體的 numpy 數(shù)組創(chuàng)建,可以調(diào)用 DistributedMatrix.from_file 從文件中讀取數(shù)據(jù)創(chuàng)建,或者手動(dòng)創(chuàng)建(對(duì)于一些比較特殊的容易創(chuàng)建的 DistributedMatrix)。

  3. 調(diào)用 DistributedMatrix 自身的方法或 scalapy.routines 模塊的求解例程以完成計(jì)算。
    計(jì)算的結(jié)果一般都是 DistributedMatrix,可以通過調(diào)用 DistributedMatrix.to_global_array 將其轉(zhuǎn)化為一個(gè)整體的 numpy 數(shù)組,或調(diào)用 DistributedMatrix.to_file 將其對(duì)應(yīng)的整體矩陣存入到文件。

例程

下面給出簡單的使用例程。

# scalapy_demo.py

"""
Demonstrate the use of scalapy.

Run this with 4 process like:
$ mpiexec -n 4 python scalapy_demo.py
"""

import os
import numpy as np
import scipy.linalg as la
from mpi4py import MPI
from scalapy import core
import scalapy.routines as rt


comm = MPI.COMM_WORLD
rank = comm.rank
size = comm.size

if size != 4:
    raise Exception("Must run with 4 processes")

# define a function to compare whether two arrays are equal
allclose = lambda a, b: np.allclose(a, b, rtol=1e-4, atol=1e-6)

# initialize a global ProcessContext object,
# which includes the initialization of a 2 x 2 process grid
core.initmpi([2, 2], block_shape=[16, 16])

N = 300
# create a N x N numpy array with random numbers
gA = np.random.standard_normal((N, N)).astype(np.float64)
gA = np.asfortranarray(gA)
# create a DistributedMatrix from gA
dA = core.DistributedMatrix.from_global_array(gA, rank=0)
print 'rank %d has global_shape of dA = %s' % (rank, dA.global_shape)
print 'rank %d has local_shape of dA = %s' % (rank, dA.local_shape)
print 'rank %d has block_shape of dA = %s' % (rank, dA.block_shape)

# compute the inverse of dA
invA, ipiv = rt.inv(dA)
# convert to a global numpy array hold by rank 0 only
ginvA = invA.to_global_array(rank=0)

if rank == 0:
    # compare the result with that of scipy.linalg.inv
    print 'result equals that of scipy: ', allclose(ginvA, la.inv(gA))

# write dA to file
file_name = 'dA.dat'
dA.to_file(file_name)
# now read it from file and check it equals the original DistributedMatrix
dA1 = core.DistributedMatrix.from_file(file_name, dA.global_shape, dA.dtype, dA.block_shape, dA.context)
print 'rank %d has dA.local_array == dA1.local_array: %s' % (rank, allclose(dA.local_array, dA1.local_array))

# remove the file
if rank == 0:
    os.remove(file_name)

運(yùn)行結(jié)果如下:

$ mpiexec -n 4 python scalapy_demo.py
rank 0 has global_shape of dA = (300, 300)
rank 0 has local_shape of dA = (156, 156)
rank 0 has block_shape of dA = (16, 16)
rank 1 has global_shape of dA = (300, 300)
rank 1 has local_shape of dA = (156, 144)
rank 1 has block_shape of dA = (16, 16)
rank 2 has global_shape of dA = (300, 300)
rank 2 has local_shape of dA = (144, 156)
rank 2 has block_shape of dA = (16, 16)
rank 3 has global_shape of dA = (300, 300)
rank 3 has local_shape of dA = (144, 144)
rank 3 has block_shape of dA = (16, 16)
result equals that of scipy:  True
rank 3 has dA.local_array == dA1.local_array: True
rank 1 has dA.local_array == dA1.local_array: True
rank 2 has dA.local_array == dA1.local_array: True
rank 0 has dA.local_array == dA1.local_array: True

以上介紹了使用 scalapy 調(diào)用 ScaLAPACK 進(jìn)行分布式內(nèi)存的線性代數(shù)運(yùn)算。Python 作為一種膠水語言,可以非常容易地包裝和調(diào)用其它計(jì)算機(jī)語言已有的程序代碼和工具庫,如果我們有用 C,C++,F(xiàn)ortran 或其它計(jì)算機(jī)語言編寫的 MPI 計(jì)算程序,也能很容易地將其包裝后在 mpi4py 中進(jìn)行調(diào)用。另外我們也可以用這些計(jì)算機(jī)語言編寫一些運(yùn)算速度更快的 MPI 擴(kuò)展模塊供 mpi4py 程序調(diào)用。在下面的章節(jié)中我們將介紹怎么在 mpi4py 程序中包裝和調(diào)用 C,C++,F(xiàn)ortran 的 MPI 程序。在下一篇中我們首先介紹直接使用 Python C API 進(jìn)行 C 語言 MPI 程序包裝的方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容