@@ -1263,24 +1263,43 @@ Abstract type for type indicating that something is "distributional".
1263
1263
"""
1264
1264
abstract type Distributional end
1265
1265
1266
+ """
1267
+ should_auto_prefix(distributional)
1268
+
1269
+ Return `true` if the `distributional` should use automatic prefixing, and `false` otherwise.
1270
+ """
1271
+ function should_auto_prefix end
1272
+
1273
+ """
1274
+ is_rhs_model(x)
1275
+
1276
+ Return `true` if the `distributional` is a model, and `false` otherwise.
1277
+ """
1278
+ function is_rhs_model end
1279
+
1266
1280
"""
1267
1281
Sampleable{M} <: Distributional
1268
1282
1269
1283
A wrapper around a model indicating it is sampleable.
1270
1284
"""
1271
- struct Sampleable{M} <: Distributional
1285
+ struct Sampleable{M,AutoPrefix } <: Distributional
1272
1286
model:: M
1273
1287
end
1274
1288
1289
+ should_auto_prefix (:: Sampleable{<:Any,AutoPrefix} ) where {AutoPrefix} = AutoPrefix
1275
1290
is_rhs_model (x:: Sampleable ) = is_rhs_model (x. model)
1276
1291
1277
1292
# TODO : Export this if it end up having a purpose beyond `to_submodel`.
1278
1293
"""
1279
- to_sampleable(model)
1294
+ to_sampleable(model[, auto_prefix] )
1280
1295
1281
1296
Return a wrapper around `model` indicating it is sampleable.
1297
+
1298
+ # Arguments
1299
+ - `model::Model`: the model to wrap.
1300
+ - `auto_prefix::Bool`: whether to prefix the variables in the model. Default: `true`.
1282
1301
"""
1283
- to_sampleable (model) = Sampleable (model)
1302
+ to_sampleable (model, auto_prefix :: Bool = true ) = Sampleable {typeof(model),auto_prefix} (model)
1284
1303
1285
1304
"""
1286
1305
rand_like!!(model_wrap, context, varinfo)
@@ -1326,7 +1345,7 @@ Return a `model` wrapper indicating that it is a model over its return-values.
1326
1345
returned (model:: Model ) = ReturnedModelWrapper (model)
1327
1346
1328
1347
"""
1329
- to_submodel(model::Model)
1348
+ to_submodel(model::Model[, auto_prefix::Bool] )
1330
1349
1331
1350
Return a model wrapper indicating that it is a sampleable model over the return-values.
1332
1351
@@ -1338,9 +1357,13 @@ the model can be sampled from but not necessarily evaluated for its log density.
1338
1357
such as [`condition`](@ref) or [`fix`](@ref), will also not work with `to_submodel`.
1339
1358
1340
1359
!!! warning
1341
- It's generally recommended to use [`prefix(::Model, input)`](@ref) when working with submodels
1342
- to ensure that the variables in `model` are unique and do not clash with other variables in the
1343
- parent model or in other submodels.
1360
+ To avoid variable names clashing between models, it is recommend leave argument `auto_prefix` equal to `true`.
1361
+ If one does not use automatic prefixing, then it's recommended to use [`prefix(::Model, input)`](@ref) explicitly.
1362
+
1363
+ # Arguments
1364
+ - `model::Model`: the model to wrap.
1365
+ - `auto_prefix::Bool`: whether to automatically prefix the variables in the model using the left-hand
1366
+ side of the `~` statement. Default: `true`.
1344
1367
1345
1368
# Examples
1346
1369
@@ -1361,7 +1384,7 @@ When we sample from the model `demo2(missing, 0.4)` random variable `x` will be
1361
1384
```jldoctest submodel-to_submodel
1362
1385
julia> vi = VarInfo(demo2(missing, 0.4));
1363
1386
1364
- julia> @varname(x ) in keys(vi)
1387
+ julia> @varname(var \" a.x \" ) in keys(vi)
1365
1388
true
1366
1389
```
1367
1390
@@ -1375,29 +1398,42 @@ false
1375
1398
We can check that the log joint probability of the model accumulated in `vi` is correct:
1376
1399
1377
1400
```jldoctest submodel-to_submodel
1378
- julia> x = vi[@varname(x )];
1401
+ julia> x = vi[@varname(var \" a.x \" )];
1379
1402
1380
1403
julia> getlogp(vi) ≈ logpdf(Normal(), x) + logpdf(Uniform(0, 1 + abs(x)), 0.4)
1381
1404
true
1382
1405
```
1383
1406
1384
- ## With prefixing
1407
+ ## Without automatic prefixing
1408
+ As mentioned earlier, by default, the `auto_prefix` argument specifies whether to automatically
1409
+ prefix the variables in the submodel. If `auto_prefix=false`, then the variables in the submodel
1410
+ will not be prefixed.
1385
1411
```jldoctest submodel-to_submodel-prefix; setup=:(using Distributions)
1386
1412
julia> @model function demo1(x)
1387
1413
x ~ Normal()
1388
1414
return 1 + abs(x)
1389
1415
end;
1390
1416
1417
+ julia> @model function demo2_no_prefix(x, z)
1418
+ a ~ to_submodel(demo1(x), false)
1419
+ return z ~ Uniform(-a, 1)
1420
+ end;
1421
+
1422
+ julia> vi = VarInfo(demo2_no_prefix(missing, 0.4));
1423
+
1424
+ julia> @varname(x) in keys(vi) # here we just use `x` instead of `a.x`
1425
+ true
1426
+ ```
1427
+ However, not using prefixing is generally not recommended as it can lead to variable name clashes
1428
+ unless one is careful. For example, if we're re-using the same model twice in a model, not using prefixing
1429
+ will lead to variable name clashes: However, one can manually prefix using the [`prefix(::Model, input)`](@ref):
1430
+ ```jldoctest submodel-to_submodel-prefix
1391
1431
julia> @model function demo2(x, y, z)
1392
- a ~ to_submodel(prefix(demo1(x), :sub1))
1393
- b ~ to_submodel(prefix(demo1(y), :sub2))
1432
+ a ~ to_submodel(prefix(demo1(x), :sub1), false )
1433
+ b ~ to_submodel(prefix(demo1(y), :sub2), false )
1394
1434
return z ~ Uniform(-a, b)
1395
1435
end;
1396
- ```
1397
1436
1398
- When we sample from the model `demo2(missing, missing, 0.4)` random variables `sub1.x` and
1399
- `sub2.x` will be sampled:
1400
- ```jldoctest submodel-to_submodel-prefix
1401
1437
julia> vi = VarInfo(demo2(missing, missing, 0.4));
1402
1438
1403
1439
julia> @varname(var"sub1.x") in keys(vi)
@@ -1432,40 +1468,6 @@ julia> getlogp(vi) ≈ logprior + loglikelihood
1432
1468
true
1433
1469
```
1434
1470
1435
- ## Different ways of setting the prefix
1436
- ```jldoctest submodel-to_submodel-prefix-alts; setup=:(using DynamicPPL, Distributions)
1437
- julia> @model inner() = x ~ Normal()
1438
- inner (generic function with 2 methods)
1439
-
1440
- julia> # When `prefix` is unspecified, no prefix is used.
1441
- @model submodel_noprefix() = a ~ to_submodel(inner())
1442
- submodel_noprefix (generic function with 2 methods)
1443
-
1444
- julia> @varname(x) in keys(VarInfo(submodel_noprefix()))
1445
- true
1446
-
1447
- julia> # Using a static string.
1448
- @model submodel_prefix_string() = a ~ to_submodel(prefix(inner(), "my prefix"))
1449
- submodel_prefix_string (generic function with 2 methods)
1450
-
1451
- julia> @varname(var"my prefix.x") in keys(VarInfo(submodel_prefix_string()))
1452
- true
1453
-
1454
- julia> # Using string interpolation.
1455
- @model submodel_prefix_interpolation() = a ~ to_submodel(prefix(inner(), "\$ (nameof(inner()))"))
1456
- submodel_prefix_interpolation (generic function with 2 methods)
1457
-
1458
- julia> @varname(var"inner.x") in keys(VarInfo(submodel_prefix_interpolation()))
1459
- true
1460
-
1461
- julia> # Or using some arbitrary expression.
1462
- @model submodel_prefix_expr() = a ~ to_submodel(prefix(inner(), 1 + 2))
1463
- submodel_prefix_expr (generic function with 2 methods)
1464
-
1465
- julia> @varname(var"3.x") in keys(VarInfo(submodel_prefix_expr()))
1466
- true
1467
- ```
1468
-
1469
1471
## Usage as likelihood is illegal
1470
1472
1471
1473
Note that it is illegal to use a `to_submodel` model as a likelihood in another model:
@@ -1483,4 +1485,4 @@ julia> model()
1483
1485
ERROR: ArgumentError: `~` with a model on the right-hand side of an observe statement is not supported
1484
1486
[...]
1485
1487
"""
1486
- to_submodel (model:: Model ) = to_sampleable (returned (model))
1488
+ to_submodel (model:: Model , auto_prefix :: Bool = true ) = to_sampleable (returned (model), auto_prefix )
0 commit comments