From e8811f3e7cd8ab09f63f589ee6be34db96993f31 Mon Sep 17 00:00:00 2001 From: Tim Thatcher Date: Sun, 10 Jul 2016 14:59:48 -0400 Subject: [PATCH] Updated tests, fixed conversions --- src/functions/compositefunction.jl | 41 +++++++++++----- src/hyperparameter.jl | 1 + src/meta.jl | 73 ++++++++++++++++++++++++++++- test/functions/compositefunction.jl | 6 +-- test/functions/pairwisefunction.jl | 4 +- test/functions/pointwisefunction.jl | 6 +-- test/hyperparameter.jl | 8 ++-- test/pairwise.jl | 21 +++++---- test/runtests.jl | 8 ++++ 9 files changed, 133 insertions(+), 35 deletions(-) diff --git a/src/functions/compositefunction.jl b/src/functions/compositefunction.jl index 7f3ac91..77a6e3f 100644 --- a/src/functions/compositefunction.jl +++ b/src/functions/compositefunction.jl @@ -257,42 +257,59 @@ attainsnegative(h::CompositeFunction) = attainsnegative(h.g) #== Composition Kernels ==# doc"GaussianKernel(α) = exp(-α⋅‖x-y‖²)" -function GaussianKernel{T<:AbstractFloat}(α::Argument{T}) +function GaussianKernel{T<:AbstractFloat}(α::Variable{T}) CompositeFunction(ExponentialClass(α), SquaredEuclidean{T}()) end -function GaussianKernel{T}(α::T=1.0) - T <: AbstractFloat ? GaussianKernel(α) : GaussianKernel(convert(Float64, α)) +function GaussianKernel{T}(α::Argument{T}=1.0) + GaussianKernel(Variable{T <: AbstractFloat ? T : Float64}(α)) end SquaredExponentialKernel = GaussianKernel RadialBasisKernel = GaussianKernel doc"LaplacianKernel(α) = exp(α⋅‖x-y‖)" -function LaplacianKernel{T<:AbstractFloat}(α::Argument{T}) - CompositeFunction(GammaExponentialClass(α, convert(T, 0.5)), SquaredEuclidean{T}()) +function LaplacianKernel{T<:AbstractFloat}(α::Variable{T}) + CompositeFunction(GammaExponentialClass(α, Variable{T}(0.5)), SquaredEuclidean{T}()) end -function LaplacianKernel{T}(α::T=1.0) - T <: AbstractFloat ? LaplacianKernel(α) : LaplacianKernel(convert(Argument{Float64}, α)) +function LaplacianKernel{T<:Real}(α::Argument{T}=1.0) + LaplacianKernel(Variable{T <: AbstractFloat ? T : Float64}(α)) end doc"PeriodicKernel(α,p) = exp(-α⋅Σⱼsin²(p(xⱼ-yⱼ)))" -function PeriodicKernel{T<:AbstractFloat}(α::Argument{T}, p::Argument{T}) +function PeriodicKernel{T<:AbstractFloat}(α::Variable{T}, p::Variable{T}) CompositeFunction(ExponentialClass(α), SineSquaredKernel(p)) end -function PeriodicKernel{T1,T2}(α::Argument{T1} = 1.0, p::Argument{T2} = convert(Float64,π)) +function PeriodicKernel{T1<:Real,T2<:Real}( + α::Argument{T1} = 1.0, + p::Argument{T2} = convert(T1 <: AbstractFloat ? T1 : Float64,π) + ) Tmax = promote_type(T1, T2) T = Tmax <: AbstractFloat ? Tmax : Float64 - PeriodicKernel(convert(Argument{T}, α), convert(Argument{T}, p)) + PeriodicKernel(Variable{T}(α), Variable{T}(p)) end doc"RationalQuadraticKernel(α,β) = (1 + α⋅‖x-y‖²)⁻ᵝ" -function RationalQuadraticKernel{T<:AbstractFloat}(α::Argument{T} = 1.0, β::Argument{T} = one(T)) +function RationalQuadraticKernel{T<:AbstractFloat}(α::Variable{T}, β::Variable{T}) CompositeFunction(RationalClass(α, β), SquaredEuclidean{T}()) end +function RationalQuadraticKernel{T1<:Real,T2<:Real}( + α::Argument{T1} = 1.0, + β::Argument{T2} =one(T1) + ) + Tmax = promote_type(T1, T2) + T = Tmax <: AbstractFloat ? Tmax : Float64 + RationalQuadraticKernel(Variable{T}(α), Variable{T}(β)) +end doc"MatérnKernel(ν,θ) = 2ᵛ⁻¹(√(2ν)‖x-y‖²/θ)ᵛKᵥ(√(2ν)‖x-y‖²/θ)/Γ(ν)" -function MaternKernel{T<:AbstractFloat}(ν::Argument{T} = 1.0, θ::Argument{T} = one(T)) +function MaternKernel{T<:AbstractFloat}(ν::Variable{T}, θ::Variable{T}) CompositeFunction(MaternClass(ν, θ), SquaredEuclidean{T}()) end +function MaternKernel{T1<:Real,T2<:Real}(ν::Argument{T1} = 1.0, θ::Argument{T2} = one(T1)) + Tmax = promote_type(T1, T2) + T = Tmax <: AbstractFloat ? Tmax : Float64 + MaternKernel(Variable{T}(ν), Variable{T}(θ)) +end + MatérnKernel = MaternKernel doc"PolynomialKernel(a,c,d) = (a⋅xᵀy + c)ᵈ" diff --git a/src/hyperparameter.jl b/src/hyperparameter.jl index b58479f..f60d794 100644 --- a/src/hyperparameter.jl +++ b/src/hyperparameter.jl @@ -148,6 +148,7 @@ fixed{T<:Real}(v::T) = Variable{T}(v, true) eltype{T<:Real}(::Variable{T}) = T convert{T<:Real}(::Type{Variable{T}}, var::Variable) = Variable(convert(T, var.value), var.isfixed) +convert{T<:Real}(::Type{Variable{T}}, var::Real) = Variable(convert(T, var), false) typealias Argument{T<:Real} Union{T,Variable{T}} diff --git a/src/meta.jl b/src/meta.jl index 0919384..c17d9c2 100644 --- a/src/meta.jl +++ b/src/meta.jl @@ -1,3 +1,14 @@ +function promote_type_float(T_i::DataType...) + T_max = promote_type(T_i...) + T_max <: AbstractFloat ? T_max : Float64 +end + +function promote_type_int(U_i::DataType...) + U_max = promote_type(U_i...) + U_max <: Signed ? U_max : Int64 +end + + # Checks to make sure the fields in the datatype are of type Parameter{T} or Parameter{U} where # T<:AbstractFloat and U<:Integer function fieldparameters(obj::DataType) @@ -36,6 +47,65 @@ function fieldparameters(obj::DataType) return (fields, field_parameters) end +function promote_code_block(obj::DataType, cstr_params, field_params) + promote_T = Expr(:call, :promote_type_float, cstr_params[field_params .== :T]...) + if length(obj.parameters) == 1 + return :(T = $promote_T) + else + promote_U = Expr(:call, :promote_type_int, cstr_params[field_params .== :U]...) + return Expr(:block, :(T = $promote_T), :(U = $promote_U)) + end +end + +function fieldparameters_constructor(obj::DataType) + fields, field_params = fieldparameters(obj) + n = length(fields) + counter = [1,1] # T count, U count + constructor_params = Array(Symbol, n) + constructor_types = Array(Union{Symbol,Expr}, n) + for i in eachindex(field_params) + param_sym = field_params[i] + param_idx = param_sym == :T ? 1 : 2 + constructor_params[i] = Symbol(string(param_sym, counter[param_idx])) + if counter[param_idx] == 1 + constructor_types[i] = param_idx == 1 ? :Float64 : :Int64 + else + preceding_params = (constructor_params[1:i-1])[field_params[1:i-1] .== param_sym] + promotion = param_idx == 1 ? :promote_type_float : :promote_type_int + constructor_types[i] = Expr(:call, promotion, preceding_params...) + end + counter[param_idx] += 1 + end + (fields, field_params, constructor_params, constructor_types) +end + +function generate_outer_constructor2(obj::DataType, default_values::Tuple{Vararg{Real}}) + # (:a,:b,:c,:d), [:T, :U, :T, :U], [:T1, :U1, :T2, :U2], + # [:Float64, :Int64, promote_type_float(T1), promote_type_int(U1)] + fields, field_params, cstr_params, cstr_types = fieldparameters_constructor(obj) + + if (n = length(default_values)) != length(fields) + error("Default count does not match field count") + end + + # [:(T1 <: Real), :(T2 <: Real), :(U1 <: Real) + defn_params = [Expr(:(<:), cstr_params[i], :Real) for i = 1:n] + + # (a::Argument{T1}=convert(Float64,x), b::Argument{T2}=convert(T1,x)... + defn_args = [Expr(:kw, :($(fields[i])::Argument{$(cstr_params[i])}), + :(convert($(cstr_types[i]), $(default_values[i])))) for i = 1:n] + + # (Variable{T}(a), Variable{T}(b), Variable{U}(c)) + call_args = [:(Variable{$(field_params[i])}($(fields[i]))) for i = 1:n] + + block_definition = Expr(:call, Expr(:curly, obj.name.name, defn_params...), defn_args...) + block_promotion = promote_code_block(obj, cstr_params, field_params) + block_call = Expr(:call, Expr(:curly, obj.name.name, [p.name for p in obj.parameters]...), call_args...) + + return Expr(:function, block_definition, Expr(:block, block_promotion, block_call)) +end + + function generate_conversions(obj::DataType) fields, field_parameters = fieldparameters(obj) obj_sym = obj.name.name @@ -91,7 +161,8 @@ function generate_outer_constructor(obj::DataType, defaults::Tuple{Vararg{Real}} Expr(:call, Expr(:curly, obj_sym, type_params...), type_args...)) end + macro outer_constructor(obj, defaults) - eval(generate_outer_constructor(eval(obj), eval(defaults))) + eval(generate_outer_constructor2(eval(obj), eval(defaults))) eval(generate_conversions(eval(obj))) end diff --git a/test/functions/compositefunction.jl b/test/functions/compositefunction.jl index 08f6499..d261189 100644 --- a/test/functions/compositefunction.jl +++ b/test/functions/compositefunction.jl @@ -1,4 +1,4 @@ -info("Testing ", MOD.CompositionClass) +info("Testing ", MOD.CompositionClass.name.name) steps = length(composition_classes) counter = 0 for class_obj in composition_classes @@ -63,10 +63,10 @@ for class_obj in composition_classes show(DevNull, g) counter += 1 - info("[", @sprintf("%3.0f", counter/steps*100), "%] ", class_obj) + info("[", @sprintf("%3.0f", counter/steps*100), "%] ", class_obj.name.name) end -info("Testing ", MOD.CompositeFunction) +info("Testing ", MOD.CompositeFunction.name.name) for class_obj in composition_classes g = (class_obj)() for f_obj in pairwise_functions diff --git a/test/functions/pairwisefunction.jl b/test/functions/pairwisefunction.jl index 5c679f8..0c7aef9 100644 --- a/test/functions/pairwisefunction.jl +++ b/test/functions/pairwisefunction.jl @@ -1,4 +1,4 @@ -info("Testing ", MOD.PairwiseFunction) +info("Testing ", MOD.PairwiseFunction.name.name) steps = length(pairwise_functions) counter = 0 for f_obj in pairwise_functions @@ -63,5 +63,5 @@ for f_obj in pairwise_functions show(DevNull, f) counter += 1 - info("[", @sprintf("%3.0f", counter/steps*100), "%] ", f_obj) + info("[", @sprintf("%3.0f", counter/steps*100), "%] ", f_obj.name.name) end diff --git a/test/functions/pointwisefunction.jl b/test/functions/pointwisefunction.jl index 8bdd727..5ef0ffd 100644 --- a/test/functions/pointwisefunction.jl +++ b/test/functions/pointwisefunction.jl @@ -1,4 +1,4 @@ -info("Testing ", AffineFunction) +info("Testing ", AffineFunction.name.name) for f_obj in (pairwise_functions..., composite_functions...) for T in FloatingPointTypes @@ -76,7 +76,7 @@ for f_obj in (pairwise_functions..., composite_functions...) end -info("Testing ", FunctionSum) +info("Testing ", FunctionSum.name.name) for f_obj1 in (pairwise_functions..., composite_functions...) for f_obj2 in (pairwise_functions..., composite_functions...) for T in FloatingPointTypes @@ -137,7 +137,7 @@ for f_obj1 in (pairwise_functions..., composite_functions...) end end -info("Testing ", FunctionProduct) +info("Testing ", FunctionProduct.name.name) for f_obj1 in (pairwise_functions..., composite_functions...) for f_obj2 in (pairwise_functions..., composite_functions...) for T in FloatingPointTypes diff --git a/test/hyperparameter.jl b/test/hyperparameter.jl index b23b59f..bf5d149 100644 --- a/test/hyperparameter.jl +++ b/test/hyperparameter.jl @@ -1,4 +1,4 @@ -info("Testing ", Bound) +info("Testing ", Bound.name.name) for T in (FloatingPointTypes..., IntegerTypes...) for isopen in (true, false) B = Bound(one(T), isopen) @@ -18,7 +18,7 @@ for T in (FloatingPointTypes..., IntegerTypes...) end end -info("Testing ", Interval) +info("Testing ", Interval.name.name) for T in (FloatingPointTypes..., IntegerTypes...) for lisopen in (true, false), uisopen in (true, false) Bl = Bound(zero(T), lisopen) @@ -113,7 +113,7 @@ for T in (FloatingPointTypes..., IntegerTypes...) end end -info("Testing ", Variable) +info("Testing ", Variable.name.name) for T in (FloatingPointTypes..., IntegerTypes...) v = Variable(one(T)) @@ -135,7 +135,7 @@ for T in (FloatingPointTypes..., IntegerTypes...) end end -info("Testing ", HyperParameter) +info("Testing ", HyperParameter.name.name) for T in (FloatingPointTypes..., IntegerTypes...) I = rightbounded(one(T), :open) diff --git a/test/pairwise.jl b/test/pairwise.jl index a837743..ce69038 100644 --- a/test/pairwise.jl +++ b/test/pairwise.jl @@ -6,7 +6,7 @@ test_pairwise_functions = [(f_obj)() for f_obj in pairwise_functions] test_composite_functions = [(f_obj)() for f_obj in composite_functions] test_sample = [SquaredEuclidean(), ChiSquared(), ScalarProduct(), GaussianKernel()] -info("Testing ", MOD.unsafe_pairwise) +info("Testing ", MOD.unsafe_pairwise.env.name) for T in FloatingPointTypes x = rand(T,p) y = rand(T,p) @@ -43,7 +43,7 @@ for T in FloatingPointTypes end end -info("Testing ", MOD.pairwise) +info("Testing ", MOD.pairwise.env.name) for T in FloatingPointTypes x = rand(T,p) y = rand(T,p) @@ -98,7 +98,7 @@ for T in FloatingPointTypes end end -info("Testing ", MOD.dotvectors!) +info("Testing ", MOD.dotvectors!.env.name) for T in FloatingPointTypes Set_X = [rand(T, p) for i = 1:n] Set_Y = [rand(T,p) for i = 1:m] @@ -117,7 +117,7 @@ for T in FloatingPointTypes @test_throws DimensionMismatch MOD.dotvectors!(Val{:col}, Array(T,2), Array(T,2,3)) end -info("Testing ", MOD.gramian!) +info("Testing ", MOD.gramian!.env.name) for T in FloatingPointTypes Set_X = [rand(T, p) for i = 1:n] Set_Y = [rand(T,p) for i = 1:m] @@ -154,7 +154,7 @@ for T in FloatingPointTypes end -info("Testing ", MOD.squared_distance!) +info("Testing ", MOD.squared_distance!.env.name) for T in FloatingPointTypes Set_X = [rand(T,p) for i = 1:n] Set_Y = [rand(T,p) for i = 1:m] @@ -184,7 +184,7 @@ for T in FloatingPointTypes @test_throws DimensionMismatch MOD.squared_distance!(Array(T,3,4), Array(T,3), Array(T,5)) end -info("Testing ", MOD.rectangular_compose!) +info("Testing ", MOD.rectangular_compose!.env.name) for f_obj in composition_classes for T in FloatingPointTypes X = rand(T, n, m) @@ -195,7 +195,7 @@ for f_obj in composition_classes end end -info("Testing ", MOD.symmetric_compose!) +info("Testing ", MOD.symmetric_compose!.env.name) for f_obj in composition_classes for T in FloatingPointTypes X = rand(T, n, n) @@ -209,7 +209,7 @@ for f_obj in composition_classes end end -info("Testing ", MOD.pairwisematrix!) +info("Testing ", MOD.pairwisematrix!.env.name) test_set = (test_pairwise_functions..., test_composite_functions..., [2*f+1 for f in test_sample]..., [f1+f2 for f1 in test_sample, f2 in test_sample]..., @@ -217,7 +217,8 @@ test_set = (test_pairwise_functions..., test_composite_functions..., steps = length(test_set) counter = 0 for f_test in test_set - info("[", @sprintf("%3.0f", counter/steps*100), "%] Case ", @sprintf("%2.0f", counter+1), "/", steps) + info("[", @sprintf("%3.0f", counter/steps*100), "%] Case ", @sprintf("%2.0f", counter+1), "/", + steps, " - ", test_print(f_test)) for T in FloatingPointTypes Set_X = [rand(T,p) for i = 1:n] Set_Y = [rand(T,p) for i = 1:m] @@ -256,7 +257,7 @@ for f_test in test_set end info("[100%] Done") -info("Testing ", MOD.pairwisematrix) +info("Testing ", MOD.pairwisematrix.env.name) test_set = test_sample steps = length(test_set) counter = 0 diff --git a/test/runtests.jl b/test/runtests.jl index e79d79c..1a96af9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,6 +6,14 @@ FloatingPointTypes = (Float32, Float64) IntegerTypes = (Int32, UInt32, Int64, UInt64) MOD = MLKernels +test_print(f::RealFunction) = string(typeof(f).name) +test_print(h::AffineFunction) = string(typeof(h).name, "(", typeof(h.f).name.name, ")") +test_print(h::CompositeFunction) = string(typeof(h).name.name, "(", typeof(h.g).name.name, ",", + typeof(h.f).name.name, ")") +test_print(h::FunctionSum) = string(typeof(h).name.name, "(", typeof(h.g).name.name, ",", + typeof(h.f).name.name, ")") +test_print(h::FunctionProduct) = string(typeof(h).name.name, "(", typeof(h.g).name.name, ",", + typeof(h.f).name.name, ")") #= module MLKTest