August 13, 2018
4clojure 168 - Infinite Matrix
In what follows, m
, n
, s
, t
denote nonnegative integers, f
denotes a function that accepts two arguments and is defined for all nonnegative integers in both arguments.
In mathematics, the function f
can be interpreted as an infinite matrix with infinitely many rows and columns that, when written, looks like an ordinary matrix but its rows and columns cannot be written down completely, so are terminated with ellipses. In Clojure, such infinite matrix can be represented as an infinite lazy sequence of infinite lazy sequences, where the inner sequences represent rows.
Write a function that accepts 1, 3 and 5 arguments:
- With the argument
f
, it returns the infinite matrixA
that has the entry in thei
-th row and thej
-th column equal tof(i,j)
fori,j = 0,1,2,...
; - With the arguments
f
,m
,n
, it returns the infinite matrixB
that equals the remainder of the matrixA
after the removal of the firstm
rows and the firstn
columns; - With the arguments
f
,m
,n
,s
,t
, it returns the finites
-by-t
matrix that consists of the firstt
entries of each of the firsts
rows of the matrixB
or, equivalently, that consists of the firsts
entries of each of the firstt
columns of the matrixB
.
Special Restrictions: for
, range
, iterate
, repeat
cycle
, drop
(ns live.test
(:require [cljs.test :refer-macros [deftest is run-tests]]))
(defn imatrix
([f] (imatrix f 0 0))
([f r c] (imatrix f r c -1 -1))
([f r c h w]
(letfn [(row [st wd]
(lazy-seq
(when-not (zero? wd)
(cons st (row (inc st) (dec wd))))))]
(map #(map (partial f %) (row c w)) (row r h)))))
(deftest imatrix-test
(is (= (take 5 (map #(take 6 %) (imatrix str)))
[["00" "01" "02" "03" "04" "05"]
["10" "11" "12" "13" "14" "15"]
["20" "21" "22" "23" "24" "25"]
["30" "31" "32" "33" "34" "35"]
["40" "41" "42" "43" "44" "45"]]))
(is (= (take 6 (map #(take 5 %) (imatrix str 3 2)))
[["32" "33" "34" "35" "36"]
["42" "43" "44" "45" "46"]
["52" "53" "54" "55" "56"]
["62" "63" "64" "65" "66"]
["72" "73" "74" "75" "76"]
["82" "83" "84" "85" "86"]]))
(is (= (imatrix * 3 5 5 7)
[[15 18 21 24 27 30 33]
[20 24 28 32 36 40 44]
[25 30 35 40 45 50 55]
[30 36 42 48 54 60 66]
[35 42 49 56 63 70 77]]))
(is (= (imatrix #(/ % (inc %2)) 1 0 6 4)
[[1/1 1/2 1/3 1/4]
[2/1 2/2 2/3 1/2]
[3/1 3/2 3/3 3/4]
[4/1 4/2 4/3 4/4]
[5/1 5/2 5/3 5/4]
[6/1 6/2 6/3 6/4]]))
#_(is (= (class (imatrix (juxt bit-or bit-xor)))
(class (imatrix (juxt quot mod) 13 21))
(class (lazy-seq))))
#_(is (= (class (nth (imatrix (constantly 10946)) 34))
(class (nth (imatrix (constantly 0) 5 8) 55))
(class (lazy-seq))))
(is (= (let [m 377 n 610 w 987
check (fn [f s] (every? true? (map-indexed f s)))
row (take w (nth (imatrix vector) m))
column (take w (map first (imatrix vector m n)))
diagonal (map-indexed #(nth %2 %) (imatrix vector m n w w))]
(and (check #(= %2 [m %]) row)
(check #(= %2 [(+ m %) n]) column)
(check #(= %2 [(+ m %) (+ n %)]) diagonal)))
true)))
(run-tests)