123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- ; -*- mode: scheme; coding: utf-8 -*-
- ;; (c) Daniel Llorens - 2020-2021
- ; This library is free software; you can redistribute it and/or modify it under
- ; the terms of the GNU General Public License as published by the Free
- ; Software Foundation; either version 3 of the License, or (at your option) any
- ; later version.
- ;;; Commentary:
- ;; Concatenation procedures for newra.
- ;;; Code:
- (define-module (newra cat)
- #:export (ra-cat ra-cats))
- (import (srfi srfi-1) (srfi srfi-26) (srfi srfi-71) (newra base) (newra lib)
- (newra reshape) (newra from) (ice-9 match))
- (define (list-subst! l k val)
- (list-set! l k val)
- l)
- (define (plain-cat! i dest . xx)
- (fold (lambda (x base)
- (let ((len lo hi (if (< i (ra-rank x))
- (match (vector-ref (ra-dims x) i)
- (($ <dim> len lo _)
- (values len lo (dim-hi len lo))))
- (values 1 0 0))))
- (ra-amend! dest
- ; optimization
- (if (zero? lo)
- x
- ; move index range from (lo hi) to (0 len). Could also use ra-reshape on axis i.
- (ra-from x (dots i) (ra-iota len lo)))
- (dots i) (ra-iota len base))
- (+ base len)))
- 0 xx)
- dest)
- ; FIXME allow inf lens in non-concatenating axes?
- (define (ra-cat type i . xx)
- "
- Concatenate arrays @var{xx} ... along axis @var{i}. The shapes of @var{xx}
- ... must have matching prefixes except at axis @var{i}.
- The output array will have the rank of the @var{xx} with the largest rank, or
- @code{(+ 1 i)}, whichever is larger. If necessary, the @var{xx} are rank
- extended to this output rank. The bounds of @var{xx} must match on all axes
- other than @var{i}.
- If @var{i} is negative, the shape of each @var{xx} ... is prefix-extended by
- @code{(- i)} singleton dimensions and the concatenation is carried out along the
- first axis.
- @code{ra-cat} always creates a new array and not a shared array.
- The type of the output is @var{type}, unless @code{#f}; else the type of the
- first argument, unless @code{'d}; else @code{#t}.
- 'pcat' stands for 'prefix-cat'.
- For example:
- @verbatim
- (ra-cat #t 0 (ra-i 1 2) (ra-i 2 2)) => #%2((0 1) (0 1) (2 3)))
- (ra-cat #t 0 (ra-iota 2 1) (ra-iota 3 3)) => #%1(1 2 3 4 5))
- (ra-cat #t -1 (ra-iota 2 1) (ra-iota 2 4)) => #%2((1 2) (4 5))
- (ra-cat #t 1 (ra-iota 2 1) (ra-iota 2 4)) => #%2((1 4) (2 5))
- (ra-cat #t 0 (make-ra 'a) (ra-iota 2)) => #%1(a 0 1)
- (ra-cat #t 1 (make-ra 'a) (ra-iota 2)) => #%2((a 0) (a 1))
- (ra-cat #t -1 (make-ra 'a) (ra-iota 2)) => #%2((a a) (0 1))
- (ra-cat #t 1 (array->ra #(a b)) (ra-i 2 2)) => #%2((a 0 1) (b 2 3))
- (ra-cat #t 0 (array->ra #(a b)) (ra-i 2 2)) => #%2((a a) (b b) (0 1) (2 3))
- @end verbatim
- See also: @code{ra-cats} @code{ra-tile}
- "
- (if (> 0 i)
- (apply ra-cat type 0 (map (cute apply ra-tile <> 0 (make-list (max 0 (- i)) 1)) xx))
- (match xx
- (()
- (throw 'ra-cat-missing-arguments))
- (xx
- (let ((xm (fold (lambda (x xm) (if (> (ra-rank x) (ra-rank xm)) x xm)) (car xx) (cdr xx))))
- (apply plain-cat! i
- (apply make-typed-ra
- (or type (match (ra-type (car xx)) ('d #t) (t t)))
- *unspecified*
- (list-subst! (append (ra-dimensions xm) (make-list (max 0 (- (+ 1 i) (ra-rank xm))) 1))
- i (fold (lambda (x o) (+ o (if (> (ra-rank x) i) (ra-len x i) 1))) 0 xx)))
- xx))))))
- (define (ra-cats type i . xx)
- "
- Concatenate items of rank @var{i} of arrays @var{xx} ... The shapes of @var{xx}
- ... must have matching suffixes except at axis @code{(- (ra-rank x) 1 i)} for
- each @var{x} in @var{xx}.
- The output array will have the rank of the @var{xx} with the largest rank, or
- @code{(+ 1 i)}, whichever is larger. If necessary, the @var{xx} are rank
- extended to this output rank. The bounds of @var{xx} must match on all axes
- other than @code{(- (ra-rank x) 1 i)}.
- If @var{i} is negative, the shape of each array @var{xx} ... is suffix-extended
- by @code{(- i)} singleton dimensions and the concatenation is carried out along
- the last axis.
- @code{ra-cats} always creates a new array and not a shared array.
- The type of the output is @var{type}, unless @code{#f}; else the type of the
- first argument, unless @code{'d}; else @code{#t}.
- 'scat' stands for 'suffix-cat'.
- For example:
- @verbatim
- (ra-cats #t 0 (make-ra 'a) (make-ra 'b) (make-ra 'c)) => #%1(a b c)
- (ra-cats #t 1 (make-ra 'a) (make-ra 'b) (make-ra 'c)) => #%2((a) (b) (c))
- (ra-cats #t 0 (array->ra #(1 2 3)) (make-ra 4) (array->ra #(5 6))) => #%1(1 2 3 4 5 6)
- (ra-cats #t 0 (array->ra #2((0 1) (2 3))) (array->ra #(a b))) => #%2((0 1 a b) (2 3 a b)))
- (ra-cats #t 1 (array->ra #2((0 1) (2 3))) (array->ra #(a b))) => #%2((0 1) (2 3) (a b))
- (ra-cats #t 1 (array->ra #2((0 1))) (array->ra #(a))) => error, mismatched dimensions
- (ra-cats #t 0 (array->ra #2((0 1))) (array->ra #(a))) => #%2((0 1 a))
- (ra-cats #t -1 (array->ra #(1 2 3)) (array->ra #(a b c))) => #%2((1 a) (2 b) (3 c))
- (ra-cats #t -1 (make-ra 'a) (array->ra #(x y z))) => #%2((a x) (a y) (a z))
- @end verbatim
- See also: @code{ra-cat} @code{ra-tile}
- "
- (if (> 0 i)
- (apply ra-cats type 0 (map (lambda (x) (apply ra-tile x (ra-rank x) (make-list (max 0 (- i)) 1))) xx))
- (match xx
- (()
- (throw 'ra-cats-missing-arguments))
- (xx
- (let* ((xm (fold (lambda (x xm) (if (> (ra-rank x) (ra-rank xm)) x xm)) (car xx) (cdr xx)))
- (im (max (+ 1 i) (ra-rank xm)))
- (ii (- im 1 i))
- (xx (map (lambda (x)
- (let ((ext (append (make-list (- im (ra-rank xm)) 1)
- (take (ra-dimensions xm) (- (ra-rank xm) (ra-rank x))))))
- (apply ra-tile x 0
- (if (> (ra-rank x) i)
- ext
- (list-subst! ext ii 1)))))
- xx)))
- (apply plain-cat! ii
- (apply make-typed-ra
- (or type (match (ra-type (car xx)) ('d #t) (t t)))
- *unspecified*
- (list-subst! (ra-dimensions (car xx))
- ii (fold (lambda (x o) (+ o (ra-len x ii))) 0 xx)))
- xx))))))
|