source: src/Fragmentation/MatrixContainer.cpp@ fba720

Candidate_v1.6.1 ChemicalSpaceEvaluator TremoloParser_IncreasedPrecision
Last change on this file since fba720 was 184d89, checked in by Frederik Heber <frederik.heber@…>, 8 years ago

FIX: MatrixContainer's serialize() was broken because default cstor initialized some members.

  • boost::serialization somehow changed its default behavior when deserializing vectors. Now, if the member variables are vectors and initialized with some initial elements, then these are kept and the new elements just added on top. Before, the vector was cleared and set equal to the serialized elements.
  • Now, we have split MatrixContainer serialize() into load()/save() where we clear the member variables in question first.
  • Property mode set to 100644
File size: 20.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * MatrixContainer.cpp
25 *
26 * Created on: Sep 15, 2011
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35// include headers that implement a archive in simple text format
36// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
37#include <boost/archive/text_oarchive.hpp>
38#include <boost/archive/text_iarchive.hpp>
39
40//#include "CodePatterns/MemDebug.hpp"
41
42#include <cstring>
43#include <fstream>
44#include <iomanip>
45
46#include "CodePatterns/Log.hpp"
47#include "KeySetsContainer.hpp"
48
49#include "Fragmentation/helpers.hpp"
50#include "Helpers/defs.hpp"
51#include "Helpers/helpers.hpp"
52
53#include "MatrixContainer.hpp"
54
55/** Constructor of MatrixContainer class.
56 */
57MatrixContainer::MatrixContainer()
58{
59 Header.resize(1);
60 RowCounter.resize(1);
61 ColumnCounter.resize(1);
62 ColumnCounter[0] = -1;
63 MatrixCounter = 0;
64};
65
66/** Destructor of MatrixContainer class.
67 */
68MatrixContainer::~MatrixContainer()
69{}
70
71/** Either copies index matrix from another MatrixContainer or initialises with trivial mapping if NULL.
72 * This either copies the index matrix or just maps 1 to 1, 2 to 2 and so on for all fragments.
73 * \param *Matrix pointer to other MatrixContainer
74 * \return true - copy/initialisation sucessful, false - dimension false for copying
75 */
76bool MatrixContainer::InitialiseIndices(class MatrixContainer *_container)
77{
78 if (_container == NULL) {
79 LOG(3, "INFO: Initialising indices with trivial mapping.");
80 Indices.resize(MatrixCounter + 1);
81 for(int i=MatrixCounter+1;i--;) {
82 Indices[i].resize(RowCounter[i]);
83 for(int j=RowCounter[i];j--;)
84 Indices[i][j] = j;
85 }
86 } else {
87 std::stringstream output;
88 if (MatrixCounter != _container->MatrixCounter)
89 return false;
90 Indices.resize(MatrixCounter + 1);
91 for(int i=MatrixCounter+1;i--;) {
92 if (RowCounter[i] != _container->RowCounter[i])
93 return false;
94 Indices[i].resize(_container->RowCounter[i]);
95 for(int j=_container->RowCounter[i];j--;) {
96 Indices[i][j] = _container->Indices[i][j];
97 output << Indices[i][j] << "\t";
98 }
99 }
100 LOG(3, "INFO: Initialising indices from other MatrixContainer: " << output.str());
101 }
102 return true;
103};
104
105/** Parsing a number of matrices.
106 * -# open the matrix file
107 * -# skip some lines (\a skiplines)
108 * -# scan header lines for number of columns
109 * -# scan lines for number of rows
110 * -# allocate a temporary matrix
111 * -# loop over found column and row counts and parse in each entry
112 * -# use MatrixContainer::AddMatrix() to add the parsed matrix to the internal
113 * \param &input input stream
114 * \param skiplines number of inital lines to skip
115 * \param skiplines number of inital columns to skip
116 * \param MatrixNr index number in Matrix array to parse into
117 * \return parsing successful
118 */
119bool MatrixContainer::ParseMatrix(std::istream &input, int skiplines, int skipcolumns, size_t MatrixNr)
120{
121 stringstream line;
122 string token;
123 char filename[1023];
124
125 if (input.fail()) {
126 ELOG(1, endl << "MatrixContainer::ParseMatrix: Unable to parse istream.");
127 //performCriticalExit();
128 return false;
129 }
130
131 // parse header
132 std::string header;
133 char dummy[1024];
134 for (int m=skiplines+1;m--;)
135 input.getline(dummy, 1023);
136 line.str(dummy);
137 for(int k=skipcolumns;k--;)
138 line >> header;
139 LOG(3, "INFO: Header of Matrix " << MatrixNr << " :" << line.str());
140
141 // scan header for number of columns
142 size_t ColumnCounter = 0;
143 while ( getline(line,token, '\t') ) {
144 if (token.length() > 0)
145 ColumnCounter++;
146 }
147 LOG(3, "INFO: "+line.str());
148
149 // scan rest for number of rows/lines
150 size_t RowCounter = -1;
151 while (!input.eof()) {
152 input.getline(filename, 1023);
153 LOG(3, "INFO: Comparing: " << strncmp(filename,"MeanForce",9));
154 RowCounter++; // then line was not last MeanForce
155 if (strncmp(filename,"MeanForce", 9) == 0) {
156 break;
157 }
158 }
159
160 // allocate temporary matrix
161 MatrixArray temp_matrix;
162 temp_matrix.resize(RowCounter);
163 for(MatrixArray::iterator iter = temp_matrix.begin(); iter != temp_matrix.end(); ++iter)
164 (*iter).resize(ColumnCounter);
165
166 // parse in each entry for this matrix
167 input.clear();
168 input.seekg(ios::beg);
169 for (int m=skiplines+1;m--;)
170 input.getline(dummy, 1023); // skip header
171 line.str(dummy);
172 LOG(3, "INFO: Header: " << line.str());
173 for(int k=skipcolumns;k--;) // skip columns in header too
174 line >> filename;
175 header = line.str();
176 for(size_t j=0;j<RowCounter;j++) {
177 input.getline(filename, 1023);
178 std::stringstream lines(filename);
179 std::stringstream output;
180 output << "INFO: Matrix at level " << j << ":";// << filename << endl;
181 for(int k=skipcolumns;k--;)
182 lines >> filename;
183 for(size_t k=0;(k<ColumnCounter) && (!lines.eof());k++) {
184 lines >> temp_matrix[j][k];
185 output << " " << std::setprecision(2) << temp_matrix[j][k] << endl;
186 }
187 LOG(3, output.str());
188 }
189
190 // finally add the matrix
191 return AddMatrix(header, temp_matrix, MatrixNr);
192}
193
194/** Adds a matrix at position \a MatrixNr to MatrixContainer::Matrix.
195 *
196 * @param header header to add for this matrix
197 * @param matrix to add
198 * @param MatrixNr position in MatrixContainer::Matrix.
199 * @return true - insertion ok, false - invalid matrix
200 */
201bool MatrixContainer::AddMatrix(const std::string &header, const MatrixArray &matrix, size_t MatrixNr)
202{
203 // make some pre-checks
204 if (header.size() == 0)
205 ELOG(2, "The given header of the matrix to add is empty.");
206 if (matrix.size() == 0) {
207 ELOG(1, "RowCounter[" << MatrixNr << "]: " << RowCounter[MatrixNr] << " from input stream.");
208 return false;
209 }
210 if (matrix[0].size() == 0) {
211 ELOG(1, "ColumnCounter[" << MatrixNr << "]: " << ColumnCounter[MatrixNr] << " from ostream.");
212 return false;
213 }
214
215 // add header
216 if (Header.size() <= MatrixNr)
217 Header.resize(MatrixNr+1);
218 Header[MatrixNr] = header;
219
220 // row count
221 if (RowCounter.size() <= MatrixNr)
222 RowCounter.resize(MatrixNr+1);
223 RowCounter[MatrixNr] = matrix.size();
224 LOG(4, "INFO: RowCounter[" << MatrixNr << "]: " << RowCounter[MatrixNr] << " from input stream.");
225
226 // column count
227 if (ColumnCounter.size() <= MatrixNr)
228 ColumnCounter.resize(MatrixNr+1);
229 ColumnCounter[MatrixNr] = matrix[0].size();
230 LOG(4, "INFO: ColumnCounter[" << MatrixNr << "]: " << ColumnCounter[MatrixNr] << ".");
231
232 // allocate matrix ...
233 if (Matrix.size() <= MatrixNr)
234 Matrix.resize(MatrixNr+1);
235 MatrixCounter = Matrix.size()-1;
236 Matrix[MatrixNr].resize(RowCounter[MatrixNr] + 1);
237 for(int j=0;j<=RowCounter[MatrixNr];++j)
238 Matrix[MatrixNr][j].resize(ColumnCounter[MatrixNr]+1);
239
240 // .. and copy values
241 for(int j=0;j<RowCounter[MatrixNr];++j)
242 for(int k=0;k<ColumnCounter[MatrixNr];++k)
243 Matrix[MatrixNr][j][k] = matrix[j][k];
244 // reset last column
245 for(int j=0;j<RowCounter[MatrixNr];++j)
246 Matrix[MatrixNr][j][ ColumnCounter[MatrixNr] ] = 0.;
247 // reset last row
248 for(int k=0;k<=ColumnCounter[MatrixNr];++k)
249 Matrix[MatrixNr][ RowCounter[MatrixNr] ][ k ] = 0.;
250
251 return true;
252}
253
254/** Parsing a number of matrices.
255 * -# First, count the number of matrices by counting lines in KEYSETFILE
256 * -# Then,
257 * -# construct the fragment number
258 * -# open the matrix file
259 * -# skip some lines (\a skiplines)
260 * -# scan header lines for number of columns
261 * -# scan lines for number of rows
262 * -# allocate matrix
263 * -# loop over found column and row counts and parse in each entry
264 * -# Finally, allocate one additional matrix (\a MatrixCounter) containing combined or temporary values
265 * \param *name directory with files
266 * \param *prefix prefix of each matrix file
267 * \param *suffix suffix of each matrix file
268 * \param skiplines number of inital lines to skip
269 * \param skiplines number of inital columns to skip
270 * \return parsing successful
271 */
272bool MatrixContainer::ParseFragmentMatrix(const std::string name, const std::string prefix, std::string suffix, int skiplines, int skipcolumns)
273{
274 char filename[1023];
275 ifstream input;
276 char *FragmentNumber = NULL;
277 stringstream file;
278 string token;
279
280 // count the number of matrices
281 MatrixCounter = -1; // we count one too much
282 file << name << FRAGMENTPREFIX << KEYSETFILE;
283 input.open(file.str().c_str(), ios::in);
284 if (input.bad()) {
285 ELOG(1, "MatrixContainer::ParseFragmentMatrix: Unable to open " << file.str() << ", is the directory correct?");
286 return false;
287 }
288 while (!input.eof()) {
289 input.getline(filename, 1023);
290 stringstream zeile(filename);
291 MatrixCounter++;
292 }
293 input.close();
294 LOG(2, "INFO: Determined " << MatrixCounter << " fragments.");
295
296 LOG(1, "STATUS: Parsing through each fragment and retrieving " << prefix << suffix << ".");
297 Header.clear();
298 Matrix.clear();
299 RowCounter.clear();
300 ColumnCounter.clear();
301 Header.resize(MatrixCounter + 1); // one more each for the total molecule
302 Matrix.resize(MatrixCounter + 1); // one more each for the total molecule
303 RowCounter.resize(MatrixCounter + 1);
304 ColumnCounter.resize(MatrixCounter + 1);
305 for(int i=0; i < MatrixCounter;i++) {
306 // open matrix file
307 FragmentNumber = FixedDigitNumber(MatrixCounter, i);
308 file.str(" ");
309 file << name << FRAGMENTPREFIX << FragmentNumber << prefix << suffix;
310 std::ifstream input(file.str().c_str());
311 LOG(2, "INFO: Opening " << file.str() << " ... ");
312 if (!ParseMatrix(input, skiplines, skipcolumns, i)) {
313 input.close();
314 return false;
315 }
316 input.close();
317 delete[](FragmentNumber);
318 }
319 return true;
320};
321
322/** Allocates and resets the memory for a number \a MCounter of matrices.
323 * \param **GivenHeader Header line for each matrix
324 * \param MCounter number of matrices
325 * \param *RCounter number of rows for each matrix
326 * \param *CCounter number of columns for each matrix
327 * \return Allocation successful
328 */
329bool MatrixContainer::AllocateMatrix(StringVector GivenHeader, int MCounter, IntVector RCounter, IntVector CCounter)
330{
331 MatrixCounter = MCounter;
332 Header.resize(MatrixCounter + 1);
333 Matrix.resize(MatrixCounter + 1); // one more each for the total molecule
334 RowCounter.resize(MatrixCounter + 1);
335 ColumnCounter.resize(MatrixCounter + 1);
336 for(int i=MatrixCounter+1;i--;) {
337 Header[i] = GivenHeader[i];
338 RowCounter[i] = RCounter[i];
339 ColumnCounter[i] = CCounter[i];
340 if ((int)Matrix[i].size() <= RowCounter[i] + 2)
341 Matrix[i].resize(RowCounter[i] + 1);
342 for(int j=0;j<=RowCounter[i];j++)
343 if ((int)Matrix[i][j].size() <= ColumnCounter[i]+1)
344 Matrix[i][j].resize(ColumnCounter[i]);
345 // allocation with 0 is guaranted by STL
346 }
347 return true;
348};
349
350/** Resets all values in MatrixContainer::Matrix.
351 * \return true if successful
352 */
353bool MatrixContainer::ResetMatrix()
354{
355 for(int i=MatrixCounter+1;i--;)
356 for(int j=RowCounter[i]+1;j--;)
357 for(int k=ColumnCounter[i];k--;)
358 Matrix[i][j][k] = 0.;
359 return true;
360};
361
362/** Scans all elements of MatrixContainer::Matrix for greatest absolute value.
363 * \return greatest value of MatrixContainer::Matrix
364 */
365double MatrixContainer::FindMaxValue()
366{
367 double max = Matrix[0][0][0];
368 for(int i=MatrixCounter+1;i--;)
369 for(int j=RowCounter[i]+1;j--;)
370 for(int k=ColumnCounter[i];k--;)
371 if (fabs(Matrix[i][j][k]) > max)
372 max = fabs(Matrix[i][j][k]);
373 if (fabs(max) < MYEPSILON)
374 max += MYEPSILON;
375 return max;
376};
377
378/** Scans all elements of MatrixContainer::Matrix for smallest absolute value.
379 * \return smallest value of MatrixContainer::Matrix
380 */
381double MatrixContainer::FindMinValue()
382{
383 double min = Matrix[0][0][0];
384 for(int i=MatrixCounter+1;i--;)
385 for(int j=RowCounter[i]+1;j--;)
386 for(int k=ColumnCounter[i];k--;)
387 if (fabs(Matrix[i][j][k]) < min)
388 min = fabs(Matrix[i][j][k]);
389 if (fabs(min) < MYEPSILON)
390 min += MYEPSILON;
391 return min;
392};
393
394/** Sets all values in the last of MatrixContainer::Matrix to \a value.
395 * \param value reset value
396 * \param skipcolumns skip initial columns
397 * \return true if successful
398 */
399bool MatrixContainer::SetLastMatrix(double value, int skipcolumns)
400{
401 for(int j=RowCounter[MatrixCounter]+1;j--;)
402 for(int k=skipcolumns;k<ColumnCounter[MatrixCounter];k++)
403 Matrix[MatrixCounter][j][k] = value;
404 return true;
405};
406
407/** Sets all values in the last of MatrixContainer::Matrix to \a value.
408 * \param **values matrix with each value (must have at least same dimensions!)
409 * \param skipcolumns skip initial columns
410 * \return true if successful
411 */
412bool MatrixContainer::SetLastMatrix(const MatrixArray &values, int skipcolumns)
413{
414 for(int j=RowCounter[MatrixCounter]+1;j--;)
415 for(int k=skipcolumns;k<ColumnCounter[MatrixCounter];k++)
416 Matrix[MatrixCounter][j][k] = values[j][k];
417 return true;
418};
419
420/** Sums the entries with each factor and put into last element of \a ***Matrix.
421 * Sums over "E"-terms to create the "F"-terms
422 * \param Matrix MatrixContainer with matrices (LevelCounter by *ColumnCounter) with all the energies.
423 * \param KeySets KeySetContainer with bond Order and association mapping of each fragment to an order
424 * \param Order bond order
425 * \return true if summing was successful
426 */
427bool MatrixContainer::SumSubManyBodyTerms(class MatrixContainer &MatrixValues, class KeySetsContainer &KeySets, int Order)
428{
429 // go through each order
430 for (int CurrentFragment=0;CurrentFragment<KeySets.FragmentsPerOrder[Order];CurrentFragment++) {
431 //LOG(0, "Current Fragment is " << CurrentFragment << "/" << KeySets.OrderSet[Order][CurrentFragment] << ".");
432 // then go per order through each suborder and pick together all the terms that contain this fragment
433 for(int SubOrder=0;SubOrder<=Order;SubOrder++) { // go through all suborders up to the desired order
434 for (int j=0;j<KeySets.FragmentsPerOrder[SubOrder];j++) { // go through all possible fragments of size suborder
435 if (KeySets.Contains(KeySets.OrderSet[Order][CurrentFragment], KeySets.OrderSet[SubOrder][j])) {
436 //LOG(0, "Current other fragment is " << j << "/" << KeySets.OrderSet[SubOrder][j] << ".");
437 // if the fragment's indices are all in the current fragment
438 for(int k=0;k<RowCounter[ KeySets.OrderSet[SubOrder][j] ];k++) { // go through all atoms in this fragment
439 int m = MatrixValues.Indices[ KeySets.OrderSet[SubOrder][j] ][k];
440 //LOG(0, "Current index is " << k << "/" << m << ".");
441 if (m != -1) { // if it's not an added hydrogen
442 for (int l=0;l<RowCounter[ KeySets.OrderSet[Order][CurrentFragment] ];l++) { // look for the corresponding index in the current fragment
443 //LOG(0, "Comparing " << m << " with " << MatrixValues.Indices[ KeySets.OrderSet[Order][CurrentFragment] ][l] << ".");
444 if (m == MatrixValues.Indices[ KeySets.OrderSet[Order][CurrentFragment] ][l]) {
445 m = l;
446 break;
447 }
448 }
449 //LOG(0, "Corresponding index in CurrentFragment is " << m << ".");
450 if (m > RowCounter[ KeySets.OrderSet[Order][CurrentFragment] ]) {
451 ELOG(0, "In fragment No. " << KeySets.OrderSet[Order][CurrentFragment] << " current force index " << m << " is greater than " << RowCounter[ KeySets.OrderSet[Order][CurrentFragment] ] << "!");
452 performCriticalExit();
453 return false;
454 }
455 if (Order == SubOrder) { // equal order is always copy from Energies
456 for(int l=ColumnCounter[ KeySets.OrderSet[SubOrder][j] ];l--;) // then adds/subtract each column
457 Matrix[ KeySets.OrderSet[Order][CurrentFragment] ][m][l] += MatrixValues.Matrix[ KeySets.OrderSet[SubOrder][j] ][k][l];
458 } else {
459 for(int l=ColumnCounter[ KeySets.OrderSet[SubOrder][j] ];l--;)
460 Matrix[ KeySets.OrderSet[Order][CurrentFragment] ][m][l] -= Matrix[ KeySets.OrderSet[SubOrder][j] ][k][l];
461 }
462 }
463 //if ((ColumnCounter[ KeySets.OrderSet[SubOrder][j] ]>1) && (RowCounter[0]-1 >= 1))
464 //LOG(0, "Fragments[ KeySets.OrderSet[" << Order << "][" << CurrentFragment << "]=" << KeySets.OrderSet[Order][CurrentFragment] << " ][" << RowCounter[0]-1 << "][" << 1 << "] = " << Matrix[ KeySets.OrderSet[Order][CurrentFragment] ][RowCounter[0]-1][1]);
465 }
466 } else {
467 //LOG(0, "Fragment " << KeySets.OrderSet[SubOrder][j] << " is not contained in fragment " << KeySets.OrderSet[Order][CurrentFragment] << ".");
468 }
469 }
470 }
471 //LOG(0, "Final Fragments[ KeySets.OrderSet[" << Order << "][" << CurrentFragment << "]=" << KeySets.OrderSet[Order][CurrentFragment] << " ][" << KeySets.AtomCounter[0]-1 << "][" << 1 << "] = " << Matrix[ KeySets.OrderSet[Order][CurrentFragment] ][KeySets.AtomCounter[0]-1][1]);
472 }
473
474 return true;
475};
476
477/** Writes the summed total fragment terms \f$F_{ij}\f$ to file.
478 * \param *name inputdir
479 * \param *prefix prefix before \a EnergySuffix
480 * \return file was written
481 */
482bool MatrixContainer::WriteTotalFragments(const std::string name, const std::string prefix)
483{
484 ofstream output;
485 char *FragmentNumber = NULL;
486
487 LOG(1, "STATUS: Writing fragment files.");
488 for(int i=0;i<MatrixCounter;i++) {
489 stringstream line;
490 FragmentNumber = FixedDigitNumber(MatrixCounter, i);
491 line << name << FRAGMENTPREFIX << FragmentNumber << "/" << prefix;
492 delete[](FragmentNumber);
493 output.open(line.str().c_str(), ios::out);
494 if (output == NULL) {
495 ELOG(0, "MatrixContainer::WriteTotalFragments: Unable to open output energy file " << line.str() << "!");
496 performCriticalExit();
497 return false;
498 }
499 output << Header[i] << endl;
500 for(int j=0;j<RowCounter[i];j++) {
501 for(int k=0;k<ColumnCounter[i];k++)
502 output << scientific << Matrix[i][j][k] << "\t";
503 output << endl;
504 }
505 output.close();
506 }
507 return true;
508};
509
510/** Writes the summed total values in the last matrix to file.
511 * \param *name inputdir
512 * \param *prefix prefix
513 * \param *suffix suffix
514 * \return file was written
515 */
516bool MatrixContainer::WriteLastMatrix(const std::string name, const std::string prefix, const std::string suffix)
517{
518 ofstream output;
519 stringstream line;
520
521 LOG(1, "STATUS: Writing matrix values of " << suffix << ".");
522 line << name << prefix << suffix;
523 output.open(line.str().c_str(), ios::out);
524 if (output == NULL) {
525 ELOG(0, "MatrixContainer::WriteLastMatrix: Unable to open output matrix file " << line.str() << "!");
526 performCriticalExit();
527 return false;
528 }
529 output << Header[MatrixCounter] << endl;
530 for(int j=0;j<RowCounter[MatrixCounter];j++) {
531 for(int k=0;k<ColumnCounter[MatrixCounter];k++)
532 output << scientific << Matrix[MatrixCounter][j][k] << "\t";
533 output << endl;
534 }
535 output.close();
536 return true;
537};
538
539/** Comparison operator for class MatrixContainer.
540 *
541 * @param other instance to compare to
542 * @return true - both instances are the same in each member variable.
543 */
544bool MatrixContainer::operator==(const MatrixContainer &other) const
545{
546 // compare matrices
547 if (Matrix != other.Matrix)
548 return false;
549 // compare Indices
550 if (Indices != other.Indices)
551 return false;
552 // compare Headers
553 if (Header != other.Header)
554 return false;
555 // compare MatrixCounter
556 if (MatrixCounter != other.MatrixCounter)
557 return false;
558 // compare RowCounter
559 if (RowCounter != other.RowCounter)
560 return false;
561 // compare ColumnCounter
562 if (ColumnCounter != other.ColumnCounter)
563 return false;
564 return true;
565}
566
567std::ostream & operator << (std::ostream &ost, const MatrixContainer &m)
568{
569 for (int i=0;i<=m.MatrixCounter;++i) {
570 ost << "Matrix " << i << " in MatrixContainer:" << std::endl;
571 for (int j=0;j<=m.RowCounter[i];++j) {
572 for (int k=0;k<m.ColumnCounter[i];++k) {
573 ost << m.Matrix[i][j][k] << " ";
574 }
575 ost << std::endl;
576 }
577 }
578 ost << std::endl;
579 return ost;
580}
581
Note: See TracBrowser for help on using the repository browser.