summaryrefslogtreecommitdiffstats
path: root/src/bdd/reo/reoSift.c
blob: 93d82f08a74266e971cbdb96bdc356532c56d3c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/**CFile****************************************************************

  FileName    [reoSift.c]

  PackageName [REO: A specialized DD reordering engine.]

  Synopsis    [Implementation of the sifting algorihtm.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - October 15, 2002.]

  Revision    [$Id: reoSift.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]

***********************************************************************/

#include "reo.h"

////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                    FUNCTION DEFINITIONS                          ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    [Implements the variable sifting algorithm.]

  Description [Performs a sequence of adjacent variable swaps known as "sifting".
  Uses the cost functions determined by the flag.]

  SideEffects []

  SeeAlso     []

***********************************************************************/
void reoReorderSift( reo_man * p )
{
    double CostCurrent;  // the cost of the current permutation
    double CostLimit;    // the maximum increase in cost that can be tolerated
    double CostBest;     // the best cost
    int BestQ;           // the best position
    int VarCurrent;      // the current variable to move   
    int q;               // denotes the current position of the variable
    int c;               // performs the loops over variables until all of them are sifted
    int v;               // used for other purposes

    assert( p->nSupp > 0 );

    // set the current cost depending on the minimization criteria
    if ( p->fMinWidth )
        CostCurrent = p->nWidthCur;
    else if ( p->fMinApl )
        CostCurrent = p->nAplCur;
    else
        CostCurrent = p->nNodesCur;

    // find the upper bound on tbe cost growth
    CostLimit = 1 + (int)(REO_REORDER_LIMIT * CostCurrent);

    // perform sifting for each of p->nSupp variables
    for ( c = 0; c < p->nSupp; c++ )
    {
        // select the current variable to be the one with the largest number of nodes that is not sifted yet
        VarCurrent = -1;
        CostBest   = -1.0;
        for ( v = 0; v < p->nSupp; v++ )
        {
            p->pVarCosts[v] = REO_HIGH_VALUE;
            if ( !p->pPlanes[v].fSifted )
            {
//                VarCurrent = v;
//                if ( CostBest < p->pPlanes[v].statsCost )
                if ( CostBest < p->pPlanes[v].statsNodes )
                {
//                    CostBest   = p->pPlanes[v].statsCost;
                    CostBest   = p->pPlanes[v].statsNodes;
                    VarCurrent = v;
                }

            }
        }
        assert( VarCurrent != -1 );
        // mark this variable as sifted
        p->pPlanes[VarCurrent].fSifted = 1;

        // set the current value
        p->pVarCosts[VarCurrent] = CostCurrent;

        // set the best cost
        CostBest = CostCurrent;
        BestQ    = VarCurrent; 

        // determine which way to move the variable first (up or down)
        // the rationale is that if we move the shorter way first
        // it is more likely that the best position will be found on the longer way
        // and the reverse movement (to take the best position) will be faster
        if ( VarCurrent < p->nSupp/2 ) // move up first, then down
        {
            // set the total cost on all levels above the current level
            p->pPlanes[0].statsCostAbove = 0;
            for ( v = 1; v <= VarCurrent; v++ )
                p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
            // set the total cost on all levels below the current level
            p->pPlanes[p->nSupp].statsCostBelow = 0;
            for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
                p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;

            assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove + 
                                    p->pPlanes[VarCurrent].statsCost +
                                    p->pPlanes[VarCurrent].statsCostBelow );

            // move up
            for ( q = VarCurrent-1; q >= 0; q-- )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
                // now q points to the position of this var in the order
                p->pVarCosts[q] = CostCurrent;
                // update the lower bound (assuming that for level q+1 it is set correctly)
                p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
                // check the upper bound
                if ( CostCurrent >= CostLimit )
                    break;
                // check the lower bound
                if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
                    break;
                // update the best cost
                if ( CostBest > CostCurrent )
                {
                    CostBest = CostCurrent;
                    BestQ    = q;
                    // adjust node limit
                    CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
                }

                // when we are reordering for width or APL, it may happen that
                // the number of nodes has grown above certain limit,
                // in which case we have to resize the data structures
                if ( p->fMinWidth || p->fMinApl )
                {
                    if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
                    {
//                        printf( "Resizing data structures. Old size = %6d. New size = %6d.\n",  p->nNodesMaxAlloc, p->nNodesCur );
                        reoResizeStructures( p, 0, p->nNodesCur, 0 );
                    }
                }
            }
            // fix the plane index
            if ( q == -1 )
                q++;
            // now p points to the position of this var in the order

            // move down
            for ( ; q < p->nSupp-1; )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
                q++;    // change q to point to the position of this var in the order
                // sanity check: the number of nodes on the back pass should be the same
                if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
                    printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
                p->pVarCosts[q] = CostCurrent;
                // update the lower bound (assuming that for level q-1 it is set correctly)
                p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
                // check the bounds only if the variable already reached its previous position
                if ( q >= BestQ )
                {
                    // check the upper bound
                    if ( CostCurrent >= CostLimit )
                        break;
                    // check the lower bound
                    if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
                        break;
                }
                // update the best cost
                if ( CostBest >= CostCurrent )
                {
                    CostBest = CostCurrent;
                    BestQ    = q;
                    // adjust node limit
                    CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
                }

                // when we are reordering for width or APL, it may happen that
                // the number of nodes has grown above certain limit,
                // in which case we have to resize the data structures
                if ( p->fMinWidth || p->fMinApl )
                {
                    if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
                    {
//                        printf( "Resizing data structures. Old size = %6d. New size = %6d.\n",  p->nNodesMaxAlloc, p->nNodesCur );
                        reoResizeStructures( p, 0, p->nNodesCur, 0 );
                    }
                }
            }
            // move the variable up from the given position (q) to the best position (BestQ)
            assert( q >= BestQ );
            for ( ; q > BestQ; q-- )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q-1, 1 );
                // sanity check: the number of nodes on the back pass should be the same
                if ( fabs( p->pVarCosts[q-1] - CostCurrent ) > REO_COST_EPSILON )
                {
                    printf("reoReorderSift():  Error! On the return move, the costs are different.\n" );
                    fflush(stdout);
                }
            }
        }
        else // move down first, then up
        {
            // set the current number of nodes on all levels above the given level
            p->pPlanes[0].statsCostAbove = 0;
            for ( v = 1; v <= VarCurrent; v++ )
                p->pPlanes[v].statsCostAbove = p->pPlanes[v-1].statsCostAbove + p->pPlanes[v-1].statsCost;
            // set the current number of nodes on all levels below the given level
            p->pPlanes[p->nSupp].statsCostBelow = 0;
            for ( v = p->nSupp - 1; v >= VarCurrent; v-- )
                p->pPlanes[v].statsCostBelow = p->pPlanes[v+1].statsCostBelow + p->pPlanes[v+1].statsCost;
            
            assert( CostCurrent == p->pPlanes[VarCurrent].statsCostAbove + 
                                    p->pPlanes[VarCurrent].statsCost +
                                    p->pPlanes[VarCurrent].statsCostBelow );

            // move down
            for ( q = VarCurrent; q < p->nSupp-1; )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
                q++;    // change q to point to the position of this var in the order
                p->pVarCosts[q] = CostCurrent;
                // update the lower bound (assuming that for level q-1 it is set correctly)
                p->pPlanes[q].statsCostAbove = p->pPlanes[q-1].statsCostAbove + p->pPlanes[q-1].statsCost;
                // check the upper bound
                if ( CostCurrent >= CostLimit )
                    break;
                // check the lower bound
                if ( p->pPlanes[q].statsCostAbove + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostBelow/REO_QUAL_PAR >= CostBest )
                    break;
                // update the best cost
                if ( CostBest > CostCurrent )
                {
                    CostBest = CostCurrent;
                    BestQ    = q;
                    // adjust node limit
                    CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
                }

                // when we are reordering for width or APL, it may happen that
                // the number of nodes has grown above certain limit,
                // in which case we have to resize the data structures
                if ( p->fMinWidth || p->fMinApl )
                {
                    if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
                    {
//                        printf( "Resizing data structures. Old size = %6d. New size = %6d.\n",  p->nNodesMaxAlloc, p->nNodesCur );
                        reoResizeStructures( p, 0, p->nNodesCur, 0 );
                    }
                }
            }

            // move up
            for ( --q; q >= 0; q-- )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q, 1 );
                // now q points to the position of this var in the order
                // sanity check: the number of nodes on the back pass should be the same
                if ( p->pVarCosts[q] != REO_HIGH_VALUE && fabs( p->pVarCosts[q] - CostCurrent ) > REO_COST_EPSILON )
                    printf("reoReorderSift(): Error! On the backward move, the costs are different.\n");
                p->pVarCosts[q] = CostCurrent;
                // update the lower bound (assuming that for level q+1 it is set correctly)
                p->pPlanes[q].statsCostBelow = p->pPlanes[q+1].statsCostBelow + p->pPlanes[q+1].statsCost;
                // check the bounds only if the variable already reached its previous position
                if ( q <= BestQ )
                {
                    // check the upper bound
                    if ( CostCurrent >= CostLimit )
                        break;
                    // check the lower bound
                    if ( p->pPlanes[q].statsCostBelow + (REO_QUAL_PAR-1)*p->pPlanes[q].statsCostAbove/REO_QUAL_PAR >= CostBest )
                        break;
                }
                // update the best cost
                if ( CostBest >= CostCurrent )
                {
                    CostBest = CostCurrent;
                    BestQ    = q;
                    // adjust node limit
                    CostLimit = ddMin( CostLimit, 1 + (int)(REO_REORDER_LIMIT * CostCurrent) );
                }

                // when we are reordering for width or APL, it may happen that
                // the number of nodes has grown above certain limit,
                // in which case we have to resize the data structures
                if ( p->fMinWidth || p->fMinApl )
                {
                    if ( p->nNodesCur >= 2 * p->nNodesMaxAlloc )
                    {
//                        printf( "Resizing data structures. Old size = %6d. New size = %6d.\n",  p->nNodesMaxAlloc, p->nNodesCur );
                        reoResizeStructures( p, 0, p->nNodesCur, 0 );
                    }
                }
            }
            // fix the plane index
            if ( q == -1 )
                q++;
            // now q points to the position of this var in the order
            // move the variable down from the given position (q) to the best position (BestQ)
            assert( q <= BestQ );
            for ( ; q < BestQ; q++ )
            {
                CostCurrent -= reoReorderSwapAdjacentVars( p, q, 0 );
                // sanity check: the number of nodes on the back pass should be the same
                if ( fabs( p->pVarCosts[q+1] - CostCurrent ) > REO_COST_EPSILON )
                {
                    printf("reoReorderSift(): Error! On the return move, the costs are different.\n" );
                    fflush(stdout);
                }
            }
        }
        assert( fabs( CostBest - CostCurrent ) < REO_COST_EPSILON );

        // update the cost 
        if ( p->fMinWidth )
            p->nWidthCur = (int)CostBest;
        else if ( p->fMinApl )
            p->nAplCur = CostCurrent;
        else
            p->nNodesCur = (int)CostBest;
    }

    // remove the sifted attributes if any
    for ( v = 0; v < p->nSupp; v++ )
        p->pPlanes[v].fSifted = 0;
}

////////////////////////////////////////////////////////////////////////
///                         END OF FILE                              ///
////////////////////////////////////////////////////////////////////////