An interesting problem

McGlinchy, Alistair Alistair.McGlinchy at marks-and-spencer.com
Thu Jan 4 13:25:28 GMT 2007


> >> I think that the previous mention of a 2D autocorrelation will be
> >> good to explore, but you can use the "moving average" trick 
> >to avoid
> >> lots of extra cycles while summing neighborhoods.  I've implemented
> >> this in C before and gotten speedups of 1x to 50x, 
> depending on the  
> >> neighborhood size.
> >
> >Aye, That's the trick. Run time from 10 mins to 16secs for 
> the 30x100 
> >case. Great fun!
> >
> >Code available if anyone else was interested.
> 
> I certainly am, and I'd imagine most others who read the thread.
> 

OK some warts'n'all code here. Something is munging my posts to either
word-wrap or delete attachments. I'll attach the code as a .txt file as
well and see if that helps.

#!/usr/bin/perl 
use strict;
use warnings;
my %store;

# Data stores using in process. Global out of laziness. 
my @sum_row;
my @sum_range;
my @table; 

# Read in the numbers
while (<DATA>) {
    chomp;
    s/^\s+//;# Remove initial  whitespace.
    s/\s+$//;# Remove trailing whitespace.
    next if /^\s*$/; #Ignore blank lines
    my @row = split /\s+/;
    push @table, \@row;
}
my $max_x = $#table;
my $max_y = $#{$table[0]};

warn "Preparing row cache\n";
prepare_sum_row();
warn "Row Cache Constructed\n";
my ($max, @result ) = max_sum_range();
print "Best range ($result[0],$result[1]) , ($result[2],$result[3]) has
maximum val $max\n";
exit 0;

sub prepare_sum_row { 
    # Prepare a cache of AoAoA of sum of intervales within each row 
    # $sum_row[$x][$y_start][$y_end] is the sum of the cells in row 
    # x from column y_start to y_end
    for my $x        (0 .. $max_x) {
    for my $y_start  (0 .. $max_y) {
        $sum_row[$x][$y_start][$y_start] = $table[$x][$y_start]; # First
cell in the row
        for my $y_end ($y_start +1 .. $max_y) {
            $sum_row[$x][$y_start][$y_end] =    
                $sum_row[$x][$y_start][$y_end-1] + # All previous cells
                $table[$x][$y_end];                # plust this one
        }
    }}
}

sub max_sum_range { 
    # Note for ref lookup efficiency the matrix is in a funny order 
    # $sum_range[$x_start][$y_start][$y_end][$x_end  ]
    # is the sum of the range from (x_start,y_start) to (x_end,_y_end)
    my $max;
    for my $x_start (0..$max_x)  {
        for my $y_start (0..$max_y)  {
            my $row_ender =   $sum_row[$x_start][$y_start];     #keep
this ref hand
            my $range_cnr = $sum_range[$x_start][$y_start]=[];  #keep
this ref handy too
            for my $y_end ($y_start .. $max_y ) {
                my $range_2cnrs= $range_cnr->[$y_end];
                my $val = $range_2cnrs->[$x_start] =
$row_ender->[$y_end]; 
                if (!defined($max) or $max < $val ) {
                    $max = $val;
                    print "Range ($x_start,$y_start) , ($x_start,$y_end)
is better with $val\n";
                    @result = ($x_start,$y_start,$x_start,$y_end);
                }
                for my $x_end ($x_start+1 .. $max_x) {
                    $val = $range_2cnrs->[$x_end] = 
                           $range_2cnrs->[$x_end-1] + 
                           $sum_row[$x_end][$y_start][$y_end];


                    if ($max < $val) {
                        $max = $val;
                        print "Range ($x_start,$y_start) ,
($x_end,$y_end) is better with $val\n";
                        @result = ($x_start,$y_start,$x_end,$y_end);
                    }
                }
            }               
        }
    }
    return ($max, @result);
}
            
__DATA__
-22 -42 -37 -48 29  48  -31 7   -19 -47 -50 -25 -27 -23 38  -24 20  -45
38  -31 -27 14  25  18  -5  13  33  25  19  41  23  26  -43 -21 45  9
-42 18  15  4   49  -45 46  13  -31 -17 -34 27  3   -41
-12 16  38  -18 -18 -43 -39 -44 47  -45 40  -46 -27 5   -23 -26 18  48
15  -11 -41 45  -5  4   -5  -40 18  -34 1   -48 40  39  -33 -24 25  -32
-9  -12 -5  16  10  48  4   14  -20 -20 -39 1   -36 29
-14 37  -34 -21 43  13  4   46  -43 38  -33 -21 -44 24  36  37  46  1
-31 42  -23 -37 -12 -11 -36 29  -46 10  -22 2   -41 -29 41  0   40  22
20  -1  24  -49 -29 1   21  -14 43  -47 13  26  -4  -5

**********************************************************************
Registered Office:
Marks and Spencer plc
Waterside House
35 North Wharf Road
London
W2 1NW

Registered No. 214436 in England and Wales.

Telephone (020) 7935 4422
Facsimile (020) 7487 2670

<<www.marksandspencer.com>>

Please note that electronic mail may be monitored.

This e-mail is confidential. If you received it by mistake, please let us know and then delete it from your system; you should not copy, disclose, or distribute its contents to anyone nor act in reliance on this e-mail, as this is prohibited and may be unlawful.
2005


-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: max_range5.txt
Url: http://london.pm.org/pipermail/london.pm/attachments/20070104/db76688b/max_range5-0001.txt


More information about the london.pm mailing list