boost multiarray und fill



  • Hallo ihr Lieben,

    ich habe mir einen Multi Array mit drei Einträgen A[i][j][k] erstellt.

    Ist es möglich, z.B. bezüglich des zweiten Eintrags den Algorithmus fill_n anzuwenden?

    Gruß,
    -- Klaus.


  • Mod

    Das sollte funktionieren (ungetestet), indem du dir einen passenden "View" erstellst:
    http://www.boost.org/doc/libs/1_54_0/libs/multi_array/doc/user.html#sec_views



  • Okay,
    hat etwas länger gedauert, musste mich zunächst mit boost vertraut machen. 🙂

    Also ich habe ein Beispiel zusammengebastelt. Ich habe klein angefangen und für einen 2D das jeweils letzte Element einer Spalte für eine beliebige Zeile ausgeben wollen.

    In Zeile 31 recht kompakt mit der Notation von vector . Allerdings will ich multi_array von boost verwenden, weil der schneller als verschachtelte Vektoren sein soll.

    In Zeile 33 also ein multi_array und gelöst durch das Mitschleppen der Spaltenlänge.

    In Zeile 35 durch das einmalige Programmieren eines Index. Funktioniert, hat aber keine Abfrage nach der gewünschten Zeile.

    Und schließlich den von dir angesprochenen viewer in Zeile 37.

    Sieht gut aus, oder?

    #include <iostream>
    #include <vector>
    #include <boost/multi_array.hpp>
    
    typedef boost::multi_array<double,2> two_D_array;
    typedef boost::multi_array_types::index_range range;
    
    int main()
    {
    	unsigned int const n = 2;
    	unsigned int const m = 10;
    
    	unsigned int const zeile = 1;
    
    	std::vector<std::vector<double>> vec(n,std::vector<double>(m,0.0));
    
    	two_D_array A(boost::extents[n][m]);
    	boost::array<two_D_array::index,2> idx = {{1,9}};
    	two_D_array::index_gen indices;
    	two_D_array::array_view<1>::type my_view = A[ indices[range(0,n)][m-1] ];
    
    	for(unsigned int i = 0; i < vec.size(); ++i)
    	{
    		for(unsigned int j = 0; j < vec[zeile].size(); ++j)
    		{
    			vec[i][j] = static_cast<double>(i+1) * static_cast<double>(j+1);
    			A[i][j] = static_cast<double>(i+1) * static_cast<double>(j+1);
    		}
    	}
    
    	std::cout << "Vektor: " << vec[zeile].back() << std::endl;
    
    	std::cout << "Boost Multi Array manuell: " << A[zeile][m-1] << std::endl;
    
    	std::cout << "Boost Multi Array idx: " << A(idx) << std::endl;
    
    	std::cout << "Boost Multi Array view: " << my_view[zeile] << std::endl;
    
    	return 0;
    }
    

    Gruß,
    -- Klaus.


  • Mod

    Es ist übrigens ein Trugschluss, dass verschachtelte Vectoren einem mehrdimensionalen Array entsprechen. Beim vector ist schließlich alles dynamisch, d.h. man hätte eine dynamische Liste von dynamischen Listen (die jeweils alle voneinander unabhängig sind, also auch nicht die gleiche Größe haben müssen). Einem mehrdimensionales Array entspricht in C++ eines der folgenden:
    1. alle Dimensionen statisch: std::array von std::arrays
    2. alle Dimensionen statisch bis auf eine: std::vector von std::arrays
    3. alle Dimensionen dynamisch: Einfacher Wrapper um std::vector oder aber boost::multiarray (letzteres dann nehmen, wenn man die Zusatzfeatures des multiarrays nutzt).

    Sieht gut aus, oder?

    Dein Beispiel macht die Sachen, die es macht, richtig.



  • SeppJ schrieb:

    Dein Beispiel macht die Sachen, die es macht, richtig.

    Okay, immerhin. 🙂 Nur ich wollte ja Teile einer Zeile einer Matrix füllen.

    Ich habe folgenden Voschlag bei Stackoverflow gefunden und mich daran orientiert.

    Ich habe dazu ein wrapper geschrieben, der beim Aufruf spontan einen viewer für die betreffende Zeile erstellt und den Bereich dann mittels fill füllt.

    Ich dachte, dass es möglich sein müsste den viewer gänzlich von zwei Parametern abhängig zu machen (Zeile und Spalte), nur dann kann ich auch gleich den array A[n][m] selbst nehmen, oder nicht? Oder benötige ich den viewer, um die Syntax data() , begin() verwenden zu können? Ich werde leider noch nicht vollständig schlau draus. 😕

    Also es läuft, ich kriege nur folgende Fehlermeldung

    array2d.cpp: In member function ‘void array2d::fill_row(unsigned int, unsigned int, unsigned int, double)’:
    array2d.cpp:17:6: warning: ‘new_strides.boost::array<long int, 1ul>::elems[0ul]’ may be used uninitialized in this function [-Wmaybe-uninitialized]

    /*
    array2d.h
    */
    #ifndef N_D_ARRAY_H_
    #define N_D_ARRAY_H_
    #include <algorithm>
    #include <boost/multi_array.hpp>
    #include <iostream>
    
    typedef boost::multi_array<double,2> array;
    typedef boost::multi_array_types::index_range range;
    
    class array2d
    {
    	public:
    		array2d(unsigned int,unsigned int);
    		void fill_row(unsigned int, unsigned int, unsigned int, double);
    		double content(unsigned int, unsigned int);
    
    	private:
    		unsigned int _n, _m;
    		array A;
    		array::index_gen indices;
    };
    #endif
    
    /*
    array2d.cpp
    */
    #include "array2d.h"
    /*
    ---{}--- constructor ---{}---
    */
    array2d::array2d(unsigned int n, unsigned int m):
    _n(n), _m(m),
    A(boost::extents[n][m])
    {
    	std::fill( A.data(), A.data() + A.num_elements(), 0.0);
    }
    /*
    ---{}--- fill row ---{}---
    */
    auto array2d::fill_row(unsigned int row, unsigned int from,
    	unsigned int till, double value) -> void
    {
    	array::array_view<1>::type view(A[ indices[row][range(0,_m-1)] ]);
    	std::fill( view.begin() + from, view.begin() + till, value);
    }
    /*
    ---{}--- content ---{}---
    */
    auto array2d::content(unsigned int n, unsigned int m) -> double
    {
    	return A[n][m];
    }
    

    Gruß,
    -- Klaus.



  • Ich habe dazu mal noch eine dumme Frage:
    Dieses fill übernimmt in Zeile 12 einen Pointer durch A.data() und in Zeile 21 einen Iterator view.begin() .

    Wieso knirsch das nicht? Es heißt zwar, dass ein Iterator im Prinzip eine Art Pointer auf eine bestimmte Stelle des Containers ist - aber kann ich beide Objekte im Gebrauch einfach einander tauschen?

    Oder wird da irgendwo noch ein Typ konvertiert? Oder ist ein Iterator eine Art Wrapper um einen Pointer, wo die Info schon drin steckt auf welches Objekt der Pointer zeigen soll?

    Gruß,
    -- Klaus.


  • Mod

    Klaus: Nicht trailing-return-types falsch verwenden. Du sollst schon weiterhin void und double hinschreiben:

    double array2d::content(unsigned int n, unsigned int m)
    

    Die sind fuer etwas ganz anderes gedacht.

    Wieso knirsch das nicht? Es heißt zwar, dass ein Iterator im Prinzip eine Art Pointer auf eine bestimmte Stelle des Containers ist - aber kann ich beide Objekte im Gebrauch einfach einander tauschen?

    Ein Iterator ist einfach ein allgemeiner Zeiger. vector::iterator kann ein Zeiger sein, aber auch ein Wrapper um einen Zeiger, oder aber ein Zeiger auf den Arrayanfang/Zeiger auf den vector und ein Offset (evt. sinnvoll zum Debuggen).
    Ein Zeiger erfuellt genauso die Anforderungen an einen Forward Iterator wie der Iterator aus dem View.

    aber kann ich beide Objekte im Gebrauch einfach einander tauschen?

    Wenn sie auf dasselbe Objekt verweisen, und dieselbe Operator-Semantik haben (wie sich der Verweis nach ++/-- aendert).



  • Klaus82 schrieb:

    Also es läuft, ich kriege nur folgende Fehlermeldung

    array2d.cpp: In member function ‘void array2d::fill_row(unsigned int, unsigned int, unsigned int, double)’:
    array2d.cpp:17:6: warning: ‘new_strides.boost::array<long int, 1ul>::elems[0ul]’ may be used uninitialized in this function [-Wmaybe-uninitialized]

    Scheinbar ist diese Art Fehler bekannt, wie hier gemeldet, nur gibt es noch keine Lösung?

    Gruß,
    -- Klaus.


  • Mod

    Kann ich mit Boost 1.49 und GCC 4.8 nicht nachvollziehen. Welche Versionen nutzt du?



  • SeppJ schrieb:

    Kann ich mit Boost 1.49 und GCC 4.8 nicht nachvollziehen. Welche Versionen nutzt du?

    Also laut Paketmanager meines Debiansystems kann ich auch Boost 1.49 installieren, habe allerdings gcc 4.7.2.

    Gruß,
    -- Klaus.



  • was passiert dann wenn ich sowas definiere?

    typedef boost::multi_array<int, 3> array_type;
    array_type arr;
    arr.resize(boost::extents[2][3][0]);
    


  • kann ich eine 1d,2d,3d array klasse definieren indem ich die groesse als template param uebergebe?



  • bitte um hilfe 😃


  • Mod

    Vollständige Problembeschreibung. Klare Fragen. Keine Threads grundlos von den Toten beleben.


Anmelden zum Antworten