README · Model · Kettle & Pine example · Decision workflow · Validation
The runtime namespaces are org.replikativ.marketing.model, .inference,
.decision, .io, and .hierarchy. Other namespaces are implementation detail
and marked as such. The numerical compiler (Raster) and probability engine
(Foerster) are pinned dependencies; callers need no compiler internals.
model/specification validates channels, supplied controls, response family,
lag length, fixed scaling, priors, seasonality and observation likelihood.model/prepare validates original-unit observations and constructs runtime
numerical inputs. :x is period-by-channel, :controls period-by-control,
and :y one outcome per period. All rows must align in time and order.model/build creates the numerical model. Defaults are lagged density,
automatic split/packed data layout and automatic scalar/array gradient layout.inference/fit runs NUTS and returns detached posterior chains, named
coordinates, diagnostics, sampler statistics and timings.inference/diagnostics-summary keys R-hat, bulk/tail ESS, MCSE and quantiles
by parameter name (for example [:beta "search"]) and reports divergences,
depth-limit visits and :passes? against inference/default-gates
(R-hat < 1.01, ESS >= 100, no divergences). Pass your own gates as a second
argument.The :jvm alias enables jdk.incubator.vector. The repository currently targets
Java 25. Fit options include :draws, :tune, :chains, :seed,
:target-accept, :max-depth, :timeout-ms (default two hours; nil for
none), :init and
:gradient-backend (:aot by default, or explicit runtime AD), :metric
(:variance by default, or :fisher), and boolean :jitter (default false).
Unknown options are rejected. Marketing explicitly disables Foerster's default
per-chain jitter to preserve the supplied unconstrained starting point. With
:jitter true, that point is the center of Foerster's per-chain jitter.
The sampler metadata records the supplied point, metric and jitter setting.
Results retain Foerster's Markov-chain inference contract, including that no
evidence estimate is available. Chain lengths and sampler-statistic alignment
are checked before detaching the result and survive EDN/JSON persistence.
:draws excludes warm-up; use at least two chains. :init is unconstrained,
whereas returned chain positions are constrained natural parameters. Prefer
model/initial-position to constructing a positional initialization manually.
Four requested chains do not imply four sampling threads; see Limits.
A first AOT fit prepares an executable; subsequent compatible fits can reuse it.
The fit budget includes gradient preparation, but does not include the prior
model/prepare and model/build calls. Cancellation/worker termination has not
been qualified as a hard resource deadline.
Supply fixed positive scaling: one :scaling :channel value per channel and a
:scaling :target outcome scale. These are supplied conventions; the package
does not learn preprocessing on the holdout. Predictors and likelihoods use
normalized coordinates internally. Predictions, decision budgets, experiment
estimates and scenario totals use original units. Prior parameters use internal
scaled coordinates, including control coefficients; user controls are not
implicitly standardized.
Geometric adstock uses lags 0 through l-max-1, normalized by the sum of those
geometric weights. Spend before the first supplied row is zero. Supply actual
prehistory when that assumption would be wrong.
| Family | Response to normalized effective spend z | Shape meaning |
|---|---|---|
:logistic | beta * tanh(lambda*z/2) | lambda controls curvature |
:michaelis-menten | beta*z/(kappa+z) | kappa is effective spend at half ceiling |
:none | beta*z | No shape parameter |
beta is positive. Intercept and controls are additive. Priors must match the
support of each latent. Gaussian noise is the default; a Student-t likelihood
uses {:distribution :student-t :nu 4.0} with fixed finite nu > 2.
Fourier seasonality appends sine/cosine controls; explicit
:time-index values are required when configured and must preserve phase across
training and prediction. Use the parameter names returned with a model/posterior
rather than fixed numeric offsets, which differ by response family and controls.
model/mean-response takes a built model and one constrained parameter vector
and returns original-unit conditional means. It does not draw observation noise.
model/pointwise-log-likelihood returns original-unit observation log densities,
excluding priors and experiment evidence. For a new history or prediction path,
prepare it with the same canonical specification, then combine its data/inputs
with the existing built model. Keep structural layouts compatible; rebuild when
structure changes.
(decision/compare-plans built restored
{:x [[1100.0 900.0] [1100.0 900.0]] :controls future-controls}
{:x [[900.0 1100.0] [900.0 1100.0]] :controls future-controls})
Both plans need the same nonempty horizon and identical controls. The API keeps
up to l-max-1 rows of training history, appends zero-spend carryover periods,
and compares the plans using paired posterior draws. Optional time indices must
immediately follow training history. The returned :active, :carryover and
:total summaries describe conditional-mean differences, not predictive noise
or uncertainty about the future controls. In a seasonal model future phase is
continued from the training time index. An optional fifth argument
{:max-draws n} evaluates on a thinned posterior.
decision/plan-responses returns the per-draw weekly conditional-mean response
paths of one plan, over its horizon plus l-max-1 carryover weeks, in original
units. Use it when a plan's demand feeds a larger simulation, as in the
warehouse extension.
decision/allocate maximizes posterior expected response for a constant weekly
channel allocation. Provide positive :budget, positive integer :horizon,
future controls, and optional feasible :lower/:upper bounds per channel.
The budget is weekly, not a total over the horizon. The response objective
includes the active horizon and l-max-1 zero-spend carryover periods. There is
no arbitrary time-varying budget optimizer, profit/cost utility or risk objective.
Inspect :converged?, :projected-gradient-residual, :iterations, feasibility
and finite results. Optimization uses budget fractions and response divided by
:scaling :target; the residual is the maximum fraction-coordinate change after
a projected unit step of that normalized objective gradient.
:objective-response-scale records the target normalization. Returned
:expected-response and :gradient retain original outcome and spend units.
The residual therefore depends on the declared target normalization; compare it
only under the same convention. An iteration-limit exit is not success.
Derivatives come from Raster AD; finite differences in the tests check them
independently. Allocation is iterative, so large posteriors are usually thinned:
:max-draws n (or decision/thin) keeps at most n draws, evenly spaced within
each chain. This API currently supports flat models and explicitly rejects geo
models.
(posterior-io/write! "fit.edn" posterior)
(posterior-io/write! "fit.json" posterior :json)
(posterior-io/read! "fit.edn")
(posterior-io/read! "fit.json" :json)
Files preserve chains, canonical specification, names, diagnostics, statistics and timings. Tagged JSON preserves keyword identities and nonfinite diagnostics; it is not a conventional plain JSON schema. Loading validates the format, coordinate layout, finiteness and parameter supports.
A posterior does not contain the original training observations or executable kernels. Store training data/history, time indices and provenance separately, then rebuild in the consumer process. The study stores the fixture, the posterior and source fingerprints and checks them on a fresh replay.
Static :lift observations require :type :effective-spend-contrast and describe
a channel's effective-spend contrast with original-unit :x, :delta-x, :delta-y and positive measurement :sigma.
Time-path :experiments specify baseline/treatment media schedules, shared
prehistory, a weighted observation window, signed :estimate, uncertainty, and
:independent-of-training? true. The first l-max-1 rows provide common history
and have zero measurement weights. Experiment estimates measure the weighted
sum of the modeled contrast, not automatically an average or a per-week effect.
A top-level :experiment-covariance can supply a fixed symmetric positive
definite joint measurement covariance. Otherwise each experiment supplies its
own positive :sigma. The uncertainty is measurement error on the estimator,
not the training residual scale. Transportability and independence are supplied
assumptions. Do not count training outcomes again as independent calibration.
The calibrated Kettle & Pine case (data)
shows a time-path experiment with history, treatment and follow-up weeks.
hierarchy/specification, hierarchy/prepare and hierarchy/build expose a
focused noncentered geo model. Channel amplitudes are partially pooled; adstock,
shape and controls are shared; intercept/noise vary by group. Histories are
isolated by group. This is not arbitrary multidimensional modelling, and the
decision API does not accept geo models yet.
inference/fit does not expose an executor option.model/build chooses split or packed data layouts and scalar or
array gradients automatically. These change representation, not the
statistical target. Scalar AD supports at most 18 arguments.:timeout-ms stops sampling, but is not a hard resource
deadline. Run large fits in disposable processes.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |