diff --git a/src/matrix/auto.clj b/src/matrix/auto.clj index 6f63917..a9e1782 100644 --- a/src/matrix/auto.clj +++ b/src/matrix/auto.clj @@ -26,3 +26,8 @@ ;; (defn apply-operations-with-steps ;; "Takes a matrix and a list of operations and returns a seq of matrices" ;; ) + +;; (defn gaussian-top-op +;; [m] +;; "Takes a matrix and returns the op required to gaussian-eliminate the top" +;; {:n}) diff --git a/src/matrix/base.clj b/src/matrix/base.clj index 412a2fc..9997056 100644 --- a/src/matrix/base.clj +++ b/src/matrix/base.clj @@ -1,4 +1,5 @@ -(ns matrix.base) +(ns matrix.base + (:require [matrix.spec :as opspec])) (defn to-vec [v] @@ -66,3 +67,25 @@ (def matrix-height "Get the height of a matrix" count) + +(defn apply-row-op + "Apply a spec-compliant row-op to a matrix, curriable" + ([op] + (fn [m] + (apply-row-op op m))) + ([op m] + (if-let [[type inner] (opspec/conform op)] + (case type + :swap (swap-rows + m + (:swap inner) + (:with inner)) + :add (add-rows-with-mul + m + (:times inner) + (:add-row inner) + (:to inner)) + :mul (mul-row + m + (:by inner) + (:mul-row inner)))))) diff --git a/src/matrix/render.clj b/src/matrix/render.clj index 06ae39f..348d854 100644 --- a/src/matrix/render.clj +++ b/src/matrix/render.clj @@ -2,7 +2,8 @@ (ns matrix.render (:require [clojure.string :as str]) - (:require [matrix.base :refer :all])) + (:require [matrix.base :refer :all]) + (:require [matrix.spec :refer :all])) (def default-render-options {:bar? false @@ -152,26 +153,27 @@ (str/join (map shrink-digit (str n)))) (defn pretty-swap [op] - (str "R" (shrink-number (:a op)) + (str "R" (shrink-number (:swap op)) " ↔ " - "R" (shrink-number (:b op)))) + "R" (shrink-number (:with op)))) (defn pretty-mul [op] - (str (:n op) "R" (shrink-number (:row op)))) + (str (:by op) "R" (shrink-number (:mul-row op)))) (defn pretty-add [op] - (let [n (if (= 1 (:n op)) + (let [n (if (= 1 (:times op)) "" - (str (:n op)))] + (str (:times op)))] (str n - "R" (shrink-number (:from op)) + "R" (shrink-number (:add-row op)) " + " "R" (shrink-number (:to op))))) (defn pretty-row-op "Returns a pretty string of a row operation" [op] - (cond - (:swap op) (pretty-swap op) - (:mul op) (pretty-mul op) - (:add op) (pretty-add op))) + (if-let [[op-type inner] (conform op)] + (case op-type + :swap (pretty-swap inner) + :mul (pretty-mul inner) + :add (pretty-add inner)))) diff --git a/src/matrix/spec.clj b/src/matrix/spec.clj new file mode 100644 index 0000000..b50bedc --- /dev/null +++ b/src/matrix/spec.clj @@ -0,0 +1,35 @@ +(ns matrix.spec + (:require [clojure.spec.alpha :as spec])) + +;; (spec/def ::n number?) +;; (spec/def ::a number?) +;; (spec/def ::b number?) +;; (spec/def ::row number?) +;; (spec/def ::from number?) +;; (spec/def ::to number?) + +(spec/def ::swap + (spec/map-of #{:swap :with} number?)) + +(spec/def ::add + (spec/map-of #{:add-row :times :to} number?)) + +(spec/def ::mul + (spec/map-of #{:mul-row :by} number?)) + +(spec/def ::row-op + (spec/or :swap ::swap + :add ::add + :mul ::mul)) + +;; (def bla (spec/conform ::row-op {:mul-by 1 :row 2})) +(defn conform + [op] + (let [conformed (spec/conform ::row-op op)] + (if (spec/invalid? conformed) + nil + conformed))) + +(defn explain + [op] + (spec/explain ::row-op op)) diff --git a/test/matrix/core_test.clj b/test/matrix/core_test.clj index d337a25..bab7d97 100644 --- a/test/matrix/core_test.clj +++ b/test/matrix/core_test.clj @@ -2,6 +2,8 @@ (:require [clojure.test :refer :all] [matrix.base :refer :all])) +; TODO: more tests + (deftest test-mul-row (testing "Multiplying by one remains the same" (let [mat (id-matrix 10)]