File Coverage

blib/lib/Math/Symbolic/Custom/Transformation/Group.pm
Criterion Covered Total %
statement 21 67 31.3
branch 0 22 0.0
condition 0 6 0.0
subroutine 7 11 63.6
pod 4 4 100.0
total 32 110 29.0


line stmt bran cond sub pod time code
1             package Math::Symbolic::Custom::Transformation::Group;
2              
3 1     1   29 use 5.006;
  1         4  
  1         45  
4 1     1   7 use strict;
  1         3  
  1         38  
5 1     1   5 use warnings;
  1         3  
  1         1437  
6              
7 1     1   6 use Carp qw/croak/;
  1         1  
  1         65  
8 1     1   5 use Math::Symbolic qw/:all/;
  1         2  
  1         271  
9 1     1   5 use Math::Symbolic::Custom::Pattern;
  1         2  
  1         31  
10 1     1   4 use base 'Math::Symbolic::Custom::Transformation', 'Exporter';
  1         2  
  1         806  
11              
12             our $VERSION = '2.02';
13              
14             =encoding utf8
15              
16             =head1 NAME
17              
18             Math::Symbolic::Custom::Transformation::Group - Group of Transformations
19              
20             =head1 SYNOPSIS
21              
22             use Math::Symbolic::Custom::Transformation qw/:all/;
23             use Math::Symbolic qw/parse_from_string/;
24            
25             my $group = new_trafo_group(
26             ',',
27             new_trafo( 'TREE_x ^ 1' => 'TREE_x' ),
28             new_trafo( 'TREE_x ^ CONST_a' => 'TREE_x * TREE_x^value{CONST_a-1}' ),
29             );
30            
31             my $function = parse_from_string(
32             '(foo+1)^3 + bar^2'
33             );
34            
35             while(1) {
36             my $result = $group->apply_recursive($function);
37             last if not defined $result;
38             $function = $result;
39             }
40            
41             print $function."\n"
42             # prints "((foo + 1) * ((foo + 1) * (foo + 1))) + (bar * bar)"
43              
44             =head1 DESCRIPTION
45              
46             A C object (Trafo Group for now)
47             represents a conjunction of several transformations and is a transformation
48             itself. An example is in order here:
49              
50             my $group = new_trafo_group( ',', $trafo1, $trafo2, ... );
51              
52             Now, C<$group> can be applied to L trees as if it was
53             an ordinary transformation object itself. In fact it is, because this is
54             a subclass of L.
55              
56             The first argument to the constructor specifies the condition under which the
57             grouped transformations are applied. C<','> is the simplest form. It means
58             that all grouped transformations are always applied. C<'&'> means that
59             the next transformation will only be applied if the previous one succeeded.
60             Finally, C<'|'> means that the first transformation to succeed is the last
61             that is tried. C<'&'> and C<'|'> are C and C operators if you will.
62              
63             =head2 EXPORT
64              
65             None by default, but you may choose to import the C
66             subroutine as an alternative constructor for
67             C objects.
68              
69             =cut
70              
71             =head2 METHODS
72              
73             This is a list of public methods.
74              
75             =over 2
76              
77             =cut
78              
79             =item new
80              
81             This is the constructor for C
82             objects.
83             First argument must be the type of the group as explained above. (C<','>,
84             C<'&'>, or C<'|'>.) Following the group type may be any number
85             of transformations (or groups thereof).
86              
87             =cut
88              
89             our %EXPORT_TAGS = ( 'all' => [ qw(
90             new_trafo_group
91             ) ] );
92              
93             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
94              
95             our @EXPORT = qw();
96              
97             my %Conjunctions = (
98             '&' => 1,
99             '|' => 1,
100             ',' => 1,
101             );
102              
103             sub new {
104 0     0 1   my $proto = shift;
105 0   0       my $class = ref($proto)||$proto;
106              
107 0           my $conjunction = shift;
108 0 0         $conjunction = ',' if not defined $conjunction;
109              
110 0 0         unless ($Conjunctions{$conjunction}) {
111 0           croak("Invalid conjunction type '$conjunction'.");
112             }
113              
114 0           my @trafos;
115 0           while (@_) {
116 0           my $this = shift @_;
117 0 0 0       if (
118             ref($this)
119             and $this->isa('Math::Symbolic::Custom::Transformation')
120             )
121             {
122 0           push @trafos, $this;
123             }
124             else {
125 0           my $pattern = shift @_;
126 0           my $trafo = Math::Symbolic::Custom::Transformation->new(
127             $this, $pattern
128             );
129 0           push @trafos, $trafo;
130             }
131             }
132              
133 0           my $self = {
134             transformations => \@trafos,
135             conjunction => $conjunction,
136             };
137              
138 0           bless $self => $class;
139              
140 0           return $self;
141             }
142              
143              
144             =item apply
145              
146             Applies the transformation (group) to a
147             C tree. First argument must be
148             a C tree to transform. The tree is not transformed in-place,
149             but its matched subtrees are contained in the transformed tree, so if you plan
150             to use the original tree as well as the transformed tree, take
151             care to clone one of the trees.
152              
153             C returns the transformed tree if the transformation pattern matched
154             and a false value otherwise.
155              
156             On errors, it throws a fatal error.
157              
158             =cut
159              
160             sub apply {
161 0     0 1   my $self = shift;
162 0           my $tree = shift;
163              
164 0 0         if (not ref($tree) =~ /^Math::Symbolic/) {
165 0           croak("First argument to apply() must be a Math::Symbolic tree.");
166             }
167              
168 0           my $new;
169 0           my $trafos = $self->{transformations};
170 0           my $conj = $self->{conjunction};
171              
172             # apply sequentially regardless of outcome
173 0 0         if ($conj eq ',') {
    0          
    0          
174 0           foreach my $trafo (@$trafos) {
175 0           my $res = $trafo->apply($tree);
176 0 0         $new = $tree = $res if defined $res;
177             }
178             }
179             # apply as long as the previous applied
180             elsif ($conj eq '&') {
181 0           foreach my $trafo (@$trafos) {
182 0           my $res = $trafo->apply($tree);
183 0 0         $new = $tree = $res if defined $res;
184 0 0         last unless defined $res;
185             }
186             }
187             # apply until the first is applied
188             elsif ($conj eq '|') {
189 0           foreach my $trafo (@$trafos) {
190 0           my $res = $trafo->apply($tree);
191 0 0         if(defined $res) {
192 0           $new = $tree = $res;
193 0           last;
194             }
195             }
196             }
197             else {
198 0           warn "Invalid conjunction '$conj'";
199             }
200              
201 0           return $new;
202             }
203              
204              
205             =item to_string
206              
207             Returns a string representation of the transformation.
208             In presence of the C or C hooks, this may
209             fail to return the correct represenation. It does not round-trip!
210              
211             (Generally, it should work if only one hook is present, but fails if
212             more than one hook is found.)
213              
214             =cut
215              
216             sub to_string {
217 0     0 1   my $self = shift;
218              
219 0           my $str = '[ ' . join(
220             ' '.$self->{conjunction}.' ',
221             map {
222 0           $_->to_string()
223 0           } @{$self->{transformations}}
224             ) . ' ]';
225 0           return $str;
226             }
227              
228             =item apply_recursive
229              
230             This method is inherited from L.
231              
232             =back
233              
234             =head2 SUBROUTINES
235              
236             This is a list of public subroutines.
237              
238             =over 2
239              
240             =cut
241              
242             =item new_trafo_group
243              
244             This subroutine is an alternative to the C constructor for
245             Math::Symbolic::Custom::Transformation::Group objects that uses a hard coded
246             package name. (So if you want to subclass this module, you should be aware
247             of that!)
248              
249             =cut
250              
251             sub new_trafo_group {
252 0     0 1   unshift @_, __PACKAGE__;
253 0           goto &new;
254             }
255              
256             1;
257             __END__