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