Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion include/greedysearch.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
#include <vector>
#include "../include/graph.hpp"
#include <unordered_map>

using namespace std;

// L_set, V_set should be empty when calling the function
// L_set, V_set will be full once function call terminated
void GreedySearch(Node *start_node, vector<double> &queryCoords, int k, int L, set<Node *> &L_set, set<Node *> &V_set);
void GreedySearch(Node *start_node, vector<double> &queryCoords, int k, int L, set<Node *> &L_set, set<Node *> &V_set);

// Hash function used for: unordered_map<pair<Node*, Node*>, double, PairHash> nodePairMap
struct PairHash {
size_t operator()(const pair<Node*, Node*>& p) const {
auto h1 = hash<Node*>()(p.first);
auto h2 = hash<Node*>()(p.second);
// Combine hashes in an order-independent way for symmetry
return h1 ^ h2; // xor
}
};

// Δύο είναι οι διαφορές από τον από πάνω greedy search: 1. Το query δίνεται σε Node* και όχι σε vector, 2. Λαμβάνει ως παράμετρο τις αποθηκευμένες αποστάσεις (nodePairMap)
// IMPORTANT: Γι' αυτούς του δύο λόγους, καλείται *μόνο* από τον vamana, και *όχι* από την first_main.
void GreedySearchIndex(Node* start_node, Node* query_node, int k, int L, set<Node*> &L_set, set<Node*> &V_set, unordered_map<pair<Node*, Node*>, double, PairHash>& nodePairMap);
8 changes: 8 additions & 0 deletions include/stitchedVamanaParallelDistances.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef STITCHEDVAMANAPARALLELDISTANCES_HPP
#define STITCHEDVAMANAPARALLELDISTANCES_HPP

#include "graph.hpp"

Graph stitchedVamanaParallelDistances(vector<vector<double>> &coords, set<int> F, double a, int L_small, int R_small, int R_stitched, map<int, Node *> &medoids);

#endif
2 changes: 2 additions & 0 deletions include/vamana.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@

int Vamana(Graph &graph, vector<Node *> &coords, int R, double a, int int_L); // added parameter f = label, to pass to generate_graph
// so that it creates a graph with nodes of label f.

int VamanaParallelDistances(Graph &graph, vector<Node *> &coords, int R, double a, int int_L);
63 changes: 63 additions & 0 deletions src/greedysearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,68 @@ void GreedySearch(Node* start_node, vector<double> &queryCoords, int k, int L, s
L_set.insert(it->second); // `it->second` is the node
}

return;
}

void GreedySearchIndex(Node* start_node, Node* query_node, int k, int L, set<Node*> &L_set, set<Node*> &V_set, unordered_map<pair<Node*, Node*>, double, PairHash>& nodePairMap) {

// All the elements in a set have unique values
// by default set is sorted in ascending order
assert(L_set.empty() == true); // given L_set should be empty
assert(V_set.empty() == true); // given V_set should be empty
assert(L >= k);
assert(start_node != NULL);
assert(query_node->getCoordinates().size() > 0);

unordered_map<Node*, double> nodeMap; // Main storage
set<pair<double, Node*>, Compare> sortedSet; // Secondary sorted viewm of main storage
set<pair<double, Node*>, Compare> LminusV;


// Create an order-independent key
pair<Node*, Node*> key = {min(start_node, query_node), max(start_node, query_node)}; // The hash and key use min and max to ensure that {node1, node2} is treated the same as {node2, node1}. This eliminates the need to insert the symmetric pair manually.
assert(nodePairMap.find(key) != nodePairMap.end()); // assert if key doesn't exist
double dist = nodePairMap[key]; // already precomputed!
insert(nodeMap, sortedSet, start_node, dist, L); // Initialization of L_set
// V_set is empty

// L\V = {start} \ {} = {start}
LminusV.emplace(dist, start_node); // Inserts a new pair in the set, if unique. This new pair is constructed in place using args as the arguments for its construction.

while(LminusV.empty() == false) { // while LminusV != {}

auto first_pair = *LminusV.begin(); // LminusV is sorted based on distance in descending order. Therefore, first element of LminusV is the min we are looking for
Node* p_star = first_pair.second; // The 'Node*'

// Update V_set [V = V U p*]
V_set.insert(p_star); // if p_star is already in V_set, p_set won't be inserted in V


// Update L_set [ L = L U Nout(p*) ]
list<Node*> p_star_out = p_star->getEdges(); // out-neighbors of p*
for(auto node : p_star_out) { // Insert all of out-neighbors of p* into L set

pair<Node*, Node*> key = {min(node, query_node), max(node, query_node)}; // Create an order-independent key
assert(nodePairMap.find(key) != nodePairMap.end()); // assert if key doesn't exist
double dist = nodePairMap[key]; // already precomputed!
insert(nodeMap, sortedSet, node, dist, L);
}

// Update of L to retain top L elements of vector happens immediately whenever we insert an element in "L set"

LminusV = set_difference(sortedSet, V_set);
}

// We update L to retain top k elements of vector
int my_k = k;
if(static_cast<int>(sortedSet.size()) < k) {
my_k = sortedSet.size();
}

int i = 0;
for (auto it = sortedSet.begin(); i < my_k; ++it, ++i) {
L_set.insert(it->second); // `it->second` is the node
}

return;
}
104 changes: 104 additions & 0 deletions src/stitchedVamanaParallelDistances.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* StitchedVamana parallel implementation file:
Contains the parallel implementation of stitchedVamana with pthreads.

stitchedVamana returns a stitched graph, that consists of a collection of subgraphs, one for each label.
if there are no nodes for a label, then the graph would be empty.
*/

#include "../include/stitchedVamana.hpp"
#include "../include/stitchedVamanaParallel.hpp"
#include "../include/vamana.hpp"
#include "../include/filteredrobustprune.hpp"
#include "../include/generate_graph.hpp"
#include <pthread.h>

using namespace std;

struct Thread_params {
int label;
vector<Node *> Pf;
double a;
int R_small;
int L_small;
Graph *graph; // pointer to the main graph
map<int, Node *> *medoids; // pointer to medoids map
pthread_mutex_t *mutex_union; // mutex for graphUnion - we will need the mutexes for the functions that are accessed by the threads (shared functions)
pthread_mutex_t *mutex_medoid; // mutex for store_medoid
};

// thread function -- is done by each thread: the work of processing one label: make Gf, stitch it, store medoid.
static void *processLabel(void *args)
{
Thread_params *params = static_cast<Thread_params *>(args);

// create a subgraph for this label
Graph Gf;
int medoidId = VamanaParallelDistances(Gf, params->Pf, params->R_small, params->a, params->L_small);

// merge (stitch) the subgraph into the main graph
pthread_mutex_lock(params->mutex_union);
params->graph->graphUnion(std::move(Gf));
pthread_mutex_unlock(params->mutex_union);

Gf.clear();

// store the medoid node
if (medoidId != -1)
{
pthread_mutex_lock(params->mutex_medoid);
store_medoid(*params->graph, *params->medoids, params->label, medoidId);
pthread_mutex_unlock(params->mutex_medoid);
}

return nullptr;
}


Graph stitchedVamanaParallelDistances(vector<vector<double>> &coords, set<int> F, double a, int L_small, int R_small, int R_stitched, map<int, Node *> &medoids)
{
Graph G;
unordered_map<int, set<int>> Fx = compute_Fx(coords);
unordered_map<int, vector<Node *>> PfMap = compute_PfMap(coords, F);

// initialize pthreads
pthread_t threads[F.size()];
Thread_params params[F.size()];
pthread_mutex_t mutex_union = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_medoid = PTHREAD_MUTEX_INITIALIZER;

int i = 0;
for (int f : F)
{
vector<Node *> Pf = PfMap[f];

// if Pf is empty, then we were given no nodes with this label
if (Pf.empty())
{
// continue without calling vamana to avoid extra work
continue;
}

// prepare thread parameters
params[i] = {f, Pf, a, R_small, L_small, &G, &medoids, &mutex_union, &mutex_medoid};

// create a thread
if (pthread_create(&threads[i], nullptr, processLabel, &params[i]) != 0) {
cerr << "Error creating thread for label " << f << endl;
}

i++;
}

// wait for all threads to complete
for (int j = 0; j < i; j++)
{
pthread_join(threads[j], nullptr);
}

pthread_mutex_destroy(&mutex_union);
pthread_mutex_destroy(&mutex_medoid);

// connect_subgraphs(G, PfMap);

return G;
}
Loading
Loading