Perl Weekly Challenge 248: Submatrix Sum

These are some answers to the Week 248, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on December 24, 2023, at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Submatrix Sum

You are given a NxM matrix A of integers.

Write a script to construct a (N-1)x(M-1) matrix B having elements that are the sum over the 2x2 submatrices of A,

b[i,k] = a[i,k] + a[i,k+1] + a[i+1,k] + a[i+1,k+1]

Example 1

Input: $a = [
              [1,  2,  3,  4],
              [5,  6,  7,  8],
              [9, 10, 11, 12]
            ]

Output: $b = [
               [14, 18, 22],
               [30, 34, 38]
             ]

Example 2

Input: $a = [
              [1, 0, 0, 0],
              [0, 1, 0, 0],
              [0, 0, 1, 0],
              [0, 0, 0, 1]
            ]

Output: $b = [
               [2, 1, 0],
               [1, 2, 1],
               [0, 1, 2]
             ]

This is not very difficult. To keep it simple, we simply need to work row by row, and make sure we don't mess indices around.

Submatrix Sum in Raku

As said above, it is quite simple if we work row by row.

sub submatrix-sum (@in) {
    my $max-row = @in.end;
    my $max-col = @in[0].end;
    my @result;
    for 0..^$max-row -> $i {
        my @row;
        for 0..^$max-col -> $j {
            push @row, @in[$i][$j] + @in[$i][$j+1] + 
                @in[$i+1][$j] + @in[$i+1][$j+1];
        }
        push @result, @row; # push doesn't flatten 
    }
    return @result;
}

my @tests = [
              [1,  2,  3,  4],
              [5,  6,  7,  8],
              [9, 10, 11, 12]
            ],
            [
              [1, 0, 0, 0],
              [0, 1, 0, 0],
              [0, 0, 1, 0],
              [0, 0, 0, 1]
            ];
for @tests -> @test {
    print @test.gist, " => ";;
    say submatrix-sum @test;
}

This program displays the following output:

$ raku ./submatrix-sum.raku
[[1 2 3 4] [5 6 7 8] [9 10 11 12]] => [[14 18 22] [30 34 38]]
[[1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]] => [[2 1 0] [1 2 1] [0 1 2]]

Submatrix Sum in Perl

This a port to Perl of the above Raku program. It is slightly more complicated in Perl than in Raku, because we need to use references for nested data structures, but it is really not that difficult.

use strict;
use warnings;
use feature 'say';

sub submatrix_sum {
    my @in = @_;
    my $max_row = $#in - 1;
    my $max_col = $#{$in[0]};
    my @result;
    for my $i (0..$max_row ) {
        my @row;
        for my $j (0..$max_col - 1) {
            push @row, $in[$i][$j] + $in[$i][$j+1] + 
                $in[$i+1][$j] + $in[$i+1][$j+1];
        }
        push @result, [@row];
    }
    return @result;
}

my @tests = ([
              [1,  2,  3,  4],
              [5,  6,  7,  8],
              [9, 10, 11, 12]
             ],
             [
              [1, 0, 0, 0],
              [0, 1, 0, 0],
              [0, 0, 1, 0],
              [0, 0, 0, 1]
             ]);
for my $test (@tests) {
    print join ", ", map { "[@$_]" } @$test;
    print " => ";
    say join ", ", map { "[@$_]" } submatrix_sum @$test;
}

This program displays the following output:

$ perl  ./submatrix-sum.pl
[1 2 3 4], [5 6 7 8], [9 10 11 12] => [14 18 22], [30 34 38]
[1 0 0 0], [0 1 0 0], [0 0 1 0], [0 0 0 1] => [2 1 0], [1 2 1], [0 1 2]

Wrapping up

Season's greetings to everyone. The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on December 31, 2023. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.