-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
127 lines (105 loc) · 3.93 KB
/
main.cpp
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
116
117
118
119
120
121
122
123
124
125
126
127
#include <mpi.h>
#include <iostream>
#include <random>
#include "gnuplot.h"
// Settings for the sampler
#define STARTING_SAMPLE -1.0
#define LOWLIMU 0.0
#define UPPLIMU 1.0
#define COUPLING true
#define COUPLING_INTERVAL 100
#define PROPOSALS 100000
#define WALKSTEP0 0.5
#define WALKSTEP1 0.05
// Target function
double doubleWell(double x, double gamma = 4) {
return gamma * (x * x - 1) * (x * x - 1);
}
int main() {
// MPI initialization
MPI_Init(NULL, NULL);
int world_size, world_rank;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
// RNG's for proposal and acceptance rule
std::random_device rd;
std::mt19937 gen(rd());
std::normal_distribution<double> nDis(0.0, (world_rank == 0 ? WALKSTEP0 : WALKSTEP1));
std::uniform_real_distribution<double> uDis(LOWLIMU, UPPLIMU);
// Variables for sampling
unsigned long nproposals = PROPOSALS;
double current;
double proposal;
double currentX;
double proposalX;
int accepted = 0;
int acceptedSwitches = COUPLING ? 0 : int();
// Storage objects
std::vector<double> samples(nproposals);
std::vector<double> misfits(nproposals);
// Startings sample
samples[0] = STARTING_SAMPLE;
// Well function
int gamma = (world_rank == 0) ? 1 : 30;
currentX = doubleWell(samples[0], gamma);
for (int i = 1; i < nproposals; i++) {
// Random walk update
current = samples[i - 1];
proposal = current + nDis(gen);
proposalX = doubleWell(proposal, gamma);
double exponentWalk = exp((currentX - proposalX));
if (exponentWalk > uDis(gen)) {
samples[i] = proposal;
misfits[i] = proposalX;
current = proposal;
currentX = proposalX;
accepted++;
} else {
samples[i] = current;
misfits[i] = currentX;
}
if (COUPLING and i % COUPLING_INTERVAL == 0) {
// Coupling update
i++;
double incoming;
double gamma1 = 1 * 20 + 1;
if (world_rank == 0) {
MPI_Recv(&incoming, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
double exponentCoupling = exp(doubleWell(current, gamma) + doubleWell(incoming, gamma1)
- doubleWell(incoming, gamma) - doubleWell(current, gamma1));
if (exponentCoupling > uDis(gen)) {
acceptedSwitches++;
// Replica exchange accepted
// Send own replica back, update current to incoming
MPI_Send(¤t, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
current = incoming;
currentX = doubleWell(current, gamma);
} else {
// Replica exchange rejected
// Send original back, don't update current sample.
MPI_Send(&incoming, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
}
samples[i] = current;
misfits[i] = currentX;
} else {
MPI_Send(&samples[i - 1], 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
MPI_Recv(¤t, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
samples[i] = current;
currentX = doubleWell(current, gamma);
misfits[i] = currentX;
}
MPI_Barrier(MPI_COMM_WORLD);
}
}
std::cout << "Chain " << world_rank << ": " << accepted << std::endl;
if (COUPLING and world_rank == 0) std::cout << "Accepted switches: " << acceptedSwitches << std::endl;
char samplesFilename[50];
sprintf(samplesFilename, "samples%d.dat", world_rank);
std::ofstream ofs(samplesFilename, std::ofstream::out);
for (int i = 0; i < nproposals; ++i) {
ofs << samples[i] << "\n";
}
ofs.close();
MPI_Finalize();
return 0;
}