Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

help with simplifying program

by crunch_this! (Acolyte)
on May 24, 2013 at 05:06 UTC ( [id://1035063]=perlquestion: print w/replies, xml ) Need Help??

crunch_this! has asked for the wisdom of the Perl Monks concerning the following question:

Hi again

I've got this part of my program, which is meant to go through all possibilities of w, x, y, z, except for when they're evenly spaced apart, or in arithmetic sequence if that makes sense to you. Since I already know those cases won't give me what I'm looking for I want to save perl the trouble of considering them. Here's what I've come up with, but I have a feeling there's a way to make it go faster. I wonder if I really need that s variable since it's just one more thing to deal with:

foreach my $w (3..100) { foreach my $x (2..$w-1) { foreach my $y (1..$x-1) { foreach my $z (0..$y-1) { foreach my $s (1..20) { unless ( $x == $w + $s && $y == $x + $s && $z == $ +y + $s ) {

I can add more context if you want, this is just part of the program which works fine I just thought I'd see if there's a way to streamline it.

Replies are listed 'Best First'.
Re: help with simplifying program
by BrowserUk (Patriarch) on May 24, 2013 at 05:36 UTC

    That makes no sense?

    Each of your inner loops is limited to the value of the preceding loop counter-1, so can never attain a value that would trigger your condition.

    Ie. $x is limited to $w-1, so $x can never become equal to $w + $s for any value of $s, unless $s was -1 or less, but your $s loop start from 1 and increases.

    In other words; your unless condition will always be false, and so it is doing nothing (except consuming cycles).


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      True. $s should really go from -1 to -33 I think.

      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: help with simplifying program
by tobyink (Canon) on May 24, 2013 at 05:38 UTC

    Untested, but makes sense to me...

    foreach my $w (3..100) { foreach my $x (2..$w-1) { foreach my $y (1..$x-1) { foreach my $z (0..$y-1) { next if ($z-$y==$y-$x and $y-$x==$x-$w); ...; } } } }
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: help with simplifying program
by BillKSmith (Monsignor) on May 24, 2013 at 14:19 UTC

      This is the part of the program it comes from. I thought all the math stuff would be Math::Something so I didn't know about that combinatorics module! That sounds very interesting. I wonder if/how it could be applied here? It runs through all the possible polynomials of a certain form and spits out the ones whose derivatives have (approximately) integer roots.

      # $lep means smallest nonzero root in the interval [0, $rep] # $rep means right endpoint of the interval [0, $rep] my $lep = int 1; my $rep = int 100; foreach my $x ($lep+2 .. $rep ) { foreach my $y ($lep+1 .. $x-1 ) { foreach my $z ($lep .. $y-1 ) { foreach my $s (1..$rep/4) { unless ($y == $x + $s && $z == $y + $s ) { # assigns a truth value to whether or not it is wi +thin 0.0001 of an integer (1=true, 0=false) sub is_approximately_an_integer { my $eps = 0.0001; while( my $w = shift ) { # need to use "round", "int" does not work! return 0 if abs( $w-round($w) ) > $eps; } return 1 } } } push @wants, map { { join(', ', $x, $y, $z) => $_ } } grep { is_approximately_an_integer( @$_ ) } [ poly_roots( poly_derivative( # expanded form of x*(x - $x)*(x - $y)*(x +- $z) 1, -$x - $y - $z, $x*$y + $x*$z + $y*$z, - +$x*$y*$z, 0 ) ) ]; } } }
        Oops, I was slightly wrong. Combinations will only replace three of your loops. You still have to select the applicable combinations.
        use Algorithm::Combinatorics qw(combinations); my $lep = int 1; my $rep = int 100; my $iter = combinations( [$lep+2 ..$rep], 3 ); while (my $c = $iter->next) { my ($x, $y, $z) = @$c; foreach my $s (1..$rep/4) { # as before } }
        Bill

        You should figure this out yourself!! Read the documentation!!

        use strict; use warnings; use Algorithm::Combinatorics qw(combinations); my $rep = 5; # should be 100 my @data = 0..$rep; my $iter = combinations( \@data, 4 ); while( my $p = $iter->next ) { my ( $z, $y, $x, $w ) = @$p; next unless $w-2*$x+$y or $x-2*$y+$z; print "$w, $x, $y, $z\n"; }
Re: help with simplifying program
by snoopy (Curate) on May 24, 2013 at 05:50 UTC
    Hi There, I'm not sure, if the unless condition is actually filtering anything:
    use strict; my $n1; my $n2; foreach my $w (3..100) { foreach my $x (2..$w-1) { foreach my $y (1..$x-1) { foreach my $z (0..$y-1) { foreach my $s (1..20) { $n1++; unless ( $x == $w + $s && $y == $x + $s && $z == $y + $s ) { $n2++; } } } } } } print "n1: $n1\n"; print "n2: $n2\n";
    Output:
    n1: 81658500 n2: 81658500
Re: help with simplifying program
by hdb (Monsignor) on May 24, 2013 at 08:40 UTC

    From your description I take you want (w, x, y, z) such that 0 <= z < y < x < w <= 100 and not w-x == x-y == y-z. In order to achieve this I would parametrize the loops using the differences dwx = w-x, dxy = x-y, dyz = y-z.

    use strict; use warnings; my $n = 5; # should be 100 my $c1 = my $c2 = 0; for my $w (3..$n) { for my $dwx (1..$w-2) { my $x = $w - $dwx; for my $dxy (1..$x-1) { my $y = $x - $dxy; for my $dyz (1..$y) { my $z = $y - $dyz; $c1++; next unless $dwx != $dxy or $dxy != $dyz; $c2++; print "$w $x $y $z\n"; } } } } print "Found $c2 out of $c1 combinations\n";
    UPDATE: Changes next unless... for better readibility.
      The unless should read
      next unless $dwx != $dxy and $dxy != $dyz;
      otherwise you will not get all of the valid combinations

        Your proposal gets less combinations! I admit that using unless and != is rather confusing but it is correct. It translates into

        next if $dwx == $dxy and $dxy == $dyz;

        which I should have used in the first place.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1035063]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2024-04-19 21:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found