EduardBargues / NonLinearEquationsSolver

This repository aim to provide with an easy-to-use library to solve non-linear systems of equations.
25 stars 7 forks source link

Reducing memory allocations #6

Open wo80 opened 4 years ago

wo80 commented 4 years ago

I played around with the ILinearSolver interface of the sparse-matrices branch. Here's an implemetation which comes with zero additional memory allocations (using a custom LU implementation):

class OptimizedLinearSolverForTesting : ILinearSolver
{
    private ReusableLU lu;
    private Vector<double> solution;

    public OptimizedLinearSolverForTesting(int dimension)
    {
        this.lu = new ReusableLU(dimension);
        this.solution = new DenseVector(dimension);
    }

    public void Update(DenseMatrix stiffness)
    {
        lu.Compute(stiffness);
    }

    public Vector<double> Solve(Vector<double> input)
    {
        lu.Solve(input.AsArray(), solution.AsArray());
        return solution;
    }
}

It would be used like this:

[Fact]
public void SolveQuadraticFunctionSmallIncrements()
{
    // ALLOCATE MEMORY
    var reaction = new DenseVector(2);
    var stiffness = new DenseMatrix(2, 2);

    var solver = new OptimizedLinearSolverForTesting(2);

    // ARRANGE
    Vector<double> Reaction(Vector<double> u)
    {
        reaction[0] = u[0] * u[0] + 2 * u[1] * u[1];
        reaction[1] = 2 * u[0] * u[0] + u[1] * u[1];
        return reaction;
    };

    ILinearSolver Stiffness(Vector<double> u)
    {
        stiffness[0, 0] = 2 * u[0];
        stiffness[0, 1] = 4 * u[1];
        stiffness[1, 0] = 4 * u[0];
        stiffness[1, 1] = 2 * u[1];

        solver.Update(stiffness);

        return solver;
    }

    DenseVector force = new DenseVector(2) { [0] = 3, [1] = 3 };
    NonLinearSolver Solver = NonLinearSolver.Builder
        .Solve(2, Reaction, Stiffness)
        .Under(force)
        .WithInitialConditions(0.1, DenseVector.Create(2, 0), DenseVector.Create(2, 1))
        .UsingStandardNewtonRaphsonScheme(0.01)
        .Build();

    // ACT
    List<LoadState> states = Solver.Broadcast().TakeWhile(x => x.Lambda <= 1).ToList();

    // ASSERT
    AssertSolutionsAreCorrect(Reaction, force, states);
}

As already mentioned in https://github.com/EduardBargues/NonLinearEquationsSolver/issues/2#issuecomment-667889790, there are a couple of places in the NonLinearEquationsSolver code, where further optimization can be done (memory allocations in an iterative process should always be reduced as much as possible).

That's also a point where CSparse.NET has to be improved, if it should be used efficiently with this library (at the moment, matrix factors cannot be reused).

EduardBargues commented 4 years ago

Great test! Thank you. Ill include it in the tests suite. I'll check your comment and act accordingly (maybe another pull request). In the mean time, I think we can move forward with the pull reqeust. If you dont have any additional comments please approve 👍 :)

EduardBargues commented 4 years ago

A pull request has been added @epsi1on and @wo80 :) !

EduardBargues commented 4 years ago

btw @wo80 , where can i get the "ReusableLU" class? Im trying to include the test in the test-suite. Thanks!

wo80 commented 4 years ago

https://github.com/wo80/mathnet-extensions/blob/master/src/Numerics/LinearAlgebra/Double/Factorization/ReusableLU.cs

In #8 you are using operator overloads in the Vector class, which means a new array allocation for each vector operation. Are you planning to address this in a separate pull request resolving this issue?

EduardBargues commented 4 years ago

yes, thats the idea :) !