Skip to content

Commit

Permalink
Parameterize Constant on the type of its value
Browse files Browse the repository at this point in the history
This allows for more expressive condition checking using dispatch, as
complex numbers, real numbers, or arrays thereof can be handled as
separate methods.

This also limits the types that can be accepted as constant values to
scalars, vectors, and matrices. Previously this was assumed but not
actually checked.
  • Loading branch information
ararslan committed Jan 8, 2019
1 parent cd08c70 commit 7e60564
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 33 deletions.
59 changes: 26 additions & 33 deletions src/constant.jl
Expand Up @@ -5,54 +5,47 @@
export Constant
export vexity, evaluate, sign, conic_form!

struct Constant <: AbstractExpr
const ComplexValue = Union{Complex,AbstractVecOrMat{<:Complex}}

_size(x::Number) = (1, 1)
_size(x::AbstractVector) = (length(x), 1)
_size(x::AbstractMatrix) = size(x)

_sign(x::ComplexValue) = ComplexSign()
_sign(x::Number) = x >= 0 ? Positive() : Negative()
_sign(v::AbstractVecOrMat) = all(x->x >= 0, v) ? Positive() : Negative()

struct Constant{T<:Value} <: AbstractExpr
head::Symbol
id_hash::UInt64
value::Value
value::T
size::Tuple{Int, Int}
vexity::Vexity
sign::Sign

function Constant(x::Value, sign::Sign)
sz = (size(x, 1), size(x, 2))
return new(:constant, objectid(x), x, sz, ConstVexity(), sign)
function Constant(x::T, sign::Union{ComplexSign,NoSign}) where T<:ComplexValue
new{T}(:constant, objectid(x), x, _size(x), sign)
end

function Constant(x::Value, check_sign::Bool=true)
if check_sign
if !isreal(x)
return Constant(x, ComplexSign())
elseif all(xi >= 0 for xi in x)
return Constant(x, Positive())
elseif all(xi <= 0 for xi in x)
return Constant(x, Negative())
end
end
return Constant(x, NoSign())
function Constant(x::T, sign::Union{Positive,Negative,NoSign}) where T<:Value
new{T}(:constant, objectid(x), x, _size(x), sign)
end
end
#### Constant Definition end #####

function vexity(x::Constant)
return x.vexity
Constant(x::Value, check_sign::Bool=true) = Constant(x, check_sign ? _sign(x) : NoSign())
end

function evaluate(x::Constant)
return x.value
end
#### Constant Definition end #####

function sign(x::Constant)
return x.sign
end
vexity(::Constant) = ConstVexity()

evaluate(x::Constant) = x.value

function real_conic_form(x::Constant)
return vec([real(x.value);])
end
sign(x::Constant) = x.sign

function imag_conic_form(x::Constant)
return im*vec([imag(x.value);])
end
real_conic_form(x::Constant{<:Number}) = [real(x.value)]
real_conic_form(x::Constant{<:AbstractVecOrMat}) = vec(real(x.value))

imag_conic_form(x::Constant{<:Number}) = [im * imag(x.value)]
imag_conic_form(x::Constant{<:AbstractVecOrMat}) = im * vec(imag(x.value))

# We can more efficiently get the length of a constant by asking for the length of its
# value, which Julia can get via Core.arraylen for arrays and knows is 1 for scalars
Expand Down
15 changes: 15 additions & 0 deletions test/test_utilities.jl
Expand Up @@ -42,6 +42,21 @@
@test size(y) == (2, 1)
end

@testset "Parametric constants" begin
z = Constant([1.0 0.0im; 0.0 1.0])
@test z isa Constant{Matrix{Complex{Float64}}}

# Helper functions
@test Convex._size(3) == (1, 1)
@test Convex._sign(3) == Positive()
@test Convex._size([-1,1,1]) == (3, 1)
@test Convex._sign([-1,1,1]) == Negative()
@test Convex._size([0 0; 0 0]) == (2, 2)
@test Convex._sign([0 0; 0 0]) == Positive()
@test Convex._size(0+1im) == (1, 1)
@test Convex._sign(0+1im) == ComplexSign()
end

# returns [21]; not sure why
# context("iteration") do
# x = Variable(2,3)
Expand Down

0 comments on commit 7e60564

Please sign in to comment.