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 class CUI_DagNode.
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 #include "CUI_Theory.hh"
36
37 // interface class definitions
38 #include "binarySymbol.hh"
39 #include "dagNode.hh"
40 #include "term.hh"
41 #include "rawDagArgumentIterator.hh"
42 #include "lhsAutomaton.hh"
43 #include "rhsAutomaton.hh"
44 #include "subproblem.hh"
45 #include "extensionInfo.hh"
46
47 // core class definitions
48 #include "substitution.hh"
49 #include "pendingUnificationStack.hh"
50 #include "unificationContext.hh"
51
52 // variable class definitions
53 #include "variableDagNode.hh"
54
55 // CUI theory class definitions
56 #include "CUI_Symbol.hh"
57 #include "CUI_DagNode.hh"
58 #include "CUI_DagArgumentIterator.hh"
59
60 RawDagArgumentIterator*
arguments()61 CUI_DagNode::arguments()
62 {
63 return new CUI_DagArgumentIterator(argArray);
64 }
65
66 size_t
getHashValue()67 CUI_DagNode::getHashValue()
68 {
69 if (isHashValid())
70 return hashCache;
71 size_t hashValue = hash(hash(symbol()->getHashValue(), argArray[0]->getHashValue()),
72 argArray[1]->getHashValue());
73 hashCache = hashValue;
74 setHashValid();
75 return hashValue;
76 }
77
78 int
compareArguments(const DagNode * other) const79 CUI_DagNode::compareArguments(const DagNode* other) const
80 {
81 const CUI_DagNode* d = static_cast<const CUI_DagNode*>(other);
82 int r = argArray[0]->compare(d->argArray[0]);
83 if (r != 0)
84 return r;
85 return argArray[1]->compare(d->argArray[1]);
86 }
87
88 DagNode*
markArguments()89 CUI_DagNode::markArguments()
90 {
91 argArray[0]->mark();
92 return argArray[1];
93 }
94
95 DagNode*
copyEagerUptoReduced2()96 CUI_DagNode::copyEagerUptoReduced2()
97 {
98 CUI_Symbol* s = symbol();
99 CUI_DagNode* n = new CUI_DagNode(s);
100 n->argArray[0] = s->eagerArgument(0) ? argArray[0]->copyEagerUptoReduced() : argArray[0];
101 n->argArray[1] = s->eagerArgument(1) ? argArray[1]->copyEagerUptoReduced() : argArray[1];
102 return n;
103 }
104
105 void
clearCopyPointers2()106 CUI_DagNode::clearCopyPointers2()
107 {
108 argArray[0]->clearCopyPointers();
109 argArray[1]->clearCopyPointers();
110 }
111
112 void
overwriteWithClone(DagNode * old)113 CUI_DagNode::overwriteWithClone(DagNode* old)
114 {
115 CUI_DagNode* d = new(old) CUI_DagNode(symbol());
116 d->copySetRewritingFlags(this);
117 d->setSortIndex(getSortIndex());
118 d->argArray[0] = argArray[0];
119 d->argArray[1] = argArray[1];
120 }
121
122 DagNode*
makeClone()123 CUI_DagNode::makeClone()
124 {
125 CUI_DagNode* d = new CUI_DagNode(symbol());
126 d->copySetRewritingFlags(this);
127 d->setSortIndex(getSortIndex());
128 d->argArray[0] = argArray[0];
129 d->argArray[1] = argArray[1];
130 return d;
131 }
132
133 DagNode*
copyWithReplacement(int argIndex,DagNode * replacement)134 CUI_DagNode::copyWithReplacement(int argIndex, DagNode* replacement)
135 {
136 CUI_DagNode* d = new CUI_DagNode(symbol());
137 if (argIndex == 0)
138 {
139 d->argArray[0] = replacement;
140 d->argArray[1] = argArray[1];
141 }
142 else
143 {
144 Assert(argIndex == 1, "bad argument index");
145 d->argArray[0] = argArray[0];
146 d->argArray[1] = replacement;
147 }
148 return d;
149 }
150
151 DagNode*
copyWithReplacement(Vector<RedexPosition> & redexStack,int first,int last)152 CUI_DagNode::copyWithReplacement(Vector<RedexPosition>& redexStack,
153 int first,
154 int last)
155 {
156 if (first == last)
157 return copyWithReplacement(redexStack[first].argIndex(), redexStack[first].node());
158
159 Assert(first + 1 == last, "nrArgs clash");
160 CUI_DagNode* d = new CUI_DagNode(symbol());
161 d->argArray[0] = redexStack[first].node();
162 d->argArray[1] = redexStack[last].node();
163 return d;
164 }
165
166 void
stackArguments(Vector<RedexPosition> & stack,int parentIndex,bool respectFrozen)167 CUI_DagNode::stackArguments(Vector<RedexPosition>& stack,
168 int parentIndex,
169 bool respectFrozen)
170 {
171 /*
172 DebugAdvisory("CUI_DagNode::stackArguments() " << this <<
173 " left = " << argArray[0]->isUnstackable() <<
174 " right = " << argArray[1]->isUnstackable());
175 */
176 const NatSet& frozen = symbol()->getFrozen();
177 DagNode* d = argArray[0];
178 if (!(respectFrozen && frozen.contains(0)) && !(d->isUnstackable()))
179 stack.append(RedexPosition(d, parentIndex, 0));
180 DagNode* d2 = argArray[1];
181 if (!(respectFrozen && frozen.contains(1)) && !(d2->isUnstackable()) &&
182 !(symbol()->comm() && d->equal(d2))) // don't stack equal args in the comm case
183 stack.append(RedexPosition(d2, parentIndex, 1));
184 }
185
186 void
collapseTo(int argNr)187 CUI_DagNode::collapseTo(int argNr)
188 {
189 DagNode* remaining = (symbol()->eagerArgument(argNr)) ?
190 argArray[argNr] : argArray[argNr]->copyReducible();
191 remaining->overwriteWithClone(this);
192 }
193
194 bool
normalizeAtTop()195 CUI_DagNode::normalizeAtTop()
196 {
197 CUI_Symbol* s = symbol();
198 Term* identity = s->getIdentity();
199 if (identity != 0)
200 {
201 if (s->leftId() && identity->equal(argArray[0]))
202 {
203 collapseTo(1);
204 return true;
205 }
206 if (s->rightId() && identity->equal(argArray[1]))
207 {
208 collapseTo(0);
209 return true;
210 }
211 }
212 if (s->comm() || s->idem())
213 {
214 int r = argArray[0]->compare(argArray[1]);
215 if (s->idem() && r == 0)
216 {
217 collapseTo(0);
218 return true;
219 }
220 if (s->comm() && r > 0)
221 {
222 DagNode* t = argArray[0];
223 argArray[0] = argArray[1];
224 argArray[1] = t;
225 }
226 }
227 return false;
228 }
229
230 //
231 // Unification code.
232 //
233
234 DagNode::ReturnResult
computeBaseSortForGroundSubterms()235 CUI_DagNode::computeBaseSortForGroundSubterms()
236 {
237 CUI_Symbol* s = symbol();
238 if (/* s->leftId() || s->rightId() ||*/ s->idem())
239 {
240 //
241 // We only support unification for commutativity at the moment
242 // so let the backstop version handle it.
243 //
244 return DagNode::computeBaseSortForGroundSubterms();
245 }
246 ReturnResult r0 = argArray[0]->computeBaseSortForGroundSubterms();
247 if (r0 == UNIMPLEMENTED)
248 return UNIMPLEMENTED;
249 ReturnResult r1 = argArray[1]->computeBaseSortForGroundSubterms();
250 if (r1 == UNIMPLEMENTED)
251 return UNIMPLEMENTED;
252 if (r0 == GROUND && r1 == GROUND)
253 {
254 s->computeBaseSort(this);
255 setGround();
256 return GROUND;
257 }
258 return NONGROUND;
259 }
260
261 bool
computeSolvedFormCommutativeCase(CUI_DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)262 CUI_DagNode::computeSolvedFormCommutativeCase(CUI_DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
263 {
264 //
265 // We are have a C symbol and the rhs has the same symbol.
266 // Both dagnodes are assumed to have their arguments sorted in ascending order. Equality
267 // between any two of the four arguments eliminates the need for branching.
268 //
269 DagNode** rhsArgs = rhs->argArray;
270 DagNode* l0 = argArray[0];
271 DagNode* l1 = argArray[1];
272 DagNode* r0 = rhsArgs[0];
273 DagNode* r1 = rhsArgs[1];
274 //
275 // We know l0 <= l1 and r0 <= r1 because of normal forms.
276 // In the C case we will decide if at least one of the 6 possible equalities holds in at most 4 comparisons.
277 // In the CU case we will postpone the issue of l0 vs l1 and r0 vs r1, and push the problem if none of the other 4 equalities hold.
278 //
279 int r = l0->compare(r0);
280 if (r == 0)
281 return l1->computeSolvedForm(r1, solution, pending);
282 if (r > 0)
283 {
284 //
285 // Swap unificands to turn > 0 case in to < 0 case.
286 swap(l0, r0);
287 swap(l1, r1);
288 }
289
290 r = l1->compare(r0);
291 if (r == 0)
292 return l0->computeSolvedForm(r1, solution, pending);
293
294 if (r < 0)
295 {
296 //
297 // We have l0 <= l1 < r0 <= r1. If we are in the C case we check both sides for duplicated arguments.
298 //
299 CUI_Symbol* s = symbol();
300 if (!(l0->equal(l1) || r0->equal(r1)))
301 {
302 //
303 // Either we have an identity or there were no equalities. Either way we need to consider multiple
304 // possibilities.
305 //
306 pending.push(s, this, rhs);
307 return true;
308 }
309 }
310 else
311 {
312 r = l1->compare(r1);
313 if (r == 0)
314 return l0->computeSolvedForm(r0, solution, pending);
315 if (r < 0)
316 {
317 //
318 // We have l0 < r0 < l1 < r1. No equalities possible; need to consider multiple possibilities.
319 //
320 pending.push(symbol(), this, rhs);
321 return true;
322 }
323 else
324 {
325 //
326 // We have l0 < r0 < l1 and r1 < l1. So r0 = r1 is our only possible equality.
327 //
328 CUI_Symbol* s = symbol();
329 if (!(r0->equal(r1)))
330 {
331 //
332 // Either we have an identity or there were no equalities. Either way we need to consider multiple
333 // possibilities.
334 //
335 pending.push(s, this, rhs);
336 return true;
337 }
338 }
339 }
340 //
341 // If we got here, we have no identity and duplicated arguments in at least one unificand.
342 // We only need to consider a singe possibility.
343 //
344 return l0->computeSolvedForm(r0, solution, pending) && l1->computeSolvedForm(r1, solution, pending);
345 }
346
347 bool
computeSolvedForm2(DagNode * rhs,UnificationContext & solution,PendingUnificationStack & pending)348 CUI_DagNode::computeSolvedForm2(DagNode* rhs, UnificationContext& solution, PendingUnificationStack& pending)
349 {
350 //cout << "CUI_DagNode::computeSolvedForm2() " << (DagNode*) this << " vs " << rhs << endl;
351 CUI_Symbol* s = symbol();
352 if (s == rhs->symbol())
353 {
354 if (!(s->leftId() || s->rightId()))
355 return computeSolvedFormCommutativeCase(safeCast(CUI_DagNode*, rhs), solution, pending); // optimized case for C
356 pending.push(s, this, rhs); // consider all alternatives
357 return true;
358 }
359
360 if (VariableDagNode* v = dynamic_cast<VariableDagNode*>(rhs))
361 {
362 //
363 // Get representative variable.
364 //
365 VariableDagNode* r = v->lastVariableInChain(solution);
366 if (DagNode* value = solution.value(r->getIndex()))
367 return computeSolvedForm2(value, solution, pending);
368 //
369 // We have a unification problem f(u, v) =? X where X unbound.
370 //
371 if (s->leftId() || s->rightId())
372 {
373 //
374 // Because we could collapse, potentially to a smaller sort, we consider multiple alternatives.
375 //
376 pending.push(s, this, rhs);
377 return true;
378 }
379 //
380 // We need to bind the variable to our purified form.
381 //
382 // We cut a corner here by treating each commutative symbol as its
383 // own theory, and rely on cycle detection to do occurs checks that
384 // pass through multiple symbols.
385 //
386 /*
387 bool needToRebuild = false;
388
389 DagNode* l0 = argArray[0];
390 if (VariableDagNode* a = dynamic_cast<VariableDagNode*>(l0))
391 {
392 if (a->lastVariableInChain(solution)->equal(r))
393 return false; // occurs check fail
394 }
395 else
396 {
397 VariableDagNode* abstractionVariable = solution.makeFreshVariable(s->domainComponent(0));
398 //
399 // solution.unificationBind(abstractionVariable, l0) would be unsafe since l0 might not be pure.
400 //
401 l0->computeSolvedForm(abstractionVariable, solution, pending);
402 l0 = abstractionVariable;
403 needToRebuild = true;
404 }
405
406 DagNode* l1 = argArray[1];
407 if (l1->equal(argArray[0]))
408 l1 = l0; // arguments equal so treat them the same in purified version
409 else
410 {
411 if (VariableDagNode* a = dynamic_cast<VariableDagNode*>(l1))
412 {
413 if (a->lastVariableInChain(solution)->equal(r))
414 return false; // occurs check fail
415 }
416 else
417 {
418 VariableDagNode* abstractionVariable = solution.makeFreshVariable(s->domainComponent(1));
419 //
420 // solution.unificationBind(abstractionVariable, l1) would be unsafe since l1 might not be pure.
421 //
422 l1->computeSolvedForm(abstractionVariable, solution, pending);
423 l1 = abstractionVariable;
424 needToRebuild = true;
425 }
426 }
427
428 CUI_DagNode* purified = this;
429 if (needToRebuild)
430 {
431 purified = new CUI_DagNode(s);
432 if (l0->compare(l1) <= 0)
433 {
434 purified->argArray[0] = l0;
435 purified->argArray[1] = l1;
436 }
437 else
438 {
439 purified->argArray[0] = l1;
440 purified->argArray[1] = l0;
441 }
442 }
443 //cout << "unification bind " << (DagNode*) r << " vs " << (DagNode*) purified << endl;
444 */
445 CUI_DagNode* purified = makePurifiedVersion(solution, pending);
446 solution.unificationBind(r, purified);
447 return true;
448 }
449 return pending.resolveTheoryClash(this, rhs);
450 }
451
452 CUI_DagNode*
makePurifiedVersion(UnificationContext & solution,PendingUnificationStack & pending)453 CUI_DagNode::makePurifiedVersion(UnificationContext& solution, PendingUnificationStack& pending)
454 {
455 CUI_Symbol* s = symbol();
456 bool needToRebuild = false;
457
458 DagNode* l0 = argArray[0];
459 if (dynamic_cast<VariableDagNode*>(l0) == 0) // need to purify
460 {
461 VariableDagNode* abstractionVariable = solution.makeFreshVariable(s->domainComponent(0));
462 //
463 // solution.unificationBind(abstractionVariable, l0) would be unsafe since l0 might not be pure.
464 //
465 l0->computeSolvedForm(abstractionVariable, solution, pending);
466 l0 = abstractionVariable;
467 needToRebuild = true;
468 }
469
470 DagNode* l1 = argArray[1];
471 if (l1->equal(argArray[0]))
472 l1 = l0; // arguments equal so treat them the same in purified version
473 else
474 {
475 if (dynamic_cast<VariableDagNode*>(l1) == 0) // need to purify
476 {
477 VariableDagNode* abstractionVariable = solution.makeFreshVariable(s->domainComponent(1));
478 //
479 // solution.unificationBind(abstractionVariable, l1) would be unsafe since l1 might not be pure.
480 //
481 l1->computeSolvedForm(abstractionVariable, solution, pending);
482 l1 = abstractionVariable;
483 needToRebuild = true;
484 }
485 }
486 if (!needToRebuild)
487 return this;
488
489 CUI_DagNode* purified = new CUI_DagNode(s);
490 if (l0->compare(l1) <= 0)
491 {
492 purified->argArray[0] = l0;
493 purified->argArray[1] = l1;
494 }
495 else
496 {
497 purified->argArray[0] = l1;
498 purified->argArray[1] = l0;
499 }
500 return purified;
501 }
502
503 void
insertVariables2(NatSet & occurs)504 CUI_DagNode::insertVariables2(NatSet& occurs)
505 {
506 argArray[0]->insertVariables(occurs);
507 argArray[1]->insertVariables(occurs);
508 }
509
510 DagNode*
instantiate2(const Substitution & substitution)511 CUI_DagNode::instantiate2(const Substitution& substitution)
512 {
513 bool changed = false;
514 DagNode* a0 = argArray[0];
515 if (DagNode* n = a0->instantiate(substitution))
516 {
517 a0 = n;
518 changed = true;
519 }
520 DagNode* a1 = argArray[1];
521 if (DagNode* n = a1->instantiate(substitution))
522 {
523 a1 = n;
524 changed = true;
525 }
526 if (changed)
527 {
528 CUI_Symbol* s = symbol();
529 CUI_DagNode* d = new CUI_DagNode(s);
530 d->argArray[0] = a0;
531 d->argArray[1] = a1;
532 if(!(d->normalizeAtTop()) && a0->isGround() && a1->isGround())
533 {
534 s->computeBaseSort(d);
535 d->setGround();
536 }
537 return d;
538 }
539 return 0;
540 }
541
542 //
543 // Narrowing code.
544 //
545
546 bool
indexVariables2(NarrowingVariableInfo & indices,int baseIndex)547 CUI_DagNode::indexVariables2(NarrowingVariableInfo& indices, int baseIndex)
548 {
549 return argArray[0]->indexVariables(indices, baseIndex) & // always make both calls
550 argArray[1]->indexVariables(indices, baseIndex);
551 }
552
553 DagNode*
instantiateWithReplacement(const Substitution & substitution,const Vector<DagNode * > & eagerCopies,int argIndex,DagNode * replacement)554 CUI_DagNode::instantiateWithReplacement(const Substitution& substitution, const Vector<DagNode*>& eagerCopies, int argIndex, DagNode* replacement)
555 {
556 CUI_DagNode* d = new CUI_DagNode(symbol());
557 int other = 1 - argIndex;
558 d->argArray[argIndex] = replacement;
559
560 DagNode* n = argArray[other];
561 DagNode* c = symbol()->eagerArgument(other) ?
562 n->instantiateWithCopies(substitution, eagerCopies) :
563 n->instantiate(substitution); // lazy case - ok to use original unifier bindings since we won't evaluate them
564 if (c != 0) // changed under substitutition
565 n = c;
566
567 d->argArray[other] = n;
568 return d;
569 }
570
571 DagNode*
instantiateWithCopies2(const Substitution & substitution,const Vector<DagNode * > & eagerCopies)572 CUI_DagNode::instantiateWithCopies2(const Substitution& substitution, const Vector<DagNode*>& eagerCopies)
573 {
574 bool changed = false;
575 DagNode* a0 = argArray[0];
576 {
577 DagNode* n = symbol()->eagerArgument(0) ?
578 a0->instantiateWithCopies(substitution, eagerCopies) :
579 a0->instantiate(substitution);
580 if (n != 0)
581 {
582 a0 = n;
583 changed = true;
584 }
585 }
586 DagNode* a1 = argArray[1];
587 {
588 DagNode* n = symbol()->eagerArgument(1) ?
589 a1->instantiateWithCopies(substitution, eagerCopies) :
590 a1->instantiate(substitution);
591 if (n != 0)
592 {
593 a1 = n;
594 changed = true;
595 }
596 }
597
598 if (changed)
599 {
600 CUI_Symbol* s = symbol();
601 CUI_DagNode* d = new CUI_DagNode(s);
602 d->argArray[0] = a0;
603 d->argArray[1] = a1;
604 if(!(d->normalizeAtTop()) && a0->isGround() && a1->isGround())
605 {
606 s->computeBaseSort(d);
607 d->setGround();
608 }
609 return d;
610 }
611 return 0;
612 }
613