-
Notifications
You must be signed in to change notification settings - Fork 0
/
f4_dynamic_july_2020.hpp
496 lines (484 loc) · 17.8 KB
/
f4_dynamic_july_2020.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#ifndef __F4_REDUCTION_HPP__
#define __F4_REDUCTION_HPP__
/*****************************************************************************\
* This file is part of DynGB. *
* *
* DynGB is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* DynGB is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with DynGB. If not, see <http://www.gnu.org/licenses/>. *
\*****************************************************************************/
#include <set>
using std::set;
#include <list>
using std::list;
#include <vector>
using std::vector;
#include <cstdlib>
#include <utility>
using std::pair;
#include <functional>
using std::function;
#include <mutex>
using std::mutex;
#include "system_constants.hpp"
#include "fields.hpp"
#include "monomial.hpp"
#include "monomial_ordering.hpp"
#include "polynomial.hpp"
#include "critical_pair.hpp"
#include "f4_hash.hpp"
#include "lp_solver.hpp"
using LP_Solvers::LP_Solver;
#include "dynamic_engine.hpp"
using Dynamic_Engine::PP_With_Ideal;
using Dynamic_Engine::Dynamic_Heuristic;
/**
@brief enumeration of styles of row analysis for selecting a new ordering
*/
enum class Analysis {
row_sequential, /**< analyze only one row (topmost unprocessed) */
whole_matrix /**< analyze every row of the matrix */
};
/**
@ingroup GBComputation
@brief equivalent to @c buchberger(), but for Faugère’s F4 algorithm
@param F generators of a polynomial ideal
@param finalized_monomials monomials computed for the basis
@param hash_table an @c F4_Hash to store monomials computed for the basis
@param static_algorithm whether the algorithm should run traditionally or
using dynamic techniques
@param max_refinements maximum number of refinements per matrix;
default (0) means no maximum
@param style whether to analyze each row of the matrix in order, or to
analyze the entire matrix
@param heur which heuristic to use when selecting an ordering
@return a Gröbner basis of the ideal generated by @f$ F @f$
with respect to the ordering already assigned to its polynomials
*/
list<Abstract_Polynomial *> f4_control(
const list<Abstract_Polynomial *> &F,
vector<Monomial *> & finalized_monomials,
F4_Hash & hash_table,
const bool static_algorithm = true,
const unsigned max_refinements = 0,
const Analysis style = Analysis::row_sequential,
const Dynamic_Heuristic heur = Dynamic_Heuristic::ORD_HILBERT_THEN_DEG
);
extern unsigned location_of_monomial_index(
vector< pair< unsigned, COEF_TYPE > > & row, unsigned i
);
/**
@brief used to compare monomials for STL containers such as @c map
*/
struct MonCmp {
/**
@brief returns @c true iff the monomial pointed to by @p t is smaller than
the monomial pointed to by @p u
@param t monomial we're comparing
@param u monomial we're comparing
@return @c true iff the monomial pointed to by @p t is smaller than
the monomial pointed to by @p u
*/
bool operator()(
const Monomial * t,
const Monomial * u
) const {
return *t < *u;
}
};
/**
@brief Implementation of Faugère’s F4 algorithm.
@ingroup GBComputation
@details Currently computes a Gröbner basis by selecting several
s-polynomials of lowest lcm degree. Data is stored in a semi-sparse matrix
format, with each row a contiguous array of entries (@c A).
Each row of @c A begins at the position indicated
by the corresponding @c offset,
and its first non-zero entry appears at the position indicated by
the corresponding @c head.
So the leading coefficient of the polynomial in row @c k appears in
<c>A[head[k]]</c> and the leading monomial appears in
<c>M[offset[k]+head[k]]</c>.
Starting from <c>head[k]</c>, row @c k is actually dense.
While this is not sparse, it does succeed in saving more space
than one might expect.
*/
class F4_Reduction_Data {
public:
/** @name Construction */
///@{
/**
@brief encapsulation of one step of the F4 algorithm for the polynomials
indicated by @p P and @p B
@param curr_ord current monomial ordering
@param P list of critical pairs that will create a new basis; matrix will
have this many rows
@param B list of polynomials currently in the basis
@param method heuristic the system should use in choosing leading monomials
*/
F4_Reduction_Data(
WGrevlex * curr_ord,
const list<Critical_Pair_Dynamic *> & P,
const list<Abstract_Polynomial *> & B,
Dynamic_Heuristic method
);
/**
@brief adds monomials of @f$ ug @f$ to @c M_builder
@param curr_ord current monomial ordering
@param g polynomial, such as an s-polynomial generator or a reducer
@param u monomial to multiply to @p g to add monomials
@param new_row if @c true, adds the leading monomial; otherwise, adds only
trailing monomials
*/
void add_monomials(
const WGrevlex * curr_ord,
const Abstract_Polynomial *g,
const Monomial & u,
bool new_row = false
);
/**
@brief creates the matrix
@details called internally by constructor, which has already performed some
setup; inadvisable to use elsewhere
@param P list of critical pairs that will generate the matrix
*/
void initialize_many(const list<Critical_Pair_Dynamic *> & P);
///@}
/** @name Destruction */
///@{
/**
@brief releases space for the matrix
*/
~F4_Reduction_Data();
///@}
/** @name Basic properties */
///@{
/**
@brief returns @c true iff all the entries are 0
*/
bool is_zero();
/** @brief returns the number of nonzero entries on the indicated row */
unsigned number_of_nonzero_entries(unsigned i) { return nonzero_entries[i]; }
/** @brief basic properties */
unsigned number_of_rows() const { return A.size(); }
/** @brief set of monomials in row @p i that are not zero (absolute index) */
void monomials_in_row(unsigned i, list<unsigned> &) const;
/** @brief current ordering of monomials */
const WGrevlex * current_ordering() const { return mord; }
/**
@brief returns the number of compatible monomials detected in the given row
*/
unsigned number_of_compatibles(unsigned row) {
return compatible_pps[row].size();
}
/** @brief return the indicated monomial */
const Monomial & monomial(unsigned i) { return *M[i]; }
/** @brief find the index of the monomial of greatest weight in this row */
unsigned head_monomial_index(unsigned i, bool static_algorithm = false) {
const auto & Ai = A[i];
unsigned result = Ai[0].first;
if (not static_algorithm) {
auto & t = *M[result];
for (unsigned k = 1; k < Ai.size(); ++k) {
if (mord->first_smaller(t, *M[Ai[k].first])) {
result = Ai[k].first;
t = *M[result];
}
}
}
return result;
}
///@}
/** @name Conversion */
///@{
/**
@brief converts indicated row to a Polynomial_Hashed, returns result
*/
Polynomial_Hashed * finalize(unsigned, vector< Monomial * > &, F4_Hash &);
///@}
/** @name Modification */
///@{
/**
@brief for each monomial of the matrix, finds another monomial that
dominates it under the current skeleton (if any such dominator exists)
@param skel the current skeleton
*/
void determine_dominators(const LP_Solver * skel);
/**
@brief prunes from the list of all monomials those that are clearly
dominated by another monomial in the row's support
@param all_pps initial list of pp's
@param i the current row
*/
void prune_dominators(list< unsigned > & all_pps, unsigned i);
///@}
/** @name Computation */
///@{
/** @brief reduces polynomials */
void reduce_by_old();
/** @brief reduces polynomials */
void reduce_by_new(unsigned i, unsigned lhead_i, const set<unsigned> &);
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief Create constraints for a candidate LPP.
@param pp_I pair of PP with the ideal it would have.
@param monomials_for_comparison indices of monomials used to generate constraints with LPP
@param result the new constraints
*/
void constraints_for_new_pp(
const PP_With_Ideal &I,
const set<int> &monomials_for_comparison,
vector<Constraint> &result
);
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief identifies potential leading monomials and sorts them by preference
@param my_row which row of the matrix we are working on
@param currentLPP current leading monomial of this polynomial
@param allPP_indices indices of the support of a polynomial in need of a new choice of LPP
*/
void create_and_sort_ideals(
int my_row,
const list<Monomial> & CurrentLPPs,
const Dense_Univariate_Integer_Polynomial * current_hilbert_numerator,
const list<Abstract_Polynomial *> & CurrentPolys,
const list<Critical_Pair_Dynamic *> & crit_pairs,
const Ray & w,
Dynamic_Heuristic method
);
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief refines the ordering, if possible
@param my_row the row of the matrix that we are refining
@param currSkel the current skeleton, corresponding to the choices `CurrentLPPs`
@param CurrentPolys list of current polynomials in the basis (needed to verify consistency)
*/
pair< bool, LP_Solver * > refine(
unsigned my_row,
LP_Solver * currSkel,
const list<Abstract_Polynomial *> & CurrentPolys
);
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief determines the weights of each monomial, according to the given skeleton
@param skel current skeleton
*/
void recache_weights(LP_Solver * skel);
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief cleans up various records after we compute a new ordering
@param my_row the row of the matrix that we are refining
@param w the old ordering
@param current_hilbert_numerator the basis' current Hilbert numerator
@param currSkel the current skeleton
@param winner the @c PP_With_Ideal with information relating to the selected monomial
@param ordering_changed whether the ordering has changed (written, not read)
*/
/**
@ingroup GBComputation
@author John Perry
@date 2019
@brief prints the weights cached for each monomial, according to most recent
skeleton used
*/
void print_cached_weights();
void reassign(
unsigned my_row,
const Ray & w,
Dense_Univariate_Integer_Polynomial * & current_hilbert_numerator,
LP_Solver * currSkel,
const PP_With_Ideal & winner,
bool & ordering_changed
);
/**
@brief selects leading monomials for one remaining nonzero rows
@details This functions basically fills the role that select_monomial()
fills in the dynamic Buchberger algorithm.
Unlike the other select_dynamic(), however,
it chooses only one row at a time.
@param unprocessed set of unprocessed rows;
the result will from from this set
@param T list of current leading monomials
@param G list of current basis polynomials
@param P list of current critical pairs
@param curr_ord current monomial ordering
@param skel the current LP_Solver that defines the term ordering
@param expected_result used for debugging
@param style which approach to take to selecting a row
@return the row with the recommended new ordering
*/
unsigned select_dynamic_single(
set<unsigned> & unprocessed,
list<Monomial> & T,
const list<Abstract_Polynomial *> & G,
const list<Critical_Pair_Dynamic *> & P,
WGrevlex * curr_ord,
LP_Solver * & skel,
Monomial * & expected_result,
const Analysis & style = Analysis::row_sequential
);
/**
@brief eliminates duplicates of rows:
later rows that are identical to earlier rows will be eliminated
@param in_use rows that are currently still in use by the matrix
*/
void simplify_identical_rows(set<unsigned> & in_use);
/** @brief make row monic at indicated index */
void normalize(unsigned i, unsigned lhead_i) {
auto & Ai = A[i];
auto mod = Rx.ground_field().modulus();
COEF_TYPE a = Rx.ground_field().inverse(Ai[location_of_monomial_index(Ai, lhead_i)].second);
for (auto k = 0; k < Ai.size(); ++k) {
Ai[k].second *= a; Ai[k].second %= mod;
}
}
///@}
/** @name I/O */
///@{
/** @brief lists the reducers selected for each column, in order */
void list_reducers();
/**
@brief prints the matrix
@param show_data whether to show the monomials that correspond to each column
*/
void print_matrix(bool show_data=false);
/**
@brief prints indicated row of the matrix
@details If the second argument is true, the row is printed as a polynomial.
*/
void print_row(unsigned, bool=false);
/**
@brief prints the pairs of monomials and reducers that are being built
*/
void print_builder();
///@}
protected:
/**
@brief creates rows of the matrix indexed by the specified pairs,
starting at the specified row
*/
void initialize_some_rows(const list<Critical_Pair_Dynamic *> &, unsigned);
/** @brief builds a reducer for the specified column */
void build_reducer(unsigned);
/**
@brief reduces the specified set of rows, suitable for multithreading
@param rows the rows to reduce
@param buffer space to expand each row in @p rows and then reduce
@param next @c expand needs this to track monomial locations
*/
void reduce_my_rows(
const vector<int> &rows,
vector <COEF_TYPE> &buffer, vector <unsigned> & prev, vector <unsigned> & next
);
/**
@brief reduces the specified set of rows by the specified row,
suitable for multithreading
@param i row of the row to use when reducing
@param lhead_i the location of the (new) leading monomial of @p i
@param buffer space to expand each row for reduction
@param next @c expand needs this to track monomial locations
@param to_reduce which rows of the matrix this thread will reduce
*/
void reduce_my_new_rows(
unsigned i,
unsigned lhead_i,
vector< COEF_TYPE > & buffer,
vector< unsigned > & prev, vector< unsigned > & next,
const set<unsigned> & to_reduce,
unsigned mod
);
/** @brief number of columns in the polynomial */
unsigned num_cols;
/** @brief number of rows in the matrix */
unsigned num_rows;
/** @brief monomials for each matrix */
vector< Monomial * > M;
/** @brief hash table of the monomials in @c M */
F4_Hash M_table;
/** @brief locks on the reducers */
vector<mutex> red_lock;
/**
@brief coefficient data in sparse representation; each vector entry
indicates position and coefficient
*/
vector< vector < pair < unsigned, COEF_TYPE > > > A;
/** @brief whether the row was modified during reduction */
vector<bool> dirty;
/** @brief ordering this row's compatibility was last checked */
vector<WGrevlex *> last_compatible_ordering;
/** @brief index of the preferred head term of this row (absolute index) */
vector<unsigned> pref_head;
/** @brief number of nonzero entries of each expanded row of A */
vector<unsigned> nonzero_entries;
/** @brief compatible pp's for each row (absolute index) */
vector< list<int> > compatible_pps;
/** @brief cache of monomial weights under current ordering */
vector< vector<unsigned> > pp_weights;
/** @brief potential ideals for the given row */
vector< list<PP_With_Ideal> > potential_ideals;
/** @brief storage of monomials and reducers while preprocessing */
map<Monomial *, Abstract_Polynomial *, MonCmp> M_builder;
/** @brief finalized list of indices of reducers for the corresponding monomials of @c f */
vector<Abstract_Polynomial *> R;
/** @brief mutexes for building rows of @c R */
vector<mutex> red_mutex;
/** @brief reducers actually generated */
vector<vector<pair<unsigned, COEF_TYPE> > > R_built;
/** @brief record of a monomial always greater than this one */
vector< unsigned > dominators;
/** @brief current basis of ideal */
const list<Abstract_Polynomial *> & G;
/** @brief how the monomials are ordered */
WGrevlex * mord;
/** @brief polynomial ring */
Polynomial_Ring & Rx;
/** @brief strategy data for each polynomial */
vector<Poly_Sugar_Data *> strategies;
/**
@brief each entry contains a set of monomials that could be a leading
monomial of the corresponding row of the matrix
*/
vector<list<PP_With_Ideal> > I;
/** @brief heuristic the system should use in choosing leading monomials */
Dynamic_Heuristic heur;
/** @brief function corresponding to @c heur */
function <bool(PP_With_Ideal &, PP_With_Ideal &)> heuristic_judges_smaller;
friend void compatible_pp(
int my_row,
F4_Reduction_Data & F4,
WGrevlex * curr_ord,
const LP_Solver * skel,
bool & stop,
vector<bool> & completed
);
friend void divisibility_tests(
list<int> & allPPs,
F4_Reduction_Data & F4,
bool & stop
);
friend void divisibility_tests_new(
list<int> & allPPs,
F4_Reduction_Data & F4,
bool & stop
);
};
#endif