C++-Programmierung/ Eine Matrix-Bibliothek – mitrax/ matrix.hpp

Aus Wikibooks
Zur Navigation springen Zur Suche springen
Nuvola-inspired-terminal.svg
  1 #ifndef _mitrax_mitrax_matrix_hpp_INCLUDED_
  2 #define _mitrax_mitrax_matrix_hpp_INCLUDED_
  3 /// \file matrix.hpp
  4 ///
  5 /// \brief Matrixklasse
  6 ///
  7 /// In dieser Datei steht die Definition der <code>matrix</code>-Klasse, welche die Kernkomponente
  8 /// von mitrax bildet. Eine Überladung der <code>swap()</code>-Funktion für
  9 /// <code>matrix</code>-Objekte ist ebenfalls hier definiert. Weiterhin existiert in dieser Datei
 10 /// die von mitrax genutzter Trait-Klasse <code>identity</code>, welche für einen gegeben Datentyp
 11 /// die neutralen Elemente bezüglich der Addition und Multiplikation liefert.
 12 
 13 
 14 #include <vector>
 15 #include "proxy.hpp"
 16 #include "dimension.hpp"
 17 
 18 namespace mitrax{
 19 
 20 namespace detail{
 21 
 22 /// \brief Positionsberechnung eines Elements in einem 1D-Feld anhand der 2D-Position
 23 ///
 24 /// Diese Klasse sollte nicht direkt vom Nutzer verwendet werden.
 25 ///
 26 /// siehe matrix::position_adapter
 27 template < typename SizeType >
 28 class position_adapter{
 29 public:
 30     /// \brief Nutzt <code>columns</code> als Spaltenanzahl
 31     position_adapter(SizeType columns):columns_(columns){}
 32     /// \brief Nutzt <code>dim.columns()</code> als Spaltenanzahl
 33     position_adapter(dimension< SizeType > const& dim):columns_(dim.columns()){}
 34 
 35     /// \brief Gibt <code>row * Spaltenanzahl + column</code> zurück
 36     SizeType const operator()(SizeType const& row, SizeType const& column){
 37         return row * columns_ + column;
 38     }
 39 
 40 private:
 41     /// \brief Gespeicherte Spaltenanzahl
 42     SizeType columns_;
 43 };
 44 
 45 }
 46 
 47 /// \brief Matrizen mit Elementzugriff und Größenanpassung
 48 ///
 49 /// Die <code>matrix</code>-Templateklasse ist das Herzstück von mitrax. Sie besitzt im
 50 /// Wesentlichen eine Dimension (Zeilen mal Spalten) und die entsprechend angeordneten Element.
 51 ///
 52 /// Die Erstellung einer Matrix kann mittels Standardkonstruktor mit einer Dimension von Null
 53 /// erfolgen. Weiterhin existieren Konstruktoren für die Erstellung mit einer angegebenen Dimension
 54 /// und einem Füllelement (Defaultwert T()) oder einem Argument vom Typ Referenz auf Container,
 55 /// welches die korrekte Anzahl von Elementen enthalten muss. Das Argument wird nach dem Aufruf
 56 /// keine Elemente mehr enthalten!
 57 ///
 58 /// Compilergenerierte Methoden:
 59 ///   - Kopierkonstruktor
 60 ///     - T muss kopierkonstruierbar sein
 61 ///     - Container muss kopierkonstruierbar sein
 62 ///     - size_type muss kopierkonstruierbar sein
 63 ///   - Kopierzuweisung
 64 ///     - T muss kopierzuweisbar sein
 65 ///     - Container muss kopierzuweisbar sein
 66 ///     - size_type muss kopierzuweisbar sein
 67 ///   - Desturktor
 68 ///     - T muss destruierbar sein
 69 ///     - Container muss destruierbar sein
 70 ///     - size_type muss destruierbar sein
 71 ///
 72 /// \section proxy_interface Proxy-Interface
 73 ///
 74 /// Der wahlfreie Zugriff auf einzelne Elemente erfolgt, unter Zuhilfenahme von Proxyklassen, durch
 75 /// zweimalige Anwendung des Indexoperators (<code>operator[]()</code>). Der Zugriff kann auch über
 76 /// Methoden <code>row()</code> und <code>column()</code> erfolgen. Entsprechend ist auch der
 77 /// Zugriff auf einzelne Zeilen und Spalten möglich. Der Zugriff über Zeilenproxys ist tendenziell
 78 /// schneller.
 79 ///
 80 /// Die Proxyklassen können kopiert und aneinander zugewiesen werden, so dass unter bestimmten
 81 /// Umständen, die Vertauschung zweier Proxys stellvertretend für die Vertauschung zweier
 82 /// kompletter Zeilen oder Spalten genutzt werden kann. Zu diesem Zweck kann beispielsweise ein
 83 /// Feld mit allen Zeilenproxys einer Matrix erstellt werden. Der Zugriff auf die Elemente ist
 84 /// dann, durch zweimalige Anwendung des Indexoperators, auch über dieses Feld möglich.
 85 ///
 86 /// Um Zuweisungen an ein temporäres Objekt zu verhindern, sind die von matrix zurückgegebenen
 87 /// Proxyobjekte immer konstant. Die Daten, auf welche die Proxys verweisen, haben mit dieser
 88 /// Konstantheit natürlich nichts zu tun.
 89 ///
 90 /// \section iterator_interface Iterator-Interface
 91 ///
 92 /// Für die elementweise Bearbeitung der Elemente wird ein Iterator-Interface angeboten. Neben den
 93 /// Methoden <code>begin()</code> und <code>end()</code>, welche in einer konstanten und einer
 94 /// nicht-konstante Version existieren, gibt es auch noch die Methoden <code>cbegin()</code> und
 95 /// <code>cend()</code>, welche immer <code>const_iterator</code>-Objekte zurückgeben.
 96 ///
 97 /// Auch die Proxyklassen verfügen über ein Iteratorinterface dieser Art. Wobei zu beachten ist,
 98 /// das die Methoden <code>begin()</code> und <code>end()</code> für die Proxys für nicht-konstante
 99 /// Matrizen (<code>row_proxy</code> und <code>column_proxy</code>) immer auch Iteratoren für
100 /// nicht-konstante Matrizen zurückgeben, unabhängig davon, ob das Proxyobjekt selbst konstant ist.
101 template < typename T, typename Container = std::vector< T > >
102 class matrix{
103 public:
104     // types:
105     /// \brief Datentyp der Elemente
106     typedef T                                     value_type;
107     /// \brief Referenz auf ein Element
108     typedef T&                                    reference;
109     /// \brief Referenz auf ein konstantes Element
110     typedef T const&                              const_reference;
111     /// \brief Typ des Containers
112     typedef Container                             container_type;
113 
114     /// \brief Typ für eine Anzahl Zeilen oder Spalten
115     typedef typename Container::size_type         size_type;
116     /// \brief Typ der Dimension
117     typedef mitrax::dimension< size_type >        dimension_type;
118 
119     /// \brief Iteratortyp der auf den <code>value_type</code> verweist
120     typedef typename Container::iterator          iterator;
121     /// \brief Iteratortyp der auf den konstanten <code>value_type</code> verweist
122     typedef typename Container::const_iterator    const_iterator;
123     /// \brief Vorzeichenbehaftete Ganzzahl
124     typedef typename Container::difference_type   difference_type;
125 
126     /// \brief Proxy für eine Zeile
127     typedef mitrax::row_proxy< matrix >           row_proxy;
128     /// \brief Proxy für eine konstante Zeile
129     typedef mitrax::row_const_proxy< matrix >     row_const_proxy;
130     /// \brief Proxy für eine Spalte
131     typedef mitrax::column_proxy< matrix >        column_proxy;
132     /// \brief Proxy für eine konstante Spalte
133     typedef mitrax::column_const_proxy< matrix >  column_const_proxy;
134 
135     /// \brief Positionsberechnung eines Elements in einem 1D-Feld anhand der 2D-Position
136     ///
137     /// Es handelt sich bei diesem Typ um einen Funktor, welcher anhand einer Zeilenlänge und
138     /// zweier 2D-Koordinaten die Speicherposition eines Elements, in einem eindimensionalen
139     /// Container berechnet. Er bekommt bei seiner Initialisierung die Anzahl der Spalten
140     /// (Zeilenlänge) und kann anschließend mit den zwei Koordinaten (x, y) aufgerufen werden.
141     ///
142     /// Zur Initialisierung kann neben einer Zeilenlänge auch ein <code>dimension</code>-Objekt
143     /// verwendet werden.
144     typedef detail::position_adapter< size_type > position_adapter;
145 
146 
147     // construct/copy/destroy:
148     /// \brief Erstellt eine Matrix mit Null Zeilen und Spalten
149     matrix();
150     /// \brief Erstellt eine Matrix der Dimension <code>size</code> und füllt alle Elemente mit
151     ///        <code>fill</code>
152     matrix(dimension_type const& size, const_reference fill = value_type());
153     /// \brief Erstellt eine Matrix mit <code>rows</code> Zeilen und <code>columns</code> Spalten
154     ///        und füllt alle Elemente mit <code>fill</code>
155     matrix(size_type const& rows, size_type const& columns, const_reference fill = value_type());
156     /// \brief Erstellt eine Matrix der Dimension <code>size</code> und verwendet <code>data</code>
157     ///        als Elemente
158     ///
159     /// In <code>data</code> müssen <code>size.rows() * size.columns()</code> viele Einträge
160     /// enthalten sein. Der Konstruktor tauscht <code>data</code> gegen einen leeren Container aus.
161     /// Die Berechnung der zweidimensionalen Position erfolgt mit
162     /// <code>row * columns + column</code>. Dies gewährleistet eine sehr effiziente
163     /// Initialisierung.
164     ///
165     /// \throw error::data_size falls <code>data.size() != size.rows() * size.columns()</code>
166     matrix(dimension_type const& size, container_type& data);
167     /// \brief Erstellt eine Matrix mit rows Zeilen und columns Spalten und verwendet data als
168     ///        Elemente
169     ///
170     /// \throw error::data_size falls <code>data.size() != size.rows() * size.columns()</code>
171     matrix(size_type const& rows, size_type const& columns, container_type& data);
172 
173 
174     // iterators:
175     /// \brief Gibt einen Schreib-/Leseiterator auf das erste Element der Matrix zurück
176     ///
177     /// Siehe \ref iterator_interface "Iterator-Interface"
178     iterator const       begin();
179     /// \brief Gibt einen Leseiterator auf das erste Element der Matrix zurück
180     ///
181     /// Siehe \ref iterator_interface "Iterator-Interface"
182     const_iterator const begin()const;
183     /// \brief Gibt einen Schreib-/Leseiterator hinter das letzte Element der Matrix zurück
184     ///
185     /// Siehe \ref iterator_interface "Iterator-Interface"
186     iterator const       end();
187     /// \brief Gibt einen Leseiterator hinter das letzte Element der Matrix zurück
188     ///
189     /// Siehe \ref iterator_interface "Iterator-Interface"
190     const_iterator const end()const;
191     /// \brief Gibt einen Leseiterator auf das erste Element der Matrix zurück
192     ///
193     /// Siehe \ref iterator_interface "Iterator-Interface"
194     const_iterator const cbegin()const;
195     /// \brief Gibt einen Leseiterator hinter das letzte Element der Matrix zurück
196     ///
197     /// Siehe \ref iterator_interface "Iterator-Interface"
198     const_iterator const cend()const;
199 
200 
201     // capacity:
202     /// \brief Gibt die Dimension der Matrix zurück
203     ///
204     /// Die Dimension einer Matrix beinhaltet die Anzahl der Zeilen und Spalten.
205     ///
206     /// Siehe auch:
207     ///   - \link rows \endlink
208     ///   - \link columns \endlink
209     dimension_type const dimension()const;
210 
211     /// \brief Gibt die Anzahl der Zeilen zurück
212     ///
213     /// Siehe auch:
214     ///   - \link rows \endlink
215     ///   - \link dimension \endlink
216     size_type const rows()const;
217     /// \brief Gibt die Anzahl der Spalten zurück
218     ///
219     /// Siehe auch:
220     ///   - \link columns \endlink
221     ///   - \link dimension \endlink
222     size_type const columns()const;
223 
224     /// \brief Setzt die Dimension der Matrix neu
225     ///
226     /// Diese Methode setzt die Dimension der Matrix neu. Ist <code>preserve</code> gesetzt,
227     /// werden Elemente die bei der alten und neuen Dimension existieren, erhalten. Alle übrigen
228     /// Elemente werden auf <code>fill</code> gesetzt. Ist <code>preserve</code> nicht gesetzt,
229     /// werden alle Elemente auf <code>fill</code> gesetzt.
230     void resize(
231         dimension_type const& size,
232         bool preserve = true,
233         const_reference fill = value_type()
234     );
235     /// \brief Setzt die Dimension der Matrix neu
236     ///
237     /// Siehe \link resize \endlink
238     void resize(
239         size_type const& rows,
240         size_type const& columns,
241         bool preserve = true,
242         const_reference fill = value_type()
243     );
244 
245     /// \brief Reinitialisiert die Matrix mit gegebener Dimension und gegebenen Daten
246     ///
247     /// In <code>data</code> müssen <code>size.rows() * size.columns()</code> viele Einträge
248     /// enthalten sein. Der Konstruktor tauscht <code>data</code> gegen den aktuellen Container
249     /// mit den Elementdaten aus. Die Berechnung der zweidimensionalen Position erfolgt mit
250     /// <code>row * columns + column</code>. Dies gewährleistet eine sehr effiziente
251     /// Initialisierung.
252     ///
253     /// \throw error::data_size falls <code>data.size() != size.rows() * size.columns()</code>
254     void reinit(dimension_type const& size, container_type& data);
255     /// \brief Reinitiallisiert die Matrix mit gegebener Dimension und gegebenen Daten
256     ///
257     /// \throw error::data_size falls <code>data.size() != size.rows() * size.columns()</code>
258     void reinit(size_type const& rows, size_type const& columns, container_type& data);
259 
260 
261     // element access:
262     /// \brief Gibt einen Schreib-/Leseproxy für die Zeile <code>row</code> zurück
263     row_proxy const          operator[](size_type const& row);
264     /// \brief Gibt einen Leseproxy für die Zeile <code>row</code> zurück
265     row_const_proxy const    operator[](size_type const& row)const;
266     /// \brief Gibt einen Schreib-/Leseproxy für die Zeile <code>number</code> zurück
267     row_proxy const          row(size_type const& number);
268     /// \brief Gibt einen Leseproxy für die Zeile <code>number</code> zurück
269     row_const_proxy const    row(size_type const& number)const;
270     /// \brief Gibt einen Schreib-/Leseproxy für die Spalte <code>number</code> zurück
271     column_proxy const       column(size_type const& number);
272     /// \brief Gibt einen Leseproxy für die Spalte <code>number</code> zurück
273     column_const_proxy const column(size_type const& number)const;
274 
275 
276     // modifiers:
277     /// \brief Löscht eine oder mehrere Zeile
278     ///
279     /// Durch das Löschen von <code>count</code> vielen Zeilen verringert sich die Anzahl
280     /// der Zeilen um <code>count</code>.
281     void erase_row(size_type const& number, size_type const& count = size_type(1));
282     /// \brief Löscht eine oder mehrere Spalte
283     ///
284     /// Durch das Löschen von <code>count</code> vielen Spalten verringert sich die Anzahl
285     /// der Spalten um <code>count</code>.
286     void erase_column(size_type const& number, size_type const& count = size_type(1));
287 
288     /// \brief Tauscht Dimension und Werte der aktuellen Matrix mit jenen aus <code>m</code>
289     ///
290     /// Die Vertauschung erfolgt durch den Aufruf von <code>swap()</code> für die beiden
291     /// Containerobjekte und die Dimensionobjekte. Bei ersteren existiert oft eine überladene
292     /// oder spezialisierte Version, die sehr Effizient ist. Die argumentabhängige Namenssuche
293     /// für eine solche <code>swap()</code>-Funktion wird unterstützt.
294     void swap(matrix& m);
295 
296 private:
297     /// \brief Speichert die Anzahl der Zeilen und Spalten
298     dimension_type dimension_;
299     /// \brief Speichert die Elemente der Matrix
300     ///
301     /// Der Zugriff im 2D-Raum erfolgt mittels <code>row * columns + column</code>
302     container_type data_;
303 
304     /// \brief Helfer um Codeverdopplung zu vermeiden
305     ///
306     /// Prüft ob die Anzahl der Elemente in <code>data</code> zu <code>size</code> passt. Ist dies
307     /// nicht der Fall, wird eine Ausnahme vom Typ <code>error::data_size</code> geworfen.
308     /// Andernfalls wird <code>swap(data_, data)</code> aufgerufen. Die Dimension wird \em nicht
309     /// zugewiesen.
310     ///
311     /// \throw error::data_size
312     void raw_data_swap(dimension_type const& size, container_type& data);
313 };
314 
315 /// \brief Vertauscht zwei Matrizen
316 ///
317 /// Ruft <code>lhs.swap(rhs)</code> auf.
318 template < typename T, typename Container >
319 void swap(matrix< T, Container >& lhs, matrix< T, Container >& rhs);
320 
321 /// \brief Neutrale Elemente für einen numerischen Datentyp <code>T</code>
322 ///
323 /// Dies ist eine Trait-Klasse. Sie stellt durch die statischen Funktionen <code>additive()</code>
324 /// und <code>multiplicative()</code> die neutralen Elemente bezüglich der Addition und der
325 /// Multiplikation mit einem Objekt eines numerischen Datentyps <code>T</code> bereit.
326 ///
327 /// In der Standardimplementierung wird angenommen, das ein standardkonstruiertes
328 /// <code>T</code>-Objekt bezüglich der Addition neutral ist. Addiert man zu diesem den
329 /// <code>int</code>-Literal <code>1</code> sollte sich das neutrale Element bezüglich der
330 /// Multiplikation ergeben. Trifft dies auf einen Datentyp den Sie verwenden möchten nicht zu, so
331 /// können Sie eine entsprechende Spezialisierung des Templates  <code>identity</code> vornehmen.
332 ///
333 /// Standardmäßig gibt es eine Spezialisierung für alle Klassentemplates, die eine Parametertyp
334 /// <code>U</code> übernehmen. Für derartige Klassen wird wiederum angenommen, das ein
335 /// standardkonstruiertes Objekt bezüglich der Addition neutral ist. Für die Multiplikation wird
336 /// diesmal angenommen, dass sich das neutrale Element durch die Addition des standardkonstruierten
337 /// Objekts mit dem multiplikativen Neutrum von <code>U<code> ergibt.
338 ///
339 /// Klassen, die mehrere neutrale Elemente pro Operation besitzen, wie etwa die
340 /// <code>matrix</code>-Klasse, werden derzeit nicht unterstützt.
341 template < typename T >
342 struct identity{
343     /// \brief Additives Neutrum
344     static T const& additive()      { static T const t=T();    return t; };
345     /// \brief Multiplikatives Neutrum
346     static T const& multiplicative(){ static T const t(T()+1); return t; };
347 };
348 
349 /// \brief Neutrale Elemente für einen numerischen Datentyp <code>Numeric< T ></code>
350 ///
351 /// Speziallisierung von <code>identity< T ></code>.
352 template < typename T, template < typename U > class Numeric >
353 struct identity< Numeric< T > >{
354     /// \brief Additives Neutrum
355     static Numeric< T > const& additive(){
356         static Numeric< T > const t=T(); return t;
357     };
358 
359     /// \brief Multiplikatives Neutrum
360     static Numeric< T > const& multiplicative(){
361         static Numeric< T > const t(Numeric< T >() + identity< T >::multiplicative());
362         return t;
363     };
364 };
365 
366 
367 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
368 // Definitionen
369 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
370 
371 template < typename T, typename Container >
372 inline
373 matrix< T, Container >::matrix()
374     {}
375 
376 template < typename T, typename Container >
377 inline
378 matrix< T, Container >::matrix(
379     matrix< T, Container >::dimension_type const& size,
380     const_reference fill
381 ):
382     dimension_(size),
383     data_(elements(dimension_), fill)
384     {}
385 
386 template < typename T, typename Container >
387 inline
388 matrix< T, Container >::matrix(
389     size_type const& rows,
390     size_type const& columns,
391     const_reference fill
392 ):
393     dimension_(dimension_type(rows, columns)),
394     data_(elements(dimension_), fill)
395     {}
396 
397 template < typename T, typename Container >
398 inline
399 matrix< T, Container >::matrix(
400     dimension_type const& size,
401     container_type& data
402 ):
403     dimension_(size)
404 {
405     raw_data_swap(dimension_, data);
406 }
407 
408 template < typename T, typename Container >
409 inline
410 matrix< T, Container >::matrix(
411     size_type const& rows,
412     size_type const& columns,
413     container_type& data
414 ):
415     dimension_(dimension_type(rows, columns))
416 {
417     raw_data_swap(dimension_, data);
418 }
419 
420 template < typename T, typename Container >
421 inline
422 typename matrix< T, Container >::dimension_type const
423 matrix< T, Container >::dimension()const{
424     return dimension_;
425 }
426 
427 template < typename T, typename Container >
428 inline
429 typename matrix< T, Container >::size_type const
430 matrix< T, Container >::rows()const{
431     return dimension_.rows();
432 }
433 
434 template < typename T, typename Container >
435 inline
436 typename matrix< T, Container >::size_type const
437 matrix< T, Container >::columns()const{
438     return dimension_.columns();
439 }
440 
441 
442 template < typename T, typename Container >
443 inline
444 typename matrix< T, Container >::iterator const
445 matrix< T, Container >::begin(){
446     return data_.begin();
447 }
448 
449 template < typename T, typename Container >
450 inline
451 typename matrix< T, Container >::const_iterator const
452 matrix< T, Container >::begin()const{
453     return data_.begin();
454 }
455 
456 template < typename T, typename Container >
457 inline
458 typename matrix< T, Container >::iterator const
459 matrix< T, Container >::end(){
460     return data_.end();
461 }
462 
463 template < typename T, typename Container >
464 inline
465 typename matrix< T, Container >::const_iterator const
466 matrix< T, Container >::end()const{
467     return data_.end();
468 }
469 
470 
471 template < typename T, typename Container >
472 inline
473 typename matrix< T, Container >::const_iterator const
474 matrix< T, Container >::cbegin()const{
475     return begin();
476 }
477 
478 template < typename T, typename Container >
479 inline
480 typename matrix< T, Container >::const_iterator const
481 matrix< T, Container >::cend()const{
482     return end();
483 }
484 
485 
486 template < typename T, typename Container >
487 inline
488 typename matrix< T, Container >::row_proxy const
489 matrix< T, Container >::operator[](
490     size_type const& number
491 ){
492     return row(number);
493 }
494 
495 template < typename T, typename Container >
496 inline
497 typename matrix< T, Container >::row_const_proxy const
498 matrix< T, Container >::operator[](
499     size_type const& number
500 )const{
501     return row(number);
502 }
503 
504 template < typename T, typename Container >
505 inline
506 typename matrix< T, Container >::row_proxy const
507 matrix< T, Container >::row(
508     size_type const& number
509 ){
510     return row_proxy(*this, number);
511 }
512 
513 template < typename T, typename Container >
514 inline
515 typename matrix< T, Container >::row_const_proxy const
516 matrix< T, Container >::row(
517     size_type const& number
518 )const{
519     return row_const_proxy(*this, number);
520 }
521 
522 template < typename T, typename Container >
523 inline
524 typename matrix< T, Container >::column_proxy const
525 matrix< T, Container >::column(
526     size_type const& number
527 ){
528     return column_proxy(*this, number);
529 }
530 
531 template < typename T, typename Container >
532 inline
533 typename matrix< T, Container >::column_const_proxy const
534 matrix< T, Container >::column(
535     size_type const& number
536 )const{
537     return column_const_proxy(*this, number);
538 }
539 
540 
541 template < typename T, typename Container >
542 inline
543 void matrix< T, Container >::raw_data_swap(dimension_type const& size, container_type& data){
544     if(elements(size) != data.size()){
545         throw error::data_size("mitrax::matrix<>::raw_data_swap", size, data);
546     }
547     using std::swap;
548     swap(data_, data);
549 }
550 
551 
552 template < typename T, typename Container >
553 inline
554 void
555 matrix< T, Container >::resize(
556     matrix< T, Container >::dimension_type const& size,
557     bool preserve,
558     const_reference fill
559 ){
560     container_type init(elements(size), fill); // Neuer Container
561 
562     if(preserve){
563         // Länge der pro Zeile zu kopierenden Elemente ermitteln
564         size_type min_columns = std::min(size.columns(), dimension_.columns());
565         // Differenz von kurzen und langen Zeilen
566         size_type dif_columns = std::max(size.columns(), dimension_.columns()) - min_columns;
567         // Iteratoren beider Container
568         iterator  data_iter = data_.begin();
569         iterator  init_iter = init.begin();
570         // Iterator mit den längeren Zeilen ermitteln
571         iterator& bigger    = size.columns() < dimension_.columns() ? data_iter : init_iter;
572         // Zeilenweise durchlaufen
573         for(size_type i = size_type(); i < size.rows() && i < dimension_.rows(); ++i){
574             // Iteratoren hinter das Ende des zu kopierenden Bereiches setzen
575             iterator begin_data_iter = data_iter;
576             iterator begin_init_iter = init_iter;
577             data_iter += min_columns;
578             init_iter += min_columns;
579             // Kopie durchführen
580             std::copy(begin_data_iter, data_iter, begin_init_iter);
581             // Iterator mit den längeren Zeilen auf den Anfang der nächsten Zeile setzen
582             bigger += dif_columns;
583         }
584     }
585 
586     using std::swap;
587     swap(data_, init);
588     dimension_ = size;
589 }
590 
591 template < typename T, typename Container >
592 inline
593 void
594 matrix< T, Container >::resize(
595     size_type const& rows,
596     size_type const& columns,
597     bool preserve,
598     const_reference fill
599 ){
600     resize(dimension_type(rows, columns), preserve, fill);
601 }
602 
603 template < typename T, typename Container >
604 inline
605 void
606 matrix< T, Container >::reinit(
607     dimension_type const& size,
608     container_type& data
609 ){
610     raw_data_swap(size, data);
611     dimension_ = size;
612 }
613 
614 template < typename T, typename Container >
615 inline
616 void
617 matrix< T, Container >::reinit(
618     size_type const& rows,
619     size_type const& columns,
620     container_type& data
621 ){
622     reinit(dimension_type(rows, columns), data);
623 }
624 
625 
626 template < typename T, typename Container >
627 inline
628 void
629 matrix< T, Container >::erase_row(
630     size_type const& number,
631     size_type const& count
632 ){
633     if(rows() < number + count){
634         throw error::row_access("mitrax::matrix<>::erase_row", dimension_, rows());
635     }
636 
637     // Zeilen löschen
638     iterator iter = data_.begin();
639     iter += number * columns();
640     data_.erase(iter, iter + count * columns());
641     // Dimension anpassen
642     dimension_.resize(rows() - count, columns());
643 }
644 
645 template < typename T, typename Container >
646 inline
647 void
648 matrix< T, Container >::erase_column(
649     size_type const& number,
650     size_type const& count
651 ){
652     if(columns() < number + count){
653         throw error::column_access("mitrax::matrix<>::erase_column", dimension_, columns());
654     }
655 
656     // Zeilen löschen
657     for(size_type i = size_type(); i < rows(); ++i){
658         iterator iter = data_.begin();
659         iter += number + (columns() - count) * i;
660         data_.erase(iter, iter + count);
661     }
662     // Dimension anpassen
663     dimension_.resize(rows(), columns() - count);
664 }
665 
666 
667 
668 template < typename T, typename Container >
669 inline
670 void
671 matrix< T, Container >::swap(
672     matrix< T, Container >& m
673 ){
674     using std::swap;
675     swap(data_, m.data_);
676     swap(dimension_, m.dimension_);
677 }
678 
679 template < typename T, typename Container >
680 inline
681 void
682 swap(
683     matrix< T, Container >& lhs,
684     matrix< T, Container >& rhs
685 ){
686     lhs.swap(rhs);
687 }
688 
689 
690 }
691 
692 #endif