File Coverage

blib/lib/Math/Symbolic/Custom/DumpToFastEval.pm
Criterion Covered Total %
statement 66 72 91.6
branch 11 18 61.1
condition 3 8 37.5
subroutine 12 12 100.0
pod 0 1 0.0
total 92 111 82.8


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Math::Symbolic::Custom::DumpToFastEval - Compile Math::Symbolic trees fast RPN form
5              
6             =head1 SYNOPSIS
7              
8             use Math::Symbolic::Custom::DumpToFastEval;
9              
10             =head1 DESCRIPTION
11              
12             FIXME documentation!
13              
14             =head2 EXPORT
15              
16             None by default, but you may choose to import the compile(), compile_to_sub(),
17             and compile_to_code() subroutines to your namespace using the standart
18             Exporter semantics including the ':all' tag.
19              
20             =head1 SUBROUTINES
21              
22             =cut
23              
24             package Math::Symbolic::Custom::DumpToFastEval;
25 1     1   761 use 5.006;
  1         4  
  1         47  
26 1     1   6 use strict;
  1         2  
  1         1555  
27 1     1   7 use warnings;
  1         2  
  1         48  
28              
29             our $VERSION = '0.01';
30              
31 1     1   6 use Math::SymbolicX::FastEvaluator;
  1         1  
  1         23  
32 1     1   4 use Math::Symbolic::Custom::Base;
  1         1  
  1         34  
33 1     1   36 BEGIN {*import = \&Math::Symbolic::Custom::Base::aggregate_import}
34              
35             our $Aggregate_Export = [qw/to_fasteval/];
36              
37 1     1   6 use Math::Symbolic::ExportConstants qw/:all/;
  1         1  
  1         369  
38              
39             sub to_fasteval {
40 3     3 0 43441 my $tree = shift;
41 3 50 33     20 $tree = shift if not ref $tree and $tree eq __PACKAGE__;
42              
43 3   50     23 my $order = shift || [];
44 3         6 my %order;
45 3 50       39 if (ref($order) eq 'HASH') {
    50          
46 0         0 %order = %$order;
47             }
48             elsif (ref($order) eq 'ARRAY') {
49 3         5 my $count = 0;
50 3         12 %order = map { ( $_, $count++ ) } @$order;
  0         0  
51             }
52              
53 1     1   6 no warnings 'recursion';
  1         2  
  1         254  
54              
55 3         18 my $vars = [ $tree->explicit_signature() ];
56              
57 3         589 my %vars;
58             my @not_placed;
59 3         9 foreach (@$vars) {
60 4         7 my $pos = $order{$_};
61 4 50       10 if ( defined $pos ) {
62 0         0 $vars{$_} = $pos;
63             }
64             else {
65 4         10 push @not_placed, $_;
66             }
67             }
68              
69 3         5 my $count = 0;
70 3         11 foreach ( sort @not_placed ) {
71 4         11 $vars{$_} = @$vars - @not_placed + $count++;
72             }
73              
74             # The user is to do that himself. Left in to show that it would be
75             # a sensible (if slow) thing to do.
76             # $tree = $tree->simplify();
77             # $tree = $tree->apply_derivatives();
78             # $tree = $tree->simplify();
79              
80 3         5 my @trees;
81              
82 3         36 my $expr = Math::SymbolicX::FastEvaluator::Expression->new();
83 3         13 my $success = _rec_ms_to_expr( $expr, $tree, \%vars );
84 3 50       10 return() if not $success;
85            
86 3         14 $expr->SetNVars(scalar keys %vars);
87              
88 3         11 return($expr);
89             }
90              
91              
92             {
93 1     1   6 no warnings 'recursion';
  1         1  
  1         437  
94             sub _rec_ms_to_expr {
95 3     3   6 my $expr = shift;
96 3         5 my $tree = shift;
97 3         5 my $vars = shift;
98              
99 3         25 my $op = Math::SymbolicX::FastEvaluator::Op->new();
100              
101 3         6 eval {
102             $tree->descend(
103             in_place => 1,
104             after => sub {
105 26     26   1181 my $t = shift;
106 26         55 my $ttype = $t->term_type;
107 26 100       102 if ($ttype == T_VARIABLE) {
    100          
108 4         12 $op->SetVariable();
109 4         14 $op->SetValue($vars->{$t->name});
110             #print $t->name, " ";
111             }
112             elsif ($ttype == T_CONSTANT) {
113 9         23 $op->SetNumber();
114 9         22 $op->SetValue($t->value);
115             #print $t->value, " ";
116             }
117             else {
118 13         268 my $type = $t->type;
119 13 50 33     99 if ($type == U_P_DERIVATIVE || $type == U_T_DERIVATIVE) {
120 0         0 die "Can't convert dertivatives to RPN for the FastEvaluator!";
121             }
122 13         30 $op->SetOpType($type);
123             #print $Math::Symbolic::Operator::Op_Types[$type]{prefix_string}, " ";
124             }
125 26         251 $expr->AddOp($op);
126             },
127 3         33 );
128             };
129 3 50       35 if ($@) {
130 0         0 warn "Caught exception while converting Math::Symbolic tree to RPN: $@";
131 0         0 return();
132             }
133 3         18 return 1;
134             }
135             }
136              
137             1;
138             __END__