summaryrefslogtreecommitdiffstats
path: root/src/misc/espresso/contain.c
blob: 63eba8b2c4e38d682e7ca0fb8c21cbddba49a7cc (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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
 * Revision Control Information
 *
 * $Source$
 * $Author$
 * $Revision$
 * $Date$
 *
 */
/*
    contain.c -- set containment routines

    These are complex routines for performing containment over a
    family of sets, but they have the advantage of being much faster
    than a straightforward n*n routine.

    First the cubes are sorted by size, and as a secondary key they are
    sorted so that if two cubes are equal they end up adjacent.  We can
    than quickly remove equal cubes from further consideration by
    comparing each cube to its neighbor.  Finally, because the cubes
    are sorted by size, we need only check cubes which are larger (or
    smaller) than a given cube for containment.
*/

#include "espresso.h"

ABC_NAMESPACE_IMPL_START



/*
    sf_contain -- perform containment on a set family (delete sets which
    are contained by some larger set in the family).  No assumptions are
    made about A, and the result will be returned in decreasing order of
    set size.
*/
pset_family sf_contain(A)
INOUT pset_family A;            /* disposes of A */
{
    int cnt;
    pset *A1;
    pset_family R;

    A1 = sf_sort(A, descend);           /* sort into descending order */
    cnt = rm_equal(A1, descend);        /* remove duplicates */
    cnt = rm_contain(A1);               /* remove contained sets */
    R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */
    sf_free(A);
    return R;
}


/*
    sf_rev_contain -- perform containment on a set family (delete sets which
    contain some smaller set in the family).  No assumptions are made about
    A, and the result will be returned in increasing order of set size
*/
pset_family sf_rev_contain(A)
INOUT pset_family A;            /* disposes of A */
{
    int cnt;
    pset *A1;
    pset_family R;

    A1 = sf_sort(A, ascend);            /* sort into ascending order */
    cnt = rm_equal(A1, ascend);         /* remove duplicates */
    cnt = rm_rev_contain(A1);           /* remove containing sets */
    R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */
    sf_free(A);
    return R;
}


/*
    sf_ind_contain -- perform containment on a set family (delete sets which
    are contained by some larger set in the family).  No assumptions are
    made about A, and the result will be returned in decreasing order of
    set size.  Also maintains a set of row_indices to track which rows
    disappear and how the rows end up permuted.
*/
pset_family sf_ind_contain(A, row_indices)
INOUT pset_family A;            /* disposes of A */
INOUT int *row_indices;         /* updated with the new values */
{
    int cnt;
    pset *A1;
    pset_family R;

    A1 = sf_sort(A, descend);           /* sort into descending order */
    cnt = rm_equal(A1, descend);        /* remove duplicates */
    cnt = rm_contain(A1);               /* remove contained sets */
    R = sf_ind_unlist(A1, cnt, A->sf_size, row_indices, A->data);
    sf_free(A);
    return R;
}


/* sf_dupl -- delete duplicate sets in a set family */
pset_family sf_dupl(A)
INOUT pset_family A;            /* disposes of A */
{
    register int cnt;
    register pset *A1;
    pset_family R;

    A1 = sf_sort(A, descend);           /* sort the set family */
    cnt = rm_equal(A1, descend);        /* remove duplicates */
    R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */
    sf_free(A);
    return R;
}


/*
    sf_union -- form the contained union of two set families (delete
    sets which are contained by some larger set in the family).  A and
    B are assumed already sorted in decreasing order of set size (and
    the SIZE field is assumed to contain the set size), and the result
    will be returned sorted likewise.
*/
pset_family sf_union(A, B)
INOUT pset_family A, B;         /* disposes of A and B */
{
    int cnt;
    pset_family R;
    pset *A1 = sf_list(A), *B1 = sf_list(B), *E1;

    E1 = ALLOC(pset, MAX(A->count, B->count) + 1);
    cnt = rm2_equal(A1, B1, E1, descend);
    cnt += rm2_contain(A1, B1) + rm2_contain(B1, A1);
    R = sf_merge(A1, B1, E1, cnt, A->sf_size);
    sf_free(A); sf_free(B);
    return R;
}


/*
    dist_merge -- consider all sets to be "or"-ed with "mask" and then
    delete duplicates from the set family.
*/
pset_family dist_merge(A, mask)
INOUT pset_family A;            /* disposes of A */
IN pset mask;                   /* defines variables to mask out */
{
    pset *A1;
    int cnt;
    pset_family R;

    (void) set_copy(cube.temp[0], mask);
    A1 = sf_sort(A, d1_order);
    cnt = d1_rm_equal(A1, d1_order);
    R = sf_unlist(A1, cnt, A->sf_size);
    sf_free(A);
    return R;
}


/*
    d1merge -- perform an efficient distance-1 merge of cubes of A
*/
pset_family d1merge(A, var)
INOUT pset_family A;            /* disposes of A */
IN int var;
{
    return dist_merge(A, cube.var_mask[var]);
}



/* d1_rm_equal -- distance-1 merge (merge cubes which are equal under a mask) */
int d1_rm_equal(A1, compare)
register pset *A1;                /* array of set pointers */
int (*compare)();                /* comparison function */
{
    register int i, j, dest;

    dest = 0;
    if (A1[0] != (pcube) NULL) {
    for(i = 0, j = 1; A1[j] != (pcube) NULL; j++)
        if ( (*compare)(&A1[i], &A1[j]) == 0) {
        /* if sets are equal (under the mask) merge them */
        (void) set_or(A1[i], A1[i], A1[j]);
        } else {
        /* sets are unequal, so save the set i */
        A1[dest++] = A1[i];
        i = j;
        }
    A1[dest++] = A1[i];
    }
    A1[dest] = (pcube) NULL;
    return dest;
}


/* rm_equal -- scan a sorted array of set pointers for duplicate sets */
int rm_equal(A1, compare)
INOUT pset *A1;                 /* updated in place */
IN int (*compare)();
{
    register pset *p, *pdest = A1;

    if (*A1 != NULL) {                  /* If more than one set */
    for(p = A1+1; *p != NULL; p++)
        if ((*compare)(p, p-1) != 0)
        *pdest++ = *(p-1);
    *pdest++ = *(p-1);
    *pdest = NULL;
    }
    return pdest - A1;
}


/* rm_contain -- perform containment over a sorted array of set pointers */
int rm_contain(A1)
INOUT pset *A1;                 /* updated in place */
{
    register pset *pa, *pb;
    register pset *pcheck = NULL; // Suppress "might be used uninitialized"
    register pset a, b;
    pset *pdest = A1;
    int last_size = -1;

    /* Loop for all cubes of A1 */
    for(pa = A1; (a = *pa++) != NULL; ) {
    /* Update the check pointer if the size has changed */
    if (SIZE(a) != last_size)
        last_size = SIZE(a), pcheck = pdest;
    for(pb = A1; pb != pcheck; ) {
        b = *pb++;
        INLINEsetp_implies(a, b, /* when_false => */ continue);
        goto lnext1;
    }
    /* set a was not contained by some larger set, so save it */
    *pdest++ = a;
    lnext1: ;
    }

    *pdest = NULL;
    return pdest - A1;
}


/* rm_rev_contain -- perform rcontainment over a sorted array of set pointers */
int rm_rev_contain(A1)
INOUT pset *A1;                 /* updated in place */
{
    register pset *pa, *pb;
    register pset *pcheck = NULL; // Suppress "might be used uninitialized"
    register pset a, b;
    pset *pdest = A1;
    int last_size = -1;

    /* Loop for all cubes of A1 */
    for(pa = A1; (a = *pa++) != NULL; ) {
    /* Update the check pointer if the size has changed */
    if (SIZE(a) != last_size)
        last_size = SIZE(a), pcheck = pdest;
    for(pb = A1; pb != pcheck; ) {
        b = *pb++;
        INLINEsetp_implies(b, a, /* when_false => */ continue);
        goto lnext1;
    }
    /* the set a did not contain some smaller set, so save it */
    *pdest++ = a;
    lnext1: ;
    }

    *pdest = NULL;
    return pdest - A1;
}


/* rm2_equal -- check two sorted arrays of set pointers for equal cubes */
int rm2_equal(A1, B1, E1, compare)
INOUT register pset *A1, *B1;           /* updated in place */
OUT pset *E1;
IN int (*compare)();
{
    register pset *pda = A1, *pdb = B1, *pde = E1;

    /* Walk through the arrays advancing pointer to larger cube */
    for(; *A1 != NULL && *B1 != NULL; )
    switch((*compare)(A1, B1)) {
        case -1:    /* "a" comes before "b" */
        *pda++ = *A1++; break;
        case 0:     /* equal cubes */
        *pde++ = *A1++; B1++; break;
        case 1:     /* "a" is to follow "b" */
        *pdb++ = *B1++; break;
    }

    /* Finish moving down the pointers of A and B */
    while (*A1 != NULL)
    *pda++ = *A1++;
    while (*B1 != NULL)
    *pdb++ = *B1++;
    *pda = *pdb = *pde = NULL;

    return pde - E1;
}


/* rm2_contain -- perform containment between two arrays of set pointers */
int rm2_contain(A1, B1)
INOUT pset *A1;                 /* updated in place */
IN pset *B1;                    /* unchanged */
{
    register pset *pa, *pb, a, b, *pdest = A1;

    /* for each set in the first array ... */
    for(pa = A1; (a = *pa++) != NULL; ) {
    /* for each set in the second array which is larger ... */
    for(pb = B1; (b = *pb++) != NULL && SIZE(b) > SIZE(a); ) {
        INLINEsetp_implies(a, b, /* when_false => */ continue);
        /* set was contained in some set of B, so don't save pointer */
        goto lnext1;
    }
    /* set wasn't contained in any set of B, so save the pointer */
    *pdest++ = a;
    lnext1: ;
    }

    *pdest = NULL;                      /* sentinel */
    return pdest - A1;                  /* # elements in A1 */
}



/* sf_sort -- sort the sets of A */
pset *sf_sort(A, compare)
IN pset_family A;
IN int (*compare)();
{
    register pset p, last, *pdest, *A1;

    /* Create a single array pointing to each cube of A */
    pdest = A1 = ALLOC(pset, A->count + 1);
    foreach_set(A, last, p) {
    PUTSIZE(p, set_ord(p));         /* compute the set size */
    *pdest++ = p;                   /* save the pointer */
    }
    *pdest = NULL;                      /* Sentinel -- never seen by sort */

    /* Sort cubes by size */
    qsort((char *) A1, (size_t)A->count, sizeof(pset), compare);
    return A1;
}


/* sf_list -- make a list of pointers to the sets in a set family */
pset *sf_list(A)
IN register pset_family A;
{
    register pset p, last, *pdest, *A1;

    /* Create a single array pointing to each cube of A */
    pdest = A1 = ALLOC(pset, A->count + 1);
    foreach_set(A, last, p)
    *pdest++ = p;                   /* save the pointer */
    *pdest = NULL;                      /* Sentinel */
    return A1;
}


/* sf_unlist -- make a set family out of a list of pointers to sets */
pset_family sf_unlist(A1, totcnt, size)
IN pset *A1;
IN int totcnt, size;
{
    register pset pr, p, *pa;
    pset_family R = sf_new(totcnt, size);

    R->count = totcnt;
    for(pr = R->data, pa = A1; (p = *pa++) != NULL; pr += R->wsize)
    INLINEset_copy(pr, p);
    FREE(A1);
    return R;
}


/* sf_ind_unlist -- make a set family out of a list of pointers to sets */
pset_family sf_ind_unlist(A1, totcnt, size, row_indices, pfirst)
IN pset *A1;
IN int totcnt, size;
INOUT int *row_indices;
IN register pset pfirst;
{
    register pset pr, p, *pa;
    register int i, *new_row_indices;
    pset_family R = sf_new(totcnt, size);

    R->count = totcnt;
    new_row_indices = ALLOC(int, totcnt);
    for(pr = R->data, pa = A1, i=0; (p = *pa++) != NULL; pr += R->wsize, i++) {
    INLINEset_copy(pr, p);
    new_row_indices[i] = row_indices[(p - pfirst)/R->wsize];
    }
    for(i = 0; i < totcnt; i++)
    row_indices[i] = new_row_indices[i];
    FREE(new_row_indices);
    FREE(A1);
    return R;
}


/* sf_merge -- merge three sorted lists of set pointers */
pset_family sf_merge(A1, B1, E1, totcnt, size)
INOUT pset *A1, *B1, *E1;               /* will be disposed of */
IN int totcnt, size;
{
    register pset pr, ps, *pmin, *pmid, *pmax;
    pset_family R;
    pset *temp[3], *swap;
    int i, j, n;

    /* Allocate the result set_family */
    R = sf_new(totcnt, size);
    R->count = totcnt;
    pr = R->data;

    /* Quick bubble sort to order the top member of the three arrays */
    n = 3;  temp[0] = A1;  temp[1] = B1;  temp[2] = E1;
    for(i = 0; i < n-1; i++)
    for(j = i+1; j < n; j++)
        if (desc1(*temp[i], *temp[j]) > 0) {
        swap = temp[j];
        temp[j] = temp[i];
        temp[i] = swap;
        }
    pmin = temp[0];  pmid = temp[1];  pmax = temp[2];

    /* Save the minimum element, then update pmin, pmid, pmax */
    while (*pmin != (pset) NULL) {
    ps = *pmin++;
    INLINEset_copy(pr, ps);
    pr += R->wsize;
    if (desc1(*pmin, *pmax) > 0) {
        swap = pmax; pmax = pmin; pmin = pmid; pmid = swap;
    } else if (desc1(*pmin, *pmid) > 0) {
        swap = pmin; pmin = pmid; pmid = swap;
    }
    }

    FREE(A1);
    FREE(B1);
    FREE(E1);
    return R;
}
ABC_NAMESPACE_IMPL_END