Skip to content

Commit 5e3a4a2

Browse files
committed
Refactor SDE integrators to use proper namespacing and enhance test clarity
- Updated integrator constructors to use the correct namespace (diffeq::) for consistency. - Improved test output formatting for better readability. - Added diffusion derivative functions for Milstein integrators in tests to clarify their implementation.
1 parent 85dcbac commit 5e3a4a2

File tree

2 files changed

+51
-27
lines changed

2 files changed

+51
-27
lines changed

test/integration/test_sde_integration.cpp

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ void test_sde_infrastructure() {
9393
double expected_std = std::sqrt(0.01);
9494
assert(std::abs(dW[0]) < 5 * expected_std); // 5-sigma test
9595

96-
std::cout << " �SDE problem and Wiener process creation\n";
97-
std::cout << " �Noise generation (dW[0] = " << dW[0] << ")\n";
96+
std::cout << " ?SDE problem and Wiener process creation\n";
97+
std::cout << " ?Noise generation (dW[0] = " << dW[0] << ")\n";
9898
}
9999

100100
void test_euler_maruyama() {
@@ -105,7 +105,7 @@ void test_euler_maruyama() {
105105
test_problems::gbm_drift, test_problems::gbm_diffusion);
106106
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 42);
107107

108-
EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
108+
diffeq::EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
109109

110110
// Test integration
111111
std::vector<double> state = {100.0}; // Initial stock price
@@ -120,9 +120,9 @@ void test_euler_maruyama() {
120120
// Result should be reasonable (not too far from initial value for small T)
121121
assert(state[0] > 50.0 && state[0] < 200.0);
122122

123-
std::cout << " �GBM integration: S(0) = 100.0 �S(" << T << ") = "
123+
std::cout << " ?GBM integration: S(0) = 100.0 ?S(" << T << ") = "
124124
<< std::fixed << std::setprecision(2) << state[0] << "\n";
125-
std::cout << " �Method: " << integrator.name() << "\n";
125+
std::cout << " ?Method: " << integrator.name() << "\n";
126126
}
127127

128128
void test_milstein_method() {
@@ -132,7 +132,13 @@ void test_milstein_method() {
132132
test_problems::gbm_drift, test_problems::gbm_diffusion);
133133
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 123);
134134

135-
MilsteinIntegrator<std::vector<double>, double> integrator(problem, wiener);
135+
// For GBM g(t, S) = σ * S, so g'(t, S) = σ
136+
auto diffusion_derivative = [](double t, const std::vector<double>& x, std::vector<double>& dgx) {
137+
double sigma = 0.2; // Same as in gbm_diffusion
138+
dgx[0] = sigma;
139+
};
140+
141+
diffeq::MilsteinIntegrator<std::vector<double>> integrator(problem, diffusion_derivative, wiener);
136142

137143
std::vector<double> state = {100.0};
138144
double dt = 0.001;
@@ -143,9 +149,9 @@ void test_milstein_method() {
143149
assert(state[0] > 0);
144150
assert(state[0] > 50.0 && state[0] < 200.0);
145151

146-
std::cout << " �GBM integration: S(0) = 100.0 �S(" << T << ") = "
152+
std::cout << " ?GBM integration: S(0) = 100.0 ?S(" << T << ") = "
147153
<< std::fixed << std::setprecision(2) << state[0] << "\n";
148-
std::cout << " �Method: " << integrator.name() << "\n";
154+
std::cout << " ?Method: " << integrator.name() << "\n";
149155
}
150156

151157
void test_sri1_method() {
@@ -155,7 +161,7 @@ void test_sri1_method() {
155161
test_problems::ou_drift, test_problems::ou_diffusion);
156162
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 456);
157163

158-
SRI1Integrator<std::vector<double>, double> integrator(problem, wiener);
164+
diffeq::SRI1Integrator<std::vector<double>> integrator(problem, wiener);
159165

160166
std::vector<double> state = {1.0}; // Initial value
161167
double dt = 0.001;
@@ -166,9 +172,9 @@ void test_sri1_method() {
166172
// OU process should be bounded and tend toward mean
167173
assert(std::abs(state[0]) < 5.0); // Reasonable bounds
168174

169-
std::cout << " �OU process integration: X(0) = 1.0 �X(" << T << ") = "
175+
std::cout << " ?OU process integration: X(0) = 1.0 ?X(" << T << ") = "
170176
<< std::fixed << std::setprecision(3) << state[0] << "\n";
171-
std::cout << " �Method: " << integrator.name() << "\n";
177+
std::cout << " ?Method: " << integrator.name() << "\n";
172178
}
173179

174180
void test_implicit_euler_maruyama() {
@@ -178,7 +184,7 @@ void test_implicit_euler_maruyama() {
178184
test_problems::ou_drift, test_problems::ou_diffusion);
179185
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 789);
180186

181-
ImplicitEulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
187+
diffeq::ImplicitEulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
182188

183189
std::vector<double> state = {2.0};
184190
double dt = 0.01; // Larger time step to test stability
@@ -188,9 +194,9 @@ void test_implicit_euler_maruyama() {
188194

189195
assert(std::abs(state[0]) < 5.0);
190196

191-
std::cout << " �OU process integration: X(0) = 2.0 �X(" << T << ") = "
197+
std::cout << " ?OU process integration: X(0) = 2.0 ?X(" << T << ") = "
192198
<< std::fixed << std::setprecision(3) << state[0] << "\n";
193-
std::cout << " �Method: " << integrator.name() << "\n";
199+
std::cout << " ?Method: " << integrator.name() << "\n";
194200
}
195201

196202
void test_multidimensional_sde() {
@@ -200,7 +206,7 @@ void test_multidimensional_sde() {
200206
test_problems::multi_drift, test_problems::multi_diffusion);
201207
auto wiener = factory::make_wiener_process<std::vector<double>>(2, 999);
202208

203-
EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
209+
diffeq::EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
204210

205211
std::vector<double> state = {1.0, 1.0}; // Initial values
206212
double dt = 0.001;
@@ -212,7 +218,7 @@ void test_multidimensional_sde() {
212218
assert(state[0] > 0 && state[0] < 10.0);
213219
assert(state[1] > 0 && state[1] < 10.0);
214220

215-
std::cout << " �2D system: [1.0, 1.0] �["
221+
std::cout << " ?2D system: [1.0, 1.0] ?["
216222
<< std::fixed << std::setprecision(3) << state[0] << ", " << state[1] << "]\n";
217223
}
218224

@@ -225,12 +231,12 @@ void test_noise_types() {
225231
test_problems::multi_drift, test_problems::multi_diffusion, NoiseType::SCALAR_NOISE);
226232
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 111);
227233

228-
EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
234+
diffeq::EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
229235

230236
std::vector<double> state = {1.0, 1.0};
231237
integrator.integrate(state, 0.001, 0.05);
232238

233-
std::cout << " �Scalar noise: [1.0, 1.0] �["
239+
std::cout << " ?Scalar noise: [1.0, 1.0] ?["
234240
<< std::fixed << std::setprecision(3) << state[0] << ", " << state[1] << "]\n";
235241
}
236242

@@ -240,12 +246,18 @@ void test_noise_types() {
240246
test_problems::multi_drift, test_problems::multi_diffusion, NoiseType::DIAGONAL_NOISE);
241247
auto wiener = factory::make_wiener_process<std::vector<double>>(2, 222);
242248

243-
MilsteinIntegrator<std::vector<double>, double> integrator(problem, wiener);
249+
// For multi_diffusion g(t, x) = [0.2*x[0], 0.15*x[1]], so g'(t, x) = [0.2, 0.15]
250+
auto diffusion_derivative = [](double t, const std::vector<double>& x, std::vector<double>& dgx) {
251+
dgx[0] = 0.2; // Derivative of 0.2*x[0] w.r.t. x[0]
252+
dgx[1] = 0.15; // Derivative of 0.15*x[1] w.r.t. x[1]
253+
};
254+
255+
diffeq::MilsteinIntegrator<std::vector<double>> integrator(problem, diffusion_derivative, wiener);
244256

245257
std::vector<double> state = {1.0, 1.0};
246258
integrator.integrate(state, 0.001, 0.05);
247259

248-
std::cout << " �Diagonal noise: [1.0, 1.0] �["
260+
std::cout << " ?Diagonal noise: [1.0, 1.0] ?["
249261
<< std::fixed << std::setprecision(3) << state[0] << ", " << state[1] << "]\n";
250262
}
251263
}
@@ -267,8 +279,15 @@ void test_convergence_properties() {
267279
auto wiener_em = factory::make_wiener_process<std::vector<double>>(1, 42);
268280
auto wiener_mil = factory::make_wiener_process<std::vector<double>>(1, 42);
269281

270-
EulerMaruyamaIntegrator<std::vector<double>> em_integrator(problem, wiener_em);
271-
MilsteinIntegrator<std::vector<double>, double> mil_integrator(problem, wiener_mil);
282+
diffeq::EulerMaruyamaIntegrator<std::vector<double>> em_integrator(problem, wiener_em);
283+
284+
// For GBM g(t, S) = σ * S, so g'(t, S) = σ
285+
auto diffusion_derivative = [](double t, const std::vector<double>& x, std::vector<double>& dgx) {
286+
double sigma = 0.2; // Same as in gbm_diffusion
287+
dgx[0] = sigma;
288+
};
289+
290+
diffeq::MilsteinIntegrator<std::vector<double>> mil_integrator(problem, diffusion_derivative, wiener_mil);
272291

273292
std::vector<double> state_em = {100.0};
274293
std::vector<double> state_mil = {100.0};
@@ -282,8 +301,8 @@ void test_convergence_properties() {
282301
errors_milstein.push_back(std::abs(state_mil[0] - 100.0));
283302
}
284303

285-
std::cout << " �Convergence test completed for dt values: 0.01, 0.005, 0.0025\n";
286-
std::cout << " �Both methods show expected convergence behavior\n";
304+
std::cout << " ?Convergence test completed for dt values: 0.01, 0.005, 0.0025\n";
305+
std::cout << " ?Both methods show expected convergence behavior\n";
287306
}
288307

289308
void test_step_by_step_integration() {
@@ -293,7 +312,7 @@ void test_step_by_step_integration() {
293312
test_problems::gbm_drift, test_problems::gbm_diffusion);
294313
auto wiener = factory::make_wiener_process<std::vector<double>>(1, 314);
295314

296-
EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
315+
diffeq::EulerMaruyamaIntegrator<std::vector<double>> integrator(problem, wiener);
297316

298317
std::vector<double> state = {100.0};
299318
double dt = 0.01;
@@ -308,7 +327,7 @@ void test_step_by_step_integration() {
308327
}
309328

310329
assert(state[0] > 0);
311-
std::cout << " �Step-by-step integration maintains positivity\n";
330+
std::cout << " ?Step-by-step integration maintains positivity\n";
312331
}
313332

314333
int main() {

test/integration/test_sde_solvers.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,12 @@ void test_basic_sde_solvers() {
125125

126126
// Test Milstein
127127
{
128-
diffeq::MilsteinIntegrator<std::vector<double>> integrator(problem, wiener);
128+
// For Geometric Brownian Motion g(t, S) = σ * S, so g'(t, S) = σ
129+
auto diffusion_derivative = [&gbm](double t, const std::vector<double>& S, std::vector<double>& dgS) {
130+
dgS[0] = gbm.sigma; // Derivative of σ * S with respect to S is σ
131+
};
132+
133+
diffeq::MilsteinIntegrator<std::vector<double>> integrator(problem, diffusion_derivative, wiener);
129134
std::vector<double> S = {100.0};
130135

131136
double dt = 0.01;

0 commit comments

Comments
 (0)