This project has moved and is read-only. For the latest updates, please go here.

Refactor vector and matrix classes?

Nov 7, 2013 at 9:07 AM
Hi guys,

Looking through the code and at some of the outstanding issues, it seems there is a lot of duplicate code with respect to the way the Matrix operations handle arithmetic in the different types of matrices. For example, the DoSubtract code in the Double matrix partial is:
        protected override void DoSubtract(Matrix<double> other, Matrix<double> result)
        {
            for (var i = 0; i < RowCount; i++)
            {
                for (var j = 0; j < ColumnCount; j++)
                {
                    result.At(i, j, At(i, j) - other.At(i, j));
                }
            }
        }
and the code in Complex32 matrix partial is:
        protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
        {
            for (var i = 0; i < RowCount; i++)
            {
                for (var j = 0; j < ColumnCount; j++)
                {
                    result.At(i, j, At(i, j) - other.At(i, j));
                }
            }
        }
Given that we have the following declaration for the Complex32 type:
    public static Complex32 operator -(Complex32 minuend, Complex32 subtrahend)
        {
            return new Complex32(minuend._real - subtrahend._real, minuend._imag - subtrahend._imag);
        }
The DoSubtract subtraction (and operators) can be moved into the parent Matrix with a generic operator. That will make the rest of the code cleaner, with an override only when we need to modify the process of multiplication. For example, for issue:

https://github.com/mathnet/mathnet-numerics/issues/146

Am I OK to go ahead and refactor this? I see that there are already tests around it, so I can use them for the refactor.

Regards


Ethar
Nov 7, 2013 at 11:13 AM
Hi Ethar,

Can you quickly show what you mean in practice with a generic operator?

We do not use generic arithmetic mostly (but not only) for performance reason in the storage-specific classes (DenseMatrix, SparseMatrix etc), although it might be fine to use some at the parent base-classes which is essentially fallback code only anyway (and not supposed to be used when working with our dense or sparse implementations in practice, unless when mixing between them).

Thanks,
Chris
Nov 7, 2013 at 2:26 PM
Hi Chris,

Thanks for that explanation. The problem was in my mind, all matrix operations are inherently pretty standard. Whether we use doubles, singles, complex numbers, integers etc. they are just different types of the same thing, even though performance will mean we'd aim to move from a O(n^2) to a O(n) for dense to diagonal matrices.

Off the top of my head (apologies for any code smells I produce whilst explaining ;-) For a dense subtraction, complexity of O(n^2), all matrix subtractions of any type are basically:
public abstract class Matrix<T> where T : struct
{
 protected abstract T SubtractFromElementAt( int i, int j, T value);
// ...
        protected virtual void DoSubtract(Matrix<T> other, Matrix<T> result)  // Note generic types
        {
            for (var i = 0; i < RowCount; i++)
            {
                for (var j = 0; j < ColumnCount; j++)
                {
                      // Some element subtraction. This can be abstract as far as this class is concerned      
                      result.At(i, j, SubtractFromElementAt( i, j, other( i, j ) ));
                }
            }
        }
//...
}
So in other classes, such as Double's Matrix.cs, all it need do is define the SubtractFromElement method as opposed to rewriting the whole function for each partial.
protected override double SubtractFromElementAt( int i, int j, double value)
{
    return ( this.At(i,j) - value );
}
And similarly for Complex32's Matrix.cs
protected override Complex32 SubtractFromElementAt( int i, int j, Complex32 value)
{
    return ( this.At(i,j) - value );
}
When it comes to the implementing the performance improvements for the DiagonalMatrix it can then use the O(n) subtraction of:
protected override void DoSubtract(Matrix<T> other, Matrix<T> result)  // Note generic types
{
        for (var i = 0; i < RowCount; i++)
        {
                result.At(i, i, SubtractFromElementAt( i, i, other( i, i ) ));
        }
}
Which is the override for diagonal matrix that I thought would work.

Alternatively, a matrix could be a separate class with abstract elements within the MatrixStorage and those elements are wrappers which contain types, and it is the elements that are added (not the values) but the principle is the same. The aim is to reduce the amount of code that needs to be created/modified in the other partials. This also somewhat gets around the limitations in generics, where you can't constrain T to be something that implements +, - etc. Is there likely to be a performance hit with this method from your experience?

Regards


Ethar
Nov 14, 2013 at 11:36 PM
Edited Nov 14, 2013 at 11:37 PM
Hi Ethar,

Thanks for the explanation!

I remember there used to be a significant performance degradation with this approach, although things may have changed with newer .Net releases. We should run some benchmarks to see actual numbers instead of guessing though (also on mono)!

Note that I'm "ok" with some internal quasi code duplication for performance reasons. It would be very nice if we could avoid it, but on the other hand it is code that doesn't change a lot, so it's not that much of a burden in practice.

Thanks,
Christoph