diff --git a/src/constant.jl b/src/constant.jl index ec1dddbf4..d1a09765d 100644 --- a/src/constant.jl +++ b/src/constant.jl @@ -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 diff --git a/test/test_utilities.jl b/test/test_utilities.jl index 674ac3b90..5a32bf1a5 100644 --- a/test/test_utilities.jl +++ b/test/test_utilities.jl @@ -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)