@mcmcjs/julia 0.7.1 → 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.
Files changed (2) hide show
  1. package/dist/fitlib.jl +32 -2
  2. package/package.json +3 -3
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 = getfield(Main, Symbol(request["model"]["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.7.1",
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/core": "0.6.0",
50
- "@mcmcjs/engine": "0.5.0"
49
+ "@mcmcjs/engine": "0.5.0",
50
+ "@mcmcjs/core": "0.6.0"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup",