Repository navigation
nfa: +refactor Bucket the antichain of processed macrostates by cardinality - #885
Conversation
e17ebc3 to
36f2170
Compare
|
…nality "is_included_antichains()" kept the macrostates processed for one state of the smaller automaton in one unsorted vector, so both the subsumption test and the pruning read every stored entry. Cardinality alone decides which entries can be related to a candidate: a subset is never larger, a superset is never smaller, and at equal cardinality both relations reduce to equality. The processed entries are now bucketed by the cardinality of their macrostate, so the subsumption test reads only the buckets below "|succ|" plus one equality scan, and pruning reads only the buckets above it. Only the cardinalities that actually hold an entry get a bucket, and the buckets are kept ordered by cardinality. Indexing the buckets by cardinality instead would cost a bucket header per unused size: with 10 000 states in the initial macrostate that is 240 KiB per state of the smaller automaton (+303 MiB of peak RSS at 2 000 such states, measured), and both the subsumption test and the pruning would walk those empty buckets. The comment claiming the lists were sorted by set size was wrong (they were only appended to) and is gone, together with the commented-out variants of the orderings that were tried. Measured on random instances where many macrostates share one state of the smaller automaton, inclusion holding in all cases: 8.0 s -> 5.8 s (8 states, 128 noise states, 8 instances) and 294.1 s -> 180.9 s (12 states, 288 noise states, 5 instances). Fixes #785.
36f2170 to
bfed5b6
Compare
|
I benchmarked this branch against the commit it branched off (
43 instances faster, 49 slower, median speed-up 1.00 (min 0.50, max 2.00).
24 faster, 18 slower, median speed-up 1.00 (min 0.67, max 1.67).
197 faster, 187 slower, median speed-up 1.004. No instance changed its answer, no timeout appeared or disappeared, and no family moved outside measurement noise. So the change is performance-neutral on these benchmarks -- that is not a refutation of the speed-up claimed in #785: these families answer in roughly 2 ms at the median and never build the long processed lists the bucketing is meant to shorten, and the Worth noting on the correctness side: the neutral result means the bucketing costs nothing on inputs it cannot help, which is the property one would want from it. |
"is_included_antichains()" kept the macrostates processed for one state of the
smaller automaton in one unsorted vector, so both the subsumption test and the
pruning read every stored entry. Cardinality alone decides which entries can
be related to a candidate: a subset is never larger, a superset is never
smaller, and at equal cardinality both relations reduce to equality. The
processed entries are now bucketed by the cardinality of their macrostate, so
the subsumption test reads only the buckets below "|succ|" plus one equality
scan, and pruning reads only the buckets above it.
Only the cardinalities that actually hold an entry get a bucket, and the
buckets are kept ordered by cardinality. Indexing the buckets by cardinality
instead would cost a bucket header per unused size: with 10 000 states in the
initial macrostate that is 240 KiB per state of the smaller automaton (+303
MiB of peak RSS at 2 000 such states, measured), and both the subsumption test
and the pruning would walk those empty buckets.
The comment claiming the lists were sorted by set size was wrong (they were
only appended to) and is gone, together with the commented-out variants of the
orderings that were tried.
Measured on random instances where many macrostates share one state of the
smaller automaton, inclusion holding in all cases: 8.0 s -> 5.8 s (8 states,
128 noise states, 8 instances) and 294.1 s -> 180.9 s (12 states, 288 noise
states, 5 instances).
Fixes #785.
Fixes #785