Mata: A Fast and Simple Finite Automata Library

. Mata is a well-engineered automata library written in C++ that offers a unique combination of speed and simplicity. It is meant to serve in applications such as string constraint solving and reasoning about regular expressions, and as a reference implementation of automata algorithms. Besides basic algorithms for (non)deterministic automata, it implements a fast simulation reduction and antichain-based language inclusion checking. The simplicity allows a straightforward access to the low-level structures, making it relatively easy to extend and modify. Besides the C++ API, the library also implements a Python binding. The library comes with a large benchmark of automata problems collected from relevant applications such as string constraint solving, regular model checking, and reasoning about regular expressions. We show that Mata is on this benchmark significantly faster than all libraries from a wide range of automata libraries we collected. Its usefulness in string constraint solving is demonstrated by the string solver Z3-Noodler, which is based on Mata and outperforms the state of the art in string constraint solving on many standard benchmarks.


Introduction
We introduce a new finite automata library Mata1.It is intended to be used in applications where automata languages are manipulated by set operations and queries, presumably in a tight loop where automata are iteratively combined together using the classical as well as special-purpose constructions.Examples are applications like string constraint solving algorithms such as [11,24,22,1,10,3,71], processing of regular expressions [28,49], regular model checking (e.g., [16,15,58,26,13,81,6]), or decision procedures for logics such as WS1S or quantified Presburger arithmetic [20,80,43,12].The solved problems are computationally hard, often beyond the PSPACE-completeness of basic automata problems such as language inclusion.Efficiency is hence a primary concern.Achieving speed in applications requires, on one hand, fast implementation of basic automata algorithms (union, intersection, complement, minimization or size reduction, determinization, emptiness/inclusion/equivalence/membership test, parsing of regular expressions) and, on the other hand, access to low-level primitives to implement diverse application-specific algorithms and optimizations that often build on a tight integration with the application environment.Moreover, processing of regular expressions and, even more so, string constraint solving are areas of active research, with constantly evolving algorithms, heuristics, and optimizations.An automata library hence needs flexibility, extensibility, easy access to the low-level data structures, and Our contributions can be summarised by the following three points: 1. Mata, a fast, simple, and well-engineered automata library, well suited for application in string constraint solving and regex processing, in research and student projects, as well as in industrial applications.2.An extension of a benchmark of automata problems from string constraint solving, processing regular expressions, regular model checking, and solving arithmetic constraints.3. A comparison of a representative sample of well-known automata libraries against the above benchmark, demonstrating the superior performance of Mata.

Related Work
In this overview of automata algorithms and implementations, we focus on the technology relevant to Mata, i.e., automata used as a symbolic representation of sets of words and manipulated mainly by set operations.We omit automata technology made for other purposes, such as regular pattern matching, which concentrates on the membership test.
Automata techniques.The most textbook-like approach is to keep finite automata deterministic (the so-called DFA), which has the advantage of simple algorithms and data structures.Essentially all classical problems reduce to product construction, determinization by subset construction, final state reachability test, and minimization (by Hopcroft's [50], Moore's [62], Brzozowski's [19], or Huffman's [51] algorithms).The obvious drawback is the susceptibility to state explosion in determinization.
An alternative is to determinize automata only when necessary (e.g., only before complementing).Non-determinism may bring up to exponential savings in automata sizes and modern algorithms for nondeterministic finite automata (NFA) can in practice avoid the exponential worst-case cost of problems like the language inclusion test.
Namely, a major breakthrough in working with NFAs were the antichain-based algorithms for testing language universality and inclusion of NFA first introduced (to the best of our knowledge) in [74] and later rediscovered in [82].They dramatically improve practical efficiency of the subset construction by subsumption pruning (discarding larger sets).They were later extended with simulation [5,35] (and generalized to numerous other kinds of automata and problems).A principally similar is the bisimulation upto congruence technique of [14], which optimizes the NFA language equivalence test.Although experimental data in various works are somewhat contradictory, the more systematic studies so far found antichain-based algorithms more efficient [39,38].
NFAs require more involved reduction methods than DFAs, such as those based on simulation [65,21,44,52,48] or bisimulation [76,64,46].Simulation reduces significantly more but is much more costly.The algorithms for computing simulation of the second generation [65,21], which use the so-called partition-relation pairs to represent preorders on states, are practically much faster than the first generation algorithms [44,52].
Representations of the transition relation.In order to handle automata over large or infinite alphabets, such as Unicode or bit vectors, some implementations of automata represent transitions symbolically.Transitions may be annotated by sets of symbols represented as BDDs, logical formulae, intervals of numbers, etc.The most systematic approach to this has been taken in works on symbolic automata [78,32,33], where the symbol predicates may be taken from any effective Boolean algebra (essentially a countable set closed under Boolean operations).Some libraries, such as Spot [36], Owl [57], or Mosel [55] use BDDs to compactly represent sets of symbols on transitions.Even more compact are the symbolic representations of the transition relation used in Mona [43] and in the symbolic version of the tree automata library Vata [59], where all transitions starting at a state are represented as a single multi-terminal BDDs with the target states in the leaves (the paths represent symbols).Although symbolic representation may offer new optimization opportunities [32] and give more generality, it also brings complexity and overhead.Adapting the known algorithms may be nontrivial [32,46] to the point of being a difficult unsolved problem (such as the fast computation of simulation relation of [65,21]).In our application area, working with large alphabets can mostly be avoided in preprocessing, for instance by means of a priori mintermization (partitioning the alphabet into groups of symbols indistinguishable from the viewpoint of the input problem).The simplicity and transparency of explicit representation of transitions then seems preferable.
Alternating automata.Alternating automata (AFA) received attention recently in the context of string solving and regex processing [79,28,45,40].They allow to keep automata operations implicit up to the point of the PSPACE-complete emptiness test, which can be solved by clever heuristics (e.g.[79,28,45,82,38,30]). Available implementations were recently compared with selected NFA libraries [38] and neither approach dominated.AFA are, however, often not a viable alternative since adapting complex algorithms from, e.g., string solving to AFA typically requires to redesign the entire algorithm from scratch (as, e.g., in [45,79]).
String solving and SMT solvers.String constraint solving is currently the primary application target of Mata.Mata is already a basis of an efficient string solver Z3-Noodler [25] and a number of other string solvers could perhaps benefit from its performance, especially those that already use automata as a primary data structure, e.g.[23,3,10,1].Besides, SMT string constraint solvers can also be used to reason about regular properties, though the results of [38] suggest that their efficiency is not on par with dedicated fast automata libraries.
Automata libraries.We give overview of known automata libraries with a focus on those that we later include in our experimental comparison in Section 6.
The Brics [63] automata library is often considered a baseline in comparisons.It implements both NFA and DFA, where each state keeps the set (implemented as a hash map) of transitions, which are represented symbolically using character ranges.It is written in Java and relatively optimized.
The Automata.netlibrary [77], written in C#, implements symbolic NFA parameterized by an effective Boolean algebra.The transition relation (as well as its inverse) are implemented as a hash map from states to the dynamic array of transitions from a given state, each transition annotated with a predicate over the algebra.We use it in our comparison with the algebra of BDDs.Automata.nethas been developed for a long time and has accumulated a number of novel techniques (e.g., an optimized minimization [31]).
Mona [43], written in C, is a famous optimized implementation of deterministic automata used for deciding WS1S/WSS formulae.To handle DFA with complex transition relations over large alphabets of bit vectors, Mona uses a compact fully symbolic representation of the transition relation: a single MTBDD for all transitions originating in a state, with the target states in its leaves.Mona can represent only a DFA, hence every operation implicitly determinizes its output.
Vata [59], written in C++, implements non-deterministic tree automata.It can be used with NFA, too as they are a special case of tree automata.It is relatively optimized and features fast implementation of the antichain-based inclusion checking [15,47] (which for NFA boils down to the inclusion check of [35]) and the second generation simulation computation algorithm of [48].
Awali [60] is a library that targets weighted automata and transducers over an arbitrary semiring.To implement the transition relation, it keeps a vector of transitions and for each state  two vectors: one keeps the indices of transitions leaving  and the other one the indices of transitions entering .
AutomataLib [53] is a Java automata library and the basis of the automata learning framework LearnLib [54].It focuses on DFAs and implements their transition relation as a flattened 2D matrix that maps the source state and symbol to the target state.
Automata.py[37] is written in Python.It defines the transition relation in a liberal way, as any mapping from source states to a mapping of symbols to a target state (DFA) or to a set of target states (NFA).
FAdo [7] is a Python library written with efficiency in mind.It uses a similar structure as Automata.py,but more specific, with the transition as a Python dictionary (a hash map), and states represented as numbers used as indices into an array.
There is a number of other automata libraries that we do not include into our comparison since they seem similar to the included ones or we were not able to use them.The C alternative of Brics [61] and the Java implementation of symbolic NFA of [29] are in our experiment covered by Automata.netand Brics.Alaska [34] contains interesting implementations of antichain-based algorithms, but is no longer maintained nor available.Lash [12] is a long-developed tool for arithmetic reasoning based on automata, with an efficient core automata library, written in C. Its transition relation is an array indexed by states, where every state is associated with a symboltarget ordered list of transitions.Lash uses partial symbolic representation -it encodes symbols as sequence of binary digits.The comparison with Mona in [56] on automata benchmark originating from arithmetic problems placed its performance significantly behind Mona.It seems to no longer be maintained, and we were not able to run it on our benchmarks.
There is also a number of implementations of automata over infinite words, for instance Spot [36], Owl [57], or Goal [75], which are in their nature close to the finite word automata libraries (Spot and Owl are optimized and use BDDs on transition edges similarly as Automata.net),but implement different algorithms.
Mata evolved from a prototype implementation eNfa used in the comparison of AFA emptiness checkers as a baseline implementation of classical automata [38].Surprised by its performance, we decided to turn it into a serious widely usable library.Current Mata is much more mature and efficient than the eNfa of [38].

Preliminaries on Finite Automata
Words and alphabets.An alphabet is a set Σ of symbols/letters (usually denoted , , , . ..) and the set of all words over Σ is denoted as Σ * .The concatenation of words  and  is denoted by  • .The empty word, the neutral element of concatenation, is denoted by  ( ∉ Σ).

Finite automata. A (nondeterministic) finite automaton (NFA) over an alphabet Σ is a tuple
The run is accepting if  0 ∈  and   ∈ , and the language  (A) of A is the set of all words for which A has an accepting run.
A state is useful if it belongs to some accepting run, else it is useless.An automaton with no useless states is trimmed.A state is reachable if it appears on a run starting at an initial state.In Mata, we further use post () = {(, post (, )) | post (, ) ≠ ∅} to denote the state-post of .We call symbol-post and state-post the post-image functions.We also use − → where  ∈ post (, ) to denote transitions.The set of all transitions of A is called the transition relation of A and we denote it by Δ.
Automata operations.In this paragraph we assume automata without  transitions.The subset construction generates from A the DFA ( ⊆ , post ⊆ ,  ⊆ ,  ⊆ ) where  ⊆ = P (), and where post ⊆ (, ) = ∈ post (, ).The automaton for complement is obtained from it by complementing  ⊆ , i.e., the set of final states is given as  ⊆ \ ⊆ .The intersection of two automata where post × ((, ), ) = post 1 (, ) × post 2 (, ).A sensible implementation of course only computes the reachable parts of the product and the subset construction.The union  (A 1 ) ∪  (A 2 ) is obtained by disjointly uniting all components of A 1 and A 2 .Similarly, the concatenation (A 1 ). (A 2 ) is the automaton (this construction avoids introducing -transitions).Note that we omit superscript of symbol-post function when it is clear from the context.

The Architecture of Mata
We explain in this section the implementation techniques that make Mata efficient on a wide range of automata operations.

Automata Representation
States and transition symbols are unsigned integers (starting from 0).This makes it easy to store information about them in a state-/symbol-indexed vectors.A frequently used low-level data structure is OrdVector, a set of ordered elements implemented as an ordered array (with std::vector as the underlying data structure).It has constant time addition and removal of the largest element (push back and pop back), linear union, intersection, and difference (by variants of merging), good memory locality and fast iteration through elements, logarithmic lookup (by binary search), but a slow insertion and removal (insert and erase) at other than the last position, as the elements on the right of the modified position must be shifted.Many Mata algorithms utilize the constant time handling of the largest element in, e.g., synchronized traversal of multiple OrdVector containers.Initial and final states are kept in sparse sets [18], with fast iteration through elements and constant lookup, insertion, and removal.The weak point of Delta is inherited from OrdVector: slow insert or erase of a specific transition (these operations are, however, used scarcely in the considered scenarios).Its strength is mainly fast iteration through the post-image of a state, of a pair of states in the product construction, and of a set of states in the subset construction.

Automata Operations
Generating post-images in subset construction.In the subset construction, each iteration through post () for a set of states  is keeping an array of iterators, one into each post () for all  ∈ .Every iteration shifts the iterators to the right, to post (, ) where  is the closest from above to the current global minimal symbol , and returns post (, ) as the union of all post (, )'s pointed to by the iterators.No searching in vectors is needed.The entire iteration through all post ()'s makes the iterators in the SymbolPosts traverse their respective vectors only once.
Constructing the transitions leading from  while iterating through post () is done by appending to OrdVectors, without a need to insert at internal positions of vectors.The iteration through the SymbolPosts is ordered by symbol, hence each newly created transition from the macrostate  has a larger symbol than all the previously created ones.The symbol-post therefore belongs at the end of the OrdVector of symbol-posts of post (), where it is push backed.Since the resulting automaton is deterministic, the vectors of targets are singletons, and their creation does not require insert either.
Generating post-images in product construction.Similarly as in the subset construction above, iterating through post ((, )) in the product construction is done by synchronous iteration through post () and post () from the smallest common symbol to the largest.In each step, the iteration returns the Cartesian product of the targets in the symbolposts.Unlike the subset construction, adding the corresponding transitions from (, ) to the product automaton sometimes does need an insert into the vector of targets.It is however not that frequent: Newly discovered product states are assigned the so far highest numbers, so these are added to the target vectors by push back.The insert may hence be needed only when creating a non-deterministic transition to a state discovered earlier.
Storing sets and pairs of states in the subset and product construction.OrdVector is also used to map generated sets in the subset to the identities of generated states.The map uses a hash table (std::unordered map) where values are OrdVectors.The product construction uses either a two-dimensional array to map pairs of states to product states (for smaller automata) or a vector pro map of hash tables, where the identity of the product state (, ) is found in the hash map prod map[q] under the key .
Emptiness test and trimming.Emptiness test and trimming are used frequently and must be fast.Mata's emptiness test is just a state space exploration that utilizes the fast iteration through post-images of a state.
Trimming consists of two steps: (1) identification of useful states and (2) removal of states that are not useful.Identification of useful states must, besides forward exploration to identify reachable states, identify states that reach a final state.A naive solution would be a backward exploration from final states.Delta is, however, not well suited for backward search and although reverting it is doable, its cost is not negligible either.We therefore use a smarter solution, which uses a simplification of the non-recursive Tarjan's algorithm [73] to discover strongly connected components (SCCs).Tarjan's algorithm is essentially a depth-first exploration augmented to identify the SCCs.To identify useful states, on finding an SCC with a final state, we mark the entire SCC as useful together with all states on the path to that SCC, which is readily stored on the depth-first search stack.The cost of computing useful states is then similar to the cost of a single depth-first exploration, which is indeed negligible.
Removal of useless states then needs to be done in a Delta-friendly way.The naive approach that removes useless states and transitions incident with them one by one would be extremely slow due to the need of searching and calling erase in the OrdVectors of Delta.Instead, we perform the whole removal and related operations in a single pass through Delta.Before the pass begins, first, we create a map renaming mapping each useful state to its new name (the trimming also renames the states in order to have the remaining states form a consecutive sequence).During the pass, the following operations need to be performed: (i) in the outermost loop, each useful state  in Delta is moved to index renaming[], (ii) in every vector of target states, each useful target is moved to the left in the target vector by that many positions, as there were smaller useless states before it, and (iii) while doing that, the target state  is renamed to renaming[].
Union and concatenation.Mata is relatively slow in operations that copy or create large parts of automata, such as non-deterministic union or concatenation, or simple copying of an automaton.This is perhaps due to the imperfect memory locality (the three layers of vectors in Delta) and the need to copy every single transition (unlike, e.g., symbolic automata with BDDs on transitions, where the BDDs may be shared).Mata has, however, in-place variants of union and concatenation, which do not copy Delta, but only append the post vectors and rename the target states in the appended part, which is fast.The price for the speed is the loss of the original automata, but they are in many use cases not needed (as, e.g., in inductive constructions of automata from regular expressions or formulae).[35].Given the inclusion problem (A) ⊆  (B), the algorithm explores the space of the product of A and the subset construction on B, consisting of pairs (, ) with  being a state of A and  being a set of states of B. In particular, it searches, on the fly, for a reachable pair (, ) with a final  and a non-final , which would be a witness non-inclusion.The algorithm optimizes the search by subsumption pruning-discarding states (, ) if another (,  ′ ) with  ⊆  ′ has been found.Our implementation uses the infrastructure for computing post-images of product and subset construction discussed above.The reached pairs (, ) are stored in a state--indexed vector incl map of collections of sets .The sets are again represented as OrdVectors.On reaching a pair (, ), all sets  ′ stored in incl map[] are tested for inclusion with .If  ⊇  ′ , then  is dropped, and if  ⊆  ′ , then  ′ is removed from incl map[] (as well as other sets  ′′ such that  ⊆  ′′ ) and  is added to incl map [𝑞].A large speed-up is sometimes obtained by prioritizing exploration of pairs (, ) with  being of a small size.A smaller set means a better chance to subsume other pairs, to reach a witness of non-inclusion, and to generate other pairs with small sets.The algorithm then explores a much smaller state space.

Antichain-based inclusion checking. Mata implements the antichain-based inclusion checking of
Simulation.Mata uses an implementation of a fast algorithms for computing simulation, namely, the algorithm from [65], which was adapted from Kripke structures to automata in [4], and later further optimized in [48].The implementation originates in Vata [59].
Low-level API.The API of Mata contains an interface for accessing the most low-level features needed to implement algorithms in the style described above.For instance, the API provides iterators over transitions of Δ in the form of triples − →, iterators through moves (pairs (, ) such that − → ∈ Δ) of a state , or generic synchronized iterators, which allow a simultaneous iteration in a set of vectors used in union and in computing the post-image in the product and subset construction.Since the main data structures are not complicated and have simple invariants, programming with them on the low level is possible even for an outsider.This low-level Mata API is, for instance, used in the string solver Z3-Noodler.[25] presents a detailed comparison of Z3-Noodler with the state of the art in string solving.Its exceptional performance on regex and word equation-heavy constraints is to a large degree due to Mata.

Infrastructure of Mata
Mata comes with the following tools and features to make using, developing, and extending it convenient.
Python interface.Mata provides an easy-to-use Python interface, making it a fullfledged automata library for Python projects.It is available on the official Python package repository4 and can be installed easily using the pip package manager:

$ pip install libmata
An example of using the Mata Python binding is shown in Fig. 2. The interface is implemented using the optimizing static compiler Cython wrapping the C++ Mata calls and covers all important parts of the C++ functionality.This low-level interaction with the optimized C++ code keeps the Python code fast.To show the capabilities of the interface and to provide material for easy onboarding, Mata also contains several Jupyter notebooks with examples of how to use it.(lambda aut, q: q in aut.final_states, {'color':'red','fillcolor':'red'}), (lambda aut, q: q in aut.initial_states, {'color': 'orange', 'fillcolor': 'orange'}), ] plotting.plot(con_aut,with_scc=True, node_highlight=n_h, edge_highlight=e_h) (a) An example of using Mata from Python..mataformat and parsing.Mata brings its own automata format.The main features of the format are extensibility to cover various types of automata, human-readability, yet still high level of compactness.Each .matafile consists of automata definitions.
The first line of the definition describes the type of the automaton, together with the alphabet.The format supports both explicit and symbolic (bit vector) alphabets.For a symbolic alphabet, symbols are encoded as formulae over atomic propositions, where the parser of .mataimplements mintermization (partitioning the alphabet into groups of symbols indistinguishable from the viewpoint of the input problem), which transforms it into an explicit alphabet with the symbols representing the minterms.The following lines contain a sequence of key-values statements that set particular traits of the automaton, such as initial or final states.The rest of the definition is a list of transitions.
Examples of automata in .mataformat are shown in Fig. 3.
Other than the introduced format, Mata can also parse automata from regular expressions using the parser from the regex matcher RE2 [41].This means that Mata can handle even complex syntax used in real-world regular expressions.
Continuous integration.We implement continuous integration via GitHub Actions.In particular, actions automatically build the library including the Python binding on MacOS and Ubuntu, check for warnings, code quality and run unit tests together with the code coverage.The actions are triggered after each commit, and the checks are mandatory for merging branches to the main branch, and can also be run locally.
We mainly aim to demonstrate the efficiency of the basic data structures and implementation techniques of Mata.This is best seen on standard constructions, where all libraries implement the same high-level algorithm, such as product, subset construction, or reachability test within complementation, intersection, emptiness test, etc.We then also showcase the efficiency of more advanced algorithms implemented only in Mata and Vata, the antichain-based inclusion test and simulation reduction.
Table 1: Statistics for the benchmarks.We list the number of timeouts (TO), average time on solved instances (Avg), median time over all instances (Med), and standard deviation over solved instances (Std), with the best values in bold.The times are in milliseconds unless seconds are explicitly stated.We use ∼0 to denote a value close to zero.Benchmarks.We use the following benchmark sets.
b-smt [38] contains 384 instances of boolean combinations of regular properties, obtained from SMT formulae over the theory of strings.These include difficult handwritten problems containing membership in regular expressions extended with intersection and complement from [71] and emptiness problems from Norn [2,3] and SyGuS-qgen benchmarks, collected in SMT-LIB [9,67,68].email-filter [38] contains 500 inclusion checks of the form  5 ⊆  1 ∧ 2 ∧ 3 ∧ 4 obtained analogously as in [30].Each   is one of the 75 regexes6 from RegExLib [66], selected so that  1 ∧  2 ∧  3 ∧  4 ∧  5 is not empty.Similar kind of these problems is solved in spam-filtering: one tests whether a new filter  5 adds anything new to existing filters.param-inter [38] contains 4 sets of parametric intersection problems from [40] and 2 sets from [28].In total, this includes 267 problems.The parameter controls the size of the regex or the number of regexes to be combined.param-union is the variant of the benchmark that performs union instead of intersection.armc-incl [38] contains 136 language inclusion problems derived from runs of an abstract regular model checker of [15] (verification of the bakery algorithm, bubble sort, and a producer-consumer system).lia consists of 169 complementation problems created during the run of Amaya [8], a tool for deciding linear integer arithmetic (LIA) formulae using an automata-based decision procedure of [17].The formulae are taken from UltimateAutomizer [42] and tptp [72] benchmarks, collected in SMT-LIB [9,69].The transition relation in Amaya is represented symbolically using BDDs; in our experiments we tested both symbolic representation (in lia-symbolic) and explicit representation (in liaexplicit), where explicit symbols are bit vectors represented by the BDDs.noodler consists of instances created during the run of the string solver Z3-Noodler [11,24,25] on the regex-heavy benchmark AutomatArk [10] from SMT-LIB [9,67].We collected 751 complementation, 438 concatenation, and 4,872 intersection problems in noodler-compl, noodler-conc, and noodler-inter respectively.
Experimental setup.We converted all benchmarks into a common textual automata format (the .mataformat, see Section 5), and wrote dedicated parsers or conversions for all the libraries.The conversion and parsing are not included in the run times since the parsers are not optimized and the typical use cases do not require parsing every input automaton from a textual format.From some of the benchmarks, we excluded small units of examples where the conversion failed.We measure only the time needed for carrying out the specified operations on automata already parsed into each library's internal data structures.Automata in all benchmarks but lia and those coming from regexes, emailfilter, b-smt, param-inter, and param-union, had small or moderate alphabet sizes (all below 100 symbols, except noodler-inter with up to 252 symbols).The explicit automata from LIA solving (lia-explicit) have at most 1,024 symbols (corresponding to 10 bits).7After performing mintermization on automata with symbolic representation (lia-symbolic), the number of symbols was reduced to at most 30, and mintermization runs on automata from regular expressions returned alphabets with at most 80 symbols.Results.We summarize the results of each benchmark in cactus plots in Fig. 4 (displaying cumulative run times of benchmarks, with the instances ordered by their run time) and Table 1.Table 2 shows relative speedups of Mata over each library on problem instances that both libraries finished in time.We also present statistics for individual automata operations across the entire benchmark in Fig. 5 and Table 3.We do not show the performance of Mata's Python interface in the plots and tables as it is matches that one of Mata.All examples were run in six parallel jobs on Fedora GNU/Linux 38 with an Intel Core 3.4 GHz processor and 20 GiB RAM with 60 s timeout.
Mata consistently outperforms all other libraries on all benchmarks and in all operations, up to few exceptions.It is sometimes matched or outperformed by Automata.netand Brics in union and concatenation operation (on param-union and noodler-conc).Brics and Automata.netare sometimes faster since they may be able to share parts of the representation (such as BDDs on the transitions) between the automata operands and the union/concatenation, while Mata copies the entire data structure (and the memory locality of Delta, with its three layers of vectors, is not perfect).Brics appears particularly fast in emptiness checking since it implicitly trims the automata, after which the emptiness test becomes a trivial query on emptiness of the set of states.The cost of the emptiness check is thus hidden in the cost of other operations (we do not state statistics from trimming for Brics for this reason).Brics and Automata.netalso have a smaller average time in constructing the complements in lia-symbolic, due to a few high run times of Mata on examples that have many transitions per a pair of states.Solving these examples, and generally examples generated from solving LIA, is indeed Table 3: Statistics for the operations on solved instances.We list the average time (Avg), median time (Med), and standard deviation (Std), with the best values in bold.The times are in milliseconds.Note that only the operations that the given library finished within the timeout are counted, hence the numbers are significantly biased in favour of libraries that timeouted more (the harder benchmarks are no counted in), and should be red in the context of Table 1 and the cactus plots.We use ∼0 to denote a value close to zero.Mata's simulation reduction (Mata-Sim in the results) does not help much when the time for computing the simulation is counted in, as seen in Fig. 4. Simulation reduction is indeed costly, and our eager strategy of reducing all automata is probably sub-optimal.The run times of complement, however, show a considerable speedup after automata are reduced, and Mata-Sim solves some complement and also parametric intersection examples that no other library can.
Overall, Mata appears significantly faster than all the libraries we have tried, with the closest competitor being often more than an order of magnitude slower.
Threats to validity.Our results must be taken with a grain of salt as the experiment contains an inherent room for error.Mainly, not knowing every library intimately, we might have missed the most optimal solutions, and our parsers of the .mataformat might be building the internal data structures of the libraries in a sub-optimal way.The experiment was also running in parallel on a server with limited resources, which might lead to fluctuations in run times We are, however, confident that our main conclusions are well justified.

Conclusions and Future Work
We have introduced a new automata library Mata, explained its principles, and evaluated its performance.Mata is not the most general or feature-full library.Libraries such as Awali or Automata.netare much more complex and comprehensive, are more widely applicable, either to various symbolic representations of automata or to automata with registers, while still being impressively efficient.Mata, however, does what it is meant to do better than all the other libraries: solve examples from string solving, regular expression processing, and regular model checking much faster, while staying simple and transparent, easily extensible and applicable to projects.
We continue working on Mata's set of features as well as its efficiency.We plan to extend Mata with transducers, add support for registers that could handle, e.g., counting in regular expressions, and experiment with the poor man's symbolic representation of bit vector alphabets represented as sequences of bits (used in Lash [12]), so that Mata can be used adequately in applications such as solving WS1S and arithmetic formulae.We believe that the efficiency of the basic data structures discussed here can be much improved by focusing on the low-level performance.Custom data structures, specialised memory management, improvement in memory locality, and, generally, the class of optimizations used in BDD packages, could shift Mata's performance much further.
Data structure for the transition relation.The main determinant of Mata is its threelayered data structure Delta for the transition relation.It is implemented as a vector post where, for every state , post[] is of the type StatePost, representing post () as an OrdVector of objects of the type SymbolPost, each in turn representing one post (, ) by storing the symbol  and an OrdVector of the target states.The SymbolPosts in OrdVector are ordered by their symbols3.A visualization of Delta is shown in Fig. 1.

Fig. 2 :Fig. 3 :
Fig.2: An example of a Python interface for Mata.The code (a) loads automata from regular expressions (a, b are transition symbols; * , and + represent iterations: 0 or more, and 1 or more, respectively), concatenates them, and displays the trimmed concatenation using the conditional formatting with the output in (b).

Fig. 4 :
Fig. 4: Cactus plot showing cumulative run time per benchmark.The time axis is logarithmic.

Fig. 5 :
Fig. 5: Cactus plot showing cumulative run time per operation.The time axis is logarithmic.

Table 2 :
Relative speedup of Mata on instances where both libraries finished.
case for symbolic representation of transitions, and it is currently not a primary target of Mata.However, Mata is still much faster than any other library on mintermised versions of the same examples.AutomataLib is faster in some parametric intersection examples because of its implicit determinization, which in some particular examples returns much smaller automata.When the other libraries are made to determinize, they behave analogously, and Mata again solves most examples and takes the least time.Still, on all operations except emptiness, Mata is the fastest overall, and on emptiness it is by far the fastest from libraries that actually do solve the emptiness problem.Mata has especially efficient inclusion test, and trimming, an operation which is usually needed very frequently, is also a strong point of Mata's performance. a