-
-
Notifications
You must be signed in to change notification settings - Fork 396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing KeyIterator used for JuMPArray to work also when index sets are non indexable. #836
Changes from 6 commits
734b58e
4204781
5e59724
452743c
cc53bdc
ab0d709
ee819c7
c980b33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -151,8 +151,10 @@ Base.ndims{T,N}(x::JuMPDict{T,N}) = N | |
Base.abs(x::JuMPDict) = map(abs, x) | ||
# avoid dangerous behavior with "end" (#730) | ||
Base.endof(x::JuMPArray) = error("endof() (and \"end\" syntax) not implemented for JuMPArray objects.") | ||
Base.size(x::JuMPArray) = error("size (and \"end\" syntax) not implemented for JuMPArray objects. Use JuMP.size if you want to access the dimensions.") | ||
Base.size(x::JuMPArray,k) = error("size (and \"end\" syntax) not implemented for JuMPArray objects. Use JuMP.size if you want to access the dimensions.") | ||
Base.size(x::JuMPArray) = error(string("size (and \"end\" syntax) not implemented for JuMPArray objects.", | ||
"Use JuMP.size if you want to access the dimensions.")) | ||
Base.size(x::JuMPArray,k) = error(string("size (and \"end\" syntax) not implemented for JuMPArray objects.", | ||
" Use JuMP.size if you want to access the dimensions.")) | ||
size(x::JuMPArray) = size(x.innerArray) | ||
size(x::JuMPArray,k) = size(x.innerArray,k) | ||
# for uses of size() within JuMP | ||
|
@@ -183,13 +185,57 @@ Base.length(it::ValueIterator) = length(it.x) | |
|
||
type KeyIterator{JA<:JuMPArray} | ||
x::JA | ||
dim::Int | ||
next_k_cache::Array{Any,1} | ||
function KeyIterator(d) | ||
n = ndims(d.innerArray) | ||
new(d, n, Array(Any, n+1)) | ||
end | ||
end | ||
|
||
KeyIterator{JA}(d::JA) = KeyIterator{JA}(d) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this method necessary with the inner constructor above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. deleting line 196 gives this error ERROR: LoadError: MethodError: Cannot There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, strange. OK, thanks. |
||
|
||
@generated function _start{T,N,NT}(x::JuMPArray{T,N,NT}) | ||
quote | ||
$(Expr(:tuple, 0, [:(start(x.indexsets[$i])) for i in 1:N]...)) | ||
end | ||
end | ||
Base.start(it::KeyIterator) = start(it.x.innerArray) | ||
@generated __next{T,N,NT}(x::JuMPArray{T,N,NT}, k) = | ||
|
||
Base.start(it::KeyIterator) = _start(it.x) | ||
|
||
@generated function _next{T,N,NT}(x::JuMPArray{T,N,NT}, k) | ||
quote | ||
subidx = ind2sub(size(x),k) | ||
$(Expr(:tuple, [:(x.indexsets[$i][subidx[$i]]) for i in 1:N]...)), next(x.innerArray,k)[2] | ||
$(Expr(:tuple, [:(next(x.indexsets[$i], k[$i+1])[1]) for i in 1:N]...)) | ||
end | ||
end | ||
|
||
function Base.next(it::KeyIterator, k) | ||
cartesian_key = JuMPKey(_next(it.x, k)) | ||
pos = -1 | ||
for i in 1:it.dim | ||
if(!done(it.x.indexsets[i], next(it.x.indexsets[i], k[i+1])[2] ) ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Style point: it's preferred to use whitespace, not parentheses, in if statements: if !done(it.x.indexsets[i], next(it.x.indexsets[i], k[i+1])[2]) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry about that. I will fix it in my next commit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries, just a minor point |
||
pos = i | ||
break | ||
end | ||
end | ||
if pos == - 1 | ||
return cartesian_key, (1) | ||
end | ||
it.next_k_cache[1] = 0 | ||
for i in 1:it.dim | ||
if i < pos | ||
it.next_k_cache[i+1] = start(it.x.indexsets[i]) | ||
elseif i == pos | ||
it.next_k_cache[i+1] = next(it.x.indexsets[i], k[i+1])[2] | ||
else | ||
it.next_k_cache[i+1] = k[i+1] | ||
end | ||
end | ||
Base.next(it::KeyIterator, k) = __next(it.x,k) | ||
Base.done(it::KeyIterator, k) = done(it.x.innerArray, k) | ||
cartesian_key, tuple(it.next_k_cache...) | ||
end | ||
|
||
function Base.done(it::KeyIterator, k) | ||
return k[1] == 1 | ||
end | ||
|
||
Base.length(it::KeyIterator) = length(it.x.innerArray) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does performance improve if this is instead
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it doesn't @joehuchette . The wrapper is the second modification I have made and it is the first one that had a negative impact on the performance, namely using iterators instead of indexes. Maybe I confused you, by not opening another PR. I thought it is related ...
Should I open a new PR for the JuMPKey wrapper?