as-array.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ; (c) Daniel Llorens - 2012-2013
  2. ; Array memory order operations and array conversion.
  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. ; The order options are for interfacing with foreign libraries.
  8. ; In normal Guile array code one shouldn't be concerned about storage order.
  9. (define-module (ploy as-array))
  10. (import (ice-9 optargs) (srfi srfi-26) (srfi srfi-1) (srfi srfi-11)
  11. (srfi srfi-9) (srfi srfi-8) (ploy basic) (ploy assert) (ice-9 control))
  12. (define (c-order? a)
  13. (reset
  14. (fold (lambda (i s c)
  15. (if (not (= (* c s) i))
  16. (shift k #f)
  17. (* c s)))
  18. 1
  19. (reverse (shared-array-increments a))
  20. (cons 1 (reverse (array-dimensions a))))))
  21. (define (fortran-order? a)
  22. (reset
  23. (fold (lambda (i s c)
  24. (if (not (= (* c s) i))
  25. (shift k #f)
  26. (* c s)))
  27. 1
  28. (shared-array-increments a)
  29. (cons 1 (array-dimensions a)))))
  30. (define (assignable? a)
  31. (reset
  32. (case (array-rank a)
  33. ((0) #t)
  34. ((1) (or (< (tally a) 2) (not (zero? (first (shared-array-increments a))))))
  35. (else
  36. ; ignore singleton axes, bail out on null axes.
  37. (let ((is (sort (filter (lambda (is)
  38. (case (second is)
  39. ((0) (shift k #f))
  40. ((1) #f)
  41. (else #t)))
  42. (zip (shared-array-increments a) (array-dimensions a)))
  43. (lambda (a b) (< (magnitude (first a)) (magnitude (first b)))))))
  44. (let loop ((is is))
  45. (cond ((null? is) #t)
  46. ((zero? (first (car is))) #f)
  47. ((null? (cdr is)) #t)
  48. ((> (* (magnitude (first (car is))) (second (car is)))
  49. (magnitude (first (cadr is))))
  50. #f)
  51. (else (loop (cdr is))))))))))
  52. (export c-order? fortran-order? assignable?)
  53. ; Convert possibly nested arraylike object to array.
  54. ; @todo (as-array (reshape 1 10) #:type 'f64) creates a full size 10 array. Is this what we want?
  55. (define* (arraylike-dimensions A #:key rank)
  56. (let loop ((A A) (i 0) (dims '()) (nested-list? #t))
  57. (cond ((and rank (= i rank)) (values dims nested-list?))
  58. ((and rank (> i rank)) (throw 'as-array-dimensions-cannot-be-split-by-rank rank))
  59. ((array? A) (let ((dims (append dims (array-dimensions A)))
  60. (root (shared-array-root A)))
  61. (if (zero? (tally root))
  62. (values dims #f)
  63. (loop (array-ref root 0) (+ i (array-rank A)) dims #f))))
  64. ((list? A) (if (null? A)
  65. (values (append dims '(0)) nested-list?)
  66. (loop (car A) (+ i 1) (append dims (list (length A))) nested-list?)))
  67. ((and rank (< i rank)) (throw 'as-array-requested-rank-too-large rank i))
  68. (else (values dims nested-list?)))))
  69. (define* (as-array A #:key type order rank unique? check?)
  70. (let*-values (((dims nested-list?) (arraylike-dimensions A #:rank rank))
  71. ((rank) (or rank (length dims))))
  72. (define (make-dest-array type)
  73. (case order
  74. ((c #f) (apply make-typed-array type *unspecified* dims))
  75. ((fortran) (apply transpose-array (apply make-typed-array type *unspecified* (reverse dims))
  76. (iota rank (- rank 1) -1)))
  77. (else (throw 'arbitrary-order-not-implemented))))
  78. (cond
  79. ; never ever return #0().
  80. ((zero? rank) A)
  81. ; special case. @todo for order != c, list->array and then array-copy would still be faster.
  82. ((and nested-list? (or (eq? order 'c) (eq? order #f)))
  83. (list->typed-array (or type #t) rank A))
  84. ((and (array? A) (= (array-rank A) rank))
  85. (assert (not (zero? rank)) "BAD")
  86. (if (and (case order
  87. ((#f) #t)
  88. ((fortran) (fortran-order? A))
  89. ((c) (c-order? A))
  90. (else (throw 'arbitrary-order-not-implemented)))
  91. (or (not type) (eq? (array-type A) type))
  92. (not unique?))
  93. A
  94. (or check?
  95. (let ((B (make-dest-array (or type (array-type A)))))
  96. (array-copy! A B)
  97. B))))
  98. ; need to delve and convert.
  99. (else
  100. (and (not check?)
  101. (let ((B (make-dest-array (or type #t))))
  102. (let loopd ((A A) (B B) (rank rank))
  103. (if (list? A)
  104. (let ((rank- (- rank 1)))
  105. (if (zero? rank-)
  106. (array-copy! (list->array 1 A) B)
  107. (let loop ((A A) (i 0))
  108. (unless (null? A)
  109. (loopd (car A) (array-cell-ref B i) rank-)
  110. (loop (cdr A) (+ i 1))))))
  111. (let ((rank- (- rank (array-rank A))))
  112. (if (zero? rank-)
  113. (array-copy! A B)
  114. (array-slice-for-each (array-rank A) (lambda (A B) (loopd (array-cell-ref A) (array-cell-ref B) rank-)) A B)))))
  115. B))))))
  116. (export arraylike-dimensions as-array)