### help with simplifying program

by crunch_this! (Acolyte)
 on May 24, 2013 at 05:06 UTC 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 (Pope) 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 (Abbot) 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 snoopy (Deacon) 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 (Prior) 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.
```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.

Re: help with simplifying program
by BillKSmith (Priest) 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";
}

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1035063]
Approved by davido
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2017-06-28 09:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
How many monitors do you use while coding?

Results (631 votes). Check out past polls.