-
Notifications
You must be signed in to change notification settings - Fork 16
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
Rewrite ICP in ReverseDiff style #97
Conversation
@jrevels what about cassette? |
Cassette would definitely be useful here if it was released/usable with a released version of Julia, but that's not currently the case. Always down to help folks play around with a Cassette-based implementation if somebody wants to make the attempt, though. |
I discussed using Cassette with @eeshan9815. We decided that this would be a good first step. We are very interested in discussing that with you, though, @jrevels. |
src/IntervalConstraintProgramming.jl
Outdated
@@ -20,9 +20,12 @@ export | |||
SubPaving, Paving, | |||
pave, refine!, | |||
Vol, | |||
show_code | |||
show_code, icp! |
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.
You need to export icp
too / 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.
Okay, I will add both versions.
src/icp.jl
Outdated
julia> constraint = -∞..1 | ||
[-∞, 1] | ||
|
||
julia> icp(f, X, constraint) |
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.
Should this be icp!
?
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.
Oh yeah, sorry about the typo.
src/tape/tracked.jl
Outdated
const NULL_INDEX = typemin(Int) | ||
const NULL_TAPE = InstructionTape() | ||
|
||
type TrackedReal{V<:Real,O} <: Real |
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.
immutable
? And spacing problem.
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.
The value
s in the TrackedReal
are modified as the tape is traversed, so it can't be an immutable
src/tape/tracked.jl
Outdated
|
||
TrackedReal{V}(v::V, tp::InstructionTape = NULL_TAPE) = TrackedReal{V,Void}(v, tp) | ||
|
||
immutable TrackedArray{V,N,VA} <: AbstractArray{TrackedReal{V,TrackedArray{V,N,VA}},N} |
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.
Extra space
|
src/tape/tracked.jl
Outdated
const NULL_INDEX = typemin(Int) | ||
const NULL_TAPE = InstructionTape() | ||
|
||
type TrackedReal{V<:Real,O} <: Real |
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.
type
-> mutable struct
src/tape/icp.jl
Outdated
@@ -106,16 +106,47 @@ function reverse_pass!(tape::InstructionTape, input::AbstractArray) | |||
t = tape | |||
t[i].output.value = t[i].output.value ∩ t[i].cache | |||
op = IntervalContractors.reverse_operations[Symbol(t[i].func)] | |||
if op == :mul_rev | |||
if istracked(t[i].input[1]) && istracked(t[i].input[2]) |
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.
This if
seems to just be a combination of the two below, so can be eliminated (replacing the elseif
s by if
s).
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.
Won't that require four comparisions, instead of the current three?
The current flow of control is -
if a && b
else if a #if a && !b
else if b #if !a && b
else #if !a && !b
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.
As far as I can tell, there's just two things to check: a
or !a
, and separately b
or !b
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.
But isn't that four comparisions in the worst case, instead of 3 if elseif
is used?
src/tape/icp.jl
Outdated
elseif istracked(t[i].input[1]) | ||
rev_result = mul_rev_2(value(t[i].output), value.(t[i].input)...) | ||
t[i].input[1].value = rev_result | ||
if 0 < t[i].input[1].index <= n |
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.
What is this line for?
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.
If the index of the variables is between 0 and n, that means that the variable is one of the input variables, for which, the changes need to be reflected in the input array as well.
|
||
""" | ||
|
||
function icp!(f::Function, input::AbstractArray, constraint::Interval) |
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.
The convention is that the first argument is modified, so I think we should reverse the order of the first two arguments.
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.
Actually, if the mutating function accepts a function argument, then that usually comes first, e.g.
help?> map!
search: map! asyncmap! map mapfoldr mapfoldl mapslices mapreduce mapreducedim asyncmap macroexpand @macroexpand
map!(function, destination, collection...)
Like map, but stores the result in destination rather than a new collection. destination must be at least as large
as the first collection.
with the reason being that it allows use of the convenient do
notation.
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.
Ah, OK, thanks!
It's two comparisons: one for a and a separate one for b. Two separate ifs
- they are independent. Or am I mistaken?
…On Mon, 16 Jul 2018, 9:38 am Eeshan Gupta, ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/tape/icp.jl
<#97 (comment)>
:
> @@ -106,16 +106,47 @@ function reverse_pass!(tape::InstructionTape, input::AbstractArray)
t = tape
t[i].output.value = t[i].output.value ∩ t[i].cache
op = IntervalContractors.reverse_operations[Symbol(t[i].func)]
+ if op == :mul_rev
+ if istracked(t[i].input[1]) && istracked(t[i].input[2])
But isn't that four comparisions in the worst case, instead of 3 if elseif
is used?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#97 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AALtTr400e48GlUjoJHCf4uRBnxxFXxuks5uHJdsgaJpZM4VLWJz>
.
|
Since you seem to just be duplicating the code.
…On Mon, 16 Jul 2018, 9:45 am David P. Sanders, ***@***.***> wrote:
It's two comparisons: one for a and a separate one for b. Two separate ifs
- they are independent. Or am I mistaken?
On Mon, 16 Jul 2018, 9:38 am Eeshan Gupta, ***@***.***>
wrote:
> ***@***.**** commented on this pull request.
> ------------------------------
>
> In src/tape/icp.jl
> <#97 (comment)>
> :
>
> > @@ -106,16 +106,47 @@ function reverse_pass!(tape::InstructionTape, input::AbstractArray)
> t = tape
> t[i].output.value = t[i].output.value ∩ t[i].cache
> op = IntervalContractors.reverse_operations[Symbol(t[i].func)]
> + if op == :mul_rev
> + if istracked(t[i].input[1]) && istracked(t[i].input[2])
>
> But isn't that four comparisions in the worst case, instead of 3 if
> elseif is used?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#97 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AALtTr400e48GlUjoJHCf4uRBnxxFXxuks5uHJdsgaJpZM4VLWJz>
> .
>
|
Ohh, I just realized what you mean! |
Please remove 0.5 from testing, and make nightly an allowed failure. |
t = tape | ||
t[i].output.value = t[i].output.value ∩ t[i].cache #Propogation of constraints up | ||
op = IntervalContractors.reverse_operations[Symbol(t[i].func)] #Looking up the reverse function in IntervalContractors | ||
if op == :mul_rev #Special behavior to deal with constants |
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.
Isn't this generic for any binary operator?
I believe this is not up to date with Julia 1.0, so I am planning to close it. Feel free to re-open when possible. |
No longer relevant. |
No description provided.