• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LearnLib / automatalib / 12304577693

12 Dec 2024 08:51PM UTC coverage: 91.182% (+0.4%) from 90.804%
12304577693

push

github

web-flow
Overhaul minimization code (#83)

* add valmaris algorithm

* initial PT refactoring

* implement bisimulation via valmari

* add documentation

* cleanups

* add invasive hopcroft methods

* some more universal tests

* performance tweaks

* move OneSEVPAMinimizer

* improve documentation

* cleanup

* wording

* fix javadoc errors

564 of 581 new or added lines in 25 files covered. (97.07%)

1 existing line in 1 file now uncovered.

16535 of 18134 relevant lines covered (91.18%)

1.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.1
/util/src/main/java/net/automatalib/util/automaton/minimizer/HopcroftMinimizer.java
1
/* Copyright (C) 2013-2024 TU Dortmund University
2
 * This file is part of AutomataLib, http://www.automatalib.net/.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.automatalib.util.automaton.minimizer;
17

18
import java.util.Collection;
19

20
import net.automatalib.alphabet.Alphabet;
21
import net.automatalib.alphabet.impl.Alphabets;
22
import net.automatalib.automaton.AutomatonCreator;
23
import net.automatalib.automaton.MutableDeterministic;
24
import net.automatalib.automaton.MutableDeterministic.IntAbstraction;
25
import net.automatalib.automaton.UniversalDeterministicAutomaton;
26
import net.automatalib.automaton.UniversalDeterministicAutomaton.FullIntAbstraction;
27
import net.automatalib.automaton.concept.InputAlphabetHolder;
28
import net.automatalib.automaton.fsa.DFA;
29
import net.automatalib.automaton.fsa.MutableDFA;
30
import net.automatalib.automaton.fsa.impl.CompactDFA;
31
import net.automatalib.automaton.impl.UniversalCompactDet;
32
import net.automatalib.automaton.transducer.MealyMachine;
33
import net.automatalib.automaton.transducer.MutableMealyMachine;
34
import net.automatalib.automaton.transducer.impl.CompactMealy;
35
import net.automatalib.util.automaton.minimizer.Storage.BooleanStorage;
36
import net.automatalib.util.automaton.minimizer.Storage.GenericStorage;
37
import net.automatalib.util.automaton.minimizer.Storage.VoidStorage;
38
import net.automatalib.util.minimizer.Minimizer;
39
import net.automatalib.util.partitionrefinement.AutomatonInitialPartitioning;
40
import net.automatalib.util.partitionrefinement.Block;
41
import net.automatalib.util.partitionrefinement.Hopcroft;
42
import net.automatalib.util.partitionrefinement.HopcroftExtractors;
43
import net.automatalib.util.partitionrefinement.HopcroftInitializers;
44
import net.automatalib.util.partitionrefinement.PruningMode;
45
import net.automatalib.util.partitionrefinement.StateSignature;
46

47
/**
48
 * Hopcroft's minimization algorithm for deterministic finite automata.
49
 * <p>
50
 * Hopcroft's algorithm solves the functional coarsest partition problem for finite automata in running time
51
 * {@code O(nk log n)}, where {@code n} is the size of the input DFA and {@code k} the size of the input alphabet.
52
 * <p>
53
 * <b>Important note:</b> Hopcroft's minimization algorithm works for complete automata only. If the automaton is
54
 * partial, you may use the {@link #minimizePartialDFA(DFA) minimizePartial...} utility methods that automatically add a
55
 * sink state when encountering an undefined transitions. If you have very sparse automata, {@link Minimizer} may yield
56
 * better performance.
57
 * <p>
58
 * Note that the partition refinement step only calculates classes of equivalent states. However, minimization also
59
 * requires pruning of states that cannot be reached from the initial state. Most methods in this class support a
60
 * variable of type {@link PruningMode} that controls if and when pruning is performed: if the automaton to be minimized
61
 * is known to be <i>initially connected</i> (i.e., it contains no unreachable states), pruning can be omitted
62
 * completely (by specifying {@link PruningMode#DONT_PRUNE}) without impairing correctness. Otherwise, pruning can be
63
 * chosen to be performed on the automaton to be minimized ({@link PruningMode#PRUNE_BEFORE}), or on the calculated
64
 * state partition ({@link PruningMode#PRUNE_AFTER}). Note that using {@link PruningMode#PRUNE_BEFORE} with the
65
 * {@link #minimizePartialDFA(DFA) minimizePartial...} methods may result in the artificial sink state being included in
66
 * the final automaton. For methods that do not provide a {@code pruningMode} parameter, the default is
67
 * {@link PruningMode#PRUNE_AFTER}.
68
 */
69
public final class HopcroftMinimizer {
70

71
    private HopcroftMinimizer() {}
72

73
    /**
74
     * Minimizes the given, complete DFA. The result is returned in the form of a {@link CompactDFA}, using the input
75
     * alphabet obtained via {@link InputAlphabetHolder#getInputAlphabet()}. Pruning is performed after computing state
76
     * equivalences.
77
     *
78
     * @param dfa
79
     *         the DFA to minimize
80
     * @param <I>
81
     *         input symbol type
82
     * @param <A>
83
     *         automaton type
84
     *
85
     * @return a minimized version of the specified DFA
86
     */
87
    public static <I, A extends DFA<?, I> & InputAlphabetHolder<I>> CompactDFA<I> minimizeDFA(A dfa) {
88
        return minimizeDFA(dfa, dfa.getInputAlphabet());
2✔
89
    }
90

91
    /**
92
     * Minimizes the given, complete DFA. The result is returned in the form of a {@link CompactDFA}, and pruning is
93
     * performed after computing state equivalences.
94
     *
95
     * @param dfa
96
     *         the DFA to minimize
97
     * @param alphabet
98
     *         the input alphabet (this will be the input alphabet of the returned DFA)
99
     * @param <I>
100
     *         input symbol type
101
     *
102
     * @return a minimized version of the specified DFA
103
     */
104
    public static <I> CompactDFA<I> minimizeDFA(DFA<?, I> dfa, Alphabet<I> alphabet) {
105
        return minimizeDFA(dfa, alphabet, PruningMode.PRUNE_AFTER);
2✔
106
    }
107

108
    /**
109
     * Minimizes the given, complete DFA. The result is returned in the form of a {@link CompactDFA}.
110
     *
111
     * @param dfa
112
     *         the DFA to minimize
113
     * @param alphabet
114
     *         the input alphabet (this will be the input alphabet of the returned DFA)
115
     * @param pruningMode
116
     *         the pruning mode
117
     * @param <I>
118
     *         input symbol type
119
     *
120
     * @return a minimized version of the specified DFA
121
     */
122
    public static <I> CompactDFA<I> minimizeDFA(DFA<?, I> dfa, Alphabet<I> alphabet, PruningMode pruningMode) {
123
        return minimizeDFA(dfa, alphabet, pruningMode, new CompactDFA.Creator<>());
2✔
124
    }
125

126
    /**
127
     * Minimizes the given, complete DFA. The result is returned in the form of the automaton created by the given
128
     * creator.
129
     *
130
     * @param dfa
131
     *         the DFA to minimize
132
     * @param alphabet
133
     *         the input alphabet (this will be the input alphabet of the returned DFA)
134
     * @param pruningMode
135
     *         the pruning mode
136
     * @param creator
137
     *         the creator for constructing the automata instance to return
138
     * @param <A>
139
     *         automaton type
140
     * @param <I>
141
     *         input symbol type
142
     *
143
     * @return a minimized version of the specified DFA
144
     */
145
    public static <A extends MutableDFA<?, I>, I> A minimizeDFA(DFA<?, I> dfa,
146
                                                                Alphabet<I> alphabet,
147
                                                                PruningMode pruningMode,
148
                                                                AutomatonCreator<A, I> creator) {
149
        return minimizeUniversal(dfa, alphabet, pruningMode, AutomatonInitialPartitioning.BY_STATE_PROPERTY, creator);
2✔
150
    }
151

152
    /**
153
     * Minimizes the given, complete DFA. The result is written directly to the input DFA.
154
     *
155
     * @param dfa
156
     *         the DFA to minimize
157
     * @param inputs
158
     *         the input symbols to consider for minimization
159
     * @param <A>
160
     *         automaton type
161
     * @param <I>
162
     *         input symbol type
163
     *
164
     * @return {@code dfa} for convenience
165
     */
166
    public static <I, A extends MutableDFA<?, I>> A minimizeDFAInvasive(A dfa, Collection<? extends I> inputs) {
167
        return minimizeInvasive(dfa,
2✔
168
                                inputs,
169
                                AutomatonInitialPartitioning.BY_STATE_PROPERTY,
170
                                new BooleanStorage(),
171
                                new VoidStorage());
172
    }
173

174
    /**
175
     * Minimizes the given, potentially partial DFA. The result is returned in the form of a {@link CompactDFA}, using
176
     * the input alphabet obtained via {@link InputAlphabetHolder#getInputAlphabet()}. Pruning is performed after
177
     * computing state equivalences.
178
     *
179
     * @param dfa
180
     *         the DFA to minimize
181
     * @param <I>
182
     *         input symbol type
183
     * @param <A>
184
     *         automaton type
185
     *
186
     * @return a minimized version of the specified DFA
187
     */
188
    public static <I, A extends DFA<?, I> & InputAlphabetHolder<I>> CompactDFA<I> minimizePartialDFA(A dfa) {
189
        return minimizePartialDFA(dfa, dfa.getInputAlphabet());
2✔
190
    }
191

192
    /**
193
     * Minimizes the given, potentially partial DFA. The result is returned in the form of a {@link CompactDFA}, and
194
     * pruning is performed after computing state equivalences.
195
     *
196
     * @param dfa
197
     *         the DFA to minimize
198
     * @param alphabet
199
     *         the input alphabet (this will be the input alphabet of the returned DFA)
200
     * @param <I>
201
     *         input symbol type
202
     *
203
     * @return a minimized version of the specified DFA
204
     */
205
    public static <I> CompactDFA<I> minimizePartialDFA(DFA<?, I> dfa, Alphabet<I> alphabet) {
206
        return minimizePartialDFA(dfa, alphabet, PruningMode.PRUNE_AFTER);
2✔
207
    }
208

209
    /**
210
     * Minimizes the given, potentially partial DFA. The result is returned in the form of a {@link CompactDFA}.
211
     *
212
     * @param dfa
213
     *         the DFA to minimize
214
     * @param alphabet
215
     *         the input alphabet (this will be the input alphabet of the returned DFA)
216
     * @param pruningMode
217
     *         the pruning mode
218
     * @param <I>
219
     *         input symbol type
220
     *
221
     * @return a minimized version of the specified DFA
222
     */
223
    public static <I> CompactDFA<I> minimizePartialDFA(DFA<?, I> dfa, Alphabet<I> alphabet, PruningMode pruningMode) {
224
        return minimizePartialDFA(dfa, alphabet, pruningMode, new CompactDFA.Creator<>());
2✔
225
    }
226

227
    /**
228
     * Minimizes the given, potentially partial DFA. The result is returned in the form of the automaton created by the
229
     * given creator.
230
     *
231
     * @param dfa
232
     *         the DFA to minimize
233
     * @param alphabet
234
     *         the input alphabet (this will be the input alphabet of the returned DFA)
235
     * @param pruningMode
236
     *         the pruning mode
237
     * @param creator
238
     *         the creator for constructing the automata instance to return
239
     * @param <A>
240
     *         automaton type
241
     * @param <I>
242
     *         input symbol type
243
     *
244
     * @return a minimized version of the specified DFA
245
     */
246
    public static <A extends MutableDFA<?, I>, I> A minimizePartialDFA(DFA<?, I> dfa,
247
                                                                       Alphabet<I> alphabet,
248
                                                                       PruningMode pruningMode,
249
                                                                       AutomatonCreator<A, I> creator) {
250
        return minimizePartialUniversal(dfa,
2✔
251
                                        alphabet,
252
                                        pruningMode,
253
                                        AutomatonInitialPartitioning.BY_STATE_PROPERTY,
254
                                        Boolean.FALSE,
255
                                        creator);
256
    }
257

258
    /**
259
     * Minimizes the given, complete Mealy machine. The result is returned in the form of a {@link CompactMealy}, using
260
     * the alphabet obtained via {@link InputAlphabetHolder#getInputAlphabet()}. Pruning is performed after computing
261
     * state equivalences.
262
     *
263
     * @param mealy
264
     *         the Mealy machine to minimize
265
     * @param <I>
266
     *         input symbol type
267
     * @param <O>
268
     *         output symbol type
269
     * @param <A>
270
     *         automaton type
271
     *
272
     * @return a minimized version of the specified Mealy machine
273
     */
274
    public static <I, O, A extends MealyMachine<?, I, ?, O> & InputAlphabetHolder<I>> CompactMealy<I, O> minimizeMealy(A mealy) {
NEW
275
        return minimizeMealy(mealy, mealy.getInputAlphabet());
×
276
    }
277

278
    /**
279
     * Minimizes the given, complete Mealy machine. The result is returned in the form of a {@link CompactMealy}, and
280
     * pruning is performed after computing state equivalences.
281
     *
282
     * @param mealy
283
     *         the Mealy machine to minimize
284
     * @param alphabet
285
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
286
     * @param <I>
287
     *         input symbol type
288
     * @param <O>
289
     *         output symbol type
290
     *
291
     * @return a minimized version of the specified Mealy machine
292
     */
293
    public static <I, O> CompactMealy<I, O> minimizeMealy(MealyMachine<?, I, ?, O> mealy, Alphabet<I> alphabet) {
NEW
294
        return minimizeMealy(mealy, alphabet, PruningMode.PRUNE_AFTER);
×
295
    }
296

297
    /**
298
     * Minimizes the given, complete Mealy machine. The result is returned in the form of a {@link CompactMealy}.
299
     *
300
     * @param mealy
301
     *         the Mealy machine to minimize
302
     * @param alphabet
303
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
304
     * @param pruningMode
305
     *         the pruning mode
306
     * @param <I>
307
     *         input symbol type
308
     * @param <O>
309
     *         output symbol type
310
     *
311
     * @return a minimized version of the specified Mealy machine
312
     */
313
    public static <I, O> CompactMealy<I, O> minimizeMealy(MealyMachine<?, I, ?, O> mealy,
314
                                                          Alphabet<I> alphabet,
315
                                                          PruningMode pruningMode) {
NEW
316
        return minimizeMealy(mealy, alphabet, pruningMode, new CompactMealy.Creator<>());
×
317
    }
318

319
    /**
320
     * Minimizes the given, complete Mealy machine. The result is returned in the form of the automaton created by the
321
     * given creator.
322
     *
323
     * @param mealy
324
     *         the Mealy machine to minimize
325
     * @param alphabet
326
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
327
     * @param pruningMode
328
     *         the pruning mode
329
     * @param creator
330
     *         the creator for constructing the automata instance to return
331
     * @param <A>
332
     *         automaton type
333
     * @param <I>
334
     *         input symbol type
335
     * @param <O>
336
     *         output symbol type
337
     *
338
     * @return a minimized version of the specified Mealy machine
339
     */
340
    public static <A extends MutableMealyMachine<?, I, ?, O>, I, O> A minimizeMealy(MealyMachine<?, I, ?, O> mealy,
341
                                                                                    Alphabet<I> alphabet,
342
                                                                                    PruningMode pruningMode,
343
                                                                                    AutomatonCreator<A, I> creator) {
NEW
344
        return minimizeUniversal(mealy,
×
345
                                 alphabet,
346
                                 pruningMode,
347
                                 AutomatonInitialPartitioning.BY_TRANSITION_PROPERTIES,
348
                                 creator);
349
    }
350

351
    /**
352
     * Minimizes the given, complete Mealy machine. The result is written directly to the input Mealy machine.
353
     *
354
     * @param mealy
355
     *         the Mealy machine to minimize
356
     * @param inputs
357
     *         the input symbols to consider for minimization
358
     * @param <A>
359
     *         automaton type
360
     * @param <I>
361
     *         input symbol type
362
     * @param <O>
363
     *         output symbol type
364
     *
365
     * @return {@code mealy} for convenience
366
     */
367
    public static <I, O, A extends MutableMealyMachine<?, I, ?, O>> A minimizeMealyInvasive(A mealy,
368
                                                                                            Collection<? extends I> inputs) {
369
        return minimizeInvasive(mealy,
2✔
370
                                inputs,
371
                                AutomatonInitialPartitioning.BY_TRANSITION_PROPERTIES,
372
                                new VoidStorage(),
373
                                new GenericStorage<>());
374
    }
375

376
    /**
377
     * Minimizes the given, potentially partial Mealy machine. The result is returned in the form of a
378
     * {@link CompactMealy}, using the alphabet obtained via {@link InputAlphabetHolder#getInputAlphabet()}. Pruning is
379
     * performed after computing state equivalences.
380
     *
381
     * @param mealy
382
     *         the Mealy machine to minimize
383
     * @param <I>
384
     *         input symbol type
385
     * @param <O>
386
     *         output symbol type
387
     * @param <A>
388
     *         automaton type
389
     *
390
     * @return a minimized version of the specified Mealy machine
391
     */
392
    public static <I, O, A extends MealyMachine<?, I, ?, O> & InputAlphabetHolder<I>> CompactMealy<I, O> minimizePartialMealy(
393
            A mealy) {
NEW
394
        return minimizePartialMealy(mealy, mealy.getInputAlphabet());
×
395
    }
396

397
    /**
398
     * Minimizes the given, potentially partial Mealy machine. The result is returned in the form of a
399
     * {@link CompactMealy}, and pruning is performed after computing state equivalences.
400
     *
401
     * @param mealy
402
     *         the Mealy machine to minimize
403
     * @param alphabet
404
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
405
     * @param <I>
406
     *         input symbol type
407
     * @param <O>
408
     *         output symbol type
409
     *
410
     * @return a minimized version of the specified Mealy machine
411
     */
412
    public static <I, O> CompactMealy<I, O> minimizePartialMealy(MealyMachine<?, I, ?, O> mealy, Alphabet<I> alphabet) {
NEW
413
        return minimizePartialMealy(mealy, alphabet, PruningMode.PRUNE_AFTER);
×
414
    }
415

416
    /**
417
     * Minimizes the given, potentially partial Mealy machine. The result is returned in the form of a
418
     * {@link CompactMealy}.
419
     *
420
     * @param mealy
421
     *         the Mealy machine to minimize
422
     * @param alphabet
423
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
424
     * @param pruningMode
425
     *         the pruning mode
426
     * @param <I>
427
     *         input symbol type
428
     * @param <O>
429
     *         output symbol type
430
     *
431
     * @return a minimized version of the specified Mealy machine
432
     */
433
    public static <I, O> CompactMealy<I, O> minimizePartialMealy(MealyMachine<?, I, ?, O> mealy,
434
                                                                 Alphabet<I> alphabet,
435
                                                                 PruningMode pruningMode) {
436
        return minimizePartialMealy(mealy, alphabet, pruningMode, new CompactMealy.Creator<>());
2✔
437
    }
438

439
    /**
440
     * Minimizes the given, potentially partial Mealy machine. The result is returned in the form of the automaton
441
     * created by the given creator.
442
     *
443
     * @param mealy
444
     *         the Mealy machine to minimize
445
     * @param alphabet
446
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
447
     * @param pruningMode
448
     *         the pruning mode
449
     * @param creator
450
     *         the creator for constructing the automata instance to return
451
     * @param <A>
452
     *         automaton type
453
     * @param <I>
454
     *         input symbol type
455
     * @param <O>
456
     *         output symbol type
457
     *
458
     * @return a minimized version of the specified Mealy machine
459
     */
460
    public static <A extends MutableMealyMachine<?, I, ?, O>, I, O> A minimizePartialMealy(MealyMachine<?, I, ?, O> mealy,
461
                                                                                           Alphabet<I> alphabet,
462
                                                                                           PruningMode pruningMode,
463
                                                                                           AutomatonCreator<A, I> creator) {
464
        return minimizePartialUniversal(mealy,
2✔
465
                                        alphabet,
466
                                        pruningMode,
467
                                        AutomatonInitialPartitioning.BY_TRANSITION_PROPERTIES,
468
                                        StateSignature.byTransitionProperties(new Object[alphabet.size()]),
2✔
469
                                        creator);
470
    }
471

472
    /**
473
     * Minimizes the given, complete automaton using the full state signature. Pruning is performed after computing
474
     * state equivalences.
475
     *
476
     * @param automaton
477
     *         the automaton to minimize
478
     * @param alphabet
479
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
480
     * @param <I>
481
     *         input symbol type
482
     * @param <SP>
483
     *         state property type
484
     * @param <TP>
485
     *         transition property type
486
     *
487
     * @return the minimized automaton, initially constructed from the given {@code creator}.
488
     */
489
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizeUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
490
                                                                               Alphabet<I> alphabet) {
NEW
491
        return minimizeUniversal(automaton, alphabet, PruningMode.PRUNE_AFTER);
×
492
    }
493

494
    /**
495
     * Minimizes the given, complete automaton using the full state signature.
496
     *
497
     * @param automaton
498
     *         the automaton to minimize
499
     * @param alphabet
500
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
501
     * @param pruningMode
502
     *         the pruning mode
503
     * @param <I>
504
     *         input symbol type
505
     * @param <SP>
506
     *         state property type
507
     * @param <TP>
508
     *         transition property type
509
     *
510
     * @return the minimized automaton, initially constructed from the given {@code creator}.
511
     */
512
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizeUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
513
                                                                               Alphabet<I> alphabet,
514
                                                                               PruningMode pruningMode) {
NEW
515
        return minimizeUniversal(automaton, alphabet, pruningMode, AutomatonInitialPartitioning.BY_FULL_SIGNATURE);
×
516
    }
517

518
    /**
519
     * Minimizes the given, complete automaton depending on the given partitioning function.
520
     *
521
     * @param automaton
522
     *         the automaton to minimize
523
     * @param alphabet
524
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
525
     * @param pruningMode
526
     *         the pruning mode
527
     * @param ip
528
     *         the initial partitioning function, determining how states will be distinguished
529
     * @param <I>
530
     *         input symbol type
531
     * @param <SP>
532
     *         state property type
533
     * @param <TP>
534
     *         transition property type
535
     *
536
     * @return the minimized automaton, initially constructed from the given {@code creator}.
537
     */
538
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizeUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
539
                                                                               Alphabet<I> alphabet,
540
                                                                               PruningMode pruningMode,
541
                                                                               AutomatonInitialPartitioning ip) {
NEW
542
        return minimizeUniversal(automaton, alphabet, pruningMode, ip, new UniversalCompactDet.Creator<>());
×
543
    }
544

545
    /**
546
     * Minimizes the given, complete automaton depending on the given partitioning function. The result is returned in
547
     * the form of the automaton created by the given creator.
548
     *
549
     * @param automaton
550
     *         the automaton to minimize
551
     * @param alphabet
552
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
553
     * @param ip
554
     *         the initial partitioning function, determining how states will be distinguished
555
     * @param pruningMode
556
     *         the pruning mode
557
     * @param creator
558
     *         the creator for constructing the automata instance to return
559
     * @param <I>
560
     *         input symbol type
561
     * @param <SP>
562
     *         state property type
563
     * @param <TP>
564
     *         transition property type
565
     * @param <A>
566
     *         automaton type
567
     *
568
     * @return the minimized automaton, initially constructed from the given {@code creator}.
569
     */
570
    public static <I, SP, TP, A extends MutableDeterministic<?, I, ?, SP, TP>> A minimizeUniversal(
571
            UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
572
            Alphabet<I> alphabet,
573
            PruningMode pruningMode,
574
            AutomatonInitialPartitioning ip,
575
            AutomatonCreator<A, I> creator) {
576

577
        final FullIntAbstraction<?, SP, TP> abs = automaton.fullIntAbstraction(alphabet);
2✔
578
        final Hopcroft hopcroft =
2✔
579
                HopcroftInitializers.initializeComplete(abs, ip, pruningMode == PruningMode.PRUNE_BEFORE);
2✔
580

581
        hopcroft.computeCoarsestStablePartition();
2✔
582

583
        return HopcroftExtractors.toDeterministic(hopcroft,
2✔
584
                                                  creator,
585
                                                  alphabet,
586
                                                  abs,
587
                                                  abs::getStateProperty,
2✔
588
                                                  abs::getTransitionProperty,
2✔
589
                                                  pruningMode == PruningMode.PRUNE_AFTER);
590

591
    }
592

593
    /**
594
     * Minimizes the given, complete automaton using the full state signature. The result is written directly to the
595
     * input automaton.
596
     *
597
     * @param automaton
598
     *         the automaton to minimize
599
     * @param inputs
600
     *         the input symbols to consider for minimization
601
     * @param <I>
602
     *         input symbol type
603
     * @param <SP>
604
     *         state property type
605
     * @param <TP>
606
     *         transition property type
607
     * @param <A>
608
     *         automaton type
609
     *
610
     * @return {@code automaton} for convenience
611
     */
612
    public static <I, SP, TP, A extends MutableDeterministic<?, I, ?, SP, TP>> A minimizeUniversalInvasive(A automaton,
613
                                                                                                           Collection<? extends I> inputs) {
614
        return minimizeUniversalInvasive(automaton, inputs, AutomatonInitialPartitioning.BY_FULL_SIGNATURE);
2✔
615
    }
616

617
    /**
618
     * Minimizes the given, complete automaton depending on the given partitioning function. The result is written
619
     * directly to the input automaton.
620
     *
621
     * @param automaton
622
     *         the automaton to minimize
623
     * @param inputs
624
     *         the input symbols to consider for minimization
625
     * @param ip
626
     *         the initial partitioning function, determining how states will be distinguished
627
     * @param <I>
628
     *         input symbol type
629
     * @param <SP>
630
     *         state property type
631
     * @param <TP>
632
     *         transition property type
633
     * @param <A>
634
     *         automaton type
635
     *
636
     * @return {@code automaton} for convenience
637
     */
638
    public static <I, SP, TP, A extends MutableDeterministic<?, I, ?, SP, TP>> A minimizeUniversalInvasive(A automaton,
639
                                                                                                           Collection<? extends I> inputs,
640
                                                                                                           AutomatonInitialPartitioning ip) {
641
        return minimizeInvasive(automaton, inputs, ip, new GenericStorage<>(), new GenericStorage<>());
2✔
642
    }
643

644
    /**
645
     * Minimizes the given, potentially partial automaton using the full signature as initial partitioning. Pruning is
646
     * performed after computing state equivalences.
647
     *
648
     * @param automaton
649
     *         the automaton to minimize
650
     * @param alphabet
651
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
652
     * @param <I>
653
     *         input symbol type
654
     * @param <SP>
655
     *         state property type
656
     * @param <TP>
657
     *         transition property type
658
     *
659
     * @return the minimized automaton, initially constructed from the given {@code creator}.
660
     */
661
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizePartialUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
662
                                                                                      Alphabet<I> alphabet) {
NEW
663
        return minimizePartialUniversal(automaton, alphabet, PruningMode.PRUNE_AFTER);
×
664
    }
665

666
    /**
667
     * Minimizes the given, potentially partial automaton using the full signature as initial partitioning.
668
     *
669
     * @param automaton
670
     *         the automaton to minimize
671
     * @param alphabet
672
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
673
     * @param pruningMode
674
     *         the pruning mode
675
     * @param <I>
676
     *         input symbol type
677
     * @param <SP>
678
     *         state property type
679
     * @param <TP>
680
     *         transition property type
681
     *
682
     * @return the minimized automaton, initially constructed from the given {@code creator}.
683
     */
684
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizePartialUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
685
                                                                                      Alphabet<I> alphabet,
686
                                                                                      PruningMode pruningMode) {
687

688
        return minimizePartialUniversal(automaton,
2✔
689
                                        alphabet,
690
                                        pruningMode,
691
                                        AutomatonInitialPartitioning.BY_FULL_SIGNATURE,
692
                                        StateSignature.byFullSignature(null, new Object[alphabet.size()]));
2✔
693
    }
694

695
    /**
696
     * Minimizes the given, potentially partial automaton depending on the given partitioning function.
697
     *
698
     * @param automaton
699
     *         the automaton to minimize
700
     * @param alphabet
701
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
702
     * @param pruningMode
703
     *         the pruning mode
704
     * @param ip
705
     *         the initial partitioning function, determining how states will be distinguished
706
     * @param sinkClassification
707
     *         the signature identifying the artificial sink state
708
     * @param <I>
709
     *         input symbol type
710
     * @param <SP>
711
     *         state property type
712
     * @param <TP>
713
     *         transition property type
714
     *
715
     * @return the minimized automaton, initially constructed from the given {@code creator}.
716
     */
717
    public static <I, SP, TP> UniversalCompactDet<I, SP, TP> minimizePartialUniversal(UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
718
                                                                                      Alphabet<I> alphabet,
719
                                                                                      PruningMode pruningMode,
720
                                                                                      AutomatonInitialPartitioning ip,
721
                                                                                      Object sinkClassification) {
722

723
        return minimizePartialUniversal(automaton,
2✔
724
                                        alphabet,
725
                                        pruningMode,
726
                                        ip,
727
                                        sinkClassification,
728
                                        new UniversalCompactDet.Creator<>());
729
    }
730

731
    /**
732
     * Minimizes the given, potentially partial automaton depending on the given partitioning function. The result is
733
     * returned in the form of the automaton created by the given creator.
734
     *
735
     * @param automaton
736
     *         the automaton to minimize
737
     * @param alphabet
738
     *         the input alphabet (this will be the input alphabet of the resulting Mealy machine)
739
     * @param pruningMode
740
     *         the pruning mode
741
     * @param ip
742
     *         the initial partitioning function, determining how states will be distinguished
743
     * @param sinkClassification
744
     *         the signature identifying the artificial sink state
745
     * @param creator
746
     *         the creator for constructing the automata instance to return
747
     * @param <I>
748
     *         input symbol type
749
     * @param <SP>
750
     *         state property type
751
     * @param <TP>
752
     *         transition property type
753
     * @param <A>
754
     *         automaton type
755
     *
756
     * @return the minimized automaton, initially constructed from the given {@code creator}.
757
     */
758
    public static <I, SP, TP, A extends MutableDeterministic<?, I, ?, SP, TP>> A minimizePartialUniversal(
759
            UniversalDeterministicAutomaton<?, I, ?, SP, TP> automaton,
760
            Alphabet<I> alphabet,
761
            PruningMode pruningMode,
762
            AutomatonInitialPartitioning ip,
763
            Object sinkClassification,
764
            AutomatonCreator<A, I> creator) {
765

766
        final FullIntAbstraction<?, SP, TP> abs = automaton.fullIntAbstraction(alphabet);
2✔
767
        final Hopcroft hopcroft = HopcroftInitializers.initializePartial(abs,
2✔
768
                                                                         ip,
769
                                                                         sinkClassification,
770
                                                                         pruningMode == PruningMode.PRUNE_BEFORE);
771

772
        hopcroft.computeCoarsestStablePartition();
2✔
773

774
        return HopcroftExtractors.toDeterministic(hopcroft,
2✔
775
                                                  creator,
776
                                                  alphabet,
777
                                                  abs,
778
                                                  abs::getStateProperty,
2✔
779
                                                  abs::getTransitionProperty,
2✔
780
                                                  pruningMode == PruningMode.PRUNE_AFTER);
781

782
    }
783

784
    private static <I, SP, TP, A extends MutableDeterministic<?, I, ?, SP, TP>> A minimizeInvasive(A automaton,
785
                                                                                                   Collection<? extends I> alphabet,
786
                                                                                                   AutomatonInitialPartitioning ip,
787
                                                                                                   Storage<SP> spStorage,
788
                                                                                                   Storage<TP> tpStorage) {
789

790
        final MutableDeterministic.FullIntAbstraction<?, SP, TP> abs =
2✔
791
                automaton.fullIntAbstraction(Alphabets.fromCollection(alphabet));
2✔
792

793
        final int init = abs.getIntInitialState();
2✔
794
        if (init == IntAbstraction.INVALID_STATE) {
2✔
NEW
795
            automaton.clear();
×
NEW
796
            return automaton;
×
797
        }
798

799
        final Hopcroft hopcroft = HopcroftInitializers.initializeComplete(abs, ip, true);
2✔
800

801
        hopcroft.computeCoarsestStablePartition();
2✔
802

803
        final int n = hopcroft.getNumBlocks();
2✔
804
        final int k = alphabet.size();
2✔
805

806
        spStorage.init(n);
2✔
807
        tpStorage.init(n * k);
2✔
808
        final int[] succs = new int[n * k];
2✔
809

810
        for (Block b : hopcroft.blockList()) {
2✔
811
            final int rep = hopcroft.getRepresentative(b);
2✔
812
            for (int i = 0; i < k; i++) {
2✔
813
                final int pos = b.id * k + i;
2✔
814
                succs[pos] = hopcroft.getBlockForState(abs.getSuccessor(rep, i)).id;
2✔
815
                tpStorage.set(pos, abs.getTransitionProperty(rep, i));
2✔
816
            }
817
            spStorage.set(b.id, abs.getStateProperty(rep));
2✔
818
        }
2✔
819

820
        automaton.clear();
2✔
821

822
        for (int i = 0; i < n; i++) {
2✔
823
            abs.addIntState(spStorage.get(i));
2✔
824
        }
825

826
        abs.setInitialState(hopcroft.getBlockForState(init).id);
2✔
827

828
        for (int i = 0; i < n; i++) {
2✔
829
            for (int j = 0; j < k; j++) {
2✔
830
                final int pos = i * k + j;
2✔
831
                abs.setTransition(i, j, succs[pos], tpStorage.get(pos));
2✔
832
            }
833
        }
834

835
        return automaton;
2✔
836
    }
837
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc