C#雅可比方法

时间:2016-03-11 18:15:59

标签: c# math

我一直致力于为C#dll实现Jacobi方法,我将扩展,因为我在学校学习了更多可以在代码中实现的数学概念。我一直用3X3矩阵和带3个值的Vector测试它。

我一直在测试的输入如下:

double[][] m = new double[3][];
m[0] = new double[3];
m[1] = new double[3];
m[2] = new double[3];

m[0][0] = 10;
m[0][1] = -4;
m[0][2] = -2;

m[1][0] = -4;
m[1][1] = 10;
m[1][2] = -4;

m[2][0] = -6;
m[2][1] = -2;
m[2][2] = 12;

Matrix inputMatrix = new Matrix(m);
Vector inputVector = new Vector(new double[] { 2, 3, 1 });

LinearSolvers.JacobiMethod(inputMatrix, inputVector, 80);

函数调用结束时的80是迭代次数。 我的功能是:

    public static Vector JacobiMethod(Matrix inputMatrix, Vector expectedOutcome, int iterations)
    {
        Vector solvedVector = new Vector(new double[] { 0, 0, 0});
        for(int p = 0; p < iterations; p++)
        {
            for (int i = 0; i < inputMatrix.RowCount; i++)
            {
                for (int j = 0; j < inputMatrix.ColumnCount; j++)
                {
                    if (j != i)
                        solvedVector.vectorValues[i] += solvedVector.vectorValues[i] - (inputMatrix._matrix[i][j] * expectedOutcome.vectorValues[j]);
                }
                solvedVector.vectorValues[i] /= inputMatrix._matrix[i][i];
            }
            expectedOutcome = solvedVector;
            Console.WriteLine("Step: " + p + "\n" + expectedOutcome.ToString());
        }
        return solvedVector;
    }

我认为我已经正确地实现了该方法,但是我得到了错误的输出值。

编辑:1

根据https://www.easycalculation.com/operations-research/gaussjacobi.php的预期值应为:

Value of x0 = 0.597
Value of x1 = 0.741
Value of x2 = 0.505

Matrix类:

public class Matrix
{
    public double[][] _matrix { get; protected set; }
    public int RowCount { get; private set; }
    public int ColumnCount { get; private set; }
    public bool IsDiagonallyDominant { get; private set; }

    public Matrix() { }

    public Matrix(double[][] matrix)
    {
        _matrix = matrix;
        RowCount = matrix.Length;
        ColumnCount = matrix[0].Length;
        CheckDiagonalDominance();
    }

    private void CheckDiagonalDominance()
    {

    }

    /// <summary>
    /// Returns the product of two matrices.
    /// </summary>
    public static Matrix MultiplicationWithMatrix(Matrix matrix1, Matrix matrix2)
    {
        double[][] multipliedMatrix = new double[matrix1.RowCount][];

        //Check the needed requirements for a matrix multiplication.
        if (matrix1.ColumnCount == matrix2.RowCount)
        {
            //Set up the new multiplied matrix.
            for (int i = 0; i < multipliedMatrix.Length; i++)
                multipliedMatrix[i] = new double[matrix2.ColumnCount];

            for (int i = 0; i < matrix1.RowCount; i++)
            {
                for(int j = 0; j < matrix2.ColumnCount; j++)
                {
                    for(int k = 0; k < matrix2.ColumnCount-1; k++)
                    {
                        multipliedMatrix[i][j] += matrix1._matrix[i][k] * matrix2._matrix[k][j];
                    }
                }
            }
        }
        return new Matrix(multipliedMatrix);
    }

    /// <summary>
    /// Returns the product of a matrix and a scalar.
    /// </summary>
    public static Matrix MultiplicationWithScalar(Matrix matrix, double scalar)
    {
        //TODO: Multiplication with a scalar.
        return new Matrix(new double[4][]);
    }

    /// <summary>
    /// Returns the product of a matrix and a 3D vector.
    /// </summary>
    public static Vector3D MultiplicationWithVector3D(Matrix matrix, Vector3D vector)
    {
        //Check the needed requirements for a multiplication.
        if(matrix._matrix.Length == 3)
        {
            //Perform the multiplication and return a new 3D vector, since that is the result. 
            return new Vector3D(
                matrix._matrix[0][0] * vector.X + matrix._matrix[0][1] * vector.Y + matrix._matrix[0][2] * vector.Z,
                matrix._matrix[1][0] * vector.X + matrix._matrix[1][1] * vector.Y + matrix._matrix[1][2] * vector.Z,
                matrix._matrix[2][0] * vector.X + matrix._matrix[2][1] * vector.Y + matrix._matrix[2][2] * vector.Z);
        }
        return new Vector3D(0, 0, 0);
    }

    /// <summary>
    /// Returns the product of a matrix and a 4D vector.
    /// </summary>
    public static Vector4D MultiplicationWithVector(Matrix matrix, Vector4D vector)
    {
        //Check the needed requirements for a multiplication.
        if (matrix._matrix.Length == 4)
        {
            //Perform the multiplication and return a new 4D vector, since that is the result. 
            return new Vector4D(
                matrix._matrix[0][0] * vector.X + matrix._matrix[0][1] * vector.Y + matrix._matrix[0][2] * vector.Z,
                matrix._matrix[1][0] * vector.X + matrix._matrix[1][1] * vector.Y + matrix._matrix[1][2] * vector.Z,
                matrix._matrix[2][0] * vector.X + matrix._matrix[2][1] * vector.Y + matrix._matrix[2][2] * vector.Z,
                matrix._matrix[3][0] * vector.X + matrix._matrix[3][1] * vector.Y + matrix._matrix[3][2] * vector.Z);
        }
        return new Vector4D(0, 0, 0, 0);
    }

    public override string ToString()
    {
        string matrixAsString = "";
        for (int i = 0; i < _matrix.Length; i++)
        {
            for(int j = 0; j < _matrix[i].Length; j++)
            {
                matrixAsString += _matrix[i][j] + "\t";
            }
            matrixAsString += "\n";
        }

        return matrixAsString;
    }

}

和Vector类:

public class Vector
{
    public double[] vectorValues;

    public Vector(double[] values)
    {
        vectorValues = values;
    }

    /// <summary>
    /// Returns the dot product of two vectors.
    /// </summary>
    public static double DotProduct(Vector vector1, Vector vector2)
    {
        double dotProduct = 0;
        if (vector1.vectorValues.Length == vector2.vectorValues.Length)
        {
            for(int i = 0; i < vector1.vectorValues.Length; i++)
            {
                dotProduct += vector1.vectorValues[i] * vector2.vectorValues[i];
            }
        }
        return dotProduct;
    }

    /// <summary>
    /// Returns the directional vector between two vectors.
    /// </summary>
    public static Vector Subtract(Vector vector1, Vector vector2)
    {
        double[] subtractedValues = new double[vector1.vectorValues.Length];
        for(int i = 0; i < vector1.vectorValues.Length; i++)
        {
            subtractedValues[i] = vector1.vectorValues[i] - vector2.vectorValues[i];
        }
        return new Vector(subtractedValues);
    }

    /// <summary>
    /// Returns the sum of two vectors.
    /// </summary>
    public static Vector Add(Vector vector1, Vector vector2)
    {
        double[] addedValues = new double[vector1.vectorValues.Length];
        for (int i = 0; i < vector1.vectorValues.Length; i++)
        {
            addedValues[i] = vector1.vectorValues[i] + vector2.vectorValues[i];
        }
        return new Vector(addedValues);
    }

    /// <summary>
    /// Returns the length of a vector.
    /// </summary>
    public static double Magnitude(Vector vector)
    {
        double squaredValues = 0;

        for (int i = 0; i < vector.vectorValues.Length; i++)
            squaredValues += Math.Pow(vector.vectorValues[i], 2);

        return Math.Sqrt(squaredValues);
    }

    /// <summary>
    /// Returns the cross product of two vectors.
    /// </summary>
    public static void CrossProduct(Vector2D vector1, Vector2D vector2)
    {
        //TODO: Implement CrossProduct logic
    }

    public override string ToString()
    {
        string vectorAsString = "";

        for (int i = 0; i < vectorValues.Length; i++)
            vectorAsString += "|" + vectorValues[i] + "|\n";

        return vectorAsString;
    }
}

提前致谢!

2 个答案:

答案 0 :(得分:1)

您的JacobiMethod不正确。这是一个工作,我使用了Wikipedia page的算法。

public static Vector JacobiMethod(Matrix inputMatrix, Vector expectedOutcome, int iterations)
{
    Vector solvedVector = new Vector(Enumerable.Repeat(0.0, expectedOutcome.vectorValues.Length).ToArray());
    for(int p = 0; p < iterations; p++)
    {
        for (int i = 0; i < inputMatrix.RowCount; i++)
        {
            double sigma = 0;
            for (int j = 0; j < inputMatrix.ColumnCount; j++)
            {
                if (j != i)
                    sigma += inputMatrix._matrix[i][j] * solvedVector.vectorValues[j];
            }
            solvedVector.vectorValues[i] = (expectedOutcome.vectorValues[i] - sigma) / inputMatrix._matrix[i][i];
        }
        Console.WriteLine("Step #" + p + ": " + String.Join(", ", solvedVector.vectorValues.Select(v => v.ToString()).ToArray()));
    }
    return solvedVector;
}

此外,我修改了方法,以便expectedOutcome不会在其中进行更改,而solvedVector现在是从新的零填充数组创建的。

请注意,您不会检查收敛条件并始终执行指定的迭代次数。对于10次迭代,我得到了以下结果

Step: 0
|0.2|
|0.38|
|0.246666666666667|

Step: 1
|0.401333333333333|
|0.5592|
|0.3772|

Step: 2
|0.49912|
|0.650528|
|0.441314666666667|

Step: 3
|0.548474133333333|
|0.69591552|
|0.47355632|

Step: 4
|0.573077472|
|0.7186535168|
|0.489647655466667|

Step: 5
|0.585390937813333|
|0.730015437312|
|0.497698041792|

Step: 6
|0.5915457832832|
|0.73569753003008|
|0.501722479979947|

Step: 7
|0.594623508008021|
|0.738538395195187|
|0.503734819869875|

Step: 8
|0.59616232205205|
|0.73995885676877|
|0.504740970487487|

Step: 9
|0.596931736805005|
|0.740669082916997|
|0.505244048888669|

答案 1 :(得分:0)

我正在看the Wikipedia page for the Jacobi method。它并不像我正在实施公式x^(k+1) = D^(-1) (b - R x^(k))那样。你所拥有的似乎是x^(k+1) = D^(-1) (x^(k) - R b),虽然我无法确定。

我的建议是,您为程序变量提供与已发布公式中的名称相同的名称,以便更容易验证您是否正确实现了公式。第二个想法是使用诸如Octave之类的数字包来执行几个步骤,这样您就可以比较C#程序中的数字。在Octave和类似的包中,您可以执行矩阵运算,例如D^(-1)*(b - R*x)