File Coverage

blib/lib/Set/FA.pm
Criterion Covered Total %
statement 40 43 93.0
branch 8 8 100.0
condition n/a
subroutine 10 11 90.9
pod 8 8 100.0
total 66 70 94.2


line stmt bran cond sub pod time code
1             package Set::FA;
2              
3 2     2   57652 use parent 'Set::Object';
  2         838  
  2         12  
4 2     2   49578 use strict;
  2         7  
  2         79  
5 2     2   11 use warnings;
  2         4  
  2         3978  
6              
7             our $VERSION = '1.08';
8              
9             # -----------------------------------------------
10              
11             sub accept
12             {
13 2     2 1 765 my($self, $input) = @_;
14 2         9 my($set) = (ref $self) -> new;
15              
16 2         14 for my $automaton ($self -> members)
17             {
18 30 100       68 $set -> insert($automaton) if ($automaton -> accept($input) );
19             }
20              
21 2         10 return $set;
22              
23             } # End of accept.
24              
25             # -----------------------------------------------
26              
27             sub advance
28             {
29 0     0 1 0 my($self, $input) = @_;
30              
31 0         0 for my $automaton ($self -> members)
32             {
33 0         0 $automaton -> advance($input);
34             }
35              
36             } # End of advance.
37              
38             # -----------------------------------------------
39              
40             sub clone
41             {
42 1     1 1 3 my($self) = @_;
43 1         5 my($set) = (ref $self) -> new;
44              
45 1         6 for my $automaton ($self -> members)
46             {
47 15         37 $set -> insert($automaton -> clone);
48             }
49              
50 1         8 return $set;
51              
52             } # End of clone
53              
54             # -----------------------------------------------
55              
56             sub final
57             {
58 5     5 1 26 my($self) = @_;
59 5         26 my($set) = (ref $self) -> new;
60              
61 5         49 for my $automaton ($self -> members)
62             {
63 75 100       194 $set -> insert($automaton) if ($automaton -> final);
64             }
65              
66 5         26 return $set;
67              
68             } # End of final.
69              
70             # -----------------------------------------------
71              
72             sub id
73             {
74 1     1 1 3128 my($self, $id) = @_;
75 1         7 my($set) = (ref $self) -> new;
76              
77 1         16 for my $automaton ($self -> members)
78             {
79 15 100       56 $set -> insert($automaton) if ($automaton -> id eq $id);
80             }
81              
82 1         7 return $set;
83              
84             } # End of id.
85              
86             # -----------------------------------------------
87              
88             sub in_state
89             {
90 8     8 1 2747 my($self, $state) = @_;
91 8         60 my($set) = (ref $self) -> new;
92              
93 8         60 for my $automaton ($self -> members)
94             {
95 120 100       305 $set -> insert($automaton) if ($automaton -> state eq $state);
96             }
97              
98 8         114 return $set;
99              
100             } # End of in_state.
101              
102             # -----------------------------------------------
103              
104             sub reset
105             {
106 2     2 1 1840 my($self) = @_;
107              
108 2         26 for my $automaton ($self -> members)
109             {
110 27         64 $automaton -> reset;
111             }
112              
113             } # End of reset.
114              
115             # -----------------------------------------------
116              
117             sub step
118             {
119 1     1 1 4 my($self, $input) = @_;
120              
121 1         7 for my $automaton ($self -> members)
122             {
123 15         35 $automaton -> step($input);
124             }
125              
126             } # End of step.
127              
128             # -----------------------------------------------
129              
130             1;
131              
132             =pod
133              
134             =head1 NAME
135              
136             L<Set::FA> - A Set of Discrete Finite Automata
137              
138             =head1 Synopsis
139              
140             #!/usr/bin/perl
141            
142             use strict;
143             use warnings;
144            
145             use Set::FA;
146             use Set::FA::Element;
147            
148             # --------------------------
149            
150             my(@a) = map
151             {
152             Set::FA::Element -> new
153             (
154             accepting => ['ping'],
155             id => "a.$_",
156             start => 'ping',
157             transitions =>
158             [
159             ['ping', 'a', 'pong'],
160             ['ping', '.', 'ping'],
161             ['pong', 'b', 'ping'],
162             ['pong', '.', 'pong'],
163             ],
164             )
165             } (0 .. 2);
166            
167             my(@b) = map
168             {
169             Set::FA::Element -> new
170             (
171             accepting => ['pong'],
172             id => "b.$_",
173             start => 'ping',
174             transitions =>
175             [
176             ['ping', 'a', 'pong'],
177             ['ping', '.', 'ping'],
178             ['pong', 'b', 'ping'],
179             ['pong', '.', 'pong'],
180             ],
181             )
182             } (0 .. 4);
183              
184             my($set) = Set::FA -> new(@a, @b);
185             my($sub_a) = $set -> accept('aaabbaaabdogbbbbbababa');
186             my($sub_b) = $set -> final;
187              
188             print 'Size of $sub_a: ', $sub_a -> size, ' (expect 3). ',
189             'Size of @a: ', scalar @a, ' (expect 3). ',
190             'Size of $sub_b: ', $sub_b -> size, ' (expect 5). ',
191             'Size of @b: ', scalar @b, ' (expect 5). ', "\n",
192              
193             =head1 Description
194              
195             L<Set::FA> provides a mechanism to define and run a set of DFAs.
196              
197             =head1 Installation
198              
199             Install L<Set::FA> as you would for any C<Perl> module:
200              
201             Run:
202              
203             cpanm Set::FA
204              
205             or run:
206              
207             sudo cpan Set::FA
208              
209             or unpack the distro, and then either:
210              
211             perl Build.PL
212             ./Build
213             ./Build test
214             sudo ./Build install
215              
216             or:
217              
218             perl Makefile.PL
219             make (or dmake or nmake)
220             make test
221             make install
222              
223             =head1 Constructor and Initialization
224              
225             =head2 Parentage
226              
227             This class extends L<Set::Object>, meaning L<Set::FA> is a subclass of L<Set::Object>.
228              
229             For the (long) list of methods available and provided by L<Set::Object>, see that object's
230             documentation.
231              
232             =head2 Using new()
233              
234             C<new()> is called as C<< my($set) = Set::FA -> new(@list_of_dfas) >>.
235              
236             It returns a new object of type C<Set::FA>.
237              
238             You may supply a list of L<Set::FA::Element> objects to new.
239              
240             If the list is empty, you will need to call $set -> insert(@list_of_dfas) to do anything meaningful
241             with $set.
242              
243             The new object is a set whose members are all L<Set::FA::Element> objects.
244              
245             This class allows you to operate on all members of the set simultaneously, as in the
246             synopsis.
247              
248             =head1 Methods
249              
250             =head2 accept($input)
251              
252             Calls L<Set::FA::Element/accept($input)> on all members of the set. This in turn calls
253             L<Set::FA::Element/advance($input)> on each member.
254              
255             Note: This does I<not> mean it calls advance() on the set object.
256              
257             Returns a L<Set::FA> object containing just the members of the original set which have ended up
258             in their respective accepting states.
259              
260             =head2 advance($input)
261              
262             Calls L<Set::FA::Element/advance($input)> on all members of the set.
263              
264             Returns nothing.
265              
266             =head2 clone()
267              
268             Returns a clone of the set. All references (except for code references) in the
269             new set point to newly created objects.
270              
271             =head2 final()
272              
273             Calls L<Set::FA::Element/final()> on all members of the set.
274              
275             Returns a L<Set::FA> object containing just the members of the original set which are
276             in their respective accepting states.
277              
278             =head2 id($id)
279              
280             Returns a L<Set::FA> object containing just the members of the original set whose ids
281             match the $id parameter.
282              
283             =head2 in_state($state)
284              
285             Returns a L<Set::FA> object containing just the members of the original set who current
286             state matches the $state parameter.
287              
288             =head2 reset()
289              
290             Calls L<Set::FA::Element/reset()> on all members of the set.
291              
292             Returns nothing.
293              
294             =head2 step($input)
295              
296             Calls L<Set::FA::Element/step($input)> on all members of the set.
297              
298             Returns nothing.
299              
300             =head1 Machine-Readable Change Log
301              
302             The file CHANGES was converted into Changelog.ini by L<Module::Metadata::Changes>.
303              
304             =head1 Version Numbers
305              
306             Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
307              
308             =head1 Credit
309              
310             The code was rewritten to perform exactly as did earlier versions (pre-1.00) of L<Set::FA> and
311             L<Set::FA::Element>, and hence is essentially the same, line for line.
312              
313             I've reformatted it, and changed the OO nature and the logging, obviously, but Mark Rogaski, the author of
314             L<Set::FA> gets the credit for the code.
315              
316             I've rewritten the documentation from scratch.
317              
318             =head1 See Also
319              
320             Before adopting L<Set::FA> (for L<Graph::Easy::Marpa>'s lexer), other DFA modules I looked at were:
321              
322             =over 4
323              
324             =item o L<DFA::Kleene>
325              
326             The author definitely knows what he's doing, but this module addresses a different issue than I
327             face. It outputs regexps corresponding to the transitions you specify.
328              
329             =item o L<DFA::Statemap>
330              
331             This is a wrapper around the State Machine Compiler, to output a SM in Perl. SMC requires Java,
332             and can output in a range of languages. See L<http://smc.sourceforge.net/>.
333              
334             SMC looks sophisticated, but it's a rather indirect way of doing things when Perl modules such
335             as L<Set::FA::Element> are already available.
336              
337             =item o L<DMA::FSM>
338              
339             Uses a very old-fashioned style of writing Perl.
340              
341             =item o FLAT::DSA. See L<FLAT>
342              
343             A toolkit for manipulating DFAs.
344              
345             =item o L<IDS::Algorithm::DFA>
346              
347             Uses an old-fashioned style of writing Perl.
348              
349             =item o L<MooseX::FSM>
350              
351             Looks like an unfinished thought-bubble.
352              
353             =item o L<Parse::FSM>
354              
355             Outputs a Perl module implementing the FSM you define.
356              
357             =item o L<The Ragel State Machine Compiler|http://www.complang.org/ragel/>
358              
359             A non-Perl solution.
360              
361             That page has lots of interesting links.
362              
363             =item o L<Shishi>
364              
365             Doesn't use a transition table, but does allow you to modify the SM while it's running.
366             You build up a transition network diagram, labouriously, with 1 line of code at a time.
367              
368             =back
369              
370             See also L<this Wikipedia article|http://en.wikipedia.org/wiki/Deterministic_finite-state_machine>.
371              
372             =head1 Support
373              
374             Email the author, or log a bug on RT:
375              
376             L<https://rt.cpan.org/Public/Dist/Display.html?Name=Set::FA>.
377              
378             =head1 Author
379              
380             L<Set::FA> was written by Mark Rogaski and Ron Savage I<E<lt>ron@savage.net.auE<gt>> in 2011.
381              
382             Home page: L<http://savage.net.au/index.html>.
383              
384             =head1 Copyright
385              
386             Australian copyright (c) 2011, Ron Savage.
387              
388             All Programs of mine are 'OSI Certified Open Source Software';
389             you can redistribute them and/or modify them under the terms of
390             The Artistic License, a copy of which is available at:
391             http://www.opensource.org/licenses/index.html
392              
393             =cut