Gröbner basis project
Codebase for research into Gröbner basis computation
test_cyclicn_mpi.cpp
1 /*****************************************************************************\
2 * This file is part of DynGB. *
3 * *
4 * DynGB 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 * Foobar 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 DynGB. If not, see <http://www.gnu.org/licenses/>. *
16 \*****************************************************************************/
17 
18 #include <set>
19 #include <cstring>
20 #include <iostream>
21 
22 using std::set;
23 using std::cout; using std::endl;
24 
25 #include "system_constants.hpp"
26 
27 #include "cyclic_n.hpp"
28 #include "polynomial.hpp"
29 #include "strategies.hpp"
30 #include "monomial_ordering.hpp"
31 #include "particular_orderings.hpp"
32 #include "algorithm_buchberger_basic.hpp"
33 #include "algorithm_buchberger_explorer.hpp"
34 #include "f4_reduction.hpp"
35 
36 #include "mpi.h"
37 
38 extern Monomial_Ordering * generic_grevlex_ptr;
39 
40 // Forward declarations
41 bool meaningful_arguments(
42  int, char **, bool &, int &, int &, SPolyCreationFlags &, bool &,
43  Monomial_Ordering **, StrategyFlags &, WT_TYPE **
44  );
45 void give_help();
46 
47 int main(int argc, char *argv[]) {
48  bool homog;
49  bool f4 = false;
50  int modulus, numvars;
51  SPolyCreationFlags method;
52  StrategyFlags strategy = StrategyFlags::SUGAR_STRATEGY;
53  WT_TYPE *grading;
54  Monomial_Ordering * mord = generic_grevlex_ptr;
55  // Multiprocessing
56  MPI_Init(nullptr, nullptr);
57  double start_time = MPI_Wtime();
58  int comm_size, comm_id;
59  MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
60  MPI_Comm_rank(MPI_COMM_WORLD, &comm_id);
61  if (not meaningful_arguments(
62  argc, argv, homog, modulus, numvars, method, f4,
63  &mord, strategy, &grading
64  )) {
65  if (comm_id == 0) // only need help from the first process
66  give_help();
67  } else {
68  Prime_Field FF = Prime_Field(modulus);
69  // set up the basis
70  list<Abstract_Polynomial *> B = cyclic_n(numvars, FF, homog, mord);
71  vector<Abstract_Polynomial *> F;
72  for (auto b : B)
73  F.push_back(b);
74  // message
75  if (comm_id == 0) {
76  cout << "Computing a Groebner basis for:\n";
77  for (Abstract_Polynomial * f : F)
78  cout << '\t' << *f << endl;
79  }
80  // compute basis
81  //set<Constant_Polynomial *, smaller_lm> G = buchberger(F, method);
82  list<Constant_Polynomial *> G;
83  G = buchberger_explorer(F, method, strategy, grading, comm_id, comm_size);
84  cout << comm_id << " returned from GB\n";
85  // display basis
86  if (comm_id == 0) {
87  cout << G.size() << " polynomials in basis:\n";
88  /*for (list<Constant_Polynomial *>::const_iterator g = G.begin(); g != G.end(); ++g)
89  cout << '\t' << *(*g) << endl;*/
90  Polynomial_Ring * R = & (G.front()->base_ring());
91  cout << G.size() << " leading monomials:\n";
92  for (Constant_Polynomial * g : G) {
93  cout << g->leading_monomial() << ' ' << endl;
94  delete g;
95  }
96  for (Abstract_Polynomial * f : F) delete f;
97  delete R;
98  }
99  }
100  if (mord != generic_grevlex_ptr)
101  delete mord;
102  cout << "bye from " << comm_id << "\n";
103  MPI_Barrier(MPI_COMM_WORLD);
104  if (comm_id == 0)
105  cout << "elapsed time: " << MPI_Wtime() - start_time << endl;
106  MPI_Finalize();
107 }
108 
109 enum order_flags { GENERIC_GREVLEX = 0, GREVLEX, LEX, WGREVLEX };
110 
111 bool meaningful_arguments(int argc, char *argv[], bool & homogeneous,
112  int & modulus, int & numvars,
113  SPolyCreationFlags & method, bool &f4,
114  Monomial_Ordering ** mord, StrategyFlags & strategy,
115  WT_TYPE ** grading
116  )
117 {
118  modulus = 43;
119  method = SPolyCreationFlags::LINKED_LST;
120  homogeneous = false;
121  WT_TYPE * weights = nullptr;
122  unsigned int order_flag = 0;
123  bool good_args = (argc > 1);
124  if (good_args) {
125  for (int i = 1; good_args and i < argc; ++i) {
126  if (!strcmp(argv[i],"hom") or !strcmp(argv[i],"homog")
127  or !strcmp(argv[i],"homogeneous"))
128  homogeneous = true;
129  else if (!strcmp(argv[i],"f4"))
130  f4 = true;
131  else {
132  int j = 0;
133  for (/* */; argv[i][j] != '=' and argv[i][j] != '\0'; ++j) { /* */ }
134  if (argv[i][j] != '=') {
135  good_args = false;
136  cout << "Arguments must have form <option>=<value>.\n";
137  }
138  else {
139  argv[i][j] = '\0';
140  if (!strcmp(argv[i],"n") or !strcmp(argv[i],"num")
141  or !strcmp(argv[i],"numvars")) {
142  numvars = atoi(&(argv[i][j+1]));
143  if (numvars < 3) {
144  good_args = false;
145  cout << "Invalid number of variables: must be at least 3.\n";
146  }
147  }
148  else if (!strcmp(argv[i],"m") or !strcmp(argv[i],"mod")
149  or !strcmp(argv[i],"modulus"))
150  {
151  modulus = atoi(&(argv[i][j+1]));
152  if (modulus < 2) {
153  good_args = false;
154  cout << "Invalid modulus; must be at least 2.\n";
155  }
156  }
157  else if (!strcmp(argv[i],"r") or !strcmp(argv[i],"repr")
158  or !strcmp(argv[i], "representation"))
159  {
160  method = (SPolyCreationFlags )atoi(&(argv[i][j+1]));
161  if (
162  method <= SPolyCreationFlags::MIN_SPCREATE_FLAG or
163  method > SPolyCreationFlags::MAX_SPCREATE_FLAG
164  ) {
165  good_args = false;
166  cout << "Invalid method; must be at least 1 and at most 3.\n";
167  }
168  }
169  else if (!strcmp(argv[i],"ord") or !strcmp(argv[i],"order")
170  or !strcmp(argv[i],"ordering"))
171  {
172  char * request = &(argv[i][j+1]);
173  if (!strcmp(request, "generic"))
174  order_flag = GENERIC_GREVLEX;
175  else if (!strcmp(request, "grevlex"))
176  order_flag = GREVLEX;
177  else if (!strcmp(request, "lex"))
178  order_flag = LEX;
179  else if (!strcmp(request, "wgrevlex")) {
180  order_flag = WGREVLEX;
181  unsigned n = (homogeneous) ? numvars + 1 : numvars;
182  weights = new WT_TYPE [n];
183  unsigned k = ++i;
184  for (/* */; k < i + n and k < argc; ++k)
185  weights[k - i] = atoi(argv[k]);
186  if (k - i < n)
187  good_args = false;
188  i = k;
189  }
190  else {
191  good_args = false;
192  cout << "Ordering must be 'generic', 'grevlex', "
193  << "'lex', or 'wgrevlex'.\n"
194  << "(Matrix orderings not yet supported via command line.)\n"
195  << "When using 'wgrevlex', follow it with a list of 'n' "
196  << "positive integers.\n";
197  }
198  }
199  else if (!strcmp(argv[i],"strat") or !strcmp(argv[i],"strategy")) {
200  char * request = &(argv[i][j+1]);
201  if (!strcmp(request, "normal") or !strcmp(request, "norm"))
202  strategy = StrategyFlags::NORMAL_STRATEGY;
203  else if (!strcmp(request, "sugar") or !strcmp(request, "sug"))
204  strategy = StrategyFlags::SUGAR_STRATEGY;
205  else if (!strcmp(request, "wsugar") or !strcmp(request, "wsug")) {
206  strategy = StrategyFlags::WSUGAR_STRATEGY;
207  unsigned n = (homogeneous) ? numvars + 1 : numvars;
208  *grading = new WT_TYPE [n];
209  unsigned k = ++i;
210  for (/* */; k < i + n and k < argc; ++k)
211  (*grading)[k - i] = atoi(argv[k]);
212  if (k - i < n)
213  good_args = false;
214  i = k;
215  }
216  else {
217  good_args = false;
218  cout << "Strategy must be 'normal' or 'sugar'.";
219  }
220  }
221  else {
222  cout << "Unrecognized argument.\n"; good_args = false;
223  }
224  }
225  }
226  }
227  }
228  if (good_args) {
229  unsigned n = (homogeneous) ? numvars + 1 : numvars;
230  switch (order_flag) {
231  case GENERIC_GREVLEX: *mord = generic_grevlex_ptr; break;
232  case GREVLEX: *mord = new Grevlex_Ordering(n); break;
233  case LEX: *mord = new Lex_Ordering(n); break;
234  case WGREVLEX: *mord = new CachedWGrevlex_Ordering(n, weights); break;
235  default: *mord = generic_grevlex_ptr;
236  }
237  }
238  return good_args;
239 }
240 
241 void give_help() {
242  cout << "This is the same as test_cyclicn, only using OpenMPI for multiprocessing.\n";
243  cout << "Call with options n=<num> m=<mod> r=<repr>\n";
244  cout << "You *must* specify <num> vars, an integer greater than 2.\n";
245  cout << "You can add optional <mod>ulus (please make it prime).\n";
246  cout << "The option <hom>ogenize will give you a homogenized ideal.\n";
247  cout << "You can also select the <repr>esentation of s-polynomials:\n";
248  cout << "\t1) linked lists,\n";
249  cout << "\t2) geobuckets, or\n";
250  cout << "\t3) double-buffered polynomials.\n";
251  cout << "So 'test_cyclicn n=6 m=43 r=2' would compute the Groebner basis\n";
252  cout << "of the Cyclic-n ideal in 6 variables, modulo 43,";
253  cout << "using geobuckets.\n";
254  cout << "You can also specify the strategy ('normal', 'sugar', 'wsugar')\n";
255  cout << "('wsugar' requires a list of <num> integers, where <num> is as above,";
256  cout << "and the term ordering ('generic', 'grevlex', 'lex', 'wgrevlex').\n";
257  cout << "('wgrevlex' requires a list of <num> integers, where <num>";
258  cout << " is as above.\n";
259  cout << "The 'f4' option runs the F4 algorithm.\n";
260 }
The general class of a polynomial.
Definition: polynomial.hpp:101
list< Constant_Polynomial * > buchberger_explorer(const vector< Abstract_Polynomial *> &F, SPolyCreationFlags method, StrategyFlags strategy, WT_TYPE *strategy_weights, const int comm_id, const int comm_size)
Alternate implementation of Buchberger’s algorithm, for parallelization.
A Constant_Polynomial is a polynomial that should not change.
Information necessary for a field modulo a prime.
Definition: fields.hpp:49
StrategyFlags
flag indicating which strategy to use for computation
Definition: strategies.hpp:34
SPolyCreationFlags
flag indicating which structure to use for an s-polynomial
interface to a monomial ordering
Encapsulates information about a polynomial ring for easy access: ground field, number of indetermina...
the lex ordering for a specified number of variables
the grevlex ordering for a specified number of variables
the weighted grevlex ordering for a specified number of variables, with cached weights for each monom...
list< Abstract_Polynomial * > cyclic_n(NVAR_TYPE n, Prime_Field &F, bool homog, Monomial_Ordering *mord=generic_grevlex_ptr)
generates the Cyclic- system
Definition: cyclic_n.hpp:57