Skip to content

Commit

Permalink
Documentation improvements (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
sunxd3 authored Sep 29, 2024
1 parent da988a2 commit 1fc7be9
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 279 deletions.
14 changes: 7 additions & 7 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ using DynamicPPL: SimpleVarInfo
makedocs(;
sitename="JuliaBUGS.jl",
pages=[
"Introduction" => "index.md",
"Differences from Other BUGS Implementations" => "differences.md",
"Home" => "index.md",
"Example" => "example.md",
"API" => [
"General" => "api.md",
"Functions" => "functions.md",
"Distributions" => "distributions.md",
"Defining New Function and Distributions" => "user_defined_functions.md",
"General" => "api/api.md",
"Functions" => "api/functions.md",
"Distributions" => "api/distributions.md",
"User-Defined Functions and Distributions" => "api/user_defined_functions.md",
],
"Differences from Other BUGS Implementations" => "differences.md",
"Pitfalls" => "pitfalls.md",
"Plotting" => "graph_plotting.md",
"R Interface" => "R_interface.md",
"Pitfalls" => "pitfalls.md",
"For Developers" =>
["Parser" => "parser.md", "Notes on BUGS Implementations" => "BUGS_notes.md"],
],
Expand Down
179 changes: 8 additions & 171 deletions docs/src/R_interface.md
Original file line number Diff line number Diff line change
@@ -1,174 +1,11 @@
# Integrating R in Julia
# R Interface

Julia offers a seamless interface to the [`R` language](https://www.r-project.org/about.html).
There is great support of interoperability between Julia and R.

- The [`RCall.jl`](https://github.com/JuliaInterop/RCall.jl) package enables interaction with R functions in Julia.
- The [`RData.jl`](https://github.com/JuliaData/RData.jl) package allows interfacing with R data in Julia.
Here are some very useful packages:

## Reading BUGS `data` and `init` from R like lists
>
> **Warning**: The data layout in BUGS assumes that the data is stored in row-major order, while R uses column-major order. This discrepancy can lead to issues. [`Stan`](https://mc-stan.org/) developers have transformed the data and initializations of example BUGS models for R, which can be found [here](https://github.com/stan-dev/example-models/tree/master/bugs_examples).
### Reading the `list` data structure from R

The data for `Rats` is available [here](https://chjackson.github.io/openbugsdoc/Examples/Ratsdata.html).

In Julia, we can read this data into a Julia dictionary using the `RCall.jl` package.

```julia-repl
julia> using RCall
julia> data = R"
list(
x = c(8.0, 15.0, 22.0, 29.0, 36.0), xbar = 22, N = 30, T = 5,
Y = structure(
.Data = c(
151, 199, 246, 283, 320,
145, 199, 249, 293, 354,
147, 214, 263, 312, 328,
155, 200, 237, 272, 297,
135, 188, 230, 280, 323,
159, 210, 252, 298, 331,
141, 189, 231, 275, 305,
159, 201, 248, 297, 338,
177, 236, 285, 350, 376,
134, 182, 220, 260, 296,
160, 208, 261, 313, 352,
143, 188, 220, 273, 314,
154, 200, 244, 289, 325,
171, 221, 270, 326, 358,
163, 216, 242, 281, 312,
160, 207, 248, 288, 324,
142, 187, 234, 280, 316,
156, 203, 243, 283, 317,
157, 212, 259, 307, 336,
152, 203, 246, 286, 321,
154, 205, 253, 298, 334,
139, 190, 225, 267, 302,
146, 191, 229, 272, 302,
157, 211, 250, 285, 323,
132, 185, 237, 286, 331,
160, 207, 257, 303, 345,
169, 216, 261, 295, 333,
157, 205, 248, 289, 316,
137, 180, 219, 258, 291,
153, 200, 244, 286, 324
),
.Dim = c(30, 5)
)
)
"
RObject{VecSxp}
$x
[1] 8 15 22 29 36
$xbar
[1] 22
$N
[1] 30
$T
[1] 5
$Y
[,1] [,2] [,3] [,4] [,5]
[1,] 151 141 154 157 132
[2,] 199 189 200 212 185
[3,] 246 231 244 259 237
[4,] 283 275 289 307 286
[5,] 320 305 325 336 331
[6,] 145 159 171 152 160
[7,] 199 201 221 203 207
[8,] 249 248 270 246 257
[9,] 293 297 326 286 303
[10,] 354 338 358 321 345
[11,] 147 177 163 154 169
[12,] 214 236 216 205 216
[13,] 263 285 242 253 261
[14,] 312 350 281 298 295
[15,] 328 376 312 334 333
[16,] 155 134 160 139 157
[17,] 200 182 207 190 205
[18,] 237 220 248 225 248
[19,] 272 260 288 267 289
[20,] 297 296 324 302 316
[21,] 135 160 142 146 137
[22,] 188 208 187 191 180
[23,] 230 261 234 229 219
[24,] 280 313 280 272 258
[25,] 323 352 316 302 291
[26,] 159 143 156 157 153
[27,] 210 188 203 211 200
[28,] 252 220 243 250 244
[29,] 298 273 283 285 286
[30,] 331 314 317 323 324
```

alternatively, `reval(s::String)` will produce the same result in this case.

If the data is stores in a file, user can use function (may require customizing the function to fit specific needs)

```julia
function read_rlist_to_dictionary(filepath::String)
r_data = open(filepath) do f
s = read(f, String)
reval(s)
end
return rcopy(r_data)
end
```

, and save the result to a Julia variable and access the data as a Julia dictionary

```julia-repl
julia> rcopy(data)
OrderedDict{Symbol, Any} with 5 entries:
:x => [8.0, 15.0, 22.0, 29.0, 36.0]
:xbar => 22.0
:N => 30.0
:T => 5.0
:Y => [151.0 141.0 … 157.0 132.0; 199.0 189.0 … 212.0 185.0; … ; 298.0 273.0 … 285.0 286.0; 331.0 314.0 … 323.0 324.0]
```

It is worth noting that `rcopy` will automatically convert data names contains `.` to `_` in Julia. E.g.

```julia
julia> rcopy(R"list(a.b = 1)")
OrderedDict{Symbol, Any} with 1 entry:
:a_b => 1.0
```

### Transform Data read from R to Julia convention

If you want to load data using the R interface, but the data source is in the same layout as BUGS, you can process the data in Julia, for instance

```julia-repl
# define a row-major reshape function, because Julia's `reshape` is column-major
julia> function rreshape(v::Vector, dim)
return permutedims(reshape(v, reverse(dim)), length(dim):-1:1)
end
rreshape (generic function with 1 method)
julia> rreshape(vcat(data[:Y]...), (30, 5))
30×5 Matrix{Float64}:
151.0 199.0 246.0 283.0 320.0
145.0 199.0 249.0 293.0 354.0
147.0 214.0 263.0 312.0 328.0
155.0 200.0 237.0 272.0 297.0
135.0 188.0 230.0 280.0 323.0
159.0 210.0 252.0 298.0 331.0
141.0 189.0 231.0 275.0 305.0
159.0 201.0 248.0 297.0 338.0
146.0 191.0 229.0 272.0 302.0
157.0 211.0 250.0 285.0 323.0
132.0 185.0 237.0 286.0 331.0
160.0 207.0 257.0 303.0 345.0
169.0 216.0 261.0 295.0 333.0
157.0 205.0 248.0 289.0 316.0
137.0 180.0 219.0 258.0 291.0
153.0 200.0 244.0 286.0 324.0
```

Please always verify the data before using.
- [`RCall.jl`](https://github.com/JuliaInterop/RCall.jl): interaction with R runtime.
- [`RData.jl`](https://github.com/JuliaData/RData.jl): reading and writing R data files.
- [`DataFrames.jl`](https://github.com/JuliaData/DataFrames.jl): `pandas` and `dplyr` for Julia.
- [`CSV.jl`](https://github.com/JuliaData/CSV.jl): CSV file reading and writing.
- [`JSON.jl`](https://github.com/JuliaIO/JSON.jl), [`JSON3.jl`](https://github.com/quinnj/JSON3.jl), [`Serde.jl`](https://github.com/bhftbootcamp/Serde.jl): JSON file reading and writing.
1 change: 0 additions & 1 deletion docs/src/api.md → docs/src/api/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
```@docs
@bugs
compile
BUGSModel
initialize!
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
57 changes: 0 additions & 57 deletions docs/src/bugs_lang.md

This file was deleted.

57 changes: 45 additions & 12 deletions docs/src/differences.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
# Differences From Other BUGS Implementations

There exists many implementations of BUGS, notably WinBUGS, OpenBUGS, MultiBUGS, JAGS, and r-nimble.
There exist many implementations of BUGS, notably [`WinBUGS`](https://www.mrc-bsu.cam.ac.uk/software/), [`OpenBUGS`](https://chjackson.github.io/openbugsdoc/Manuals/ModelSpecification.html), [`MultiBUGS`](https://www.multibugs.org/documentation/latest/), [`JAGS`](https://mcmc-jags.sourceforge.io/), and [`nimble`](https://r-nimble.org/).

This section aims to outline some differences between JuliaBUGS and other BUGS implementations.
This comparison is not exhaustive, and we welcome further discussion and reports on the matter.
This comparison is not exhaustive, and we welcome any further discussion and reports on the matter.

## Use of generaic function in distribution functions

In `WinBUGS`, `OpenBUGS`, and `MultiBUGS`, the arguments to distribution functions are typically restricted to variables or constants, not general expressions. JuliaBUGS, however, allows for more flexibility in these arguments.

For example, the following expressions are allowed in all BUGS implementations, including JuliaBUGS (assuming `y = [1, 2, 3]`):

```S
model {
x ~ dnorm(y[y[2]], 1)
}
model {
x ~ dnorm(y[y[2]+1], 1)
}
```

However, JuliaBUGS allows more flexibility in these arguments. The following expressions, which are not allowed in traditional BUGS implementations, are permitted in JuliaBUGS:

```S
model {
x ~ dnorm(y[1] + 1, 1)
}
model {
x ~ dnorm(sum(y[1:2]), 1)
}
model {
x ~ dnorm(y[sum(y[1:2])], 1)
}
```

## `cumulative`, `density`, and `deviance` Functions

In [`OpenBUGS`]((https://chjackson.github.io/openbugsdoc/Manuals/ModelSpecification.html)), there are several functions for working with distributions:
In [`OpenBUGS`](https://chjackson.github.io/openbugsdoc/Manuals/ModelSpecification.html), there are several functions for working with distributions:

* cumulative(s1, s2): Computes the tail area (cumulative distribution function) of the distribution of s1 up to the value of s2. s1 must be a stochastic node, and s1 and s2 can be the same.
* density(s1, s2): Computes the density function of the distribution of s1 at the value of s2. s1 must be a stochastic node supplied as data, and s1 and s2 can be the same.
* deviance(s1, s2): Computes the deviance of the distribution of s1 at the value of s2. s1 must be a stochastic node supplied as data, and s1 and s2 can be the same.
* `cumulative(s1, s2)`: Computes the tail area (cumulative distribution function) of the distribution of s1 up to the value of s2. s1 must be a stochastic node, and s1 and s2 can be the same.
* `density(s1, s2)`: Computes the density function of the distribution of s1 at the value of s2. s1 must be a stochastic node supplied as data, and s1 and s2 can be the same.
* `deviance(s1, s2)`: Computes the deviance of the distribution of s1 at the value of s2. s1 must be a stochastic node supplied as data, and s1 and s2 can be the same.

In [`MultiBUGS`](https://www.multibugs.org/documentation/latest/Functions.html), these functions have been replaced with the `cdf.dist`, `pdf.dist`, and `dev.dist` family of functions.

Expand Down Expand Up @@ -75,10 +108,10 @@ JuliaBUGS inherits these functions, but it's important to note that the link fun

Instead, users are advised to use the inverse functions of these link functions by calling them on the right-hand side (RHS) of the statement. The inverse functions are:

* `log` -> `exp`
* `logit` -> `logistic`
* `cloglog` -> `cloglog`
* `probit` -> `probit`
* `log` `exp`
* `logit` `logistic`
* `cloglog` `cloglog`
* `probit` `probit`

So the above model should be rewritten as

Expand All @@ -102,6 +135,6 @@ end

It's also worth noting that JuliaBUGS uses [`Bijectors.jl`](https://turinglang.org/Bijectors.jl/dev/) to handle constrained parameters.

### Compare with `r-nimble`
### Compare with `nimble`

In the BUGS language, link functions are only supported in logical assignments. However, `r-nimble` extends this functionality by allowing link functions to be used in stochastic assignments as well. JuliaBUGS doesn't currently support this syntax.
In the BUGS language, link functions are only supported in logical assignments. However, `nimble` extends this functionality by allowing link functions to be used in stochastic assignments as well. `nimble` will creates new node as intermediate variables. JuliaBUGS doesn't currently support this syntax.
34 changes: 16 additions & 18 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
# Introduction
# JuliaBUGS.jl

JuliaBUGS is a graph-based probabilistic programming language and a component of the Turing ecosystem.
The package aims to support modelling and inference for probabilistic programs written in the [BUGS](https://www.mrc-bsu.cam.ac.uk/software/bugs/) language.
JuliaBUGS is a graph-based probabilistic programming framework inspired by the BUGS language.

This project is still in its early stage, with many key components needing to be completed.
Key features of JuliaBUGS include:

Please refer to the [example](https://turinglang.org/JuliaBUGS.jl/stable/example/) for usage information and a complete example.
- Compatibility with existing BUGS programs
- Extensibility through user-defined functions and distributions; programmable inference
- Seamless integration with Julia's high-performance numerical and scientific computing libraries
- Automatic differentiation and sampling using Hamiltonian Monte Carlo

## What is BUGS?
It's important to note that while BUGS traditionally refers to either the software system, the language, or the inference algorithm, JuliaBUGS is a pure Julia implementation of the BUGS language, not a wrapper for the BUGS system.

The BUGS (Bayesian inference Using Gibbs Sampling) system is a probabilistic programming framework designed for specifying directed graphical models.
Unlike some other probabilistic programming languages (PPLs), such as Turing.jl or Pyro, the focus of BUGS is on specifying declarative relationships between nodes in a graph, which can be either logical or stochastic.
This means that explicit declarations of variables, inputs, outputs, etc., are not required, and the order of statements is not critical.
## Understanding the BUGS Language

## The BUGS Approach and Benefits
The BUGS (Bayesian inference Using Gibbs Sampling) language is designed for specifying directed graphical models in probabilistic programming. Unlike imperative probabilistic programming languages such as Turing.jl or Pyro, BUGS focuses on declarative relationships between nodes in a graph.

Loops in BUGS are essentially a form of "plate notation," offering a concise way to express repetitive statements across many constant indices.
Variables in BUGS are either the names of nodes within the program or constant parts of the "data" that must be combined with a model for instantiation.
This graph-based approach offers several advantages:

A BUGS model provides a comprehensive representation of the relationships and dependencies among a set of variables within a Bayesian framework.
Our goal is to support BUGS programs as much as possible while also incorporating Julia-specific syntax enhancements.
1. Clarity: It provides a clear understanding of dependencies and relationships within complex systems.
2. Transparency: Users can explicitly state conditional dependencies between variables, making model structure and assumptions more transparent.
3. Ease of development and interpretation: The graphical representation aids in both model development and result interpretation.
4. Efficient inference: The graph structure facilitates the application of advanced inference algorithms, enabling more efficient computation by leveraging the model's structure.

The key advantage of utilizing such a graph-based approach is the clarity it provides in understanding the dependencies and relationships within a complex system.
These graphical models allow users to explicitly state the conditional dependencies between variables.
This makes the model's structure and assumptions transparent, aiding both in the development and interpretation stages.
Furthermore, using such a graphical approach makes it easier to apply advanced algorithms for model inference, as it enables more efficient computation by identifying and exploiting the structure of the model.
By adopting this approach, JuliaBUGS aims to combine the clarity and power of graphical models with the performance and flexibility of the Julia programming language.
Loading

0 comments on commit 1fc7be9

Please sign in to comment.