Macaulay2 Engine
Loading...
Searching...
No Matches
BasicPolyListParser.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <fstream>
5
6std::string readEntireFile(const std::string &fileName)
7{
8 std::ifstream ifs(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
9
10 std::ifstream::pos_type fileSize = ifs.tellg();
11 ifs.seekg(0, std::ios::beg);
12
13 std::vector<char> bytes(fileSize);
14 ifs.read(bytes.data(), fileSize);
15
16 return std::string(bytes.data(), fileSize);
17}
18
19// TODO: also remove initial white space on the line.
20std::string_view next_line(std::string_view& str)
21// modifies str (removes first line and \n\r chars), and returns first line as a string
22{
23 long last = -1;
24 long i = 0;
25 for (; i < str.size(); ++i)
26 {
27 char c = str[i];
28 if (c == '\r' or c == '\n')
29 {
30 last = i;
31 break;
32 }
33 }
34 std::string_view result = str.substr(0, last);
35 str = str.substr(last+1);
36 return result;
37}
38
39// TODO: check for overflow
40// TODO: make a readCoefficient function
41// it should be able to read arbitrary precision ints too...
42// also maybe a set of variables for the coefficient ring
43// and allow e.g.: (3*a+2)*x^2*y^3
44long readInteger_long(const std::string_view& str, size_t& begin_loc, size_t end_loc)
45{
46 // if str[0] is a digit, find the value, and increment str past the number.
47 // if it is not: return 1, leave str unchanged.
48 if (not isdigit(str[begin_loc])) return 1;
49 long result = 0;
50 size_t loc = begin_loc;
51 while (loc < end_loc and isdigit(str[loc]))
52 {
53 result = 10 * result + (str[loc] - '0');
54 loc++;
55 }
56
57 begin_loc = loc;
58 return result;
59}
60
61// allocates memory to (and inits) an __mpz_struct
62// void readInteger_mpz_t(mpz_t& result, const std::string_view& str, size_t& begin_loc, size_t end_loc)
63// {
64// // if str[0] is a digit, find the value, and increment str past the number.
65// // if it is not: return 1, leave str unchanged.
66// if (not isdigit(str[begin_loc])) return mpz_set_ui(result,1);
67// mpz_set_ui(result, 0);
68// size_t loc = begin_loc;
69// while (loc < end_loc and isdigit(str[loc]))
70// {
71// mpz_mul_ui(result, result, 10);
72// mpz_add_ui(result, result, (str[loc] - '0'));
73// loc++;
74// }
75// begin_loc = loc;
76// }
77
78mpz_class readInteger_mpz_class(const std::string_view& str, size_t& begin_loc, size_t end_loc)
79{
80 // if str[0] is a digit, find the value, and increment str past the number.
81 // if it is not: return 1, leave str unchanged.
82 mpz_class result;
83 if (not isdigit(str[begin_loc])) return result = 1;
84 result = 0;
85 size_t loc = begin_loc;
86 while (loc < end_loc and isdigit(str[loc]))
87 {
88 result *= 10;
89 result += str[loc] - '0';
90 loc++;
91 }
92 begin_loc = loc;
93 return result;
94}
95
96int readIdentifier(const std::string_view& str, const IdentifierHash& map, size_t& begin_loc, size_t end_loc)
97{
98 /*
99 std::cout << str << "(begin=" << begin_loc << ", end=" << end_loc << " )" << std::endl;
100 */
101 // if str[0] is a character, find the identifier, and increment str past that,
102 if (begin_loc >= end_loc or not isalpha(str[begin_loc])) return -1; // TODO: throw an error here?
103 size_t loc = begin_loc;
104 while (loc < end_loc and (isdigit(str[loc]) or isalpha(str[loc]) or str[loc] == '_'))
105 {
106 loc++;
107 }
108 std::string_view iden = str.substr(begin_loc, loc-begin_loc);
109 begin_loc = loc;
110 return map.find(iden);
111}
112
113std::vector<std::string> readIdentifierList(const std::string_view line)
114{
115 std::vector<std::string> result;
116 for (auto i = 0; i < line.size(); ++i)
117 {
118 char c = line[i];
119 if (not isalpha(c)) continue; // possibly should give an error if we see a number? or non-identifieer start char?
120 auto loc = i+1;
121 while (loc < line.size() and (isalpha(line[loc]) or isdigit(line[loc]) or line[loc] == '_'))
122 {
123 loc++;
124 }
125 std::string iden {line.substr(i, loc-i)};
126 result.push_back(iden);
127 }
128 return result;
129}
130
131// This function reads in a polynomial with (signed?) integer coefficients (but limited to size 2^31-1)
132// A parse error results in a thrown error with an indication of the error (and which line, character in the string).
133// TODO: throwing the error: not done
134// TODO: keep track of line, positioninline.
135// TODO: check for errors!
136// TODO: ignore white space
137void parseBasicPoly(const std::string_view& str, const IdentifierHash& idenHash, BasicPoly& result)
138{
139 size_t begin_loc = 0;
140 size_t end_loc = str.size();
141
142 result.clear();
143
144 if (end_loc > begin_loc and str[begin_loc] == '[')
145 {
146 ++begin_loc;
147 }
148 while (end_loc > begin_loc and str[end_loc-1] == ' ') --end_loc;
149 if (end_loc > begin_loc and str[end_loc-1] == ',') --end_loc;
150 if (end_loc > begin_loc and str[end_loc-1] == ':') --end_loc;
151 if (end_loc > begin_loc and str[end_loc-1] == ']') --end_loc;
152
153 if (begin_loc == end_loc) return; // result is already set to 0.
154
155 while (end_loc > begin_loc)
156 {
157 int sign = 1;
158
159 // Read the next term into `result`.
160 if (str[begin_loc] == '+')
161 {
162 ++begin_loc;
163 }
164 // TODO: do not want +- ...
165 if (str[begin_loc] == '-')
166 {
167 ++begin_loc;
168 sign = -1;
169 }
170 mpz_class coeff{readInteger_mpz_class(str, begin_loc, end_loc)}; // defaults to 1 if no integer present.
171
172 if (sign == -1) coeff = -coeff;
173 result.mCoefficients.push_back(coeff); // do not clear(coeff) !
174
175 // Now we read the monomial part.
176 long loc = result.mMonomials.size(); // this is where the length field will go.
177 result.mMonomials.push_back(1); // 1 means that the monomial is `1`.
178
179 // We expect the first character to be an identifier char.
180 // then right after that a `*` or `^'.
181 // If we get to "+", or "-" or end of string: we set result.mMonomials[loc] to the correct size.
182 while (end_loc > begin_loc)
183 {
184 char c = str[begin_loc];
185 if (c == '-' or c == '+')
186 break; // on to the next term
187 if (c == '*')
188 {
189 ++begin_loc;
190 if (begin_loc == end_loc)
191 {
192 throw parsing_error("line ends after a *");
193 // throw an error
194 }
195 c = str[begin_loc];
196 }
197
198 if (not isalpha(c))
199 // not well forrmed, I think.
200 {
201 throw parsing_error("expected an identifier at position " + std::to_string(begin_loc));
202 }
203 // TODO: in fact, throw an error here
204 auto prev_loc = begin_loc;
205 int v = readIdentifier(str, idenHash, begin_loc, end_loc);
206 if (v == -1)
207 {
208 throw parsing_error("expected a variable name at position " + std::to_string(prev_loc));
209 }
210 // TODO: if the identifier is not found, throw an error.
211 int e = 1;
212 if (end_loc > begin_loc and str[begin_loc] == '^')
213 {
214 ++begin_loc;
215 // if not a digit, throw an error. Note: here we are currently assuming positive exponents.
216 if (begin_loc >= end_loc or not std::isdigit(str[begin_loc]))
217 {
218 throw parsing_error("expected a digit at position " + std::to_string(begin_loc));
219 }
220 e = readInteger_long(str, begin_loc, end_loc);
221 }
222 // if exponent is zero, don't add anything to monomial.
223 if (e != 0)
224 {
225 result.mMonomials.push_back(v);
226 result.mMonomials.push_back(e);
227 result.mMonomials[loc] += 2;
228 }
229 }
230 }
231}
232
233BasicPoly parseBasicPoly(std::string poly, std::vector<std::string> varnames)
234{
235 std::string_view str { poly};
236 IdentifierHash idenMap {varnames};
238 parseBasicPoly(str, idenMap, result);
239 return result;
240}
241
242BasicPolyList parseBasicPolyListFromString(std::string contents, const IdentifierHash& idenMap)
243// The string should contain a polynomial per line, although lines starting with # are ignored.
244{
245 std::string_view fileView { contents };
246 BasicPolyList Fs;
247 while (fileView.size() > 0)
248 {
249 std::string_view thisline = next_line(fileView);
250
251 if (thisline.size() == 0 or thisline[0] == '#')
252 {
253 continue;
254 }
255
256 BasicPoly F;
257 parseBasicPoly(thisline, idenMap, F);
258 Fs.push_back(F);
259 }
260 return Fs;
261}
262
263BasicPolyList parseBasicPolyListFromString(std::string contents, std::vector<std::string> varnames)
264// The string should contain a polynomial per line, although lines starting with # are ignored.
265{
266 IdentifierHash idenMap {varnames};
267 return parseBasicPolyListFromString(contents, idenMap);
268}
269
271// MSolve specific functions //
273bool lineContainsVars(std::string_view& line) // if returns true, line now contains the part of the line with the variable names.
274{
275 std::string varHeader {"#variable order:"};
276 if (line.compare(0, varHeader.size(), varHeader) != 0)
277 return false;
278 line.remove_prefix(varHeader.size());
279 return true;
280}
281
283{
284 // Read in file
285 // Read in enough of the header to get identifiers
286
287 IdentifierHash idenMap;
288 std::string_view fileView { contents };
289
290 BasicPolyList Fs;
291 while (fileView.size() > 0)
292 {
293 std::string_view thisline = next_line(fileView);
294
295 if (lineContainsVars(thisline))
296 {
297 std::vector<std::string> idenList = readIdentifierList(thisline);
298 /*
299 std::cout << "-- idenList" << std::endl;
300 for (auto& id : idenList)
301 std::cout << id << std::endl;
302 */
303 idenMap = { idenList };
304 continue;
305 }
306
307 if (thisline.size() == 0 or thisline[0] == '#' or thisline[0] == ']')
308 {
309 continue;
310 }
311
312 BasicPoly F;
313 parseBasicPoly(thisline, idenMap, F);
314 Fs.push_back(F);
315 }
316 return Fs;
317}
318
319BasicPolyList parseMsolveFile(std::string filename)
320{
321 std::string fileContents { readEntireFile(filename) };
322 return parseMsolveFromString(fileContents);
323}
324
325// TODO:
326// readMSolveHeader: returns vector of strings, characteristic, and monomial order, and number of polynomials.
327// input format: first line is list of variables
328// second line is characteristic
329// what about monomial order? (is that done in file or on command line?)
330// parsing: should give errors, not infinite loops!
331
332// BasicPolyList: should have a memoryUsed function.
333// Monoid: should return std::vector<std::string> of variable names.
334//
335
336// TODO: read sparse matrix, first line is `#rows #cols`, each line is of the form e.g. `0 5 2*x^2*y^2-3*x*y`
337// how to end it?
338// TODO: read dense matrix, first line is `#rows #cols`, each line is of the form e.g. `2*x^2*y^2-3*x*y`
339
340// Local Variables:
341// indent-tabs-mode: nil
342// End:
std::vector< BasicPoly > BasicPolyList
int readIdentifier(const std::string_view &str, const IdentifierHash &map, size_t &begin_loc, size_t end_loc)
bool lineContainsVars(std::string_view &line)
mpz_class readInteger_mpz_class(const std::string_view &str, size_t &begin_loc, size_t end_loc)
std::string_view next_line(std::string_view &str)
BasicPolyList parseMsolveFile(std::string filename)
std::string readEntireFile(const std::string &fileName)
std::vector< std::string > readIdentifierList(const std::string_view line)
void parseBasicPoly(const std::string_view &str, const IdentifierHash &idenHash, BasicPoly &result)
This version is a potentially faster alternative when reading many polynomials.
long readInteger_long(const std::string_view &str, size_t &begin_loc, size_t end_loc)
BasicPolyList parseMsolveFromString(std::string contents)
BasicPolyList parseBasicPolyListFromString(std::string contents, const IdentifierHash &idenMap)
Parsers from text (string or file) into a BasicPolyList, including the Msolve input format.
Standalone, self-contained polynomial representation independent of any engine Ring — coefficients ar...
Definition BasicPoly.hpp:64
auto find(std::string_view s) const -> int
IdentifierHash: used to facilitate parsing of polynomials from strings and files.
VALGRIND_MAKE_MEM_DEFINED & result(result)