7c256c69e753691a0d52e77706fb4bcb64b81436
[lineal.git] / src / overload / concatenate.lisp
blob7c256c69e753691a0d52e77706fb4bcb64b81436
2 (in-package :lineal.overload)
4 (defun over-cat (&rest args)
5 (if args
6 (if (cdr args)
7 (reduce #'cat2 args :from-end t)
8 (car args))
9 (throw 'over-ex "Can't cat nothing.")))
11 (defun over-vcat (&rest args)
12 (if args
13 (if (cdr args)
14 (reduce #'vcat2 args :from-end t)
15 (car args))
16 (throw 'over-ex "Can't vcat nothing.")))
18 (defmethod cat2 ((u list) v)
19 (cat2 (tuple-list u) v))
21 (defmethod cat2 (u (v list))
22 (cat2 u (tuple-list v)))
24 (defmethod vcat2 ((u list) v)
25 (vcat2 (tuple-list u) v))
27 (defmethod vcat2 (u (v list))
28 (vcat2 u (tuple-list v)))
30 ;V The do* macro with tails.V
31 (defmacro tails-do*
32 (((&body tails-args) . do-args)
33 (s-pred . s-cleanup) . s-proc)
34 (let ((begin-loop-tag (gensym))
35 (end-loop-tag (gensym))
36 pre-inits post-inits
37 do-setqs tail-setqs
38 s-conditail-setqs
39 s-declarations
40 var-init-p)
41 (loop
42 :for (v a ta condit) :in tails-args
43 ;V See if /v/ has an initial value.V
44 :for init-v = (when (consp v)
45 (setq var-init-p t)
46 (prog1 (cadr v)
47 (setq v (car v))))
48 ;V Find if the tail should be V
49 ;V initialized as something. V
50 :for tadef =
51 (if ta
52 (if (consp ta)
53 (cadr (shiftf ta (car ta)))
54 (if a nil ta))
55 ;V No tail mentioned by user, set /ta/ V
56 ;V as a symbol name and return nil. V
57 (shiftf ta (gensym)))
58 ;> /ta/ is now strictly the variable name referring to the
59 ;> accum-list's tail. There is always a tail at this point.
60 ;V Find what the accum-list is initialized with V
61 ;V and what its part of the /post-inits/ looks like.V
62 :for (adef a-init-part) =
63 (if (listp a)
64 (list (when a (cadr (shiftf a (car a))))
65 ;^ If /a/ is a cons, set it to its symbol ^
66 ;^ name and return its initialization form.^
67 (if tadef `(list ,v)
68 `(if ,a (cdr (rplacd (last ,a) (cons ,v nil)))
69 (setq ,a (list ,v)))))
70 ;V The accum-list does not have an init value, V
71 ;V but will be initialized in the beginning let.V
72 `(nil (setq ,a (cons ,v nil))))
73 ;> /a/ is now strictly the variable name referring to the
74 ;> accum-list or nil if the list exists before this macro.
75 :for default-val-setq =
76 (when condit
77 (if (consp condit)
78 (when (cdr condit)
79 (cons v (cdr condit)))
80 (list v nil)))
81 ;V Collect variables and initializations V
82 ;V to be used in the outer let form. V
83 :collect (if init-v (list v init-v) v) :into vlist
84 :when a
85 :collect (if adef (list a adef) a) :into vlist
86 :collect (if tadef (list ta tadef) ta) :into vlist
87 ;V The stuff for /post-inits/.V
88 :nconc
89 `(,ta ,(if tadef `(cdr (rplacd ,ta ,a-init-part))
90 a-init-part))
91 :into ilist
92 :if condit
93 :nconc default-val-setq :into ilist
94 :and :collect
95 `(if ,(if (consp condit) (car condit) v)
96 (setq ,ta (cdr (rplacd ,ta (cons ,v nil)))
97 ,@default-val-setq))
98 :into condlist
99 :else :nconc
100 `(,ta (cdr (rplacd ,ta (cons ,v nil))))
101 :into qlist
102 :finally (setq pre-inits vlist
103 post-inits ilist
104 s-conditail-setqs condlist
105 tail-setqs qlist))
106 ;V Handle regular do arguments.V
107 (loop :for (v i a) :in do-args
108 :collect (if i (list v i) v) :into vlist
109 :when a :collect v :into alist
110 :and :collect a :into alist
111 :finally (nconc pre-inits vlist)
112 (setq do-setqs alist))
113 (loop :while (and (consp (car s-proc))
114 (eq 'declare (caar s-proc)))
115 :collect (pop s-proc) :into decl
116 :finally (setq s-declarations decl))
117 `(let* (,@pre-inits);< All variable initializations.
118 ,@s-declarations
119 (unless ,s-pred
120 ;V Run loop contents here only if the first V
121 ;V value to accumulate is not specified. V
122 ,@(unless var-init-p s-proc)
123 ;V Give all tails a value if they don't have one, V
124 (setq ,@post-inits);< update some nil lists too.
125 (tagbody
126 ,begin-loop-tag
127 (setq ,@do-setqs);< Normal do-loop updates.
128 (if ,s-pred (go ,end-loop-tag))
129 ,@s-proc;< Run inner loop.
130 ,@s-conditail-setqs;< Conditional tail updates.
131 (setq ,@tail-setqs);< Update all tails.
132 (go ,begin-loop-tag)
133 ,end-loop-tag))
134 ;V Loop is over, run user's cleanup forms.V
135 ,@s-cleanup)))
137 (defmacro cat2-fill
138 (((arow s-arows)
139 (brow s-brows)
140 rows)
141 s-cat
142 (width
143 (s-awidth s-azeros)
144 (s-bwidth s-bzeros))
145 s-return)
146 (let ((row (gensym))
147 (tail (gensym))
148 (arem (gensym)) (brem (gensym))
149 (finished (gensym)))
150 `(tails-do*
151 (((,row ,rows ,tail))
152 (,arem ,s-arows (cdr ,arem))
153 (,brem ,s-brows (cdr ,brem))
154 (,finished nil (not (and ,arem ,brem))))
155 (,finished
156 (rplacd
157 ,tail
158 (if ,arem
159 (let* (,@(when s-bwidth `((,width ,s-bwidth)))
160 (,brow ,s-bzeros))
161 (mapcar #'(lambda (,arow) ,s-cat) ,arem))
162 (when ,brem
163 (let* (,@(when s-awidth `((,width ,s-awidth)))
164 (,arow ,s-azeros))
165 (mapcar #'(lambda (,brow) ,s-cat) ,brem)))))
166 ,s-return)
167 (let ((,arow (car ,arem))
168 (,brow (car ,brem)))
169 (setq ,row ,s-cat)))))
172 (defmethod cat2 ((a number) (b number))
173 (make-mtrix :dimdom 2 :dimcodom 1
174 :elems (list (list a b))))
176 (defmethod vcat2 ((a number) (b number))
177 (make-tuple :dim 2 :elems (list a b)))
179 (defmethod cat2 ((k number) (u tuple))
180 (make-mtrix :dimdom 2 :dimcodom (tuple-dim u)
181 :elems (mapcar #'(lambda (x) (list k x))
182 (tuple-elems u))))
184 (defmethod cat2 ((u tuple) (k number))
185 (make-mtrix :dimdom 2 :dimcodom (tuple-dim u)
186 :elems (mapcar #'(lambda (x) (list x k))
187 (tuple-elems u))))
189 (defmethod vcat2 ((k number) (u tuple))
190 (make-tuple :dim (1+ (tuple-dim u))
191 :elems (cons k (tuple-elems u))))
193 (defmethod vcat2 ((u tuple) (k number))
194 (make-tuple :dim (1+ (tuple-dim u))
195 :elems `(,@(tuple-elems u) ,k)))
197 ;V Align two tuples into a column matrix.V
198 (defmethod cat2 ((u tuple) (v tuple))
199 (cat2-fill
200 ((uelem (tuple-elems u))
201 (velem (tuple-elems v))
202 rows)
203 (list uelem velem)
204 (nil (nil 0) (nil 0))
205 (make-mtrix :dimdom 2
206 :dimcodom (max (tuple-dim u)
207 (tuple-dim v))
208 :elems rows)))
210 ;V Merge two tuples together into one long vector.V
211 (defmethod vcat2 ((u tuple) (v tuple))
212 (make-tuple :dim (+ (tuple-dim u) (tuple-dim v))
213 :elems (append (tuple-elems u)
214 (tuple-elems v))))
216 ;V Add a column vector /u/ to V
217 ;V the left side of matrix /a/.V
218 (defmethod cat2 ((u tuple) (a mtrix))
219 (cat2-fill
220 ((uelem (tuple-elems u))
221 (arow (mtrix-elems a))
222 rows)
223 (cons uelem arow)
224 (width
225 (nil 0)
226 ((mtrix-dimdom a)
227 (make-list width :initial-element 0)))
228 (make-mtrix :dimdom (1+ (mtrix-dimdom a))
229 :dimcodom (max (tuple-dim u)
230 (mtrix-dimcodom a))
231 :elems rows)))
233 (defmethod cat2 ((a mtrix) (u tuple))
234 (cat2-fill
235 ((arow (mtrix-elems a))
236 (uelem (tuple-elems u))
237 rows)
238 `(,@arow ,uelem)
239 (width
240 ((mtrix-dimdom a)
241 (make-list width :initial-element 0))
242 (nil 0))
243 (make-mtrix :dimdom (1+ (mtrix-dimdom a))
244 :dimcodom (mtrix-dimcodom a)
245 :elems rows)))
247 (defmethod cat2 ((a mtrix) (b mtrix))
248 (cat2-fill
249 ((arow (mtrix-elems a))
250 (brow (mtrix-elems b))
251 rows)
252 (append arow brow)
253 (width
254 ((mtrix-dimdom a)
255 (make-list width :initial-element 0))
256 ((mtrix-dimdom b)
257 (make-list width :initial-element 0)))
258 (make-mtrix :dimdom (+ (mtrix-dimdom a)
259 (mtrix-dimdom b))
260 :dimcodom (max (mtrix-dimcodom a)
261 (mtrix-dimcodom b))
262 :elems rows)))
264 (defmethod vcat2 ((u tuple) (a mtrix))
265 (let ((uwid (tuple-dim u))
266 (awid (mtrix-dimdom a))
267 (rows (cons (tuple-elems u)
268 (mtrix-elems a))))
269 (if (< uwid awid)
270 (rplaca rows
271 (append
272 (car rows)
273 (make-list (- awid uwid)
274 :initial-element 0)))
275 (unless (= uwid awid)
276 (shiftf awid uwid (- uwid awid))
277 (rplacd
278 rows
279 (mapcar
280 #'(lambda (row)
281 (append
283 (make-list uwid :initial-element 0)))
284 (cdr rows)))))
285 (make-mtrix :dimdom awid
286 :dimcodom (1+ (mtrix-dimcodom a))
287 :elems rows)))
289 (defmethod vcat2 ((a mtrix) (u tuple))
290 (let ((awid (mtrix-dimdom a))
291 (uwid (tuple-dim u)))
292 (make-mtrix
293 :dimcodom (1+ (mtrix-dimcodom a))
294 :elems
295 (if (< uwid awid)
296 `(,@(mtrix-elems a)
297 ,(append (tuple-elems u)
298 (make-list (- awid uwid)
299 :initial-element 0)))
300 (if (= uwid awid)
301 `(,@(mtrix-elems a) ,(tuple-elems u))
302 (progn
303 (shiftf awid uwid (- uwid awid))
304 (tails-do*
305 (((row rows tail))
306 (arem (mtrix-elems a) (cdr arem)))
307 ((not arem)
308 (rplacd tail (cons (tuple-elems u) nil))
309 rows)
310 (setq row
311 (append
312 (car arem)
313 (make-list
314 uwid :initial-element 0)))))))
315 :dimdom awid)))
317 ;V Join a column of /k/'s onto the left of /a/.V
318 (defmethod cat2 ((k number) (a mtrix))
319 (make-mtrix
320 :dimdom (1+ (mtrix-dimdom a))
321 :dimcodom (mtrix-dimcodom a)
322 :elems (mapcar #'(lambda (row) (cons k row))
323 (mtrix-elems a))))
325 ;V Join a column of /k/'s onto the right of /a/.V
326 (defmethod cat2 ((a mtrix) (k number))
327 (make-mtrix
328 :dimdom (1+ (mtrix-dimdom a))
329 :dimcodom (mtrix-dimcodom a)
330 :elems (mapcar #'(lambda (row) `(,@row ,k))
331 (mtrix-elems a))))
333 ;V Join a row of /k/'s onto the top of /a/.V
334 (defmethod vcat2 ((k number) (a mtrix))
335 (make-mtrix
336 :dimdom (mtrix-dimdom a)
337 :dimcodom (1+ (mtrix-dimcodom a))
338 :elems (cons (make-list (mtrix-dimdom a)
339 :initial-element k)
340 (mtrix-elems a))))
342 ;V Join a row of /k/'s onto the bottom of /a/.V
343 (defmethod vcat2 ((a mtrix) (k number))
344 (make-mtrix
345 :dimdom (mtrix-dimdom a)
346 :dimcodom (1+ (mtrix-dimcodom a))
347 :elems `(,@(mtrix-elems a)
348 ,(make-list (mtrix-dimdom a)
349 :initial-element k))))
351 (defmethod vcat2 ((a mtrix) (b mtrix))
352 (let* ((awid (mtrix-dimdom a))
353 (bwid (mtrix-dimdom b))
354 (finwid (max awid bwid))
355 (zeros (make-list (abs (- awid bwid))
356 :initial-element 0)))
357 (make-mtrix
358 :dimdom finwid
359 :dimcodom (+ (mtrix-dimcodom a)
360 (mtrix-dimcodom b))
361 :elems (append
362 (if (= awid finwid) (mtrix-elems a)
363 (mapcar #'(lambda (row)
364 (append row zeros))
365 (mtrix-elems a)))
366 (if (= bwid finwid) (mtrix-elems b)
367 (mapcar #'(lambda (row)
368 (append row zeros))
369 (mtrix-elems b)))))))