1 /* ========================================================================== */
2 /* === Source/Mongoose_IO.cpp =============================================== */
3 /* ========================================================================== */
4 
5 /* -----------------------------------------------------------------------------
6  * Mongoose Graph Partitioning Library  Copyright (C) 2017-2018,
7  * Scott P. Kolodziej, Nuri S. Yeralan, Timothy A. Davis, William W. Hager
8  * Mongoose is licensed under Version 3 of the GNU General Public License.
9  * Mongoose is also available under other licenses; contact authors for details.
10  * -------------------------------------------------------------------------- */
11 
12 /**
13  * Simplified I/O functions for reading matrices and graphs
14  *
15  * For reading Matrix Market files into Mongoose, read_graph and read_matrix
16  * are provided (depending on if a Graph class instance or CSparse matrix
17  * instance is needed). The filename can be specified as either a const char*
18  * (easier for C programmers) or std::string (easier from C++).
19  */
20 
21 #include "Mongoose_IO.hpp"
22 #include "Mongoose_Internal.hpp"
23 #include "Mongoose_Logger.hpp"
24 #include "Mongoose_Sanitize.hpp"
25 #include <iostream>
26 
27 using namespace std;
28 
29 namespace Mongoose
30 {
31 
read_graph(const std::string & filename)32 Graph *read_graph(const std::string &filename)
33 {
34     return read_graph(filename.c_str());
35 }
36 
read_matrix(const std::string & filename,MM_typecode & matcode)37 cs *read_matrix(const std::string &filename, MM_typecode &matcode)
38 {
39     return read_matrix(filename.c_str(), matcode);
40 }
41 
read_graph(const char * filename)42 Graph *read_graph(const char *filename)
43 {
44     Logger::tic(IOTiming);
45     LogInfo("Reading graph from file " << std::string(filename) << "\n");
46 
47     MM_typecode matcode;
48     cs *A = read_matrix(filename, matcode);
49     if (!A)
50     {
51         LogError("Error reading matrix from file\n");
52         return NULL;
53     }
54     cs *sanitized_A = sanitizeMatrix(A, mm_is_symmetric(matcode), false);
55     cs_spfree(A);
56     if (!sanitized_A)
57         return NULL;
58 
59     Graph *G = Graph::create(sanitized_A, true);
60 
61     if (!G)
62     {
63         LogError("Ran out of memory in Mongoose::read_graph\n");
64         cs_spfree(sanitized_A);
65         Logger::toc(IOTiming);
66         return NULL;
67     }
68 
69     sanitized_A->p = NULL;
70     sanitized_A->i = NULL;
71     sanitized_A->x = NULL;
72     cs_spfree(sanitized_A);
73 
74     Logger::toc(IOTiming);
75 
76     return G;
77 }
78 
read_matrix(const char * filename,MM_typecode & matcode)79 cs *read_matrix(const char *filename, MM_typecode &matcode)
80 {
81     LogInfo("Reading Matrix from " << std::string(filename) << "\n");
82     FILE *file = fopen(filename, "r");
83     if (!file)
84     {
85         LogError("Error: Cannot read file " << std::string(filename) << "\n");
86         return NULL;
87     }
88 
89     LogInfo("Reading Matrix Market banner...");
90     if (mm_read_banner(file, &matcode) != 0)
91     {
92         LogError("Error: Could not process Matrix Market banner\n");
93         fclose(file);
94         return NULL;
95     }
96     if (!mm_is_matrix(matcode) || !mm_is_sparse(matcode)
97         || mm_is_complex(matcode))
98     {
99         LogError(
100             "Error: Unsupported matrix format - Must be real and sparse\n");
101         fclose(file);
102         return NULL;
103     }
104 
105     Int M, N, nz;
106     if ((mm_read_mtx_crd_size(file, &M, &N, &nz)) != 0)
107     {
108         LogError("Error: Could not parse matrix dimension and size.\n");
109         fclose(file);
110         return NULL;
111     }
112     if (M != N)
113     {
114         LogError("Error: Matrix must be square.\n");
115         fclose(file);
116         return NULL;
117     }
118 
119     LogInfo("Reading matrix data...\n");
120     Int *I = (Int *)SuiteSparse_malloc(static_cast<size_t>(nz), sizeof(Int));
121     Int *J = (Int *)SuiteSparse_malloc(static_cast<size_t>(nz), sizeof(Int));
122     double *val
123         = (double *)SuiteSparse_malloc(static_cast<size_t>(nz), sizeof(double));
124 
125     if (!I || !J || !val)
126     {
127         LogError("Error: Ran out of memory in Mongoose::read_matrix\n");
128         SuiteSparse_free(I);
129         SuiteSparse_free(J);
130         SuiteSparse_free(val);
131         fclose(file);
132         return NULL;
133     }
134 
135     mm_read_mtx_crd_data(file, M, N, nz, I, J, val, matcode);
136     fclose(file); // Close the file
137 
138     for (Int k = 0; k < nz; k++)
139     {
140         --I[k];
141         --J[k];
142         if (mm_is_pattern(matcode))
143             val[k] = 1;
144     }
145 
146     cs *A = (cs *)SuiteSparse_malloc(1, sizeof(cs));
147     if (!A)
148     {
149         LogError("Error: Ran out of memory in Mongoose::read_matrix\n");
150         SuiteSparse_free(I);
151         SuiteSparse_free(J);
152         SuiteSparse_free(val);
153         return NULL;
154     }
155 
156     A->nzmax = nz;
157     A->m     = M;
158     A->n     = N;
159     A->p     = J;
160     A->i     = I;
161     A->x     = val;
162     A->nz    = nz;
163 
164     LogInfo("Compressing matrix from triplet to CSC format...\n");
165     cs *compressed_A = cs_compress(A);
166     cs_spfree(A);
167     if (!compressed_A)
168     {
169         LogError("Error: Ran out of memory in Mongoose::read_matrix\n");
170         return NULL;
171     }
172 
173     return compressed_A;
174 }
175 
176 } // end namespace Mongoose
177