Perl Weekly Challenge 266: X Matrix

These are some answers to the Week 266, 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 April 28, 2024 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 2: X Matrix

You are given a square matrix, $matrix.

Write a script to find if the given matrix is X Matrix.

A square matrix is an X Matrix if all the elements on the main diagonal and antidiagonal are non-zero and everything else are zero.

Example 1

Input: $matrix = [ [1, 0, 0, 2],
                   [0, 3, 4, 0],
                   [0, 5, 6, 0],
                   [7, 0, 0, 1],
                 ]
Output: true

Example 2

Input: $matrix = [ [1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9],
                 ]
Output: false

Example 3

Input: $matrix = [ [1, 0, 2],
                   [0, 3, 0],
                   [4, 0, 5],
                 ]
Output: true

The matrix items on the main diagonal (from top left to bottom right) are those whose row index is equal to the column index, such as @matrix[0][0] or @matrix[1][1], i.e. items 1, 3, 6, and 1 in the first example above.

The matrix items on the anti-diagonal (from top right to bottom left) are those whose row index plus the column index is equal to the matrix size - 1, such as @matrix[0][3] or @matrix[1][2], i.e. items 2, 4, 5 and 7 in the first example above.

X Matrix in Raku

We iterate over the items of the matrix using two nested loops. If an item on a diagonal or an anti-diagonal (see above) is zero, then we return False; if an item not on a diagonal or an anti-diagonal is not zero, then we also return False. If we arrive at the end of the two loops, then we have an X matrix and can return True.

sub is-x-matrix (@m) {
    my $end = @m.end; # end = size - 1
    for 0..$end -> $i {
        for 0..$end -> $j {
            if $i == $j or $i + $j == $end { # diag or antidiag
                return False if @m[$i][$j] == 0;
            } else {    # not diag or antidiag
                return False if @m[$i][$j] != 0;
            }
        }
    }
    # If we got here, it is an X-matrix
    return True;
}

my @tests = 
    [ [1, 0, 0, 2],
      [0, 3, 4, 0],
      [0, 5, 6, 0],
      [7, 0, 0, 1],
    ],
    [ [1, 2, 3],
      [4, 5, 6],
      [7, 8, 9],
    ],
    [ [1, 0, 2],                                                          
      [0, 3, 0],
      [4, 0, 5],
    ];
for @tests -> @test {
    printf "[%-10s...] => ", "@test[0]";
    say is-x-matrix @test;
}

Note that we display only the first row of each test matrix for the sake of getting a better formatting. This program displays the following output:

$ raku ./x-matrix.raku
[1 0 0 2   ...] => True
[1 2 3     ...] => False
[1 0 2     ...] => True

X Matrix in Perl

This is a port to Perl of the above Raku program. Please refer to the previous section if you need further explanations.

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

sub is_x_matrix {
    my $m = shift;
    my $end = scalar @{$m->[0]} - 1; # $end = size - 1
    for my $i (0..$end) {
        for my $j (0..$end) {
            if ($i == $j or $i + $j == $end) { # diag or antidiag
                return "false" if $m->[$i][$j] == 0;
            } else {    # not diag or antidiag
                return "false" if $m->[$i][$j] != 0;
            }
        }
    }
    # If we got here, it is an X-matrix
    return "true";
}

my @tests = (
    [ [1, 0, 0, 2],
      [0, 3, 4, 0],
      [0, 5, 6, 0],
      [7, 0, 0, 1],
    ],
    [ [1, 2, 3],
      [4, 5, 6],
      [7, 8, 9],
    ],
    [ [1, 0, 2],                                                          
      [0, 3, 0],
      [4, 0, 5],
    ]
    );
for my $test (@tests) {
    printf "[%-10s...] => ", "@{$test->[0]}";
    say is_x_matrix $test;
}

This program displays the following output:

$ perl ./x-matrix.pl
[1 0 0 2   ...] => true
[1 2 3     ...] => false
[1 0 2     ...] => true

Wrapping up

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 May 5, 2024. 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.