A toolkit for working with phylogenetic data.
v0.20.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
utils/containers/matrix/writer.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_CONTAINERS_MATRIX_WRITER_H_
2 #define GENESIS_UTILS_CONTAINERS_MATRIX_WRITER_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2018 Lucas Czech and HITS gGmbH
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@h-its.org>
23  Exelixis Lab, Heidelberg Institute for Theoretical Studies
24  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
25 */
26 
37 
38 #include <cassert>
39 #include <functional>
40 #include <stdexcept>
41 #include <sstream>
42 #include <string>
43 #include <vector>
44 
45 namespace genesis {
46 namespace utils {
47 
48 // =================================================================================================
49 // MatrixWriter
50 // =================================================================================================
51 
52 template <typename T>
54 {
55 public:
56 
57  // -------------------------------------------------------------
58  // Typedefs and Enums
59  // -------------------------------------------------------------
60 
61  enum class Format
62  {
63  kMatrix,
64  kList,
66  };
67 
68  // -------------------------------------------------------------
69  // Constructors and Rule of Five
70  // -------------------------------------------------------------
71 
72  MatrixWriter() = default;
73  ~MatrixWriter() = default;
74 
75  MatrixWriter(MatrixWriter const&) = default;
76  MatrixWriter(MatrixWriter&&) = default;
77 
78  MatrixWriter& operator= (MatrixWriter const&) = default;
79  MatrixWriter& operator= (MatrixWriter&&) = default;
80 
81  // -------------------------------------------------------------
82  // Reading
83  // -------------------------------------------------------------
84 
85  void to_stream(
86  Matrix<T> const& mat,
87  std::ostream& os,
88  std::vector<std::string> const& row_names = {},
89  std::vector<std::string> const& col_names = {},
90  std::string const& corner = ""
91  ) const {
92  to_stream_( mat, os, row_names, col_names, corner );
93  }
94 
95  void to_file(
96  Matrix<T> const& mat,
97  std::string const& fn,
98  std::vector<std::string> const& row_names = {},
99  std::vector<std::string> const& col_names = {},
100  std::string const& corner = ""
101  ) const {
102  std::ofstream ofs;
103  utils::file_output_stream( fn, ofs );
104  to_stream_( mat, ofs, row_names, col_names, corner );
105  }
106 
107  std::string to_string(
108  Matrix<T> const& mat,
109  std::vector<std::string> const& row_names = {},
110  std::vector<std::string> const& col_names = {},
111  std::string const& corner = ""
112  ) const {
113  std::ostringstream oss;
114  to_stream_( mat, oss, row_names, col_names, corner );
115  return oss.str();
116  }
117 
118  // -------------------------------------------------------------
119  // Properties
120  // -------------------------------------------------------------
121 
122  std::string const& separator_string() const
123  {
124  return separator_;
125  }
126 
127  MatrixWriter& separator_string( std::string const& value )
128  {
129  separator_ = value;
130  return *this;
131  }
132 
133  Format format() const
134  {
135  return format_;
136  }
137 
139  {
140  format_ = value;
141  return *this;
142  }
143 
144  MatrixWriter& write_value_functor( std::function<std::string( T const& )> functor )
145  {
146  write_value_ = functor;
147  }
148 
149  // -------------------------------------------------------------
150  // Internal Functions
151  // -------------------------------------------------------------
152 
153 private:
154 
155  void to_stream_(
156  Matrix<T> const& mat,
157  std::ostream& os,
158  std::vector<std::string> const& row_names,
159  std::vector<std::string> const& col_names,
160  std::string const& corner
161  ) const {
162 
163  // Checks.
164  if( ! row_names.empty() && row_names.size() != mat.rows() ) {
165  throw std::invalid_argument( "Number of row names is different from Matrix row size." );
166  }
167  if( ! col_names.empty() && col_names.size() != mat.cols() ) {
168  throw std::invalid_argument( "Number of col names is different from Matrix col size." );
169  }
170 
171  // Format switch
172  switch( format_ ) {
173  case Format::kMatrix: {
174  to_matrix_( mat, os, row_names, col_names, corner );
175  break;
176  }
177  case Format::kList: {
178  to_list_( mat, os, row_names, col_names );
179  break;
180  }
181  case Format::kTriangular: {
182  to_triangular_( mat, os, row_names, col_names, corner );
183  break;
184  }
185  default: {
186  throw std::invalid_argument( "Invalid enum value for MatrixWriter::Format" );
187  }
188  }
189  }
190 
191  void to_matrix_(
192  Matrix<T> const& mat,
193  std::ostream& os,
194  std::vector<std::string> const& row_names,
195  std::vector<std::string> const& col_names,
196  std::string const& corner
197  ) const {
198 
199  // Write top corner cell if needed.
200  if( ! row_names.empty() && ! col_names.empty() ) {
201  os << corner << separator_;
202  }
203 
204  // Write col names.
205  if( ! col_names.empty() ) {
206  for( size_t c = 0; c < col_names.size(); ++c ) {
207  if( c > 0 ) {
208  os << separator_;
209  }
210  os << col_names[c];
211  }
212  os << "\n";
213  }
214 
215  // Write lines.
216  for( size_t r = 0; r < mat.rows(); ++r ) {
217  if( ! row_names.empty() ) {
218  os << row_names[r] << separator_;
219  }
220 
221  for( size_t c = 0; c < mat.cols(); ++c ) {
222  if( c > 0 ) {
223  os << separator_;
224  }
225  if( write_value_ ) {
226  os << write_value_( mat( r, c ));
227  } else {
228  os << mat( r, c );
229  }
230  }
231 
232  os << "\n";
233  }
234  }
235 
236  void to_list_(
237  Matrix<T> const& mat,
238  std::ostream& os,
239  std::vector<std::string> const& row_names,
240  std::vector<std::string> const& col_names
241  ) const {
242 
243  // Simple: one line per cell
244  for( size_t r = 0; r < mat.rows(); ++r ) {
245  for( size_t c = 0; c < mat.cols(); ++c ) {
246  if( ! row_names.empty() ) {
247  os << row_names[r] << separator_;
248  }
249  if( ! col_names.empty() ) {
250  os << col_names[c] << separator_;
251  }
252  os << mat( r, c );
253  os << "\n";
254  }
255  }
256  }
257 
258  void to_triangular_(
259  Matrix<T> const& mat,
260  std::ostream& os,
261  std::vector<std::string> const& row_names,
262  std::vector<std::string> const& col_names,
263  std::string const& corner
264  ) const {
265 
266  // Check
267  if( mat.rows() != mat.cols() ) {
268  throw std::invalid_argument( "Cannot write triangular matrix, as it is not quadratic." );
269  }
270 
271  // Write top corner cell if needed.
272  if( ! row_names.empty() && ! col_names.empty() ) {
273  os << corner << separator_;
274  }
275 
276  // Write col names backwards.
277  if( ! col_names.empty() ) {
278  for( size_t cb = 0; cb < col_names.size(); ++cb ) {
279  auto const c = col_names.size() - cb - 1;
280  if( cb > 0 ) {
281  os << separator_;
282  }
283  os << col_names[c];
284  }
285  os << "\n";
286  }
287 
288  // Write lines, with backwards columns to get a nice looking triangluar matrix.
289  for( size_t r = 0; r < mat.rows(); ++r ) {
290  if( ! row_names.empty() ) {
291  os << row_names[r] << separator_;
292  }
293 
294  // Write the trinangular columns, starting at col = row
295  for( size_t cb = 0; cb < mat.cols() - r; ++cb ) {
296  auto const c = mat.cols() - cb - 1;
297  assert( c < mat.cols() );
298 
299  if( cb > 0 ) {
300  os << separator_;
301  }
302  if( write_value_ ) {
303  os << write_value_( mat( r, c ));
304  } else {
305  os << mat( r, c );
306  }
307  }
308 
309  os << "\n";
310  }
311  }
312 
313  // -------------------------------------------------------------
314  // Data Members
315  // -------------------------------------------------------------
316 
317 private:
318 
319  std::string separator_ = "\t";
320  Format format_ = Format::kMatrix;
321 
322  std::function<std::string( T const& )> write_value_;
323 
324 };
325 
326 } // namespace utils
327 } // namespace genesis
328 
329 #endif // include guard
MatrixWriter & write_value_functor(std::function< std::string(T const &)> functor)
void file_output_stream(std::string const &filename, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out)
Helper function to obtain an output stream to a file.
Provides some valuable additions to STD.
MatrixWriter & operator=(MatrixWriter const &)=default
MatrixWriter & separator_string(std::string const &value)
std::string const & separator_string() const
void to_file(Matrix< T > const &mat, std::string const &fn, std::vector< std::string > const &row_names={}, std::vector< std::string > const &col_names={}, std::string const &corner="") const
std::string to_string(Matrix< T > const &mat, std::vector< std::string > const &row_names={}, std::vector< std::string > const &col_names={}, std::string const &corner="") const
void to_stream(Matrix< T > const &mat, std::ostream &os, std::vector< std::string > const &row_names={}, std::vector< std::string > const &col_names={}, std::string const &corner="") const