1

I am working on a library (in my spare time) that I hope to open source soon. One of the elements in the library is a method for calculating the determinant of a given input matrix. For this, I have created a sub-project called "LUDecomposition" because I will use LU Decomposition in order to calculate the Determinant.

Now, my best approach was:

  1. Have a class "LUDecomposition" which calculates the LU Decomposition of an input signal

  2. Have another class "Determinant" which uses the LUDecomposition for the calculate and then returns this.

Currently, it is contained in one file, and, "Determinant" is inheriting from "LUDecompostion" but it does not look right, since, the relationship makes no sense. LUDecomposition -> CAN BE/IS A Determinant

But I cannot see any other option other than having a method inside the "LU Decomposition" and returning it from there. BUT the only problem is that, what if I did not want the users of the library/interface to know how the determinant is calculated?

#include <iostream>
#include <vector>

typedef std::vector<double> Vector;


namespace LUDecomposition {

    class LUDecompostion {

        public:

            LUDecompostion();


            template<typename Inverse>
            LUDecompostion(Inverse begin, Inverse end)
            : matrix_input(begin, end)
            {
                    const size_t matrix_size = matrix_input.size();

                    this->upper.resize(matrix_size, std::vector<double>(matrix_size));
                    this->lower.resize(matrix_size, std::vector<double>(matrix_size));
                    Solve();

            }

            void Solve();

            std::vector<Vector> getUpper();
            std::vector<Vector> getLower();

        protected:

            std::vector<Vector> matrix_input;
            std::vector<Vector> upper;
            std::vector<Vector> lower;

        };

        /*
                Class Determinant

        */


    class Determinant : public LUDecomposition {

        public:

            Determinant();

            template<typename Inverse>
            Determinant(Inverse begin, Inverse end)
            :   matrix_input(begin, end)
            {
                    /*
                            TO DO
                            TO DO
                            TO DO
                    */

            }


    };
}

EDIT:

namespace LUP
{

    class LUPDecomposition {

        public:

            LUPDecomposition()
            {

            }

            string getLower()
            {
                return "This is the lower matrix";
            }

            string getUpper()
            {
                return "This is the upper matrix";
            }

        protected:

            std::vector<double> data; 


    };

    LUPDecomposition FactorMatrix()
    {
        return LUPDecomposition();

    }
}

1 Answer 1

2

First, there is nothing wrong with your inheritance, although I would avoid naming the class Determinant; I would probably use LUP::Determinant and if compatibility with other objects is requested implement a IDeterminant interface (but in this specific case seems overkill). This is because your determinant is not a generic determinant but a specific implementation on top of a factorization. And I see no problem from having your determinant object reduced to the factorization it was computed from. There might be space and performance concerns though (if I need just the determinant why store everything else?).

With the namespace, I'd rather have a Decomposition namespace with LUP factorization, Cholesky factorization, QR factorization and so on. And note that you probably plan to do LUP not LU factorization so that should also be reflected.

Now, back to the factorizations, you probably do not want to have the solve which is the algorithm and the result which represents the data in the same object. For this you can:

  • Use generic functions and break inheritance and object dependencies

Can be implemented with functions or functor objects but the API should be something like:

LUP::Decomposition decomposition = LUP::FactorMatrix(matrix.begin(), matrix.end());
auto determinant = LUP::ComputeDeterminant(decomposition);

where

LUP::FactorMatrix factors the matrix and returns the LU (or LUP) decomposition; this could be just a simple function (with template iterators)

LUP::Decomposition (or LU) contains the lower and upper triangular matrix and, if needed, the permutation matrix

LUP::ComputeDeterminant can be used on a various of inputs, and in this case an overload that works with a decomposition will return the matrix determinant. You can have it in a more generic namespace with an overload for LUP decomposition.

The advantage is that you can easily decide what data you store and you can also add other operations such as:

LUP::Decomposition decomposition = LUP::FactorMatrix(matrix.begin(), matrix.end());
if (LUP::ComputeDeterminant(decomposition) > 5) //whatever
    auto matrix = LUP::ComputeMatrixInverse(decomposition);

Few other advantages:

  • Dependency injection is easy as long as you keep the interfaces compatible. You can have two Solve methods that behave differently (iterative?) but returns the same type of object so the process is the same.
  • There is no inheritance so adding functionality is as simple as creating a new function (functor)
  • You can even combine to a certain degree different algorithms from different methods
  • You control what is called, when it is called, what resources is each step using and so on. You can decide when to release the decomposition from memory and what to do with that.
  • You have a clear separation between your data and your algorithms which for such applications is a plus.
8
  • Thank you so much for your detailed answer. Just a quick question: Should the LUP::FactorMatrix be a static member that returns an object of LUDecomposition almost like a global object/singleton?
    – Phorce
    Mar 18, 2015 at 8:30
  • No, no, personally I would make it a function (you can also make it a functor). LUP would be a namespace. You can also have a class if you wish, but I don't feel the need to model this specific solver with a class. LUPDecomposition (or LUP::Decomposition to be more accurate) should be some kind of object modeling the result. A structure with the requrired data would suffice, so would a more complicated object.
    – Memleak
    Mar 18, 2015 at 8:45
  • I've noticed that I was not consistent with the naming so I made sure to append LUP as a namespace for each identifier. HOWEVER this is entirely your decision; you decide what goes where and what names to use. Mine are simple suggestions that could work or not: you know the architecture of your application.
    – Memleak
    Mar 18, 2015 at 8:47
  • Please can you take a look at my edit in my original post (Obviously just a rough design) but did you mean something like this? I have put the function that returns the object outside of the class, within the namespace
    – Phorce
    Mar 18, 2015 at 8:53
  • Something like this. You also need a way to retrieve the pivoting matrix (if you indeed use LUP). If you apply LU only then you only need to use the LU naming as well (instead of LUP).
    – Memleak
    Mar 18, 2015 at 9:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.