Skip to content

Commit a5c8e8e

Browse files
authored
Merge pull request #22 from algosup/dev
Dev
2 parents f7d1e9e + fbb409b commit a5c8e8e

File tree

16 files changed

+3471
-0
lines changed

16 files changed

+3471
-0
lines changed

src/alt.cpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// ✅ file verified.
2+
#include "incl.h"
3+
#include "decl.h"
4+
5+
// ✅ function + comment verified.
6+
/**
7+
* @brief Precomputes landmark-based shortest path estimates using the ALT heuristic.
8+
*
9+
* @detailed
10+
* This function implements ALT (A* Landmarks and Triangle Inequality) preprocessing, which enhances
11+
* heuristic pathfinding by precomputing distances from selected landmark nodes.
12+
*
13+
* Functionality:
14+
* - Uses the farthest-node method to select optimal landmarks.
15+
* - Computes shortest-path distances using Dijkstra’s algorithm.
16+
* - Optionally loads or stores precomputed landmark data for reuse.
17+
*
18+
* Steps of the Algorithm:
19+
* 1. If `save_alt` is enabled, attempt to load precomputed landmark data from storage.
20+
* 2. Initialize storage structures for distance calculations.
21+
* 3. Select the first landmark as an arbitrary node (first node in the dataset).
22+
* 4. Compute shortest-path distances using Dijkstra’s algorithm:
23+
* - `dist_landmark_to[i][j]` stores the shortest path distance **to** node `i` from landmark `j`.
24+
* - `dist_landmark_from[i][j]` stores the shortest path distance **from** node `i` to landmark `j`.
25+
* 5. Iteratively select `nb_alt` landmarks using the farthest-node heuristic:
26+
* - Find the node that has the maximum minimum distance from previous landmarks.
27+
* - Recompute shortest-path distances using Dijkstra’s algorithm.
28+
* - If no more landmarks can be choosen, break the loop and modify the configuration.
29+
* 6. If `save_alt` is enabled, store the precomputed landmark data.
30+
*
31+
* Mathematical Background:
32+
* - Landmark heuristics use the triangle inequality:
33+
*
34+
* h(n) = max{ |d_L(goal) - d_L(n)|, |d_F(n) - d_F(goal)| }
35+
*
36+
* where:
37+
* - `d_L(n)` is the precomputed distance from landmark `L` to node `n`.
38+
* - `d_F(n)` is the precomputed distance from node `n` to landmark `L`.
39+
*
40+
* - The farthest-node landmark selection ensures a wide spread of landmarks,
41+
* improving heuristic accuracy in large graphs.
42+
*
43+
* Edge Cases:
44+
* - If no valid landmarks are found, preprocessing stops early.
45+
* - If loading precomputed landmarks fails, it falls back to computation.
46+
*
47+
* @param gdata Reference to the graph data structure.
48+
* @param conf Reference to the configuration settings, which determine landmark count and storage options.
49+
*
50+
* @complexity
51+
* - Time Complexity: O(nb_alt * (E log V))
52+
* - Each landmark selection involves a Dijkstra search → O(E log V).
53+
* - `nb_alt` landmark selections are performed.
54+
* - Space Complexity: O(V * nb_alt)
55+
* - Each node stores distances to all selected landmarks.
56+
*/
57+
void preprocessAlt(graph& gdata, config& conf)
58+
{
59+
if (conf.save_alt)
60+
{
61+
if (loadAltData(gdata, conf)) {
62+
return;
63+
}
64+
}
65+
66+
logger("selecting landmarks using farthest-node strategy");
67+
68+
size_t n = gdata.node_to_index.size();
69+
70+
std::vector<int> landmarks;
71+
landmarks.reserve(conf.nb_alt);
72+
std::vector<int> md(n, std::numeric_limits<int>::max());
73+
std::vector<int> d(n, -1);
74+
75+
gdata.dist_landmark_to.resize(n, std::vector<int>(conf.nb_alt, -1));
76+
gdata.dist_landmark_from.resize(n, std::vector<int>(conf.nb_alt, -1));
77+
78+
int fl = gdata.node_to_index.begin()->first;
79+
landmarks.push_back(fl);
80+
console("info", "processing landmark " + std::to_string(fl) + " (1/" + std::to_string(conf.nb_alt) + ")");
81+
logger("processing landmark " + std::to_string(fl) + " (1/" + std::to_string(conf.nb_alt) + ")");
82+
83+
d = dijkstraSingleSource(gdata.adjacency, fl, n, gdata.node_to_index);
84+
{
85+
int i = 0;
86+
for (auto& kv : gdata.node_to_index) {
87+
size_t idx = kv.second;
88+
gdata.dist_landmark_to[idx][i] = d[idx];
89+
gdata.dist_landmark_from[idx][i] = d[idx];
90+
if (d[idx] >= 0 && d[idx] < md[idx]) md[idx] = d[idx];
91+
}
92+
}
93+
94+
for (int i = 1; i < conf.nb_alt; ++i) {
95+
int nl = -1;
96+
int mx = -1;
97+
98+
for (auto& kv : gdata.node_to_index) {
99+
size_t idx = kv.second;
100+
if (md[idx] > mx) {
101+
mx = md[idx];
102+
nl = kv.first;
103+
}
104+
}
105+
106+
if (nl == -1) {
107+
logger("warning: only selected " + std::to_string(landmarks.size()) + " landmarks as the number of requested landmarks exceeds the number of available nodes. setting new value inside the config.");
108+
console("warning", "only selected " + std::to_string(landmarks.size()) + " landmarks as the number of requested landmarks exceeds the number of available nodes. setting new value inside the config.");
109+
110+
conf.nb_alt = landmarks.size();
111+
updateNbAlt(conf, conf.nb_alt);
112+
113+
break;
114+
}
115+
116+
landmarks.push_back(nl);
117+
console("info", "processing landmark " + std::to_string(nl) +
118+
" (" + std::to_string(i + 1) + "/" + std::to_string(conf.nb_alt) + ")");
119+
logger("processing landmark " + std::to_string(nl) +
120+
" (" + std::to_string(i + 1) + "/" + std::to_string(conf.nb_alt) + ")");
121+
122+
d = dijkstraSingleSource(gdata.adjacency, nl, n, gdata.node_to_index);
123+
for (auto& kv : gdata.node_to_index) {
124+
size_t idx = kv.second;
125+
gdata.dist_landmark_to[idx][i] = d[idx];
126+
gdata.dist_landmark_from[idx][i] = d[idx];
127+
if (d[idx] >= 0 && d[idx] < md[idx]) md[idx] = d[idx];
128+
}
129+
130+
size_t selected_idx = gdata.node_to_index[nl];
131+
md[selected_idx] = -1;
132+
}
133+
134+
console("success", "ALT pre-processing complete.");
135+
logger("ALT pre-processing complete.");
136+
137+
if (conf.save_alt) {
138+
saveAltData(gdata, conf);
139+
}
140+
}
141+

0 commit comments

Comments
 (0)