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 //	Specialized mergesort algorithm for ACU argument lists.
25 //
26 
27 void
mergeSortAndUniquize()28 ACU_DagNode::mergeSortAndUniquize()
29 {
30   int nrArgs = argArray.length();
31   int nrRuns = runsBuffer.length();
32   ArgVec<Pair> mergeBuffer(nrArgs);
33 
34   while (nrRuns > 1)
35     {
36       int d = 0;
37       int rd = 0;
38       int i = 0;
39       for (; i < nrRuns - 1; i += 2)
40 	{
41 	  //
42 	  //	Merge runs i and i+1
43 	  //
44 	  int p1 = runsBuffer[i];
45 	  int e1 = runsBuffer[i + 1];
46 	  int p2 = runsBuffer[i + 1];
47 	  int e2 = i + 2 < nrRuns ? runsBuffer[i + 2] : nrArgs;
48 	  runsBuffer[rd++] = d;  // save start of merged run we are creating
49 	  for(;;)
50 	    {
51 	      int r = argArray[p1].dagNode->compare(argArray[p2].dagNode);
52 	      if (r < 0)
53 		{
54 		  mergeBuffer[d++] = argArray[p1++];
55 		  if (p1 == e1)
56 		    {
57 		      p1 = p2;
58 		      e1 = e2;
59 		      break;
60 		    }
61 		}
62 	      else if (r > 0)
63 		{
64 		  mergeBuffer[d++] = argArray[p2++];
65 		  if (p2 == e2)
66 		    break;
67 		}
68 	      else
69 		{
70 		  mergeBuffer[d].dagNode = argArray[p1].dagNode;
71 		  mergeBuffer[d++].multiplicity =
72 		    argArray[p1++].multiplicity + argArray[p2++].multiplicity;
73 		  if (p1 == e1)
74 		    {
75 		      p1 = p2;
76 		      e1 = e2;
77 		      break;
78 		    }
79 		  if (p2 == e2)
80 		    break;
81 		}
82 	    }
83 	  while (p1 < e1)
84 	    mergeBuffer[d++] = argArray[p1++];
85 	}
86       if (i < nrRuns)
87 	{
88 	  Assert(rd < i, "floor(nrRuns/2) >= nrRuns - 1");
89 	  runsBuffer[rd++] = d;  // Assert guarantees we don't overwrite runsBuffer[i]
90 	  //
91 	  //	Copy odd run into merge buffer
92 	  //
93 	  for (int p = runsBuffer[i]; p < nrArgs; p++)
94 	    mergeBuffer[d++] = argArray[p];
95 	}
96       nrArgs = d;
97       nrRuns = rd;
98       argArray.swap(mergeBuffer);
99     }
100   argArray.contractTo(nrArgs);  // merging may have shrunk number of arguments
101 }
102 
103 void
sortAndUniquize()104 ACU_DagNode::sortAndUniquize()
105 {
106   //
107   //	ACU argument lists tend to have long runs of in order
108   //	arguments so we discover these runs first befor running
109   //	the mergesort algorithm.
110   //
111   int nrArgs = argArray.length();
112   for (int i = 1; i < nrArgs; i++)
113     {
114       int r = argArray[i - 1].dagNode->compare(argArray[i].dagNode);
115       if (r >= 0)
116 	{
117 	  runsBuffer.contractTo(1);
118 	  int lastRun = 0;
119 	  runsBuffer[0] = lastRun;
120 	  int d = i - 1;
121 	  for(;;)
122 	    {
123 	      if (r == 0)
124 		argArray[d].multiplicity += argArray[i].multiplicity;
125 	      else if (r < 0)
126 		argArray[++d] = argArray[i];
127 	      else
128 		{
129 		  if (lastRun == d)  // don't make a run of length 1
130 		    {
131 		      Pair t(argArray[d]);
132 		      argArray[d] = argArray[i];
133 		      argArray[++d] = t;
134 		    }
135 		  else
136 		    {
137 		      argArray[++d] = argArray[i];
138 		      lastRun = d;
139 		      runsBuffer.append(lastRun);
140 		    }
141 		}
142 	      if (++i == nrArgs)
143 		break;
144 	      r = argArray[d].dagNode->compare(argArray[i].dagNode);
145 	    }
146 	  argArray.contractTo(d + 1);
147 	  if (runsBuffer.length() > 1)
148 	    mergeSortAndUniquize();
149 	  break;
150 	}
151     }
152 }
153 
154 void
flattenSortAndUniquize(int expansion)155 ACU_DagNode::flattenSortAndUniquize(int expansion)
156 {
157   Symbol* s = symbol();
158   int nrArgs = argArray.length();
159   ArgVec<Pair> newArray(nrArgs + expansion);
160   runsBuffer.contractTo(1);
161   int lastRun = 0;
162   runsBuffer[0] = lastRun;
163   int d = -1;  // HACK: should use iterators for everything
164 
165   for (int i = 0; i < nrArgs; i++)
166     {
167       DagNode* n = argArray[i].dagNode;
168       if (n->symbol() == s)
169 	{
170 	  //
171 	  //	Need to flatten in subterm.
172 	  //
173 	  int m = argArray[i].multiplicity;
174 	  if (d >= 0)
175 	    {
176 	      lastRun = d + 1;
177 	      runsBuffer.append(lastRun);
178 	    }
179 	  ArgVec<Pair>::iterator dest = newArray.begin() + (d + 1);
180 
181 	  if (safeCast(ACU_BaseDagNode*, n)->isTree())
182 	    {
183 	      const ACU_Tree& tree = safeCast(ACU_TreeDagNode*, n)->getTree();
184 	      ACU_FastIter i(tree);
185 	      do
186 		{
187 		  dest->dagNode = i.getDagNode();
188 		  dest->multiplicity = m * i.getMultiplicity();
189 		  ++dest;
190 		  i.next();
191 		}
192 	      while (i.valid());
193 	      d += tree.getSize();
194 	    }
195 	  else
196 	    {
197 	      const ArgVec<Pair>& argArray2 = safeCast(ACU_DagNode*, n)->argArray;
198 	      ArgVec<Pair>::const_iterator i = argArray2.begin();
199 	      const ArgVec<Pair>::const_iterator e = argArray2.end();
200 	      do
201 		{
202 		  dest->dagNode = i->dagNode;
203 		  dest->multiplicity = m * i->multiplicity;
204 		  ++dest;
205 		  ++i;
206 		}
207 	      while (i != e);
208 	      d += argArray2.length();
209 	    }
210 	}
211       else
212 	{
213 	  if (d >= 0)
214 	    {
215 	      int r = newArray[d].dagNode->compare(n);
216 	      if (r == 0)
217 		{
218 		  newArray[d].multiplicity += argArray[i].multiplicity;
219 		  continue;
220 		}
221 	      else if (r > 0)
222 		{
223 		  if (lastRun == d)  // don't make a run of length 1
224 		    {
225 		      newArray[d + 1] = newArray[d];
226 		      newArray[d] = argArray[i];
227 		      ++d;
228 		      continue;
229 		    }
230 		  else
231 		    {
232 		      lastRun = d + 1;
233 		      runsBuffer.append(lastRun);
234 		    }
235 		}
236 	    }
237 	  newArray[++d] = argArray[i];
238 	}
239     }
240   /*
241   cout << " flattenSortAndUniquize() runs buffer: ";
242   for (int i = 0; i < runsBuffer.length(); i++)
243     cout << runsBuffer[i] << ' ';
244   cout << " nrArgs = " << newArray.length() << '\n';
245   */
246   newArray.contractTo(d + 1);
247   argArray.swap(newArray);
248   if (runsBuffer.length() > 1)
249     mergeSortAndUniquize();
250 }
251