.. _troubleshooting-debugging: Debugging Functions ==================== If your PMF or PDF is not behaving as expected, this page provides a systematic process for finding and fixing the problem. .. contents:: On this page :local: :depth: 2 ---- Step 1 — Read the Auto-Correction Notice ----------------------------------------- After entering a function, ToFUL shows the interpreted form before computing. Check this carefully: * Is the expression ToFUL interpreted the same as what you intended? * If corrections were applied (shown in the collapsible notice), do they match your intention? .. code-block:: text You typed: 0.3 * 0.7^x if x >= 0 else 0 Interpreted: 0.3 · 0.7^x if x ≥ 0 else 0 ← display form The display form uses Unicode exponents and operators for readability. The actual eval form used internally is ``0.3 * 0.7**x if x >= 0 else 0``. ---- Step 2 — Check the Validation Badge ------------------------------------- After clicking Compute, the validation result appears immediately below the corrections notice. * **Green "valid distribution" badge** — PMF/PDF integrates/sums to 1. The issue (if any) is in the moment computation, not the function definition. * **Red message** — The PMF/PDF failed validation. The message shows the computed sum/integral and the deviation from 1. If the sum is far from 1 (e.g. 0.3 or 45.2), the normalising constant or the formula itself is wrong. If the sum is close but not equal (e.g. 0.9999 or 1.0001), it may be a precision issue with an infinite series — see :doc:`convergence-issues`. ---- Step 3 — Test a Single Value Mentally --------------------------------------- Pick a simple support value and compute the PMF/PDF by hand (or with a calculator) to verify the formula is correct at that point. **Example — Geometric(p=0.3) at x=0:** .. code-block:: text 0.3 * (0.7 ** 0) = 0.3 * 1 = 0.3 (correct) **Example — Poisson(λ=2) at x=1:** .. code-block:: text (exp(-2) * 2**1) / factorial(1) = 2 * exp(-2) ~ 0.2707 (correct) ---- Step 4 — Verify the Guard Condition ------------------------------------- The ``if ... else 0`` guard must cover the entire intended support and return 0 everywhere else. .. code-block:: python # Bug — guard uses >, missing x=0 0.3 * (0.7 ** x) if x > 0 else 0 # Fix — use >= 0.3 * (0.7 ** x) if x >= 0 else 0 For continuous distributions, verify the guard matches your bounds: .. code-block:: python # Bug — guard uses x<=2 but upper bound is set to 3 x if 0 <= x <= 2 else 0 # with upper bound 3 # Fix — match the guard to the upper bound x if 0 <= x <= 3 else 0 # or adjust the upper bound to 2 ---- Step 5 — Check for Python Keyword Conflicts --------------------------------------------- Several common mathematical names are Python reserved words or built-in names that conflict with the expression evaluator: +----------------+---------------------------+ | Problematic | Use instead | +================+===========================+ | ``lambda`` | ``lam`` | +----------------+---------------------------+ | ``in`` | Use comparison operators | +----------------+---------------------------+ | ``and``, ``or``| Use ``and``, ``or`` | +----------------+---------------------------+ | ``True`` | Use ``1`` | +----------------+---------------------------+ | ``False`` | Use ``0`` | +----------------+---------------------------+ | ``None`` | Use ``0`` | +----------------+---------------------------+ The name ``e`` is safe — it is pre-bound to Euler's number. ---- Step 6 — Isolate Multi-Part Expressions ----------------------------------------- For complex piecewise functions, test each piece separately first. **Example — Triangular distribution:** .. code-block:: python # Full expression x if 0<=x<=1 else (2-x) if 1