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