Skip to content

Commit

Permalink
At this point I think I've gotten the "idea" behind Strassen's algori…
Browse files Browse the repository at this point in the history
…thm and see furhtering implementation of it to be busy work. I'm moving on.
  • Loading branch information
jColeChanged committed Apr 24, 2011
1 parent 9126f31 commit 11b2b93
Showing 1 changed file with 85 additions and 31 deletions.
116 changes: 85 additions & 31 deletions For Fun Coding/strassen.clj
Expand Up @@ -45,44 +45,70 @@
The product of the two matrices."
[m1 m2]
(let [num-rows (count m1) num-cols (count (first m1))]
(for [y (range num-rows)]
(for [x (range num-cols)]
(C_yx m1 m2 y x num-rows num-cols)))))
(vec (for [y (range num-rows)]
(vec (for [x (range num-cols)]
(C_yx m1 m2 y x num-rows num-cols)))))))

;; I want this to return four vectors.
(defn split
"Returns A split through the middle.
Given a matrix nxm where both n and m are powers of two this
splits the matrix into fourths with a lower bound of n^2. Though
the upper bound on this function has not been calculated, it is
likely to be around n^2 as well.
Am I crazy in thinking that this has O(mlg(n)) running time?
Args:
A: A NxM matrix to split into fourths which has the property that
both n and m are powers of two.
Returns:
The matrix split through the middle into four new matrices such that
[[1 2] [3 4]] becomes [[1] [2] [3] [4]]."
[[1 2] [3 4]] becomes ([1] [2] [3] [4]).
In other words given a matrix it will return:
(Top left, Top right, Bottom left, Bottom right)"
[A]
(let [num-rows (count A)
num-cols (count (A 0))
row-split (/ num-cols 2)
col-split (/ num-rows 2)]
[
(for [y (range col-split)]
(for [x (range row-split)]
((A y) x)))
(for [y (range col-split)]
(for [x (range row-split num-cols)]
((A y) x)))
(for [y (range col-split num-rows)]
(for [x (range row-split)]
((A y) x)))
(for [y (range col-split num-rows)]
(for [x (range row-split num-cols)]
((A y) x)))]))
(let [num-rows (count A) ;; O(1)
num-cols (count (A 0)) ;; count is constant time,
;; but the other is log_32(n)
row-split (/ num-cols 2) ;; O(1) Haven't checked this
col-split (/ num-rows 2)] ;; O(1) Haven't checked this
(list
(vec (for [y (range col-split)] ;; m/2 iterations
(subvec (A y) 0 row-split))) ;; O(1) for subvec but log_32n otherwis
(vec (for [y (range col-split)] ;; m/2 iterations
(subvec (A y) row-split))) ;; same..
(vec (for [y (range col-split num-rows)] ;; and so on and so forth
(subvec (A y) 0 row-split))) ;; giving us 4 * m/2 * O(log_32n)
(vec (for [y (range col-split num-rows)] ;; which is 2m * O(1)
(subvec (A y) row-split))))))

;; So all in all we have 3 * O(1) + log_32(n) + 2m * O(log_32n).
;; This reduces to O(mlogn), but the analysis is ignoring vec and vector calls
;; because I don't know how they are implemeneted. They could \dramatically\
;; effect the analysis. In the worst case the vec calls and vector calls would
;; create entirely new vectors. In the best case they would use Clojure's
;; structure sharing and be fairly performant.


(defn combine
"The inverse of split, accept this accepts the returned list as arguments, not
a list. See split for more details."
[& matrices]
(let [row-split (count (first matrices))
col-split (count ((first matrices) 0))
num-rows (* 2 row-split)
num-cols (* 2 col-split)]
(vec
(for [y (range num-cols)]
(vec
(for [x (range num-rows)]
(cond
(and (< y col-split) (< x row-split))
(((nth matrices 0) y) x)
(and (< y col-split) (>= x row-split))
(((nth matrices 1) y) (- x row-split))
(and (>= y col-split) (< x row-split))
(((nth matrices 2) (- y col-split )) x)
(and (>= y col-split) (>= x row-split))
(((nth matrices 3) (- y col-split)) (- x row-split)))))))))

(defn matrix-addition
"Returns the sume of two matrices A and B.
Expand All @@ -95,9 +121,37 @@
B: A matrix which is NxM.
Returns:
The sume of A and B."
The sum of A and B."
[A B]
(let [num-rows (count A) num-cols (count B)]
(for [y (range num-rows)]
(for [x (range num-cols)]
(+ ((A y) x) ((B y) x))))))
(let [num-rows (count A) num-cols (count B)]
(vec (for [y (range num-rows)]
(vec (for [x (range num-cols)]
(+ ((A y) x) ((B y) x))))))))

(defn strassen-introduction
"Alright. At this point I think I get the ideas behind Strassen's aglorithm."
[m1 m2]
(if (or (>= 2 (count m1)) (>= 2 (count (m1 0))))
(multiply m1 m2)
(let [m1-split (split m1)
A (nth m1-split 0)
B (nth m1-split 1)
C (nth m1-split 2)
D (nth m1-split 3)
m2-split (split m2)
E (nth m2-split 0)
F (nth m2-split 1)
G (nth m2-split 2)
H (nth m2-split 3)]
(combine
(matrix-addition (strassen-introduction A E)
(strassen-introduction B G))
(matrix-addition (strassen-introduction A F)
(strassen-introduction B H))
(matrix-addition (strassen-introduction C E)
(strassen-introduction D G))
(matrix-addition (strassen-introduction C F)
(strassen-introduction D H))))))

;; Strasses algoirthm isn't markedly different from the above, so I'm just going
;; to stop here.

0 comments on commit 11b2b93

Please sign in to comment.