Files
paradigms/clojure/linear.clj
2026-04-13 20:12:01 +03:00

93 lines
3.4 KiB
Clojure
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(defn scalar? [x] (number? x))
(defn v? [x]
(and (vector? x) (every? number? x)))
(defn m? [x]
(and (vector? x) (every? v? x)))
(defn- same-length? [& vs]
(apply = (map count vs)))
(defn- same-shape? [& ms]
(apply = (map (fn [m] (mapv count m)) ms)))
(defn- check [cond msg]
(assert cond msg))
(defn- vec-op [op & vs]
(check (every? v? vs) "Все аргументы должны быть векторами чисел")
(check (apply same-length? vs)
(str "Векторы должны быть одинаковой длины, получено: " (mapv count vs)))
(apply mapv op vs))
(def v+ (partial vec-op +))
(def v- (partial vec-op -))
(def v* (partial vec-op *))
(def vd (partial vec-op /))
(defn scalar [& vs]
(reduce + (apply v* vs)))
(defn vect
"Векторное произведение произвольного числа 3-мерных векторов."
[& vs]
(check (every? v? vs) "Все аргументы должны быть векторами")
(check (every? #(= 3 (count %)) vs)
"Векторное произведение определено только для 3-мерных векторов")
(reduce
(fn [a b]
(let [[a0 a1 a2] a
[b0 b1 b2] b]
[(- (* a1 b2) (* a2 b1))
(- (* a2 b0) (* a0 b2))
(- (* a0 b1) (* a1 b0))]))
vs))
(defn v*s [v & scalars]
(check (v? v) "Первый аргумент должен быть вектором")
(check (every? scalar? scalars) "Остальные аргументы должны быть скалярами")
(let [s (reduce * scalars)]
(mapv #(* % s) v)))
(defn- mat-op [op & ms]
(check (every? m? ms) "Все аргументы должны быть матрицами")
(check (apply same-shape? ms)
(str "Матрицы должны иметь одинаковую форму, получено: "
(mapv #(vector (count %) (count (first %))) ms)))
(apply mapv (fn [& rows] (apply vec-op op rows)) ms))
(def m+ (partial mat-op +))
(def m- (partial mat-op -))
(def m* (partial mat-op *))
(def md (partial mat-op /))
(defn m*s [m & scalars]
(check (m? m) "Первый аргумент должен быть матрицей")
(check (every? scalar? scalars) "Остальные аргументы должны быть скалярами")
(let [s (reduce * scalars)]
(mapv (fn [row] (mapv #(* % s) row)) m)))
(defn transpose [m]
(check (m? m) "Аргумент должен быть матрицей")
(apply mapv vector m))
(defn m*v [m v]
(check (m? m) "Первый аргумент должен быть матрицей")
(check (v? v) "Второй аргумент должен быть вектором")
(check (= (count (first m)) (count v))
(str "Число столбцов матрицы (" (count (first m))
") должно совпадать с длиной вектора (" (count v) ")"))
(mapv #(scalar % v) m))
(defn m*m [& ms]
(check (every? m? ms) "Все аргументы должны быть матрицами")
(reduce
(fn [a b]
(check (= (count (first a)) (count b))
(str "Число столбцов левой матрицы (" (count (first a))
") должно совпадать с числом строк правой (" (count b) ")"))
(let [bt (transpose b)]
(mapv (fn [row] (mapv #(scalar row %) bt)) a)))
ms))