cat.scm 6.2 KB

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