Skip to content

Commit 7ab0ddc

Browse files
committed
feat: manager config and small tweaks
1 parent 1cc8b95 commit 7ab0ddc

4 files changed

Lines changed: 42 additions & 74 deletions

File tree

include/lfmc/Estimator.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class EstimatorInterface {
2626
virtual Path generatePath(std::span<const double> randomNormals) = 0;
2727
};
2828

29-
template <StochasticProcess P, NumericalScheme<P> S, RandomGenerator RNG = PseudoRandom>
29+
template <StochasticProcess P = GeometricBrownianMotion, NumericalScheme<P> S = EulerMaruyama<P>,
30+
RandomGenerator RNG = PseudoRandom>
3031
class Estimator : public EstimatorInterface {
3132
private:
3233
P process_;
@@ -36,10 +37,10 @@ class Estimator : public EstimatorInterface {
3637
PathGenerator<P, S> pathGenerator_;
3738

3839
public:
39-
Estimator(P process, S scheme, RNG rng, State state)
40+
explicit Estimator(P process, S scheme, State state, RNG randomGenerator)
4041
: process_(std::move(process)), scheme_(std::move(scheme)), state_(state),
41-
randomGenerator_(std::move(rng)), pathGenerator_(process_, scheme_, state_) {}
42-
Estimator(P process, S scheme, State state)
42+
pathGenerator_(process_, scheme_, state_), randomGenerator_(std::move(randomGenerator)) {}
43+
explicit Estimator(P process, S scheme, State state)
4344
: process_(std::move(process)), scheme_(std::move(scheme)), state_(state),
4445
randomGenerator_(), pathGenerator_(process_, scheme_, state_) {}
4546

include/lfmc/Manager.hpp

Lines changed: 25 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
namespace lfmc {
2121

22-
template <StochasticProcess P, NumericalScheme<P> S, Payoff PO, RandomGenerator RNG = PseudoRandom>
22+
template <StochasticProcess P = GeometricBrownianMotion, NumericalScheme<P> S = EulerMaruyama<P>,
23+
RandomGenerator RNG = PseudoRandom, Payoff PO = EuropeanCall>
2324
class Manager {
2425
private:
2526
P process_;
@@ -31,59 +32,26 @@ class Manager {
3132
std::vector<std::unique_ptr<EstimatorInterface>> simulators_;
3233

3334
public:
34-
explicit Manager(P process, S scheme, PO payoff, RNG randomGenerator, State state) noexcept
35+
explicit Manager(P process, S scheme, PO payoff, State state, RNG randomGenerator) noexcept
3536
: process_(std::move(process)), scheme_(std::move(scheme)), payoff_(std::move(payoff)),
36-
randomGenerator_(std::move(randomGenerator)), state_(state) {}
37+
state_(state), randomGenerator_(std::move(randomGenerator)) {}
3738
explicit Manager(P process, S scheme, PO payoff, State state) noexcept
3839
: process_(std::move(process)), scheme_(std::move(scheme)), payoff_(std::move(payoff)),
39-
randomGenerator_(), state_(state) {}
40+
state_(state), randomGenerator_() {}
4041

41-
// TODO better way to do this without passing in all the same parameters to each
42-
// simulator?
43-
// Maybe a factory pattern or something? Or maybe pass in a config struct?
44-
double simulate(size_t numSimulations = 1000) {
45-
simulators_.clear();
46-
simulators_.reserve(numSimulations);
42+
// TODO better configuration for number of simulations
43+
double simulate(const ManagerConfig& config) {
44+
size_t numSimulations =
45+
config.numNoVarianceReductionSimulations + config.numAntitheticVariatesSimulations;
4746

4847
// Create simulators
49-
for (size_t i{}; i < numSimulations; ++i) {
48+
for (size_t i{}; i < config.numNoVarianceReductionSimulations; ++i) {
5049
simulators_.push_back(
51-
std::make_unique<Estimator<P, S>>(process_, scheme_, payoff_, state_));
50+
std::make_unique<Estimator<P, S, RNG>>(process_, scheme_, state_));
5251
}
53-
54-
// Run simulations
55-
std::vector<Path> results;
56-
results.reserve(numSimulations);
57-
for (auto& simulator : simulators_) {
58-
std::vector<Path> paths = simulator->sample();
59-
for (const auto& path : paths) {
60-
results.push_back(path);
61-
}
62-
}
63-
64-
// Payoffs
65-
std::vector<double> payoffs;
66-
payoffs.reserve(results.size());
67-
for (const auto& path : results) {
68-
payoffs.push_back(payoff_(path));
69-
}
70-
71-
double mean = std::accumulate(payoffs.begin(), payoffs.end(), 0.0) /
72-
static_cast<double>(numSimulations);
73-
74-
return mean;
75-
}
76-
77-
// TODO temporary simulate with antithetic variates for now, but will need to be redesigned to
78-
// support more variance reduction techniques and passing changing a simulator's type
79-
std::pair<double, double> simulateWithAntithetic(size_t numSimulations = 1000) {
80-
simulators_.clear();
81-
simulators_.reserve(numSimulations);
82-
83-
// Create simulators with antithetic variates
84-
for (size_t i{}; i < numSimulations; ++i) {
52+
for (size_t i{}; i < config.numAntitheticVariatesSimulations; ++i) {
8553
simulators_.push_back(std::make_unique<AntitheticVariates>(
86-
std::make_unique<Estimator<P, S>>(process_, scheme_, state_)));
54+
std::make_unique<Estimator<P, S, RNG>>(process_, scheme_, state_)));
8755
}
8856

8957
// Run simulations
@@ -103,29 +71,24 @@ class Manager {
10371
payoffs.push_back(payoff_(path));
10472
}
10573

106-
// Calculate mean and standard error
10774
double mean = std::accumulate(payoffs.begin(), payoffs.end(), 0.0) /
108-
static_cast<double>(payoffs.size());
109-
110-
if (results.size() < 2)
111-
return {mean, 0.0};
112-
113-
double variance = 0.0;
114-
for (const auto& r : payoffs)
115-
variance += (r - mean) * (r - mean);
116-
variance /= static_cast<double>(results.size() - 1);
117-
double stdError = std::sqrt(variance / static_cast<double>(results.size()));
75+
static_cast<double>(numSimulations);
11876

119-
return {mean, stdError};
77+
return mean;
12078
}
12179

122-
std::pair<double, double> simulateWithError(size_t numSimulations = 1000) {
123-
simulators_.clear();
124-
simulators_.reserve(numSimulations);
80+
std::pair<double, double> simulateWithError(const ManagerConfig& config) {
81+
size_t numSimulations =
82+
config.numNoVarianceReductionSimulations + config.numAntitheticVariatesSimulations;
12583

12684
// Create simulators
127-
for (size_t i{}; i < numSimulations; ++i) {
128-
simulators_.push_back(std::make_unique<Estimator<P, S>>(process_, scheme_, state_));
85+
for (size_t i{}; i < config.numNoVarianceReductionSimulations; ++i) {
86+
simulators_.push_back(
87+
std::make_unique<Estimator<P, S, RNG>>(process_, scheme_, state_));
88+
}
89+
for (size_t i{}; i < config.numAntitheticVariatesSimulations; ++i) {
90+
simulators_.push_back(std::make_unique<AntitheticVariates>(
91+
std::make_unique<Estimator<P, S, RNG>>(process_, scheme_, state_)));
12992
}
13093

13194
// Run simulations

include/lfmc/types.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ struct State {
1313
using Path = std::vector<double>;
1414
using Normals = std::vector<double>;
1515

16+
struct ManagerConfig {
17+
// TODO temp
18+
size_t numNoVarianceReductionSimulations;
19+
size_t numAntitheticVariatesSimulations;
20+
};
21+
1622
} // namespace lfmc

tests/test_manager.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@ TEST_CASE("Full Monte Carlo tests ", "[Manager]") {
2626
lfmc::EulerMaruyama<lfmc::GeometricBrownianMotion> euler;
2727
lfmc::EuropeanCall call(K);
2828
lfmc::State state{S0, T, nSteps};
29+
lfmc::ManagerConfig config{1000, 0};
2930

3031
// Create manager
31-
lfmc::Manager<lfmc::GeometricBrownianMotion,
32-
lfmc::EulerMaruyama<lfmc::GeometricBrownianMotion>, lfmc::EuropeanCall>
33-
manager(gbm, euler, call, state);
32+
lfmc::Manager<> manager(gbm, euler, call, state);
3433

3534
// Run sims
36-
auto [mcPrice, stdError] = manager.simulateWithError();
35+
auto [mcPrice, stdError] = manager.simulateWithError(config);
3736

3837
// Discount to present value
3938
double discountedPrice = mcPrice * std::exp(-r * T);
@@ -69,14 +68,13 @@ TEST_CASE("Full Monte Carlo tests ", "[Manager]") {
6968
lfmc::EulerMaruyama<lfmc::GeometricBrownianMotion> euler;
7069
lfmc::EuropeanCall call(K);
7170
lfmc::State state{S0, T, nSteps};
71+
lfmc::ManagerConfig config{0, 1000};
7272

7373
// Create manager with antithetic variates
74-
lfmc::Manager<lfmc::GeometricBrownianMotion,
75-
lfmc::EulerMaruyama<lfmc::GeometricBrownianMotion>, lfmc::EuropeanCall>
76-
manager(gbm, euler, call, state);
74+
lfmc::Manager<> manager(gbm, euler, call, state);
7775

7876
// Run sims with antithetic variates
79-
auto [mcPrice, stdError] = manager.simulateWithAntithetic();
77+
auto [mcPrice, stdError] = manager.simulateWithError(config);
8078

8179
// Discount to present value
8280
double discountedPrice = mcPrice * std::exp(-r * T);

0 commit comments

Comments
 (0)