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