refactor into modules
This commit is contained in:
parent
aaf9d826c6
commit
376ae6035e
4 changed files with 223 additions and 214 deletions
68
src/matrix/base.clj
Normal file
68
src/matrix/base.clj
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
(ns matrix.base)
|
||||||
|
|
||||||
|
(defn to-vec
|
||||||
|
[v]
|
||||||
|
(apply vector v))
|
||||||
|
|
||||||
|
(defn swap-rows
|
||||||
|
"Swap rows n and m of the given matrix, 0-indexed"
|
||||||
|
[matrix n m]
|
||||||
|
(assoc matrix
|
||||||
|
m (matrix n)
|
||||||
|
n (matrix m)))
|
||||||
|
|
||||||
|
(defn add-rows-with-mul
|
||||||
|
"n * row from + row to"
|
||||||
|
[matrix n from to]
|
||||||
|
(let [from-row (get matrix from)
|
||||||
|
to-row (get matrix to)
|
||||||
|
new-row (-> (map (fn [f t] (+ (* n f) t))
|
||||||
|
from-row to-row)
|
||||||
|
to-vec)]
|
||||||
|
(assoc matrix
|
||||||
|
to new-row)))
|
||||||
|
|
||||||
|
(defn add-rows
|
||||||
|
"row from + row to"
|
||||||
|
[matrix from to]
|
||||||
|
(add-rows-with-mul matrix 1 from to))
|
||||||
|
|
||||||
|
(defn mul-row
|
||||||
|
"n * row"
|
||||||
|
[matrix n row]
|
||||||
|
(update matrix
|
||||||
|
row #(to-vec (map (partial * n) %))))
|
||||||
|
|
||||||
|
(defn row-with-fill
|
||||||
|
"Creates a vector row with the given width and a specified fill (default 0)"
|
||||||
|
([width] (row-with-fill width 0))
|
||||||
|
([width fill]
|
||||||
|
(apply vector
|
||||||
|
(map (constantly fill)
|
||||||
|
(range 0 width)))))
|
||||||
|
|
||||||
|
(defn empty-matrix
|
||||||
|
"Creates a height x width matrix with the given default value (default 0)"
|
||||||
|
([height width] (empty-matrix height width 0))
|
||||||
|
([height width fill]
|
||||||
|
(let [row (row-with-fill width fill)]
|
||||||
|
(->> (range 0 height)
|
||||||
|
(map (constantly row))
|
||||||
|
(apply vector)))))
|
||||||
|
|
||||||
|
(defn id-matrix
|
||||||
|
"Creates the id matrix of the given width"
|
||||||
|
[width]
|
||||||
|
(let [base (empty-matrix width width 0)]
|
||||||
|
(->> base
|
||||||
|
(map (fn [i row] (assoc row i 1))
|
||||||
|
(range 0 width))
|
||||||
|
(apply vector))))
|
||||||
|
|
||||||
|
(def matrix-width
|
||||||
|
"Get the width of a matrix (assumes that all rows are the same size, as they should be!)"
|
||||||
|
(comp count first))
|
||||||
|
|
||||||
|
(def matrix-height
|
||||||
|
"Get the height of a matrix"
|
||||||
|
count)
|
|
@ -1,220 +1,8 @@
|
||||||
(ns matrix.core
|
(ns matrix.core
|
||||||
(:require [clojure.string :as str])
|
(:require [matrix.base :refer :all])
|
||||||
|
(:require [matrix.interactive :refer :all])
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
(defn to-vec
|
|
||||||
[v]
|
|
||||||
(apply vector v))
|
|
||||||
|
|
||||||
(defn swap-rows
|
|
||||||
"Swap rows n and m of the given matrix, 0-indexed"
|
|
||||||
[matrix n m]
|
|
||||||
(assoc matrix
|
|
||||||
m (matrix n)
|
|
||||||
n (matrix m)))
|
|
||||||
|
|
||||||
(defn add-rows-with-mul
|
|
||||||
"n * row from + row to"
|
|
||||||
[matrix n from to]
|
|
||||||
(let [from-row (get matrix from)
|
|
||||||
to-row (get matrix to)
|
|
||||||
new-row (-> (map (fn [f t] (+ (* n f) t))
|
|
||||||
from-row to-row)
|
|
||||||
to-vec)]
|
|
||||||
(assoc matrix
|
|
||||||
to new-row)))
|
|
||||||
|
|
||||||
(defn add-rows
|
|
||||||
"row from + row to"
|
|
||||||
[matrix from to]
|
|
||||||
(add-rows-with-mul matrix 1 from to))
|
|
||||||
|
|
||||||
(defn mul-row
|
|
||||||
"n * row"
|
|
||||||
[matrix n row]
|
|
||||||
(update matrix
|
|
||||||
row #(to-vec (map (partial * n) %))))
|
|
||||||
|
|
||||||
(defn row-with-fill
|
|
||||||
"Creates a vector row with the given width and a specified fill (default 0)"
|
|
||||||
([width] (row-with-fill width 0))
|
|
||||||
([width fill]
|
|
||||||
(apply vector
|
|
||||||
(map (constantly fill)
|
|
||||||
(range 0 width)))))
|
|
||||||
|
|
||||||
(defn empty-matrix
|
|
||||||
"Creates a height x width matrix with the given default value (default 0)"
|
|
||||||
([height width] (empty-matrix height width 0))
|
|
||||||
([height width fill]
|
|
||||||
(let [row (row-with-fill width fill)]
|
|
||||||
(->> (range 0 height)
|
|
||||||
(map (constantly row))
|
|
||||||
(apply vector)))))
|
|
||||||
|
|
||||||
(defn id-matrix
|
|
||||||
"Creates the id matrix of the given width"
|
|
||||||
[width]
|
|
||||||
(let [base (empty-matrix width width 0)]
|
|
||||||
(->> base
|
|
||||||
(map (fn [i row] (assoc row i 1))
|
|
||||||
(range 0 width))
|
|
||||||
(apply vector))))
|
|
||||||
|
|
||||||
(def matrix-width
|
|
||||||
"Get the width of a matrix (assumes that all rows are the same size, as they should be!)"
|
|
||||||
(comp count first))
|
|
||||||
|
|
||||||
(def matrix-height
|
|
||||||
"Get the height of a matrix"
|
|
||||||
count)
|
|
||||||
|
|
||||||
(defn surround-with
|
|
||||||
"Surround a string with the given left and right"
|
|
||||||
([left right] #(surround-with left right %))
|
|
||||||
([left right s] (str left s right)))
|
|
||||||
|
|
||||||
(defn add-before-last
|
|
||||||
[what where]
|
|
||||||
(concat (take (dec (count where)) where)
|
|
||||||
[what]
|
|
||||||
[(last where)]))
|
|
||||||
|
|
||||||
(defn draw-row
|
|
||||||
"Takes a seq of strs and a max length and draws a row.
|
|
||||||
Optionally takes a left and right to surround with"
|
|
||||||
([seq max-len add-bar]
|
|
||||||
(let [fmt-str (str "%" max-len "s")]
|
|
||||||
(->> seq
|
|
||||||
(map (partial format fmt-str))
|
|
||||||
((if add-bar
|
|
||||||
(partial add-before-last "│")
|
|
||||||
identity))
|
|
||||||
(str/join " "))))
|
|
||||||
([seq max-len add-bar left right]
|
|
||||||
((surround-with left right) (draw-row seq max-len add-bar))))
|
|
||||||
|
|
||||||
(defn max-str-len
|
|
||||||
"Returns the maximum length of a stringified seq"
|
|
||||||
[seq]
|
|
||||||
(->> seq
|
|
||||||
(map str)
|
|
||||||
(map count)
|
|
||||||
(apply max 0)))
|
|
||||||
|
|
||||||
(defn max-str-len-matrix
|
|
||||||
"Returns the maximum length of the stringified elements of the matrix"
|
|
||||||
[m]
|
|
||||||
(apply max (map max-str-len m)))
|
|
||||||
|
|
||||||
; could do latex, but what's the point
|
|
||||||
(defn pretty-matrix-rows
|
|
||||||
"Make a list of fancy display strings of the rows given matrix"
|
|
||||||
([m] (pretty-matrix-rows m false))
|
|
||||||
([m add-bar]
|
|
||||||
(let [max-len (max-str-len-matrix m)
|
|
||||||
width (matrix-width m)
|
|
||||||
row-len (+ (- width 1) (* max-len width))
|
|
||||||
middle (map #(draw-row % max-len add-bar "┃ " " ┃") m)
|
|
||||||
space (apply str (repeat (+ (if add-bar 2 0) row-len) " "))]
|
|
||||||
(concat [(str "┏ " space " ┓")]
|
|
||||||
middle
|
|
||||||
[(str "┗ " space " ┛")]))))
|
|
||||||
|
|
||||||
(defn pretty-matrix
|
|
||||||
"Make a fancy display string from the given matrix"
|
|
||||||
([m] (pretty-matrix m false))
|
|
||||||
([m add-bar]
|
|
||||||
(str/join "\n" (pretty-matrix-rows m add-bar))))
|
|
||||||
|
|
||||||
(defn pprint-matrix
|
|
||||||
"Pretty print the given matrix"
|
|
||||||
([m] (pprint-matrix m false))
|
|
||||||
([m add-bar]
|
|
||||||
((comp println #(pretty-matrix % add-bar)) m)
|
|
||||||
m))
|
|
||||||
|
|
||||||
;; repl commands
|
|
||||||
(defn fmt-num
|
|
||||||
"Format a number, empty string for 1"
|
|
||||||
[n]
|
|
||||||
(if (= 1 n)
|
|
||||||
""
|
|
||||||
(str n)))
|
|
||||||
|
|
||||||
(defn mid-sign
|
|
||||||
"Format a term as either '+ n' or '- n'"
|
|
||||||
[n]
|
|
||||||
(if (pos? n)
|
|
||||||
(str "+ " (fmt-num n))
|
|
||||||
(str "- " (fmt-num (* -1 n)))))
|
|
||||||
|
|
||||||
(defn single-term
|
|
||||||
[val name first]
|
|
||||||
(if (zero? val)
|
|
||||||
""
|
|
||||||
(str (if first
|
|
||||||
(fmt-num val)
|
|
||||||
(mid-sign val))
|
|
||||||
name)))
|
|
||||||
|
|
||||||
; could be generalized
|
|
||||||
(defn equation-from-row
|
|
||||||
"Write a pretty equation from one row of an augmented matrix"
|
|
||||||
([row] (apply equation-from-row row))
|
|
||||||
([x eq] (str (single-term x "x" true)
|
|
||||||
" = "
|
|
||||||
eq))
|
|
||||||
([x y eq]
|
|
||||||
(let [x (single-term x "x" true)
|
|
||||||
y (single-term y "y" (empty? x))]
|
|
||||||
(str x
|
|
||||||
(if (not-empty x) " ")
|
|
||||||
y
|
|
||||||
(if (not-empty y) " ")
|
|
||||||
"= " eq)))
|
|
||||||
([x y z eq]
|
|
||||||
(let [x (single-term x "x" true)
|
|
||||||
y (single-term y "y" (empty? x))
|
|
||||||
z (single-term z "z" (and (empty? x) (empty? y)))]
|
|
||||||
(str x
|
|
||||||
(if (not-empty x) " ")
|
|
||||||
y
|
|
||||||
(if (not-empty y) " ")
|
|
||||||
z
|
|
||||||
(if (not-empty z) " ")
|
|
||||||
"= " eq))))
|
|
||||||
|
|
||||||
(defn print-matrix-equations
|
|
||||||
[m]
|
|
||||||
(do
|
|
||||||
(last (for [row m]
|
|
||||||
(println (equation-from-row row))))
|
|
||||||
m))
|
|
||||||
|
|
||||||
(defn swap [n m] #(swap-rows % n m))
|
|
||||||
(defn add [from to] #(add-rows % from to))
|
|
||||||
(defn add-mul [n from to] #(add-rows-with-mul % n from to))
|
|
||||||
(defn mul [n at] #(mul-row % n at))
|
|
||||||
(def print-equations print-matrix-equations)
|
|
||||||
|
|
||||||
(defn apply-input
|
|
||||||
[m]
|
|
||||||
(let [got (read)]
|
|
||||||
(case got
|
|
||||||
[:q
|
|
||||||
:wq
|
|
||||||
:exit
|
|
||||||
:x
|
|
||||||
:done] m
|
|
||||||
((eval got) m))))
|
|
||||||
|
|
||||||
(defn matrix-repl
|
|
||||||
([m] (matrix-repl m false))
|
|
||||||
([m add-bar]
|
|
||||||
(pprint-matrix m add-bar)
|
|
||||||
(iterate (comp #(pprint-matrix % add-bar) apply-input) m)))
|
|
||||||
|
|
||||||
(defn -main
|
(defn -main
|
||||||
"I don't do a whole lot ... yet."
|
"I don't do a whole lot ... yet."
|
||||||
[& args]
|
[& args]
|
||||||
|
@ -229,6 +17,7 @@
|
||||||
; TODO: parse equations (easy, but requires context (e.g. x = 1 could be any number of variables))
|
; TODO: parse equations (easy, but requires context (e.g. x = 1 could be any number of variables))
|
||||||
; TODO: undoing
|
; TODO: undoing
|
||||||
; will have to have a higher level thing for storing state
|
; will have to have a higher level thing for storing state
|
||||||
|
; use a set for options on the higher-level thing #{:show-equations? :show-bar? :color?}
|
||||||
; TODO: solving id-matrix
|
; TODO: solving id-matrix
|
||||||
; TODO: solving gaussian-eliminated matrix
|
; TODO: solving gaussian-eliminated matrix
|
||||||
; TODO: automation
|
; TODO: automation
|
||||||
|
|
33
src/matrix/interactive.clj
Normal file
33
src/matrix/interactive.clj
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
(ns matrix.interactive
|
||||||
|
(:require [matrix.base :refer :all])
|
||||||
|
(:require [matrix.render :refer :all]))
|
||||||
|
|
||||||
|
(defn print-matrix-equations
|
||||||
|
[m]
|
||||||
|
(do
|
||||||
|
(last (for [row m]
|
||||||
|
(println (equation-from-row row))))
|
||||||
|
m))
|
||||||
|
|
||||||
|
(defn swap [n m] #(swap-rows % n m))
|
||||||
|
(defn add [from to] #(add-rows % from to))
|
||||||
|
(defn add-mul [n from to] #(add-rows-with-mul % n from to))
|
||||||
|
(defn mul [n at] #(mul-row % n at))
|
||||||
|
(def print-equations print-matrix-equations)
|
||||||
|
|
||||||
|
(defn apply-input
|
||||||
|
[m]
|
||||||
|
(let [got (read)]
|
||||||
|
(case got
|
||||||
|
[:q
|
||||||
|
:wq
|
||||||
|
:exit
|
||||||
|
:x
|
||||||
|
:done] m
|
||||||
|
((eval got) m))))
|
||||||
|
|
||||||
|
(defn matrix-repl
|
||||||
|
([m] (matrix-repl m false))
|
||||||
|
([m add-bar]
|
||||||
|
(pprint-matrix m add-bar)
|
||||||
|
(iterate (comp #(pprint-matrix % add-bar) apply-input) m)))
|
119
src/matrix/render.clj
Normal file
119
src/matrix/render.clj
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
(ns matrix.render
|
||||||
|
(:require [clojure.string :as str])
|
||||||
|
(:require [matrix.base :refer :all]))
|
||||||
|
|
||||||
|
(defn surround-with
|
||||||
|
"Surround a string with the given left and right"
|
||||||
|
([left right] #(surround-with left right %))
|
||||||
|
([left right s] (str left s right)))
|
||||||
|
|
||||||
|
(defn add-before-last
|
||||||
|
[what where]
|
||||||
|
(concat (take (dec (count where)) where)
|
||||||
|
[what]
|
||||||
|
[(last where)]))
|
||||||
|
|
||||||
|
(defn draw-row
|
||||||
|
"Takes a seq of strs and a max length and draws a row.
|
||||||
|
Optionally takes a left and right to surround with"
|
||||||
|
([seq max-len add-bar]
|
||||||
|
(let [fmt-str (str "%" max-len "s")]
|
||||||
|
(->> seq
|
||||||
|
(map (partial format fmt-str))
|
||||||
|
((if add-bar
|
||||||
|
(partial add-before-last "│")
|
||||||
|
identity))
|
||||||
|
(str/join " "))))
|
||||||
|
([seq max-len add-bar left right]
|
||||||
|
((surround-with left right) (draw-row seq max-len add-bar))))
|
||||||
|
|
||||||
|
(defn max-str-len
|
||||||
|
"Returns the maximum length of a stringified seq"
|
||||||
|
[seq]
|
||||||
|
(->> seq
|
||||||
|
(map str)
|
||||||
|
(map count)
|
||||||
|
(apply max 0)))
|
||||||
|
|
||||||
|
(defn max-str-len-matrix
|
||||||
|
"Returns the maximum length of the stringified elements of the matrix"
|
||||||
|
[m]
|
||||||
|
(apply max (map max-str-len m)))
|
||||||
|
|
||||||
|
; could do latex, but what's the point
|
||||||
|
(defn pretty-matrix-rows
|
||||||
|
"Make a list of fancy display strings of the rows given matrix"
|
||||||
|
([m] (pretty-matrix-rows m false))
|
||||||
|
([m add-bar]
|
||||||
|
(let [max-len (max-str-len-matrix m)
|
||||||
|
width (matrix-width m)
|
||||||
|
row-len (+ (- width 1) (* max-len width))
|
||||||
|
middle (map #(draw-row % max-len add-bar "┃ " " ┃") m)
|
||||||
|
space (apply str (repeat (+ (if add-bar 2 0) row-len) " "))]
|
||||||
|
(concat [(str "┏ " space " ┓")]
|
||||||
|
middle
|
||||||
|
[(str "┗ " space " ┛")]))))
|
||||||
|
|
||||||
|
(defn pretty-matrix
|
||||||
|
"Make a fancy display string from the given matrix"
|
||||||
|
([m] (pretty-matrix m false))
|
||||||
|
([m add-bar]
|
||||||
|
(str/join "\n" (pretty-matrix-rows m add-bar))))
|
||||||
|
|
||||||
|
(defn pprint-matrix
|
||||||
|
"Pretty print the given matrix"
|
||||||
|
([m] (pprint-matrix m false))
|
||||||
|
([m add-bar]
|
||||||
|
((comp println #(pretty-matrix % add-bar)) m)
|
||||||
|
m))
|
||||||
|
|
||||||
|
;; repl commands
|
||||||
|
(defn fmt-num
|
||||||
|
"Format a number, empty string for 1"
|
||||||
|
[n]
|
||||||
|
(if (= 1 n)
|
||||||
|
""
|
||||||
|
(str n)))
|
||||||
|
|
||||||
|
(defn mid-sign
|
||||||
|
"Format a term as either '+ n' or '- n'"
|
||||||
|
[n]
|
||||||
|
(if (pos? n)
|
||||||
|
(str "+ " (fmt-num n))
|
||||||
|
(str "- " (fmt-num (* -1 n)))))
|
||||||
|
|
||||||
|
(defn single-term
|
||||||
|
[val name first]
|
||||||
|
(if (zero? val)
|
||||||
|
""
|
||||||
|
(str (if first
|
||||||
|
(fmt-num val)
|
||||||
|
(mid-sign val))
|
||||||
|
name)))
|
||||||
|
|
||||||
|
; could be generalized
|
||||||
|
(defn equation-from-row
|
||||||
|
"Write a pretty equation from one row of an augmented matrix"
|
||||||
|
([row] (apply equation-from-row row))
|
||||||
|
([x eq] (str (single-term x "x" true)
|
||||||
|
" = "
|
||||||
|
eq))
|
||||||
|
([x y eq]
|
||||||
|
(let [x (single-term x "x" true)
|
||||||
|
y (single-term y "y" (empty? x))]
|
||||||
|
(str x
|
||||||
|
(if (not-empty x) " ")
|
||||||
|
y
|
||||||
|
(if (not-empty y) " ")
|
||||||
|
"= " eq)))
|
||||||
|
([x y z eq]
|
||||||
|
(let [x (single-term x "x" true)
|
||||||
|
y (single-term y "y" (empty? x))
|
||||||
|
z (single-term z "z" (and (empty? x) (empty? y)))]
|
||||||
|
(str x
|
||||||
|
(if (not-empty x) " ")
|
||||||
|
y
|
||||||
|
(if (not-empty y) " ")
|
||||||
|
z
|
||||||
|
(if (not-empty z) " ")
|
||||||
|
"= " eq))))
|
Loading…
Reference in a new issue