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 base class DagNode
25 //
26 
27 //	utility stuff
28 #include "macros.hh"
29 #include "vector.hh"
30 #include "indent.hh"
31 
32 //	forward declarations
33 #include "interface.hh"
34 #include "core.hh"
35 #include "variable.hh"
36 
37 //	interface class definitions
38 #include "symbol.hh"
39 #include "binarySymbol.hh"
40 #include "dagNode.hh"
41 #include "subproblem.hh"
42 #include "lhsAutomaton.hh"
43 #include "extensionInfo.hh"
44 
45 //	core class definitions
46 #include "substitution.hh"
47 #include "rewritingContext.hh"
48 #include "sortCheckSubproblem.hh"
49 #include "dagArgumentIterator.hh"
50 #include "module.hh"
51 #include "rootContainer.hh"
52 #include "sortBdds.hh"
53 #include "unificationContext.hh"
54 #include "equation.hh"
55 
56 //	variable class definitions
57 #include "variableDagNode.hh"
58 
59 bool
checkSort(const Sort * boundSort,Subproblem * & returnedSubproblem)60 DagNode::checkSort(const Sort* boundSort, Subproblem*& returnedSubproblem)
61 {
62   returnedSubproblem = 0;
63   if (getSortIndex() != Sort::SORT_UNKNOWN)
64     return leq(boundSort);
65   topSymbol->computeBaseSort(this);
66   if (leq(boundSort))
67     {
68       if (!(topSymbol->sortConstraintFree()))
69 	setSortIndex(Sort::SORT_UNKNOWN);
70     }
71   else
72     {
73       if (topSymbol->sortConstraintFree())
74 	return false;
75       setSortIndex(Sort::SORT_UNKNOWN);
76       returnedSubproblem = new SortCheckSubproblem(this, boundSort);
77     }
78   return true;
79 }
80 
81 bool
checkSort(const Sort * boundSort,RewritingContext & context)82 DagNode::checkSort(const Sort* boundSort, RewritingContext& context)
83 {
84   if (getSortIndex() == Sort::SORT_UNKNOWN)
85     {
86       topSymbol->computeBaseSort(this);
87       if (leq(boundSort))
88 	{
89 	  if (!(topSymbol->sortConstraintFree()))
90 	    setSortIndex(Sort::SORT_UNKNOWN);
91 	  return true;
92 	}
93       else
94 	{
95 	  if (topSymbol->sortConstraintFree())
96 	    return false;
97 	  RewritingContext* local = context.makeSubcontext(this, RewritingContext::SORT_EVAL);
98 	  topSymbol->constrainToSmallerSort(this, *local);
99 	  context.addInCount(*local);
100 	  delete local;
101 	}
102     }
103   return leq(boundSort);
104 }
105 
106 bool
matchVariable(int index,const Sort * sort,bool copyToAvoidOverwriting,Substitution & solution,Subproblem * & returnedSubproblem,ExtensionInfo * extensionInfo)107 DagNode::matchVariable(int index,
108 		       const Sort* sort,
109 		       bool copyToAvoidOverwriting,
110 		       Substitution& solution,
111 		       Subproblem*& returnedSubproblem,
112 		       ExtensionInfo* extensionInfo)
113 {
114   if (extensionInfo != 0)
115     return matchVariableWithExtension(index, sort, solution, returnedSubproblem, extensionInfo);
116   DagNode* d = solution.value(index);
117   if (d == 0)
118     {
119       if (checkSort(sort, returnedSubproblem))
120         {
121           solution.bind(index, copyToAvoidOverwriting ? makeClone() : this);
122           return true;
123         }
124     }
125   else
126     {
127       if (compare(d) == 0)
128         {
129           returnedSubproblem = 0;
130           return true;
131         }
132     }
133   return false;
134 }
135 
136 ExtensionInfo*
makeExtensionInfo()137 DagNode::makeExtensionInfo()
138 {
139   return 0;
140 }
141 
142 //
143 //	Dummy functions to allow linking of theories which don't use extension.
144 //
145 
146 bool
matchVariableWithExtension(int,const Sort *,Substitution &,Subproblem * &,ExtensionInfo *)147 DagNode::matchVariableWithExtension(int /* index */,
148 				    const Sort* /* sort */,
149 				    Substitution& /* solution */,
150 				    Subproblem*& /* returnedSubproblem */,
151 				    ExtensionInfo* /* extensionInfo */)
152 {
153   CantHappen("Called on subject " << this);
154   return false;
155 }
156 
157 void
partialReplace(DagNode *,ExtensionInfo *)158 DagNode::partialReplace(DagNode* /* replacement */, ExtensionInfo* /* extensionInfo */)
159 {
160   CantHappen("Called on subject " << this);
161 }
162 
163 DagNode*
partialConstruct(DagNode *,ExtensionInfo *)164 DagNode::partialConstruct(DagNode* /* replacement */, ExtensionInfo* /* extensionInfo */)
165 {
166   CantHappen("Called on subject " << this);
167   return 0;
168 }
169 
170 //
171 //	Unification code.
172 //
173 
174 DagNode::ReturnResult
computeBaseSortForGroundSubterms()175 DagNode::computeBaseSortForGroundSubterms()
176 {
177   //
178   //	This is the backstop version for an unimplemented theory. If
179   //	all our subterms are ground we compute our sort and return GROUND
180   //	other we return UNIMPLEMENTED.
181   //
182   for (DagArgumentIterator a(*this); a.valid(); a.next())
183     {
184       switch (a.argument()->computeBaseSortForGroundSubterms())
185 	{
186 	case NONGROUND:
187 	  IssueWarning("Term " << QUOTE(this) <<
188 		       " is non-ground and unification for its top symbol is not currently supported.");
189 	  // fall thru
190 	case UNIMPLEMENTED:
191 	  return UNIMPLEMENTED;
192 	default:
193 	  ;  // to avoid compiler warning
194 	}
195     }
196   topSymbol->computeBaseSort(this);
197   setGround();
198   return GROUND;
199 }
200 
201 bool
computeSolvedForm(DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)202 DagNode::computeSolvedForm(DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
203 {
204   DebugAdvisory("computeSolvedForm() lhs = " << this << " rhs = " << rhs);
205   //
206   //	If we are nonground we dispatch the theory specific algorithm.
207   //
208   if (!isGround())
209     return computeSolvedForm2(rhs, solution, pending);
210   //
211   //	Ground. If the other unificand is nonground, call its algorithm.
212   //
213   if (!(rhs->isGround()))
214     return rhs->computeSolvedForm2(this, solution, pending);
215   //
216   //
217   //	We have two ground terms so we can just compare them without the
218   //	need for an unification algorithm.
219   //
220   return equal(rhs);
221 }
222 
223 bool
computeSolvedForm2(DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)224 DagNode::computeSolvedForm2(DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
225 {
226   DebugAdvisory("DagNode::computeSolvedForm2() " << this << " vs " << rhs);
227 
228   if (isGround())
229     {
230       //
231       //	We handle the case
232       //	  <ground term> =? X
233       //	for unimplmented theories now that variable code no longer binds variables to nonvariables.
234       //
235       if (VariableDagNode* v = dynamic_cast<VariableDagNode*>(rhs))
236 	{
237 	  VariableDagNode* repVar = v->lastVariableInChain(solution);
238 	  if (DagNode* value = solution.value(repVar->getIndex()))
239 	    return computeSolvedForm(value, solution, pending);
240 	  else
241 	    {
242 	      solution.unificationBind(repVar, this);  // bind variable to unpurified ground term
243 	      return true;
244 	    }
245 	}
246     }
247   //
248   //	this should be ground since computeBaseSortForGroundSubterms() screens for variables below unimplemented theories.
249   //	If rhs is ground computeSolvedForm() should have solved the problem.
250   //	If rhs is nonground then its theory should have been given the problem.
251   //	And we just handle the variable rhs case above.
252   //
253   CantHappen("this = " << this << "   rhs = " << rhs);
254   //IssueWarning("Unification modulo the theory of operator " << QUOTE(this->topSymbol) << " is not currently supported.");
255   return false;
256 }
257 
258 void
computeGeneralizedSort(const SortBdds & sortBdds,const Vector<int> & realToBdd,Vector<Bdd> & generalizedSort)259 DagNode::computeGeneralizedSort(const SortBdds& sortBdds,
260 				const Vector<int>& realToBdd,
261 				Vector<Bdd>& generalizedSort)
262 {
263   if (isGround())
264     {
265       //
266       //	We assume that any code setting the ground flag will also ensure a sort index is set.
267       //	FIXME: this may not be true if the node is unreduced.
268       //
269       Assert(getSortIndex() != Sort::SORT_UNKNOWN, "unknown sort in node flagged as ground");
270       int nrBdds = sortBdds.getNrVariables(symbol()->rangeComponent()->getIndexWithinModule());
271       sortBdds.makeIndexVector(nrBdds, getSortIndex(), generalizedSort);
272     }
273   else
274     symbol()->computeGeneralizedSort(sortBdds, realToBdd, this, generalizedSort);
275 }
276 
277 // experimental code
278 
279 void
computeGeneralizedSort2(const SortBdds & sortBdds,const Vector<int> & realToBdd,Vector<Bdd> & outputBdds)280 DagNode::computeGeneralizedSort2(const SortBdds& sortBdds,
281 				 const Vector<int>& realToBdd,
282 				 Vector<Bdd>& outputBdds)
283 {
284     if (isGround())
285     {
286       //
287       //	We assume that any code setting the ground flag will also ensure a sort index is set.
288       //	FIXME: this may not be true if the node is unreduced.
289       //
290       Assert(getSortIndex() != Sort::SORT_UNKNOWN, "unknown sort in node flagged as ground");
291       int nrBdds = sortBdds.getNrVariables(symbol()->rangeComponent()->getIndexWithinModule());
292       sortBdds.appendIndexVector(nrBdds, getSortIndex(), outputBdds);
293     }
294   else
295     symbol()->computeGeneralizedSort2(sortBdds, realToBdd, this, outputBdds);
296 }
297 
298 //
299 //	Narrowing code.
300 //
301 
302 bool
indexVariables2(NarrowingVariableInfo & indices,int baseIndex)303 DagNode::indexVariables2(NarrowingVariableInfo& indices, int baseIndex)
304 {
305   //
306   //	This is the backstop version for an unimplemented theory. It does the right
307   //	thing but is rather inefficient for runtime code.
308   //
309   bool ground = true;
310   for (DagArgumentIterator a(*this); a.valid(); a.next())
311     {
312       if (!(a.argument()->indexVariables(indices, baseIndex)))
313 	ground = false;
314     }
315   return ground;
316 }
317 
318 //
319 //	Variant narrowing code.
320 //
321 
322 bool
reducibleByVariantEquation(RewritingContext & context)323 DagNode::reducibleByVariantEquation(RewritingContext& context)
324 {
325   //
326   //	If it is already reduced wrt all equations it clearly can't be reduced by a variant equation.
327   //
328   if (isReduced() || isIrreducibleByVariantEquations())
329     return false;
330   //
331   //	Naive and inefficient approach.
332   //
333   for (DagArgumentIterator a(this); a.valid(); a.next())
334     {
335       if (a.argument()->reducibleByVariantEquation(context))
336 	return true;
337     }
338 
339   Subproblem* sp;
340   ExtensionInfo* extensionInfo = makeExtensionInfo();
341 
342   const Vector<Equation*>& equations = symbol()->getEquations();
343   FOR_EACH_CONST(i, Vector<Equation*>, equations)
344     {
345       Equation* eq = *i;
346       if (eq->isVariant())
347 	{
348 	  int nrVariables = eq->getNrProtectedVariables();
349 	  context.clear(nrVariables);
350 	  if (eq->getLhsAutomaton()->match(this, context, sp, extensionInfo))
351 	    {
352 	      if (sp == 0 || sp->solve(true, context))
353 		{
354 		  delete extensionInfo;
355 		  delete sp;
356 		  return true;
357 		}
358 	      delete sp;
359 	    }
360 	}
361     }
362   setIrreducibleByVariantEquations();
363   delete extensionInfo;
364   return false;
365 }
366 
367 #ifdef DUMP
368 void
dump(ostream & s,int indentLevel)369 DagNode::dump(ostream& s, int indentLevel)
370 {
371   s << Indent(indentLevel) << "Begin{DagNode}\n";
372   ++indentLevel;
373   dumpCommon(s, indentLevel);
374   s << Indent(indentLevel) << "arguments:\n";
375   ++indentLevel;
376   for (DagArgumentIterator a(*this); a.valid(); a.next())
377     a.argument()->dump(s, indentLevel);
378   s << Indent(indentLevel - 2) << "End{DagNode}\n";
379 }
380 
381 void
dumpCommon(ostream & s,int indentLevel)382 DagNode::dumpCommon(ostream& s, int indentLevel)
383 {
384   s << Indent(indentLevel) << "topSymbol = " << topSymbol << '\n';
385 }
386 #endif
387