From 98559a684ae7fc516a246a2c3b9250f5ee9f120d Mon Sep 17 00:00:00 2001 From: David Muhr Date: Wed, 3 Nov 2021 16:26:26 +0100 Subject: [PATCH] export and document macros --- Project.toml | 2 +- src/OutlierDetectionInterface.jl | 8 ++-- src/interface.jl | 25 ------------ src/macros.jl | 70 ++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 src/macros.jl diff --git a/Project.toml b/Project.toml index bb4b9f6..09cfd65 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OutlierDetectionInterface" uuid = "1722ece6-f894-4ffc-b6be-6ca1174e2011" authors = ["David Muhr and contributors"] -version = "0.1.4" +version = "0.1.5" [deps] CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" diff --git a/src/OutlierDetectionInterface.jl b/src/OutlierDetectionInterface.jl index c1bdf76..21ea109 100644 --- a/src/OutlierDetectionInterface.jl +++ b/src/OutlierDetectionInterface.jl @@ -9,9 +9,6 @@ module OutlierDetectionInterface const CLASS_OUTLIER = "outlier" const DEFAULT_THRESHOLD = 0.9 - # we might customize this macro later - const var"@detector" = var"@mlj_model" - # those do not get reexported from MLJModelInterface const _process_model_def = MMI._process_model_def const _model_constructor = MMI._model_constructor @@ -38,7 +35,9 @@ module OutlierDetectionInterface export ncolons # macros - export @detector + export @detector, + @default_frontend, + @default_metadata # macro helpers export _process_model_def, @@ -47,4 +46,5 @@ module OutlierDetectionInterface include("base.jl") include("interface.jl") + include("macros.jl") end diff --git a/src/interface.jl b/src/interface.jl index cfb50e4..0a7a17f 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -29,28 +29,3 @@ MMI.transform_scitype(::Type{<:Detector}) = AbstractVector{<:MMI.Continuous} # helper function to generate colons according to the data dimensionality ncolons(X::Data) = ntuple(_ -> Colon(), Val(ndims(X) - 1)) - -macro default_frontend(detector) - detector = esc(detector) - return quote - MMI.reformat(::$detector, X::Data) = (X,) - MMI.reformat(::$detector, X::Data, y) = (X, y) - MMI.reformat(::$detector, X::Data, y, w) = (X, y, w) - MMI.reformat(::$detector, X) = (MMI.matrix(X, transpose=true),) - MMI.reformat(::$detector, X, y) = (MMI.matrix(X, transpose=true), y) - MMI.reformat(::$detector, X, y, w) = (MMI.matrix(X, transpose=true), y, w) - MMI.selectrows(::$detector, I, Xmatrix) = (view(Xmatrix, ncolons(Xmatrix)..., I),) - MMI.selectrows(::$detector, I, Xmatrix, y) = (view(Xmatrix, ncolons(Xmatrix)..., I), view(y, I)) - MMI.selectrows(::$detector, I, Xmatrix, y, w) = (view(Xmatrix, ncolons(Xmatrix)..., I), view(y, I), view(w, I)) - end -end - -macro default_metadata(detector, uuid::String) - detector = esc(detector) - quote - MMI.metadata_pkg($detector, package_name=string(@__MODULE__), package_uuid=$uuid, - package_url="https://github.com/OutlierDetectionJL/$(@__MODULE__).jl", - is_pure_julia=true, package_license="MIT", is_wrapper=false) - MMI.load_path(::Type{$detector}) = string($detector) - end -end diff --git a/src/macros.jl b/src/macros.jl new file mode 100644 index 0000000..02060e4 --- /dev/null +++ b/src/macros.jl @@ -0,0 +1,70 @@ +""" + @detector(expr) + +An alternative to declaring the detector struct, clean! method and keyword constructor, direcly referring to +MLJModelInterface.@mlj_model. + +Parameters +---------- + expr::Expr +An expression of a mutable struct defining a detector's hyperparameters. +""" +const var"@detector" = var"@mlj_model" + +""" + @default_frontend(detector) + +Define a data front end for a given detector, which transforms the input data to `OutlierDetectionInterface.Data`. + +Parameters +---------- + detector::T where T<:Detector +The detector datatype for which the data frontend should be defined. +""" +macro default_frontend(detector) + detector = esc(detector) + return quote + MMI.reformat(::$detector, X::Data) = (X,) + MMI.reformat(::$detector, X::Data, y) = (X, y) + MMI.reformat(::$detector, X::Data, y, w) = (X, y, w) + MMI.reformat(::$detector, X) = (MMI.matrix(X, transpose=true),) + MMI.reformat(::$detector, X, y) = (MMI.matrix(X, transpose=true), y) + MMI.reformat(::$detector, X, y, w) = (MMI.matrix(X, transpose=true), y, w) + MMI.selectrows(::$detector, I, Xmatrix) = (view(Xmatrix, ncolons(Xmatrix)..., I),) + MMI.selectrows(::$detector, I, Xmatrix, y) = (view(Xmatrix, ncolons(Xmatrix)..., I), view(y, I)) + MMI.selectrows(::$detector, I, Xmatrix, y, w) = (view(Xmatrix, ncolons(Xmatrix)..., I), view(y, I), view(w, I)) + end +end + +""" + @default_metadata(detector, + uuid) + +Define the default metadata for a given detector, which is useful when a detector is exported into MLJModels, such that +it can be directly loaded with MLJ. By default, we assume that a detector is exported on a package's top-level and we +set the `load_path` accordingly. + +Additionally, we assume the following metadata defaults: + +- `package_name` is equal to the `@__MODULE__`, where `@default_metadata` is used +- The detector is implemented in julia, `is_pure_julia=true` +- The detector is no wrapper, `is_wrapper=false` +- The package lives in the `OutlierDetectionJL` github organization + +Parameters +---------- + detector::T where T<:Detector +The detector datatype for which the data frontend should be defined. + + uuid::String +The UUID of the detector's package. +""" +macro default_metadata(detector, uuid::String) + detector = esc(detector) + quote + MMI.metadata_pkg($detector, package_name=string(@__MODULE__), package_uuid=$uuid, + package_url="https://github.com/OutlierDetectionJL/$(@__MODULE__).jl", + is_pure_julia=true, package_license="MIT", is_wrapper=false) + MMI.load_path(::Type{$detector}) = string($detector) + end +end