Guest User

Untitled

a guest
Dec 16th, 2017
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.23 KB | None | 0 0
  1. import Base.Slice
  2. import Base._unsafe_getindex!
  3.  
  4. function mapslices2(f, A::AbstractArray, B::AbstractArray, dims::AbstractVector)
  5. if isempty(dims)
  6. return map(f,A,B)
  7. end
  8.  
  9. @assert size(A) == size(B)
  10.  
  11. dimsA = [indices(A)...]
  12. ndimsA = ndims(A)
  13. alldims = [1:ndimsA;]
  14.  
  15. otherdims = setdiff(alldims, dims)
  16.  
  17. idx = Any[first(ind) for ind in indices(A)]
  18. itershape = tuple(dimsA[otherdims]...)
  19. for d in dims
  20. idx[d] = Slice(indices(A, d))
  21. end
  22.  
  23. # Apply the function to the first slice in order to determine the next steps
  24. Aslice = A[idx...]
  25. Bslice = B[idx...]
  26. r1 = f(Aslice, Bslice)
  27. # In some cases, we can re-use the first slice for a dramatic performance
  28. # increase. The slice itself must be mutable and the result cannot contain
  29. # any mutable containers. The following errs on the side of being overly
  30. # strict (#18570 & #21123).
  31. safe_for_reuse = isa(Aslice, StridedArray) &&
  32. (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
  33.  
  34. # determine result size and allocate
  35. Rsize = copy(dimsA)
  36. # TODO: maybe support removing dimensions
  37. if !isa(r1, AbstractArray) || ndims(r1) == 0
  38. r1 = [r1]
  39. end
  40. nextra = max(0, length(dims)-ndims(r1))
  41. if eltype(Rsize) == Int
  42. Rsize[dims] = [size(r1)..., ntuple(d->1, nextra)...]
  43. else
  44. Rsize[dims] = [indices(r1)..., ntuple(d->OneTo(1), nextra)...]
  45. end
  46. R = similar(r1, tuple(Rsize...,))
  47.  
  48. ridx = Any[map(first, indices(R))...]
  49. for d in dims
  50. ridx[d] = indices(R,d)
  51. end
  52.  
  53. R[ridx...] = r1
  54.  
  55. nidx = length(otherdims)
  56. indexes = Iterators.drop(CartesianRange(itershape), 1)
  57. inner_mapslices2!(safe_for_reuse, indexes, nidx, idx, otherdims, ridx, Aslice,
  58. Bslice, A, B, f, R)
  59. end
  60.  
  61. function inner_mapslices2!(safe_for_reuse, indexes, nidx, idx, otherdims, ridx, Aslice,
  62. Bslice, A, B, f, R)
  63. if safe_for_reuse
  64. # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
  65. # so we can reuse Aslice
  66. for I in indexes # skip the first element, we already handled it
  67. replace_tuples2!(nidx, idx, ridx, otherdims, I)
  68. _unsafe_getindex!(Aslice, A, idx...)
  69. _unsafe_getindex!(Bslice, B, idx...)
  70. R[ridx...] = f(Aslice, Bslice)
  71. end
  72. else
  73. # we can't guarantee safety (#18524), so allocate new storage for each slice
  74. for I in indexes
  75. replace_tuples!(nidx, idx, ridx, otherdims, I)
  76. R[ridx...] = f(A[idx...], B[idx...])
  77. end
  78. end
  79.  
  80. return R
  81. end
  82.  
  83. function mapslicesN(f, AN::Array{T,1}, dims::AbstractVector) where T<:AbstractArray
  84. if isempty(dims)
  85. return map(f,AN...)
  86. end
  87.  
  88. A = AN[1]
  89.  
  90. dimsA = [indices(A)...]
  91. ndimsA = ndims(A)
  92. alldims = [1:ndimsA;]
  93.  
  94. otherdims = setdiff(alldims, dims)
  95.  
  96. idx = Any[first(ind) for ind in indices(A)]
  97. itershape = tuple(dimsA[otherdims]...)
  98. for d in dims
  99. idx[d] = Slice(indices(A, d))
  100. end
  101.  
  102. # Apply the function to the first slice in order to determine the next steps
  103. ANslices = [x[idx...] for x in AN]
  104. r1 = f(ANslices...)
  105. # In some cases, we can re-use the first slice for a dramatic performance
  106. # increase. The slice itself must be mutable and the result cannot contain
  107. # any mutable containers. The following errs on the side of being overly
  108. # strict (#18570 & #21123).
  109. safe_for_reuse = isa(ANslices[1], StridedArray) &&
  110. (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
  111.  
  112. # determine result size and allocate
  113. Rsize = copy(dimsA)
  114. # TODO: maybe support removing dimensions
  115. if !isa(r1, AbstractArray) || ndims(r1) == 0
  116. r1 = [r1]
  117. end
  118. nextra = max(0, length(dims)-ndims(r1))
  119. if eltype(Rsize) == Int
  120. Rsize[dims] = [size(r1)..., ntuple(d->1, nextra)...]
  121. else
  122. Rsize[dims] = [indices(r1)..., ntuple(d->OneTo(1), nextra)...]
  123. end
  124. R = similar(r1, tuple(Rsize...,))
  125.  
  126. ridx = Any[map(first, indices(R))...]
  127. for d in dims
  128. ridx[d] = indices(R,d)
  129. end
  130.  
  131. R[ridx...] = r1
  132.  
  133. nidx = length(otherdims)
  134. indexes = Iterators.drop(CartesianRange(itershape), 1)
  135. inner_mapslicesN!(safe_for_reuse, indexes, nidx, idx, otherdims, ridx, ANslices,
  136. AN, f, R)
  137. end
  138.  
  139. function inner_mapslicesN!(safe_for_reuse, indexes, nidx, idx, otherdims, ridx, ANslices,
  140. AN, f, R)
  141. if safe_for_reuse
  142. # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
  143. # so we can reuse Aslice
  144. for I in indexes # skip the first element, we already handled it
  145. replace_tuples2!(nidx, idx, ridx, otherdims, I)
  146. for (ind,slice) in enumerate(ANslices)
  147. _unsafe_getindex!(slice, AN[ind], idx...)
  148. end
  149. R[ridx...] = f(ANslices...)
  150. end
  151. else
  152. # we can't guarantee safety (#18524), so allocate new storage for each slice
  153. for I in indexes
  154. replace_tuples!(nidx, idx, ridx, otherdims, I)
  155. R[ridx...] = f([x[idx...] for x in AN]...)
  156. end
  157. end
  158.  
  159. return R
  160. end
  161.  
  162. function replace_tuples!(nidx, idx, ridx, otherdims, I)
  163. for i in 1:nidx
  164. idx[otherdims[i]] = ridx[otherdims[i]] = I.I[i]
  165. end
  166. end
Add Comment
Please, Sign In to add comment