Skip to content
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

Fix #889 #891

Merged
merged 2 commits into from
Dec 21, 2016
Merged

Fix #889 #891

merged 2 commits into from
Dec 21, 2016

Conversation

blegat
Copy link
Member

@blegat blegat commented Nov 10, 2016

No description provided.

@mlubin
Copy link
Member

mlubin commented Nov 10, 2016

Thanks for the PR! Should we be doing this though or should we move towards the built-in broadcast syntax?

@blegat
Copy link
Member Author

blegat commented Nov 10, 2016

The issue with the broadcast syntax is that it does not preserve the sparsity

julia> f(x) = x*x
f (generic function with 1 method)

julia> X = sparse([1, 3], [2, 3], [3, 9])
3×3 sparse matrix with 2 Int64 nonzero entries:
    [1, 2]  =  3
    [3, 3]  =  9

julia> f.(X)
3×3 Array{Int64,2}:
 0  9   0
 0  0   0
 0  0  81

julia> broadcast(f, X)
3×3 Array{Int64,2}:
 0  9   0
 0  0   0
 0  0  81

@mlubin
Copy link
Member

mlubin commented Nov 10, 2016

Is there an upstream discussion on this?

@blegat
Copy link
Member Author

blegat commented Nov 10, 2016

The thing is that broadcast needs to be sure that the function maps zero to zero.
Currently there is the _broadcast_unary_nz2nz_z2z where we ensure that nonzero are mapped to nonzero and zero are mapped to zeros so that it can just apply the function to every nonzero entry.
There is also this pull request: JuliaLang/julia#19239 that checks when you call broadcast whether the function maps zero to zero.

Do you think we should only support getvalue of objects created by JuMP (like @variable [1:n,1:m]) and ask the user to use getvalue. when he has created a container of JuMP expressions since it seems that in Julia 0.6, broadcast on sparse matrices will return sparse matrices ?

@mlubin
Copy link
Member

mlubin commented Nov 10, 2016

Yes, I'd say we shouldn't implement any magic for types that aren't directly created by JuMP. JuMP will never directly create a sparse matrix of variables. Mapping zero to zero is nonsensical in this case though, hope the broadcasting works when you have nonnumeric entries.

@blegat
Copy link
Member Author

blegat commented Nov 10, 2016

If the JuliaLang pull request is merged as is, it will fail since it will do

julia> getvalue(typeof(zero(JuMP.Variable))) == zero(Variable)
ERROR: MethodError: no method matching getvalue(::Type{JuMP.GenericAffExpr{Float64,JuMP.Variable}})
Closest candidates are:
  getvalue(::JuMP.NonlinearExpression) at /home/blegat/.julia/v0.5/JuMP/src/nlp.jl:1236
  getvalue(::JuMP.NonlinearParameter) at /home/blegat/.julia/v0.5/JuMP/src/nlp.jl:39
  getvalue(::JuMP.GenericQuadExpr{Float64,JuMP.Variable}) at /home/blegat/.julia/v0.5/JuMP/src/quadexpr.jl:92
  ...

@mlubin
Copy link
Member

mlubin commented Nov 10, 2016

Well that's an issue. Should we let them know?

@blegat
Copy link
Member Author

blegat commented Nov 10, 2016

We could also define getvalue for AffineExpr

@mlubin
Copy link
Member

mlubin commented Nov 10, 2016

IIRC that should already be defined.

@blegat
Copy link
Member Author

blegat commented Nov 11, 2016

Oh I didn't write it correctly... What is going to be called is

julia> getvalue(zero(Variable)) == zero(Variable)
false
julia> typeof(zero(Variable))
JuMP.GenericAffExpr{Float64,JuMP.Variable}
julia> typeof(getvalue(zero(Variable)))
Float64

The problem is that there is no method == between an AffExpr and something else. If we add

(==)(lhs::AffExpr,rhs) = (sum(abs(lhs.coeffs)) == 0) && (lhs.constant == rhs)
(==)(lhs,rhs::AffExpr) = rhs == lhs

then we get

julia> getvalue(zero(Variable)) == zero(Variable)
true

@joehuchette
Copy link
Contributor

Any reason not to merge this?

@mlubin
Copy link
Member

mlubin commented Dec 9, 2016

I remove my objection. If you update the PR and get tests passing this is okay to merge. We'll revisit the use of broadcast syntax for everything in JuMP at a later point.

@codecov-io
Copy link

codecov-io commented Dec 9, 2016

Current coverage is 88.30% (diff: 72.00%)

Merging #891 into master will increase coverage by 0.43%

@@             master       #891   diff @@
==========================================
  Files            18         18          
  Lines          4403       4687   +284   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           3869       4139   +270   
- Misses          534        548    +14   
  Partials          0          0          

Powered by Codecov. Last update ff2e4ce...03e0284

@@ -98,8 +98,8 @@ pushmeta!(x::JuMPContainer, sym::Symbol, val) = (x.meta[sym] = val)
getmeta(x::JuMPContainer, sym::Symbol) = x.meta[sym]

# duck typing approach -- if eltype(innerArray) doesn't support accessor, will fail
for accessor in (:getdual, :getlowerbound, :getupperbound)
@eval $accessor(x::Union{JuMPContainer,Array}) = map($accessor,x)
for accessor in (:getdual, :getlowerbound, :getupperbound, :getvalue)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't getvalue(::JuMPContainer) already explicitly defined somewhere else? There's a reason it's not on this list.

Copy link
Member Author

@blegat blegat Dec 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an excellent question. I have updated the PR with a proposal to unify these accessors on JuMPContainer/AbstractArray

@blegat blegat force-pushed the fix889 branch 2 times, most recently from cd06733 to 89fe12f Compare December 12, 2016 00:23
@joehuchette
Copy link
Contributor

Seems reasonable to me, but Travis has some pretty crazy-looking errors.

@blegat
Copy link
Member Author

blegat commented Dec 14, 2016

Wouldn't it be more consistent with getvalue if getdual outputs a warning and a vector of NaN instead of throwing an error ?

@joehuchette
Copy link
Contributor

joehuchette commented Dec 15, 2016 via email

@mlubin
Copy link
Member

mlubin commented Dec 20, 2016

@blegat, if you tidy this up this week we can get it in for 0.15.

@blegat
Copy link
Member Author

blegat commented Dec 21, 2016

@mlubin @joehuchette The PR is ready for review, the tests are passing for Julia v0.5

@joehuchette joehuchette merged commit c090df7 into jump-dev:master Dec 21, 2016
@joehuchette
Copy link
Contributor

Thanks, @blegat!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants