用Java实现Gram-Schmidt正交化

用Java实现Gram-Schmidt正交化,java,matrix,Java,Matrix,我必须使用Gram-Schimdt进行正交化处理,这样才能得到A=QR。我将矩阵列作为double[]来处理,它们存储在一个ArrayList中,问题是,我只是在计算Q,以便在得到Q后可以更轻松地完成其余的工作。但我的问题是,当程序开始添加finalArray时,我不知道为什么参数数组被修改了,其中的每个向量都被修改了,显然结果是错误的。我做错了什么?(顺便说一句,我不能用Java库来解决这个问题)。另外,我用自己的双手测试算法,它应该可以工作,因为我也会打印结果,并注意它在哪里被修改 /* I

我必须使用Gram-Schimdt进行正交化处理,这样才能得到A=QR。我将矩阵列作为double[]来处理,它们存储在一个ArrayList中,问题是,我只是在计算Q,以便在得到Q后可以更轻松地完成其余的工作。但我的问题是,当程序开始添加finalArray时,我不知道为什么参数数组被修改了,其中的每个向量都被修改了,显然结果是错误的。我做错了什么?(顺便说一句,我不能用Java库来解决这个问题)。另外,我用自己的双手测试算法,它应该可以工作,因为我也会打印结果,并注意它在哪里被修改

/*
I should do Uk = (Vk - (Uk-1*Vk)*Uk-1 - ... - (U1*Vk)*Uk1)/||Uk|| 
Where ||Uk|| = Length of Uk

Vectors U own to finalArray and the V ones own to array 
*/
public ArrayList< double[] > gramSchmidt(ArrayList< double[] > array)
{
    ArrayList< double[] > finalArray= new ArrayList<>();

    //I set the first vector because it never changes, it's always the first vector of the array receive divided between it's length
    finalArray.add(multiplyScalarPerVector(1/(calculateVectorLength(array.get(0))), array.get(0)));
    //This last line is the one that modifies EVERYTHING in array and it shouldn't

    for(int i=1; i<array .size(); i++)
    {
        double[] newVector= substractVectors(array .get(i), proyection(finalArray.get(i-1),array .get(i)));
        for(int e=i-1;e>0;e--)
        {
            newVector= substractVectors(newVector, proyection(finalArray.get(e-1),array .get(i)));
        }
        newVector= multiplyScalarPerVector(1/(calculateVectorLength(newVector)), newVector);
        finalArray.add(newVector);
    }
    return finalArray;
}

//Obtain the (Uk-1*Vk)*Uk-1
public double[] proyection(double[] array1, double[] array2)
{
    double dotProductResult= dotProduct(array1,array2);
    double[] finalVector= multiplyScalarPerVector(dotProductResult, array1);
    return finalVector;
}

//To do Uk-1*Vk
public double dotProduct(double[] vector1, double[] vector2)
{
    double result = 0;
    for(int i=0; i<vector1.length; i++)
    {
        result +=vector1[i]*vector2[i];
    }
    return result ;
}

public double[] multiplyScalarPerVector(double scalar, double[] vector)
{
    double[] newVector = new double[vector.length];
    for(int i=0; i<vector.length; i++)
    {
        newVector[i] = scalar*vector[i];
    }
    return newVector;
}

public double[] substractVectors(double[] vector1, double[] vector2)
{
    double[] finalVector= new double[vector1.length];
    for(int i=0; i<vector1.length; i++)
    {
        finalVector[i] = vector1[i] - vector2[i];
    }
    return finalVector;
}

//Calculate the euclidean distance
public double calculateVectorLength(double[] vector)
{
    double result = 0;
    for(int i=0; i<vector.length; i++)
    {
        result +=Math.pow(vector[i], 2);
    }
    return Math.sqrt(result );
}
/*
我应该做Uk=(Vk-(Uk-1*Vk)*Uk-1-…-(U1*Vk)*Uk1)/| Uk |
式中| | Uk | |=Uk的长度
向量U属于finalArray,向量V属于array
*/
公共ArrayListgramSchmidt(ArrayListarray)
{
ArrayListfinalArray=newarraylist();
//我设置了第一个向量,因为它永远不会改变,它总是数组接收的第一个向量除以它的长度
add(multilyscalarpervector(1/(calculateVectorLength(array.get(0))),array.get(0));
//最后一行是修改数组中所有内容的行,它不应该修改
对于(int i=1;i0;e--)
{
newVector=减向量(newVector,proyection(finalArray.get(e-1),array.get(i));
}
newVector=多重CalarPervector(1/(calculateVectorLength(newVector)),newVector);
finalArray.add(newVector);
}
返回最终射线;
}
//获取(Uk-1*Vk)*Uk-1
公共双[]项目(双[]阵列1,双[]阵列2)
{
double dotProductResult=dotProduct(array1,array2);
double[]finalVector=multiplyScalarPerVector(dotProductResult,array1);
回报终结者;
}
//要做Uk-1*Vk
公共双点积(双[]向量1,双[]向量2)
{
双结果=0;
对于(int i=0;i当您分配

double[] newVector= vector;
然后不创建新对象,而是对同一对象的
newVector
vector
引用。
newVector
不是新对象,而是对与
vector
引用相同的对象的引用

这导致循环中的

for(int i=0; i<vector.length; i++)
{
    newVector[i] = scalar*vector[i];
}
注意,您不会使用新内容创建新的向量对象,但可以更改输入向量对象并返回对更改对象的引用。
因此,您需要更改源向量对象,这在进一步的计算中仍然需要。这会导致最终结果与预期不符

创建新对象以解决此问题:

double[] newVector= new double[vector.length];


另请参见

好的…不知道为什么,但它很有效!谢谢
double[] newVector= new double[vector.length];
double[] finalVector= new double[vector1.length];