1 /* Copyright (C) FFLAS-FFPACK 2017
2  * written by Clement Pernet (clement.pernet@univ-grenoble-alpes.fr)
3  * ========LICENCE========
4  * This file is part of the library FFLAS-FFPACK.
5  *
6  * FFLAS-FFPACK is free software: you can redistribute it and/or modify
7  * it under the terms of the  GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  * ========LICENCE========
20  */
21 
22 #ifndef __FFLAS_IO_H
23 #define __FFLAS_IO_H
24 
25 #include <cstring>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <fstream>
29 
30 namespace FFLAS{
31 
32     enum FFLAS_FORMAT {
33         FflasAuto     = 0, // Automated detection of the format
34         FflasDense    = 1, // Dense format (Array)
35         FflasSMS      = 2, // Sparse Matrix format (Matrix Market)
36         FflasBinary   = 3, // Binary format
37         FflasMath     = 4, // Standard math. notation
38         FflasMaple    = 5, // Maple input
39         FflasSageMath = 6  // SageMath input
40     };
41 
42     template<class Field>
43     std::ostream& WriteMatrix (std::ostream& c, const Field& F, size_t m, size_t n,
44                                typename Field::ConstElement_ptr A, size_t lda,
45                                FFLAS_FORMAT format = FflasMath,
46                                bool column_major=false);
47 }
48 
49 #include "fflas-ffpack/fflas/fflas.h"
50 #include "fflas_memory.h"
51 
52 // Reading and writing matrices over field
53 
54 namespace FFLAS{
55 
preamble(std::ifstream & ifs,FFLAS_FORMAT & format)56     inline void preamble(std::ifstream&ifs, FFLAS_FORMAT& format){
57         char st[9] = {0};
58         ifs.read(st, 8);
59         if (!strcmp(st,"FFBinFmt")){
60             format = FflasBinary;
61         }else{
62             // No detection of non-binary formats for the moment
63             format = FflasSMS;
64         }
65         ifs.seekg(0, std::ios::beg);
66         return;
67     }
68 
69     /**
70      * @brief ReadMatrix: read a matrix from an input stream
71      * @param ifs: input stream
72      * @param F: base field
73      * @param [out] m: row dimension
74      * @param [out] n: column dimension
75      * @param [out] A: output matrix
76      * @param format: input format (FflasAuto, FflasDense, FflasSMS, FflasBinary)
77      */
78     template<class Field>
79     typename Field::Element_ptr
80     ReadMatrix (std::ifstream& ifs, Field& F, size_t& m, size_t& n,
81                 typename Field::Element_ptr& A, FFLAS_FORMAT format = FflasAuto){
82 
83         FFLAS_FORMAT form = format;
84 
85         if (form == FflasAuto){
86             // Preamble analysis. Update form to the discovered format.
87             preamble(ifs, form);
88         }
89 
90         switch (form){
91         case FflasDense:{
92                             ifs >> m;
93                             ifs >> n;
94                             A = fflas_new(F, m,n);
95                             for (size_t i=0; i<m*n; i++){
96                                 F.read (ifs, A[i]);
97                             }
98                             break;
99                         }
100         case FflasSMS:{
101                           // Ignore comments (starting with %)
102                           while (ifs.peek() == '%') {
103                               ifs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
104                           }
105 
106                           ifs >> m >> n;
107                           size_t i,j;
108                           std::string tmp;
109                           typename Field::Element val;
110                           ifs >> tmp;
111                           A = fflas_new(F, m,n);
112                           fzero(F,m,n,A,n);
113                           do{
114                               ifs >> i >> j;
115                               if (i>m || j>n){
116                                   std::cerr<<"Matrix file does not respect the SMS format"<<std::endl;
117                                   return NULL;
118                               }
119                               F.read (ifs, val);
120                               if (i>0 && i>0) F.assign (A [(i-1)*n+j-1], val);
121                           } while (!(i==0 && j==0 && F.isZero(val)));
122                           break;
123                       }
124         case FflasBinary:{
125                              char st[9];
126                              ifs.getline(st, 9);
127                              if (strcmp (st,"FFBinFmt")){
128                                  std::cerr<<"Not a FFLAS-FFPACK binary matrix format: preamble = "<<st<<std::endl;
129                                  return NULL;
130                              }
131                              size_t mm, nn;
132                              ifs.read(reinterpret_cast<char *>(&mm), sizeof(size_t));
133                              ifs.read(reinterpret_cast<char *>(&nn), sizeof(size_t));
134                              m=mm,n=nn;
135                              A = fflas_new(F, m,n);
136                              ifs.read (reinterpret_cast<char *>(A), sizeof(typename Field::Element)*m*n);
137                              ifs.close();
138                              break;
139                          }
140         default:
141                          std::cerr<<"Unable to detect the file format"<<std::endl;
142         }
143         return A;
144     }
145 
146     /**
147      * @brief ReadMatrix: read a matrix from a file
148      * @param matrix_file: filename
149      * @param F: base field
150      * @param [out] m: row dimension
151      * @param [out] n: column dimension
152      * @param [out] A: output matrix
153      * @param format: input format (FflasAuto, FflasDense, FflasSMS, FflasBinary)
154      */
155     template<class Field>
156     inline typename Field::Element_ptr
157     ReadMatrix (const std::string& matrix_file, Field & F, size_t & m, size_t& n,
158                 typename Field::Element_ptr& A, FFLAS_FORMAT format = FflasAuto){
159 
160         std::ios_base::openmode mode = std::ios::in;
161         if (format == FflasBinary)
162             mode |= std::ifstream::binary;
163 
164         std::ifstream ifs (matrix_file, mode);
165         if (ifs.is_open()){
166             ReadMatrix (ifs, F, m, n, A, format);
167             ifs.close();
168         } else
169             std::cerr<<"Error: unable to open file "<<matrix_file<<std::endl;
170 
171         return A;
172     }
173 
174     /**
175      * @brief WriteMatrix: write a matrix to an output stream
176      * @param c: output stream
177      * @param F: base field
178      * @param m: row dimension
179      * @param n: column dimension
180      * @param A: matrix
181      * @param format: input format (FflasAuto, FflasDense, FflasSMS, FflasBinary)
182      * @param column_major: whether the matrix is stored in column or row major (row by default)
183      */
184     template<class Field>
WriteMatrix(std::ostream & c,const Field & F,size_t m,size_t n,typename Field::ConstElement_ptr A,size_t lda,FFLAS_FORMAT format,bool column_major)185     inline std::ostream& WriteMatrix (std::ostream& c, const Field& F, size_t m, size_t n,
186                                       typename Field::ConstElement_ptr A, size_t lda,
187                                       FFLAS_FORMAT format, bool column_major) {
188         switch (format){
189         case FflasSageMath:
190             c << "Matrix (";
191             if (F.characteristic() == 0)
192                 c << "ZZ, ";
193             else
194                 c << "GF("<<F.cardinality()<<"), ";
195             c << m <<", " << n << ", [" ;
196             for (size_t i = 0; i<m; ++i){
197                 c << '[';
198                 for (size_t j=0; j<n;++j){
199                     if (column_major) F.write (c, A[j*lda+i]);
200                     else F.write (c, A[i*lda+j]);
201                     if (j < n-1) c << ", ";
202                 }
203                 c << ']';
204                 if (i < m-1) c << ", ";
205             }
206             c << "])\n";
207             break;
208         case FflasMaple:
209             c << "Matrix (";
210             c << m <<", " << n << ", [" ;
211             for (size_t i = 0; i<m; ++i){
212                 c << '[';
213                 for (size_t j=0; j<n;++j){
214                     if (column_major) F.write (c, A[j*lda+i]);
215                     else F.write (c, A[i*lda+j]);
216                     if (j < n-1) c << ", ";
217                 }
218                 c << ']';
219                 if (i < m-1) c << ", ";
220             }
221             c << "]);\n";
222             break;
223         case FflasDense:
224             c<<m<<" "<<n<<std::endl;
225             for (size_t i = 0; i<m; ++i){
226                 for (size_t j=0; j<n;++j){
227                     if (column_major) F.write (c, A[j*lda+i]);
228                     else F.write (c, A[i*lda+j]);
229                     c << ' ';
230                 }
231             }
232             c<<std::endl;
233             break;
234         case FflasSMS:
235             c<<m<<' '<<n<<' '<<F.cardinality()<<std::endl;
236             for (size_t i = 0; i<m; ++i){
237                 for (size_t j=0; j<n;++j){
238                     typename Field::ConstElement_ptr x;
239                     if (column_major) x= A + j*lda+i;
240                     else x = A + i*lda +j;
241                     if (!F.isZero(*x)){
242                         c << (i+1) << ' ' << (j+1) << ' ';
243                         F.write (c, *x);
244                         c << std::endl;
245                     }
246                 }
247             }
248             c << "0 0 0"<<std::endl;
249             break;
250         case FflasBinary:{
251                              char st[9]="FFBinFmt";
252                              c.write (st, 8);
253                              c<<std::endl;
254                              c.write ( reinterpret_cast<char*> (&m), sizeof (size_t));
255                              c.write ( reinterpret_cast<char*> (&n), sizeof (size_t));
256                              c.write ( reinterpret_cast<const char*> (A), sizeof(typename Field::Element)*m*n);
257                              break;
258                          }
259         default:{ // format == FflasMath
260                     size_t char_width = ceil(FFLAS::bitsize (F,m,n,A,lda)*0.301029995663982);
261                     Givaro::Integer p;
262                     F.characteristic(p);
263                     if (p==0 || F.minElement()<0) char_width++; // minus sign
264                     c.fill(' ');
265                     for (size_t i = 0; i<m; ++i){
266                         for (size_t j=0; j<n;++j){
267                             c.width(char_width);
268                             if (column_major) F.write (c, A[j*lda+i]);
269                             else F.write (c, A[i*lda+j]);
270                             if (j < n-1) c << ' ';
271                         }
272                         c<<std::endl;
273                     }
274                 }
275         }
276         return c ;
277     }
278 
279     /**
280      * @brief WriteMatrix: write a matrix to a file
281      * @param matrix_file: file name
282      * @param F: base field
283      * @param m: row dimension
284      * @param n: column dimension
285      * @param A: matrix
286      * @param format: input format (FflasAuto, FflasDense, FflasSMS, FflasBinary)
287      * @param column_major: whether the matrix is stored in column or row major (row by default)
288      */
289     template<class Field>
290     void WriteMatrix (std::string& matrix_file, const Field& F, int m, int n,
291                       typename Field::ConstElement_ptr A, size_t lda,
292                       FFLAS_FORMAT format = FflasDense,
293                       bool column_major=false) {
294 
295         std::ios_base::openmode mode = std::ios::out;
296         if (format == FflasBinary)
297             mode |= std::ios::binary;
298 
299         std::ofstream ofs (matrix_file, mode);
300         if (ofs.is_open()){
301             WriteMatrix (ofs, F, m, n, A, lda, format, column_major);
302             ofs.close();
303         } else
304             std::cerr<<"Error: unable to open file "<<matrix_file<<std::endl;
305     }
306 
307     /**
308      * @brief WritePermutation: write a permutation matrix to an output stream
309      * @param c: output stream
310      * @param P: permutation
311      * @param N: size of the permutation
312      */
WritePermutation(std::ostream & c,const size_t * P,size_t N)313     inline std::ostream& WritePermutation (std::ostream& c, const size_t* P, size_t N){
314         c<<"[ ";
315         for (size_t i=0; i<N; ++i){
316             if (i)
317                 c<<", ";
318             c<<P[i];
319         }
320         c<<"]"<<std::endl;
321         return c;
322     }
323 
324 } //namespace FFLAS
325 
326 #endif //__FFLAS_IO_H
327 /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
328 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
329