Frobby  0.9.0
CoCoA4IOHandler.cpp
Go to the documentation of this file.
1 /* Frobby: Software for monomial ideal computations.
2  Copyright (C) 2007 Bjarke Hammersholt Roune (www.broune.com)
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see http://www.gnu.org/licenses/.
16 */
17 #include "stdinc.h"
18 #include "CoCoA4IOHandler.h"
19 
20 #include "Scanner.h"
21 #include "VarNames.h"
22 #include "Term.h"
23 #include "TermTranslator.h"
24 #include "FrobbyStringStream.h"
25 #include "DataType.h"
26 #include "IdealWriter.h"
27 #include "PolyWriter.h"
28 #include "error.h"
29 #include "InputConsumer.h"
30 
31 #include <cstdio>
32 
33 namespace IO {
34  namespace CoCoA4 {
35  void writeRing(const VarNames& names, FILE* out);
36  void writeTermProduct(const Term& term,
37  const TermTranslator& translator,
38  FILE* out);
39  void writeTermProduct(const vector<mpz_class>& term,
40  const VarNames& names,
41  FILE* out);
42  void readTerm(Scanner& in, vector<mpz_class>& term);
43  void readTerm(Scanner& in, InputConsumer& consumer);
44  void readVarPower(vector<mpz_class>& term, Scanner& in);
45  void readVarPower(Scanner& in, InputConsumer& consumer);
46  void readCoefTerm(mpz_class& coef,
47  vector<mpz_class>& term,
48  bool firstTerm,
49  Scanner& in);
50  }
51  namespace C = CoCoA4;
52 
53  class CoCoA4IdealWriter : public IdealWriter {
54  public:
55  CoCoA4IdealWriter(FILE* out): IdealWriter(out) {
56  }
57 
58  private:
59  virtual void doWriteHeader(bool first) {
61  fputs("I := Ideal(", getFile());
62  }
63 
64  virtual void doWriteTerm(const Term& term,
65  const TermTranslator& translator,
66  bool first) {
67  fputs(first ? "\n " : ",\n ", getFile());
68  C::writeTermProduct(term, translator, getFile());
69  }
70 
71  virtual void doWriteTerm(const vector<mpz_class>& term,
72  bool first) {
73  fputs(first ? "\n " : ",\n ", getFile());
75  }
76 
77  virtual void doWriteFooter(bool wasZeroIdeal) {
78  fputs("\n);\n", getFile());
79  }
80 
81  virtual void doWriteEmptyList() {
83  }
84  };
85 
86  class CoCoA4PolyWriter : public PolyWriter {
87  public:
88  CoCoA4PolyWriter(FILE* out): PolyWriter(out) {
89  }
90 
91  virtual void doWriteHeader() {
93  fputs("p :=", getFile());
94  }
95 
96  virtual void doWriteTerm(const mpz_class& coef,
97  const Term& term,
98  const TermTranslator& translator,
99  bool firstGenerator) {
100  fputs("\n ", getFile());
101 
102  if (coef >= 0 && !firstGenerator)
103  fputc('+', getFile());
104 
105  if (term.isIdentity()) {
106  gmp_fprintf(getFile(), "%Zd", coef.get_mpz_t());
107  return;
108  }
109 
110  if (coef == -1)
111  fputc('-', getFile());
112  else if (coef != 1)
113  gmp_fprintf(getFile(), "%Zd", coef.get_mpz_t());
114 
115  C::writeTermProduct(term, translator, getFile());
116  }
117 
118  virtual void doWriteTerm(const mpz_class& coef,
119  const vector<mpz_class>& term,
120  bool firstGenerator) {
121  fputs("\n ", getFile());
122  if (coef >= 0 && !firstGenerator)
123  fputc('+', getFile());
124 
125  bool isIdentity = true;
126  for (size_t var = 0; var < term.size(); ++var)
127  if (term[var] != 0)
128  isIdentity = false;
129 
130  if (isIdentity) {
131  gmp_fprintf(getFile(), "%Zd", coef.get_mpz_t());
132  return;
133  }
134 
135  if (coef == -1)
136  fputc('-', getFile());
137  else if (coef != 1)
138  gmp_fprintf(getFile(), "%Zd", coef.get_mpz_t());
139 
141  }
142 
143  virtual void doWriteFooter(bool wasZero) {
144  if (wasZero)
145  fputs("\n 0", getFile());
146  fputs(";\n", getFile());
147  }
148  };
149 
151  IOHandlerCommon(staticGetName(),
152  "Format understandable by the program CoCoA 4.") {
158  }
159 
161  return "cocoa4";
162  }
163 
165  return new CoCoA4IdealWriter(out);
166  }
167 
169  return new CoCoA4PolyWriter(out);
170  }
171 
172  void CoCoA4IOHandler::doWriteTerm(const vector<mpz_class>& term,
173  const VarNames& names,
174  FILE* out) {
175  C::writeTermProduct(term, names, out);
176  }
177 
179  C::readTerm(in, consumer);
180  }
181 
183  names.clear();
184 
185  in.expect("Use");
186  in.expect('R');
187  in.expect("::=");
188  in.expect('Q');
189  in.expect('[');
190  in.expect('x');
191 
192  size_t varCount = 0;
193  if (in.match('[')) {
194  in.expect('1');
195  in.expect("..");
196  in.readSizeT(varCount);
197  in.expect(']');
198  }
199  in.expect(']');
200  in.expect(';');
201 
202  in.expect("Names");
203  in.expect(":=");
204  in.expect('[');
205 
206  for (size_t var = 0; var < varCount; ++var) {
207  in.expect('\"');
208  if (in.peekWhite())
209  reportSyntaxError(in, "Variable name contains space.");
210 
211  names.addVarSyntaxCheckUnique(in, in.readIdentifier());
212 
213  if (in.peekWhite())
214  reportSyntaxError(in, "Variable name contains space.");
215 
216  in.expect('\"');
217  if (var < varCount - 1)
218  in.expect(',');
219  }
220 
221  in.expect(']');
222  in.expect(';');
223  }
224 
226  return in.peek('U') || in.peek('u');
227  }
228 
230  (Scanner& in, InputConsumer& consumer) {
231  consumer.beginIdeal();
232 
233  in.expect('I');
234  in.expect(":=");
235  in.expect("Ideal");
236  in.expect('(');
237 
238  if (!in.match(')')) {
239  do {
240  C::readTerm(in, consumer);
241  } while (in.match(','));
242  in.expect(')');
243  }
244  in.match(';');
245 
246  consumer.endIdeal();
247  }
248 
250  const VarNames& names,
251  CoefBigTermConsumer& consumer) {
252  consumer.consumeRing(names);
253  vector<mpz_class> term(names.getVarCount());
254  mpz_class coef;
255 
256  in.expect('p');
257  in.expect(":=");
258 
259  consumer.beginConsuming();
260  bool first = true;
261  do {
262  C::readCoefTerm(coef, term, first, in);
263  consumer.consume(coef, term);
264  first = false;
265  } while (!in.match(';'));
266  consumer.doneConsuming();
267  }
268 
269  void C::writeRing(const VarNames& names, FILE* out) {
270  if (names.getVarCount() == 0) {
271  fputs("Use R ::= Q[x];\nNames := [];\n", out);
272  return;
273  }
274 
275  fprintf(out, "Use R ::= Q[x[1..%lu]];\n",
276  (unsigned long)names.getVarCount());
277 
278  fputs("Names := [", out);
279 
280  const char* pre = "\"";
281  for (size_t i = 0; i < names.getVarCount(); ++i) {
282  fputs(pre, out);
283  fputs(names.getName(i).c_str(), out);
284  pre = "\", \"";
285  }
286  fputs("\"];\n", out);
287  }
288 
289  void C::writeTermProduct(const Term& term,
290  const TermTranslator& translator,
291  FILE* out) {
292  bool seenNonZero = false;
293  size_t varCount = term.getVarCount();
294  for (size_t var = 0; var < varCount; ++var) {
295  const char* exp = translator.getExponentString(var, term[var]);
296  if (exp == 0)
297  continue;
298  seenNonZero = true;
299 
300  fprintf(out, "x[%lu]", (unsigned long)(var + 1));
301  if (exp[0] != '1' || exp[1] != '\0') {
302  fputc('^', out);
303  fputs(exp, out);
304  }
305  }
306 
307  if (!seenNonZero)
308  fputc('1', out);
309  }
310 
311  void C::writeTermProduct(const vector<mpz_class>& term,
312  const VarNames& names,
313  FILE* out) {
314  bool seenNonZero = false;
315  size_t varCount = term.size();
316  for (size_t var = 0; var < varCount; ++var) {
317  if (term[var] == 0)
318  continue;
319  seenNonZero = true;
320 
321  fprintf(out, "x[%lu]", (unsigned long)(var + 1));
322  if (term[var] != 1) {
323  fputc('^', out);
324  mpz_out_str(out, 10, term[var].get_mpz_t());
325  }
326  }
327 
328  if (!seenNonZero)
329  fputc('1', out);
330  }
331 
332  void C::readTerm(Scanner& in, vector<mpz_class>& term) {
333  for (size_t var = 0; var < term.size(); ++var)
334  term[var] = 0;
335 
336  if (in.match('1'))
337  return;
338 
339  do {
340  C::readVarPower(term, in);
341  in.eatWhite();
342  } while (in.peek() == 'x');
343  }
344 
345  void C::readTerm(Scanner& in, InputConsumer& consumer) {
346  consumer.beginTerm();
347  if (!in.match('1')) {
348  do {
349  C::readVarPower(in, consumer);
350  in.eatWhite();
351  } while (in.peek() == 'x');
352  }
353  consumer.endTerm();
354  }
355 
356  void C::readVarPower(vector<mpz_class>& term, Scanner& in) {
357  in.expect('x');
358  in.expect('[');
359 
360  size_t var;
361  in.readSizeT(var);
362  if (var == 0 || var > term.size()) {
363  FrobbyStringStream errorMsg;
364  errorMsg << "There is no variable x[" << var << "].";
365  reportSyntaxError(in, errorMsg);
366  }
367  --var;
368 
369  in.expect(']');
370 
371  if (term[var] != 0) {
372  FrobbyStringStream errorMsg;
373  errorMsg << "The variable x["
374  << (var + 1)
375  << "] appears twice in the same monomial.";
376  reportSyntaxError(in, errorMsg);
377  }
378 
379  if (in.match('^')) {
380  in.readInteger(term[var]);
381  if (term[var] <= 0) {
382  FrobbyStringStream errorMsg;
383  errorMsg << "Expected positive integer as exponent but got "
384  << term[var] << '.';
385  reportSyntaxError(in, errorMsg);
386  }
387  } else
388  term[var] = 1;
389  }
390 
391  void C::readVarPower(Scanner& in, InputConsumer& consumer) {
392  in.expect('x');
393  in.expect('[');
394  size_t var = consumer.consumeVarNumber(in);
395  in.expect(']');
396  if (in.match('^'))
397  consumer.consumeVarExponent(var, in);
398  else
399  consumer.consumeVarExponentOne(var, in);
400  }
401 
402  void C::readCoefTerm(mpz_class& coef,
403  vector<mpz_class>& term,
404  bool firstTerm,
405  Scanner& in) {
406  for (size_t var = 0; var < term.size(); ++var)
407  term[var] = 0;
408 
409  bool positive = true;
410  if (!firstTerm && in.match('+'))
411  positive = !in.match('-');
412  else if (in.match('-'))
413  positive = false;
414  else if (!firstTerm) {
415  in.expect('+');
416  return;
417  }
418  if (in.match('+') || in.match('-'))
419  reportSyntaxError(in, "Too many adjacent signs.");
420 
421  if (in.peekIdentifier()) {
422  coef = 1;
423  C::readVarPower(term, in);
424  } else
425  in.readInteger(coef);
426 
427  in.eatWhite();
428  while (in.peek() == 'x') {
429  C::readVarPower(term, in);
430  in.eatWhite();
431  }
432 
433  if (!positive)
434  coef = -coef;
435  }
436 }
static const DataType & getPolynomialType()
Returns the one and only instance for polynomials.
Definition: DataType.cpp:50
This class contains further functionality that makes it more convenient to derive from than IOHandler...
virtual void doReadBarePolynomial(Scanner &in, const VarNames &names, CoefBigTermConsumer &consumer)
virtual void consumeRing(const VarNames &names)=0
static bool isIdentity(const Exponent *a, size_t varCount)
Returns whether a is 1, i.e. whether all entries of a are 0.
Definition: Term.h:308
void writeTermProduct(const Term &term, const TermTranslator &translator, FILE *out)
static const char * staticGetName()
virtual void doWriteEmptyList()
size_t consumeVarNumber(Scanner &in)
Reads variable as a number so that the first variable is 1.
virtual void doReadTerm(Scanner &in, InputConsumer &consumer)
void eatWhite()
Reads past any whitespace, where whitespace is defined by the standard function isspace().
Definition: Scanner.h:267
static const DataType & getMonomialIdealListType()
Returns the one and only instance for monomial ideal lists.
Definition: DataType.cpp:54
size_t getVarCount() const
Returns the current number of variables.
Definition: VarNames.h:112
const VarNames & getNames()
Definition: IdealWriter.h:44
void clear()
Resets the number of variables to zero.
Definition: VarNames.cpp:106
virtual void doWriteFooter(bool wasZero)
virtual BigTermConsumer * doCreateIdealWriter(FILE *out)
bool peekWhite()
Returns true if the next character is whitespace.
Definition: Scanner.h:137
void registerOutput(const DataType &type)
Specify that output of the argument type is supported.
void readCoefTerm(mpz_class &coef, vector< mpz_class > &term, bool firstTerm, Scanner &in)
virtual void consume(const mpz_class &coef, const Term &term)
void endIdeal()
Done reading an ideal.
void readTerm(Scanner &in, vector< mpz_class > &term)
Defines the variables of a polynomial ring and facilities IO involving them.
Definition: VarNames.h:40
virtual bool doPeekRing(Scanner &in)
size_t getVarCount() const
Definition: Term.h:85
virtual void doWriteTerm(const vector< mpz_class > &term, bool first)
virtual void doWriteHeader(bool first)
void readInteger(mpz_class &integer)
Read an arbitrary-precision integer.
Definition: Scanner.h:238
void beginTerm()
Start consuming a term.
void addVarSyntaxCheckUnique(const Scanner &in, const string &name)
As addvar, except it reports a syntax error if name is already a variable.
Definition: VarNames.cpp:68
void readVarPower(Scanner &in, InputConsumer &consumer)
This class offers an input interface which is more convenient and for some purposes more efficient th...
Definition: Scanner.h:50
const char * getExponentString(size_t variable, Exponent exponent) const
as getExponent, except the string "e" is returned, where e is the exponent.
void endTerm()
Done reading a term.
const string & getName(size_t index) const
The returned reference can become invalid next time addVar is called.
Definition: VarNames.cpp:100
bool peekIdentifier()
Skips whitespace and returns true if the next token is an identifier.
Definition: Scanner.h:257
void writeTermProduct(const vector< mpz_class > &term, const VarNames &names, FILE *out)
void registerInput(const DataType &type)
Specify that input of the argument type is supported.
const VarNames & getNames() const
Definition: PolyWriter.h:41
void readSizeT(size_t &size)
Reads a size_t, where the representable range of that type determines when the number is too big...
Definition: Scanner.cpp:205
bool isIdentity(const Word *a, Word *aEnd)
void consumeVarExponent(size_t var, Scanner &in)
Consumes var raised to an exponent read from in.
virtual void doWriteTerm(const Term &term, const TermTranslator &translator, bool first)
virtual void doReadBareIdeal(Scanner &in, InputConsumer &consumer)
bool peek(char character)
Skips whitespace and returns true if the next character is equal to the parameter(s).
Definition: Scanner.h:262
const char * readIdentifier()
The returned string is only valid until the next method on this object gets called.
Definition: Scanner.cpp:255
FILE * getFile()
Definition: IdealWriter.h:43
virtual void doWriteTerm(const mpz_class &coef, const vector< mpz_class > &term, bool firstGenerator)
void beginIdeal()
Start consuming an ideal.
TermTranslator handles translation between terms whose exponents are infinite precision integers and ...
void expect(char expected)
Require the next character to be equal to expected.
Definition: Scanner.h:231
virtual CoefBigTermConsumer * doCreatePolynomialWriter(FILE *out)
virtual void doWriteTerm(const vector< mpz_class > &term, const VarNames &names, FILE *out)
void reportSyntaxError(const Scanner &scanner, const string &errorMsg)
Definition: error.cpp:44
static const DataType & getMonomialIdealType()
Returns the one and only instance for monomial ideals.
Definition: DataType.cpp:45
virtual void doWriteTerm(const mpz_class &coef, const Term &term, const TermTranslator &translator, bool firstGenerator)
void writeRing(const VarNames &names, FILE *out)
virtual void doWriteHeader()
void consumeVarExponentOne(size_t var, const Scanner &in)
Consumes var raised to the exponent 1.
A replacement for stringstream.
FILE * getFile()
Definition: PolyWriter.h:40
void readVarPower(vector< mpz_class > &term, Scanner &in)
Term represents a product of variables which does not include a coefficient.
Definition: Term.h:49
void readTerm(Scanner &in, InputConsumer &consumer)
virtual void beginConsuming()=0
virtual void doReadRing(Scanner &in, VarNames &names)
bool match(char c)
Return true if the next character is c, and in that case skip past it.
Definition: Scanner.h:215
virtual void doWriteFooter(bool wasZeroIdeal)
virtual void doneConsuming()=0