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 "randomDataGenerators.h"
19
20 #include "BigIdeal.h"
21 #include "Ideal.h"
22 #include "Term.h"
23 #include "error.h"
24 #include "FrobbyStringStream.h"
25
26 #include <limits>
27 #include <ctime>
28 #include <unistd.h>
29
generateLinkedListIdeal(BigIdeal & ideal,size_t variableCount)30 void generateLinkedListIdeal(BigIdeal& ideal, size_t variableCount) {
31 VarNames names(variableCount);
32 ideal.clearAndSetNames(variableCount);
33 ideal.reserve(variableCount);
34 for (size_t var = 1; var < variableCount; ++var) {
35 ideal.newLastTerm();
36 ideal.getLastTermExponentRef(var) = 1;
37 ideal.getLastTermExponentRef(var - 1) = 1;
38 }
39 }
40
generateChessIdeal(BigIdeal & bigIdeal,size_t rowCount,size_t columnCount,int deltaRow[],int deltaColumn[],size_t deltaCount)41 void generateChessIdeal(BigIdeal& bigIdeal,
42 size_t rowCount,
43 size_t columnCount,
44 int deltaRow[],
45 int deltaColumn[],
46 size_t deltaCount) {
47 if (mpz_class(rowCount) * mpz_class(columnCount) >
48 numeric_limits<size_t>::max())
49 reportError("Number of positions on requested chess board too large.");
50
51 // Generate names
52 VarNames names;
53 for (size_t row = 0; row < rowCount; ++row) {
54 for (size_t column = 0; column < columnCount; ++column) {
55 FrobbyStringStream name;
56 name << 'r' << (row + 1) << 'c' << (column + 1);
57 names.addVar(name);
58 }
59 }
60 bigIdeal.clearAndSetNames(names);
61 Ideal ideal(bigIdeal.getVarCount());
62
63 // Generate ideal
64 for (size_t row = 0; row < rowCount; ++row) {
65 for (size_t column = 0; column < columnCount; ++column) {
66 for (size_t delta = 0; delta < deltaCount; ++delta) {
67 // Check that the target position is within the board.
68
69 if (deltaRow[delta] == numeric_limits<int>::min() ||
70 (deltaRow[delta] < 0 &&
71 row < (size_t)-deltaRow[delta]) ||
72 (deltaRow[delta] > 0 &&
73 rowCount - row <= (size_t)deltaRow[delta]))
74 continue;
75
76 if (deltaColumn[delta] == numeric_limits<int>::min() ||
77 (deltaColumn[delta] < 0 &&
78 column < (size_t)-deltaColumn[delta]) ||
79 (deltaColumn[delta] > 0 &&
80 columnCount - column <= (size_t)deltaColumn[delta]))
81 continue;
82
83 Term chessMove(ideal.getVarCount());
84 chessMove[row * columnCount + column] = 1;
85
86 size_t targetRow = row + deltaRow[delta];
87 size_t targetColumn = column + deltaColumn[delta];
88 ASSERT(targetRow < rowCount);
89 ASSERT(targetColumn < columnCount);
90
91 chessMove[targetRow * columnCount + targetColumn] = 1;
92 ideal.insert(chessMove);
93 }
94 }
95 }
96
97 ideal.sortReverseLex();
98 bigIdeal.insert(ideal);
99 }
100
generateKingChessIdeal(BigIdeal & ideal,size_t rowsAndColumns)101 void generateKingChessIdeal(BigIdeal& ideal, size_t rowsAndColumns) {
102 int deltaRow[] = {-1, 0, 1, 1}; // the other moves follow by symmetry
103 int deltaColumn[] = { 1, 1, 1, 0};
104 ASSERT(sizeof(deltaRow) == sizeof(deltaColumn));
105
106 size_t deltaCount = sizeof(deltaRow) / sizeof(int);
107
108 generateChessIdeal(ideal, rowsAndColumns, rowsAndColumns,
109 deltaRow, deltaColumn, deltaCount);
110 }
111
generateKnightChessIdeal(BigIdeal & ideal,size_t rowsAndColumns)112 void generateKnightChessIdeal(BigIdeal& ideal, size_t rowsAndColumns) {
113 int deltaRow[] = {-1, 1, 2, 2}; // the other moves follow by symmetry
114 int deltaColumn[] = { 2, 2, 1, -1};
115 ASSERT(sizeof(deltaRow) == sizeof(deltaColumn));
116
117 size_t deltaCount = sizeof(deltaRow) / sizeof(int);
118
119 generateChessIdeal(ideal, rowsAndColumns, rowsAndColumns,
120 deltaRow, deltaColumn, deltaCount);
121 }
122
123 namespace {
124 /** Consider the entries of pattern as the bits in a binary
125 number. This method adds 1 and returns true if the resulting
126 pattern is all zeroes. */
nextBitPattern(vector<char> & pattern)127 bool nextBitPattern(vector<char>& pattern) {
128 typedef vector<char>::iterator iterator;
129 for (iterator it = pattern.begin(); it != pattern.end(); ++it) {
130 if (*it)
131 *it = 0;
132 else {
133 *it = 1;
134 ASSERT(pattern != vector<char>(pattern.size()));
135 return true;
136 }
137 }
138
139 ASSERT(pattern == vector<char>(pattern.size()));
140 return false;
141 }
142 }
143
generateTreeIdeal(BigIdeal & ideal,size_t varCount)144 void generateTreeIdeal(BigIdeal& ideal, size_t varCount) {
145 ideal.clearAndSetNames(VarNames(varCount));
146
147 // Declare outside of loop to avoid repeated initialization.
148 mpz_class exponent;
149
150 // Using vector<char> to avoid vector<bool> which has special
151 // properties. Going through all "bit" patterns by simulating adding
152 // one at each step. pattern starts at all zero, which represents
153 // the identity, so we take the next bit pattern even in the first
154 // iteration to go past that.
155 vector<char> pattern(varCount);
156 while (nextBitPattern(pattern)) {
157 size_t setSize = 0;
158 typedef vector<char>::iterator iterator;
159 for (iterator it = pattern.begin(); it != pattern.end(); ++it)
160 setSize += (size_t)*it;
161
162 exponent = varCount - setSize + 1;
163 ideal.newLastTerm();
164 for (size_t var = 0; var < varCount; ++var)
165 if (pattern[var])
166 ideal.getLastTermExponentRef(var) = exponent;
167 }
168 }
169
generateRookChessIdeal(BigIdeal & bigIdeal,size_t n,size_t k)170 void generateRookChessIdeal(BigIdeal& bigIdeal, size_t n, size_t k) {
171 if (n == 0 || k == 0)
172 reportError("One side of rook ideal has zero vertices.");
173 if (n > 1000 || k > 1000)
174 reportError("Number of variables in rook ideal too large.");
175 if (n > k)
176 std::swap(n, k);
177
178 size_t varCount = n * k;
179 Ideal ideal(varCount);
180 Term term(varCount);
181
182 vector<char> taken(k);
183 vector<size_t> choice(n);
184 size_t level = 0;
185 while (true) {
186 if (choice[level] == k) {
187 if (level == 0)
188 break;
189 --level;
190 ASSERT(static_cast<bool>(taken[choice[level]]) == true);
191 ASSERT(term[level * k + choice[level]] == 1);
192 taken[choice[level]] = false;
193 term[level * k + choice[level]] = 0;
194 ++choice[level];
195 continue;
196 }
197 if (taken[choice[level]]) {
198 ++choice[level];
199 continue;
200 }
201 taken[choice[level]] = true;
202 ASSERT(term[level * k + choice[level]] == 0);
203 term[level * k + choice[level]] = 1;
204
205 if (level < n - 1) {
206 ++level;
207 choice[level] = 0;
208 } else {
209 ideal.insert(term);
210 ASSERT(static_cast<bool>(taken[choice[level]]) == true);
211 ASSERT(term[level * k + choice[level]] == 1);
212 taken[choice[level]] = false;
213 term[level * k + choice[level]] = 0;
214 ++choice[level];
215 }
216 }
217
218 VarNames names(varCount);
219 bigIdeal.clearAndSetNames(names);
220 bigIdeal.insert(ideal);
221 }
222
generateMatchingIdeal(BigIdeal & bigIdeal,size_t n)223 void generateMatchingIdeal(BigIdeal& bigIdeal, size_t n) {
224 if (n == 0)
225 reportError("Too few variables in matching ideal.");
226 if (n > 1000 || n > 1000)
227 reportError("Number of variables in matching ideal too large.");
228
229 class State {
230 public:
231 State(size_t nodeCount):
232 _notTaken(-1), _nodes(nodeCount), _isAnchor(nodeCount) {
233 std::fill(_nodes.begin(), _nodes.end(), _notTaken);
234 const size_t varCount = nodeCount * (nodeCount - 1) / 2; // n choose 2
235 _term.reset(varCount);
236 }
237
238 void takeEdge(size_t anchor, size_t other) {
239 ASSERT(anchor < _nodes.size());
240 ASSERT(other < _nodes.size());
241 ASSERT(!isTaken(anchor));
242 ASSERT(!isTaken(other));
243 _nodes[anchor] = other;
244 _nodes[other] = anchor;
245 _isAnchor[anchor] = true;
246
247 const size_t var = edgeToVar(anchor, other);
248 ASSERT(_term[var] == 0);
249 _term[var] = 1;
250 }
251
252 void takeNode(size_t node) {
253 ASSERT(node < getNodeCount());
254 ASSERT(!isTaken(node));
255 ASSERT(!isAnchor(node));
256 _nodes[node] = node;
257 }
258
259 void dropNode(size_t node) {
260 ASSERT(node < getNodeCount());
261 ASSERT(isTaken(node));
262 ASSERT(!isAnchor(node));
263 ASSERT(_nodes[node] == node);
264 _nodes[node] = _notTaken;
265 }
266
267 void dropEdge(size_t anchor) {
268 ASSERT(anchor < _nodes.size());
269 ASSERT(isTaken(anchor));
270 ASSERT(isAnchor(anchor));
271 _isAnchor[anchor] = false;
272 const size_t other = _nodes[anchor];
273 _nodes[other] = _notTaken;
274 _nodes[anchor] = _notTaken;
275
276 const size_t var = edgeToVar(anchor, other);
277 ASSERT(_term[var] == 1);
278 _term[var] = 0;
279 }
280
281 size_t getNeighbor(size_t node) const {
282 ASSERT(isTaken(node));
283 return _nodes[node];
284 }
285
286 bool isAnchor(size_t node) const {
287 ASSERT(node < _nodes.size());
288 return _isAnchor[node];
289 }
290
291 bool isTaken(size_t node) const {
292 ASSERT(node < _nodes.size());
293 return _nodes[node] != _notTaken;
294 }
295
296 const Term& getTerm() const {return _term;}
297 size_t getNodeCount() const {return _nodes.size();}
298
299 // Returns static_cast<size_t>(-1) if there are no anchors to the
300 // left (negative direction).
301 size_t getAnchorLeft(size_t node) const {
302 ASSERT(node <= getNodeCount());
303 for (--node; node != static_cast<size_t>(-1); --node)
304 if (isAnchor(node))
305 break;
306 return node;
307 }
308
309 // returns getNodeCount() if all are taken to right (positive
310 // direction).
311 size_t getNotTakenRight(size_t node) const {
312 ASSERT(node < getNodeCount());
313 for (++node; node < getNodeCount(); ++node)
314 if (!isTaken(node))
315 break;
316 return node;
317 }
318
319 private:
320 size_t edgeToVar(size_t a, size_t b) const {
321 ASSERT(a != b);
322 ASSERT(a < _nodes.size());
323 ASSERT(b < _nodes.size());
324 if (a < b)
325 std::swap(a, b);
326 const size_t var = (a * (a - 1)) / 2 + b;
327 ASSERT(var < _term.getVarCount());
328 return var;
329 }
330
331 const size_t _notTaken; // cannot be static when local class
332 std::vector<size_t> _nodes;
333 std::vector<size_t> _isAnchor;
334 Term _term;
335 };
336
337 State state(n);
338 Ideal ideal(state.getTerm().getVarCount());
339 size_t node = 0;
340
341 // one node cannot be used in maximum matching if odd number of nodes.
342 size_t notUsed = state.getNodeCount();
343 if (state.getNodeCount() % 2 == 1) {
344 notUsed = 0;
345 state.takeNode(notUsed);
346 ++node;
347 }
348 while (true) {
349 if (node == static_cast<size_t>(-1)) {
350 if (notUsed < state.getNodeCount()) {
351 state.dropNode(notUsed);
352 ++notUsed;
353 }
354 if (notUsed == state.getNodeCount())
355 break;
356 state.takeNode(notUsed);
357 node = 0; // start over with next node unused
358 }
359 ASSERT(node <= state.getNodeCount());
360 if (node == state.getNodeCount()) {
361 ideal.insert(state.getTerm());
362 node = state.getAnchorLeft(node);
363 } else if (!state.isTaken(node)) {
364 const size_t neighbor = state.getNotTakenRight(node);
365 if (neighbor == state.getNodeCount()) {
366 node = state.getAnchorLeft(node);
367 } else {
368 state.takeEdge(node, neighbor);
369 node = state.getNotTakenRight(neighbor);
370 }
371 } else {
372 ASSERT(state.isTaken(node));
373 ASSERT(state.isAnchor(node));
374 const size_t neighbor = state.getNeighbor(node);
375 const size_t nextNeighbor = state.getNotTakenRight(neighbor);
376 state.dropEdge(node);
377 if (nextNeighbor == state.getNodeCount()) {
378 node = state.getAnchorLeft(node);
379 } else {
380 state.takeEdge(node, nextNeighbor);
381 node = state.getNotTakenRight(node);
382 }
383 }
384 }
385
386 VarNames names(state.getTerm().getVarCount());
387 bigIdeal.clearAndSetNames(names);
388 bigIdeal.insert(ideal);
389 }
390
generateRandomEdgeIdeal(BigIdeal & bigIdeal,size_t variableCount,size_t generatorCount)391 bool generateRandomEdgeIdeal
392 (BigIdeal& bigIdeal, size_t variableCount, size_t generatorCount) {
393 Ideal ideal(variableCount);
394 Term term(variableCount);
395
396 size_t generatorsToGo = generatorCount;
397 size_t triesLeft = (size_t)4 * 1000 * 1000;
398 while (generatorsToGo > 0 && triesLeft > 0) {
399 --triesLeft;
400
401 size_t a = rand() % variableCount;
402 size_t b = rand() % variableCount;
403 if (a == b)
404 continue;
405
406 term[a] = 1;
407 term[b] = 1;
408
409 if (ideal.isIncomparable(term)) {
410 ideal.insert(term);
411 --generatorsToGo;
412 }
413
414 term[a] = 0;
415 term[b] = 0;
416
417 --triesLeft;
418 }
419
420 VarNames names(variableCount);
421 bigIdeal.clearAndSetNames(names);
422 bigIdeal.insert(ideal);
423
424 return generatorsToGo == 0;
425 }
426
427
generateRandomIdeal(BigIdeal & bigIdeal,size_t exponentRange,size_t variableCount,size_t generatorCount)428 bool generateRandomIdeal(BigIdeal& bigIdeal,
429 size_t exponentRange,
430 size_t variableCount,
431 size_t generatorCount) {
432 Ideal ideal(variableCount);
433 Term term(variableCount);
434
435 size_t generatorsToGo = generatorCount;
436 size_t triesLeft = (size_t)4 * 1000 * 1000;
437 while (generatorsToGo > 0 && triesLeft > 0) {
438 --triesLeft;
439
440 for (size_t var = 0; var < variableCount; ++var) {
441 term[var] = rand();
442 if (exponentRange != numeric_limits<size_t>::max())
443 term[var] %= exponentRange + 1;
444 }
445
446 if (ideal.isIncomparable(term)) {
447 ideal.insert(term);
448 --generatorsToGo;
449 }
450 }
451
452 VarNames names(variableCount);
453 bigIdeal.clearAndSetNames(names);
454 bigIdeal.insert(ideal);
455
456 return generatorsToGo == 0;
457 }
458
generateRandomFrobeniusInstance(vector<mpz_class> & instance,size_t entryCount,const mpz_class & maxEntry)459 void generateRandomFrobeniusInstance(vector<mpz_class>& instance,
460 size_t entryCount,
461 const mpz_class& maxEntry) {
462 ASSERT(entryCount >= 1);
463 ASSERT(maxEntry >= 1);
464
465 gmp_randclass random(gmp_randinit_default);
466
467 /// @todo: preserve state across calls.
468 random.seed((unsigned long)time(0) +
469 #ifdef __GNUC__ // Only GCC defines this macro.
470 (unsigned long)getpid() +
471 #endif
472 (unsigned long)clock());
473
474 instance.resize(entryCount);
475
476 // Populate instance with random numbers in range [1,maxEntry].
477 for (size_t i = 0; i < entryCount; ++i)
478 instance[i] = random.get_z_range(maxEntry) + 1;
479
480 // Calculate greatest common divisor of instance.
481 mpz_class gcd = instance[0];
482 for (size_t i = 1; i < entryCount; ++i)
483 mpz_gcd(gcd.get_mpz_t(), gcd.get_mpz_t(), instance[i].get_mpz_t());
484
485 // Ensure that instance are relatively prime.
486 instance.front() /= gcd;
487
488 sort(instance.begin(), instance.end());
489 }
490