diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a867236 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*DS_Store +Manifest.toml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6f11424 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +# Documentation: http://docs.travis-ci.com/user/languages/julia/ +language: julia +os: + - linux +julia: + - 1.1 + - 1.2 + - 1.3 + - 1.4 + - nightly +matrix: + allow_failures: + - julia: nightly +notifications: + email: false +after_success: + # push coverage results to Codecov + - julia -e 'using Pkg; pkg"add Coverage"; using Coverage; Codecov.submit(Codecov.process_folder())' diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..85a7804 --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,6 @@ +# This file is machine-generated - editing it directly is not advised + +[[ScientificTypes]] +git-tree-sha1 = "661a775ebf854f14509f590952eba63b47c82a5f" +uuid = "321657f4-b219-11e9-178b-2701a2544e81" +version = "0.6.0" diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..9f368ed --- /dev/null +++ b/Project.toml @@ -0,0 +1,17 @@ +name = "MLJModelInterface" +uuid = "e80e1ace-859a-464e-9ed9-23947d8ae3ea" +authors = ["Thibaut Lienart "] +version = "0.1.0" + +[deps] +ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81" + +[compat] +ScientificTypes = "^0.6" + +[extras] +Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test", "Tables"] diff --git a/src/MLJModelInterface.jl b/src/MLJModelInterface.jl new file mode 100644 index 0000000..4305cd3 --- /dev/null +++ b/src/MLJModelInterface.jl @@ -0,0 +1,47 @@ +module MLJModelInterface + +# ------------------------------------------------------------------------ +# Dependency (note that ScientificTypes itself does not have dependencies) +import ScientificTypes: trait + +# ------------------------------------------------------------------------ +# Single export: matrix, everything else is qualified in MLJBase +export matrix + +# ------------------------------------------------------------------------ + +abstract type Mode end +struct LightInterface <: Mode end +struct FullInterface <: Mode end + +const INTERFACE_MODE = Ref{Mode}(LightInterface()) + +set_interface_mode(m::Mode) = (INTERFACE_MODE[] = m) + +get_interface_mode() = INTERFACE_MODE[] + +struct InterfaceError <: Exception + m::String +end + +vtrait(X) = X |> trait |> Val + +""" + matrix(X; transpose=false) + +If `X <: AbstractMatrix`, return `X` or `permutedims(X)` if `transpose=true`. +If `X` is a Tables.jl compatible table source, convert `X` into a `Matrix`. +""" +matrix(X; kw...) = matrix(vtrait(X), X, get_interface_mode(); kw...) + +matrix(::Val{:other}, X::AbstractMatrix, ::Mode; transpose=false) = + transpose ? permutedims(X) : X + +matrix(::Val{:other}, X, ::Mode; kw...) = + throw(ArgumentError("Function `matrix` only supports AbstractMatrix or " * + "containers implementing the Tables interface.")) + +matrix(::Val{:table}, X, ::LightInterface; kw...) = + throw(InterfaceError("Only `MLJModelInterface` loaded. Import `MLJBase`.")) + +end # module diff --git a/test/runtests.jl b/test/runtests.jl new file mode 100644 index 0000000..88f6baf --- /dev/null +++ b/test/runtests.jl @@ -0,0 +1,41 @@ +using Test, MLJModelInterface, ScientificTypes +using Tables + +const M = MLJModelInterface + +ScientificTypes.TRAIT_FUNCTION_GIVEN_NAME[:table] = Tables.istable + +@testset "light-interface" begin + M.set_interface_mode(M.LightInterface()) + @test M.get_interface_mode() isa M.LightInterface + + # matrix object (:other) + X = zeros(3, 4) + mX = matrix(X) + mtX = matrix(X; transpose=true) + + @test mX === X + @test mtX == permutedims(X) + + # :other but not matrix + X = (1, 2, 3, 4) + @test_throws ArgumentError matrix(X) + + # :table + X = (x=[1,2,3], y=[1,2,3]) + @test M.vtrait(X) isa Val{:table} + @test_throws M.InterfaceError matrix(X) +end + +@testset "full-interface" begin + M.set_interface_mode(M.FullInterface()) + @test M.get_interface_mode() isa M.FullInterface + + M.matrix(::Val{:table}, X, ::M.FullInterface; kw...) = + Tables.matrix(X; kw...) + + X = (x=[1,2,3], y=[1,2,3]) + mX = matrix(X) + @test mX isa Matrix + @test mX == hcat(X.x, X.y) +end