-
-
Notifications
You must be signed in to change notification settings - Fork 397
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
Make things work for general AbstractArray
s
#980
Changes from 10 commits
b87c015
6306e2c
ae06063
722fd26
553981a
035cfe9
5776b09
5c300c4
a8e0ab9
46b5548
2254e20
bded621
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 |
---|---|---|
|
@@ -181,13 +181,15 @@ function addconstraint(m::Model, c::LinearConstraint) | |
end | ||
return LinConstrRef(m,length(m.linconstr)) | ||
end | ||
addconstraint(m::Model, c::Array{LinearConstraint}) = | ||
addconstraint(m::Model, c::AbstractArray{LinearConstraint}) = | ||
error("The operators <=, >=, and == can only be used to specify scalar constraints. If you are trying to add a vectorized constraint, use the element-wise dot comparison operators (.<=, .>=, or .==) instead") | ||
|
||
function addVectorizedConstraint(m::Model, v::Array{LinearConstraint}) | ||
ret = Array{LinConstrRef}(size(v)) | ||
for I in eachindex(v) | ||
ret[I] = addconstraint(m, v[I]) | ||
function addVectorizedConstraint(m::Model, v::AbstractArray{LinearConstraint}) | ||
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. This is an internal function, it's unclear how it could be called with an 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. I'm somewhat uncertain if this method should be changed. Is there a compelling reason to pass a sparse matrix of linear constraints, for example? 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. Without changing this method, the following fails: m = Model()
v = @variable(m, [1:3])
x = OffsetArray(v, -3)
@constraint(m, x .== 0) because there is no 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. This doesn't seem like the right fix. I think 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. Since this also doesn't work: t = OffsetArray(rand(3), -3)
t .== 0 I'm not sure this is desirable behavior. 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. OK, will change. @joehuchette, that seems like a bug in Base. 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. Done. |
||
# Can't use map! because map! for sparse vectors needs zero to be defined for | ||
# JuMP.GenericRangeConstraint{JuMP.GenericAffExpr{Float64,JuMP.Variable}} on 0.6 | ||
ret = similar(v, LinConstrRef) | ||
for i in eachindex(v) | ||
ret[i] = addconstraint(m, v[i]) | ||
end | ||
ret | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -277,7 +277,8 @@ Base.sum(j::JuMPDict) = sum(values(j.tupledict)) | |
Base.sum(j::JuMPArray{Variable}) = AffExpr(vec(j.innerArray), ones(length(j.innerArray)), 0.0) | ||
Base.sum(j::JuMPDict{Variable}) = AffExpr(collect(values(j.tupledict)), ones(length(j.tupledict)), 0.0) | ||
Base.sum(j::Array{Variable}) = AffExpr(vec(j), ones(length(j)), 0.0) | ||
function Base.sum{T<:GenericAffExpr}(affs::Array{T}) | ||
Base.sum(j::AbstractArray{Variable}) = sum([j[i] for i in eachindex(j)]) # to handle non-one-indexed arrays. | ||
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. As long as 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. I tried that first, but 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. Cool, thanks for the explanation. |
||
function Base.sum{T<:GenericAffExpr}(affs::AbstractArray{T}) | ||
new_aff = zero(T) | ||
for aff in affs | ||
append!(new_aff, aff) | ||
|
@@ -348,7 +349,10 @@ function Base.issymmetric{T<:JuMPTypes}(x::Matrix{T}) | |
end | ||
|
||
# Special-case because the the base version wants to do fill!(::Array{Variable}, zero(AffExpr)) | ||
Base.diagm(x::Vector{Variable}) = diagm(convert(Vector{AffExpr}, x)) | ||
function Base.diagm(x::AbstractVector{Variable}) | ||
@assert one_indexed(x) # Base.diagm doesn't work for non-one-indexed arrays in general. | ||
diagm(copy!(similar(x, AffExpr), x)) | ||
end | ||
|
||
############### | ||
# The _multiply!(buf,y,z) adds the results of y*z into the buffer buf. No bounds/size | ||
|
@@ -448,7 +452,7 @@ _multiply!(ret, lhs, rhs) = A_mul_B!(ret, lhs, ret) | |
|
||
import Base.At_mul_B | ||
import Base.Ac_mul_B | ||
# these methods are called when one does A.'*v or A'*v respectively | ||
# these methods are called when one does A.'*v or A'*v respectively | ||
At_mul_B{T<:JuMPTypes}(A::Union{Matrix{T},SparseMatrixCSC{T}}, x::Union{Matrix, Vector, SparseMatrixCSC}) = _matmult(A, x) | ||
At_mul_B{T<:JuMPTypes,R<:JuMPTypes}(A::Union{Matrix{T},SparseMatrixCSC{T}}, x::Union{Matrix{R}, Vector{R}, SparseMatrixCSC{R}}) = _matmult(A, x) | ||
At_mul_B{T<:JuMPTypes}(A::Union{Matrix,SparseMatrixCSC}, x::Union{Matrix{T}, Vector{T}, SparseMatrixCSC{T}}) = _matmult(A, x) | ||
|
@@ -485,40 +489,37 @@ _return_arrayt{R,S}(A::AbstractMatrix{R}, x::AbstractVector{S}) = _fillwithzeros | |
_return_arrayt{R,S}(A::AbstractMatrix{R}, x::AbstractMatrix{S}) = _fillwithzeros(Array{_multiply_type(R,S)}(size(A,2), size(x, 2))) | ||
|
||
# helper so we don't fill the buffer array with the same object | ||
function _fillwithzeros{T}(arr::Array{T}) | ||
function _fillwithzeros{T}(arr::AbstractArray{T}) | ||
for I in eachindex(arr) | ||
arr[I] = zero(T) | ||
end | ||
arr | ||
end | ||
|
||
# Let's be conservative and only define arithmetic for the basic types | ||
typealias ArrayOrSparseMat{T} Union{Array{T}, SparseMatrixCSC{T}} | ||
|
||
for op in [:+, :-]; @eval begin | ||
function $op{T<:JuMPTypes}(lhs::Number,rhs::ArrayOrSparseMat{T}) | ||
ret = Array{typeof($op(lhs, zero(T)))}(size(rhs)) | ||
function $op{T<:JuMPTypes}(lhs::Number,rhs::AbstractArray{T}) | ||
ret = similar(rhs, typeof($op(lhs, zero(T)))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs, rhs[I]) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes}(lhs::ArrayOrSparseMat{T},rhs::Number) | ||
ret = Array{typeof($op(zero(T), rhs))}(size(lhs)) | ||
function $op{T<:JuMPTypes}(lhs::AbstractArray{T},rhs::Number) | ||
ret = similar(lhs, typeof($op(zero(T), rhs))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs[I], rhs) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes,S}(lhs::T,rhs::ArrayOrSparseMat{S}) | ||
ret = Array{typeof($op(lhs, zero(S)))}(size(rhs)) | ||
function $op{T<:JuMPTypes,S}(lhs::T,rhs::AbstractArray{S}) | ||
ret = similar(rhs, typeof($op(lhs, zero(S)))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs, rhs[I]) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes,S}(lhs::ArrayOrSparseMat{S},rhs::T) | ||
ret = Array{typeof($op(zero(S), rhs))}(size(lhs)) | ||
function $op{T<:JuMPTypes,S}(lhs::AbstractArray{S},rhs::T) | ||
ret = similar(lhs, typeof($op(zero(S), rhs))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs[I], rhs) | ||
end | ||
|
@@ -527,29 +528,29 @@ for op in [:+, :-]; @eval begin | |
end; end | ||
|
||
for op in [:*, :/]; @eval begin | ||
function $op{T<:JuMPTypes}(lhs::Number,rhs::Array{T}) | ||
ret = Array{typeof($op(lhs, zero(T)))}(size(rhs)) | ||
function $op{T<:JuMPTypes}(lhs::Number,rhs::AbstractArray{T}) | ||
ret = similar(rhs, typeof($op(lhs, zero(T)))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs, rhs[I]) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes}(lhs::Array{T},rhs::Number) | ||
ret = Array{typeof($op(zero(T), rhs))}(size(lhs)) | ||
function $op{T<:JuMPTypes}(lhs::AbstractArray{T},rhs::Number) | ||
ret = similar(lhs, typeof($op(zero(T), rhs))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs[I], rhs) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes,S}(lhs::T,rhs::Array{S}) | ||
ret = Array{typeof($op(lhs, zero(S)))}(size(rhs)) | ||
function $op{T<:JuMPTypes,S}(lhs::T,rhs::AbstractArray{S}) | ||
ret = similar(rhs, typeof($op(lhs, zero(S)))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs, rhs[I]) | ||
end | ||
ret | ||
end | ||
function $op{T<:JuMPTypes,S}(lhs::Array{S},rhs::T) | ||
ret = Array{typeof($op(zero(S), rhs))}(size(lhs)) | ||
function $op{T<:JuMPTypes,S}(lhs::AbstractArray{S},rhs::T) | ||
ret = similar(lhs, typeof($op(zero(S), rhs))) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs[I], rhs) | ||
end | ||
|
@@ -569,18 +570,6 @@ end; end | |
(/){T<:JuMPTypes}(lhs::SparseMatrixCSC{T}, rhs::Number) = | ||
SparseMatrixCSC(lhs.m, lhs.n, copy(lhs.colptr), copy(lhs.rowval), lhs.nzval ./ rhs) | ||
|
||
# The following are primarily there for internal use in the macro code for @constraint | ||
for op in [:(+), :(-)]; @eval begin | ||
function $op(lhs::Array{Variable},rhs::Array{Variable}) | ||
(sz = size(lhs)) == size(rhs) || error("Incompatible sizes for $op: $sz $op $(size(rhs))") | ||
ret = Array{AffExpr}(sz) | ||
for I in eachindex(ret) | ||
ret[I] = $op(lhs[I], rhs[I]) | ||
end | ||
ret | ||
end | ||
end; end | ||
|
||
for (dotop,op) in [(:.+,:+), (:.-,:-), (:.*,:*), (:./,:/)] | ||
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. Are these methods now covered by built-ins in Julia? 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. 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. Ok, thanks for checking |
||
@eval begin | ||
$dotop(lhs::Number,rhs::JuMPTypes) = $op(lhs,rhs) | ||
|
@@ -611,15 +600,15 @@ for (dotop,op) in [(:.+,:+), (:.-,:-), (:.*,:*), (:./,:/)] | |
end | ||
|
||
|
||
(+){T<:JuMPTypes}(x::Array{T}) = x | ||
function (-){T<:JuMPTypes}(x::Array{T}) | ||
(+){T<:JuMPTypes}(x::AbstractArray{T}) = x | ||
function (-){T<:JuMPTypes}(x::AbstractArray{T}) | ||
ret = similar(x, typeof(-one(T))) | ||
for I in eachindex(ret) | ||
ret[I] = -x[I] | ||
end | ||
ret | ||
end | ||
(*){T<:JuMPTypes}(x::Array{T}) = x | ||
(*){T<:JuMPTypes}(x::AbstractArray{T}) = x | ||
|
||
############################################################################### | ||
# Add nonlinear function fallbacks for JuMP built-in types | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,13 +149,15 @@ function addconstraint(m::Model, c::QuadConstraint) | |
end | ||
return ConstraintRef{Model,QuadConstraint}(m,length(m.quadconstr)) | ||
end | ||
addconstraint(m::Model, c::Array{QuadConstraint}) = | ||
addconstraint(m::Model, c::AbstractArray{QuadConstraint}) = | ||
error("Vectorized constraint added without elementwise comparisons. Try using one of (.<=,.>=,.==).") | ||
|
||
function addVectorizedConstraint(m::Model, v::Array{QuadConstraint}) | ||
ret = Array{ConstraintRef{Model,QuadConstraint}}(size(v)) | ||
for I in eachindex(v) | ||
ret[I] = addconstraint(m, v[I]) | ||
function addVectorizedConstraint(m::Model, v::AbstractArray{QuadConstraint}) | ||
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. This change is not covered by tests. 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. I wasn't able to construct a test case involving nonstandard arrays of |
||
# Can't use map! because map! for sparse vectors needs zero to be defined for | ||
# JuMP.GenericRangeConstraint{JuMP.GenericAffExpr{Float64,JuMP.Variable}} on 0.6 | ||
ret = similar(v, ConstraintRef{Model,QuadConstraint}) | ||
for i in eachindex(v) | ||
ret[i] = addconstraint(m, v[i]) | ||
end | ||
ret | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ GLPKMathProgInterface | |
Ipopt | ||
ECOS | ||
SCS | ||
OffsetArrays 0.2.13 |
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 change is not covered by tests.
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.
Fixed.