la4j 显性特征值 - 在 java 8 中将命令式算法转换为函数式风格
la4j dominant eigenvalue - converting imperative algorithm to functional style in java 8
我正在研究矩阵特征值问题,使用幂法估计主特征值,其中 A 是 n x n 实矩阵。我正在使用 la4j 线性代数库。该算法使用以下步骤
- 归一化x0构造单位向量x1=x0/euclidean norm(x0)
对于 k=1 到 kmax
- 求x[k+1]=A[x[k]]
- 计算alpha[k+1]=转置(x[k])*x[k+1]
- 规范化x[k+1]并且不重命名x[k+1]=x[k+1]/euclidean norm(x[k+1])
- 终止条件:如果|alpha[k+1]-alpha[k]| <容忍,停止
否则,将 k 增加到 k+1 并转到步骤 2
这是我的class。我想使用 java 8 将 dominantEigenV 转换为功能样式。任何帮助将不胜感激。
import org.la4j.Matrix;
import org.la4j.Vector;
import org.la4j.Vectors;
public class EigenDecomp
{
public class EigenVO
{
private double e_val;
private Vector e_vec;
public EigenVO(double e_val, Vector e_vec)
{
this.e_val=e_val;
this.e_vec=e_vec;
}
public double getE_val()
{
return e_val;
}
public void setE_val(double e_val)
{
this.e_val = e_val;
}
public Vector getE_vec()
{
return e_vec;
}
public void setE_vec(Vector e_vec)
{
this.e_vec = e_vec;
}
}
private Matrix A;
private Vector x0;
private double tolerance;
private double alpha0;
private int kMax;
private EigenVO result;
public EigenVO getResult()
{
return result;
}
public EigenDecomp(Matrix A, Vector x0, double tolerance, int kMax)
{
this.A = A;
this.x0 = x0;
this.tolerance = tolerance;
this.kMax = kMax;
this.result = new EigenVO(0.0, x0);
this.alpha0 = Integer.MAX_VALUE;
}
public void dominantEigenV()
{
for (int k=1; k<kMax; k++)
{
alpha0=result.getE_val();
x0=result.getE_vec();
result.setE_vec(A.multiply(result.getE_vec().toColumnMatrix()).getColumn(0));
result.setE_val(((Vector)x0.toRowMatrix().multiply(result.getE_vec())).get(0));
result.setE_vec(result.getE_vec().transform(Vectors.asDivFunction(result.getE_vec().euclideanNorm())));
System.out.println("k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val());
if (Math.abs(result.getE_val() - alpha0) < tolerance)
{
break;
}
}
}
public static void main(String args[])
{
Matrix A = Matrix
.from2DArray(new double[][]
{
{ -3.0, -4.0, -4.0 },
{ 6.0, 9.0, 6.0 },
{ -9.0, -14.0, -8.0 }
});
Vector x0=Vector.fromArray(new double[] { 0.0, 1.0, 1.0 });
double tolerance=0.0001;
int kMax=50;
EigenDecomp test=new EigenDecomp(A,x0, tolerance,kMax);
test.dominantEigenV();
System.out.println("eVal:" + test.getResult().getE_val());
System.out.println("eVector:\n" +
test.getResult().getE_vec().toColumnMatrix().toString());
}
}
下面是使用 3x3 A 矩阵的主要方法的输出
k:1,xk:0.000 1.000 1.000,xkp1:-0.288 0.540 -0.791,alpha_k:0.0,alphak_1:-7.0
k:2,xk:-0.288 0.540 -0.791,xkp1:0.662 -0.573 0.484,alpha_k:-7.0,alphak_1:-2.49288486416559
k:3,xk:0.662 -0.573 0.484,xkp1:-0.547 0.577 -0.607,alpha_k:-2.49288486416559,alphak_1:-2.936497651061076
k:4,xk:-0.547 0.577 -0.607,xkp1:0.587 -0.577 0.567,alpha_k:-2.936497651061076,alphak_1:-2.992843189162536
k:5,xk:0.587 -0.577 0.567,xkp1:-0.574 0.577 -0.581,alpha_k:-2.992843189162536,alphak_1:-2.9992035320913533
k:6,xk:-0.574 0.577 -0.581,xkp1:0.578 -0.577 0.576,alpha_k:-2.9992035320913533,alphak_1:-2.999911487899692
k:7,xk:0.578 -0.577 0.576,xkp1:-0.577 0.577 -0.578,alpha_k:-2.999911487899692,alphak_1:-2.999990165128744
eVal:-2.999990165128744
eVector:
-0.577
0.577
-0.578
首先让我把你的命令式方法再放一遍,这样我们就可以比较两者
public void dominantEigenV()
{
for (int k=1; k<kMax; k++)
{
alpha0=result.getE_val();
x0=result.getE_vec();
result.setE_vec(A.multiply(result.getE_vec().toColumnMatrix()).getColumn(0));
result.setE_val(((Vector)x0.toRowMatrix().multiply(result.getE_vec())).get(0));
result.setE_vec(result.getE_vec().transform(Vectors.asDivFunction(result.getE_vec().euclideanNorm())));
System.out.println("k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val());
if (Math.abs(result.getE_val() - alpha0) < tolerance)
{
break;
}
}
}
然后,您只需要创建一个Consumer方法并添加一个辅助方法来打印每次迭代中的值
public Consumer<EigenDecomp> dominantEigenV =
ei->IntStream.range(1, kMax)
.peek(k->
((Consumer<EigenDecomp>)e->ei.alpha0=ei.result.getE_val())
.andThen(e->x0=ei.result.getE_vec())
.andThen(e->ei.result.setE_vec(A.multiply(ei.result.getE_vec().toColumnMatrix()).getColumn(0)))
.andThen(e->ei.result.setE_val(((Vector)ei.x0.toRowMatrix().multiply(ei.result.getE_vec())).get(0)))
.andThen(e->ei.result.setE_vec(ei.result.getE_vec().transform(Vectors.asDivFunction(ei.result.getE_vec().euclideanNorm()))))
.andThen(e->System.out.println(e.toString(k)))
.accept(ei)
).allMatch(k->Math.abs(ei.result.getE_val()-ei.alpha0) > ei.tolerance);
public String toString(int k)
{
return "k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val();
}
让我解释一下主要部分:
for (int k=1; k<kMax; k++)
替换为
IntStream.range(1, kMax)
每次k迭代后使用peek操作执行一个consumer block
.peek(k->
)
对于每个操作,使用消费者链,为了在 peek 中启用它,您可以在消费者中进行第一个赋值,然后在第二个和 Then() 上进行另一个表示为 lambda 的赋值......等等,直到所有作业已完成
(Consumer<EigenDecomp>)e->ei.alpha0=ei.result.getE_val()).andThen(
链结束后,pass accept传过来的参数ei
.accept(ei)
对于停止条件,使用 allMatch 并添加一个谓词,以便在满足条件时算法可以在 k 达到 kMax 之前停止
.allMatch(k->Math.abs(ei.result.getE_val()-ei.alpha0) > ei.tolerance)
我正在研究矩阵特征值问题,使用幂法估计主特征值,其中 A 是 n x n 实矩阵。我正在使用 la4j 线性代数库。该算法使用以下步骤
- 归一化x0构造单位向量x1=x0/euclidean norm(x0)
对于 k=1 到 kmax
- 求x[k+1]=A[x[k]]
- 计算alpha[k+1]=转置(x[k])*x[k+1]
- 规范化x[k+1]并且不重命名x[k+1]=x[k+1]/euclidean norm(x[k+1])
- 终止条件:如果|alpha[k+1]-alpha[k]| <容忍,停止 否则,将 k 增加到 k+1 并转到步骤 2
这是我的class。我想使用 java 8 将 dominantEigenV 转换为功能样式。任何帮助将不胜感激。
import org.la4j.Matrix;
import org.la4j.Vector;
import org.la4j.Vectors;
public class EigenDecomp
{
public class EigenVO
{
private double e_val;
private Vector e_vec;
public EigenVO(double e_val, Vector e_vec)
{
this.e_val=e_val;
this.e_vec=e_vec;
}
public double getE_val()
{
return e_val;
}
public void setE_val(double e_val)
{
this.e_val = e_val;
}
public Vector getE_vec()
{
return e_vec;
}
public void setE_vec(Vector e_vec)
{
this.e_vec = e_vec;
}
}
private Matrix A;
private Vector x0;
private double tolerance;
private double alpha0;
private int kMax;
private EigenVO result;
public EigenVO getResult()
{
return result;
}
public EigenDecomp(Matrix A, Vector x0, double tolerance, int kMax)
{
this.A = A;
this.x0 = x0;
this.tolerance = tolerance;
this.kMax = kMax;
this.result = new EigenVO(0.0, x0);
this.alpha0 = Integer.MAX_VALUE;
}
public void dominantEigenV()
{
for (int k=1; k<kMax; k++)
{
alpha0=result.getE_val();
x0=result.getE_vec();
result.setE_vec(A.multiply(result.getE_vec().toColumnMatrix()).getColumn(0));
result.setE_val(((Vector)x0.toRowMatrix().multiply(result.getE_vec())).get(0));
result.setE_vec(result.getE_vec().transform(Vectors.asDivFunction(result.getE_vec().euclideanNorm())));
System.out.println("k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val());
if (Math.abs(result.getE_val() - alpha0) < tolerance)
{
break;
}
}
}
public static void main(String args[])
{
Matrix A = Matrix
.from2DArray(new double[][]
{
{ -3.0, -4.0, -4.0 },
{ 6.0, 9.0, 6.0 },
{ -9.0, -14.0, -8.0 }
});
Vector x0=Vector.fromArray(new double[] { 0.0, 1.0, 1.0 });
double tolerance=0.0001;
int kMax=50;
EigenDecomp test=new EigenDecomp(A,x0, tolerance,kMax);
test.dominantEigenV();
System.out.println("eVal:" + test.getResult().getE_val());
System.out.println("eVector:\n" +
test.getResult().getE_vec().toColumnMatrix().toString());
}
}
下面是使用 3x3 A 矩阵的主要方法的输出
k:1,xk:0.000 1.000 1.000,xkp1:-0.288 0.540 -0.791,alpha_k:0.0,alphak_1:-7.0
k:2,xk:-0.288 0.540 -0.791,xkp1:0.662 -0.573 0.484,alpha_k:-7.0,alphak_1:-2.49288486416559
k:3,xk:0.662 -0.573 0.484,xkp1:-0.547 0.577 -0.607,alpha_k:-2.49288486416559,alphak_1:-2.936497651061076
k:4,xk:-0.547 0.577 -0.607,xkp1:0.587 -0.577 0.567,alpha_k:-2.936497651061076,alphak_1:-2.992843189162536
k:5,xk:0.587 -0.577 0.567,xkp1:-0.574 0.577 -0.581,alpha_k:-2.992843189162536,alphak_1:-2.9992035320913533
k:6,xk:-0.574 0.577 -0.581,xkp1:0.578 -0.577 0.576,alpha_k:-2.9992035320913533,alphak_1:-2.999911487899692
k:7,xk:0.578 -0.577 0.576,xkp1:-0.577 0.577 -0.578,alpha_k:-2.999911487899692,alphak_1:-2.999990165128744
eVal:-2.999990165128744
eVector:
-0.577
0.577
-0.578
首先让我把你的命令式方法再放一遍,这样我们就可以比较两者
public void dominantEigenV()
{
for (int k=1; k<kMax; k++)
{
alpha0=result.getE_val();
x0=result.getE_vec();
result.setE_vec(A.multiply(result.getE_vec().toColumnMatrix()).getColumn(0));
result.setE_val(((Vector)x0.toRowMatrix().multiply(result.getE_vec())).get(0));
result.setE_vec(result.getE_vec().transform(Vectors.asDivFunction(result.getE_vec().euclideanNorm())));
System.out.println("k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val());
if (Math.abs(result.getE_val() - alpha0) < tolerance)
{
break;
}
}
}
然后,您只需要创建一个Consumer方法并添加一个辅助方法来打印每次迭代中的值
public Consumer<EigenDecomp> dominantEigenV =
ei->IntStream.range(1, kMax)
.peek(k->
((Consumer<EigenDecomp>)e->ei.alpha0=ei.result.getE_val())
.andThen(e->x0=ei.result.getE_vec())
.andThen(e->ei.result.setE_vec(A.multiply(ei.result.getE_vec().toColumnMatrix()).getColumn(0)))
.andThen(e->ei.result.setE_val(((Vector)ei.x0.toRowMatrix().multiply(ei.result.getE_vec())).get(0)))
.andThen(e->ei.result.setE_vec(ei.result.getE_vec().transform(Vectors.asDivFunction(ei.result.getE_vec().euclideanNorm()))))
.andThen(e->System.out.println(e.toString(k)))
.accept(ei)
).allMatch(k->Math.abs(ei.result.getE_val()-ei.alpha0) > ei.tolerance);
public String toString(int k)
{
return "k:"+k + ",xk:" + this.x0 + ",xkp1:" + this.result.getE_vec() + ",alpha_k:" + this.alpha0 + ",alphak_1:" + this.result.getE_val();
}
让我解释一下主要部分:
for (int k=1; k<kMax; k++)
替换为
IntStream.range(1, kMax)
每次k迭代后使用peek操作执行一个consumer block
.peek(k->
)
对于每个操作,使用消费者链,为了在 peek 中启用它,您可以在消费者中进行第一个赋值,然后在第二个和 Then() 上进行另一个表示为 lambda 的赋值......等等,直到所有作业已完成
(Consumer<EigenDecomp>)e->ei.alpha0=ei.result.getE_val()).andThen(
链结束后,pass accept传过来的参数ei
.accept(ei)
对于停止条件,使用 allMatch 并添加一个谓词,以便在满足条件时算法可以在 k 达到 kMax 之前停止
.allMatch(k->Math.abs(ei.result.getE_val()-ei.alpha0) > ei.tolerance)