Skip to content

Commit

Permalink
1.0 now passes
Browse files Browse the repository at this point in the history
  • Loading branch information
ExpandingMan committed Aug 21, 2018
1 parent 503b104 commit 217e8cb
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 80 deletions.
172 changes: 100 additions & 72 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -288,30 +288,17 @@ end
# Base Julia's generic fallback vecdot requires that dot be defined
# for scalars, so instead of defining them one-by-one, we will
# fallback to the multiplication operator
LinearAlgebra.dot(lhs::JuMPTypes, rhs::JuMPTypes) = lhs*rhs
LinearAlgebra.dot(lhs::JuMPTypes, rhs::Number) = lhs*rhs
LinearAlgebra.dot(lhs::Number, rhs::JuMPTypes) = lhs*rhs

LinearAlgebra.dot(lhs::AbstractArray{T,N}, rhs::JuMPArray{S,N}) where {T,S,N} = vecdot(lhs,rhs)
LinearAlgebra.dot(lhs::JuMPArray{T,N},rhs::AbstractArray{S,N}) where {T,S,N} = vecdot(lhs,rhs)
LinearAlgebra.dot(lhs::JuMPArray{T,N},rhs::JuMPArray{S,N}) where {T,S,N} = vecdot(lhs,rhs)
LinearAlgebra.dot(lhs::AbstractArray{T,N}, rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S,N} = vecdot(lhs,rhs)
LinearAlgebra.dot(lhs::AbstractArray{T,N}, rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S<:JuMPTypes,N} = vecdot(lhs,rhs)
LinearAlgebra.dot(lhs::AbstractArray{T,N}, rhs::AbstractArray{S,N}) where {T,S<:JuMPTypes,N} = vecdot(lhs,rhs)

LinearAlgebra.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T<:JuMPTypes,S<:JuMPTypes} = _dot(lhs,rhs)
LinearAlgebra.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T<:JuMPTypes,S} = _dot(lhs,rhs)
LinearAlgebra.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T,S<:JuMPTypes} = _dot(lhs,rhs)

if VERSION < v"0.7-"
LinearAlgebra.vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S,N} = _dot(lhs,rhs)
LinearAlgebra.vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S<:JuMPTypes,N} = _dot(lhs,rhs)
LinearAlgebra.vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T,S<:JuMPTypes,N} = _dot(lhs,rhs)
else
vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S,N} = _dot(lhs,rhs)
vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S<:JuMPTypes,N} = _dot(lhs,rhs)
vecdot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T,S<:JuMPTypes,N} = _dot(lhs,rhs)
end
Compat.LinearAlgebra.dot(lhs::JuMPTypes, rhs::JuMPTypes) = lhs*rhs
Compat.LinearAlgebra.dot(lhs::JuMPTypes, rhs::Number) = lhs*rhs
Compat.LinearAlgebra.dot(lhs::Number, rhs::JuMPTypes) = lhs*rhs

Compat.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T<:JuMPTypes,S<:JuMPTypes} = _dot(lhs,rhs)
Compat.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T<:JuMPTypes,S} = _dot(lhs,rhs)
Compat.dot(lhs::AbstractVector{T},rhs::AbstractVector{S}) where {T,S<:JuMPTypes} = _dot(lhs,rhs)

Compat.dot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S<:JuMPTypes,N} = _dot(lhs,rhs)
Compat.dot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T<:JuMPTypes,S,N} = _dot(lhs,rhs)
Compat.dot(lhs::AbstractArray{T,N},rhs::AbstractArray{S,N}) where {T,S<:JuMPTypes,N} = _dot(lhs,rhs)

function _dot(lhs::AbstractArray{T}, rhs::AbstractArray{S}) where {T,S}
size(lhs) == size(rhs) || error("Incompatible dimensions")
Expand Down Expand Up @@ -340,7 +327,7 @@ Compat.adjoint(x::JuMPArray) = _throw_transpose_error()

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

function LinearAlgebra.issymmetric(x::Matrix{T}) where T<:JuMPTypes
function Compat.LinearAlgebra.issymmetric(x::Matrix{T}) where T<:JuMPTypes
(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 @@ -349,7 +336,7 @@ function LinearAlgebra.issymmetric(x::Matrix{T}) where T<:JuMPTypes
end

# Special-case because the the base version wants to do fill!(::Array{Variable}, zero(AffExpr))
function LinearAlgebra.diagm(x::AbstractVector{Variable})
function Compat.LinearAlgebra.diagm(x::AbstractVector{Variable})
@assert one_indexed(x) # Base.diagm doesn't work for non-one-indexed arrays in general.
diagm(copyto!(similar(x, AffExpr), x))
end
Expand All @@ -359,6 +346,21 @@ end
# 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).

# this is a generic fallback
function _multiply!(ret::Array{T}, lhs::Array, rhs::Array) where T
#@warn("A terrible fallback is being called!") # occasionally check for this in testing
m, n = size(lhs,1), size(lhs,2)
r, s = size(rhs,1), size(rhs,2)
for i 1:m, j 1:s
for k 1:n
tmp = convert(T, lhs[i,k]*rhs[k,j])
ret[i,j] += tmp
end
end
ret
end


function _multiply!(ret::Array{T}, lhs::Array, rhs::Array) where T<:JuMPTypes
m, n = size(lhs,1), size(lhs,2)
r, s = size(rhs,1), size(rhs,2)
Expand Down Expand Up @@ -440,9 +442,22 @@ function _multiplyt!(ret::Array{T}, lhs::Matrix, rhs::SparseMatrixCSC) where T<:
end


function Base.Matrix(S::SparseMatrixCSC{V}) where V<:Variable
A = zeros(GenericAffExpr{Float64, V}, S.m, S.n)
for Sj 1:S.n
for Sk nzrange(S, Sj)
Si = S.rowval[Sk]
Sv = S.nzval[Sk]
A[Si, Sj] = Sv
end
end
A
end


# TODO: implement sparse * sparse code as in base/sparse/linalg.jl (spmatmul)
_multiply!(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::SparseMatrixCSC) where {T<:JuMPTypes} = _multiply!(ret, lhs, Array(rhs))
_multiplyt!(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::SparseMatrixCSC) where {T<:JuMPTypes} = _multiplyt!(ret, lhs, Array(rhs))
_multiply!(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::SparseMatrixCSC) where {T<:JuMPTypes} = _multiply!(ret, lhs, Matrix(rhs))
_multiplyt!(ret::AbstractArray{T}, lhs::SparseMatrixCSC, rhs::SparseMatrixCSC) where {T<:JuMPTypes} = _multiplyt!(ret, lhs, Matrix(rhs))

function Base.:*(A::Union{Matrix{T},SparseMatrixCSC{T}},
x::Union{Matrix,Vector,SparseMatrixCSC}) where {T<:JuMPTypes}
Expand All @@ -453,46 +468,11 @@ function Base.:*(A::Union{Matrix{T},SparseMatrixCSC{T}},
_matmul(A, x)
end
function Base.:*(A::Union{Matrix,SparseMatrixCSC},
x::Union{Matrix{T},Vector{T},SparseMatrixCSC{T}}) where {T<:JuMPTypes}
x::Union{Matrix{T},Vector{T},SparseMatrixCSC{T}}) where {T<:JuMPTypes}
_matmul(A, x)
end


function _matmul(A, x)
m, n = size(A,1), size(A,2)
r, s = size(x,1), size(x,2)
n == r || error("Incompatible sizes")
ret = _return_array(A, x)
_multiply!(ret, A, x)
ret
end

function _matmult(A, x)
m, n = size(A,2), size(A,1) # transpose
r, s = size(x,1), size(x,2)
n == r || error("Incompatible sizes")
ret = _return_arrayt(A, x)
_multiplyt!(ret, A, x)
ret
end

# See https://github.com/JuliaLang/julia/pull/18218
_matprod_type(R, S) = typeof(one(R) * one(S) + one(R) * one(S))
# Don't do size checks here in _return_array, defer that to (*)
_return_array(A::AbstractMatrix{R}, x::AbstractVector{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,1)))
_return_array(A::AbstractMatrix{R}, x::AbstractMatrix{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,1), size(x,2)))
# these are for transpose return matrices
_return_arrayt(A::AbstractMatrix{R}, x::AbstractVector{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,2)))
_return_arrayt(A::AbstractMatrix{R}, x::AbstractMatrix{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,2), size(x, 2)))

# helper so we don't fill the buffer array with the same object
function _fillwithzeros(arr::AbstractArray{T}) where T
for I in eachindex(arr)
arr[I] = zero(T)
end
arr
end

for op in [:+, :-]; @eval begin
function Base.$op(lhs::Number,rhs::AbstractArray{T}) where T<:JuMPTypes
ret = similar(rhs, typeof($op(lhs, zero(T))))
Expand Down Expand Up @@ -632,11 +612,20 @@ if VERSION ≥ v"0.7-"
ret = _return_arrayt(A, x)
return mul!(ret, transpose(A), x)
end
# WARNING these are inefficient fallbacks
function Base.:*(adjA::Adjoint{<:JuMPTypes,<:SparseMatrixCSC},
x::SparseMatrixCSC)
# WARNING this is an inefficient hack
adjA * Array(x)
adjA * Matrix(x)
end
function Base.:*(adjA::Transpose{<:JuMPTypes,<:SparseMatrixCSC},
x::SparseMatrixCSC)
adjA * Matrix(x)
end
#function Base.:*(adjA::Adjoint{<:JuMPTypes,<:SparseMatrixCSC},
# x::SparseMatrixCSC)
# # WARNING this is an inefficient hack
# adjA * Array(x)
#end
# mul! is adapted from upstream Julia.
#=
> Copyright (c) 2009-2018: Jeff Bezanson, Stefan Karpinski, Viral B. Shah,
Expand Down Expand Up @@ -702,26 +691,65 @@ else
Base.Ac_mul_B(A::Union{Matrix,SparseMatrixCSC}, x::Union{Matrix{T}, Vector{T}, SparseMatrixCSC{T}}) where {T<:JuMPTypes} = _matmult(A, x)
end

function _matmul(A, x)
m, n = size(A,1), size(A,2)
r, s = size(x,1), size(x,2)
n == r || error("Incompatible sizes")
ret = _return_array(A, x)
_multiply!(ret, A, x)
ret
end

function _matmult(A, x)
m, n = size(A,2), size(A,1) # transpose
r, s = size(x,1), size(x,2)
n == r || error("Incompatible sizes")
ret = _return_arrayt(A, x)
_multiplyt!(ret, A, x)
ret
end

# See https://github.com/JuliaLang/julia/pull/18218
_matprod_type(R, S) = typeof(one(R) * one(S) + one(R) * one(S))
# Don't do size checks here in _return_array, defer that to (*)
_return_array(A::AbstractMatrix{R}, x::AbstractVector{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,1)))
_return_array(A::AbstractMatrix{R}, x::AbstractMatrix{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,1), size(x,2)))
# these are for transpose return matrices
_return_arrayt(A::AbstractMatrix{R}, x::AbstractVector{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,2)))
_return_arrayt(A::AbstractMatrix{R}, x::AbstractMatrix{S}) where {R,S} = _fillwithzeros(Array{_matprod_type(R,S)}(undef, size(A,2), size(x, 2)))

# helper so we don't fill the buffer array with the same object
function _fillwithzeros(arr::AbstractArray{T}) where T
for I in eachindex(arr)
arr[I] = zero(T)
end
arr
end

# Special-case sparse matrix scalar multiplication/division
Base.:*(lhs::Number, rhs::SparseMatrixCSC{T}) where {T<:JuMPTypes} =
SparseMatrixCSC(rhs.m, rhs.n, copy(rhs.colptr), copy(rhs.rowval), lhs .* rhs.nzval)
Base.:*(lhs::JuMPTypes, rhs::SparseMatrixCSC) =
SparseMatrixCSC(rhs.m, rhs.n, copy(rhs.colptr), copy(rhs.rowval), lhs * rhs.nzval)
SparseMatrixCSC(rhs.m, rhs.n, copy(rhs.colptr), copy(rhs.rowval), lhs .* rhs.nzval)
Base.:*(lhs::SparseMatrixCSC{T}, rhs::Number) where {T<:JuMPTypes} =
SparseMatrixCSC(lhs.m, lhs.n, copy(lhs.colptr), copy(lhs.rowval), lhs.nzval .* rhs)
Base.:*(lhs::SparseMatrixCSC, rhs::JuMPTypes) =
SparseMatrixCSC(lhs.m, lhs.n, copy(lhs.colptr), copy(lhs.rowval), lhs.nzval .* rhs)
Base.:/(lhs::SparseMatrixCSC{T}, rhs::Number) where {T<:JuMPTypes} =
SparseMatrixCSC(lhs.m, lhs.n, copy(lhs.colptr), copy(lhs.rowval), lhs.nzval ./ rhs)

for (op,opsymbol) in [(+,:+), (-,:-), (*,:*), (/,:/)]
@eval begin
Base.broadcast(::typeof($op),lhs::Number,rhs::JuMPTypes) = $opsymbol(lhs,rhs)
Base.broadcast(::typeof($op),lhs::JuMPTypes,rhs::Number) = $opsymbol(lhs,rhs)
if VERSION v"0.7-"
Base.BroadcastStyle(::Type{<:JuMPTypes}) = Base.Broadcast.DefaultArrayStyle{0}()
Base.broadcastable(x::JuMPTypes) = fill(x, ())
else
for (op,opsymbol) in [(+,:+), (-,:-), (*,:*), (/,:/)]
@eval begin
Base.broadcast(::typeof($op),lhs::Number,rhs::JuMPTypes) = $opsymbol(lhs,rhs)
Base.broadcast(::typeof($op),lhs::JuMPTypes,rhs::Number) = $opsymbol(lhs,rhs)
end
end
end


Base.:+(x::AbstractArray{T}) where {T<:JuMPTypes} = x
function Base.:-(x::AbstractArray{T}) where T<:JuMPTypes
ret = similar(x, typeof(-one(T)))
Expand Down
4 changes: 1 addition & 3 deletions src/parseExpr_staged.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,7 @@ addtoexpr(ex::AbstractArray{T}, c::AbstractArray, x::AbstractArray) where {T<:Ge
addtoexpr(ex::AbstractArray{T}, c::AbstractArray, x::Number) where {T<:GenericAffExpr} = append!.(ex, c*x)
addtoexpr(ex::AbstractArray{T}, c::Number, x::AbstractArray) where {T<:GenericAffExpr} = append!.(ex, c*x)

addtoexpr(ex::Number, c::Number, x::AbstractArray) = 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
2 changes: 1 addition & 1 deletion test/fuzzer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
using JuMP, Compat.Test
using JuMP, Compat.Test, Compat, Compat.Random

function random_aff_expr(N, vars::Vector)
ex = Expr(:call, :+)
Expand Down
15 changes: 12 additions & 3 deletions test/operator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ Base.transpose(t::MySumType) = MySumType(t.a)
*(t1::MyType{S}, t2::T) where {S, T} = MyType(t1.a*t2)
*(t1::S, t2::MyType{T}) where {S, T} = MyType(t1*t2.a)
*(t1::MyType{S}, t2::MyType{T}) where {S, T} = MyType(t1.a*t2.a)
if VERSION v"0.7-"
Base.adjoint(t::MyType) = t
Base.adjoint(t::MySumType) = t
Base.convert(::Type{MySumType{T}}, t::MyType{T}) where {T} = MySumType(t.a)
end


#@testset "Operator overloads" begin
@testset "Operator overloads" begin

_lt(x,y) = (x.col < y.col)
function sort_expr!(x::AffExpr)
Expand Down Expand Up @@ -878,7 +883,11 @@ Base.transpose(t::MySumType) = MySumType(t.a)
ElemT = MySumType{JuMP.GenericAffExpr{Float64,JuMP.Variable}}
@test typeof(y) == Vector{ElemT}
@test size(y) == (3,)
@test typeof(z) == (isdefined(Base, :RowVector) ? RowVector{ElemT, ConjArray{ElemT, 1, Vector{ElemT}}} : Matrix{ElemT})
if VERSION v"0.7-"
@test typeof(z) == (isdefined(Base, :RowVector) ? RowVector{ElemT, ConjArray{ElemT, 1, Vector{ElemT}}} : Matrix{ElemT})
else
@test typeof(z) == Adjoint{ElemT,Vector{ElemT}}
end
@test size(z) == (1, 3)
for i in 1:3
# Q is symmetric
Expand All @@ -890,4 +899,4 @@ Base.transpose(t::MySumType) = MySumType(t.a)
@test z[i].a == y[i].a == a
end
end
#end
end
2 changes: 1 addition & 1 deletion test/print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ end
A = [2.0 0.0;
0.0 1.0]
@variable(m, X[1:2,1:2], SDP)
s = @SDconstraint(m, X >= A)
s = @SDconstraint(m, X .>= A)
io_test(REPLMode, s, " X[1,1] - 2 X[1,2] is semidefinite\n X[1,2] X[2,2] - 1")
end

Expand Down

0 comments on commit 217e8cb

Please sign in to comment.