1 /*
2
3 This file is part of the Maude 2 interpreter.
4
5 Copyright 1997-2012 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 class VariantFolder.
25 //
26
27 // utility stuff
28 #include "macros.hh"
29 #include "vector.hh"
30
31 // forward declarations
32 #include "interface.hh"
33 #include "core.hh"
34 //#include "variable.hh"
35
36 // interface class definitions
37 #include "symbol.hh"
38 #include "dagNode.hh"
39 #include "term.hh"
40 #include "lhsAutomaton.hh"
41 #include "subproblem.hh"
42
43 // core class definitions
44 #include "rewritingContext.hh"
45 #include "subproblemAccumulator.hh"
46 #include "variableInfo.hh"
47
48 // higher class definitions
49 #include "variantFolder.hh"
50
VariantFolder()51 VariantFolder::VariantFolder()
52 {
53 currentVariantIndex = -1;
54 }
55
~VariantFolder()56 VariantFolder::~VariantFolder()
57 {
58 FOR_EACH_CONST(i, RetainedVariantMap, mostGeneralSoFar)
59 delete i->second;
60 }
61
62 void
markReachableNodes()63 VariantFolder::markReachableNodes()
64 {
65 FOR_EACH_CONST(i, RetainedVariantMap, mostGeneralSoFar)
66 {
67 Vector<DagNode*>& variant = i->second->variant;
68 FOR_EACH_CONST(j, Vector<DagNode*>, variant)
69 (*j)->mark();
70 }
71 }
72
73 bool
insertVariant(const Vector<DagNode * > & variant,int index,int parentIndex)74 VariantFolder::insertVariant(const Vector<DagNode*>& variant, int index, int parentIndex)
75 {
76 //cerr << " i" << index << "p" << parentIndex;
77 //
78 // First we check if it is subsumed by one of the existing variants.
79 //
80 FOR_EACH_CONST(i, RetainedVariantMap, mostGeneralSoFar)
81 {
82 if (subsumes(i->second, variant))
83 {
84 DebugAdvisory("new variant subsumed");
85 //cout << "!!!!!!!" << index << "subsumed by " << i->first << endl;
86 return false;
87 }
88 }
89 DebugAdvisory("new variant added");
90 //
91 // Compile a set of matching automata for this variant.
92 //
93 RetainedVariant* newVariant = new RetainedVariant(variant);
94 //
95 // Compute ancestor set.
96 //
97 set<int> ancestors;
98 for (int i = parentIndex; i != NONE; )
99 {
100 ancestors.insert(i);
101 RetainedVariantMap::const_iterator j = mostGeneralSoFar.find(i);
102 Assert(j != mostGeneralSoFar.end(), "couldn't find variant with index " << i);
103 i = j->second->parentIndex;
104 }
105 //
106 // See if this variant can evict an existing variant.
107 //
108 set<int> existingVariantsSubsumed;
109 RetainedVariantMap::iterator i = mostGeneralSoFar.begin();
110 while (i != mostGeneralSoFar.end())
111 {
112 RetainedVariantMap::iterator next = i;
113 ++next;
114
115 if (ancestors.find(i->first) == ancestors.end()) // can't mess with ancestors of new variant
116 {
117 RetainedVariant* potentialVictim = i->second;
118 if (existingVariantsSubsumed.find(potentialVictim->parentIndex) != existingVariantsSubsumed.end())
119 {
120 //
121 // Our parent was subsumed so we are also subsumed.
122 //
123 DebugAdvisory("new variant evicted descendent of an older variant " << i->first);
124 /*
125 cerr << "!!!!!!! new variant " << index << endl;
126 FOR_EACH_CONST(k, Vector<DagNode*>, variant)
127 cerr << *k << endl;
128 cerr << " evicted " << i->first << endl;
129 potentialVictim->dump();
130 cerr << " via parent " << potentialVictim->parentIndex << endl;
131 */
132 existingVariantsSubsumed.insert(i->first);
133 delete potentialVictim;
134 mostGeneralSoFar.erase(i);
135 }
136 else if (subsumes(newVariant, potentialVictim->variant))
137 {
138 //
139 // Direct subsumption by new variant.
140 //
141 DebugAdvisory("new variant evicted an older variant " << i->first);
142 /*
143 cerr << "!!!!!!! new variant " << index << endl;
144 FOR_EACH_CONST(k, Vector<DagNode*>, variant)
145 cerr << *k << endl;
146 cerr << " evicted " << i->first << endl;
147 potentialVictim->dump();
148 */
149 existingVariantsSubsumed.insert(i->first);
150 delete potentialVictim;
151 mostGeneralSoFar.erase(i);
152 }
153 }
154
155 i = next;
156 }
157 //
158 // Add to the mostGeneralSoFar collection of variants.
159 //
160 //cerr << "*";
161 newVariant->parentIndex = parentIndex;
162 newVariant->layerNumber = 0;
163 if (parentIndex != NONE)
164 {
165 RetainedVariantMap::iterator parentVariant = mostGeneralSoFar.find(parentIndex);
166 Assert(parentVariant != mostGeneralSoFar.end(), "parent " << parentIndex << " of variant " << index << " has been deleted");
167 newVariant->layerNumber = parentVariant->second->layerNumber + 1;
168 }
169
170 mostGeneralSoFar.insert(RetainedVariantMap::value_type(index, newVariant));
171 return true;
172 }
173
174 /*
175 const Vector<DagNode*>*
176 VariantFolder::getNextSurvivingVariant(int& nrFreeVariables, bool& moreInLayer)
177 {
178 //
179 // We allow variants to be extracted, even though we may not be finished inserting new variants.
180 // This means that some of the variants we return may later be evicted by a subsequent insert().
181 //
182 // Between calls we keep track of current and next variant by their internal index numbers rather
183 // than iterators into mostGeneralSoFar. This is because in prinicple, the element pointed to by
184 // an iterator might vanish due to subsumption.
185 // Though even here we have a problem since we do expect to be able to access the variant at
186 // nextVariantIndex.
187 //
188 RetainedVariantMap::const_iterator currentVariant;
189
190 if (currentVariantIndex == NONE)
191 {
192 //
193 // Starting so need to find the first variant.
194 //
195 RetainedVariantMap::const_iterator currentVariant = mostGeneralSoFar.upper_bound(currentVariantIndex); // might simplify this
196 if (currentVariant == mostGeneralSoFar.end())
197 return 0; // no variants available so change nothing
198 currentVariantIndex = currentVariant->first;
199 }
200 else
201 {
202 //
203 // If there is a next variant, we already found it.
204 //
205 if (nextVariantIndex == NONE)
206 return 0; // no next variant
207 currentVariantIndex = nextVariantIndex;
208 RetainedVariantMap::const_iterator currentVariant = mostGeneralSoFar.find(currentVariantIndex); // extra lookup
209 }
210 //
211 // Now we need to find the next variant if there is one, so we know if there is moreInLayer.
212 //
213 RetainedVariantMap::const_iterator nextVariant = mostGeneralSoFar.upper_bound(currentVariantIndex); // look ahead
214 if (nextVariant == mostGeneralSoFar.end())
215 {
216 nextVariantIndex = NONE;
217 moreInLayer = false;
218 }
219 else
220 {
221 nextVariantIndex = nextVariant->first;
222 moreInLayer = true;
223 }
224
225 nrFreeVariables = currentVariant->second->nrFreeVariables;
226 return &(currentVariant->second->variant);
227 }
228 */
229
230
231 const Vector<DagNode*>*
getNextSurvivingVariant(int & nrFreeVariables,int * variantNumber,int * parentNumber,bool * moreInLayer)232 VariantFolder::getNextSurvivingVariant(int& nrFreeVariables, int* variantNumber, int* parentNumber, bool* moreInLayer)
233 {
234 RetainedVariantMap::const_iterator nextVariant = mostGeneralSoFar.upper_bound(currentVariantIndex);
235 if (nextVariant == mostGeneralSoFar.end())
236 return 0; // no variants available so change nothing
237
238 currentVariantIndex = nextVariant->first;
239 nrFreeVariables = nextVariant->second->nrFreeVariables;
240 //
241 // Optional information - non-null pointers means caller wants this information
242 // returned.
243 //
244 if (variantNumber)
245 *variantNumber = currentVariantIndex; // internal number for current variant
246 if (parentNumber)
247 *parentNumber = nextVariant->second->parentIndex; // internal number for variant's parent (or NONE if root)
248 if (moreInLayer)
249 {
250 //
251 // Flag to indicate whether next call to getNextSurvivingVariant()
252 // will return another variant in the same layer.
253 //
254 *moreInLayer = false;
255 RetainedVariantMap::const_iterator nextNextVariant = mostGeneralSoFar.upper_bound(currentVariantIndex);
256 if (nextNextVariant != mostGeneralSoFar.end() &&
257 nextNextVariant->second->layerNumber == nextVariant->second->layerNumber)
258 *moreInLayer = true;
259 }
260
261 return &(nextVariant->second->variant);
262 }
263
264 const Vector<DagNode*>*
getLastReturnedVariant(int & nrFreeVariables,int * parentNumber,bool * moreInLayer)265 VariantFolder::getLastReturnedVariant(int& nrFreeVariables, int* parentNumber, bool* moreInLayer)
266 {
267 RetainedVariantMap::const_iterator currentVariant = mostGeneralSoFar.find(currentVariantIndex);
268 Assert(currentVariant != mostGeneralSoFar.end(), "current variant purged");
269 nrFreeVariables = currentVariant->second->nrFreeVariables;
270 //
271 // Optional information - non-null pointers means caller wants this information
272 // returned.
273 //
274 if (parentNumber)
275 *parentNumber = currentVariant->second->parentIndex; // internal number for variant's parent (or NONE if root)
276 if (moreInLayer)
277 {
278 //
279 // Flag to indicate whether next call to getNextSurvivingVariant()
280 // will return another variant in the same layer.
281 //
282 *moreInLayer = false;
283 RetainedVariantMap::const_iterator nextVariant = mostGeneralSoFar.upper_bound(currentVariantIndex);
284 if (nextVariant != mostGeneralSoFar.end() &&
285 nextVariant->second->layerNumber == currentVariant->second->layerNumber)
286 *moreInLayer = true;
287 }
288 return &(currentVariant->second->variant);
289 }
290
291 bool
subsumes(const RetainedVariant * retainedVariant,const Vector<DagNode * > & variant)292 VariantFolder::subsumes(const RetainedVariant* retainedVariant, const Vector<DagNode*>& variant)
293 {
294 int nrDagsToCheck = variant.size();
295 int nrDagsInRetainedVariant = retainedVariant->matchingAutomata.size();
296 if (nrDagsToCheck != nrDagsInRetainedVariant)
297 return false; // different sized variants are trivially incomparable
298
299 MemoryCell::okToCollectGarbage(); // otherwise we have huge accumulation of junk from matching
300 //
301 // We check if retained variant is at least as general as a new variant.
302 //
303 int nrVariablesToUse = retainedVariant->nrVariables;
304 int nrSlotsToAllocate = nrVariablesToUse;
305 if (nrSlotsToAllocate == 0)
306 nrSlotsToAllocate = 1; // substitutions subject to clear() must always have at least one slot
307 RewritingContext matcher(nrSlotsToAllocate);
308 matcher.clear(nrVariablesToUse);
309 SubproblemAccumulator subproblems;
310
311 for (int i = nrDagsToCheck - 1; i >= 0; --i)
312 {
313 Subproblem* subproblem;
314
315 DebugAdvisory("Considering dag " << i);
316 DebugAdvisory("Pattern has " << retainedVariant->variant[i]);
317 DebugAdvisory("Pattern term is " << retainedVariant->terms[i]);
318 DebugAdvisory("Subject has " << variant[i]);
319
320 if (retainedVariant->matchingAutomata[i]->match(variant[i], matcher, subproblem))
321 subproblems.add(subproblem);
322 else
323 {
324 DebugAdvisory("non subsumption declared on dag " << i);
325 return false;
326 }
327 }
328 Subproblem* final = subproblems.extractSubproblem();
329 if (final == 0)
330 {
331 DebugAdvisory("no subproblem so declaring subsumption");
332 return true;
333 }
334 bool result = final->solve(true, matcher);
335 DebugAdvisory("solve result = " << result);
336 delete final;
337 return result;
338 }
339
RetainedVariant(const Vector<DagNode * > original)340 VariantFolder::RetainedVariant::RetainedVariant(const Vector<DagNode*> original)
341 : variant(original),
342 terms(original.size()),
343 matchingAutomata(original.size())
344 {
345 VariableInfo variableInfo; // does this need to be retained?
346
347 int nrDags = original.size();
348 for (int i = 0; i < nrDags; ++i)
349 {
350 DagNode* d = original[i];
351 Term* t = d->symbol()->termify(d);
352 t = t->normalize(true); // needed even though we should have a normal form, in order to set hash value
353 t->indexVariables(variableInfo);
354 t->symbol()->fillInSortInfo(t);
355 t->analyseCollapses();
356 terms[i] = t;
357 }
358
359 nrFreeVariables = variableInfo.getNrRealVariables();
360
361 NatSet boundUniquely;
362 bool subproblemLikely;
363 //
364 // Variant dags are compiled and matched in reverse order because the term part of the variant
365 // will be at the end, and it is most likely to cause early match failure.
366 //
367 for (int i = nrDags - 1; i >= 0; --i)
368 {
369 Term* t = terms[i];
370 //
371 // Accumuate the context variables for this term.
372 //
373 for (int j = 0; j < nrDags; ++j)
374 {
375 if (j != i)
376 t->addContextVariables(terms[j]->occursBelow()); // variables from other terms are in our context
377 }
378 t->determineContextVariables();
379 t->insertAbstractionVariables(variableInfo);
380
381 DebugAdvisory("Compiling " << t);
382 matchingAutomata[i] = t->compileLhs(false, variableInfo, boundUniquely, subproblemLikely);
383 //matchingAutomata[i]->dump(cerr, variableInfo);
384 }
385
386 nrVariables = variableInfo.getNrRealVariables(); // may also have some abstraction variables
387 }
388
~RetainedVariant()389 VariantFolder::RetainedVariant::~RetainedVariant()
390 {
391 int nrTerms = terms.size();
392 for (int i = 0; i < nrTerms; ++i)
393 {
394 delete matchingAutomata[i];
395 terms[i]->deepSelfDestruct();
396 }
397 }
398
399 void
dump()400 VariantFolder::RetainedVariant::dump()
401 {
402 int nrTerms = terms.size();
403 for (int i = 0; i < nrTerms; ++i)
404 {
405 cerr << terms[i] << endl;
406 }
407 }
408