summaryrefslogtreecommitdiffstats
path: root/src/misc/espresso/sparse.c
blob: 137ce7c1b2adcbca97bfe87daf6c17e74fb1b13b (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
/*
 * Revision Control Information
 *
 * $Source$
 * $Author$
 * $Revision$
 * $Date$
 *
 */
/*
    module: sparse.c

    make_sparse is a last-step cleanup to reduce the total number
    of literals in the cover.

    This is done by reducing the "sparse" variables (using a modified
    version of irredundant rather than reduce), followed by expanding
    the "dense" variables (using modified version of expand).
*/

#include "espresso.h"

pcover make_sparse(F, D, R)
pcover F, D, R;
{
    cost_t cost, best_cost;

    cover_cost(F, &best_cost);

    do {
    EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost);
    if (cost.total == best_cost.total)
        break;
    copy_cost(&cost, &best_cost);

    EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost);
    if (cost.total == best_cost.total)
        break;
    copy_cost(&cost, &best_cost);
    } while (force_irredundant);

    return F;
}

/*
    mv_reduce -- perform an "optimal" reduction of the variables which
    we desire to be sparse

    This could be done using "reduce" and then saving just the desired
    part of the reduction.  Instead, this version uses IRRED to find
    which cubes of an output are redundant.  Note that this gets around
    the cube-ordering problem.

    In normal use, it is expected that the cover is irredundant and
    hence no cubes will be reduced to the empty cube (however, this is
    checked for and such cubes will be deleted)
*/

pcover
mv_reduce(F, D)
pcover F, D;
{
    register int i, var;
    register pcube p, p1, last;
    int index;
    pcover F1, D1;
    pcube *F_cube_table;

    /* loop for each multiple-valued variable */
    for(var = 0; var < cube.num_vars; var++) {

    if (cube.sparse[var]) {

        /* loop for each part of the variable */
        for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) {

        /* remember mapping of F1 cubes back to F cubes */
        F_cube_table = ALLOC(pcube, F->count);

        /* 'cofactor' against part #i of variable #var */
        F1 = new_cover(F->count);
        foreach_set(F, last, p) {
            if (is_in_set(p, i)) {
            F_cube_table[F1->count] = p;
            p1 = GETSET(F1, F1->count++);
            (void) set_diff(p1, p, cube.var_mask[var]);
            set_insert(p1, i);
            }
        }

        /* 'cofactor' against part #i of variable #var */
        /* not really necessary -- just more efficient ? */
        D1 = new_cover(D->count);
        foreach_set(D, last, p) {
            if (is_in_set(p, i)) {
            p1 = GETSET(D1, D1->count++);
            (void) set_diff(p1, p, cube.var_mask[var]);
            set_insert(p1, i);
            }
        }

        mark_irredundant(F1, D1);

        /* now remove part i from cubes which are redundant */
        index = 0;
        foreach_set(F1, last, p1) {
            if (! TESTP(p1, ACTIVE)) {
            p = F_cube_table[index];

            /*   don't reduce a variable which is full
             *   (unless it is the output variable)
             */
            if (var == cube.num_vars-1 ||
                 ! setp_implies(cube.var_mask[var], p)) {
                set_remove(p, i);
            }
            RESET(p, PRIME);
            }
            index++;
        }

        free_cover(F1);
        free_cover(D1);
        FREE(F_cube_table);
        }
    }
    }

    /* Check if any cubes disappeared */
    (void) sf_active(F);
    for(var = 0; var < cube.num_vars; var++) {
    if (cube.sparse[var]) {
        foreach_active_set(F, last, p) {
        if (setp_disjoint(p, cube.var_mask[var])) {
            RESET(p, ACTIVE);
            F->active_count--;
        }
        }
    }
    }

    if (F->count != F->active_count) {
    F = sf_inactive(F);
    }
    return F;
}