BLAS(Basic Linear Algebra Subprograms,基础线性代数程序集)是一个应用程序接口(API)标准,用以规范发布基础线性代数操作的数值库(如矢量或矩阵乘法)。
BLAS按照功能被分为三个级别:
Level 1:矢量-矢量运算
Level 2:矩阵-矢量运算
Level 3:矩阵-矩阵运算
在Spark Mlib 中,采用了BLAS线性代数运算库,下面对BLAS中基本运算进行简单介绍。
函数 |
名称 |
点积 |
dot |
常数乘以向量加另一个向量 |
axpy |
准备Givens旋转 |
rotg |
实施旋转 |
rot |
准备修改过的Givens旋转 |
rotmg |
实施修改过的旋转 |
gotm |
把x复制到y |
copy |
交换x和y |
swap |
2-范数(欧几里得长度) |
nrm2 |
绝对值求和 |
asum |
常数乘以向量 |
scal |
最大绝对值元素的索引 |
amax |
等等 |
…… |
参考文献:
http://www.netlib.org/blas/
http://zh.wikipedia.org/wiki/BLAS
http://blog.csdn.net/q673327335/article/details/8547576
Spark Mlib BLAS源码函数功能如下:
axpy函数功能:y += a * x,x、y为相同维度向量,a为系数。
/**
* y += a * x
*/
privatedef axpy(a: Double, x: DenseVector, y: DenseVector): Unit = {
val n = x.size
f2jBLAS.daxpy(n, a, x.values, 1, y.values, 1)
}
dot函数功能:x、y向量内积。
已知两个非零向量a=(x1,y1),b=(x2,y2),则有a·b=x1x2+y1y2。
/**
* dot(x, y)
*/
privatedef dot(x: DenseVector, y: DenseVector): Double = {
val n = x.size
f2jBLAS.ddot(n, x.values, 1, y.values, 1)
}
copy函数功能:把向量x复制到向量y。
/**
* y = x
*/
def copy(x: Vector, y: Vector): Unit = {
scal函数功能:把向量x乘以常数a。
/**
* x = a * x
*/
def scal(a: Double, x: Vector): Unit = {
x match {
case sx: SparseVector =>
f2jBLAS.dscal(sx.values.size, a, sx.values, 1)
case dx: DenseVector =>
f2jBLAS.dscal(dx.values.size, a, dx.values, 1)
case _ =>
thrownew IllegalArgumentException(s"scal doesn't support vector type ${x.getClass}.")
}
}
执行对称秩1操作。
/**
* A := alpha * x * x^T^ + A
* @param alpha a real scalar that will be multiplied to x * x^T^.
* @param x the vector x that contains the n elements.
* @param A the symmetric matrix A. Size of n x n.
*/
def syr(alpha: Double, x: Vector, A: DenseMatrix) {
val mA = A.numRows
val nA = A.numCols
require(mA == nA, s"A is not a square matrix (and hence is not symmetric). A: $mA x $nA")
require(mA == x.size, s"The size of x doesn't match the rank of A. A: $mA x $nA, x: ${x.size}")
x match {
case dv: DenseVector => syr(alpha, dv, A)
case sv: SparseVector => syr(alpha, sv, A)
case _ =>
thrownew IllegalArgumentException(s"syr doesn't support vector type ${x.getClass}.")
}
}
矩阵与矩阵相乘。
/**
* C := alpha * A * B + beta * C
* @param alpha a scalar to scale the multiplication A * B.
* @param A the matrix A that will be left multiplied to B. Size of m x k.
* @param B the matrix B that will be left multiplied by A. Size of k x n.
* @param beta a scalar that can be used to scale matrix C.
* @param C the resulting matrix C. Size of m x n. C.isTransposed must be false.
*/
def gemm(
alpha: Double,
A: Matrix,
B: DenseMatrix,
beta: Double,
C: DenseMatrix): Unit = {
require(!C.isTransposed,
"The matrix C cannot be the product of a transpose() call. C.isTransposed must be false.")
if (alpha == 0.0) {
logDebug("gemm: alpha is equal to 0. Returning C.")
} else {
A match {
case sparse: SparseMatrix => gemm(alpha, sparse, B, beta, C)
case dense: DenseMatrix => gemm(alpha, dense, B, beta, C)
case _ =>
thrownew IllegalArgumentException(s"gemm doesn't support matrix type ${A.getClass}.")
}
}
}
矩阵与向量相乘。
/**
* y := alpha * A * x + beta * y
* @param alpha a scalar to scale the multiplication A * x.
* @param A the matrix A that will be left multiplied to x. Size of m x n.
* @param x the vector x that will be left multiplied by A. Size of n x 1.
* @param beta a scalar that can be used to scale vector y.
* @param y the resulting vector y. Size of m x 1.
*/
def gemv(
alpha: Double,
A: Matrix,
x: DenseVector,
beta: Double,
y: DenseVector): Unit = {
require(A.numCols == x.size,
s"The columns of A don't match the number of elements of x. A: ${A.numCols}, x: ${x.size}")
require(A.numRows == y.size,
s"The rows of A don't match the number of elements of y. A: ${A.numRows}, y:${y.size}}")
if (alpha == 0.0) {
logDebug("gemv: alpha is equal to 0. Returning y.")
} else {
A match {
case sparse: SparseMatrix =>
gemv(alpha, sparse, x, beta, y)
case dense: DenseMatrix =>
gemv(alpha, dense, x, beta, y)
case _ =>
thrownew IllegalArgumentException(s"gemv doesn't support matrix type ${A.getClass}.")
}
}
}