|
NAMEMath::Symbolic::Custom::Transformation - Transform Math::Symbolic treesSYNOPSISuse Math::Symbolic::Custom::Transformation; my $trafo = Math::Symbolic::Custom::Transformation->new( 'TREE_x + TREE_x' => '2 * TREE_x' ); my $modified = $trafo->apply($math_symbolic_tree); if (defined $modified) { print "Outermost operator is a sum of two identical trees.\n"; print "Transformed it into a product. ($modified)\n"; } else { print "Transformation could not be applied.\n"; } # shortcut: new_trafo use Math::Symbolic::Custom::Transformation qw/new_trafo/; # use the value() function to have the transformation compute the value # of the expression after the replacements. simplify{} works similar. my $another_trafo = new_trafo( 'TREE_foo / CONST_bar' => 'value{1/CONST_bar} * TREE_foo' ); # If you'll need the same transformation but don't want to keep it around in # an object, just do this: use Memoize; memoize('new_trafo'); # Then, passing the same transformation strings will result in a speedup of # about a factor 130 (on my machine) as compared to complete recreation # from strings. This is only 20% slower than using an existing # transformation. DESCRIPTIONMath::Symbolic::Custom::Transformation is an extension to the Math::Symbolic module. You're assumed to be remotely familiar with that module throughout the documentation.This package implements transformations of Math::Symbolic trees using Math::Symbolic trees. I'll try to explain what this means in the following paragraphs. Until now, in order to be able to inspect a Math::Symbolic tree, one had to use the low-level Math::Symbolic interface like comparing the top node's term type with a constant (such as "T_OPERATOR") and then its operator type with more constants. This has changed with the release of Math::Symbolic::Custom::Pattern. To modify the tree, you had to use equally low-level or even encapsulation-breaking methods. This is meant to be changed by this distribution. EXAMPLESay you want to change any tree that is a sum of two identical trees into two times one such tree. Let's assume the original object is in the variable $tree. The old way was: (strictures and warnings assumed)use Math::Symbolic qw/:all/; sub sum_to_product { if ( $tree->term_type() == T_OPERATOR and $tree->type() == B_SUM and $tree->op1()->is_identical($tree->op2()) ) { $tree = Math::Symbolic::Operator->new( '*', Math::Symbolic::Constant->new(2), $tree->op1()->new() ); } return $tree; } What you'd do with this package is significantly more readable: use Math::Symbolic::Custom::Transformation qw/new_trafo/; my $Sum_To_Product_Rule = new_trafo('TREE_a + TREE_a' => '2 * TREE_a'); sub sum_to_product { my $tree = shift; return( $Sum_To_Product_Rule->apply($tree) || $tree ); } Either version could be shortened, of course. The significant improvement, however, isn't shown by this example. If you're doing introspection beyond the outermost operator, you will end up with giant, hardly readable if-else blocks when using the old style transformations. With this package, however, such introspection scales well: use Math::Symbolic::Custom::Transformation qw/new_trafo/; my $Sum_Of_Const_Products_Rule = new_trafo( 'CONST_a * TREE_b + CONST_c * TREE_b' => 'value{CONST_a + CONST_c} * TREE_b' ); sub sum_to_product { my $tree = shift; return( $Sum_Of_Const_Products_Rule->apply($tree) || $tree ); } For details on the "value{}" construct in the transformation string, see the "SYNTAX EXTENSIONS" section. EXPORTNone by default, but you may choose to import the "new_trafo" subroutine as an alternative constructor for Math::Symbolic::Custom::Transformation objects.PERFORMANCEThe performance of transformations isn't astonishing by itself, but if you take into account that they leave the original tree intact, we end up with a speed hit of only 16% as compared to the literal code. (That's the huge if-else block I was talking about.)You may be tempted to recreate the transformation objects from strings whenever you need them. There's one thing to say about that: Don't! The construction of transformations is really slow because they have been optimised for performance on application, not creation. (Application should be around 40 times faster than creation from strings!) Note: Starting with version 2.00, this module also supports the new-ish Math::Symbolic::Parser::Yapp parser implementation which is significantly faster than the old Parse::RecDescent based implementation. Replacement strings are parsed using Yapp by default now, which means a performance increase of about 20%. The search patterns are still parsed using the default Math::Symbolic parser which will be switched to Yapp at some point in the future. If you force the use of the Yapp parser globally, the parser performance will improve by about an order of magnitude! You can do so by adding the following before using Math::Symbolic::Custom::Transformation: use Math::Symbolic; BEGIN { $Math::Symbolic::Parser = Math::Symbolic::Parser->new( implementation => 'Yapp' ); } use Math::Symbolic::Custom::Transformation; #... If you absolutely must include the source strings where the transformation is used, consider using the Memoize module which is part of the standard Perl distribution these days. use Memoize; use Math::Symbolic::Custom::Transformation qw/new_trafo/; memoize('new_trafo'); sub apply_some_trafo { my $source = shift; my $trafo = new_trafo(...some pattern... => ...some transformation...); return $trafo->apply($source); } This usage has the advantage of putting the transformation source strings right where they make the most sense in terms of readability. The memoized subroutine "new_trafo" only constructs the transformation the first time it is called and returns the cached object every time thereafter. SYNTAX EXTENSIONSThe strings from which you can create transformations are basically those that can be parsed as Math::Symbolic trees. The first argument to the transformation constructor will, in fact, be parsed as a Math::Symbolic::Custom::Pattern object. The second, however, may include some extensions to the default Math::Symbolic syntax. These extensions are the two functions "value{...}" and "simplify{...}". The curly braces serve the purpose to show the distinction from algebraic parenthesis. When finding a "value{EXPR}" directive, the module will calculate the value of "EXPR" when the transformation is applied. (That is, after the "TREE_foo", "CONST_bar" and "VAR_baz" placeholders have been inserted!) The result is then inserted into the transformed tree.Similarily, the "simplify{EXPR}" directive will use the Math::Symbolic simplification routines on "EXPR" when the transformation is being applied (and again, after replacing the placeholders with the matched sub-trees. METHODSThis is a list of public methods.
SUBROUTINESThis is a list of public subroutines.
SEE ALSONew versions of this module can be found on http://steffen-mueller.net or CPAN.This module uses the Math::Symbolic framework for symbolic computations. Math::Symbolic::Custom::Pattern implements the pattern matching routines. AUTHORSteffen Müller, <smueller@cpan.org>COPYRIGHT AND LICENSECopyright (C) 2005, 2006, 2007, 2008, 2009, 2013 by Steffen MuellerThis library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.6.1 or, at your option, any later version of Perl 5 you may have available.
Visit the GSP FreeBSD Man Page Interface. |