diff --git a/.github/workflows/version_check.jl b/.github/workflows/version_check.jl index 555c5758b..35e70bc42 100644 --- a/.github/workflows/version_check.jl +++ b/.github/workflows/version_check.jl @@ -1,6 +1,6 @@ # Set up a temporary environment just to run this script using Pkg -Pkg.activate(temp=true) +Pkg.activate(temp = true) Pkg.add(["YAML", "TOML", "JSON", "HTTP"]) import YAML import TOML @@ -18,7 +18,10 @@ end function major_minor_patch_match(vs...) first = vs[1] - all(v.:major == first.:major && v.:minor == first.:minor && v.:patch == first.:patch for v in vs) + all( + v.:major == first.:major && v.:minor == first.:minor && v.:patch == first.:patch for + v in vs + ) end """ @@ -34,7 +37,10 @@ function update_project_toml(filename, target_version::VersionNumber) open(filename, "w") do io for line in lines if occursin(r"^Turing\s*=\s*\"\d+\.\d+\"\s*$", line) - println(io, "Turing = \"$(target_version.:major).$(target_version.:minor)\"") + println( + io, + "Turing = \"$(target_version.:major).$(target_version.:minor)\"", + ) else println(io, line) end @@ -54,7 +60,10 @@ function update_quarto_yml(filename, target_version::VersionNumber) for line in lines m = match(r"^(\s+)- text:\s*\"v\d+\.\d+\"\s*$", line) if m !== nothing - println(io, "$(m[1])- text: \"v$(target_version.:major).$(target_version.:minor)\"") + println( + io, + "$(m[1])- text: \"v$(target_version.:major).$(target_version.:minor)\"", + ) else println(io, line) end @@ -108,7 +117,7 @@ if ENV["TARGET_IS_MAIN"] == "true" old_env = Pkg.project().path Pkg.activate(".") try - Pkg.add(name="Turing", version=latest_version) + Pkg.add(name = "Turing", version = latest_version) catch e # If the Manifest couldn't be updated, the error will be shown later println(e) @@ -118,14 +127,20 @@ if ENV["TARGET_IS_MAIN"] == "true" manifest_toml = TOML.parsefile(MANIFEST_TOML_PATH) manifest_version = VersionNumber(manifest_toml["deps"]["Turing"][1]["version"]) if !major_minor_patch_match(latest_version, manifest_version) - push!(errors, "Failed to update $(MANIFEST_TOML_PATH) to match latest Turing.jl version") + push!( + errors, + "Failed to update $(MANIFEST_TOML_PATH) to match latest Turing.jl version", + ) end end if isempty(errors) println("All good") else - error("The following errors occurred during version checking: \n", join(errors, "\n")) + error( + "The following errors occurred during version checking: \n", + join(errors, "\n"), + ) end else @@ -135,10 +150,12 @@ else # work as it would involve paging through the list of releases). Instead, # we just check that the minor versions match. if !major_minor_match(quarto_version, project_version, manifest_version) - error("The minor versions of Turing.jl in _quarto.yml, Project.toml, and Manifest.toml are inconsistent: - - _quarto.yml: $quarto_version_str - - Project.toml: $project_version_str - - Manifest.toml: $manifest_version - ") + error( + "The minor versions of Turing.jl in _quarto.yml, Project.toml, and Manifest.toml are inconsistent: + - _quarto.yml: $quarto_version_str + - Project.toml: $project_version_str + - Manifest.toml: $manifest_version + ", + ) end end diff --git a/Manifest.toml b/Manifest.toml index ccb972de6..0c4d1e0e0 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -2,7 +2,7 @@ julia_version = "1.11.6" manifest_format = "2.0" -project_hash = "2db94c909342da49eb3ff313436b75e25977ace6" +project_hash = "296b7e06e398e8898b40f44ed92b4d60c484484c" [[deps.ADTypes]] git-tree-sha1 = "60665b326b75db6517939d0e1875850bc4a54368" @@ -685,9 +685,9 @@ version = "0.1.2" [[deps.DelayDiffEq]] deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "FastBroadcast", "ForwardDiff", "LinearAlgebra", "Logging", "OrdinaryDiffEq", "OrdinaryDiffEqCore", "OrdinaryDiffEqDefault", "OrdinaryDiffEqDifferentiation", "OrdinaryDiffEqFunctionMap", "OrdinaryDiffEqNonlinearSolve", "OrdinaryDiffEqRosenbrock", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SimpleNonlinearSolve", "SimpleUnPack", "SymbolicIndexingInterface"] -git-tree-sha1 = "c50981fb5b6441a1213debb1423385a462e88032" +git-tree-sha1 = "d9b1e66070ce15bc2b9c3d5af6b94f693fc03ba4" uuid = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" -version = "5.56.0" +version = "5.58.0" [[deps.DelimitedFiles]] deps = ["Mmap"] @@ -1180,9 +1180,9 @@ version = "1.3.7" [[deps.ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] -git-tree-sha1 = "910febccb28d493032495b7009dce7d7f7aee554" +git-tree-sha1 = "a2df1b776752e3f344e5116c06d75a10436ab853" uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "1.0.1" +version = "0.10.38" weakdeps = ["StaticArrays"] [deps.ForwardDiff.extensions] @@ -1299,6 +1299,24 @@ git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" version = "1.0.2" +[[deps.HDF5]] +deps = ["Compat", "HDF5_jll", "Libdl", "MPIPreferences", "Mmap", "Preferences", "Printf", "Random", "Requires", "UUIDs"] +git-tree-sha1 = "e856eef26cf5bf2b0f95f8f4fc37553c72c8641c" +uuid = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" +version = "0.17.2" + + [deps.HDF5.extensions] + MPIExt = "MPI" + + [deps.HDF5.weakdeps] + MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" + +[[deps.HDF5_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "LibCURL_jll", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "OpenSSL_jll", "TOML", "Zlib_jll", "libaec_jll"] +git-tree-sha1 = "e94f84da9af7ce9c6be049e9067e511e17ff89ec" +uuid = "0234f1f7-429e-5d53-9886-15a909be8d59" +version = "1.14.6+0" + [[deps.HTTP]] deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] git-tree-sha1 = "ed5e9c58612c4e081aecdb6e1a479e18462e041e" @@ -1326,6 +1344,12 @@ weakdeps = ["Distributions"] [deps.HiddenMarkovModels.extensions] HiddenMarkovModelsDistributionsExt = "Distributions" +[[deps.Hwloc_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "92f65c4d78ce8cdbb6b68daf88889950b0a99d11" +uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" +version = "2.12.1+0" + [[deps.HypergeometricFunctions]] deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] git-tree-sha1 = "68c173f4f449de5b438ee67ed0c9c748dc31a2ec" @@ -1454,9 +1478,9 @@ version = "0.2.1" [[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e95866623950267c1e4878846f848d94810de475" +git-tree-sha1 = "eac1206917768cb54957c65a615460d87b455fc1" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "3.1.2+0" +version = "3.1.1+0" [[deps.JuliaVariables]] deps = ["MLStyle", "NameResolution"] @@ -1945,10 +1969,10 @@ version = "1.10.2" cuDNN = "02a925ec-e4fe-4b08-9a7e-0d78e3d38ccd" [[deps.MCMCChains]] -deps = ["AbstractMCMC", "AxisArrays", "DataAPI", "Dates", "Distributions", "IteratorInterfaceExtensions", "KernelDensity", "LinearAlgebra", "MCMCDiagnosticTools", "MLJModelInterface", "NaturalSort", "OrderedCollections", "PrettyTables", "Random", "RecipesBase", "Statistics", "StatsBase", "StatsFuns", "TableTraits", "Tables"] -git-tree-sha1 = "f3993c723865f670102011ef22811e2bbb0ef1a8" +deps = ["AbstractMCMC", "AxisArrays", "Dates", "Distributions", "IteratorInterfaceExtensions", "KernelDensity", "LinearAlgebra", "MCMCDiagnosticTools", "MLJModelInterface", "NaturalSort", "OrderedCollections", "PrettyTables", "Random", "RecipesBase", "Statistics", "StatsBase", "StatsFuns", "TableTraits", "Tables"] +git-tree-sha1 = "cd7aee22384792c726e19f2a22dc060b886edded" uuid = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" -version = "7.2.0" +version = "6.0.7" [[deps.MCMCDiagnosticTools]] deps = ["AbstractFFTs", "DataAPI", "DataStructures", "Distributions", "LinearAlgebra", "MLJModelInterface", "Random", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Tables"] @@ -2049,6 +2073,24 @@ git-tree-sha1 = "a772d8d1987433538a5c226f79393324b55f7846" uuid = "f1d291b0-491e-4a28-83b9-f70985020b54" version = "0.4.8" +[[deps.MPICH_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] +git-tree-sha1 = "d72d0ecc3f76998aac04e446547259b9ae4c265f" +uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" +version = "4.3.1+0" + +[[deps.MPIPreferences]] +deps = ["Libdl", "Preferences"] +git-tree-sha1 = "c105fe467859e7f6e9a852cb15cb4301126fac07" +uuid = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" +version = "0.1.11" + +[[deps.MPItrampoline_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] +git-tree-sha1 = "e214f2a20bdd64c04cd3e4ff62d3c9be7e969a59" +uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" +version = "5.5.4+0" + [[deps.MacroTools]] git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" @@ -2111,12 +2153,24 @@ git-tree-sha1 = "7dbf904fa6c4447bd1f1d316886bfbe29feacf45" uuid = "6fafb56a-5788-4b4e-91ca-c0cea6611c73" version = "0.2.2" +[[deps.MicroCanonicalHMC]] +deps = ["AbstractMCMC", "Adapt", "Distributions", "ForwardDiff", "HDF5", "LinearAlgebra", "LogDensityProblems", "LogDensityProblemsAD", "MCMCChains", "MCMCDiagnosticTools", "Markdown", "ProgressMeter", "Random", "Statistics"] +git-tree-sha1 = "99fd367f8b8fc9d479420d33e8f16f3dab3162f4" +uuid = "234d2aa0-2291-45f7-9047-6fa6f316b0a8" +version = "0.1.6" + [[deps.MicroCollections]] deps = ["Accessors", "BangBang", "InitialValues"] git-tree-sha1 = "44d32db644e84c75dab479f1bc15ee76a1a3618f" uuid = "128add7d-3638-4c79-886c-908ea0c25c34" version = "0.2.0" +[[deps.MicrosoftMPI_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bc95bf4149bf535c09602e3acdf950d9b4376227" +uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" +version = "10.1.4+3" + [[deps.Missings]] deps = ["DataAPI"] git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" @@ -2392,6 +2446,12 @@ deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" version = "0.8.5+0" +[[deps.OpenMPI_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"] +git-tree-sha1 = "ec764453819f802fc1e144bfe750c454181bd66d" +uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" +version = "5.0.8+0" + [[deps.OpenSSL]] deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] git-tree-sha1 = "f1a7e086c677df53e064e0fdd2c9d0b0833e3f6e" @@ -3937,6 +3997,12 @@ git-tree-sha1 = "b6a34e0e0960190ac2a4363a1bd003504772d631" uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" version = "0.61.1+0" +[[deps.libaec_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "f5733a5a9047722470b95a81e1b172383971105c" +uuid = "477f73a3-ac25-53e9-8cc3-50b2fa2566f0" +version = "1.1.3+0" + [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "4bba74fa59ab0755167ad24f98800fe5d727175b" diff --git a/_quarto.yml b/_quarto.yml index 9bab2644c..e8b5ea9cf 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -33,6 +33,8 @@ website: href: getting-started/ - text: Tutorials href: tutorials/ + - text: FAQ + href: faq/ - text: Libraries href: https://turinglang.org/library/ - text: News diff --git a/faq/index.qmd b/faq/index.qmd new file mode 100644 index 000000000..5af703000 --- /dev/null +++ b/faq/index.qmd @@ -0,0 +1,140 @@ +--- +title: "Frequently Asked Questions" +description: "Common questions and answers about using Turing.jl" +--- + +## Why is this variable being treated as random instead of observed? + +This is a common source of confusion. In Turing.jl, you can only condition or fix expressions that explicitly appear on the left-hand side (LHS) of a `~` statement. + +For example, if your model contains: +```julia +x ~ filldist(Normal(), 2) +``` + +You cannot directly condition on `x[2]` using `condition(model, @varname(x[2]) => 1.0)` because `x[2]` never appears on the LHS of a `~` statement. Only `x` as a whole appears there. + +However, there is an important exception: when you use the broadcasting operator `.~` with a univariate distribution, each element is treated as being separately drawn from that distribution, allowing you to condition on individual elements: + +```julia +@model function f1() + x = Vector{Float64}(undef, 3) + x .~ Normal() # Each element is a separate draw +end + +m1 = f1() | (@varname(x[1]) => 1.0) +sample(m1, NUTS(), 100) # This works! +``` + +In contrast, you cannot condition on parts of a multivariate distribution because it represents a single distribution over the entire vector: + +```julia +@model function f2() + x = Vector{Float64}(undef, 3) + x ~ MvNormal(zeros(3), I) # Single multivariate distribution +end + +m2 = f2() | (@varname(x[1]) => 1.0) +sample(m2, NUTS(), 100) # This doesn't work! +``` + +The key insight is that `filldist` creates a single distribution (not N independent distributions), which is why you cannot condition on individual elements. The distinction is not just about what appears on the LHS of `~`, but whether you're dealing with separate distributions (`.~` with univariate) or a single distribution over multiple values (`~` with multivariate or `filldist`). + +To understand more about how Turing determines whether a variable is treated as random or observed, see: +- [Core Functionality]({{< meta core-functionality >}}) - basic explanation of the `~` notation and conditioning + + +## Can I use parallelism / threads in my model? + +Yes, but with important caveats! There are two types of parallelism to consider: + +### 1. Parallel Sampling (Multiple Chains) +Turing.jl fully supports sampling multiple chains in parallel: +- **Multithreaded sampling**: Use `MCMCThreads()` to run one chain per thread +- **Distributed sampling**: Use `MCMCDistributed()` for distributed computing + +See the [Core Functionality guide]({{< meta core-functionality >}}/#sampling-multiple-chains) for examples. + +### 2. Threading Within Models +Using threads inside your model (e.g., `Threads.@threads`) requires more care: + +```julia +@model function f(y) + x = Vector{Float64}(undef, length(y)) + Threads.@threads for i in eachindex(y) + x[i] ~ Normal() # UNSAFE: `assume` statements in @threads can crash! + y[i] ~ Normal(x[i]) # `observe` statements are okay + end +end +``` + +**Important limitations:** +- **Observe statements**: Generally safe to use in threaded loops +- **Assume statements** (sampling statements): Often crash unpredictably or produce incorrect results +- **AD backend compatibility**: Many AD backends don't support threading. Check the [multithreaded column in ADTests](https://turinglang.org/ADTests/) for compatibility + +For safe parallelism within models, consider vectorized operations instead of explicit threading. + +## How do I check the type stability of my Turing model? + +Type stability is crucial for performance. Check out: +- [Performance Tips]({{< meta usage-performance-tips >}}) - includes specific advice on type stability +- Use `DynamicPPL.DebugUtils.model_warntype` to check type stability of your model + +## How do I debug my Turing model? + +For debugging both statistical and syntactical issues: +- [Troubleshooting Guide]({{< meta usage-troubleshooting >}}) - common errors and their solutions +- For more advanced debugging, DynamicPPL provides [the `DynamicPPL.DebugUtils` module](https://turinglang.org/DynamicPPL.jl/stable/api/#Debugging-Utilities) for inspecting model internals + +## What are the main differences between Turing, BUGS, and Stan syntax? + +Key syntactic differences include: + +- **Parameter blocks**: Stan requires explicit `data`, `parameters`, and `model` blocks. In Turing, everything is defined within the `@model` macro +- **Variable declarations**: Stan requires upfront type declarations in parameter blocks. Turing infers types from the sampling statements +- **Transformed data**: Stan has a `transformed data` block for preprocessing. In Turing, data transformations should be done before defining the model +- **Generated quantities**: Stan has a `generated quantities` block. In Turing, use the approach described in [Tracking Extra Quantities]({{< meta usage-tracking-extra-quantities >}}) + +Example comparison: +```stan +// Stan +data { + real y; +} +parameters { + real mu; + real sigma; +} +model { + mu ~ normal(0, 1); + sigma ~ normal(0, 1); + y ~ normal(mu, sigma); +} +``` + +```julia +# Turing +@model function my_model(y) + mu ~ Normal(0, 1) + sigma ~ truncated(Normal(0, 1); lower=0) + y ~ Normal(mu, sigma) +end +``` + +## Which automatic differentiation backend should I use? + +The choice of AD backend can significantly impact performance. See: +- [Automatic Differentiation Guide]({{< meta usage-automatic-differentiation >}}) - comprehensive comparison of ForwardDiff, Mooncake, ReverseDiff, and other backends +- [Performance Tips]({{< meta usage-performance-tips >}}#choose-your-ad-backend) - quick guide on choosing backends +- [AD Backend Benchmarks](https://turinglang.org/ADTests/) - performance comparisons across various models + +## I changed one line of my model and now it's so much slower; why? + +Small changes can have big performance impacts. Common culprits include: +- Type instability introduced by the change +- Switching from vectorized to scalar operations (or vice versa) +- Inadvertently causing AD backend incompatibilities +- Breaking assumptions that allowed compiler optimizations + +See our [Performance Tips]({{< meta usage-performance-tips >}}) and [Troubleshooting Guide]({{< meta usage-troubleshooting >}}) for debugging performance regressions. \ No newline at end of file