Skip to content

Commit fa0c406

Browse files
authored
Merge pull request #18 from mcabbott/range
Simplify by not allowing gather operations, nor indexing by ranges
2 parents 22de8de + ee7b1b6 commit fa0c406

File tree

4 files changed

+16
-98
lines changed

4 files changed

+16
-98
lines changed

docs/src/basics.md

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ julia> C' == @cast _[j,i] := C[i,j]'
278278
true
279279
```
280280

281-
## Arrays of indices or functions
281+
## Arrays of functions
282282

283283
Besides arrays of numbers (and arrays of arrays) you can also broadcast an array of functions,
284284
which is done by calling `Core._apply(f, xs...) = f(xs...)`:
@@ -298,18 +298,6 @@ begin
298298
end
299299
```
300300

301-
You can also index one array using another, this example is just `view(M, :, ind)`:
302-
303-
```jldoctest mylabel
304-
julia> ind = [1,1,2,2,4];
305-
306-
julia> @cast _[i,j] := M[i,ind[j]]
307-
3×5 view(::Array{Int64,2}, :, [1, 1, 2, 2, 4]) with eltype Int64:
308-
1 1 4 4 10
309-
2 2 5 5 11
310-
3 3 6 6 12
311-
```
312-
313301
## Repeated indices
314302

315303
The only situation in which repeated indices are allowed is when they either

docs/src/index.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ Version 0.2 was a re-write, see the [release notes](https://github.com/mcabbott/
1414
Version 0.4 has significant changes:
1515
- Broadcasting options and index ranges are now written `@cast @avx A[i,j] := B[i⊗j] (i ∈ 1:3)` instead of `@cast A[i,j] := B[i⊗j] i:3, axv` (using [LoopVectorization.jl](https://github.com/JuliaSIMD/LoopVectorization.jl) for the broadcast, and supplying the range of `i`).
1616
- To return an array without naming it, write an underscore `@cast _[i] := ...` rather than omitting it entirely.
17+
- Some fairly obscure features have been removed for simplicity: Indexing by an array `@cast A[i,k] := B[i,J[k]]` and by a range `@cast C[i] := f(D[1:3, i])` will no longer work.
18+
- Some dimension checks are inserted by default; previously the option `assert` did this.
1719
- It uses [LazyStack.jl](https://github.com/mcabbott/LazyStack.jl) to combine handles slices, simplifying earlier code. This is lazier by default, write `@cast A[i,k] := log(B[k][i]) lazy=false` (with a new keyword option) to glue into an `Array` before broadcasting.
18-
- It uses [TransmuteDims.jl](https://github.com/mcabbott/TransmuteDims.jl) to handle all permutations & many reshapes. This is lazier by default -- the earlier code sometimes copied to avoid reshaping a `PermutedDimsArray`. This isn't always faster, and can be disabled by `lazy=false`.
19-
- It inserts some dimension checks by default, previously the option `assert` did this.
20+
- It uses [TransmuteDims.jl](https://github.com/mcabbott/TransmuteDims.jl) to handle all permutations & many reshapes. This is lazier by default -- the earlier code sometimes copied to avoid reshaping a `PermutedDimsArray`. This isn't always faster, though, and can be disabled by `lazy=false`.
2021

2122
## Pages
2223

23-
1. Use of `@cast` for broadcasting, and slicing
24-
2. `@reduce` and `@matmul`, for summing over some directions
25-
3. Options: StaticArrays, LazyArrays, Strided, LoopVectorization
26-
4. Docstrings, for all details.
24+
1. Use of `@cast` for broadcasting, dealing with arrays of arrays, and generalising `mapslices`
25+
2. `@reduce` and `@matmul`, for taking the sum (or the `maximum`, etc) over some dimensions
26+
3. Options: broadcasting with Strided.jl, LoopVectorization.jl, LazyArrays.jl, and slicing with StaticArrays.jl
27+
4. Docstrings, which list the complete set of possibilities.

src/macro.jl

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ Understands the following things:
3636
* `M[i,i]` means `diag(M)[i]`, but only for matrices: `N[i,i,k]` is an error.
3737
* `P[i,i']` is normalised to `P[i,i′]` with unicode \\prime.
3838
* `R[i,-j,k]` means roughly `reverse(R, dims=2)`, and `Q[i,~j,k]` similar with `shuffle`.
39-
* `S[i,T[j,k]]` is the 3-tensor `S[:,T]` created by indexing a matrix `S` with `T`,
40-
where these integers are `all(1 .<= T .<= size(S,2))`.
4139
4240
The left and right hand sides must have all the same indices,
4341
and the only repeated index allowed is `M[i,i]`, which is a diagonal not a trace.
@@ -254,15 +252,15 @@ function standardise(ex, store::NamedTuple, call::CallInfo; LHS=false)
254252
A = Asym
255253
end
256254

257-
# Constant indices A[i,3], A[i,_], A[i,$c], and also A[i,3:5]
255+
# Constant indices A[i,3], A[i,_], A[i,$c]
258256
if isempty(ijk)
259257
# empty indices do not count as constant - this fixes some issues with 0d CuArrays
260-
elseif all(isCorR, ijk)
258+
elseif all(isconstant, ijk)
261259
needview!(ijk) # replace _ with 1, if any
262260
Asym = maybepush(:( $A[$(ijk...)] ), store, :allconst) # protect from later processing
263261
return Asym # and nothing more to do here
264-
elseif any(isCorR, ijk)
265-
ijcolon = map(i -> isCorR(i) ? i : (:), ijk)
262+
elseif any(isconstant, ijk)
263+
ijcolon = map(i -> isconstant(i) ? i : (:), ijk)
266264
if needview!(ijcolon)
267265
A = :( view($A, $(ijcolon...)) ) # TODO lazy_0?
268266
else
@@ -271,7 +269,6 @@ function standardise(ex, store::NamedTuple, call::CallInfo; LHS=false)
271269
A = :( TensorCast.transmute($A, $perm) )
272270
end
273271
ijk = filter(!isconstant, ijk) # remove actual constants from list,
274-
ijk = map(i -> isrange(i) ? :(:) : i, ijk) # but for A[i,3:5] replace with : symbol, for slicing
275272
end
276273

277274
# Slicing operations A[i,:,j], and A[i,3:5] after the above treatment
@@ -292,31 +289,7 @@ function standardise(ex, store::NamedTuple, call::CallInfo; LHS=false)
292289

293290
# Nested indices A[i,j,B[k,l,m],n] or worse A[i,B[j,k],C[i,j]]
294291
if any(i -> @capture(i, B_[klm__]), ijk)
295-
newijk, beecolon = [], [] # for simple case
296-
# listB, listijk = [], []
297-
for i in ijk
298-
if @capture(i, B_[klm__])
299-
append!(newijk, klm)
300-
push!(beecolon, B)
301-
# push!(listijk, klm)
302-
# push!(listB, B)
303-
else
304-
push!(newijk, i)
305-
push!(beecolon, (:))
306-
end
307-
end
308-
if allunique(newijk) # then we are in simple case
309-
ijk = newijk
310-
A = :( view($A, $(beecolon...)) )
311-
else
312-
throw(MacroError("can't handle this indexing yet, sorry", call))
313-
# LHS && error("can't do this indexing on LHS sorry")
314-
# A = maybepush(A, store, :preget)
315-
# target = guesstarget(??)
316-
# Bs = [ targetcast(B, target, store, call) for B in listB ]
317-
# Aex = getindex.(Ref(A), i)
318-
# A = maybepush(Aex, store, :getindex)
319-
end
292+
throw(MacroError("indexing one array by another is not supported, sorry", call))
320293
end
321294

322295
# Diagonal extraction A[i,i]
@@ -890,7 +863,7 @@ function indexparse(A, ijk::Vector, store=nothing, call=nothing; save=false)
890863

891864
for (d,i) in enumerate(ijk)
892865

893-
if iscolon(i) || isrange(i)
866+
if iscolon(i)
894867
if i isa QuoteNode && A != :_
895868
str = "fixed size in $A[" * join(ijk, ", ") * "]" # DimensionMismatch("fixed size in M[i, \$(QuoteNode(5))]: size(M, 2) == 5") TODO print more nicely
896869
push!(store.mustassert, :( size($A,$d)==$(i.value) || throw(ArgumentError($str))) )
@@ -977,7 +950,6 @@ function innerparse(firstA, ijk, store::NamedTuple, call::CallInfo; save=false)
977950
innerflat = []
978951
for (d,i) in enumerate(ijk)
979952
iscolon(i) && throw(MacroError("can't have a colon in inner index!", call))
980-
isrange(i) && @capture(i, alpha_Int:omega_) && throw(MacroError("can't have a range in inner index!", call)) # this is an imperfect check, must not be triggered by @cast R2[j]{i:3} := M[i,j] which is another kind of range!
981953
istensor(i) && throw(MacroError("can't tensor product inner indices", call))
982954
(@capture(i, -j_) || @capture(i, ~j_)) && throw(MacroError("can't reverse or shuffle along inner indices", call))
983955

@@ -1204,11 +1176,6 @@ isindexing(ex::Expr) = @capture(x, A_[ijk__])
12041176

12051177
isCorI(i) = isconstant(i) || isindexing(ii)
12061178

1207-
isrange(ex::Expr) = @capture(ex, alpha_:omega_) # this may be a terrible idea
1208-
isrange(i) = false
1209-
1210-
isCorR(i) = isconstant(i) || isrange(i) # ranges are treated a bit like constants!
1211-
12121179
istensor(n::Int) = false
12131180
istensor(s::Symbol) = false
12141181
function istensor(ex::Expr)
@@ -1285,8 +1252,8 @@ function needview!(ij::Vector)
12851252
elseif ij[k] isa Expr && ij[k].head == :($)
12861253
ij[k] = ij[k].args[1]
12871254
out = true
1288-
elseif ij[k] isa Expr && @capture(ij[k], alpha_:omega_) # i.e. isrange(ij[k])
1289-
out = true
1255+
# elseif ij[k] isa Expr && @capture(ij[k], alpha_:omega_) # i.e. isrange(ij[k])
1256+
# out = true
12901257
else
12911258
error("this should never happen! needview! got ", ij[k])
12921259
end
@@ -1412,7 +1379,6 @@ function newoutput(ex, canon, parsed, store::NamedTuple, call::CallInfo)
14121379
isempty(parsed.reversed) || throw(MacroError("can't reverse along indices on LHS right now", call))
14131380
isempty(parsed.shuffled) || throw(MacroError("can't shuffle along on LHS right now", call))
14141381
any(iscolon, parsed.outer) && throw(MacroError("can't have colons on the LHS right now", call))
1415-
any(isrange, parsed.outer) && throw(MacroError("can't have ranges on the LHS right now", call))
14161382

14171383
# Is there a reduction?
14181384
if :reduce in call.flags

test/two.jl

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -69,43 +69,6 @@ end
6969
@cast C[i] := B[i].scal
7070
@test C == 1:3
7171

72-
end
73-
@testset "int/bool indexing" begin
74-
75-
ind = [1,2,1,2]
76-
M = rand(1:99, 3,4)
77-
78-
N1 = M[1,ind]
79-
@cast N2[i] := M[1,ind[i]]
80-
@test N1 == N2
81-
82-
N3 = M[ind,ind]
83-
@cast N4[i,j] := M[ind[i],ind[j]]
84-
@test N3 == N4
85-
86-
bool = ind .== 1
87-
B1 = M[:,bool]
88-
@cast B2[i,j] := M[i,bool[j]]
89-
@test B1 == B2
90-
91-
V1 = M[CartesianIndex.(ind, ind)]
92-
# @cast V2[i] := M[ind[i],ind[i]]
93-
94-
end
95-
@testset "indexing with a range" begin
96-
97-
M = rand(1:99, 3,4)
98-
99-
# ranges are treated first like constants, then like colons:
100-
@cast C1[i,j] := identity(M[i, 1:2])[j]
101-
R1 = 1:2
102-
@cast C2[i,j] := M[i, R1[j]] # explicit inner indexing
103-
@test C1 == C2 == M[:, 1:2]
104-
105-
β = 2
106-
@cast C3[i,j] := identity(M[i, 1:β])[j]
107-
@test C3 == C1
108-
10972
end
11073
@testset "in-place += and *=" begin
11174

0 commit comments

Comments
 (0)