-
Notifications
You must be signed in to change notification settings - Fork 0
/
CPlusPlusCode.cpp
342 lines (329 loc) · 13.4 KB
/
CPlusPlusCode.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
// optimisation algorithm to find the shortest distance to travel to the top 100 most populous places in the UK
//streams imported
#include <iostream>
#include <fstream>
#include <iomanip>
#include <time.h>
#include <cmath>
#include <vector>
#include <string>
#define PI atan(1)*4
/*Improvements made:
-weighted and non weighted distances, by population, found
-the total distance found for both, and the extra distance travelled is found (when considering population)
-the nearest city to the weighted and non weighted co ordinates is identified
*/
//using namespace shortcut
using namespace std;
//define functions
//random number generator
double random_number(double upper, double lower, int n) {
double r;
r = lower + (rand() % (n + 1) * (1. / n) * (upper - lower));
return r;
}
//distance calculator
double distance_calculator(double long1, double lat1, double x, double y, double w) {
double dLat = (y * (PI / 180)) - (lat1 * (PI / 180));
double dLong = (x * (PI / 180)) - (long1 * (PI / 180));
double length_1 = pow(sin(dLat / 2), 2) + (cos(x * (PI / 180))*cos(long1 * (PI / 180))*pow(sin(dLong / 2), 2));
double length_2 = 2 * atan2(sqrt(length_1), sqrt(1 - length_1));
double final_step = 3958.75*length_2*(w);
return final_step;
}
//main program starts here
int main() {
//***********************Section 1: File is opened, read from and closed here************************************************************
// declare variables to be used in splitting the data csv file, separated by columns and commas, into a vector
string line;
string xtemp, ytemp;
int comma;
int commaNew;
int commaOld;
//creates a vector data structure to store the data
vector<vector<double> > data;
// opens up the file and reads in the data
ifstream dataFile("GBPlaces.csv");
// if file has been opened, then a message is printed telling user it opened successfully
if (dataFile.is_open()) {
cout << "File has been opened successfully! Please wait...\n";
// while the final line in the file has not been reached while reading it
while (!dataFile.eof()) {
// data in text file is read in line by line
getline(dataFile, line);
if (line.find("%", 0) == -1){
//ensures there's data in the line
if (line.length() > 0){
//using a temporary vector to hold the data
vector <double> temp;
//sets a counter so initial value for comma is 0
comma = 0;
commaNew = 0;
//finds last comma in the line of the file concerned
commaOld = line.find_last_of(",");
//have the vector hold all commas and values
while (commaNew != commaOld) {
// the items between the commas are extracted
commaNew = line.find(",", comma);
xtemp = line.substr(comma, commaNew - comma);
comma = commaNew + 1;
// these items are pushed onto the temp vector
temp.push_back(atof(xtemp.c_str()));
}
// obtains the final item after the comma
xtemp = line.substr(commaOld + 1, line.length() - commaOld - 1);
// this final value for each line is added back onto the temp vector
temp.push_back(atof(xtemp.c_str()));
//pushes all values into the data structure vector
data.push_back(temp);
}
}
}
// closes file
dataFile.close();
}
//separate vector created holding the string values for the list of places
vector<vector<string> > places;
// opens up the file and reads in the data
ifstream placesFile("GBPlaces.csv");
// if file is opeend, a message is printed
if (placesFile.is_open()) {
while (!placesFile.eof()) {
getline(placesFile, line);
if (line.find("%", 0) == -1){
vector <string> temp2;
//ensures there's data in the line
if (line.length() > 0){
//using a temporary vector to hold the data
commaOld = line.find(",", 0);
xtemp = line.substr(0, commaOld);
temp2.push_back(xtemp.c_str());
}
xtemp = line.substr(0, ',');
temp2.push_back(xtemp.c_str());
//pushes all values into the data structure vector
places.push_back(temp2);
}
}
// closes file
placesFile.close();
}
else {
// error message printed if file unable to open
cout << "Unable to open file\n";
exit(1);
}
//maximum and minimum values for latitude and longitude in the data structure are searched for to be used later when calculating a random number in the range
double max_latitude = 0;
for (int i = 0; i < data.size(); i++){
if (data[i][3] > max_latitude){
max_latitude = data[i][3];
}
}
double max_longitude = 0;
for (int i = 0; i < data.size(); i++){
if (data[i][4] > max_longitude){
max_longitude = data[i][4];
}
}
double min_longitude = 0;
for (int i = 0; i < data.size(); i++){
if (data[i][4] < min_longitude){
min_longitude = data[i][4];
}
}
double min_latitude = 0;
for (int i = 0; i < data.size(); i++){
if (data[i][3] < min_latitude){
min_latitude = data[i][3];
}
}
//*****************************Section 2: Random point found, co ordinates and total distance found after optimisation (neglecting population size)*************************************************************************
// declare variables to be used in finding the optimised location, in both cases (non weighted and weighted)
double x, y;
double glx, gly;
double glx_w, gly_w;
int dx, dy;
int dx_w, dy_w;
double step = 0.01;
double value, newValue, oldValue;
double value_w, newValue_w, oldValue_w;
double globalMin = 1000000000;
double globalMin_w = 1000000000;
double distance;
double distance_w;
srand(time(NULL));
//starts evaluations/iterations at 0
int fevals = 0;
// random starting point for x (longitude) and y (latitude) picked within range of dataset
for (int k = 0; k < 50; k++) {
x = random_number(max_longitude, min_longitude, 100);
y = random_number(max_latitude, min_latitude, 100);
distance = 0;
// Haversine formula used to find distances between places for this random value of x and y
for (int i = 0; i < data.size(); i++){
double longitude = data[i][4];
double latitude = data[i][3];
double x_rand = x;
double y_rand = y;
double weight = 1;
value = distance_calculator(longitude, latitude, x_rand, y_rand, weight);
distance += value;
}
do {
// this bit looks around the current point to see if the sum of all distances is lower
oldValue = distance;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) {
}
else {
newValue = 0;
for (int l = 0; l < data.size(); l++){
double longitude = data[l][4];
double latitude = data[l][3];
double x_rand = x;
double y_rand = y;
double weight = 1;
newValue += distance_calculator(longitude, latitude, x + step * i, y + step * j, weight);
}
if (newValue <= distance) {
dx = i;
dy = j;
distance = newValue;
}
}
}
}
// updates values for x and y to this new position
x += step * dx;
y += step * dy;
//adds one to the evaulations/iterations counter
fevals++;
} while (distance < oldValue);
//global minimum found which is the smallest distance available
if (distance < globalMin) {
globalMin = distance;
glx = x;
gly = y;
}
//************************Section 3: Random point found, co ordinates and total distance found after optimisation acknowledging population size*************************************************************************
distance_w = 0;
// Haversine formula used to find distances between places for this random value of x and y, but now the weight of each value depends on population
for (int i = 0; i < data.size(); i++){
double longitude = data[i][4];
double latitude = data[i][3];
double x_rand = x;
double y_rand = y;
double weight = 1 / data[i][2];
value_w = distance_calculator(longitude, latitude, x_rand, y_rand, weight);
distance_w += value_w;
}
do {
// looks around current value to see if the total distance to all the other places is decreased
oldValue_w = distance_w;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) {
}
else {
newValue_w = 0;
for (int l = 0; l < data.size(); l++){
double longitude = data[l][4];
double latitude = data[l][3];
double x_rand = x;
double y_rand = y;
double weight = 1 / data[l][2];
newValue_w += distance_calculator(longitude, latitude, x + step * i, y + step * j, weight);
}
if (newValue_w <= distance_w) {
dx_w = i;
dy_w = j;
distance_w = newValue_w;
}
}
}
}
// updates values of positions for these new co ordinates
x += step * dx_w;
y += step * dy_w;
} while (distance_w < oldValue_w);
if (distance_w < globalMin_w) {
globalMin_w = distance_w;
glx_w = x;
gly_w = y;
}
globalMin_w = 0;
//calculates total distance using these new weighted co ordinates
for (int i = 0; i < data.size(); i++){
double longitude = data[i][4];
double latitude = data[i][3];
double x = glx_w;
double y = gly_w;
double weight = 1;
value_w = distance_calculator(longitude, latitude, x, y, weight);
globalMin_w += value_w;
}
//prints the co ordinates for weighted and non weighted values for each iteration
cout << "Evaluations: " << fevals << ". Original: " << gly << "," << glx << ". Weighted: " << gly_w << "," << glx_w << endl;
}
//***************Section 4: Finds the nearest location to these set of global co ordinate values, for weighted and non weighted***************************************************************************************
//distance calculator used to find the distance for the non weighted co ordinates to all other places
double closestDistance;
//vector generated to hold the values for the distances from the co ordinates to other locations
vector<double>closestPositionDistance;
for (int i = 0; i < data.size(); i++){
double longitude = data[i][4];
double latitude = data[i][3];
double x = glx;
double y = gly;
double weight = 1;
closestDistance = distance_calculator(longitude, latitude, x, y, weight);
closestPositionDistance.push_back(closestDistance);
}
//index of the element in the list with the smallest distance identified, to be used in finding the nearest city/town later
int closestPosition = 0;
for (int i = 0; i < data.size(); ++i)
{
if (closestPositionDistance[i] < closestPositionDistance[closestPosition])
closestPosition = i;
}
//distance calculator used to find distance for the weighted co ordinates to all other places
double closestDistance_w;
//vector generated to hold the values for weighted distances from the co ordianates to the other locations
vector<double>closestPositionDistance_w;
for (int i = 0; i < data.size(); i++){
double longitude = data[i][4];
double latitude = data[i][3];
double x = glx_w;
double y = gly_w;
double weight = 1;
closestDistance_w = distance_calculator(longitude, latitude, x, y, weight);
closestPositionDistance_w.push_back(closestDistance_w);
}
//index of the element in the list with the smallest weighted distance identified, to be used in finding the nearest city/town later
int closestPosition_w = 0;
for (int i = 0; i < data.size(); ++i)
{
if (closestPositionDistance_w[i] < closestPositionDistance_w[closestPosition_w]) // Found a smaller min
closestPosition_w = i;
}
//************************************Section 5: Distances and differences calculated******************************************************************************************
//calculates difference between the two global minima for weighted and non weighted distances
double distance_difference = globalMin_w - globalMin;
//calculates total distance for the non weighted and weighted global minima (taking into account the fact that each distance needs to be travelled twice- i.e. to and from the global co ordinates to each city)
double total_distance = 2 * globalMin;
double total_distance_w = 2 * globalMin_w;
//************************************Section 6: Results for both are outputted******************************************************************************************
//prints a formatted output giving the co ordinates for weighted and non weighted positions, as well as the total distance travelled
printf("\nCo ordinates (non weighted for population): %6.2f,%6.2f degrees. \nTotal non weighted distance: %6.2f miles.\nCoordinates (weighted for population): %6.2f,%6.2f degrees.\nTotal weighted distance: %6.2f miles.\nExtra distance travelled: %6.2f miles. \n", gly, glx, total_distance, gly_w, glx_w, total_distance_w, distance_difference);
//prints a message giving the nearest town/city if the weighted and non weighted ones are the same
if (places[closestPosition][0] == places[closestPosition_w][0]){
cout << "The nearest town/city to the non weighted co ordinates is the same as the weighted co ordinates and is " << places[closestPosition][0] << "." << endl;
}
//prints a message giving the nearest town/city if the weighted and non weighted ones are different
else{
cout << "The nearest city to the non weighted co ordinates is " << places[closestPosition][0] << " whilst the nearest location for weighted co ordiantes is " << places[closestPosition_w][0] << ". \n" << endl;
}
return 0;
}