
(defmacro cos-sin (a)
  (with-gensyms (aname)
    `(let ((,aname ,a))
        (list (cos ,aname) (sin ,aname)))))

(defmacro sin-cos (a)
  (with-gensyms (aname)
    `(let ((,aname ,a))
        (list (sin ,aname) (cos ,aname)))))


(defmacro 2d-square-loop ((x y s) &body body)
  (with-gensyms (sname)
    `(let ((,sname ,s))
      (loop for ,x from 0 below ,sname do
        (loop for ,y from 0 below ,sname do
          ,@body)))))


(defun lscale (a s)
  (mapcar (lambda (x) (* x s)) a))

(defun liscale (a s)
  (mapcar (lambda (x) (/ x s)) a))


(defun lsub (a b)
  (mapcar #'- a b))


(defun lisub (a b)
  (mapcar #'- b a))


(defun ladd (a b)
  (mapcar #'+ a b))


(defun lmult (a b)
  (mapcar #'* a b))


(defun ldot (a b)
  (apply #'+ (lmult a b)))


(defun ldiv (a b)
  (mapcar #'/ a b))


(defun lidiv (a b)
  (mapcar #'/ b a))


(defun llenn (a)
  (reduce #'+ (mapcar (lambda (x) (* x x)) a)))


(defun llen (a)
  (sqrt (llenn a)))


(defun ldst (a b)
  (llen (lsub a b)))


(defun lnorm (a)
  (let ((l (llen a)))
    (cond
      ((<= l 0) a)
      (t (lscale a (/ 1.0 l))))))


(defun lnsub (a b)
  (lnorm (lsub a b)))


(defun lnadd (a b)
  (lnorm (ladd a b)))


(defun lmid (a b)
  (lscale (ladd a b) 0.5))


(defun lsum (a)
  (reduce #'+ a))


(defun lround (l)
  (mapcar #'round l))


(defun lget (ii a)
  (loop for i in ii
    collect (nth i a)))


(defun l-rand-get (l)
  (nth (random (list-length l)) l))


(defun leql (a b)
  (mapcar #'eql a b))


(defun lgeq (a b)
  (mapcar #'>= a b))


(defun lleq (a b)
  (mapcar #'<= a b))


(defun range (n)
  (loop for x from 0 to (1- n)
    collect x))


(defun linspace (a b n)
  (loop for i from 0 to (1- n)
    collect (+ a (* i (/ (- b a) (1- n))))))


(defun lget (ii a)
  (loop for i in ii
    collect (nth i a)))


; TODO: add dim option
(defun l-get-as-list (arr row)
  (mapcar
    (lambda (d) (aref arr row d))
    (list 0 1)))


(defun l-set-from-list (arr row vals)
  (mapcar
    (lambda (d v) (setf (aref arr row d) v))
    (list 0 1)
    vals))

