Skip to content

Make things work for general AbstractArrays #980

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

Merged
merged 12 commits into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/JuMP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ end
setobjective(m::Model, something::Any) =
error("in setobjective: needs three arguments: model, objective sense (:Max or :Min), and expression.")

setobjective(::Model, ::Symbol, x::Array) =
setobjective(::Model, ::Symbol, x::AbstractArray) =
error("in setobjective: array of size $(size(x)) passed as objective; only scalar objectives are allowed")

function setsolver(m::Model, solver::MathProgBase.AbstractMathProgSolver)
Expand Down Expand Up @@ -477,7 +477,7 @@ Base.zero(::Variable) = zero(Variable)
Base.one(::Type{Variable}) = AffExpr(Variable[],Float64[],1.0)
Base.one(::Variable) = one(Variable)

function verify_ownership(m::Model, vec::Vector{Variable})
function verify_ownership(m::Model, vec::AbstractVector{Variable})
n = length(vec)
@inbounds for i in 1:n
vec[i].m !== m && return false
Expand All @@ -487,7 +487,7 @@ end

Base.copy(v::Variable, new_model::Model) = Variable(new_model, v.col)
Base.copy(x::Void, new_model::Model) = nothing
function Base.copy(v::Array{Variable}, new_model::Model)
function Base.copy(v::AbstractArray{Variable}, new_model::Model)
ret = similar(v, Variable, size(v))
for I in eachindex(v)
ret[I] = Variable(new_model, v[I].col)
Expand Down Expand Up @@ -529,7 +529,7 @@ type SDConstraint <: AbstractConstraint
end

# Special-case X ≥ 0, which is often convenient
function SDConstraint(lhs::Matrix, rhs::Number)
function SDConstraint(lhs::AbstractMatrix, rhs::Number)
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

rhs == 0 || error("Cannot construct a semidefinite constraint with nonzero scalar bound $rhs")
SDConstraint(lhs)
end
Expand Down Expand Up @@ -741,12 +741,12 @@ function setRHS(c::LinConstrRef, rhs::Number)
end

Variable(m::Model,lower::Number,upper::Number,cat::Symbol,objcoef::Number,
constraints::JuMPArray,coefficients::Vector{Float64}, name::AbstractString="", value::Number=NaN) =
constraints::JuMPArray,coefficients::AbstractVector{Float64}, name::AbstractString="", value::Number=NaN) =
Variable(m, lower, upper, cat, objcoef, constraints.innerArray, coefficients, name, value)

# add variable to existing constraints
function Variable(m::Model,lower::Number,upper::Number,cat::Symbol,objcoef::Number,
constraints::Vector,coefficients::Vector{Float64}, name::AbstractString="", value::Number=NaN)
constraints::AbstractVector,coefficients::AbstractVector{Float64}, name::AbstractString="", value::Number=NaN)
for c in constraints
if !isa(c, LinConstrRef)
error("Unexpected constraint of type $(typeof(c)). Column-wise modeling only supported for linear constraints")
Expand Down Expand Up @@ -911,7 +911,7 @@ include("deprecated.jl")

getvalue{T<:JuMPTypes}(arr::Array{T}) = map(getvalue, arr)

function setvalue{T<:AbstractJuMPScalar}(set::Array{T}, val::Array)
function setvalue{T<:AbstractJuMPScalar}(set::Array{T}, val::AbstractArray)
promote_shape(size(set), size(val)) # Check dimensions match
for I in eachindex(set)
setvalue(set[I], val[I])
Expand Down
2 changes: 1 addition & 1 deletion src/affexpr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ 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})
Expand Down
8 changes: 4 additions & 4 deletions src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,17 @@ function constructconstraint!(normexpr::SOCExpr, sense::Symbol)
end
end

constructconstraint!(x::Array, sense::Symbol) = map(c->constructconstraint!(c,sense), x)
constructconstraint!(x::AbstractArray, sense::Symbol) = map(c->constructconstraint!(c,sense), x)

_vectorize_like(x::Number, y::Array{AffExpr}) = fill(x, size(y))
function _vectorize_like{R<:Number}(x::Array{R}, y::Array{AffExpr})
_vectorize_like(x::Number, y::AbstractArray{AffExpr}) = fill(x, size(y))
function _vectorize_like{R<:Number}(x::AbstractArray{R}, y::AbstractArray{AffExpr})
for i in 1:max(ndims(x),ndims(y))
size(x,i) == size(y,i) || error("Unequal sizes for ranged constraint")
end
x
end

function constructconstraint!(x::Array{AffExpr}, lb, ub)
function constructconstraint!(x::AbstractArray{AffExpr}, lb, ub)
LB = _vectorize_like(lb,x)
UB = _vectorize_like(ub,x)
ret = similar(x, LinearConstraint)
Expand Down
34 changes: 18 additions & 16 deletions src/norms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,26 @@ end
Base.copy{P,C,V}(x::GenericNorm{P,C,V}) = GenericNorm{P,C,V}(copy(x.terms))

# Handle the norm() function by flattening arguments into a vector
Base.norm{V<:AbstractJuMPScalar}(x::V, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::Array{V}, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::JuMPArray{V},p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::JuMPDict{V}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::GenericAffExpr{C,V}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::Array{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::JuMPArray{GenericAffExpr{C,V}},p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::JuMPDict{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::V, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::AbstractVector{V}, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::AbstractMatrix{V}, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::JuMPArray{V}, p::Real=2) = vecnorm(x,p)
Base.norm{V<:AbstractJuMPScalar}(x::JuMPDict{V}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::GenericAffExpr{C,V}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::AbstractVector{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::AbstractMatrix{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::JuMPArray{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)
Base.norm{C,V}(x::JuMPDict{GenericAffExpr{C,V}}, p::Real=2) = vecnorm(x,p)

_vecaff(C,V,x) = map(GenericAffExpr{C,V},vec(x))
Base.vecnorm{V<:AbstractJuMPScalar}(x::V, p::Real=2) = GenericNorm(p, [GenericAffExpr{Float64,V}(x)] )
Base.vecnorm{V<:AbstractJuMPScalar}(x::Array{V}, p::Real=2) = GenericNorm(p, _vecaff(Float64,V,x) )
Base.vecnorm{V<:AbstractJuMPScalar}(x::JuMPArray{V},p::Real=2) = GenericNorm(p, _vecaff(Float64,V,x.innerArray) )
Base.vecnorm{V<:AbstractJuMPScalar}(x::JuMPDict{V}, p::Real=2) = GenericNorm(p, _vecaff(Float64,V,collect(values(x))) )
Base.vecnorm{C,V}(x::GenericAffExpr{C,V}, p::Real=2) = GenericNorm(p, [x])
Base.vecnorm{C,V}(x::Array{GenericAffExpr{C,V}}, p::Real=2) = GenericNorm(p, vec(x))
Base.vecnorm{C,V}(x::JuMPArray{GenericAffExpr{C,V}},p::Real=2) = GenericNorm(p, vec(x.innerArray))
Base.vecnorm{C,V}(x::JuMPDict{GenericAffExpr{C,V}}, p::Real=2) = GenericNorm(p, collect(values(x)))
Base.vecnorm{V<:AbstractJuMPScalar}(x::V, p::Real=2) = GenericNorm(p, [GenericAffExpr{Float64,V}(x)] )
Base.vecnorm{V<:AbstractJuMPScalar}(x::AbstractArray{V}, p::Real=2) = GenericNorm(p, _vecaff(Float64,V,x) )
Base.vecnorm{V<:AbstractJuMPScalar}(x::JuMPArray{V}, p::Real=2) = GenericNorm(p, _vecaff(Float64,V,x.innerArray) )
Base.vecnorm{V<:AbstractJuMPScalar}(x::JuMPDict{V}, p::Real=2) = GenericNorm(p, _vecaff(Float64,V,collect(values(x))) )
Base.vecnorm{C,V}(x::GenericAffExpr{C,V}, p::Real=2) = GenericNorm(p, [x])
Base.vecnorm{C,V}(x::AbstractArray{GenericAffExpr{C,V}}, p::Real=2) = GenericNorm(p, vec(x))
Base.vecnorm{C,V}(x::JuMPArray{GenericAffExpr{C,V}}, p::Real=2) = GenericNorm(p, vec(x.innerArray))
Base.vecnorm{C,V}(x::JuMPDict{GenericAffExpr{C,V}}, p::Real=2) = GenericNorm(p, collect(values(x)))

# Called by the parseNorm macro for e.g. norm2{...}
# If the arguments are tightly typed, just pass to the constructor
Expand Down
40 changes: 20 additions & 20 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ Base.sum(j::JuMPArray) = sum(j.innerArray)
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}) = AffExpr(vec(j), ones(length(j)), 0.0)
function Base.sum{T<:GenericAffExpr}(affs::AbstractArray{T})
new_aff = zero(T)
for aff in affs
append!(new_aff, aff)
Expand Down Expand Up @@ -339,7 +339,7 @@ Base.ctranspose(x::JuMPArray) = _throw_transpose_error()

# Can remove the following code once == overloading is removed

function Base.issymmetric{T<:JuMPTypes}(x::Matrix{T})
function Base.issymmetric{T<:JuMPTypes}(x::AbstractMatrix{T})
(n = size(x,1)) == size(x,2) || return false
for i in 1:n, j in (i+1):n
isequal(x[i,j], x[j,i]) || return false
Expand All @@ -348,14 +348,14 @@ 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))
Base.diagm(x::AbstractVector{Variable}) = diagm(convert(Vector{AffExpr}, x))

###############
# The _multiply!(buf,y,z) adds the results of y*z into the buffer buf. No bounds/size
# checks are performed; it is expected that the caller has done this, has ensured
# that the eltype of buf is appropriate, and has zeroed the elements of buf (if desired).

function _multiply!{T<:JuMPTypes}(ret::Array{T}, lhs::Array, rhs::Array)
function _multiply!{T<:JuMPTypes}(ret::AbstractArray{T}, lhs::Array, rhs::Array)
Copy link
Member

Choose a reason for hiding this comment

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

@joehuchette should comment but I don't think this method was designed for AbstractArrays. The built-in fallback should work

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I don't think this part of the code will work with generic abstract arrays as-is.

m, n = size(lhs,1), size(lhs,2)
r, s = size(rhs,1), size(rhs,2)
for i ∈ 1:m, j ∈ 1:s
Expand All @@ -370,7 +370,7 @@ function _multiply!{T<:JuMPTypes}(ret::Array{T}, lhs::Array, rhs::Array)
end

# this computes lhs.'*rhs and places it in ret
function _multiplyt!{T<:JuMPTypes}(ret::Array{T}, lhs::Array, rhs::Array)
function _multiplyt!{T<:JuMPTypes}(ret::AbstractArray{T}, lhs::Array, rhs::Array)
m, n = size(lhs,2), size(lhs,1) # transpose
r, s = size(rhs,1), size(rhs,2)
for i ∈ 1:m, j ∈ 1:s
Expand All @@ -384,7 +384,7 @@ function _multiplyt!{T<:JuMPTypes}(ret::Array{T}, lhs::Array, rhs::Array)
ret
end

function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs::SparseMatrixCSC, rhs::Array)
function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::Array)
nzv = nonzeros(lhs)
rv = rowvals(lhs)
for col ∈ 1:lhs.n
Expand All @@ -398,11 +398,11 @@ function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs
end

# this computes lhs.'*rhs and places it in ret
function _multiplyt!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs::SparseMatrixCSC, rhs::Array)
function _multiplyt!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::Array)
_multiply!(ret, transpose(lhs), rhs) # TODO fully implement
end

function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs::Matrix, rhs::SparseMatrixCSC)
function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::AbstractArray{T}, lhs::Matrix, rhs::SparseMatrixCSC)
rowval = rowvals(rhs)
nzval = nonzeros(rhs)
for multivec_row in 1:size(lhs,1)
Expand All @@ -419,7 +419,7 @@ function _multiply!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs
end

# this computes lhs.'*rhs and places it in ret
function _multiplyt!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::Array{T}, lhs::Matrix, rhs::SparseMatrixCSC)
function _multiplyt!{T<:Union{GenericAffExpr,GenericQuadExpr}}(ret::AbstractArray{T}, lhs::Matrix, rhs::SparseMatrixCSC)
rowval = rowvals(rhs)
nzval = nonzeros(rhs)
for multivec_row ∈ 1:size(lhs,2) # transpose
Expand Down Expand Up @@ -448,7 +448,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)
Expand Down Expand Up @@ -485,7 +485,7 @@ _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
Expand Down Expand Up @@ -527,28 +527,28 @@ for op in [:+, :-]; @eval begin
end; end

for op in [:*, :/]; @eval begin
function $op{T<:JuMPTypes}(lhs::Number,rhs::Array{T})
function $op{T<:JuMPTypes}(lhs::Number,rhs::AbstractArray{T})
ret = Array{typeof($op(lhs, zero(T)))}(size(rhs))
for I in eachindex(ret)
ret[I] = $op(lhs, rhs[I])
end
ret
end
function $op{T<:JuMPTypes}(lhs::Array{T},rhs::Number)
function $op{T<:JuMPTypes}(lhs::AbstractArray{T},rhs::Number)
ret = Array{typeof($op(zero(T), rhs))}(size(lhs))
for I in eachindex(ret)
ret[I] = $op(lhs[I], rhs)
end
ret
end
function $op{T<:JuMPTypes,S}(lhs::T,rhs::Array{S})
function $op{T<:JuMPTypes,S}(lhs::T,rhs::AbstractArray{S})
ret = Array{typeof($op(lhs, zero(S)))}(size(rhs))
for I in eachindex(ret)
ret[I] = $op(lhs, rhs[I])
end
ret
end
function $op{T<:JuMPTypes,S}(lhs::Array{S},rhs::T)
function $op{T<:JuMPTypes,S}(lhs::AbstractArray{S},rhs::T)
ret = Array{typeof($op(zero(S), rhs))}(size(lhs))
for I in eachindex(ret)
ret[I] = $op(lhs[I], rhs)
Expand All @@ -571,7 +571,7 @@ end; end

# The following are primarily there for internal use in the macro code for @constraint
for op in [:(+), :(-)]; @eval begin
Copy link
Member

Choose a reason for hiding this comment

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

Are these methods now covered by built-ins in Julia?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Ok, thanks for checking

function $op(lhs::Array{Variable},rhs::Array{Variable})
function $op(lhs::AbstractArray{Variable},rhs::AbstractArray{Variable})
(sz = size(lhs)) == size(rhs) || error("Incompatible sizes for $op: $sz $op $(size(rhs))")
ret = Array{AffExpr}(sz)
for I in eachindex(ret)
Copy link
Member

@mlubin mlubin Feb 25, 2017

Choose a reason for hiding this comment

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

I'm concerned about the validity of using eachindex from ret to index into lhs and rhs when these could be different types.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think eachindex(ret,lhs,rhs) should work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, forgot this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed (here and in a number of other locations).

Expand Down Expand Up @@ -611,15 +611,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
Expand Down
8 changes: 4 additions & 4 deletions src/parseExpr_staged.jl
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,11 @@ for T1 in (GenericAffExpr,GenericQuadExpr), T2 in (Number,Variable,GenericAffExp
@eval addtoexpr(::$T1, ::_NLExpr, ::$T2) = _nlexprerr()
end

addtoexpr{T<:GenericAffExpr}(ex::Array{T}, c::AbstractArray, x::AbstractArray) = append!.(ex, c*x)
addtoexpr{T<:GenericAffExpr}(ex::Array{T}, c::AbstractArray, x::Number) = append!.(ex, c*x)
addtoexpr{T<:GenericAffExpr}(ex::Array{T}, c::Number, x::AbstractArray) = append!.(ex, c*x)
addtoexpr{T<:GenericAffExpr}(ex::AbstractArray{T}, c::AbstractArray, x::AbstractArray) = append!.(ex, c*x)
addtoexpr{T<:GenericAffExpr}(ex::AbstractArray{T}, c::AbstractArray, x::Number) = append!.(ex, c*x)
addtoexpr{T<:GenericAffExpr}(ex::AbstractArray{T}, c::Number, x::AbstractArray) = append!.(ex, c*x)

addtoexpr(ex, c, x) = ex + c*x
addtoexpr(ex, c, x) = ex + c*x

@generated addtoexpr_reorder(ex, arg) = :(addtoexpr(ex, 1.0, arg))

Expand Down
8 changes: 4 additions & 4 deletions src/print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ end

# TODO: get rid of this! This is only a helper, and should be Base.values
# (and probably live there, as well)
_values(x::Array) = x
_values(x::AbstractArray) = x
Copy link
Member

Choose a reason for hiding this comment

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

Where is this used and why does it need to change?

_values(x) = Base.values(x)

# REPL-specific symbols
Expand Down Expand Up @@ -103,7 +103,7 @@ math(s,mathmode) = mathmode ? s : "\$\$ $s \$\$"
# helper to look up corresponding JuMPContainerData
printdata(v::JuMPContainer) = _getmodel(v).varData[v]
getname(x::JuMPContainer) = hasmeta(x, :model) ? printdata(x).name : "__anon__"
function printdata(v::Array{Variable})
function printdata(v::AbstractArray{Variable})
Copy link
Member

Choose a reason for hiding this comment

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

Are you redefining printing for AbstractArray{Variable}? If not, this doesn't need to be touched

if isempty(v)
error("Cannot locate printing data for an empty array")
end
Expand Down Expand Up @@ -344,7 +344,7 @@ function fill_var_names(mode, colNames, v::JuMPDict{Variable})
end
end
end
function fill_var_names(mode, colNames, v::Array{Variable})
function fill_var_names(mode, colNames, v::AbstractArray{Variable})
isempty(v) && return
sizes = size(v)
m = first(v).m
Expand Down Expand Up @@ -400,7 +400,7 @@ Base.show(io::IO, ::MIME"text/latex", j::Union{JuMPContainer{Variable},Array{Var
# Generic string converter, called by mode-specific handlers

# Assumes that !isempty(j)
_getmodel(j::Array{Variable}) = first(j).m
_getmodel(j::AbstractArray{Variable}) = first(j).m
_getmodel(j::JuMPContainer) = getmeta(j, :model)

function cont_str(mode, j, sym::PrintSymbols)
Expand Down
4 changes: 2 additions & 2 deletions src/quadexpr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ 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})
function addVectorizedConstraint(m::Model, v::AbstractArray{QuadConstraint})
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 QuadConstraint that didn't already pass or call this unexported function directly, so I changed it back to Array.

ret = Array{ConstraintRef{Model,QuadConstraint}}(size(v))
for I in eachindex(v)
ret[I] = addconstraint(m, v[I])
Expand Down
4 changes: 2 additions & 2 deletions src/sos.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ end

addSOS1(m::Model, coll) = addSOS1(m, convert(Vector{AffExpr}, coll))

function addSOS1(m::Model, coll::Vector{AffExpr})
function addSOS1(m::Model, coll::AbstractVector{AffExpr})
Copy link
Member

Choose a reason for hiding this comment

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

Not covered by tests. This method calls constructSOS which is defined for Vector{AffExpr}.

Copy link
Member

Choose a reason for hiding this comment

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

Also doesn't seem necessary for your use case

vars, weight = constructSOS(m,coll)
push!(m.sosconstr, SOSConstraint(vars, weight, :SOS1))
if m.internalModelLoaded
Expand All @@ -59,7 +59,7 @@ end

addSOS2(m::Model, coll) = addSOS2(m, convert(Vector{AffExpr}, coll))

function addSOS2(m::Model, coll::Vector{AffExpr})
function addSOS2(m::Model, coll::AbstractVector{AffExpr})
vars, weight = constructSOS(m,coll)
push!(m.sosconstr, SOSConstraint(vars, weight, :SOS2))
if m.internalModelLoaded
Expand Down
9 changes: 9 additions & 0 deletions test/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -976,4 +976,13 @@ end
@test isnan(getdual(x))
end

@testset "Constraints with non-Array AbstractArrays" begin
m = Model()
x = sparse(@variable(m, [1: 3]))
@constraint(m, x + x[1] .== 0)
@constraint(m, x - x[1] .== 0)
@constraint(m, (x + 1) + x[1] .== 0)
@constraint(m, (x + 1) - x[1] .== 0)
end

end