in reply to Re^2: optimization help
in thread optimization help

Applying what I said in Re: optimization help,

my @functions = ( sub { # sin(x) my $in = shift; return sin($in); }, sub { # add(x,y) my ($left,$right) = @_; return ($left + $right); }, sub { # mul(x,y) my ($left,$right) = @_; return ($left * $right); }, sub { # log(x) my $in = shift; return ($in == 0) ? 0 : log(abs($in)); }, ); ... sub evalTree { my $intree = shift; my $param = shift; # A shortcut for the current node. for my $contents ($intree->{contents}) { return 0 unless defined $contents; if (ref($contents) eq 'CODE') { return $contents->( evalTree($intree->{left}, $param), evalTree($intree->{right}, $param), ); } if ($contents =~ /^[A-Za-z]$/) { return $param->{$_}; } return $contents; } }

If you need both the string and the compiled sub, save both instead of recompiling the strings over and over again.

Replies are listed 'Best First'.
Re^4: optimization help
by samtregar (Abbot) on Oct 15, 2007 at 23:06 UTC
    And how will you code the mutate step? With the B:: modules perhaps?

    UPDATE: Whoops, never mind me. I assumed it was doing some kind of textual code generation for mutate(). You're absolutely right, there's no reason not to just use sub-refs here.

    -sam

Re^4: optimization help
by GSF (Acolyte) on Oct 16, 2007 at 16:24 UTC
    More questions for those who are patient without limits: Refrencing a scalar as in ref($contents) when evaluated as a string, will return 'CODE' if it points to a subroutine?

    Part of my problem is my reasoning tells me I can't precompile all code because this is evolutionary code - there is no way for the compiler to know what it is going to do before it does it.

    However, we are no longer evaling, we are refrencing subs recursively. This may complicate structure parsing for reporting but maybe . . . . maybe I'm just resisting the shortest path. Thanks for the example, I'll take a crack at the rest of this....

    Thanks again.

      Part of my problem is my reasoning tells me I can't precompile all code because this is evolutionary code - there is no way for the compiler to know what it is going to do before it does it.

      As I understand it (and I'll admit I only gave your code a cursory glance), your building blocks are constant, only the order in which they are called is not.

      Therefore, the basic blocks (sin, add, etc) need only be compiled once, while your dynamic tree handles the execution path.

      By the way, that's very similar to how perl executes a Perl program. The program is parsed into a tree made from basic building blocks named opcodes. Perl then navigates that tree.

      >perl -MO=Terse -e"my $x = qq{Hello World\n}; print($x);" LISTOP (0x1985394) leave [1] OP (0x19852bc) enter COP (0x19853b8) nextstate BINOP (0x19853f4) sassign SVOP (0x1985418) const [3] PV (0x225eac) "Hello World\n" OP (0x1985498) padsv [1] COP (0x19852fc) nextstate LISTOP (0x1985354) print OP (0x1985338) pushmark OP (0x1985378) padsv [1] -e syntax OK
        YOU ROCK IKEGAMI!

        I'm goign to implement your suggestions if it kills me.