Adding matrices

Operations on matrices are not directly supported by the Clojure language but are implemented through the core.matrix specification. Trying to add two matrices in the REPL, as shown in the following code snippet, simply throws an error stating that a vector was found where an integer was expected:

user> (+ (matrix [[0 1]]) (matrix [[0 1]]))
ClassCastException clojure.lang.PersistentVector cannot be cast to java.lang.Number  clojure.lang.Numbers.add (Numbers.java:126)

This is because the + function operates on numbers rather than matrices. To add matrices, we should use functions from the core.matrix.operators namespace. The namespace declaration should look like the following code snippet after we have included core.matrix.operators:

(ns my-namespace
  (:use clojure.core.matrix)
  (:require [clojure.core.matrix.operators :as M]))

Note that the functions are actually imported into an aliased namespace, as function names such as + and * conflict with those in the default Clojure namespace. In practice, we should always try to use aliased namespaces via the :require and :as filters and avoid the :use filter. Alternatively, we could simply not refer to conflicting function names by using the :refer-clojure filter in the namespace declaration, which is shown in the following code. However, this should be used sparingly and only as a last resort.

For the code examples in this section, we will use the previous declaration for clarity:

(ns my-namespace
  (:use clojure.core.matrix)
  (:require clojure.core.matrix.operators)
  (:refer-clojure :exclude [+ - *])) 

We can use the M/+ function to perform the matrix addition of two or more matrices. To check the equality of any number of matrices, we use the M/== function:

user> (def A (matrix [[0 1 2] [3 4 5]]))
#'user/A
user> (def B (matrix [[0 0 0] [0 0 0]]))
#'user/B
user> (M/== B A)
false
user> (def C (M/+ A B))
#'user/C
user> C
[[0 1 2] [3 4 5]]
user> (M/== C A)
true

Two matrices A and B are said to be equal if the following equality holds true:

Adding matrices

Hence, the preceding equation explains that two or more matrices are equal if and only if the following conditions are satisfied:

  • Each matrix has the same number of rows and columns
  • All elements with the same row and column indices are equal

The following is a simple, yet elegant implementation of matrix equality. It's basically comparing vector equality using the standard reduce and map functions:

(defn mat-eq
  "Checks if two matrices are equal"
  [A B]
  (and (= (count A) (count B))
       (reduce #(and %1 %2) (map = A B))))

We first compare the row lengths of the two matrices using the count and = functions, and then use the reduce function to compare the inner vector elements. Essentially, the reduce function repeatedly applies a function that accepts two arguments to consecutive elements in a sequence and returns the final result when all the elements in the sequence have been reduced by the applied function.

Alternatively, we could use a similar composition using the every? and true? Clojure functions. Using the expression (every? true? (map = A B)), we can check the equality of two matrices. Keep in mind that the true? function returns true if it is passed true (and false otherwise), and the every? function returns true if a given predicate function returns true for all the values in a given sequence.

To add two matrices, they must have an equal number of rows and columns, and the sum is essentially a matrix composed of the sum of elements with the same row and column indices. The sum of two matrices A and B has been formally defined as follows:

Adding matrices

It's almost trivial to implement matrix addition using the standard mapv function, which is simply a variant of the map function that returns a vector. We apply mapv to each row of the matrix as well as to the entire matrix. Note that this implementation is intended for a vector of vectors, although it can be easily used with the matrix and as-vec functions from core.matrix to operate on matrices. We can implement the following function to perform matrix addition using the standard mapv function:

(defn mat-add
  "Add two matrices"
  [A B]
  (mapv #(mapv + %1 %2) A B))

We can just as easily generalize the mat-add function for any number of matrices by using the reduce function. As shown in the following code, we can extend the previous definition of mat-add to apply it to any number of matrices using the reduce function:

(defn mat-add
  "Add two or more matrices"
  ([A B]
     (mapv #(mapv + %1 %2) A B))
  ([A B & more]
     (let [M (concat [A B] more)]
       (reduce mat-add M))))

An interesting unary operation on a Adding matrices matrix A is the trace of a matrix, represented as Adding matrices. The trace of a matrix is essentially the sum of its diagonal elements:

Adding matrices

It's fairly simple enough to implement the trace function of a matrix using the cl/map-indexed and repeatedly functions as described earlier. We have skipped it here to serve as an exercise for you.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.82.4