n-dimensionale Matrizen addieren



  • Hoi! 😉

    Ich denke nicht dass sowas in der Realität relevant wäre, aber ich versuche hier gerade eine n-dimensionale Klasse für Matrizen zu bauen.
    Najo, die sollte man natürlich auch miteinander addieren können. Aber wie, da hab ich im Moment Probleme mit.

    Mein momentaner Ansatz ist:

    template<typename OtherDataT>
    inline MatrixBase<DataT, Dimensions>& add(
      MatrixBase<OtherDataT, Dimensions> const& matrix)
    {
      addMatrixRow(this->m_matrix, matrix.m_matrix, 1);
    }
    
    typedef<typename ContentT>
    void addMatrixRow(std::vector<ContentT>& left,
      std::vector<ContentT> const& right, size_t depth)
    {
      typedef typename std::vector<ContentT> RowT;
    
      if(left.size() != right.size())
        throw InvalidMatrixOperation(
          "Attempt to add matrices with different sizes");
    
      if(depth != Dimension)
      {
        for(RowT::size_type i = 0; i < right.size(); ++i)
          addMatrixRow(left[i], right[i], depth + 1);
      }
      else
      {
        for(RowT::size_type i = 0; i < right.size(); ++i)
          left[i] += right[i];
      }
    }
    

    wobei m_matrix ein n-fach verschachtelter Vektor von double/std::complex ist.

    Was aber ja leider nicht funktioniert.

    Meine einzige Idee war es, mein Wissen auszunutzen, dass ein Vektor bei jedem Datentyp ein exakt identisches Speicherlayout hat, nur der Storage ist anders.
    So könnte ich eigentlich std::vector<void*> durchhangeln bis depth == Dimension und zu nem double-Vektoren casten.

    Finde ich aber reichlich unelegant. Hat jemand eventuell eine schönere Lösung dafür? So töte ich ja das ganze Typsystem ...

    Danke!
    Grüße,
    Ethon



  • Was genau ist denn Dimension? Und wie hast du diesen n-fach geschachtelten vector<> definiert?

    (nur mal ein Gedanke: Eventuell wäre std::valarray besser als unterliegender Datentyp geeignet)


  • Mod

    aber ich versuche hier gerade eine n-dimensionale Klasse für Matrizen zu bauen.

    wobei m_matrix ein n-fach verschachtelter Vektor von double/std::complex ist.

    Ich glaube, in diesem Widerspruch liegt das Problem.

    Schreib doch ein richtiges Klassentemplate mit vernünftigen Zugriffsoperatoren, dann sehe ich da keine wesentlichen Probleme beim Addieren von N-dimensionalen Matrizen, was man dann durch ein rekursives Template lösen könnte.



  • Den Vektor definiere ich so (nbicht schlagen, mein erster Versuch in Sachen Template-Metaprogramming):

    namespace internal
      {
        template<typename DataT, size_t Dimensions>
        struct BuildMatrix
        {
          static_assert(Dimensions < 0, "Zero or negative dimension supplied!");
    
          typedef std::vector<typename BuildMatrix<DataT,
            Dimensions - 1>::Type> Type;
        };
    
        template<typename DataT>
        struct BuildMatrix<DataT, 1>
        {
          typedef std::vector<DataT> Type;
        };
      }
    

    Mit valarray hab ich mich ehrlich gesagt noch nie beschäftigt, werde ich mir mal ansehen, danke. 😉



  • Es sieht auf jeden Fall verwendbar aus. Ich würde nun die Addition rekursiv über diese Struktur definieren:

    //Standardfall - vector<...>
    template<typename Sub> vector<Sub> add_matrix(const vector<Sub>& l, const vector<Sub>& r)
    {
      assert(r.size()==l.size());
      vector<Sub> res(r.size());
      transform(l.begin(),l.end(),r.begin(),res.begin(),add_matrix);
      return res;
    }
    
    //Rekursionsabbruch - double, complex o.ä.
    template<typename Num> Num add_matrix(Num l, Num r)
    {
      return l+r;
    }
    

    (ohne Garantie)


  • Mod

    Sollte da nicht auch irgendwie fix sein, wie groß eine Dimension jeweils ist?

    Wie dem auch sein, hier ein bisschen ungetesteter Code:

    typedef<typename ContentT, size_t dimensions>
    Matrixklasse<ContentT, dimensions> operator+(const Matrixklasse<ContenT, dimensions> &left, const Matrixklasse<ContenT, dimensions> &right)
    {
      if(left.size() != right.size())
        throw InvalidMatrixOperation("Attempt to add matrices with different sizes");
      Matrixklasse<ContentT, dimensions> result;
    
      for(size_t i = 0; i < left.size(); ++i)
        result.push_back(left[i] + right[i]);  // Hier angenommen, dass die Matrixklasse das push_back von vector erbt.
    
      return result;
    }
    

    Nach dem Prinzip sollte das eigentlich funktionieren (bin jedoch in der TMP auch nicht mehr so fit, als dass ich immer alles im Blick habe, daher ohne Gewähr). Die Templaterekursion bricht von alleine ab, wenn die Dimension 1 ist, da dann left[i] und right[i] nur mehr vom Typ ContentT sind und nicht vom Typ Matrixklasse<ContenT, dimensions-1> wie in den vorherigen Durchgängen.

    edit: Zu langsam...


Log in to reply