Skip to content

Commit

Permalink
Refactor (#178)
Browse files Browse the repository at this point in the history
* Dirichlet(k::Integer, α) = Dirichlet(Fill(α, k))

* export TransformVariables as TV

* drop redundant import

* 0.0 => zero(Float64)

* drop outdated Dists.logpdf

* update StudentT

* drop redundant import

* update Uniform

* bump MeasureBase version

* reworking beta

* small update to StudentT

* basemeasure for discrete Distributions

* using LogExpFunctions => import LogExpFunctions

* quoteof(::Chain)

* prettyprinting and chain-mucking

* Some refactoring for Markov chains

* import MeasureBase: ≪

* version bound for PrettyPrinting

* copy(rng) might change its type (e.g. GLOBAL_RNG)

* tests pass

* cleaning up

* more cleanup

* big update

* get tests passing

* formatting

* oops typo

* move affine to MeasureTheory

* updating

* Val => StaticSymbol

* more fixes

* fix fix fix

* more logdesnity => logdensity_def

* more logdesnity fixes

* debugging

* formatting

* bugfixes

* working on tests

* updates

* working on tests

* tests passing!

* refactor

* working on tests

* drop static weight for now

* fix sampling from ProductMeasure{<:Base.Generator}

* tests passing!!

* more stuff

* constructor => constructorof

* constructor =? construtorof

* updates

* working on tests

* fix Dirichlet

* update Bernoulli

* working on tests

* bugfixes for RealizedSamples

* tests passing!!

* tighten down inference

* as(::PowerMeasure)

* drop type-level stuff

* using InverseFunctions.jl

* tests passing

* drop old tbasemeasure_type code

* update logdensity_def(d::Affine{(:σ,)}, x)

* update license

* Move `solve` to MeasureTheory

* better type stability

* `solve!` moved to MeasureTheory

* exponential families

* work on exponential families

* ExpFamMeasure

* applying an exponential family

* kwstruct for Laplace

* update README (license description)

* kwstruct for Laplace

* kwstruct for Bernoulli

* Simplify logdensity_def(::DynamicFor{M}, y) for now

* using ConcreteStructs

* update dependencies

* inner constructors

* inline logjac

* exponential families and tweedie distributions

* `mydot`

* Soss tests passing

* tests passing

* inline

* condiional meaures

* update affine smart constructor

* update for type stability

* tests passing!

* updates

* Make Bernoulli more efficient

* license

* compat

* Run CI on Juila 1.6

* fix typo

* bump version
  • Loading branch information
cscherrer authored Mar 16, 2022
1 parent 7102906 commit f4f8385
Show file tree
Hide file tree
Showing 49 changed files with 1,871 additions and 587 deletions.
20 changes: 20 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
indent = 4
margin = 92
always_for_in = true
whitespace_typedefs = false
whitespace_ops_in_indices = false
remove_extra_newlines = true
import_to_using = false
pipe_to_function_call = false
short_to_long_function_def = false
always_use_return = false
whitespace_in_kwargs = true
annotate_untyped_fields_with_any = false
format_docstrings = false
align_struct_field = true
align_conditional = true
align_assignment = true
align_pair_arrow = true
conditional_to_if = true
normalize_line_endings = "unix"
align_matrix = false
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
fail-fast: false
matrix:
version:
- '1.5'
- '1.6'
- '1'
os:
- ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
34 changes: 25 additions & 9 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
name = "MeasureTheory"
uuid = "eadaa1a4-d27c-401d-8699-e962e1bbc33b"
authors = ["Chad Scherrer <[email protected]> and contributors"]
version = "0.13.2"
version = "0.14.0"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
ConcreteStructs = "2569d6c7-a4a2-43d3-a901-331e8e4be471"
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
DynamicIterators = "6c76993d-992e-5bf1-9e63-34920a5a5a38"
FLoops = "cc61a311-1640-44b5-9fba-1b764f453329"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
InfiniteArrays = "4858937d-0d70-526a-a4dd-2d5cb5dd786c"
Infinities = "e1ba4f0e-776d-440f-acd9-e1d2e9742647"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
KeywordCalls = "4d827475-d3e4-43d6-abe3-9688362ede9f"
LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
Expand All @@ -26,32 +32,42 @@ PrettyPrinting = "54e16d92-306c-5ea0-a30b-337be88ac337"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
TransformVariables = "84d833dd-6860-57f9-a1a7-6da5db126cff"
Tricks = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775"

[compat]
Accessors = "0.1"
ChangesOfVariables = "0.1"
Compat = "3.35"
ConcreteStructs = "0.2"
ConstructionBase = "1.3"
DensityInterface = "0.4"
Distributions = "0.25"
DynamicIterators = "0.4"
FillArrays = "0.12"
InfiniteArrays = "0.11, 0.12"
FLoops = "0.2"
FillArrays = "0.12, 0.13"
Infinities = "0.1"
InverseFunctions = "0.1"
KeywordCalls = "0.2"
LazyArrays = "0.21, 0.22"
LogExpFunctions = "0.3.3"
MLStyle = "0.4"
MacroTools = "0.5"
MappedArrays = "0.4"
MeasureBase = "0.5"
NamedTupleTools = "0.13"
MeasureBase = "0.6"
NamedTupleTools = "0.13, 0.14"
NestedTuples = "0.3"
PositiveFactorizations = "0.2"
PrettyPrinting = "0.3"
PrettyPrinting = "0.3, 0.4"
Reexport = "1"
SpecialFunctions = "1"
SpecialFunctions = "1, 2"
Static = "0.5, 0.6"
StaticArrays = "1.3"
StatsFuns = "0.9"
TransformVariables = "0.4"
TransformVariables = "0.5, 0.6"
Tricks = "0.1"
julia = "1.5"

Expand Down
18 changes: 9 additions & 9 deletions docs/src/adding.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ The `≪` (typed as `\ll <TAB>`) can be read "is dominated by". This just means

### Defining a Log Density

Most computations involve log-densities rather than densities themselves, so these are our first priority. `density(d,x)` will default to `exp(logdensity(d,x))`, but you can add a separate method if it's more efficient.
Most computations involve log-densities rather than densities themselves, so these are our first priority. `density(d,x)` will default to `exp(logdensity_def(d,x))`, but you can add a separate method if it's more efficient.

The definition is simple:
```julia
logdensity(d::Normal{()} , x) = - x^2 / 2
logdensity_def(d::Normal{()} , x) = - x^2 / 2
```

There are a few things here worth noting.
Expand All @@ -53,7 +53,7 @@ Also, there's nothing here about `μ` and `σ`. These _location-scale parameters
Let's look at another example, the Beta distribution. Here the base measure is `Lebesgue(𝕀)` (support is the unit interval). The log-density is

```julia
function logdensity(d::Beta{(:α, :β)}, x)
@inline function logdensity_def(d::Beta{(:α, :β)}, x)
return (d.α - 1) * log(x) + (d.β - 1) * log(1 - x) - logbeta(d.α, d.β)
end
```
Expand Down Expand Up @@ -114,15 +114,15 @@ basemeasure(μ::Lebesgue) = μ

isprimitive(::Lebesgue) = true

sampletype(::Lebesgue{ℝ}) = Float64
sampletype(::Lebesgue{ℝ₊}) = Float64
sampletype(::Lebesgue{𝕀}) = Float64
gentype(::Lebesgue{ℝ}) = Float64
gentype(::Lebesgue{ℝ₊}) = Float64
gentype(::Lebesgue{𝕀}) = Float64

logdensity(::Lebesgue, x) = zero(float(x))
logdensity_def(::Lebesgue, x) = zero(float(x))
```

We haven't yet talked about `sampletype`. When you call `rand` without specifying a type, there needs to be a default. That default is the `sampletype`. This only needs to be defined for primitive measures, because others will fall back on
We haven't yet talked about `gentype`. When you call `rand` without specifying a type, there needs to be a default. That default is the `gentype`. This only needs to be defined for primitive measures, because others will fall back on

```julia
sampletype::AbstractMeasure) = sampletype(basemeasure(μ))
gentype::AbstractMeasure) = gentype(basemeasure(μ))
```
6 changes: 3 additions & 3 deletions docs/src/affine.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ z = σ⁻¹ (x - μ)
so the log-density is

```julia
logdensity(d::Normal{(:μ,:σ)}, x) = logdensity(d.σ \ (x - d.μ)) - logdet(d.σ)
logdensity_def(d::Normal{(:μ,:σ)}, x) = logdensity_def(d.σ \ (x - d.μ)) - logdet(d.σ)
```

Here the `- logdet(σ)` is the "log absolute Jacobian", required to account for the stretching of the space.
Expand All @@ -74,7 +74,7 @@ In addition to the covariance ``Σ``, it's also common to parameterize a multiva
This parameterization enables more efficient calculation of the log-density using only multiplication and addition,

```julia
logdensity(d::Normal{(:μ,:ω)}, x) = logdensity(d.ω * (x - d.μ)) + logdet(d.ω)
logdensity_def(d::Normal{(:μ,:ω)}, x) = logdensity_def(d.ω * (x - d.μ)) + logdet(d.ω)
```

## `AffineTransform`
Expand All @@ -94,7 +94,7 @@ In the univariate case this is relatively simple to invert. But if `σ` is a mat
With multiple parameterizations of a given family of measures, we can work around these issues. The inverse transform of a ``(μ,σ)`` transform will be in terms of ``(μ,ω)``, and vice-versa. So

```julia
julia> f⁻¹ = inv(f)
julia> f⁻¹ = inverse(f)
AffineTransform{(:μ, :ω), Tuple{Float64, Float64}}((μ = -1.5, ω = 2.0))

julia> f(f⁻¹(4))
Expand Down
10 changes: 5 additions & 5 deletions docs/src/old_readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,21 +153,21 @@ A density doesn't exist by itself, but is defined relative to some _base measure
```julia
@implement Density{Normal{X,P},X} where {X, P <: NamedTuple{(:μ, :σ)}} begin
basemeasure(d) = Lebesgue(X)
logdensity(d, x) = - (log(2) + log(π)) / 2 - log(d.par.σ) - (x - d.par.μ)^2 / (2 * d.par.σ^2)
logdensity_def(d, x) = - (log(2) + log(π)) / 2 - log(d.par.σ) - (x - d.par.μ)^2 / (2 * d.par.σ^2)
end
```

Now we can compute the log-density:

```julia
julia> logdensity(Normal(0.0, 0.5), 1.0)
julia> logdensity_def(Normal(0.0, 0.5), 1.0)
-2.2257913526447273
```

And just to check that our default is working,

```julia
julia> logdensity(Normal=0.0, σ=0.5), 1.0)
julia> logdensity_def(Normal=0.0, σ=0.5), 1.0)
-2.2257913526447273
```

Expand All @@ -178,14 +178,14 @@ eltype(::Type{Normal}, ::Type{NamedTuple{(:μ, :τ), Tuple{A, B}}}) where {A,B}

@implement Density{Normal{X,P},X} where {X, P <: NamedTuple{(:μ, :τ)}} begin
basemeasure(d) = Lebesgue(X)
logdensity(d, x) = - (log(2) + log(π) - log(d.par.τ) + d.par.τ * (x - d.par.μ)^2) / 2
logdensity_def(d, x) = - (log(2) + log(π) - log(d.par.τ) + d.par.τ * (x - d.par.μ)^2) / 2
end
```

And another check:

```julia
julia> logdensity(Normal=0.0, τ=4.0), 1.0)
julia> logdensity_def(Normal=0.0, τ=4.0), 1.0)
-2.2257913526447273
```

Expand Down
5 changes: 5 additions & 0 deletions jet-test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using MeasureTheory

dist = For(3) do j Normal=j) end

b = basemeasure_depth(dist)
4 changes: 2 additions & 2 deletions scratch/orderstats.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ struct OrderStatistic{n,r,B} <: AbstractMeasure
base::B
end

function basemeasure(d::OrderStatistic{n,r})
@inline function basemeasure(d::OrderStatistic{n,r})
WeightedMeasure(logbeta(n+1, r+1), d.base)
end

function logdensity(d::OrderStatistic{n,r}, x)
@inline function logdensity_def(d::OrderStatistic{n,r}, x)
logF(x) = logcdf(d.base, x)
logFᶜ(x) = logccdf(d.base, x)
return (r - 1) * logF(x) + (n - r) * logFᶜ(x)
Expand Down
Loading

2 comments on commit f4f8385

@cscherrer
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/56958

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.14.0 -m "<description of version>" f4f83851f0abcf554a4b0403d1e29943092547a8
git push origin v0.14.0

Please sign in to comment.