From 8a594bb12813d3efdf39dff05e300c014ee753d2 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 14 Oct 2021 09:44:37 +0200 Subject: [PATCH 01/44] Split docs in 2 pages and add explanations --- docs/make.jl | 2 +- docs/src/api.md | 25 +++++++++++++++++++++++++ docs/src/index.md | 17 +++++++++++++---- 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 docs/src/api.md diff --git a/docs/make.jl b/docs/make.jl index 69a122c..ce790be 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,7 +3,7 @@ using Documenter, GPLikelihoods makedocs(; modules=[GPLikelihoods], format=Documenter.HTML(), - pages=["Home" => "index.md"], + pages=["Home" => "index.md", "API" => "api.md"], repo="https://github.com/JuliaGaussianProcesses/GPLikelihoods.jl/blob/{commit}{path}#L{line}", sitename="GPLikelihoods.jl", authors="JuliaGaussianProcesses organization", diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..6e78d0a --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,25 @@ +# API + +```@index +``` + +## Likelihoods + +```@docs +BernoulliLikelihood +CategoricalLikelihood +ExponentialLikelihood +GammaLikelihood +GaussianLikelihood +PoissonLikelihood +``` + +## Links + +```@docs +Link +``` + +The rest of the links `ExpLink`, `LogisticLink`, etc., are simple aliases for the +corresponding wrapped functions in a `Link`. +For example `ExpLink == Link{::typeof(exp)}`. diff --git a/docs/src/index.md b/docs/src/index.md index b036128..064bec3 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,8 +1,17 @@ # GPLikelihoods.jl -```@index -``` +`GPLikelihoods.jl` provides a practical interface to connect non-conjugate likelihoods +with Gaussian Processes. +The API is very basic, every `AbstractLikelihood` object is functor taking a +scalar/vector `f` and returns a `Distribution` from `Distributions.jl`. -```@autodocs -Modules = [GPLikelihoods] +```@doctest + f = 2.0 + GaussianLikelihood()(f) == Normal(2.0) ``` + +Since the parameter domain of a lot of distributions is more restricted to the real +domain, for example the parameter of a `Bernoulli` distribution, most `AbstractLikelihood` +contain a `invlink` field which will map the latent variable to the right domain. + +[`Link`](@ref)s can be created using the constructor `Link(::Function)`. \ No newline at end of file From 708158faf7897176cb626caee9580921c67f6e98 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 14 Oct 2021 10:19:02 +0200 Subject: [PATCH 02/44] Update docs Manifest and add some examples/tests --- docs/Manifest.toml | 55 ++++++++++++++++++++-------------------------- docs/src/index.md | 15 ++++++++++++- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/docs/Manifest.toml b/docs/Manifest.toml index b447396..f7288ca 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -1,5 +1,10 @@ # This file is machine-generated - editing it directly is not advised +[[ANSIColoredPrinters]] +git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" +uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" +version = "0.0.1" + [[Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -7,27 +12,23 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - [[DocStringExtensions]] -deps = ["LibGit2", "Markdown", "Pkg", "Test"] -git-tree-sha1 = "50ddf44c53698f5e784bbebb3f4b21c5807401b1" +deps = ["LibGit2"] +git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.3" +version = "0.8.5" [[Documenter]] -deps = ["Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "c01a7e8bcf7a6693444a52a0c5ac8b4e9528600e" +deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] +git-tree-sha1 = "8b43e37cfb4f4edc2b6180409acc0cebce7fede8" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.26.0" +version = "0.27.7" [[IOCapture]] -deps = ["Logging"] -git-tree-sha1 = "377252859f740c217b936cebcd918a44f9b53b59" +deps = ["Logging", "Random"] +git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.1.1" +version = "0.2.2" [[InteractiveUtils]] deps = ["Markdown"] @@ -35,17 +36,14 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" +git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" +version = "0.21.2" [[LibGit2]] -deps = ["Printf"] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - [[Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" @@ -56,22 +54,21 @@ uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" + [[Parsers]] deps = ["Dates"] -git-tree-sha1 = "6370b5b3cf2ce5a3d2b6f7ab2dc10f374e4d7d2b" +git-tree-sha1 = "98f59ff3639b3d9485a03a72f3ab35bab9465720" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.14" - -[[Pkg]] -deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "2.0.6" [[Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets"] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[Random]] @@ -88,12 +85,8 @@ uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" uuid = "6462fe0b-24de-5631-8697-dd941f90decc" [[Test]] -deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - [[Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/docs/src/index.md b/docs/src/index.md index 064bec3..4969e58 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -5,13 +5,26 @@ with Gaussian Processes. The API is very basic, every `AbstractLikelihood` object is functor taking a scalar/vector `f` and returns a `Distribution` from `Distributions.jl`. -```@doctest +```@jldoctest f = 2.0 GaussianLikelihood()(f) == Normal(2.0) + + # output + + true ``` Since the parameter domain of a lot of distributions is more restricted to the real domain, for example the parameter of a `Bernoulli` distribution, most `AbstractLikelihood` contain a `invlink` field which will map the latent variable to the right domain. +```@jldoctest + f = 2.0 + BernoulliLikelihood(Link(logistic))(2.0) == Bernoulli(logistic(2.0)) + + # output + + true +``` + [`Link`](@ref)s can be created using the constructor `Link(::Function)`. \ No newline at end of file From d18754e9223077b90dae425244d92624692f9110 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 14 Oct 2021 10:33:17 +0200 Subject: [PATCH 03/44] replace jldoctest by example --- docs/src/index.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 4969e58..c9d3889 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -5,26 +5,18 @@ with Gaussian Processes. The API is very basic, every `AbstractLikelihood` object is functor taking a scalar/vector `f` and returns a `Distribution` from `Distributions.jl`. -```@jldoctest +```@example f = 2.0 GaussianLikelihood()(f) == Normal(2.0) - - # output - - true ``` Since the parameter domain of a lot of distributions is more restricted to the real domain, for example the parameter of a `Bernoulli` distribution, most `AbstractLikelihood` contain a `invlink` field which will map the latent variable to the right domain. -```@jldoctest +```@example f = 2.0 BernoulliLikelihood(Link(logistic))(2.0) == Bernoulli(logistic(2.0)) - - # output - - true ``` [`Link`](@ref)s can be created using the constructor `Link(::Function)`. \ No newline at end of file From c213531322621ff346db96fbdf9e44012b726a14 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 14 Oct 2021 10:56:10 +0200 Subject: [PATCH 04/44] Add more api docs --- docs/src/api.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/src/api.md b/docs/src/api.md index 6e78d0a..38900f2 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -11,6 +11,7 @@ CategoricalLikelihood ExponentialLikelihood GammaLikelihood GaussianLikelihood +HeteroscedasticGaussianLikelihood PoissonLikelihood ``` @@ -18,8 +19,33 @@ PoissonLikelihood ```@docs Link +ChainLink ``` The rest of the links `ExpLink`, `LogisticLink`, etc., are simple aliases for the corresponding wrapped functions in a `Link`. For example `ExpLink == Link{::typeof(exp)}`. + +We provide nonetheless docs for them: + +```@docs +LogLink +ExpLink +InvLink +SqrtLink +SquareLink +LogitLink +LogisticLink +ProbitLink +NormalCDFLink +SoftMaxLink +``` + +## Misc + +```@docs +inverse +``` + +!!! warning + This whole part might be replaced soon by the `InverseFunctions.jl` package. From cf68d0eaa3c2b1b4661d96729abe4606a137e326 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 14 Oct 2021 14:44:13 +0200 Subject: [PATCH 05/44] Resolved comments --- docs/src/api.md | 13 ++----------- docs/src/index.md | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/src/api.md b/docs/src/api.md index 38900f2..6daaca5 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -24,7 +24,7 @@ ChainLink The rest of the links `ExpLink`, `LogisticLink`, etc., are simple aliases for the corresponding wrapped functions in a `Link`. -For example `ExpLink == Link{::typeof(exp)}`. +For example `ExpLink == Link{typeof(exp)}`. We provide nonetheless docs for them: @@ -39,13 +39,4 @@ LogisticLink ProbitLink NormalCDFLink SoftMaxLink -``` - -## Misc - -```@docs -inverse -``` - -!!! warning - This whole part might be replaced soon by the `InverseFunctions.jl` package. +``` \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md index c9d3889..9c263d8 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -16,7 +16,7 @@ contain a `invlink` field which will map the latent variable to the right domain ```@example f = 2.0 - BernoulliLikelihood(Link(logistic))(2.0) == Bernoulli(logistic(2.0)) + BernoulliLikelihood(logistic)(f) == Bernoulli(logistic(2.0)) ``` -[`Link`](@ref)s can be created using the constructor `Link(::Function)`. \ No newline at end of file +[`Link`](@ref)s can be created using the constructor `Link(l)` where `l` is a function or a functor. \ No newline at end of file From 15fb16515120e52af2f36a9fb33d7134f73a0215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 22 Oct 2021 11:10:49 +0200 Subject: [PATCH 06/44] Apply suggestions from code review Co-authored-by: David Widmann --- docs/src/index.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 9c263d8..b804f97 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -2,21 +2,20 @@ `GPLikelihoods.jl` provides a practical interface to connect non-conjugate likelihoods with Gaussian Processes. -The API is very basic, every `AbstractLikelihood` object is functor taking a -scalar/vector `f` and returns a `Distribution` from `Distributions.jl`. +The API is very basic: Every `AbstractLikelihood` object is a [functor](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects-1) that takes the output of a Gaussian process as input and returns a `Distribution` from [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl). -```@example - f = 2.0 - GaussianLikelihood()(f) == Normal(2.0) +```@repl +f = 2.0; +GaussianLikelihood()(f) == Normal(2.0) ``` Since the parameter domain of a lot of distributions is more restricted to the real domain, for example the parameter of a `Bernoulli` distribution, most `AbstractLikelihood` contain a `invlink` field which will map the latent variable to the right domain. -```@example - f = 2.0 - BernoulliLikelihood(logistic)(f) == Bernoulli(logistic(2.0)) +```@repl +f = 2.0; +BernoulliLikelihood(logistic)(f) == Bernoulli(logistic(2.0)) ``` [`Link`](@ref)s can be created using the constructor `Link(l)` where `l` is a function or a functor. \ No newline at end of file From c247484033323555eee8039dd30ea685ebc51bed Mon Sep 17 00:00:00 2001 From: David Widmann Date: Thu, 11 Nov 2021 23:35:00 +0100 Subject: [PATCH 07/44] Use InverseFunctions (#56) * Use InverseFunctions * Update Project.toml --- Project.toml | 6 ++++-- src/GPLikelihoods.jl | 4 +--- src/inverse.jl | 27 --------------------------- src/links.jl | 6 +++--- test/inverse.jl | 32 -------------------------------- test/runtests.jl | 1 - 6 files changed, 8 insertions(+), 68 deletions(-) delete mode 100644 src/inverse.jl delete mode 100644 test/inverse.jl diff --git a/Project.toml b/Project.toml index b823d6d..4a0fd4c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,12 @@ name = "GPLikelihoods" uuid = "6031954c-0455-49d7-b3b9-3e1c99afaf40" authors = ["JuliaGaussianProcesses Team"] -version = "0.2.4" +version = "0.2.5" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Functors = "d9f16b24-f501-4c13-a1f2-28368ffc5196" +InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" @@ -13,5 +14,6 @@ StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" [compat] Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" Functors = "0.1, 0.2" -StatsFuns = "0.9" +InverseFunctions = "0.1.2" +StatsFuns = "0.9.13" julia = "1.3" diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index df0a070..d250c04 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -2,6 +2,7 @@ module GPLikelihoods using Distributions using Functors +using InverseFunctions: InverseFunctions using LinearAlgebra using Random using StatsFuns @@ -26,9 +27,6 @@ export Link, NormalCDFLink, SoftMaxLink -# Inverses -include("inverse.jl") - # Links include("links.jl") diff --git a/src/inverse.jl b/src/inverse.jl deleted file mode 100644 index 5e5f53a..0000000 --- a/src/inverse.jl +++ /dev/null @@ -1,27 +0,0 @@ -""" - inverse(f) - -Return the inverse of function `f`. - -This is an internal function to avoid type piracies such as `inv(::typeof(exp))`. At some -point `inv` might support standard Julia functions which would allow us to remove `inverse`. -""" -inverse(f) - -inverse(::typeof(exp)) = log -inverse(::typeof(log)) = exp - -inverse(::typeof(log1pexp)) = logexpm1 -inverse(::typeof(logexpm1)) = log1pexp - -inverse(::typeof(inv)) = inv - -square(x) = x^2 -inverse(::typeof(sqrt)) = square -inverse(::typeof(square)) = sqrt - -inverse(::typeof(logit)) = logistic -inverse(::typeof(logistic)) = logit - -inverse(::typeof(normcdf)) = norminvcdf -inverse(::typeof(norminvcdf)) = normcdf diff --git a/src/links.jl b/src/links.jl index 82d0fef..d87cdc4 100644 --- a/src/links.jl +++ b/src/links.jl @@ -25,7 +25,7 @@ end (l::Link)(x) = l.f(x) -Base.inv(l::Link) = Link(inverse(l.f)) +Base.inv(l::Link) = Link(InverseFunctions.inverse(l.f)) # alias const LogLink = Link{typeof(log)} @@ -34,7 +34,7 @@ const ExpLink = Link{typeof(exp)} const InvLink = Link{typeof(inv)} const SqrtLink = Link{typeof(sqrt)} -const SquareLink = Link{typeof(square)} +const SquareLink = Link{typeof(InverseFunctions.square)} const LogitLink = Link{typeof(logit)} const LogisticLink = Link{typeof(logistic)} @@ -77,7 +77,7 @@ SqrtLink() = Link(sqrt) `^2` link, f:ℝ->ℝ⁺∪{0}. Its inverse is the [`SqrtLink`](@ref). """ -SquareLink() = Link(square) +SquareLink() = Link(InverseFunctions.square) """ LogitLink() diff --git a/test/inverse.jl b/test/inverse.jl deleted file mode 100644 index c9a4c36..0000000 --- a/test/inverse.jl +++ /dev/null @@ -1,32 +0,0 @@ -@testset "inverse.jl" begin - @testset "square" begin - x = randn() - @test GPLikelihoods.square(x) == x^2 - end - - @testset "inverse" begin - x = rand() - for f in ( - exp, - log, - inv, - log1pexp, - logexpm1, - sqrt, - GPLikelihoods.square, - logit, - logistic, - normcdf, - norminvcdf, - ) - g = GPLikelihoods.inverse(f) - - # check that definitions are correct - @test g(f(x)) ≈ x - @test f(g(x)) ≈ x - - # check that definitions are complete - @test GPLikelihoods.inverse(g) === f - end - end -end diff --git a/test/runtests.jl b/test/runtests.jl index 5da718a..1679108 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,7 +8,6 @@ using StatsFuns @testset "GPLikelihoods.jl" begin include("test_utils.jl") - include("inverse.jl") include("links.jl") @testset "likelihoods" begin include("likelihoods/bernoulli.jl") From fcdf235e18acc63575c96f749c547d501dd08170 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 16:09:55 +0100 Subject: [PATCH 08/44] Move the test interface inside of `src` --- src/TestInterface.jl | 66 ++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 2 +- test/test_utils.jl | 51 ---------------------------------- 3 files changed, 67 insertions(+), 52 deletions(-) create mode 100644 src/TestInterface.jl delete mode 100644 test/test_utils.jl diff --git a/src/TestInterface.jl b/src/TestInterface.jl new file mode 100644 index 0000000..623496a --- /dev/null +++ b/src/TestInterface.jl @@ -0,0 +1,66 @@ +module TestInterface + +using Random + +export test_inferface + +function test_interface( +rng::AbstractRNG, lik, kernel, x::AbstractVector; functor_args=() +) +gp = GP(kernel) +lgp = LatentGP(gp, lik, 1e-5) +lfgp = lgp(x) + +# Check if likelihood produces a distribution +@test lik(rand(rng, lfgp.fx)) isa Distribution + +N = length(x) +y = rand(rng, lfgp.fx) + +if x isa MOInput + # TODO: replace with mo_inverse_transform + N = length(x.x) + y = [y[[i + j * N for j in 0:(x.out_dim - 1)]] for i in 1:N] +end + +# Check if the likelihood samples are of correct length +@test length(rand(rng, lik(y))) == N + +# Check if functor works properly +xs, re = Functors.functor(lik) +@test lik == re(xs) +if isempty(functor_args) + @test xs === () +else + @test keys(xs) == functor_args +end + +return nothing +end + +@doc raw""" + test_interface([rng::AbstractRNG,] lik, k::Kernel, x::AbstractVector; functor_args=()) + +!!! warning + + KernelFunctions.jl and AbstractGPs.jl need to be loaded in the current workspace + to run this function. + +This function provides unified method to check the interface of the various likelihoods +defined. It checks if the likelihood produces a distribution, length of likelihood +samples is correct and if the functor works as intended. + +... +# Arguments +- `lik`: the likelihood to test the interface of +- `k::Kernel`: the kernel to use for the GP +- `x::AbstractVector`: inputs to compute the likelihood on +- `functor_args=()`: a collection of symbols of arguments to match functor parameters with. +... +""" +function test_interface(lik, kernel, x::AbstractVector; kwargs...) + return test_interface(Random.GLOBAL_RNG, lik, k, x; kwargs...) +end + + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 1679108..a465a16 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,5 @@ using GPLikelihoods +using GPLikelihoods.TestInterface using AbstractGPs using Test using Random @@ -7,7 +8,6 @@ using Distributions using StatsFuns @testset "GPLikelihoods.jl" begin - include("test_utils.jl") include("links.jl") @testset "likelihoods" begin include("likelihoods/bernoulli.jl") diff --git a/test/test_utils.jl b/test/test_utils.jl deleted file mode 100644 index 02f72cf..0000000 --- a/test/test_utils.jl +++ /dev/null @@ -1,51 +0,0 @@ -function test_interface( - rng::AbstractRNG, lik, k::Kernel, x::AbstractVector; functor_args=() -) - gp = GP(k) - lgp = LatentGP(gp, lik, 1e-5) - lfgp = lgp(x) - - # Check if likelihood produces a distribution - @test lik(rand(rng, lfgp.fx)) isa Distribution - - N = length(x) - y = rand(rng, lfgp.fx) - - if x isa MOInput - # TODO: replace with mo_inverse_transform - N = length(x.x) - y = [y[[i + j * N for j in 0:(x.out_dim - 1)]] for i in 1:N] - end - - # Check if the likelihood samples are of correct length - @test length(rand(rng, lik(y))) == N - - # Check if functor works properly - xs, re = Functors.functor(lik) - @test lik == re(xs) - if isempty(functor_args) - @test xs === () - else - @test keys(xs) == functor_args - end - - return nothing -end - -""" - test_interface(lik, k::Kernel, x::AbstractVector; functor_args=()) - -This function provides unified method to check the interface of the various likelihoods -defined. It checks if the likelihood produces a distribution, length of likelihood -samples is correct and if the functor works as intended. -... -# Arguments -- `lik`: the likelihood to test the interface of -- `k::Kernel`: the kernel to use for the GP -- `x::AbstractVector`: intputs to compute the likelihood on -- `functor_args=()`: a collection of symbols of arguments to match functor parameters with. -... -""" -function test_interface(lik, k::KernelFunctions.Kernel, x::AbstractVector; kwargs...) - return test_interface(Random.GLOBAL_RNG, lik, k, x; kwargs...) -end From 37bae37639c6bb5ec93f3e535f19d8fdb7be0c57 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 16:25:59 +0100 Subject: [PATCH 09/44] Remove docs/Manifest from tracked files --- docs/Manifest.toml | 99 ---------------------------------------------- 1 file changed, 99 deletions(-) delete mode 100644 docs/Manifest.toml diff --git a/docs/Manifest.toml b/docs/Manifest.toml deleted file mode 100644 index b447396..0000000 --- a/docs/Manifest.toml +++ /dev/null @@ -1,99 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[DocStringExtensions]] -deps = ["LibGit2", "Markdown", "Pkg", "Test"] -git-tree-sha1 = "50ddf44c53698f5e784bbebb3f4b21c5807401b1" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.3" - -[[Documenter]] -deps = ["Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "c01a7e8bcf7a6693444a52a0c5ac8b4e9528600e" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.26.0" - -[[IOCapture]] -deps = ["Logging"] -git-tree-sha1 = "377252859f740c217b936cebcd918a44f9b53b59" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.1.1" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" - -[[LibGit2]] -deps = ["Printf"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "6370b5b3cf2ce5a3d2b6f7ab2dc10f374e4d7d2b" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.14" - -[[Pkg]] -deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[Test]] -deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" From c745fc07a1cdf9a727acfecd7e8a5264017e3990 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 16:51:21 +0100 Subject: [PATCH 10/44] Move things around --- .gitignore | 1 + Project.toml | 5 +++-- src/GPLikelihoods.jl | 3 +++ src/TestInterface.jl | 5 ++--- test/runtests.jl | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index a22e235..f4f2fb4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .DS_Store /Manifest.toml test/Manifest.toml +docs/Manifest.toml /dev/ /docs/build/ /docs/site/ diff --git a/Project.toml b/Project.toml index 4a0fd4c..4b8f7dd 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GPLikelihoods" uuid = "6031954c-0455-49d7-b3b9-3e1c99afaf40" authors = ["JuliaGaussianProcesses Team"] -version = "0.2.5" +version = "0.2.6" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" @@ -10,10 +10,11 @@ InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" Functors = "0.1, 0.2" InverseFunctions = "0.1.2" -StatsFuns = "0.9.13" +StatsFuns = "0.9" julia = "1.3" diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index d250c04..1640577 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -39,4 +39,7 @@ include("likelihoods/poisson.jl") include("likelihoods/gamma.jl") include("likelihoods/exponential.jl") +# TestInterface module +include("TestInterface.jl") + end # module diff --git a/src/TestInterface.jl b/src/TestInterface.jl index 623496a..25b0bbb 100644 --- a/src/TestInterface.jl +++ b/src/TestInterface.jl @@ -1,8 +1,7 @@ module TestInterface using Random - -export test_inferface +using Test function test_interface( rng::AbstractRNG, lik, kernel, x::AbstractVector; functor_args=() @@ -59,7 +58,7 @@ samples is correct and if the functor works as intended. ... """ function test_interface(lik, kernel, x::AbstractVector; kwargs...) - return test_interface(Random.GLOBAL_RNG, lik, k, x; kwargs...) + return test_interface(Random.GLOBAL_RNG, lik, kernel, x; kwargs...) end diff --git a/test/runtests.jl b/test/runtests.jl index a465a16..6be558a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,5 @@ using GPLikelihoods -using GPLikelihoods.TestInterface +using GPLikelihoods.TestInterface: test_interface using AbstractGPs using Test using Random From 8f997913a90336447d4571ccddaf0ee1df448535 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 17:20:16 +0100 Subject: [PATCH 11/44] Make docs more explicit --- docs/src/api.md | 9 ++++++--- docs/src/index.md | 33 ++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/docs/src/api.md b/docs/src/api.md index 6daaca5..13b6ca2 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -22,11 +22,14 @@ Link ChainLink ``` -The rest of the links `ExpLink`, `LogisticLink`, etc., are simple aliases for the -corresponding wrapped functions in a `Link`. +The rest of the links [`ExpLink`](@ref), [`LogisticLink`](@ref), etc., +are aliases for the corresponding wrapped functions in a `Link`. For example `ExpLink == Link{typeof(exp)}`. -We provide nonetheless docs for them: +When passing a [`Link`](@ref) to an `AbstractLikelihood`, that this link +corresponds to the transformation `p=link(f)` while, as mentioned in the +[`Constrained parameters`](@ref) section, the statistics literature usually use + the denomination [**inverse link or mean function**](https://en.wikipedia.org/wiki/Generalized_linear_model#Link_function) for it. ```@docs LogLink diff --git a/docs/src/index.md b/docs/src/index.md index b804f97..e7d7b32 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,21 +1,36 @@ -# GPLikelihoods.jl +```@meta +CurrentModule = GPLikelihoods +``` +# GPLikelihoods -`GPLikelihoods.jl` provides a practical interface to connect non-conjugate likelihoods +[`GPLikelihoods.jl`](https://github.com/JuliaGaussianProcesses/GPLikelihoods.jl) provides a practical interface to connect non-conjugate likelihoods with Gaussian Processes. -The API is very basic: Every `AbstractLikelihood` object is a [functor](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects-1) that takes the output of a Gaussian process as input and returns a `Distribution` from [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl). +The API is very basic: Every `AbstractLikelihood` object is a [functor](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects-1) +that takes the output of a Gaussian process as input and returns a +`Distribution` from [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl). ```@repl f = 2.0; GaussianLikelihood()(f) == Normal(2.0) ``` -Since the parameter domain of a lot of distributions is more restricted to the real -domain, for example the parameter of a `Bernoulli` distribution, most `AbstractLikelihood` -contain a `invlink` field which will map the latent variable to the right domain. +### Constrained parameters + +The domain of some distributions parameters can be different from +``\mathbb{R}``, the real domain. +To solve this problem, we also provide the [`Link`](@ref) type, which can be +passed to the [`Likelihood`](@ref) constructors. +Alternatively, `function`s can also directly be passed and will be wrapped in a `Link`). +For more details about which likelihoods require a [`Link`](@ref) check out their docs. +We typically named this passed link as the `invlink`. +This comes from the statistic literature, where the "link" is defined as `f = link(y)`. + +A classical example is the [`BernoulliLikelihood`](@ref) for classification, with the probability parameter ``p \in \[0, 1\]``. +The default it to use a [`logistic`](https://en.wikipedia.org/wiki/Logistic_function) transformation, but one could also use the inverse of the [`probit`](https://en.wikipedia.org/wiki/Probit) link: ```@repl f = 2.0; -BernoulliLikelihood(logistic)(f) == Bernoulli(logistic(2.0)) +BernoulliLikelihood()(f) == Bernoulli(logistic(f)) +BernoulliLikelihood(NormalCDFLink()) == Bernoulli(normalcdf(f)) ``` - -[`Link`](@ref)s can be created using the constructor `Link(l)` where `l` is a function or a functor. \ No newline at end of file +Note that we passed the `inverse` of the `probit` function which is the `normalcdf` function. \ No newline at end of file From ce81e7b5e7607ec1002119e8d58ea56b8271aca5 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 17:25:56 +0100 Subject: [PATCH 12/44] Saved current version of TestInterface --- src/TestInterface.jl | 7 ++-- test/TestInterface.jl.save | 65 +++++++++++++++++++++++++++++++++++ test/likelihoods/bernoulli.jl | 2 +- 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 test/TestInterface.jl.save diff --git a/src/TestInterface.jl b/src/TestInterface.jl index 25b0bbb..51b8167 100644 --- a/src/TestInterface.jl +++ b/src/TestInterface.jl @@ -4,14 +4,11 @@ using Random using Test function test_interface( -rng::AbstractRNG, lik, kernel, x::AbstractVector; functor_args=() +rng::AbstractRNG, lik, D_in=1; functor_args=() ) -gp = GP(kernel) -lgp = LatentGP(gp, lik, 1e-5) -lfgp = lgp(x) # Check if likelihood produces a distribution -@test lik(rand(rng, lfgp.fx)) isa Distribution +@test lik(rand(rng, )) isa Distribution N = length(x) y = rand(rng, lfgp.fx) diff --git a/test/TestInterface.jl.save b/test/TestInterface.jl.save new file mode 100644 index 0000000..0d8a17d --- /dev/null +++ b/test/TestInterface.jl.save @@ -0,0 +1,65 @@ +module TestInterface + +using Random +using Test + +function test_interface( +rng::AbstractRNG, lik, x::AbstractVector; functor_args=() +) +gp = GP(kernel) +lgp = LatentGP(gp, lik, 1e-5) +lfgp = lgp(x) + +# Check if likelihood produces a distribution +@test lik(rand(rng, lfgp.fx)) isa Distribution + +N = length(x) +y = rand(rng, lfgp.fx) + +if x isa MOInput + # TODO: replace with mo_inverse_transform + N = length(x.x) + y = [y[[i + j * N for j in 0:(x.out_dim - 1)]] for i in 1:N] +end + +# Check if the likelihood samples are of correct length +@test length(rand(rng, lik(y))) == N + +# Check if functor works properly +xs, re = Functors.functor(lik) +@test lik == re(xs) +if isempty(functor_args) + @test xs === () +else + @test keys(xs) == functor_args +end + +return nothing +end + +@doc raw""" + test_interface([rng::AbstractRNG,] lik, k::Kernel, x::AbstractVector; functor_args=()) + +!!! warning + + KernelFunctions.jl and AbstractGPs.jl need to be loaded in the current workspace + to run this function. + +This function provides unified method to check the interface of the various likelihoods +defined. It checks if the likelihood produces a distribution, length of likelihood +samples is correct and if the functor works as intended. + +... +# Arguments +- `lik`: the likelihood to test the interface of +- `k::Kernel`: the kernel to use for the GP +- `x::AbstractVector`: inputs to compute the likelihood on +- `functor_args=()`: a collection of symbols of arguments to match functor parameters with. +... +""" +function test_interface(lik, kernel, x::AbstractVector; kwargs...) + return test_interface(Random.GLOBAL_RNG, lik, kernel, x; kwargs...) +end + + +end \ No newline at end of file diff --git a/test/likelihoods/bernoulli.jl b/test/likelihoods/bernoulli.jl index 4cc2039..4905ac4 100644 --- a/test/likelihoods/bernoulli.jl +++ b/test/likelihoods/bernoulli.jl @@ -4,5 +4,5 @@ end lik = BernoulliLikelihood() - test_interface(lik, SqExponentialKernel(), rand(10)) + test_interface(lik) end From a72eacefbdc1d5b7046bbd50449c4076d029fd31 Mon Sep 17 00:00:00 2001 From: Theo Galy-Fajou Date: Thu, 16 Dec 2021 17:48:58 +0100 Subject: [PATCH 13/44] Simplified the tests --- src/TestInterface.jl | 84 ++++++++++++++++----------------- test/Project.toml | 2 - test/likelihoods/bernoulli.jl | 2 +- test/likelihoods/categorical.jl | 8 ++-- test/likelihoods/exponential.jl | 2 +- test/likelihoods/gamma.jl | 2 +- test/likelihoods/gaussian.jl | 6 +-- test/likelihoods/poisson.jl | 2 +- test/runtests.jl | 1 - 9 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/TestInterface.jl b/src/TestInterface.jl index 51b8167..4556ec3 100644 --- a/src/TestInterface.jl +++ b/src/TestInterface.jl @@ -1,62 +1,60 @@ module TestInterface +using Functors using Random using Test -function test_interface( -rng::AbstractRNG, lik, D_in=1; functor_args=() -) - -# Check if likelihood produces a distribution -@test lik(rand(rng, )) isa Distribution - -N = length(x) -y = rand(rng, lfgp.fx) - -if x isa MOInput - # TODO: replace with mo_inverse_transform - N = length(x.x) - y = [y[[i + j * N for j in 0:(x.out_dim - 1)]] for i in 1:N] -end - -# Check if the likelihood samples are of correct length -@test length(rand(rng, lik(y))) == N - -# Check if functor works properly -xs, re = Functors.functor(lik) -@test lik == re(xs) -if isempty(functor_args) - @test xs === () -else - @test keys(xs) == functor_args -end - -return nothing +function test_interface(rng::AbstractRNG, lik, out_dist, D_in=1; functor_args=()) + N = 10 + T = Float64 # TODO test Float32 as well + f, fs = if D_in == 1 + f = randn(rng, T) + fs = randn(rng, T, 10) + f, fs + else + f = randn(rng, T, D_in) + fs = [randn(rng, T, D_in) for _ in 1:N] + f, fs + end + # Check if likelihood produces the correct distribution + # and is sampleable + @test lik(f) isa out_dist + @test_nowarn rand(rng, lik(f)) + + # Check if the likelihood samples are of correct length + @test length(rand(rng, lik(fs))) == N + + # Check if functor works properly + xs, re = Functors.functor(lik) + @test lik == re(xs) + if isempty(functor_args) + @test xs === () + else + @test keys(xs) == functor_args + end + + return nothing end @doc raw""" - test_interface([rng::AbstractRNG,] lik, k::Kernel, x::AbstractVector; functor_args=()) - -!!! warning - - KernelFunctions.jl and AbstractGPs.jl need to be loaded in the current workspace - to run this function. + test_interface([rng::AbstractRNG,] lik, out_dist; functor_args=()) This function provides unified method to check the interface of the various likelihoods -defined. It checks if the likelihood produces a distribution, length of likelihood +defined. It checks if the likelihood produces the correct distribution, length of likelihood samples is correct and if the functor works as intended. ... -# Arguments +## Arguments - `lik`: the likelihood to test the interface of -- `k::Kernel`: the kernel to use for the GP -- `x::AbstractVector`: inputs to compute the likelihood on +- `out_dist::Type{<:Distribution}`: the type of distribution the likelihood should return +- `D_in::Int=1` : The input dimension of the likelihood + +## Keyword arguments - `functor_args=()`: a collection of symbols of arguments to match functor parameters with. ... """ -function test_interface(lik, kernel, x::AbstractVector; kwargs...) - return test_interface(Random.GLOBAL_RNG, lik, kernel, x; kwargs...) +function test_interface(lik, out_dist, D_in=1; kwargs...) + return test_interface(Random.GLOBAL_RNG, lik, out_dist, D_in; kwargs...) end - -end \ No newline at end of file +end diff --git a/test/Project.toml b/test/Project.toml index bccaf0a..259ad91 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,4 @@ [deps] -AbstractGPs = "99985d1d-32ba-4be9-9821-2ec096f28918" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Functors = "d9f16b24-f501-4c13-a1f2-28368ffc5196" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -7,7 +6,6 @@ StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -AbstractGPs = "0.2, 0.3, 0.4, 0.5" Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" Functors = "0.1, 0.2" StatsFuns = "0.9" diff --git a/test/likelihoods/bernoulli.jl b/test/likelihoods/bernoulli.jl index 4905ac4..d9a9b28 100644 --- a/test/likelihoods/bernoulli.jl +++ b/test/likelihoods/bernoulli.jl @@ -4,5 +4,5 @@ end lik = BernoulliLikelihood() - test_interface(lik) + test_interface(lik, Bernoulli) end diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index 042c1e6..ed5184f 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -4,9 +4,9 @@ end lik = CategoricalLikelihood() - IN_DIM = 3 + # IN_DIM = 3 OUT_DIM = 4 - N = 10 - X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) - test_interface(lik, IndependentMOKernel(SqExponentialKernel()), X) + # N = 10 + # X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) + test_interface(lik, Categorical, OUT_DIM) end diff --git a/test/likelihoods/exponential.jl b/test/likelihoods/exponential.jl index 7b3c383..4fd9ea8 100644 --- a/test/likelihoods/exponential.jl +++ b/test/likelihoods/exponential.jl @@ -4,5 +4,5 @@ end lik = ExponentialLikelihood() - test_interface(lik, SqExponentialKernel(), rand(10)) + test_interface(lik, Exponential) end diff --git a/test/likelihoods/gamma.jl b/test/likelihoods/gamma.jl index 05c7ca9..1c5141e 100644 --- a/test/likelihoods/gamma.jl +++ b/test/likelihoods/gamma.jl @@ -6,5 +6,5 @@ end lik = GammaLikelihood(1.0) - test_interface(lik, SqExponentialKernel(), rand(10); functor_args=(:α, :invlink)) + test_interface(lik, Gamma; functor_args=(:α, :invlink)) end diff --git a/test/likelihoods/gaussian.jl b/test/likelihoods/gaussian.jl index 53ad0ed..79c964e 100644 --- a/test/likelihoods/gaussian.jl +++ b/test/likelihoods/gaussian.jl @@ -1,6 +1,6 @@ @testset "GaussianLikelihood" begin lik = GaussianLikelihood(1e-5) - test_interface(lik, SqExponentialKernel(), rand(10); functor_args=(:σ²,)) + test_interface(lik, Normal; functor_args=(:σ²,)) end @testset "HeteroscedasticGaussianLikelihood" begin @@ -13,6 +13,6 @@ end IN_DIM = 3 OUT_DIM = 2 # one for the mean the other for the log-standard deviation N = 10 - X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) - test_interface(lik, IndependentMOKernel(SqExponentialKernel()), X) + # X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) + test_interface(lik, Normal, 2) end diff --git a/test/likelihoods/poisson.jl b/test/likelihoods/poisson.jl index a5d00a5..9369e94 100644 --- a/test/likelihoods/poisson.jl +++ b/test/likelihoods/poisson.jl @@ -4,6 +4,6 @@ end for lik in (PoissonLikelihood(), PoissonLikelihood(log1pexp)) - test_interface(lik, SqExponentialKernel(), rand(10)) + test_interface(lik, Poisson) end end diff --git a/test/runtests.jl b/test/runtests.jl index 6be558a..1d6735b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,5 @@ using GPLikelihoods using GPLikelihoods.TestInterface: test_interface -using AbstractGPs using Test using Random using Functors From fb7544bdcf6e0f45b7da8a124fa9e573bc554d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 16 Dec 2021 18:08:20 +0100 Subject: [PATCH 14/44] Revert compat StatsFuns --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4b8f7dd..7e9bece 100644 --- a/Project.toml +++ b/Project.toml @@ -16,5 +16,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" Functors = "0.1, 0.2" InverseFunctions = "0.1.2" -StatsFuns = "0.9" +StatsFuns = "0.9.13" julia = "1.3" From 587ee76d4882d45603e38c23e9fe6772407a08b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Mon, 20 Dec 2021 17:18:34 +0100 Subject: [PATCH 15/44] Delete TestInterface.jl.save --- test/TestInterface.jl.save | 65 -------------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 test/TestInterface.jl.save diff --git a/test/TestInterface.jl.save b/test/TestInterface.jl.save deleted file mode 100644 index 0d8a17d..0000000 --- a/test/TestInterface.jl.save +++ /dev/null @@ -1,65 +0,0 @@ -module TestInterface - -using Random -using Test - -function test_interface( -rng::AbstractRNG, lik, x::AbstractVector; functor_args=() -) -gp = GP(kernel) -lgp = LatentGP(gp, lik, 1e-5) -lfgp = lgp(x) - -# Check if likelihood produces a distribution -@test lik(rand(rng, lfgp.fx)) isa Distribution - -N = length(x) -y = rand(rng, lfgp.fx) - -if x isa MOInput - # TODO: replace with mo_inverse_transform - N = length(x.x) - y = [y[[i + j * N for j in 0:(x.out_dim - 1)]] for i in 1:N] -end - -# Check if the likelihood samples are of correct length -@test length(rand(rng, lik(y))) == N - -# Check if functor works properly -xs, re = Functors.functor(lik) -@test lik == re(xs) -if isempty(functor_args) - @test xs === () -else - @test keys(xs) == functor_args -end - -return nothing -end - -@doc raw""" - test_interface([rng::AbstractRNG,] lik, k::Kernel, x::AbstractVector; functor_args=()) - -!!! warning - - KernelFunctions.jl and AbstractGPs.jl need to be loaded in the current workspace - to run this function. - -This function provides unified method to check the interface of the various likelihoods -defined. It checks if the likelihood produces a distribution, length of likelihood -samples is correct and if the functor works as intended. - -... -# Arguments -- `lik`: the likelihood to test the interface of -- `k::Kernel`: the kernel to use for the GP -- `x::AbstractVector`: inputs to compute the likelihood on -- `functor_args=()`: a collection of symbols of arguments to match functor parameters with. -... -""" -function test_interface(lik, kernel, x::AbstractVector; kwargs...) - return test_interface(Random.GLOBAL_RNG, lik, kernel, x; kwargs...) -end - - -end \ No newline at end of file From 5e3aa5b0de6bbaef743b24fddbd74308336faee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Tue, 4 Jan 2022 13:52:48 +0100 Subject: [PATCH 16/44] Tidying up Co-authored-by: willtebbutt --- test/likelihoods/categorical.jl | 3 --- test/likelihoods/gaussian.jl | 1 - 2 files changed, 4 deletions(-) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index ed5184f..b129a24 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -4,9 +4,6 @@ end lik = CategoricalLikelihood() - # IN_DIM = 3 OUT_DIM = 4 - # N = 10 - # X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) test_interface(lik, Categorical, OUT_DIM) end diff --git a/test/likelihoods/gaussian.jl b/test/likelihoods/gaussian.jl index 79c964e..fe9f210 100644 --- a/test/likelihoods/gaussian.jl +++ b/test/likelihoods/gaussian.jl @@ -13,6 +13,5 @@ end IN_DIM = 3 OUT_DIM = 2 # one for the mean the other for the log-standard deviation N = 10 - # X = MOInput([rand(IN_DIM) for _ in 1:N], OUT_DIM) test_interface(lik, Normal, 2) end From 0d624816fb9caee322d2e9a473814a3925ecc876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Tue, 4 Jan 2022 14:09:47 +0100 Subject: [PATCH 17/44] Delete Manifest.toml --- docs/Manifest.toml | 92 ---------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 docs/Manifest.toml diff --git a/docs/Manifest.toml b/docs/Manifest.toml deleted file mode 100644 index f7288ca..0000000 --- a/docs/Manifest.toml +++ /dev/null @@ -1,92 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[ANSIColoredPrinters]] -git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" -uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" -version = "0.0.1" - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.5" - -[[Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "8b43e37cfb4f4edc2b6180409acc0cebce7fede8" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.7" - -[[IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.2" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.2" - -[[LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "98f59ff3639b3d9485a03a72f3ab35bab9465720" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.0.6" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" From f10bd3eb90cff691ed10757a066feb092368733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Tue, 4 Jan 2022 14:24:05 +0100 Subject: [PATCH 18/44] Update docs/src/api.md Co-authored-by: willtebbutt --- docs/src/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/api.md b/docs/src/api.md index 13b6ca2..48ec7ce 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -26,7 +26,7 @@ The rest of the links [`ExpLink`](@ref), [`LogisticLink`](@ref), etc., are aliases for the corresponding wrapped functions in a `Link`. For example `ExpLink == Link{typeof(exp)}`. -When passing a [`Link`](@ref) to an `AbstractLikelihood`, that this link +When passing a [`Link`](@ref) to an `AbstractLikelihood`, this link corresponds to the transformation `p=link(f)` while, as mentioned in the [`Constrained parameters`](@ref) section, the statistics literature usually use the denomination [**inverse link or mean function**](https://en.wikipedia.org/wiki/Generalized_linear_model#Link_function) for it. From f00d7b229adff76af9481da53f137c4f8365ffc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Tue, 4 Jan 2022 14:45:12 +0100 Subject: [PATCH 19/44] Explain single-latent vs multi-latent --- docs/src/index.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index e7d7b32..3b20c05 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -3,15 +3,34 @@ CurrentModule = GPLikelihoods ``` # GPLikelihoods -[`GPLikelihoods.jl`](https://github.com/JuliaGaussianProcesses/GPLikelihoods.jl) provides a practical interface to connect non-conjugate likelihoods -with Gaussian Processes. +[`GPLikelihoods.jl`](https://github.com/JuliaGaussianProcesses/GPLikelihoods.jl) provides a practical interface to connect Gaussian and non-conjugate likelihoods +to Gaussian Processes. The API is very basic: Every `AbstractLikelihood` object is a [functor](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects-1) -that takes the output of a Gaussian process as input and returns a -`Distribution` from [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl). +taking a `Real` or an `AbstractVector` as an input and returns a +`Distribution` from [`Distributions.jl`](https://github.com/JuliaStats/Distributions.jl). +### Single-latent vs multi-latent likelihoods + +Most likelihoods, like the [`GaussianLikelihood`](@ref), only require one latent Gaussian process. +Passing a `Real` will therefore return a [`UnivariateDistribution`](https://juliastats.org/Distributions.jl/latest/univariate/), +and passing an `AbstractVector{<:Real}` will return a [multivariate product of distributions](https://juliastats.org/Distributions.jl/latest/multivariate/#Product-distributions). ```@repl f = 2.0; GaussianLikelihood()(f) == Normal(2.0) +fs = [2.0, 3.0, 1.5] +GaussianLikelihood()(fs) == Product([Normal(2.0), Normal(3.0), Normal(1.5)]) +``` + +Some likelihoods, like the [`CategoricalLikelihood`](@ref), requires multiple latent Gaussian processes, +and an `AbstractVector{<:Real}` needs to be passed. +To obtain a product of distributions an `AbstractVector{<:AbstractVector{<:Real}}` has to be passed (we recommend +using [`ColVecs` and `RowVecs` from KernelFunctions.jl](https://juliagaussianprocesses.github.io/KernelFunctions.jl/stable/api/#Vector-Valued-Inputs) +if you need to transform an `AbstractMatrix`). +```@repl +fs = [2.0, 3.0, 4.5]; +CategoricalLikelihood()(fs) isa Categorical +Fs = [rand(3) for _ in 1:4] +CategoricalLikelihood()(Fs) isa Product{<:Any,<:Categorical} ``` ### Constrained parameters @@ -33,4 +52,4 @@ f = 2.0; BernoulliLikelihood()(f) == Bernoulli(logistic(f)) BernoulliLikelihood(NormalCDFLink()) == Bernoulli(normalcdf(f)) ``` -Note that we passed the `inverse` of the `probit` function which is the `normalcdf` function. \ No newline at end of file +Note that we passed the `inverse` of the `probit` function which is the `normalcdf` function. From 0ad840f84ac6c0a8272e8792c2452af7cf3cbfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 15:34:36 +0100 Subject: [PATCH 20/44] Rework categorical to allow multiple variants --- Project.toml | 2 +- src/GPLikelihoods.jl | 2 ++ src/likelihoods/categorical.jl | 34 ++++++++++++++++++++++++++++------ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index 7e9bece..f069172 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GPLikelihoods" uuid = "6031954c-0455-49d7-b3b9-3e1c99afaf40" authors = ["JuliaGaussianProcesses Team"] -version = "0.2.6" +version = "0.2.7" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 1640577..4e4079c 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -14,6 +14,8 @@ export BernoulliLikelihood, PoissonLikelihood, ExponentialLikelihood, GammaLikelihood +export SimplexVariant, + CurvedVariant export Link, ChainLink, ExpLink, diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 9756c0d..0a98d4b 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -1,22 +1,44 @@ +struct SimplexVariant end + +struct CurvedVariant end + """ - CategoricalLikelihood(l=softmax) + CategoricalLikelihood(l=softmax, variant=SimplexVariant()) Categorical likelihood is to be used if we assume that the -uncertainity associated with the data follows a Categorical distribution. +uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution) with `n` categories. ```math p(y|f_1, f_2, \\dots, f_{n-1}) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_{n-1}, 0)) + p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) ``` +Two variants are possible: +## `SimplexVariant` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n-1}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n-1}, 0)``. +It is used by default. + +## `CurvedVariant` +Given an `AbstractVector` ``[f_1, f_2, ..., f_{n}]``, returns a `Categorical` distribution, +with probabilities given by ``l(f_1, f_2, ..., f_{n})``. +The "Curved" comes from the fact that such a distribution is "curved exponential family" +as there are `n-1` independent parameters embedded in a `n` dimensional parameter space. +A lot of standard results for exponential families do not apply. +For more explanations, see this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) at the end of the section. +Use with caution! """ -struct CategoricalLikelihood{Tl<:AbstractLink} <: AbstractLikelihood +struct CategoricalLikelihood{Tl<:AbstractLink,Tv} <: AbstractLikelihood invlink::Tl + variant::Tv end -CategoricalLikelihood(l=softmax) = CategoricalLikelihood(Link(l)) +CategoricalLikelihood(l=softmax, variant=SimplexVariant()) = CategoricalLikelihood(Link(l), variant) -(l::CategoricalLikelihood)(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) +(l::CategoricalLikelihood{<:AbstractLink,SimplexVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) +(l::CategoricalLikelihood{<:AbstractLink,CurvedVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(f)) -function (l::CategoricalLikelihood)(fs::AbstractVector) +function (l::CategoricalLikelihood{<:AbstractLink,SimplexVariant})(fs::AbstractVector) return Product(Categorical.(l.invlink.(vcat.(fs, 0)))) end +function (l::CategoricalLikelihood{<:AbstractLink,CurvedVariant})(fs::AbstractVector) + return Product(Categorical.(l.invlink.(fs))) +end \ No newline at end of file From 846187208067a7cf3d8af2af1e08b73aba16af6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 15:41:04 +0100 Subject: [PATCH 21/44] Rework the constructor --- src/likelihoods/categorical.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 0a98d4b..2aef714 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -26,12 +26,12 @@ A lot of standard results for exponential families do not apply. For more explanations, see this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) at the end of the section. Use with caution! """ -struct CategoricalLikelihood{Tl<:AbstractLink,Tv} <: AbstractLikelihood +struct CategoricalLikelihood{Tv,Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl - variant::Tv + CategoricalLikelihood{Tv}(invlink::Tl) where {Tv,Tl} = new{Tv,Tl}(invlink) end -CategoricalLikelihood(l=softmax, variant=SimplexVariant()) = CategoricalLikelihood(Link(l), variant) +CategoricalLikelihood(l=softmax, variant=SimplexVariant()) = CategoricalLikelihood{typeof(variant)}(Link(l)) (l::CategoricalLikelihood{<:AbstractLink,SimplexVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) (l::CategoricalLikelihood{<:AbstractLink,CurvedVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(f)) From 0ac79c24483e143071df12197781520861ab5809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 16:21:33 +0100 Subject: [PATCH 22/44] Correct functions and add tests --- src/likelihoods/categorical.jl | 8 ++++---- test/likelihoods/categorical.jl | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 2aef714..03de1eb 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -33,12 +33,12 @@ end CategoricalLikelihood(l=softmax, variant=SimplexVariant()) = CategoricalLikelihood{typeof(variant)}(Link(l)) -(l::CategoricalLikelihood{<:AbstractLink,SimplexVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) -(l::CategoricalLikelihood{<:AbstractLink,CurvedVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(f)) +(l::CategoricalLikelihood{SimplexVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) +(l::CategoricalLikelihood{CurvedVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(f)) -function (l::CategoricalLikelihood{<:AbstractLink,SimplexVariant})(fs::AbstractVector) +function (l::CategoricalLikelihood{SimplexVariant})(fs::AbstractVector) return Product(Categorical.(l.invlink.(vcat.(fs, 0)))) end -function (l::CategoricalLikelihood{<:AbstractLink,CurvedVariant})(fs::AbstractVector) +function (l::CategoricalLikelihood{CurvedVariant})(fs::AbstractVector) return Product(Categorical.(l.invlink.(fs))) end \ No newline at end of file diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index b129a24..a89f4d4 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,9 +1,12 @@ @testset "CategoricalLikelihood" begin for args in ((), (softmax,), (SoftMaxLink(),)) - @test CategoricalLikelihood(args...) isa CategoricalLikelihood{SoftMaxLink} + @test CategoricalLikelihood(args...) isa CategoricalLikelihood{SimplexVariant,SoftMaxLink} end + @test CategoricalLikelihood(softmax, CurvedVariant()) isa CategoricalLikelihood{CurvedVariant,SoftMaxLink} - lik = CategoricalLikelihood() + lik_simplex = CategoricalLikelihood() OUT_DIM = 4 test_interface(lik, Categorical, OUT_DIM) + lik_curved = CategoricalLikelihood(softmax, CurvedVariant()) + test_interface(lik, Categorical, OUT_DIM) end From ec10c5e9dd37aff8a5416adb9e7769bcdffc1170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 16:22:12 +0100 Subject: [PATCH 23/44] Formatting --- src/GPLikelihoods.jl | 3 +-- src/likelihoods/categorical.jl | 14 ++++++++++---- test/likelihoods/categorical.jl | 6 ++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 4e4079c..1e0bea5 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -14,8 +14,7 @@ export BernoulliLikelihood, PoissonLikelihood, ExponentialLikelihood, GammaLikelihood -export SimplexVariant, - CurvedVariant +export SimplexVariant, CurvedVariant export Link, ChainLink, ExpLink, diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 03de1eb..0627395 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -31,14 +31,20 @@ struct CategoricalLikelihood{Tv,Tl<:AbstractLink} <: AbstractLikelihood CategoricalLikelihood{Tv}(invlink::Tl) where {Tv,Tl} = new{Tv,Tl}(invlink) end -CategoricalLikelihood(l=softmax, variant=SimplexVariant()) = CategoricalLikelihood{typeof(variant)}(Link(l)) +function CategoricalLikelihood(l=softmax, variant=SimplexVariant()) + return CategoricalLikelihood{typeof(variant)}(Link(l)) +end -(l::CategoricalLikelihood{SimplexVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) -(l::CategoricalLikelihood{CurvedVariant})(f::AbstractVector{<:Real}) = Categorical(l.invlink(f)) +function (l::CategoricalLikelihood{SimplexVariant})(f::AbstractVector{<:Real}) + return Categorical(l.invlink(vcat(f, 0))) +end +function (l::CategoricalLikelihood{CurvedVariant})(f::AbstractVector{<:Real}) + return Categorical(l.invlink(f)) +end function (l::CategoricalLikelihood{SimplexVariant})(fs::AbstractVector) return Product(Categorical.(l.invlink.(vcat.(fs, 0)))) end function (l::CategoricalLikelihood{CurvedVariant})(fs::AbstractVector) return Product(Categorical.(l.invlink.(fs))) -end \ No newline at end of file +end diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index a89f4d4..a71d6da 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,8 +1,10 @@ @testset "CategoricalLikelihood" begin for args in ((), (softmax,), (SoftMaxLink(),)) - @test CategoricalLikelihood(args...) isa CategoricalLikelihood{SimplexVariant,SoftMaxLink} + @test CategoricalLikelihood(args...) isa + CategoricalLikelihood{SimplexVariant,SoftMaxLink} end - @test CategoricalLikelihood(softmax, CurvedVariant()) isa CategoricalLikelihood{CurvedVariant,SoftMaxLink} + @test CategoricalLikelihood(softmax, CurvedVariant()) isa + CategoricalLikelihood{CurvedVariant,SoftMaxLink} lik_simplex = CategoricalLikelihood() OUT_DIM = 4 From 44a1f01f3ea2d1670cb7147a9f9250986deac747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 17:22:25 +0100 Subject: [PATCH 24/44] Readapt naming --- src/GPLikelihoods.jl | 1 - src/likelihoods/categorical.jl | 35 ++++++++++++++------------------- test/likelihoods/categorical.jl | 16 +++++++-------- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 1e0bea5..1640577 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -14,7 +14,6 @@ export BernoulliLikelihood, PoissonLikelihood, ExponentialLikelihood, GammaLikelihood -export SimplexVariant, CurvedVariant export Link, ChainLink, ExpLink, diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 0627395..f949e97 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -1,9 +1,5 @@ -struct SimplexVariant end - -struct CurvedVariant end - """ - CategoricalLikelihood(l=softmax, variant=SimplexVariant()) + CategoricalLikelihood(l=softmax, bijective=true)::CategoricalLikelihood{bijective,typeof(Link(k))} Categorical likelihood is to be used if we assume that the uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution) with `n` categories. @@ -12,39 +8,38 @@ uncertainty associated with the data follows a [Categorical distribution](https: p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) ``` Two variants are possible: -## `SimplexVariant` +## `bijective=true` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n-1}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n-1}, 0)``. It is used by default. -## `CurvedVariant` +## `bijective=false` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n})``. -The "Curved" comes from the fact that such a distribution is "curved exponential family" -as there are `n-1` independent parameters embedded in a `n` dimensional parameter space. -A lot of standard results for exponential families do not apply. -For more explanations, see this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) at the end of the section. -Use with caution! +This variant is over-parametrized, as there are `n-1` independent parameters +embedded in a `n` dimensional parameter space. +For more details, see the end of the section of this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) +where it corresponds to Variant 1 and 2. """ -struct CategoricalLikelihood{Tv,Tl<:AbstractLink} <: AbstractLikelihood +struct CategoricalLikelihood{Tb,Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl - CategoricalLikelihood{Tv}(invlink::Tl) where {Tv,Tl} = new{Tv,Tl}(invlink) + CategoricalLikelihood{Tb}(invlink::Tl) where {Tb,Tl} = new{Tb,Tl}(invlink) end -function CategoricalLikelihood(l=softmax, variant=SimplexVariant()) - return CategoricalLikelihood{typeof(variant)}(Link(l)) +function CategoricalLikelihood(l=softmax, bijective=true) + return CategoricalLikelihood{bijective}(Link(l)) end -function (l::CategoricalLikelihood{SimplexVariant})(f::AbstractVector{<:Real}) +function (l::CategoricalLikelihood{true})(f::AbstractVector{<:Real}) return Categorical(l.invlink(vcat(f, 0))) end -function (l::CategoricalLikelihood{CurvedVariant})(f::AbstractVector{<:Real}) +function (l::CategoricalLikelihood{false})(f::AbstractVector{<:Real}) return Categorical(l.invlink(f)) end -function (l::CategoricalLikelihood{SimplexVariant})(fs::AbstractVector) +function (l::CategoricalLikelihood{true})(fs::AbstractVector) return Product(Categorical.(l.invlink.(vcat.(fs, 0)))) end -function (l::CategoricalLikelihood{CurvedVariant})(fs::AbstractVector) +function (l::CategoricalLikelihood{false})(fs::AbstractVector) return Product(Categorical.(l.invlink.(fs))) end diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index a71d6da..d966692 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,14 +1,14 @@ @testset "CategoricalLikelihood" begin - for args in ((), (softmax,), (SoftMaxLink(),)) + for args in ((), (softmax,), (softmax, true), (SoftMaxLink(),)) @test CategoricalLikelihood(args...) isa - CategoricalLikelihood{SimplexVariant,SoftMaxLink} + CategoricalLikelihood{true,SoftMaxLink} end - @test CategoricalLikelihood(softmax, CurvedVariant()) isa - CategoricalLikelihood{CurvedVariant,SoftMaxLink} + @test CategoricalLikelihood(softmax, false) isa + CategoricalLikelihood{false,SoftMaxLink} - lik_simplex = CategoricalLikelihood() + lik_bijective = CategoricalLikelihood() OUT_DIM = 4 - test_interface(lik, Categorical, OUT_DIM) - lik_curved = CategoricalLikelihood(softmax, CurvedVariant()) - test_interface(lik, Categorical, OUT_DIM) + test_interface(lik_bijective, Categorical, OUT_DIM) + lik_nonbijective = CategoricalLikelihood(softmax, false) + test_interface(lik_nonbijective, Categorical, OUT_DIM) end From f79136b107a8ed450adaf37a899d8633d136b660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 17:22:45 +0100 Subject: [PATCH 25/44] Formatting --- test/likelihoods/categorical.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index d966692..5af2bee 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,10 +1,8 @@ @testset "CategoricalLikelihood" begin for args in ((), (softmax,), (softmax, true), (SoftMaxLink(),)) - @test CategoricalLikelihood(args...) isa - CategoricalLikelihood{true,SoftMaxLink} + @test CategoricalLikelihood(args...) isa CategoricalLikelihood{true,SoftMaxLink} end - @test CategoricalLikelihood(softmax, false) isa - CategoricalLikelihood{false,SoftMaxLink} + @test CategoricalLikelihood(softmax, false) isa CategoricalLikelihood{false,SoftMaxLink} lik_bijective = CategoricalLikelihood() OUT_DIM = 4 From e3d79dbe5c19e09a11667c5ac6277c742296cbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 17:45:31 +0100 Subject: [PATCH 26/44] Missing default constructor --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f069172..47459d2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GPLikelihoods" uuid = "6031954c-0455-49d7-b3b9-3e1c99afaf40" authors = ["JuliaGaussianProcesses Team"] -version = "0.2.7" +version = "0.3.0" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" From 8b076ba18747c2d9c9f51ed0eae6c13eaf318038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 17:45:48 +0100 Subject: [PATCH 27/44] Missing function definition --- src/likelihoods/categorical.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index f949e97..5812623 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -30,6 +30,8 @@ function CategoricalLikelihood(l=softmax, bijective=true) return CategoricalLikelihood{bijective}(Link(l)) end +CategoricalLikelihood(l::AbstractLink, bijective=true) = CategoricalLikelihood{bijective}(l) + function (l::CategoricalLikelihood{true})(f::AbstractVector{<:Real}) return Categorical(l.invlink(vcat(f, 0))) end From ba7ec3b02b6fffd13b42a10268bf4d57408954f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 18:11:19 +0100 Subject: [PATCH 28/44] Applied suggestions --- src/likelihoods/categorical.jl | 17 ++++++++++------- test/likelihoods/categorical.jl | 18 ++++++++++++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 5812623..7977ab6 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -1,5 +1,5 @@ """ - CategoricalLikelihood(l=softmax, bijective=true)::CategoricalLikelihood{bijective,typeof(Link(k))} + CategoricalLikelihood(l=softmax; bijective::Union{Bool,Val{false},Val{true}}=Val(true)) Categorical likelihood is to be used if we assume that the uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution) with `n` categories. @@ -7,8 +7,9 @@ uncertainty associated with the data follows a [Categorical distribution](https: p(y|f_1, f_2, \\dots, f_{n-1}) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_{n-1}, 0)) p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) ``` -Two variants are possible: -## `bijective=true` +Two variants are possible (you can use a `Bool` or `Val{true}`/`Val{false}` but +we recommend the latter for type stability). +## `bijective=true/Val{true}` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n-1}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n-1}, 0)``. It is used by default. @@ -23,14 +24,16 @@ where it corresponds to Variant 1 and 2. """ struct CategoricalLikelihood{Tb,Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl - CategoricalLikelihood{Tb}(invlink::Tl) where {Tb,Tl} = new{Tb,Tl}(invlink) + CategoricalLikelihood{Tb}(invlink) where {Tb} = CategoricalLikelihood{Tb}(Link(invlink)) + CategoricalLikelihood{Tb}(invlink::Tl) where {Tb,Tl<:AbstractLink} = new{Tb,Tl}(invlink) end -function CategoricalLikelihood(l=softmax, bijective=true) - return CategoricalLikelihood{bijective}(Link(l)) +function CategoricalLikelihood(l=softmax; bijective::Union{Bool,Val{true},Val{false}}=Val(true)) + CategoricalLikelihood{bijective_typeparameter(bijective)}(l) end -CategoricalLikelihood(l::AbstractLink, bijective=true) = CategoricalLikelihood{bijective}(l) +bijective_typeparameter(bijective::Bool) = bijective +bijective_typeparameter(::Val{T}) = T function (l::CategoricalLikelihood{true})(f::AbstractVector{<:Real}) return Categorical(l.invlink(vcat(f, 0))) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index 5af2bee..dbf8271 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,8 +1,18 @@ @testset "CategoricalLikelihood" begin - for args in ((), (softmax,), (softmax, true), (SoftMaxLink(),)) - @test CategoricalLikelihood(args...) isa CategoricalLikelihood{true,SoftMaxLink} - end - @test CategoricalLikelihood(softmax, false) isa CategoricalLikelihood{false,SoftMaxLink} + Catbij = CategoricalLikelihood{true,SoftMaxLink} + @test CategoricalLikelihood() isa Catbij + @test CategoricalLikelihood(; bijective=true) isa Catbij + @test CategoricalLikelihood(softmax) isa Catbij + @test CategoricalLikelihood(SoftMaxLink()) isa Catbij + @test CategoricalLikelihood(softmax; bijective=true) isa Catbij + @test CategoricalLikelihood(SoftMaxLink(); bijective=true) isa Catbij + + Catnonbij = CategoricalLikelihood{false,SoftMaxLink} + @test CategoricalLikelihood(;bijective=false) isa Catnonbij + @test CategoricalLikelihood(softmax; bijective=false) isa Catnonbij + @test CategoricalLikelihood(SoftMaxLink(); bijective=false) isa Catnonbij + @test CategoricalLikelihood(softmax; bijective=Val(false)) isa Catnonbij + @test CategoricalLikelihood(SoftMaxLink(); bijective=Val(false)) isa Catnonbij lik_bijective = CategoricalLikelihood() OUT_DIM = 4 From 2743debdbc9e5346eae3123d23955b7424dc8ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 18:12:04 +0100 Subject: [PATCH 29/44] formatting --- src/likelihoods/categorical.jl | 6 ++++-- test/likelihoods/categorical.jl | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 7977ab6..a50d47b 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -28,8 +28,10 @@ struct CategoricalLikelihood{Tb,Tl<:AbstractLink} <: AbstractLikelihood CategoricalLikelihood{Tb}(invlink::Tl) where {Tb,Tl<:AbstractLink} = new{Tb,Tl}(invlink) end -function CategoricalLikelihood(l=softmax; bijective::Union{Bool,Val{true},Val{false}}=Val(true)) - CategoricalLikelihood{bijective_typeparameter(bijective)}(l) +function CategoricalLikelihood( + l=softmax; bijective::Union{Bool,Val{true},Val{false}}=Val(true) +) + return CategoricalLikelihood{bijective_typeparameter(bijective)}(l) end bijective_typeparameter(bijective::Bool) = bijective diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index dbf8271..8764b48 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -6,9 +6,9 @@ @test CategoricalLikelihood(SoftMaxLink()) isa Catbij @test CategoricalLikelihood(softmax; bijective=true) isa Catbij @test CategoricalLikelihood(SoftMaxLink(); bijective=true) isa Catbij - + Catnonbij = CategoricalLikelihood{false,SoftMaxLink} - @test CategoricalLikelihood(;bijective=false) isa Catnonbij + @test CategoricalLikelihood(; bijective=false) isa Catnonbij @test CategoricalLikelihood(softmax; bijective=false) isa Catnonbij @test CategoricalLikelihood(SoftMaxLink(); bijective=false) isa Catnonbij @test CategoricalLikelihood(softmax; bijective=Val(false)) isa Catnonbij From ef2cc88ad7d449229b88544638de4043f1d4076d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 18:24:37 +0100 Subject: [PATCH 30/44] Missing where{T} --- src/likelihoods/categorical.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index a50d47b..b3edca6 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -35,7 +35,7 @@ function CategoricalLikelihood( end bijective_typeparameter(bijective::Bool) = bijective -bijective_typeparameter(::Val{T}) = T +bijective_typeparameter(::Val{T}) where {T} = T function (l::CategoricalLikelihood{true})(f::AbstractVector{<:Real}) return Categorical(l.invlink(vcat(f, 0))) From 1eb0f8236628ebffae2c29dffb0d42a30b3f7ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Thu, 27 Jan 2022 18:37:29 +0100 Subject: [PATCH 31/44] Fix test --- test/likelihoods/categorical.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index 8764b48..93a6c11 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -17,6 +17,6 @@ lik_bijective = CategoricalLikelihood() OUT_DIM = 4 test_interface(lik_bijective, Categorical, OUT_DIM) - lik_nonbijective = CategoricalLikelihood(softmax, false) + lik_nonbijective = CategoricalLikelihood(softmax; bijective=Val(false)) test_interface(lik_nonbijective, Categorical, OUT_DIM) end From 891916f2187446ce806994b3f6a1363ac7a385a0 Mon Sep 17 00:00:00 2001 From: Simone Surace Date: Fri, 28 Jan 2022 11:18:54 +0100 Subject: [PATCH 32/44] Correct typo in `LogisticLink` docstring --- src/links.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/links.jl b/src/links.jl index d87cdc4..ce2a8e9 100644 --- a/src/links.jl +++ b/src/links.jl @@ -89,7 +89,7 @@ LogitLink() = Link(logit) """ LogisticLink() -`exp(x)/(1+exp(-x))` link. f:ℝ->[0,1]. Its inverse is the [`LogitLink`](@ref). +`1/(1+exp(-x))` link. f:ℝ->[0,1]. Its inverse is the [`LogitLink`](@ref). """ LogisticLink() = Link(logistic) From 63a4fd27845676b885819393a68919c3ed773461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 11:28:13 +0100 Subject: [PATCH 33/44] Add inference tests --- test/likelihoods/categorical.jl | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index 93a6c11..b09c103 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,21 +1,26 @@ @testset "CategoricalLikelihood" begin Catbij = CategoricalLikelihood{true,SoftMaxLink} - @test CategoricalLikelihood() isa Catbij - @test CategoricalLikelihood(; bijective=true) isa Catbij - @test CategoricalLikelihood(softmax) isa Catbij - @test CategoricalLikelihood(SoftMaxLink()) isa Catbij - @test CategoricalLikelihood(softmax; bijective=true) isa Catbij - @test CategoricalLikelihood(SoftMaxLink(); bijective=true) isa Catbij + for args in ((), (softmax,), (SoftMaxLink(),)), + kwargs in ((), (; bijective=true), (; bijective=Val(true))) + + @test CategoricalLikelihood(args...; kwargs...) isa Catbij + if kwargs != (; bijective=true) # Inferred does not pass with Bool keyword + @inferred CategoricalLikelihood(args...; kwargs...) + end + end Catnonbij = CategoricalLikelihood{false,SoftMaxLink} - @test CategoricalLikelihood(; bijective=false) isa Catnonbij - @test CategoricalLikelihood(softmax; bijective=false) isa Catnonbij - @test CategoricalLikelihood(SoftMaxLink(); bijective=false) isa Catnonbij - @test CategoricalLikelihood(softmax; bijective=Val(false)) isa Catnonbij - @test CategoricalLikelihood(SoftMaxLink(); bijective=Val(false)) isa Catnonbij + for args in ((), (softmax,), (SoftMaxLink(),)), + kwargs in ((; bijective=false), (; bijective=Val(false))) + + @test CategoricalLikelihood(args...; kwargs...) isa Catnonbij + if kwargs != (; bijective=false) # Inferred does not pass with Bool keyword + @inferred CategoricalLikelihood(args...; kwargs...) + end + end - lik_bijective = CategoricalLikelihood() OUT_DIM = 4 + lik_bijective = CategoricalLikelihood() test_interface(lik_bijective, Categorical, OUT_DIM) lik_nonbijective = CategoricalLikelihood(softmax; bijective=Val(false)) test_interface(lik_nonbijective, Categorical, OUT_DIM) From c5135d8f9a2d1e27e1a07d7fc0e01ff1a03e5de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 13:31:48 +0100 Subject: [PATCH 34/44] Update links.jl --- src/links.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/links.jl b/src/links.jl index ce2a8e9..b8e8812 100644 --- a/src/links.jl +++ b/src/links.jl @@ -23,6 +23,9 @@ struct Link{F} <: AbstractLink f::F end +link(f) = Link{typeof(f)}(f) +link(l::AbstractLink) = l + (l::Link)(x) = l.f(x) Base.inv(l::Link) = Link(InverseFunctions.inverse(l.f)) From b934d2927c8cb519e6f9fb2e8f7da75dfd68206e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 13:36:14 +0100 Subject: [PATCH 35/44] Use smart constructor `link` to avoid overwrapping --- src/GPLikelihoods.jl | 1 + src/likelihoods/bernoulli.jl | 2 +- src/likelihoods/categorical.jl | 2 +- src/likelihoods/exponential.jl | 2 +- src/likelihoods/gamma.jl | 2 +- src/likelihoods/gaussian.jl | 2 +- src/likelihoods/poisson.jl | 2 +- src/links.jl | 2 +- test/links.jl | 5 ++++- 9 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 1640577..0ce8099 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -14,6 +14,7 @@ export BernoulliLikelihood, PoissonLikelihood, ExponentialLikelihood, GammaLikelihood +export link export Link, ChainLink, ExpLink, diff --git a/src/likelihoods/bernoulli.jl b/src/likelihoods/bernoulli.jl index a7f50c0..3866cb5 100644 --- a/src/likelihoods/bernoulli.jl +++ b/src/likelihoods/bernoulli.jl @@ -14,7 +14,7 @@ struct BernoulliLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl end -BernoulliLikelihood(l=logistic) = BernoulliLikelihood(Link(l)) +BernoulliLikelihood(l=logistic) = BernoulliLikelihood(link(l)) (l::BernoulliLikelihood)(f::Real) = Bernoulli(l.invlink(f)) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 9756c0d..7126ec1 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -13,7 +13,7 @@ struct CategoricalLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl end -CategoricalLikelihood(l=softmax) = CategoricalLikelihood(Link(l)) +CategoricalLikelihood(l=softmax) = CategoricalLikelihood(link(l)) (l::CategoricalLikelihood)(f::AbstractVector{<:Real}) = Categorical(l.invlink(vcat(f, 0))) diff --git a/src/likelihoods/exponential.jl b/src/likelihoods/exponential.jl index b568db4..fdfacb8 100644 --- a/src/likelihoods/exponential.jl +++ b/src/likelihoods/exponential.jl @@ -11,7 +11,7 @@ struct ExponentialLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl end -ExponentialLikelihood(l=exp) = ExponentialLikelihood(Link(l)) +ExponentialLikelihood(l=exp) = ExponentialLikelihood(link(l)) (l::ExponentialLikelihood)(f::Real) = Exponential(l.invlink(f)) diff --git a/src/likelihoods/gamma.jl b/src/likelihoods/gamma.jl index f3a07c2..bf632d4 100644 --- a/src/likelihoods/gamma.jl +++ b/src/likelihoods/gamma.jl @@ -14,7 +14,7 @@ struct GammaLikelihood{T<:Real,Tl<:AbstractLink} <: AbstractLikelihood end GammaLikelihood(l) = GammaLikelihood(1.0, l) -GammaLikelihood(α::Real=1.0, l=exp) = GammaLikelihood(α, Link(l)) +GammaLikelihood(α::Real=1.0, l=exp) = GammaLikelihood(α, link(l)) @functor GammaLikelihood diff --git a/src/likelihoods/gaussian.jl b/src/likelihoods/gaussian.jl index 771aaec..a20fa26 100644 --- a/src/likelihoods/gaussian.jl +++ b/src/likelihoods/gaussian.jl @@ -40,7 +40,7 @@ struct HeteroscedasticGaussianLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl end -HeteroscedasticGaussianLikelihood(l=exp) = HeteroscedasticGaussianLikelihood(Link(l)) +HeteroscedasticGaussianLikelihood(l=exp) = HeteroscedasticGaussianLikelihood(link(l)) function (l::HeteroscedasticGaussianLikelihood)(f::AbstractVector{<:Real}) return Normal(f[1], sqrt(l.invlink(f[2]))) diff --git a/src/likelihoods/poisson.jl b/src/likelihoods/poisson.jl index 3fcc397..c8f7e28 100644 --- a/src/likelihoods/poisson.jl +++ b/src/likelihoods/poisson.jl @@ -14,7 +14,7 @@ struct PoissonLikelihood{L<:AbstractLink} <: AbstractLikelihood invlink::L end -PoissonLikelihood(l=exp) = PoissonLikelihood(Link(l)) +PoissonLikelihood(l=exp) = PoissonLikelihood(link(l)) (l::PoissonLikelihood)(f::Real) = Poisson(l.invlink(f)) diff --git a/src/links.jl b/src/links.jl index b8e8812..1e86a99 100644 --- a/src/links.jl +++ b/src/links.jl @@ -23,7 +23,7 @@ struct Link{F} <: AbstractLink f::F end -link(f) = Link{typeof(f)}(f) +link(f) = Link(f) link(l::AbstractLink) = l (l::Link)(x) = l.f(x) diff --git a/test/links.jl b/test/links.jl index d4e4aa2..7a70028 100644 --- a/test/links.jl +++ b/test/links.jl @@ -4,8 +4,11 @@ # Generic link f = sin - l = Link(f) + l = link(f) + @test l == Link(f) @test l(x) == f(x) + l = link(ExpLink()) + @test l == ExpLink() # Log l = LogLink() From 4422035e812cb858cc963ab7bd949e53b904d40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 14:31:05 +0100 Subject: [PATCH 36/44] Update src/GPLikelihoods.jl Co-authored-by: David Widmann --- src/GPLikelihoods.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 0ce8099..1640577 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -14,7 +14,6 @@ export BernoulliLikelihood, PoissonLikelihood, ExponentialLikelihood, GammaLikelihood -export link export Link, ChainLink, ExpLink, From bd0c938afd89bb5dab6523ea3ebe8628ee71a803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 14:33:40 +0100 Subject: [PATCH 37/44] Update links.jl --- test/links.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/links.jl b/test/links.jl index 7a70028..b527a39 100644 --- a/test/links.jl +++ b/test/links.jl @@ -4,10 +4,10 @@ # Generic link f = sin - l = link(f) + l = GPLikelihoods.link(f) @test l == Link(f) @test l(x) == f(x) - l = link(ExpLink()) + l = GPLikelihoods.link(ExpLink()) @test l == ExpLink() # Log From c5f738773a212d2f2e12abcc11eaea8dd9362a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 14:45:29 +0100 Subject: [PATCH 38/44] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 7e9bece..f069172 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GPLikelihoods" uuid = "6031954c-0455-49d7-b3b9-3e1c99afaf40" authors = ["JuliaGaussianProcesses Team"] -version = "0.2.6" +version = "0.2.7" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" From 7dfe9022f36d977a588cce4f76623359f1f728b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:01:03 +0100 Subject: [PATCH 39/44] Refactoring of the formulation of the Categorical --- src/likelihoods/categorical.jl | 19 ++++--------------- src/links.jl | 22 ++++++++++++++++++++++ test/likelihoods/categorical.jl | 4 ++-- test/links.jl | 8 ++++++++ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index b3edca6..f0e717c 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -22,31 +22,20 @@ embedded in a `n` dimensional parameter space. For more details, see the end of the section of this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) where it corresponds to Variant 1 and 2. """ -struct CategoricalLikelihood{Tb,Tl<:AbstractLink} <: AbstractLikelihood +struct CategoricalLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl - CategoricalLikelihood{Tb}(invlink) where {Tb} = CategoricalLikelihood{Tb}(Link(invlink)) - CategoricalLikelihood{Tb}(invlink::Tl) where {Tb,Tl<:AbstractLink} = new{Tb,Tl}(invlink) end function CategoricalLikelihood( l=softmax; bijective::Union{Bool,Val{true},Val{false}}=Val(true) ) - return CategoricalLikelihood{bijective_typeparameter(bijective)}(l) + return CategoricalLikelihood(make_bijective(link(l), bijective)) end -bijective_typeparameter(bijective::Bool) = bijective -bijective_typeparameter(::Val{T}) where {T} = T - -function (l::CategoricalLikelihood{true})(f::AbstractVector{<:Real}) - return Categorical(l.invlink(vcat(f, 0))) -end -function (l::CategoricalLikelihood{false})(f::AbstractVector{<:Real}) +function (l::CategoricalLikelihood)(f::AbstractVector{<:Real}) return Categorical(l.invlink(f)) end -function (l::CategoricalLikelihood{true})(fs::AbstractVector) - return Product(Categorical.(l.invlink.(vcat.(fs, 0)))) -end -function (l::CategoricalLikelihood{false})(fs::AbstractVector) +function (l::CategoricalLikelihood)(fs::AbstractVector) return Product(Categorical.(l.invlink.(fs))) end diff --git a/src/links.jl b/src/links.jl index d87cdc4..dba07f3 100644 --- a/src/links.jl +++ b/src/links.jl @@ -27,6 +27,28 @@ end Base.inv(l::Link) = Link(InverseFunctions.inverse(l.f)) +""" + SimplexBijectiveLink(link) + +Wrapper to preprocess the inputs by adding a `0` at the end before passing it to +the link `link`. +This is a necessary step to work with simplices. +For example with the [`SoftMaxLink`](@ref), to obtain a `n`-simplex leading to +`n+1` categories for the [`CategoricalLikelihood`], +one needs to pass `n+1` latent GP. +However, by wrapping the link into a `SimplexBijectiveLink`, only `n` latent are needed. +""" +struct SimplexBijectiveLink{L} <: AbstractLink + link::L +end + +(l::SimplexBijectiveLink)(f::AbstractVector{<:Real}) = l.link(vcat(f, 0)) + +make_bijective(l::AbstractLink, ::Val{true}) = SimplexBijectiveLink(l) +make_bijective(l::AbstractLink, ::Val{false}) = l +make_bijective(l::AbstractLink, bijective::Bool) = make_bijective(l, Val(bijective)) + + # alias const LogLink = Link{typeof(log)} const ExpLink = Link{typeof(exp)} diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index b09c103..c3029e7 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,5 +1,5 @@ @testset "CategoricalLikelihood" begin - Catbij = CategoricalLikelihood{true,SoftMaxLink} + Catbij = CategoricalLikelihood{SimplexBijectiveLink{SoftMaxLink}} for args in ((), (softmax,), (SoftMaxLink(),)), kwargs in ((), (; bijective=true), (; bijective=Val(true))) @@ -9,7 +9,7 @@ end end - Catnonbij = CategoricalLikelihood{false,SoftMaxLink} + Catnonbij = CategoricalLikelihood{SoftMaxLink} for args in ((), (softmax,), (SoftMaxLink(),)), kwargs in ((; bijective=false), (; bijective=Val(false))) diff --git a/test/links.jl b/test/links.jl index d4e4aa2..f7be88b 100644 --- a/test/links.jl +++ b/test/links.jl @@ -7,6 +7,14 @@ l = Link(f) @test l(x) == f(x) + ## SimplexBijective link + l = SoftMaxLink() + sbl = SimplexBijectiveLink(l) + @test sbl(xs) == l(vcat(xs, 0)) + @test GPLikelihoods.make_bijective(l, false) isa SoftMaxLink + @test GPLikelihoods.make_bijective(l, Val(false)) isa SoftMaxLink + @test GPLikelihoods.make_bijective(l, true) isa SimplexBijectiveLink{SoftMaxLink} + @test GPLikelihoods.make_bijective(l, Val(true)) isa SimplexBijectiveLink{SoftMaxLink} # Log l = LogLink() @test l(x) == log(x) From c1ce24e7d031bf50588b2ea82b019c774a164c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:01:17 +0100 Subject: [PATCH 40/44] Formatting --- src/links.jl | 1 - test/links.jl | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/links.jl b/src/links.jl index dba07f3..a02908f 100644 --- a/src/links.jl +++ b/src/links.jl @@ -48,7 +48,6 @@ make_bijective(l::AbstractLink, ::Val{true}) = SimplexBijectiveLink(l) make_bijective(l::AbstractLink, ::Val{false}) = l make_bijective(l::AbstractLink, bijective::Bool) = make_bijective(l, Val(bijective)) - # alias const LogLink = Link{typeof(log)} const ExpLink = Link{typeof(exp)} diff --git a/test/links.jl b/test/links.jl index f7be88b..4d4b578 100644 --- a/test/links.jl +++ b/test/links.jl @@ -15,6 +15,7 @@ @test GPLikelihoods.make_bijective(l, Val(false)) isa SoftMaxLink @test GPLikelihoods.make_bijective(l, true) isa SimplexBijectiveLink{SoftMaxLink} @test GPLikelihoods.make_bijective(l, Val(true)) isa SimplexBijectiveLink{SoftMaxLink} + # Log l = LogLink() @test l(x) == log(x) From 74f6bbb678414ee49dd46540a9768550dc846ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:03:49 +0100 Subject: [PATCH 41/44] Update docs --- src/likelihoods/categorical.jl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index f0e717c..9d8d2f0 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -3,18 +3,23 @@ Categorical likelihood is to be used if we assume that the uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution) with `n` categories. -```math - p(y|f_1, f_2, \\dots, f_{n-1}) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_{n-1}, 0)) - p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) -``` + Two variants are possible (you can use a `Bool` or `Val{true}`/`Val{false}` but we recommend the latter for type stability). ## `bijective=true/Val{true}` +```math + p(y|f_1, f_2, \\dots, f_{n-1}) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_{n-1}, 0)) +``` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n-1}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n-1}, 0)``. +Under the hood, the link `l` is wrapped into a [`SimplexBijectiveLink`](@ref) which takes +care of concatenating `0`. It is used by default. ## `bijective=false` +```math + p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) +``` Given an `AbstractVector` ``[f_1, f_2, ..., f_{n}]``, returns a `Categorical` distribution, with probabilities given by ``l(f_1, f_2, ..., f_{n})``. This variant is over-parametrized, as there are `n-1` independent parameters From 777ba74b29fe83c7f84b4ebb4366601297fdeb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:42:27 +0100 Subject: [PATCH 42/44] Adressed comments --- src/likelihoods/categorical.jl | 31 +++++++++++++------------------ src/links.jl | 14 +++++--------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/likelihoods/categorical.jl b/src/likelihoods/categorical.jl index 9d8d2f0..10c5c36 100644 --- a/src/likelihoods/categorical.jl +++ b/src/likelihoods/categorical.jl @@ -1,27 +1,26 @@ """ - CategoricalLikelihood(l=softmax; bijective::Union{Bool,Val{false},Val{true}}=Val(true)) + CategoricalLikelihood(l=BijectiveSimplexLink(softmax)) Categorical likelihood is to be used if we assume that the -uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution) with `n` categories. +uncertainty associated with the data follows a [Categorical distribution](https://en.wikipedia.org/wiki/Categorical_distribution). -Two variants are possible (you can use a `Bool` or `Val{true}`/`Val{false}` but -we recommend the latter for type stability). -## `bijective=true/Val{true}` +Assuming a distribution with `n` categories: + +## `n-1` inputs (bijective link) + +One can work with a bijective transformation by wrapping a link (like `softmax`) +into a [`BijectiveSimplexLink`](@ref) and only needs `n-1` inputs: ```math p(y|f_1, f_2, \\dots, f_{n-1}) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_{n-1}, 0)) ``` -Given an `AbstractVector` ``[f_1, f_2, ..., f_{n-1}]``, returns a `Categorical` distribution, -with probabilities given by ``l(f_1, f_2, ..., f_{n-1}, 0)``. -Under the hood, the link `l` is wrapped into a [`SimplexBijectiveLink`](@ref) which takes -care of concatenating `0`. -It is used by default. +The default constructor is a bijective link around `softmax`. -## `bijective=false` +## `n` inputs (non-bijective link) + +One can also pass directly the inputs without concatenating a `0`: ```math p(y|f_1, f_2, \\dots, f_n) = \\operatorname{Categorical}(y | l(f_1, f_2, \\dots, f_n)) ``` -Given an `AbstractVector` ``[f_1, f_2, ..., f_{n}]``, returns a `Categorical` distribution, -with probabilities given by ``l(f_1, f_2, ..., f_{n})``. This variant is over-parametrized, as there are `n-1` independent parameters embedded in a `n` dimensional parameter space. For more details, see the end of the section of this [Wikipedia link](https://en.wikipedia.org/wiki/Exponential_family#Table_of_distributions) @@ -31,11 +30,7 @@ struct CategoricalLikelihood{Tl<:AbstractLink} <: AbstractLikelihood invlink::Tl end -function CategoricalLikelihood( - l=softmax; bijective::Union{Bool,Val{true},Val{false}}=Val(true) -) - return CategoricalLikelihood(make_bijective(link(l), bijective)) -end +CategoricalLikelihood(l=BijectiveSimplexLink(softmax)) = CategoricalLikelihood(link(l)) function (l::CategoricalLikelihood)(f::AbstractVector{<:Real}) return Categorical(l.invlink(f)) diff --git a/src/links.jl b/src/links.jl index ae55089..e7e66c9 100644 --- a/src/links.jl +++ b/src/links.jl @@ -31,25 +31,21 @@ link(l::AbstractLink) = l Base.inv(l::Link) = Link(InverseFunctions.inverse(l.f)) """ - SimplexBijectiveLink(link) + BijectiveSimplexLink(link) Wrapper to preprocess the inputs by adding a `0` at the end before passing it to the link `link`. This is a necessary step to work with simplices. For example with the [`SoftMaxLink`](@ref), to obtain a `n`-simplex leading to -`n+1` categories for the [`CategoricalLikelihood`], +`n+1` categories for the [`CategoricalLikelihood`](@ref), one needs to pass `n+1` latent GP. -However, by wrapping the link into a `SimplexBijectiveLink`, only `n` latent are needed. +However, by wrapping the link into a `BijectiveSimplexLink`, only `n` latent are needed. """ -struct SimplexBijectiveLink{L} <: AbstractLink +struct BijectiveSimplexLink{L} <: AbstractLink link::L end -(l::SimplexBijectiveLink)(f::AbstractVector{<:Real}) = l.link(vcat(f, 0)) - -make_bijective(l::AbstractLink, ::Val{true}) = SimplexBijectiveLink(l) -make_bijective(l::AbstractLink, ::Val{false}) = l -make_bijective(l::AbstractLink, bijective::Bool) = make_bijective(l, Val(bijective)) +(l::BijectiveSimplexLink)(f::AbstractVector{<:Real}) = l.link(vcat(f, 0)) # alias const LogLink = Link{typeof(log)} From c0c7d053b20cf6ec7b725aa06013d74d25aa1778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:49:55 +0100 Subject: [PATCH 43/44] Corrected changes --- src/GPLikelihoods.jl | 1 + test/likelihoods/categorical.jl | 23 ++++------------------- test/links.jl | 6 +----- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/GPLikelihoods.jl b/src/GPLikelihoods.jl index 1640577..34890ca 100644 --- a/src/GPLikelihoods.jl +++ b/src/GPLikelihoods.jl @@ -16,6 +16,7 @@ export BernoulliLikelihood, GammaLikelihood export Link, ChainLink, + BijectiveSimplexLink, ExpLink, LogLink, InvLink, diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index c3029e7..4db61b8 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,27 +1,12 @@ @testset "CategoricalLikelihood" begin - Catbij = CategoricalLikelihood{SimplexBijectiveLink{SoftMaxLink}} - for args in ((), (softmax,), (SoftMaxLink(),)), - kwargs in ((), (; bijective=true), (; bijective=Val(true))) + @test CategoricalLikelihood() isa CategoricalLikelihood{<:GPLikelihoods.BijectiveSimplexLink} - @test CategoricalLikelihood(args...; kwargs...) isa Catbij - if kwargs != (; bijective=true) # Inferred does not pass with Bool keyword - @inferred CategoricalLikelihood(args...; kwargs...) - end - end - - Catnonbij = CategoricalLikelihood{SoftMaxLink} - for args in ((), (softmax,), (SoftMaxLink(),)), - kwargs in ((; bijective=false), (; bijective=Val(false))) - - @test CategoricalLikelihood(args...; kwargs...) isa Catnonbij - if kwargs != (; bijective=false) # Inferred does not pass with Bool keyword - @inferred CategoricalLikelihood(args...; kwargs...) - end - end + @test CategoricalLikelihood(softmax) isa CategoricalLikelihood{SoftMaxLink} + @test CategoricalLikelihood(SoftMaxLink()) isa CategoricalLikelihood{SoftMaxLink} OUT_DIM = 4 lik_bijective = CategoricalLikelihood() test_interface(lik_bijective, Categorical, OUT_DIM) - lik_nonbijective = CategoricalLikelihood(softmax; bijective=Val(false)) + lik_nonbijective = CategoricalLikelihood(softmax) test_interface(lik_nonbijective, Categorical, OUT_DIM) end diff --git a/test/links.jl b/test/links.jl index d6ea21e..67c1af3 100644 --- a/test/links.jl +++ b/test/links.jl @@ -12,12 +12,8 @@ ## SimplexBijective link l = SoftMaxLink() - sbl = SimplexBijectiveLink(l) + sbl = BijectiveSimplexLink(l) @test sbl(xs) == l(vcat(xs, 0)) - @test GPLikelihoods.make_bijective(l, false) isa SoftMaxLink - @test GPLikelihoods.make_bijective(l, Val(false)) isa SoftMaxLink - @test GPLikelihoods.make_bijective(l, true) isa SimplexBijectiveLink{SoftMaxLink} - @test GPLikelihoods.make_bijective(l, Val(true)) isa SimplexBijectiveLink{SoftMaxLink} # Log l = LogLink() From 316d7394e0b6aebc35954339552bf88b7a06d46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Galy-Fajou?= Date: Fri, 28 Jan 2022 16:58:12 +0100 Subject: [PATCH 44/44] Update test/likelihoods/categorical.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- test/likelihoods/categorical.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/likelihoods/categorical.jl b/test/likelihoods/categorical.jl index 4db61b8..8ed48be 100644 --- a/test/likelihoods/categorical.jl +++ b/test/likelihoods/categorical.jl @@ -1,5 +1,6 @@ @testset "CategoricalLikelihood" begin - @test CategoricalLikelihood() isa CategoricalLikelihood{<:GPLikelihoods.BijectiveSimplexLink} + @test CategoricalLikelihood() isa + CategoricalLikelihood{<:GPLikelihoods.BijectiveSimplexLink} @test CategoricalLikelihood(softmax) isa CategoricalLikelihood{SoftMaxLink} @test CategoricalLikelihood(SoftMaxLink()) isa CategoricalLikelihood{SoftMaxLink}