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
|
||||
(:require [clojure.string :as str])
|
||||
(:require [matrix.base :refer :all])
|
||||
(:require [matrix.interactive :refer :all])
|
||||
(: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
|
||||
"I don't do a whole lot ... yet."
|
||||
[& args]
|
||||
|
@ -229,6 +17,7 @@
|
|||
; TODO: parse equations (easy, but requires context (e.g. x = 1 could be any number of variables))
|
||||
; TODO: undoing
|
||||
; 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 gaussian-eliminated matrix
|
||||
; 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