-
Notifications
You must be signed in to change notification settings - Fork 0
/
critical_pair.hpp
287 lines (275 loc) · 10.4 KB
/
critical_pair.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
#ifndef __CRITICAL_PAIR_HPP_
#define __CRITICAL_PAIR_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 "polynomial.hpp"
#include "polynomial_geobucket.hpp"
#include "polynomial_linked_list.hpp"
#include "polynomial_double_buffered.hpp"
#include "strategies.hpp"
#include "sugar_strategy.hpp"
#include "normal_strategy.hpp"
#include "weighted_sugar_strategy.hpp"
#include "particular_orderings.hpp"
// forward declaration
class Pair_Sugar_Data;
class Poly_Sugar_Data;
/**
@defgroup strategygroup Strategies
@brief strategies for Gröbner basis computation
*/
/**
\enum SPolyCreationFlags
@author John Perry
@date 2015
@brief flag indicating which structure to use for an s-polynomial
@ingroup GBComputation
@details The following options are currently available:
- LINKED_LST polynomials are created and manipulated in linked list format
- GEOBUCKETS polynomials are created and manipulated in geobucket format
@cite YanGeobuckets
- DOUBLE_BUF polynomials are created and manipulated in a novel,
doubled-buffered format
*/
enum class SPolyCreationFlags {
MIN_SPCREATE_FLAG = 0,
LINKED_LST,
GEOBUCKETS,
DOUBLE_BUF,
MAX_SPCREATE_FLAG
};
/**
@class Critical_Pair_Basic
@author John Perry
@date 2015
@brief Controls the creation of s-polynomials.
@ingroup GBComputation
@details This class encapsulates the information necessary to create
an @f$S@f$-polynomial, including the actual generation of
an @f$S@f$-polynomial, though it does not retain that information.
*/
class Critical_Pair_Basic {
public:
/** @name Construction */
///@{
/** @brief create critical pair (f,0) for initial polynomial */
Critical_Pair_Basic(Abstract_Polynomial * f, StrategyFlags strategy);
/** @brief create critical pair (f,g) for two polynomials */
Critical_Pair_Basic(
Abstract_Polynomial * f, Abstract_Polynomial * g, StrategyFlags strategy
);
/** @brief copy constructor */
explicit Critical_Pair_Basic(const Critical_Pair_Basic &);
///@}
/** @name Destruction */
///@{
virtual ~Critical_Pair_Basic() { if (key != nullptr) delete key; }
///@}
/** @name Basic properties */
///@{
/** @brief whether this pair is from a generator */
inline bool is_generator() const { return q == nullptr; }
/** @brief first polynomial in pair */
inline const Abstract_Polynomial * first() const { return p; }
/** @brief second polynomial in pair */
inline const Abstract_Polynomial * second() const { return q; }
/** @brief lcm of leading monomials of polynomials */
inline const Monomial & lcm() const { return tpq; }
/** @brief degree of ith variable in lcm */
inline unsigned lcm_degree(unsigned i) const { return tpq.degree(i); }
/** @brief monomial needed to multiply first polynomial to lcm() */
inline const Monomial & first_multiplier() const { return tp; }
/** @brief monomial needed to multiply second polynomial to lcm() */
inline const Monomial & second_multiplier() const { return tq; }
/** @brief strategy used for comparison of pairs */
inline const Pair_Strategy_Data * pair_key() const { return key; }
/**
@brief to use only if s-polynomial is already computed by another method
@warning If you have not already created an s-polynomial using one of
SPolyCreationFlags, then this returns @c nullptr and is useless.
@return the s-polynomial of this pair
*/
virtual Mutable_Polynomial * s_polynomial() { return s; }
///@}
/** @name Computation */
///@{
/** @brief creates the s-polynomial for first() and second() */
virtual Mutable_Polynomial * s_polynomial(
SPolyCreationFlags method, StrategyFlags strategy
) ;
///@}
/** @name Modification */
///@{
/** @brief sets the s-polynomial to @c p, for explorer methods*/
virtual void set_spoly(Mutable_Polynomial * p) { s = p; }
/** @brief in case you want to swap the polynomials, for whatever reason */
void swap() {
auto temp = p;
p = q;
q = temp;
auto temp_t = tp;
tp = tq;
tq = temp_t;
}
///@}
/** @name I/O */
///@{
friend ostream & operator<<(ostream &, const Critical_Pair_Basic &);
///@}
protected:
/** @brief first polynomial in the critical pair */
Abstract_Polynomial * p;
/** @brief second polynomial in the critical pair */
Abstract_Polynomial * q;
/** @brief S-polynomial */
Mutable_Polynomial * s;
/** @brief lcm of leading monomials of @f$p@f$ and @f$q@f$ */
Monomial tpq;
/** @brief monomial multiple of @f$p@f$ that produces @f$S@f$-polynomial */
Monomial tp;
/** @brief monomial multiple of @f$q@f$ that produces @f$S@f$-polynomial */
Monomial tq;
/** @brief strategy used to sort critical pairs */
Pair_Strategy_Data * key = nullptr;
};
/**
@class Critical_Pair_Dynamic
@author John Perry
@date 2016
@brief Controls the creation of s-polynomials, specialized for the dynamic
algorithm.
@ingroup GBComputation
@details This class encapsulates the information necessary to create
an @f$S@f$-polynomial, including the actual generation of
an @f$S@f$-polynomial, though it does not retain that information.
The main difference with @c Critical_Pair_Basic is the enabling of late
re-sorting.
*/
class Critical_Pair_Dynamic : public Critical_Pair_Basic {
public:
/** @name Construction */
///@{
/**
@brief create critical pair (f,0) for initial polynomial,
with given ordering
*/
Critical_Pair_Dynamic(
Abstract_Polynomial * f, StrategyFlags strategy,
Weighted_Ordering * how_to_order
) : Critical_Pair_Basic(f, strategy) {
ordering = how_to_order;
};
/** @brief copy constructor */
Critical_Pair_Dynamic(const Critical_Pair_Dynamic & other) :
Critical_Pair_Basic(other), ordering(other.ordering)
{ /* done */ }
/**
@brief create critical pair (f,g) for two polynomials, with given ordering
*/
Critical_Pair_Dynamic(
Abstract_Polynomial * f, Abstract_Polynomial * g, StrategyFlags strategy,
Weighted_Ordering * how_to_order
) : Critical_Pair_Basic(f, g, strategy) {
ordering = how_to_order;
tpq.set_monomial_ordering(ordering);
tp.set_monomial_ordering(ordering);
tq.set_monomial_ordering(ordering);
delete key;
switch(strategy) {
case StrategyFlags::NORMAL_STRATEGY:
key = new Normal_Strategy(*this);
break;
case StrategyFlags::SUGAR_STRATEGY :
key = new Pair_Sugar_Data(*this);
break;
case StrategyFlags::WSUGAR_STRATEGY:
key = new Pair_WSugar_Strategy(*this);
break;
default: key = new Normal_Strategy(*this); break;
}
}
///@}
// No need for a new destructor (I hope)
/** @name Computation */
///@{
/**
@brief creates the s-polynomial for first() and second()
@details If either first() or second() was sorted using an ordering
different from the one assigned the pair, it is sorted anew.
@param method a flag for what structure to use while reducing the
s-polynomial; see SPolyCreationFlags
@param strategy a flag for which strategy to use in reduction; see
StrategyFlags
@return the generated s-polynomial
*/
virtual Mutable_Polynomial * s_polynomial(
SPolyCreationFlags method, StrategyFlags strategy
);
///@}
/** @name Basic properties */
///@{
/** @brief the ordering associated with this pair */
Weighted_Ordering * how_ordered() const { return ordering; }
///@}
/** @name Modification */
///@{
/**
@brief change the ordering associated with this pair
@details This is necessary at least for critical pairs where one polynomial
is a generator that we have not yet computed.
We delay re-sorting the polynomial until the s-polynomial’s
computation.
@param new_order the new ordering for this critical pair
*/
void change_ordering(Weighted_Ordering * new_order) {
ordering = new_order;
// the leading term may change when an input polynomial is involved,
// so we need to reconsider the leading monomial & "lcm" here
if (is_generator()) {
p->set_monomial_ordering(ordering);
tpq = p->leading_monomial();
}
tpq.set_monomial_ordering(ordering);
tp.set_monomial_ordering(ordering);
tq.set_monomial_ordering(ordering);
Pair_WSugar_Strategy * strat = dynamic_cast<Pair_WSugar_Strategy *>(key);
if (strat != nullptr) {
DEG_TYPE new_sugar = first()->weighted_degree(new_order->order_weights());
new_sugar += first_multiplier().weighted_degree(new_order->order_weights());
if (second() != nullptr) {
DEG_TYPE second_sugar = first()->weighted_degree(new_order->order_weights());
second_sugar += second_multiplier().weighted_degree(new_order->order_weights());
if (second_sugar > new_sugar) new_sugar = second_sugar;
}
strat->adjust_sugar(new_sugar);
}
}
///@}
/** @name I/O */
///@{
/** @brief outputs the pair, and the ordering */
friend ostream & operator<<(ostream &, const Critical_Pair_Dynamic &);
///@}
protected:
/**
@brief the @c Monomial_Ordering assigned to this pair — might disagree
with that of polynomials; they must be updated immediately if this is a
generator; otherwise, update can wait until the critical pair is computed.
*/
Weighted_Ordering * ordering;
};
#endif