@mcmcjs/julia 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/fitlib.jl +32 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# @mcmcjs/julia
|
|
2
2
|
|
|
3
|
-
The bridge to the Julia ecosystem for [MCMC.js](https://github.com/mcmcjs/mcmcjs)
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The bridge to the Julia ecosystem for [MCMC.js](https://github.com/mcmcjs/mcmcjs).
|
|
4
|
+
|
|
5
|
+
It detects and bootstraps the Julia toolchain via juliaup, manages a pinned, per-user Julia project, and runs inference as a subprocess.
|
|
6
|
+
|
|
7
|
+
## What it provides
|
|
8
|
+
|
|
9
|
+
- **Toolchain** — detect juliaup and Julia (`detectJulia`/`detectJuliaup`), install them (`planSetup`/`runSetup`), and manage versions (`list`/`add`/`remove`/`default`/`update`/`gc`) over juliaup channels.
|
|
10
|
+
- **Managed project** — provision an isolated Julia project with Turing.jl and JuliaBUGS (and friends) and precompile it (`ensureProject`).
|
|
11
|
+
- **Driver** — the `fit` and `predict` runner (`driver.jl`) that runs Turing or JuliaBUGS and writes the MCMCChains-JSON samples file plus a run record.
|
|
6
12
|
|
|
7
13
|
> Early alpha: the API is not yet stable.
|
|
8
14
|
|
|
9
15
|
## License
|
|
10
16
|
|
|
11
|
-
[MIT](./LICENSE)
|
|
17
|
+
[MIT](./LICENSE) © [Shravan Goswami](https://shravangoswami.com)
|
package/dist/fitlib.jl
CHANGED
|
@@ -223,12 +223,30 @@ function draw_streamer(draws_per_chain::Int, batch_size::Int)
|
|
|
223
223
|
end
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
+
# Turing observes a variable only when its name is a model argument. A dict-reading
|
|
227
|
+
# model (`y = data["y"]; y[i] ~ dist`) would otherwise SAMPLE its outcome instead of
|
|
228
|
+
# observing it, so condition the built model on the data columns to turn each such
|
|
229
|
+
# `~` into an observation. Columns that are already model arguments are skipped: they
|
|
230
|
+
# are observed by construction, and conditioning one that is also an argument errors.
|
|
231
|
+
# Do not probe the model to find latent columns (e.g. via VarInfo): evaluating a
|
|
232
|
+
# dict-reading model assigns prior draws into the array the data is read from,
|
|
233
|
+
# corrupting it before we condition. Predictor columns carry no `~`, so conditioning
|
|
234
|
+
# on them is a harmless no-op.
|
|
235
|
+
function condition_on_data(model, data)
|
|
236
|
+
nt = data isa ModelData ? getfield(data, :nt) : data
|
|
237
|
+
nt isa NamedTuple || return model
|
|
238
|
+
argnames = keys(model.args)
|
|
239
|
+
pairs = [k => getproperty(nt, k) for k in keys(nt) if Base.isidentifier(string(k)) && !(k in argnames)]
|
|
240
|
+
isempty(pairs) && return model
|
|
241
|
+
return Turing.DynamicPPL.condition(model, (; pairs...))
|
|
242
|
+
end
|
|
243
|
+
|
|
226
244
|
# Build the model and sample in one call so both run in the latest world age:
|
|
227
245
|
# the model methods are defined by `include` at runtime, so a plain call from
|
|
228
246
|
# this (older) world would fail with "method too new". invokelatest fixes that.
|
|
229
247
|
# Returns Turing's default chain type, a FlexiChain. With a callback, draws stream.
|
|
230
248
|
function build_and_sample(entry, data, sampler, draws, chains, rng; callback = nothing)
|
|
231
|
-
model = entry(data)
|
|
249
|
+
model = condition_on_data(entry(data), data)
|
|
232
250
|
kw = callback === nothing ? NamedTuple() : (; callback)
|
|
233
251
|
return Logging.with_logger(JSONProgressLogger()) do
|
|
234
252
|
sample(rng, model, sampler, MCMCSerial(), draws, chains; progress = true, kw...)
|
|
@@ -320,6 +338,18 @@ function provenance()
|
|
|
320
338
|
)
|
|
321
339
|
end
|
|
322
340
|
|
|
341
|
+
# Resolve the model entry function: use the requested name, falling back to the
|
|
342
|
+
# conventional build_model. This lets a request leave the entry implicit, or name a
|
|
343
|
+
# custom entry that a given model file does not define (then build_model is used).
|
|
344
|
+
function resolve_entry(mod, requested)
|
|
345
|
+
for name in (requested, "build_model")
|
|
346
|
+
name === nothing && continue
|
|
347
|
+
sym = Symbol(name)
|
|
348
|
+
isdefined(mod, sym) && return getfield(mod, sym)
|
|
349
|
+
end
|
|
350
|
+
error("model file defines no entry function (looked for $(requested) and build_model)")
|
|
351
|
+
end
|
|
352
|
+
|
|
323
353
|
# Runs one request end to end. Returns {"ok": true, "provenance": ...} or
|
|
324
354
|
# {"ok": false, "error": ..., "stage": ...}; never throws.
|
|
325
355
|
function handle_request(request)
|
|
@@ -331,7 +361,7 @@ function handle_request(request)
|
|
|
331
361
|
Random.seed!(Int(request["seed"]))
|
|
332
362
|
rng = StableRNG(Int(request["seed"]))
|
|
333
363
|
Base.include(Main, abspath(request["model"]["file"]))
|
|
334
|
-
entry =
|
|
364
|
+
entry = resolve_entry(Main, get(request["model"], "entry", nothing))
|
|
335
365
|
|
|
336
366
|
wire = if mode == "predict"
|
|
337
367
|
backend == "turing" || error("predict is not yet supported for backend $backend")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcmcjs/julia",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Julia toolchain detection and the inference runner for MCMC.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcmc",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@mcmcjs/
|
|
50
|
-
"@mcmcjs/
|
|
49
|
+
"@mcmcjs/engine": "0.5.0",
|
|
50
|
+
"@mcmcjs/core": "0.6.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|