in reply to Re: Re: Peeling the Peelings
in thread Peeling the Peelings

Hehe - you actually do. ++

But not that much anymore: ;-)

sub get_proparg_new { my $propstr = shift; # get the property string my $level = shift || return $propstr; # get the level we want to e +xtract if($level == -1) { # special case, get the innermost argume +nt $propstr =~ /\(([^()]+)\)+/; return $1; } else { # get whatever argument $level indicates while ($level--) { $propstr =~ /\((.+)\)/; $propstr = $1; } } return $propstr; }
Benchmark: timing 25000 iterations of mine-elegant, mine-less-elegant, original, original++...
mine-elegant:  5 wallclock secs ( 4.61 usr +  0.00 sys =  4.61 CPU) @ 5422.99/s (n=25000)
mine-less-elegant:  2 wallclock secs ( 2.16 usr +  0.00 sys =  2.16 CPU) @ 11574.07/s (n=25000)
  original:  2 wallclock secs ( 2.55 usr +  0.00 sys =  2.55 CPU) @ 9803.92/s (n=25000)
original++:  3 wallclock secs ( 2.32 usr +  0.00 sys =  2.32 CPU) @ 10775.86/s (n=25000)
I guess I'll trade that performance loss against readability. But thanks for the Ideas I could borrow and reuse.

Bye
 PetaMem
    All Perl:   MT, NLP, NLU

Replies are listed 'Best First'.
Re: Re: Re: Re: Peeling the Peelings
by EvdB (Deacon) on Jul 02, 2003 at 14:31 UTC
    Warning: objections have been raised to the following code - see below for the objections and the revised code

    Hmm, I think I own you now - this uses code that writes code:

    [%# Run this through tpage - from Template %] [% numbers = [ 1, 2, 3, 4, 5, 6 ] -%] [% end = '\)' -%] [% start = '\w+\(' -%] my %functions = (); [% FOR level = numbers -%] $functions{ [% level %] } = sub { $_[0] =~ s/[% end %]{[% level %]}$//o; $_[0] =~ s/^([% start %]){[% level %]}//o; return $_[0]; }; [% END -%] sub get_proparg_evdb { $_ = $_[0]; my $level = $_[1] || return $_; if ($level == -1) { m/\(([^()]+)\)+/; return $1; } return &{$functions{ $level }}( $_ ) || die 'Add universal function here'; }
    This code, when parsed by tpage which comes with Template will create a special function for each of the cases with an optimised regexp in it. These functions are then accessed through a hash.

    The complete code that is produced is here:

    By adding this to the benchmaring stuff above from previous posts using require evdb_functions.pl (or whatever) and Benchmarking you get this (some suggestions omitted for clarity):
    Rate ori m-elegant ori++ evdb ori 6234/s -- -36% -40% -51% m-elegant 9690/s 55% -- -7% -24% ori++ 10373/s 66% 7% -- -18% evdb 12690/s 104% 31% 22% --

    Code that writes code - tip 29 from the pragmatic programmer.

    --tidiness is the memory loss of environmental mnemonics

      Another useless use of /o. See /o is dead, long live qr//!. Also, your code can be simplified by throwing away the %functions hash and just creating the matching expressions as needed.

        I think I understand what you mean about creating the matching expressions on the fly - but that would remove the speed gain from creating all the anonymous functions at compile time and then calling them as needed.

        If I have misunderstood please could you post some code to demonstrate. (PS I have revised my code - see above. That wretched \o is gone - nice posting on it ++).

        --tidiness is the memory loss of environmental mnemonics

      UPDATE: This "solution" modifies the @data, such that all entries are case 0, so the benchmarks as run are not valid.

      Nice try, though.


      IGNORE THE REST OF THIS.

      OK, I'm owned. This is pretty slick. update: Yours test fastest. However, my test numbers are way different than befpore anthe OP's best shoit is now *better* than mine - which I don't understand.

      --Bob Niederman, http://bob-n.com
        I believe I have addressed your concerns with this:
        [%# Run this through tpage - from Template %] [% debug = 0 %] [% numbers = [ 1, 2, 3, 4, 5, 6 ] -%] [% end = '\)' -%] [% start = '\w+\(' -%] my %functions = (); [% FOR level = numbers -%] $functions{ [% level %] } = sub { my $string = shift; [% IF debug %]my $warn = "running [% level %] on '$string'";[% END % +] $string =~ s/[% end %]{[% level %]}$//; $string =~ s/^([% start %]){[% level %]}//; [% IF debug %]warn "$warn to produce '$string'\n\n";[% END %] return $string; }; [% END -%] $functions{-1} = sub { my $string = shift; $string =~ m/\(([^()]+)\)+/; [% IF debug %]warn "running -1 on $string to produce '$1'\n";[% END +%] return $1; }; sub get_proparg_evdb { my $string = shift; my $level = shift || return $string; return &{$functions{ $level }}( $string ) || die 'Add universal function here'; }

        I also wrote the following test code which should check that the function is behaving as it should:

        # Test the function against another with known good results. for (@data) { my @args = split; my @copy = @args; my $A = get_proparg( @args ); my $B = get_proparg_evdb( @args ); unless ( $A eq $B ) { warn "function wrong for '$args[1]'\n"; warn "A is '$A'\nB is '$B'\n\n"; } warn "array messed up\n" unless join(' ',@copy) eq join(' ',@args); }

        I took into account the uselessness of \o (thank you diotalevi) and also removed the case == -1 check by creating a function for it. Interestingly the results are now even better:

        Rate m-elegant ori ori++ evdb m-elegant 1797/s -- -6% -11% -36% ori 1914/s 7% -- -5% -32% ori++ 2016/s 12% 5% -- -28% evdb 2818/s 57% 47% 40% --

        If I have misunderstood your critique please let me know. As you can see you can set debug = 1 in the template stuff to enable messages during the run that shows that all cases are being used.

        --tidiness is the memory loss of environmental mnemonics

Re: Re: Re: Re: Peeling the Peelings
by Jasper (Chaplain) on Jul 02, 2003 at 11:40 UTC
    That all seems pretty good now, but you can still improve the special case (-1) regexp a little.
    $propstr =~ /.*\((.*?)\)/;
    Can't help with anything else, I'm afraid.

    Jasper