Perl Weekly Challenge 145: Dot Product

by Abigail

Challenge

You are given 2 arrays of same size, @a and @b.

Write a script to implement Dot Product.

Example:

@a = (1, 2, 3);
@b = (4, 5, 6);

$dot_product = (1 * 4) + (2 * 5) + (3 * 6) => 4 + 10 + 18 => 32

Discussion

There is nothing difficult about this challenge. We just have to pairwise multiply the coordinates, and sum them, as the dot product of two vectors is defined as:

\[ v_a \bullet v_b = \sum_{i=1}^n a_i \cdot b_i, \:\text{where } v_a = (a_1, \ldots, a_n) \:\text{and } v_b = (b_1, \ldots, b_n) \]

Solution

We will be assuming we have two lines of input, each line having the coordinates of one vector. The coordinates will be separated by a space, and we will assume both vectors have the same number of coordinates.

For some languages, we will assume the coordinates are integers.

Perl

Math::Matrix has many useful operations on matrices (and vectors are just one-dimensional matrices), including dotproduct, which, as the name suggests, returns the dot product of two vectors.

Which leads to the following simple program:

use Math::Matrix;
say Math::Matrix:: -> new ([split ' ' => scalar <>]) -> dot_product
   (Math::Matrix:: -> new ([split ' ' => scalar <>]));

Find the full program on GitHub.

Scheme

Here we define a recursive function to calculate the dot product:

(define (dotproduct a b)
    (if (null? a) 0
        (+ (* (car a) (car b))
              (dotproduct (cdr a) (cdr b)))))

This defines a method dotproduct which takes arguments a and b, which we assume are lists of equal length. Lists in Scheme are implemented as (nested) pairs. car gets the first element of a pair — so the first element of a list. cdr gets the second element of a pair, hence, all but the first element of a list. So, dotproduct first checks the length of this: if the list is empty (null?), we return 0. Else, we multiply the first elements of the input lists, and add this to the recursive call to dotproduct with the remainders (cdr) of the input lists.

We read input using read-line, which we split on spaces (string-split), and convert the results to numbers using string->number. This gives the following code:

(display (dotproduct (map string->number (string-split (read-line) #\ ))
                     (map string->number (string-split (read-line) #\ ))))
(newline)

Find the full program on GitHub.

Python

Here, we use simple iteration over lists to calculate the wanted result. First, we use list comprehension to read the input, and turn it in into lists of integers:

a = [int (x) for x in input () . split (" ")]
b = [int (x) for x in input () . split (" ")]

Now it's a simple loop:

sum = 0
for i in range (len (a)):
    sum = sum + a [i] * b [i]

print (sum)

Find the full program on GitHub.

R

R actually has an operator to calculate the dot product (%*%). readLines read input, strsplit splits a string, while as.numeric transforms strings into numbers. This gives us the following compact program:

stdin <- file ('stdin', 'r')

cat (as.numeric (strsplit (readLines (stdin, n = 1), " ") [[1]]) %*%
     as.numeric (strsplit (readLines (stdin, n = 1), " ") [[1]]), "\n")

Find the full program on GitHub.

Pascal

In our Pascal solution, we first read all the integers from the input, putting them all in a single array:

var
    n, size, j, half, sum: integer;
    numbers: array of integer;

begin
    size := 0;
    while not eof do begin
        read (n);
        inc (size);
        setlength (numbers, size);
        numbers [size - 1] := n;
    end;

We then calculate the dot product by treating the first half of the array as the first vector, and the second half of the array as the second vector:

    sum := 0;
    half := (size - 1) div 2;
    for j := 0 to half do begin
        sum := sum + numbers [j] * numbers [half + j];
    end;

    writeln (sum);
end.

Find the full program on GitHub.

Other languages

We also have implementations in:

AWK, Bash, bc, C, Go, Java, Lua, Node.js, Ruby, and Tcl


Please leave any comments as a GitHub issue.