1 /*
2
3 This file is part of the Maude 2 interpreter.
4
5 Copyright 1997-2003 SRI International, Menlo Park, CA 94025, USA.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21 */
22
23 //
24 // Implementation for abstract class SortTable.
25 //
26 #include <map>
27
28 // utility stuff
29 #include "macros.hh"
30 #include "vector.hh"
31 #include "indent.hh"
32
33 // forward declarations
34 #include "interface.hh"
35 #include "core.hh"
36
37 // interface class definitions
38 #include "term.hh"
39
40 // core class definitions
41 #include "sortBdds.hh"
42 #include "sortTable.hh"
43
44 #ifdef COMPILER
45 #include "compilationContext.hh"
46 #endif
47
48 #include "ctorDiagram.cc"
49 #include "sortErrorAnalysis.cc"
50
51 /*
52 void
53 SortTable::panic() const // HACK
54 {
55 cerr << ((Symbol*)(this)) << endl;
56 ((Symbol*)(this))->dump(cerr, 0);
57 ((SortTable*)(this))->dumpSortDiagram(cerr, 0);
58 }
59 */
60
SortTable(int arity)61 SortTable::SortTable(int arity)
62 : nrArgs(arity)
63 {
64 singleNonErrorSort = 0;
65 ctorStatus = 0;
66 }
67
68 bool
domainSubsumes(int subsumer,int victim) const69 SortTable::domainSubsumes(int subsumer, int victim) const
70 {
71 const Vector<Sort*>& s = opDeclarations[subsumer].getDomainAndRange();
72 const Vector<Sort*>& v = opDeclarations[victim].getDomainAndRange();
73 for (int i = 0; i < nrArgs; ++i)
74 {
75 if (!(leq(v[i], s[i])))
76 return false;
77 }
78 return true;
79 }
80
81 void
computeMaximalOpDeclSetTable()82 SortTable::computeMaximalOpDeclSetTable()
83 {
84 //
85 // Fill out maximalOpDeclSetTable, which for each range sort gives the set
86 // of operator declaration whose range is less than that sort and whose
87 // domain is not subsumed by some other declaration in the set.
88 //
89 const ConnectedComponent* range = rangeComponent();
90 int nrSorts = range->nrSorts();
91 maximalOpDeclSetTable.resize(nrSorts);
92 int nrDeclarations = opDeclarations.length();
93 //
94 // For each range sort.
95 //
96 for (int i = 0; i < nrSorts; ++i)
97 {
98 NatSet& opDeclSet = maximalOpDeclSetTable[i];
99 const Sort* target = range->sort(i);
100 //
101 // For each declaration.
102 //
103 for (int j = 0; j < nrDeclarations; ++j)
104 {
105 if (leq(opDeclarations[j].getDomainAndRange()[nrArgs], target))
106 {
107 //
108 // For each previous declaration.
109 //
110 for (int k = 0; k < j; ++k)
111 {
112 if (opDeclSet.contains(k))
113 {
114 if(domainSubsumes(k, j))
115 goto nextDecl;
116 else if (domainSubsumes(j, k))
117 opDeclSet.subtract(k);
118 }
119 }
120 opDeclSet.insert(j);
121 }
122 nextDecl:
123 ;
124 }
125 }
126 }
127
128 void
compileOpDeclarations()129 SortTable::compileOpDeclarations()
130 {
131 #ifndef NO_ASSERT
132 int nrDeclarations = opDeclarations.length();
133 Assert(nrDeclarations > 0, "no operator declarations");
134 #endif
135
136 componentVector.expandTo(nrArgs + 1);
137 for (int i = 0; i <= nrArgs; i++)
138 {
139 ConnectedComponent* c = (opDeclarations[0].getDomainAndRange()[i])->component();
140 #ifndef NO_ASSERT
141 //
142 // Check that components really do agree for subsort overloaded
143 // operator declarations.
144 //
145 for (int j = 1; j < nrDeclarations; j++)
146 {
147 Assert(c == (opDeclarations[j].getDomainAndRange()[i])->component(),
148 "Sort declarations for operator " <<
149 static_cast<Symbol*>(this) << // hack
150 " disagree on the sort component for argument " << i + 1);
151 }
152 #endif
153 componentVector[i] = c;
154 }
155 buildSortDiagram();
156 if (ctorStatus == IS_COMPLEX)
157 buildCtorDiagram();
158 #ifdef DUMP
159 // dumpSortDiagram(cout, 0);
160 #endif
161 }
162
163 bool
kindLevelDeclarationsOnly() const164 SortTable::kindLevelDeclarationsOnly() const
165 {
166 FOR_EACH_CONST(i, Vector<OpDeclaration>, opDeclarations)
167 {
168 if (i->getDomainAndRange()[nrArgs]->index() != Sort::KIND)
169 return false;
170 }
171 return true;
172 }
173
174 bool
canProduceErrorSort() const175 SortTable::canProduceErrorSort() const
176 {
177 if (specialSortHandling())
178 return false; // optimistic - derived class must overide if it wants to be bad!
179 if (nrArgs == 0)
180 return sortDiagram[0] == 0;
181 NatSet currentStates;
182 currentStates.insert(0);
183 for (int i = 0; i < nrArgs; i++)
184 {
185 ConnectedComponent* component = componentVector[i];
186 int index = component->errorFree() ? component->nrMaximalSorts() : 0;
187 NatSet nextStates;
188 const NatSet::const_iterator e = currentStates.end();
189 for (NatSet::const_iterator j = currentStates.begin(); j != e; ++j)
190 {
191 int state = *j;
192 int k = index;
193 do
194 nextStates.insert(traverse(state, k));
195 while (--k > 0);
196 }
197 currentStates.swap(nextStates);
198 }
199 return currentStates.contains(Sort::ERROR_SORT);
200 }
201
202 void
finalizeSortInfo()203 SortTable::finalizeSortInfo()
204 {
205 // For derived classes that don't do any sort constraint dependent
206 // compile time sort calculations.
207 }
208
209 bool
partiallySubsumes(int subsumer,int victim,int argNr)210 SortTable::partiallySubsumes(int subsumer, int victim, int argNr)
211 {
212 const Vector<Sort*>& s = opDeclarations[subsumer].getDomainAndRange();
213 const Vector<Sort*>& v = opDeclarations[victim].getDomainAndRange();
214 if (!(leq(s[nrArgs], v[nrArgs])))
215 return false;
216 for (int i = argNr; i < nrArgs; i++)
217 {
218 if (!(leq(v[i], s[i])))
219 return false;
220 }
221 return true;
222 }
223
224 void
minimize(NatSet & alive,int argNr)225 SortTable::minimize(NatSet& alive, int argNr)
226 {
227 //
228 // We don't use NatSet iterators because alive is being modified.
229 //
230 // If two declarations mutually subsume one another, the earlier one
231 // removes the later one.
232 //
233 if (!(alive.empty()))
234 {
235 int min = alive.min();
236 int max = alive.max();
237 for (int i = min; i <= max; i++)
238 {
239 if (alive.contains(i))
240 {
241 for (int j = min; j <= max; j++)
242 {
243 if (j != i && alive.contains(j) && partiallySubsumes(i, j, argNr))
244 alive.subtract(j);
245 }
246 }
247 }
248 }
249 }
250
251 void
buildSortDiagram()252 SortTable::buildSortDiagram()
253 {
254 Vector<NatSet> currentStates(1);
255 NatSet& all = currentStates[0];
256 int nrDeclarations = opDeclarations.length();
257 for (int i = nrDeclarations - 1; i >= 0; i--)
258 all.insert(i); // insert in reverse order for efficiency
259 if (nrArgs == 0)
260 {
261 sortDiagram.expandTo(1);
262 bool unique;
263 int sortIndex = findMinSortIndex(all, unique);
264 WarningCheck(unique, "sort declarations for constant " << QUOTE(safeCast(Symbol*, this)) <<
265 " do not have an unique least sort.");
266 sortDiagram[0] = sortIndex;
267 singleNonErrorSort = componentVector[0]->sort(sortIndex);
268 return;
269 }
270 enum SpecialSortIndices
271 {
272 UNINITIALIZED = 0,
273 IMPOSSIBLE = -1
274 };
275 int singleNonErrorSortIndex = UNINITIALIZED;
276 Vector<NatSet> nextStates;
277 int currentBase = 0;
278 set<int> badTerminals;
279 //
280 // For each argument.
281 //
282 for (int i = 0; i < nrArgs; i++)
283 {
284 const ConnectedComponent* component = componentVector[i];
285 int nrSorts = component->nrSorts();
286 int nrCurrentStates = currentStates.length();
287
288 int nextBase = currentBase + nrSorts * nrCurrentStates;
289 sortDiagram.expandTo(nextBase);
290 int nrNextSorts = (i == nrArgs - 1) ? 0 : componentVector[i + 1]->nrSorts();
291 //
292 // For each sort that the argument might have.
293 //
294 for (int j = 0; j < nrSorts; j++)
295 {
296 Sort* s = component->sort(j);
297 //
298 // Compute the set of declarations that are viable with this argument having this sort.
299 //
300 NatSet viable;
301 for (int k = 0; k < nrDeclarations; k++)
302 {
303 if (leq(s, opDeclarations[k].getDomainAndRange()[i]))
304 viable.insert(k);
305 }
306 //
307 // For each current state, compute a new state or a sort.
308 //
309 for (int k = 0; k < nrCurrentStates; k++)
310 {
311 NatSet nextState(viable);
312 nextState.intersect(currentStates[k]);
313 int index = currentBase + k * nrSorts + j;
314 if (nrNextSorts == 0)
315 {
316 //
317 // Final argument case - we compute a sort.
318 //
319 bool unique;
320 int sortIndex = findMinSortIndex(nextState, unique);
321 sortDiagram[index] = sortIndex;
322 if (!unique)
323 badTerminals.insert(index);
324 if (sortIndex > 0)
325 {
326 if (singleNonErrorSortIndex == UNINITIALIZED)
327 singleNonErrorSortIndex = sortIndex;
328 else if (singleNonErrorSortIndex > 0 &&
329 singleNonErrorSortIndex != sortIndex)
330 singleNonErrorSortIndex = IMPOSSIBLE;
331 }
332 }
333 else
334 {
335 //
336 // Nonfinal argument case - we compute a new state by discarding
337 // redundant declarations and getting a state number for it.
338 //
339 minimize(nextState, i + 1);
340 sortDiagram[index] =
341 nextBase + nrNextSorts * findStateNumber(nextStates, nextState);
342 }
343 }
344 }
345 currentStates.swap(nextStates);
346 nextStates.contractTo(0);
347 currentBase = nextBase;
348 }
349 if (singleNonErrorSortIndex > 0)
350 singleNonErrorSort = componentVector[nrArgs]->sort(singleNonErrorSortIndex);
351 if (!(badTerminals.empty()))
352 sortErrorAnalysis(true, badTerminals);
353 DebugAdvisory("sort table for " << static_cast<Symbol*>(this) << " has " << sortDiagram.size() << " entries");
354 }
355
356 int
findStateNumber(Vector<NatSet> & stateSet,const NatSet & state)357 SortTable::findStateNumber(Vector<NatSet>& stateSet, const NatSet& state)
358 {
359 int nrStates = stateSet.length();
360 for (int i = 0; i < nrStates; i++)
361 {
362 if (stateSet[i] == state)
363 return i;
364 }
365 stateSet.append(state);
366 return nrStates;
367 }
368
369 int
findMinSortIndex(const NatSet & state,bool & unique)370 SortTable::findMinSortIndex(const NatSet& state, bool& unique)
371 {
372 Sort* minSort = componentVector[nrArgs]->sort(Sort::ERROR_SORT); // start with error sort
373 NatSet infSoFar(minSort->getLeqSorts());
374 FOR_EACH_CONST(i, NatSet, state)
375 {
376 Sort* rangeSort = opDeclarations[*i].getDomainAndRange()[nrArgs];
377 const NatSet& rangeLeqSorts = rangeSort->getLeqSorts();
378 infSoFar.intersect(rangeLeqSorts);
379 //
380 // This test only succeeds if rangeSort is less than or equal to
381 // to the range sorts of the previous declarations in the state.
382 // Thus in the case of a non-preregular operator we break in favor
383 // of the earlier declaration
384 //
385 if (infSoFar == rangeLeqSorts)
386 minSort = rangeSort;
387 }
388 unique = (infSoFar == minSort->getLeqSorts());
389 return minSort->index();
390 }
391
392 void
computeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const393 SortTable::computeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
394 {
395 if (sortDiagram.isNull())
396 return; // operator doesn't use our mechanism
397 //
398 // We take our sort decision diagram and produce a BDD version, encoding each sort index
399 // by a bit vector.
400 //
401 if (nrArgs == 0)
402 {
403 //
404 // Generate constant BDD vector for constant operator.
405 //
406 sortBdds.makeIndexVector(sortBdds.getNrVariables(componentVector[nrArgs]->getIndexWithinModule()),
407 singleNonErrorSort->index(),
408 sortFunctionBdds);
409 return;
410 }
411 //
412 // Calculate and allocate the number of BDD variables we will need to represent the domain sorts.
413 //
414 int nrBddVariablesForDomain = 0;
415 for (int i = 0; i < nrArgs; ++i)
416 nrBddVariablesForDomain += sortBdds.getNrVariables(componentVector[i]->getIndexWithinModule());
417 BddUser::setNrVariables(nrBddVariablesForDomain);
418 //
419 // We have two alternative ways of computing the vector of BDDs to that represent the sort function.
420 //
421 recursiveComputeSortFunctionBdds(sortBdds, sortFunctionBdds);
422 Vector<Bdd> altSortFunctionBdds;
423 linearComputeSortFunctionBdds(sortBdds, altSortFunctionBdds);
424 //
425 // Consistancy test code.
426 //
427 DebugAdvisory("computeSortFunctionBdds() - consistancy check");
428 int nrBdds = altSortFunctionBdds.size();
429 for (int i = 0; i < nrBdds; ++i)
430 {
431 if (altSortFunctionBdds[i] != sortFunctionBdds[i])
432 {
433 DebugAdvisory("computeSortFunctionBdds() : *** computeSortFunctionBdds() recursive =\n" << sortFunctionBdds[i] <<
434 "linear =\n" << altSortFunctionBdds[i]);
435 }
436 }
437 }
438
439 void
recursiveComputeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const440 SortTable::recursiveComputeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
441 {
442 //
443 // Calculate and allocate the number of BDD variables we will need to represent the domain sorts.
444 //
445 int nrBddVariablesForDomain = 0;
446 for (int i = 0; i < nrArgs; ++i)
447 nrBddVariablesForDomain += sortBdds.getNrVariables(componentVector[i]->getIndexWithinModule());
448 BddUser::setNrVariables(nrBddVariablesForDomain);
449
450 BddTable table(sortDiagram.size()); // only target entries actually used
451 // for (int i = 0; i < sortDiagram.size(); ++i)
452 // cerr << sortDiagram[i] << " ";
453 // cerr << endl;
454 computeBddVector(sortBdds, 0, 0, table, 0);
455 sortFunctionBdds.swap(table[0]);
456 }
457
458 void
linearComputeSortFunctionBdds(const SortBdds & sortBdds,Vector<Bdd> & sortFunctionBdds) const459 SortTable::linearComputeSortFunctionBdds(const SortBdds& sortBdds, Vector<Bdd>& sortFunctionBdds) const
460 {
461 //
462 // This is an alternative computation of the same BDDs, directly from the operator declarations.
463 //
464 const ConnectedComponent* rangeComponent = componentVector[nrArgs];
465 int nrBddVariables = sortBdds.getNrVariables(rangeComponent->getIndexWithinModule());
466 //
467 // We start with the constant error sort everywhere function.
468 //
469 sortBdds.makeIndexVector(nrBddVariables, Sort::ERROR_SORT, sortFunctionBdds);
470 //
471 // Because this algorithm breaks in favor of later considered declarations we consider the declarations
472 // in reverse order for consistancy with the standard sort calculation on non-pregular signatures.
473 //
474 for (int i = opDeclarations.length() - 1; i >= 0; --i)
475 {
476 const Vector<Sort*>& opDeclaration = opDeclarations[i].getDomainAndRange();
477 Bdd replaceWithOurRangeSort = bdd_true();
478 //
479 // First require all arguments to have a sort <= than than that of the
480 // corresponding sort in the declaration.
481 //
482 int bddVarNr = 0;
483 for (int j = 0; j < nrArgs; ++j)
484 {
485 Sort* sort = opDeclaration[j];
486 Bdd leqRelation = sortBdds.getRemappedLeqRelation(sort, bddVarNr);
487 replaceWithOurRangeSort = bdd_and(replaceWithOurRangeSort, leqRelation);
488 bddVarNr += sortBdds.getNrVariables(componentVector[j]->getIndexWithinModule());
489 }
490 //
491 // We require that the currently computed sort is not <= our range sort.
492 // This allows our sort to replace the current sort in the incomparable case
493 // and in the > case.
494 //
495 Sort* rangeSort = opDeclaration[nrArgs];
496 Bdd currentLeqOurRange = sortBdds.applyLeqRelation(rangeSort, sortFunctionBdds);
497 replaceWithOurRangeSort = bdd_and(replaceWithOurRangeSort, bdd_not(currentLeqOurRange));
498 //
499 // We now have a BDD that tells us when to replace the currently computed sort
500 // with our range sort. We update the currently computed sort BDD using ite.
501 //
502 Vector<Bdd> ourRangeSort;
503 sortBdds.makeIndexVector(nrBddVariables, rangeSort->index(), ourRangeSort);
504
505 for (int k = 0; k < nrBddVariables; ++k)
506 sortFunctionBdds[k] = bdd_ite(replaceWithOurRangeSort, ourRangeSort[k], sortFunctionBdds[k]);
507 }
508 }
509
510 void
computeBddVector(const SortBdds & sortBdds,int bddVarNr,int argNr,BddTable & table,int nodeNr) const511 SortTable::computeBddVector(const SortBdds& sortBdds,
512 int bddVarNr,
513 int argNr,
514 BddTable& table,
515 int nodeNr) const
516 {
517 // DebugAdvisory("starting computeBddVector(bddVarNr=" << bddVarNr << ", argNr=" << argNr << ", nodeNr=" << nodeNr << ")");
518 Assert(argNr < nrArgs, "bad argNr");
519 BddVector& vec = table[nodeNr];
520 if (!vec.isNull())
521 return;
522 //
523 // We fill out the BDD vector vec to make it correspond to sortDiagram[nodeNr].
524 //
525 const ConnectedComponent* component = componentVector[argNr];
526 int nrBddVariables = sortBdds.getNrVariables(component->getIndexWithinModule());
527 //
528 // We first look at each value of our argument and OR together BDDs for those
529 // that go to the same place.
530 //
531 // DebugAdvisory("starting OR phase");
532 int nrSorts = component->nrSorts();
533 typedef map<int, Bdd> BddMap;
534 BddMap disjuncts;
535 for (int i = 0; i < nrSorts; ++i)
536 {
537 Bdd& disjunct = disjuncts[sortDiagram[nodeNr + i]];
538 Bdd indexBdd = sortBdds.makeIndexBdd(bddVarNr, nrBddVariables, i);
539 //DebugAdvisory("disjunct = " << disjunct.id() << " indexBdd = " << indexBdd.id());
540 disjunct = bdd_or(disjunct, indexBdd /*sortBdds.makeIndexBdd(bddVarNr, nrBddVariables, i)*/);
541 //DebugAdvisory("done disjunct = " << disjunct.id());
542 }
543 //
544 // Now we go through the disjunctions we collected, ANDing them with the
545 // vectors at their targets and OR the products together to form our final
546 // vector.
547 //
548 // DebugAdvisory("starting OR of ANDs phase");
549 int nrBdds = sortBdds.getNrVariables(componentVector[nrArgs]->getIndexWithinModule());
550 vec.resize(nrBdds); // default construct sets all the elements to false
551 FOR_EACH_CONST(i, BddMap, disjuncts)
552 {
553 int target = i->first;
554 if (argNr + 1 == nrArgs)
555 {
556 //
557 // Target is actually the index of a sort.
558 //
559 BddVector t;
560 sortBdds.makeIndexVector(nrBdds, target, t);
561 for (int j = 0; j < nrBdds; ++j)
562 {
563 //DebugAdvisory("vec[j] " << vec[j].id());
564 //DebugAdvisory("t[j] " << t[j].id());
565 vec[j] = bdd_or(vec[j], bdd_and(i->second, t[j]));
566 }
567 }
568 else
569 {
570 computeBddVector(sortBdds, bddVarNr + nrBddVariables, argNr + 1, table, target);
571 BddVector& targetVec = table[target];
572 for (int j = 0; j < nrBdds; ++j)
573 {
574 //DebugAdvisory("vec[j] " << vec[j].id());
575 //DebugAdvisory("targetVec[j] " << targetVec[j].id());
576 vec[j] = bdd_or(vec[j], bdd_and(i->second, targetVec[j]));
577 }
578 }
579 }
580 //DebugAdvisory("done computeBddVector(bddVarNr=" << bddVarNr << ", argNr=" << argNr << ", nodeNr=" << nodeNr << ")");
581 }
582
583 #ifdef COMPILER
584 void
generateSortDiagram(CompilationContext & context) const585 SortTable::generateSortDiagram(CompilationContext& context) const
586 {
587 Vector<int> minimum(0, nrArgs);
588 Vector<int> maximum(0, nrArgs);
589 {
590 int min = 0;
591 int max = 0;
592 minimum.append(0);
593 maximum.append(0);
594 for (int i = 0; i < nrArgs - 1; i++)
595 {
596 int nrSorts = componentVector[i]->nrSorts();
597 int newMin = UNBOUNDED;
598 int newMax = 0;
599 for (int j = min; j < max + nrSorts; j++)
600 {
601 int t = sortDiagram[j];
602 if (t < newMin)
603 newMin = t;
604 if (t > newMax)
605 newMax = t;
606 }
607 min = newMin;
608 max = newMax;
609 minimum.append(min);
610 maximum.append(max);
611 }
612 }
613 int index = static_cast<const Symbol*>(this)->getIndexWithinModule();
614 for (int i = nrArgs - 1; i >= 0; i--)
615 {
616 int nrSorts = componentVector[i]->nrSorts();
617 int min = minimum[i];
618 int max = maximum[i];
619
620 for (int j = min; j <= max; j += nrSorts)
621 {
622 context.head() << "Flags";
623 for (int k = i; k < nrArgs - 1; k++)
624 context.head() << '*';
625 context.head() << " f" << index << '_' << j << "[] = { ";
626 for (int k = 0; k < nrSorts; k++)
627 {
628 if (i == nrArgs - 1)
629 context.head() << '{' << sortDiagram[j + k] << '}';
630 else
631 context.head() << 'f' << index << '_' << sortDiagram[j + k];
632 if (k + 1 < nrSorts)
633 context.head() << ", ";
634 }
635 context.head() << " };\n";
636 }
637 }
638 }
639 #endif
640
641 #ifdef DUMP
642 void
dumpSortDiagram(ostream & s,int indentLevel)643 SortTable::dumpSortDiagram(ostream& s, int indentLevel)
644 {
645 if (specialSortHandling())
646 return; // HACK
647 s << Indent(indentLevel) << "Begin{SortDiagram}";
648 indentLevel += 2;
649 set<int> nodes;
650 nodes.insert(0);
651 ConnectedComponent* range = componentVector[nrArgs];
652 if (nrArgs == 0)
653 {
654 int target = sortDiagram[0];
655 s << '\n' << Indent(indentLevel - 1) << "node 0 -> sort " <<
656 target << " (" << range->sort(target) << ")\n";
657 }
658 for (int i = 0; i < nrArgs; i++)
659 {
660 ConnectedComponent* component = componentVector[i];
661 int nrSorts = component->nrSorts();
662 set<int> nextNodes;
663 FOR_EACH_CONST(j, set<int>, nodes)
664 {
665 int n = *j;
666 s << '\n' << Indent(indentLevel - 1) << "Node " << n <<
667 " (testing argument " << i << ")\n";
668 for (int k = 0; k < nrSorts; k++)
669 {
670 int target = sortDiagram[n + k];
671 s << Indent(indentLevel) << "sort " << k << " (" <<
672 component->sort(k) << ") -> ";
673 if (i == nrArgs - 1)
674 {
675 s << "sort " << target << " (" <<
676 range->sort(target) << ")\n";
677 }
678 else
679 {
680 s << "node " << target << '\n';
681 nextNodes.insert(target);
682 }
683 }
684 }
685 nodes.swap(nextNodes);
686 }
687 s << Indent(indentLevel - 2) << "End{SortDiagram}\n";
688 }
689
690 #endif
691