cat.scm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. ; -*- mode: scheme; coding: utf-8 -*-
  2. ;; (c) Daniel Llorens - 2020-2021
  3. ; This library is free software; you can redistribute it and/or modify it under
  4. ; the terms of the GNU General Public License as published by the Free
  5. ; Software Foundation; either version 3 of the License, or (at your option) any
  6. ; later version.
  7. ;;; Commentary:
  8. ;; Concatenation procedures for newra.
  9. ;;; Code:
  10. (define-module (newra cat)
  11. #:export (ra-cat ra-cats))
  12. (import (srfi srfi-1) (srfi srfi-26) (srfi srfi-71) (newra base) (newra lib)
  13. (newra reshape) (newra from) (ice-9 match))
  14. (define (list-subst! l k val)
  15. (list-set! l k val)
  16. l)
  17. (define (plain-cat! i dest . xx)
  18. (fold (lambda (x base)
  19. (let ((len lo hi (if (< i (ra-rank x))
  20. (match (vector-ref (ra-dims x) i)
  21. (($ <dim> len lo _)
  22. (values len lo (dim-hi len lo))))
  23. (values 1 0 0))))
  24. (ra-amend! dest
  25. ; optimization
  26. (if (zero? lo)
  27. x
  28. ; move index range from (lo hi) to (0 len). Could also use ra-reshape on axis i.
  29. (ra-from x (dots i) (ra-iota len lo)))
  30. (dots i) (ra-iota len base))
  31. (+ base len)))
  32. 0 xx)
  33. dest)
  34. ; FIXME allow inf lens in non-concatenating axes?
  35. (define (ra-cat type i . xx)
  36. "
  37. Concatenate arrays @var{xx} ... along axis @var{i}. The shapes of @var{xx}
  38. ... must have matching prefixes except at axis @var{i}.
  39. The output array will have the rank of the @var{xx} with the largest rank, or
  40. @code{(+ 1 i)}, whichever is larger. If necessary, the @var{xx} are rank
  41. extended to this output rank. The bounds of @var{xx} must match on all axes
  42. other than @var{i}.
  43. If @var{i} is negative, the shape of each @var{xx} ... is prefix-extended by
  44. @code{(- i)} singleton dimensions and the concatenation is carried out along the
  45. first axis.
  46. @code{ra-cat} always creates a new array and not a shared array.
  47. The type of the output is @var{type}, unless @code{#f}; else the type of the
  48. first argument, unless @code{'d}; else @code{#t}.
  49. 'pcat' stands for 'prefix-cat'.
  50. For example:
  51. @verbatim
  52. (ra-cat #t 0 (ra-i 1 2) (ra-i 2 2)) => #%2((0 1) (0 1) (2 3)))
  53. (ra-cat #t 0 (ra-iota 2 1) (ra-iota 3 3)) => #%1(1 2 3 4 5))
  54. (ra-cat #t -1 (ra-iota 2 1) (ra-iota 2 4)) => #%2((1 2) (4 5))
  55. (ra-cat #t 1 (ra-iota 2 1) (ra-iota 2 4)) => #%2((1 4) (2 5))
  56. (ra-cat #t 0 (make-ra 'a) (ra-iota 2)) => #%1(a 0 1)
  57. (ra-cat #t 1 (make-ra 'a) (ra-iota 2)) => #%2((a 0) (a 1))
  58. (ra-cat #t -1 (make-ra 'a) (ra-iota 2)) => #%2((a a) (0 1))
  59. (ra-cat #t 1 (array->ra #(a b)) (ra-i 2 2)) => #%2((a 0 1) (b 2 3))
  60. (ra-cat #t 0 (array->ra #(a b)) (ra-i 2 2)) => #%2((a a) (b b) (0 1) (2 3))
  61. @end verbatim
  62. See also: @code{ra-cats} @code{ra-tile}
  63. "
  64. (if (> 0 i)
  65. (apply ra-cat type 0 (map (cute apply ra-tile <> 0 (make-list (max 0 (- i)) 1)) xx))
  66. (match xx
  67. (()
  68. (throw 'ra-cat-missing-arguments))
  69. (xx
  70. (let ((xm (fold (lambda (x xm) (if (> (ra-rank x) (ra-rank xm)) x xm)) (car xx) (cdr xx))))
  71. (apply plain-cat! i
  72. (apply make-typed-ra
  73. (or type (match (ra-type (car xx)) ('d #t) (t t)))
  74. *unspecified*
  75. (list-subst! (append (ra-dimensions xm) (make-list (max 0 (- (+ 1 i) (ra-rank xm))) 1))
  76. i (fold (lambda (x o) (+ o (if (> (ra-rank x) i) (ra-len x i) 1))) 0 xx)))
  77. xx))))))
  78. (define (ra-cats type i . xx)
  79. "
  80. Concatenate items of rank @var{i} of arrays @var{xx} ... The shapes of @var{xx}
  81. ... must have matching suffixes except at axis @code{(- (ra-rank x) 1 i)} for
  82. each @var{x} in @var{xx}.
  83. The output array will have the rank of the @var{xx} with the largest rank, or
  84. @code{(+ 1 i)}, whichever is larger. If necessary, the @var{xx} are rank
  85. extended to this output rank. The bounds of @var{xx} must match on all axes
  86. other than @code{(- (ra-rank x) 1 i)}.
  87. If @var{i} is negative, the shape of each array @var{xx} ... is suffix-extended
  88. by @code{(- i)} singleton dimensions and the concatenation is carried out along
  89. the last axis.
  90. @code{ra-cats} always creates a new array and not a shared array.
  91. The type of the output is @var{type}, unless @code{#f}; else the type of the
  92. first argument, unless @code{'d}; else @code{#t}.
  93. 'scat' stands for 'suffix-cat'.
  94. For example:
  95. @verbatim
  96. (ra-cats #t 0 (make-ra 'a) (make-ra 'b) (make-ra 'c)) => #%1(a b c)
  97. (ra-cats #t 1 (make-ra 'a) (make-ra 'b) (make-ra 'c)) => #%2((a) (b) (c))
  98. (ra-cats #t 0 (array->ra #(1 2 3)) (make-ra 4) (array->ra #(5 6))) => #%1(1 2 3 4 5 6)
  99. (ra-cats #t 0 (array->ra #2((0 1) (2 3))) (array->ra #(a b))) => #%2((0 1 a b) (2 3 a b)))
  100. (ra-cats #t 1 (array->ra #2((0 1) (2 3))) (array->ra #(a b))) => #%2((0 1) (2 3) (a b))
  101. (ra-cats #t 1 (array->ra #2((0 1))) (array->ra #(a))) => error, mismatched dimensions
  102. (ra-cats #t 0 (array->ra #2((0 1))) (array->ra #(a))) => #%2((0 1 a))
  103. (ra-cats #t -1 (array->ra #(1 2 3)) (array->ra #(a b c))) => #%2((1 a) (2 b) (3 c))
  104. (ra-cats #t -1 (make-ra 'a) (array->ra #(x y z))) => #%2((a x) (a y) (a z))
  105. @end verbatim
  106. See also: @code{ra-cat} @code{ra-tile}
  107. "
  108. (if (> 0 i)
  109. (apply ra-cats type 0 (map (lambda (x) (apply ra-tile x (ra-rank x) (make-list (max 0 (- i)) 1))) xx))
  110. (match xx
  111. (()
  112. (throw 'ra-cats-missing-arguments))
  113. (xx
  114. (let* ((xm (fold (lambda (x xm) (if (> (ra-rank x) (ra-rank xm)) x xm)) (car xx) (cdr xx)))
  115. (im (max (+ 1 i) (ra-rank xm)))
  116. (ii (- im 1 i))
  117. (xx (map (lambda (x)
  118. (let ((ext (append (make-list (- im (ra-rank xm)) 1)
  119. (take (ra-dimensions xm) (- (ra-rank xm) (ra-rank x))))))
  120. (apply ra-tile x 0
  121. (if (> (ra-rank x) i)
  122. ext
  123. (list-subst! ext ii 1)))))
  124. xx)))
  125. (apply plain-cat! ii
  126. (apply make-typed-ra
  127. (or type (match (ra-type (car xx)) ('d #t) (t t)))
  128. *unspecified*
  129. (list-subst! (ra-dimensions (car xx))
  130. ii (fold (lambda (x o) (+ o (ra-len x ii))) 0 xx)))
  131. xx))))))