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