-
Notifications
You must be signed in to change notification settings - Fork 9
feat(math): add finite stochastic processes domain with sigma algebras, conditional expectation, filtrations, and Doob martingales (#1806) #2036
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """Supported native finite stochastic process API.""" | ||
|
|
||
| from jacobian.math.finite_stochastic_processes.operations import ( | ||
| conditional_expectation, | ||
| doob_martingale, | ||
| filtration_natural, | ||
| sigma_algebra_from_observation, | ||
| sigma_algebra_join, | ||
| ) | ||
| from jacobian.math.finite_stochastic_processes.values import ( | ||
| FiniteProbabilitySpace, | ||
| FiniteRandomVariable, | ||
| FiniteSigmaAlgebra, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "FiniteProbabilitySpace", | ||
| "FiniteRandomVariable", | ||
| "FiniteSigmaAlgebra", | ||
| "conditional_expectation", | ||
| "doob_martingale", | ||
| "filtration_natural", | ||
| "sigma_algebra_from_observation", | ||
| "sigma_algebra_join", | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| """Owner-local admission decisions for built-in math operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from jacobian.catalog.admission import AdmissionDecision, OperationAdmission | ||
|
|
||
| ADMISSIONS: tuple[OperationAdmission, ...] = ( | ||
| OperationAdmission( | ||
| "probability.finite_sigma_algebra.from_observation.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact sigma algebra construction from an observation map with equal-value fibers", | ||
| ), | ||
| OperationAdmission( | ||
| "probability.finite_sigma_algebra.join.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact join of two finite sigma algebras as the finest common refinement", | ||
| ), | ||
| OperationAdmission( | ||
| "probability.conditional_expectation.finite.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact block-constant conditional expectation with probability-weighted block averages", | ||
| ), | ||
| OperationAdmission( | ||
| "probability.filtration.natural.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact natural filtration F_t = sigma(Y_0, ..., Y_t) with monotone refinement", | ||
| ), | ||
| OperationAdmission( | ||
| "probability.process.doob_martingale.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact Doob martingale M_t = E[payoff | F_t] with rational-valued conditional expectations", | ||
| ), | ||
| ) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,71 @@ | ||||||||||||||||||
| """Typed wire contracts for finite stochastic process operations.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| from __future__ import annotations | ||||||||||||||||||
|
|
||||||||||||||||||
| from pydantic import Field | ||||||||||||||||||
|
|
||||||||||||||||||
| from jacobian._models import StrictModel | ||||||||||||||||||
| from jacobian.math.finite_stochastic_processes.values import ( | ||||||||||||||||||
| FiniteProbabilitySpace, | ||||||||||||||||||
| FiniteRandomVariable, | ||||||||||||||||||
| FiniteSigmaAlgebra, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class FromObservationRequest(StrictModel): | ||||||||||||||||||
| """Construct a sigma algebra from an observation map.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| space: FiniteProbabilitySpace | ||||||||||||||||||
| observation: tuple[str, ...] = Field(min_length=1) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class JoinRequest(StrictModel): | ||||||||||||||||||
| """Compute the join of two sigma algebras.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| sigma1: FiniteSigmaAlgebra | ||||||||||||||||||
| sigma2: FiniteSigmaAlgebra | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class ConditionalExpectationRequest(StrictModel): | ||||||||||||||||||
| """Compute E[X | G].""" | ||||||||||||||||||
|
|
||||||||||||||||||
| rv: FiniteRandomVariable | ||||||||||||||||||
| sigma: FiniteSigmaAlgebra | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class FiltrationRequest(StrictModel): | ||||||||||||||||||
| """Compute the natural filtration of observations.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| space: FiniteProbabilitySpace | ||||||||||||||||||
| observations: tuple[tuple[str, ...], ...] = Field(default=()) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class DoobMartingaleRequest(StrictModel): | ||||||||||||||||||
| """Compute the Doob martingale of a payoff process.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| space: FiniteProbabilitySpace | ||||||||||||||||||
| observations: tuple[tuple[str, ...], ...] = Field(default=()) | ||||||||||||||||||
| payoff: tuple[str, ...] = Field(min_length=1) | ||||||||||||||||||
|
Comment on lines
+15
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Valid-looking probability requests crash the server instead of returning a result Requests that pass validation but describe mismatched data are rejected deep inside the computation by raising a plain error ( Missing cross-field validation on the request models lets kernel ValueErrors escape through dispatchVerified by running the adapters:
Fix by adding Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class FiltrationResult(StrictModel): | ||||||||||||||||||
| """The natural filtration as a tuple of sigma algebra dicts.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| sigmas: tuple[dict[str, object], ...] = Field(default=()) | ||||||||||||||||||
|
Comment on lines
+51
to
+54
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Filtration results are returned as untyped dictionaries that drop the probability space Each step of the filtration result is emitted as a loose key/value bag containing only the blocks ( FiltrationResult uses tuple[dict[str, object], ...]
AGENTS.md "Types and transport": request/result models are authoritative at operation and wire boundaries and operations should compose through their typed mathematical values.
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class DoobMartingaleResult(StrictModel): | ||||||||||||||||||
| """The Doob martingale as a tuple of rational-string value tuples.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| martingale: tuple[tuple[str, ...], ...] = Field(default=()) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| __all__ = [ | ||||||||||||||||||
| "ConditionalExpectationRequest", | ||||||||||||||||||
| "DoobMartingaleRequest", | ||||||||||||||||||
| "DoobMartingaleResult", | ||||||||||||||||||
| "FiltrationRequest", | ||||||||||||||||||
| "FiltrationResult", | ||||||||||||||||||
| "FromObservationRequest", | ||||||||||||||||||
| "JoinRequest", | ||||||||||||||||||
| ] | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| """Domain adapter for finite stochastic process operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from jacobian.math.finite_stochastic_processes._models import ( | ||
| ConditionalExpectationRequest, | ||
| DoobMartingaleRequest, | ||
| DoobMartingaleResult, | ||
| FiltrationRequest, | ||
| FiltrationResult, | ||
| FromObservationRequest, | ||
| JoinRequest, | ||
| ) | ||
| from jacobian.math.finite_stochastic_processes.operations import ( | ||
| conditional_expectation, | ||
| doob_martingale, | ||
| filtration_natural, | ||
| sigma_algebra_from_observation, | ||
| ) | ||
| from jacobian.math.finite_stochastic_processes.values import ( | ||
| FiniteRandomVariable, | ||
| FiniteSigmaAlgebra, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "compute_conditional_expectation", | ||
| "compute_doob_martingale", | ||
| "compute_filtration", | ||
| "compute_join", | ||
| "compute_sigma_from_observation", | ||
| ] | ||
|
|
||
|
|
||
| def compute_sigma_from_observation(request: FromObservationRequest) -> FiniteSigmaAlgebra: | ||
| return sigma_algebra_from_observation(request.space, request.observation) | ||
|
|
||
|
|
||
| def compute_join(request: JoinRequest) -> FiniteSigmaAlgebra: | ||
| from jacobian.math.finite_stochastic_processes.operations import ( | ||
| sigma_algebra_join_correct, | ||
| ) | ||
| return sigma_algebra_join_correct(request.sigma1, request.sigma2) | ||
|
|
||
|
|
||
| def compute_conditional_expectation( | ||
| request: ConditionalExpectationRequest, | ||
| ) -> FiniteRandomVariable: | ||
| return conditional_expectation(request.rv, request.sigma) | ||
|
|
||
|
|
||
| def compute_filtration(request: FiltrationRequest) -> FiltrationResult: | ||
| sigmas = filtration_natural(request.space, request.observations) | ||
| return FiltrationResult( | ||
| sigmas=tuple( | ||
| {"blocks": s.blocks} for s in sigmas | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| def compute_doob_martingale( | ||
| request: DoobMartingaleRequest, | ||
| ) -> DoobMartingaleResult: | ||
| result = doob_martingale(request.space, request.observations, request.payoff) | ||
| return DoobMartingaleResult(martingale=result) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| """Finite stochastic process operation declarations.""" | ||
|
|
||
| from collections.abc import Callable | ||
| from typing import Any | ||
|
|
||
| from jacobian._models import StrictModel | ||
| from jacobian.catalog._examples import example | ||
| from jacobian.catalog.models import MathTool, OperationExample | ||
| from jacobian.math.finite_stochastic_processes._models import ( | ||
| ConditionalExpectationRequest, | ||
| DoobMartingaleRequest, | ||
| DoobMartingaleResult, | ||
| FiltrationRequest, | ||
| FiltrationResult, | ||
| FromObservationRequest, | ||
| JoinRequest, | ||
| ) | ||
| from jacobian.math.finite_stochastic_processes._operations import ( | ||
| compute_conditional_expectation, | ||
| compute_doob_martingale, | ||
| compute_filtration, | ||
| compute_join, | ||
| compute_sigma_from_observation, | ||
| ) | ||
| from jacobian.math.finite_stochastic_processes.values import ( | ||
| FiniteRandomVariable, | ||
| FiniteSigmaAlgebra, | ||
| ) | ||
|
|
||
|
|
||
| def _op[ | ||
| RequestT: StrictModel, | ||
| ResultT: StrictModel, | ||
| ]( | ||
| operation_id: str, | ||
| title: str, | ||
| description: str, | ||
| request_model: type[RequestT], | ||
| result_model: type[ResultT], | ||
| operation: Callable[[RequestT], ResultT], | ||
| *tags: str, | ||
| examples: tuple[OperationExample, ...] = (), | ||
| version: str = "1", | ||
| ) -> MathTool[RequestT, ResultT]: | ||
| return MathTool( | ||
| operation_id=operation_id, | ||
| version=version, | ||
| title=title, | ||
| description=description, | ||
| request_type=request_model, | ||
| result_type=result_model, | ||
| run=operation, | ||
| tags=tags, | ||
| examples=examples, | ||
| ) | ||
|
|
||
|
|
||
| # A fair coin: samples {H, T}, masses 1/2, 1/2. | ||
| _SPACE = {"samples": ["H", "T"], "masses": ["1/2", "1/2"]} | ||
|
|
||
| FINIT_STOCHASTIC_PROCESS_OPERATIONS: tuple[MathTool[Any, Any], ...] = ( | ||
| _op( | ||
| "probability.finite_sigma_algebra.from_observation.compute", | ||
| "Construct a sigma algebra from an observation map", | ||
| "Return the sigma algebra generated by an observation map Y: Omega -> " | ||
| "labels, whose blocks are equal-value fibers.", | ||
| FromObservationRequest, | ||
| FiniteSigmaAlgebra, | ||
| compute_sigma_from_observation, | ||
| "stochastic-process", | ||
| "sigma-algebra", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "coin_observation", | ||
| "Sigma algebra from observing a fair coin.", | ||
| {"space": _SPACE, "observation": ["heads", "tails"]}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "probability.finite_sigma_algebra.join.compute", | ||
| "Compute the join of two sigma algebras", | ||
| "Return the least sigma algebra containing both input sigma algebras. " | ||
| "Under the partition representation, this is the finest partition " | ||
| "that refines both input partitions.", | ||
| JoinRequest, | ||
| FiniteSigmaAlgebra, | ||
| compute_join, | ||
| "stochastic-process", | ||
| "sigma-algebra", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "trivial_join", | ||
| "Join of two trivial sigma algebras on a fair coin.", | ||
| { | ||
| "sigma1": {"space": _SPACE, "blocks": [["H", "T"]]}, | ||
| "sigma2": {"space": _SPACE, "blocks": [["H", "T"]]}, | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "probability.conditional_expectation.finite.compute", | ||
| "Compute E[X | G] as a block-constant random variable", | ||
| "Return the conditional expectation of a random variable with respect " | ||
| "to a finite sigma algebra. On each block, the value is the " | ||
| "probability-weighted average of X over the samples in that block.", | ||
| ConditionalExpectationRequest, | ||
| FiniteRandomVariable, | ||
| compute_conditional_expectation, | ||
| "stochastic-process", | ||
| "conditional-expectation", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "coin_conditional_expectation", | ||
| "Conditional expectation of a coin payoff on the trivial sigma algebra.", | ||
| { | ||
| "rv": {"space": _SPACE, "values": ["1", "0"]}, | ||
| "sigma": {"space": _SPACE, "blocks": [["H", "T"]]}, | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "probability.filtration.natural.compute", | ||
| "Compute the natural filtration of observations", | ||
| "Return the natural filtration F_t = sigma(Y_0, ..., Y_t) for each " | ||
| "time t. Each F_t is a finite sigma algebra, and F_t refines F_{t-1}.", | ||
| FiltrationRequest, | ||
| FiltrationResult, | ||
| compute_filtration, | ||
| "stochastic-process", | ||
| "filtration", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "single_step_filtration", | ||
| "Natural filtration of a single coin observation.", | ||
| {"space": _SPACE, "observations": [["heads", "tails"]]}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "probability.process.doob_martingale.compute", | ||
| "Compute the Doob martingale M_t = E[payoff | F_t]", | ||
| "Return the Doob martingale of a payoff random variable with respect " | ||
| "to the natural filtration of observations. The result is one tuple " | ||
| "of rational strings per time step.", | ||
| DoobMartingaleRequest, | ||
| DoobMartingaleResult, | ||
| compute_doob_martingale, | ||
| "stochastic-process", | ||
| "doob-martingale", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "coin_doob_martingale", | ||
| "Doob martingale of a coin payoff process.", | ||
| {"space": _SPACE, "observations": [["heads", "tails"]], "payoff": ["1", "0"]}, | ||
| ), | ||
| ), | ||
| ), | ||
| ) | ||
|
|
||
| TOOLS = FINIT_STOCHASTIC_PROCESS_OPERATIONS | ||
|
|
||
| __all__ = ["TOOLS"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 Import block ordering breaks
ruff checkdespite the claimed clean lintThe new imports for
finite_stochastic_processesare inserted beforefinite_state_transducers, but isort ordering putsfinite_state_...first (a<o). Runninguv run ruff check src/jacobian/catalog/builtins.pyon this branch reportsI001 Import block is un-sorted or un-formatted(1 error, fixable with--fix). The PR description claimsmake checklint is clean, so this would fail CI as-is.Was this helpful? React with 👍 or 👎 to provide feedback.