1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! One-factor affine short-rate models.
//!
//! Port of the closed-form parts of `ql/models/shortrate/onefactormodel.hpp`:
//! the affine `discountBond` payoff. A single-factor affine model prices a
//! zero-coupon bond in closed form as
//! `P(t, T, r_t) = A(t,T) e^{-B(t,T) r_t}` (`onefactormodel.hpp:136`), with
//! `A` and `B` supplied by the concrete model (Vasicek in #378).
//!
//! ## Trait surface (deferral by omission)
//!
//! Rust controls the trait surface, so the deferred machinery is omitted rather
//! than stubbed to a panic. The only affine method here is
//! [`discount_bond`](OneFactorAffineModel::discount_bond) plus the factor
//! overload; three C++ pure-virtuals are intentionally absent:
//!
//! - `AffineModel::discount(Time)` (`onefactormodel.cpp:97`) routes through the
//! deferred `ShortRateDynamics`; `discountBond` takes an explicit rate and
//! does not call it, and the #378 oracle calls `discountBond` directly.
//! - `AffineModel::discountBondOption` (`model.hpp:54`) is left pure-virtual by
//! `OneFactorAffineModel` in C++ and needs the cumulative normal.
//! - `ShortRateModel::tree(const TimeGrid&)` (`model.hpp:144`) is the numerical
//! lattice path.
//!
//! ## Collapsed intermediates
//!
//! C++'s `ShortRateModel` (`model.hpp:141`) and `OneFactorModel`
//! (`onefactormodel.hpp:38`) sit between `CalibratedModel` and this trait. Each
//! adds only a constructor forwarding the argument count (subsumed by
//! [`CalibratedModel::new`](crate::models::CalibratedModel::new)) plus deferred
//! virtuals: `ShortRateModel` adds `tree()`; `OneFactorModel` adds `dynamics()`
//! and its `tree()` implementation, both numerical-tree machinery. With their
//! only non-deferred content subsumed, they carry no Rust surface this slice; a
//! concrete affine model embeds a `CalibratedModel` and implements
//! [`OneFactorAffineModel`] directly.
use crateArray;
use crate;
/// Analytically tractable model (`ql/models/model.hpp:45`), reduced to its one
/// non-deferred method: the zero-coupon bond price as a function of the state
/// factors.
/// Single-factor affine base (`onefactormodel.hpp:126`).
///
/// A concrete model supplies `A(t,T)` and `B(t,T)`; the closed-form
/// [`discount_bond`](Self::discount_bond) and, through the [`AffineModel`]
/// blanket impl, the factor overload follow.
///
/// C++'s `A`/`B` are distinct from a model's scalar parameter inspectors
/// `a()`/`b()` only by case; lowercased in Rust they share a name. The two
/// coexist on a concrete model (the inherent 0-argument inspector wins
/// method-syntax resolution, and [`discount_bond`](Self::discount_bond)
/// resolves against the trait bound), but where a model's [`a`](Self::a)
/// cross-references its [`b`](Self::b) it must qualify the call as
/// `OneFactorAffineModel::b(self, t, maturity)`.
/// `OneFactorAffineModel::discountBond(Array)` (`onefactormodel.hpp:132`)
/// delegates to the rate overload on the first factor.