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 full A/AU matcher flex part.
25 //
26 
27 bool
fullMatch(AU_DagNode * subject,Substitution & solution,SubproblemAccumulator & subproblems,AU_ExtensionInfo * extensionInfo)28 AU_LhsAutomaton::fullMatch(AU_DagNode* subject,
29 			   Substitution& solution,
30 			   SubproblemAccumulator& subproblems,
31 			   AU_ExtensionInfo* extensionInfo)
32 {
33   AU_Subproblem* subproblem = buildLeftmostPath(subject, solution, extensionInfo);
34   if (subproblem == 0)
35     return false;
36   subproblems.add(subproblem);
37   addVariableBlocks(solution, subproblem, subproblems);
38   addRemainingPaths(subject, solution, subproblem);
39   subproblem->complete();
40   if (extensionInfo != 0)
41     extensionInfo->setValidAfterMatch(false);
42   return true;
43 }
44 
45 void
addVariableBlocks(Substitution & solution,AU_Subproblem * subproblem,SubproblemAccumulator & subproblems)46 AU_LhsAutomaton::addVariableBlocks(Substitution& solution,
47 				   AU_Subproblem* subproblem,
48 				   SubproblemAccumulator& subproblems)
49 {
50   int nrVariables = solution.nrFragileBindings();
51   int layerNr = 0;
52   bool rigidEncountered = false;
53   int skip;
54   for (int i = flexLeftPos; i <= flexRightPos; i += skip)
55     {
56       Subterm& f = flexPart[i];
57       skip = f.blockLength;
58       if (skip == NOT_FIXED)
59 	{
60 	  skip = 1;
61 	  TopVariable& tv = f.variable;
62 	  int index = tv.index;
63 	  DagNode* d = solution.value(index);
64 	  if (d == 0)
65 	    {
66 	      if (rigidEncountered)
67 		{
68 		  rigidEncountered = false;
69 		  ++layerNr;
70 		}
71 	      subproblem->addTopVariable(layerNr,
72 					 index,
73 					 tv.takeIdentity || tv.awkward ? 0 : 1,
74 					 tv.upperBound,
75 					 tv.sort);
76 	      if (tv.abstracted != 0)
77 		{
78 		  subproblems.add
79 		    (new VariableAbstractionSubproblem(tv.abstracted,
80 						       index,
81 						       nrVariables));
82 		}
83 	      continue;
84 	    }
85 	  else if (tv.nastyBinding != NONE)
86 	    {
87 	      if (rigidEncountered)
88 		{
89 		  rigidEncountered = false;
90 		  ++layerNr;
91 		}
92 	      subproblem->addTopVariable(layerNr,
93 					 index,
94 					 tv.nastyBinding - 1,
95 					 tv.nastyBinding,
96 					 tv.sort);
97 	      continue;
98 	    }
99 	}
100       rigidEncountered = true;
101     }
102 }
103 
104 bool
fullMatchRigidBlock(AU_DagNode * subject,Substitution & solution,RigidBlock & block,int minShift,int maxShift,int & matchShift,Subproblem * & subproblem)105 AU_LhsAutomaton::fullMatchRigidBlock(AU_DagNode* subject,
106 				     Substitution& solution,
107 				     RigidBlock& block,
108 				     int minShift,
109 				     int maxShift,
110 				     int& matchShift,
111 				     Subproblem*& subproblem)
112 {
113   Assert(minShift <= maxShift, "bad shift range");
114   Assert(block.start <= block.end, "bad block range");
115   int shiftFactor;
116   for (int i = minShift; i <= maxShift; i += shiftFactor)
117     {
118       local.copy(solution);	// make a local copy for matching at shift i
119       if (fullMatchRigidBlock2(subject, block, i, subproblem, shiftFactor))
120 	{
121 	  matchShift = i;
122 	  return true;
123 	}
124     }
125   return false;
126 }
127 
128 bool
fullMatchRigidBlock2(AU_DagNode * subject,RigidBlock & block,int nextSubject,Subproblem * & subproblem,int & shiftFactor)129 AU_LhsAutomaton::fullMatchRigidBlock2(AU_DagNode* subject,
130 				      RigidBlock& block,
131 				      int nextSubject,
132 				      Subproblem*& subproblem,
133 				      int& shiftFactor)
134 {
135   ArgVec<DagNode*>& args = subject->argArray;
136   SubproblemAccumulator subproblems;
137   shiftFactor = 1;  // default shift increment
138   int skip;
139   for (int i = block.start; i <= block.end; i += skip)
140     {
141       Subterm& f = flexPart[i];
142       skip = f.blockLength;
143       if (skip == NOT_FIXED)
144 	{
145 	  DagNode* d = local.value(f.variable.index);
146 	  Assert(d != 0, "unbound variable in rigid block");
147 	  if (!(subject->eliminateForward(d, nextSubject, rightPos)))  // better limit?
148 	    return false;
149 	  skip = 1;
150 	}
151       else
152 	{
153 	  int sf;
154 	  int t = fullMatchFixedLengthBlock(args, i, nextSubject, subproblems, sf);
155 	  if (sf > shiftFactor)
156 	    shiftFactor = sf;
157 	  if (!t)
158 	    return false;
159 	  nextSubject += skip;
160 	}
161     }
162   subproblem = subproblems.extractSubproblem();
163   return true;
164 }
165 
166 
167 bool
fullMatchFixedLengthBlock(ArgVec<DagNode * > & args,int blockStart,int attemptedShift,SubproblemAccumulator & subproblems,int & shiftFactor)168 AU_LhsAutomaton::fullMatchFixedLengthBlock(ArgVec<DagNode*>& args,
169 					   int blockStart,
170 					   int attemptedShift,
171 					   SubproblemAccumulator& subproblems,
172 					   int& shiftFactor)
173 {
174   //
175   //	could we merge this with greedyMatchFixedLengthBlock()?
176   //	pass subproblems as a pointer and have it 0 for greedy
177   //
178   //
179   for (int i = flexPart[blockStart].blockLength - 1; i >= 0; i--)
180     {
181       Subterm& f = flexPart[blockStart + i];
182       DagNode* d = args[attemptedShift + i];
183       Assert(d->getSortIndex() != Sort::SORT_UNKNOWN,
184 	     "unknown sort for AU argument " << d <<
185 	     " at index " << attemptedShift + i <<
186 	     " topSymbol = " << topSymbol <<
187 	     " blockStart = " << blockStart);
188 
189       shiftFactor = f.shiftFactor;
190       switch (f.type)
191         {
192 	case VARIABLE:
193           {
194             Assert(f.variable.upperBound == 1 && !f.variable.takeIdentity,
195                    "non-unit variable in fixed length block");
196             DagNode* v = local.value(f.variable.index);
197             if (v == 0)
198               {
199                 if (d->leq(f.variable.sort))
200                   local.bind(f.variable.index, d);
201                 else
202                   return false;
203               }
204             else
205               {
206                 Assert(v->symbol() != topSymbol,
207                        "illegal binding to unit variable");
208                 if (!(v->equal(d)))
209                   return false;
210               }
211             break;
212           }
213         case GROUND_ALIEN:
214           {
215             if (!(f.groundAlien->equal(d)))
216               return false;
217             break;
218           }
219         case NON_GROUND_ALIEN:
220           {
221             Subproblem* sp;
222             if (!(f.alienAutomaton->match(d, local, sp)))
223               return false;
224 	    subproblems.add(sp);
225             break;
226           }
227         }
228     }
229   return true;
230 }
231 
232 AU_Subproblem*
buildLeftmostPath(AU_DagNode * subject,Substitution & solution,AU_ExtensionInfo * extensionInfo)233 AU_LhsAutomaton::buildLeftmostPath(AU_DagNode* subject,
234 				   Substitution& solution,
235 				   AU_ExtensionInfo* extensionInfo)
236 {
237   int nrRigid = rigidBlocks.length();
238   Assert(extensionInfo != 0 || nrRigid == 0 ||
239 	 (rigidBlocks[0].start > flexLeftPos &&
240 	  rigidBlocks[nrRigid - 1].end < flexRightPos),
241 	 "missing unbound variable(s)");
242   int spare = rightPos - leftPos + 1 - nrSubjectsUsed;
243   if (spare < 0)
244     return 0;
245   int nextSubject = leftPos;
246   AU_Subproblem* subproblem =
247     new AU_Subproblem(subject, leftPos, rightPos, nrRigid + 1, extensionInfo);
248 
249   for (int i = 0; i < nrRigid; i++)
250     {
251       RigidBlock& r = rigidBlocks[i];
252       int min = nextSubject + r.nrSubjectsToLeave;
253       int max = min + spare;
254       int matchShift;
255       Subproblem* sp;
256       if (!fullMatchRigidBlock(subject, solution, r, min, max, matchShift, sp))
257 	{
258 	  delete subproblem;
259 	  return 0;
260 	}
261       r.firstMatch = matchShift;
262       nextSubject = matchShift + r.nrSubjectsForUs;
263       spare -= matchShift - min;
264       subproblem->addNode(i, local - solution, sp, matchShift, nextSubject - 1);
265     }
266   return subproblem;
267 }
268 
269 void
addRemainingPaths(AU_DagNode * subject,Substitution & solution,AU_Subproblem * subproblem)270 AU_LhsAutomaton::addRemainingPaths(AU_DagNode* subject,
271 				  Substitution& solution,
272 				  AU_Subproblem* subproblem)
273 {
274   int firstUnusable = rightPos + 1 - nrSubjectsForRightVars;
275   for (int i = rigidBlocks.length() - 1; i >= 0; i--)
276     {
277       RigidBlock& r = rigidBlocks[i];
278       int max = firstUnusable - r.nrSubjectsForUs;
279       int min = r.firstMatch + 1;
280 
281       firstUnusable = r.firstMatch;
282       while (max >= min)
283 	{
284 	  int matchShift;
285 	  Subproblem* sp;
286 	  if (fullMatchRigidBlock(subject, solution, r, min, max, matchShift, sp))
287 	    {
288 	      subproblem->addNode(i, local - solution, sp, matchShift,
289 				  matchShift + r.nrSubjectsForUs - 1);
290 	      firstUnusable = matchShift;
291 	      min = matchShift + 1;
292 	    }
293 	  else
294 	    break;
295 	}
296       firstUnusable -= r.nrSubjectsToLeave;
297     }
298 }
299