Program Listing for File local_edge_index.h¶
↰ Return to documentation for file (include/shad/extensions/graph_library/local_edge_index.h
)
//===------------------------------------------------------------*- C++ -*-===//
//
// SHAD
//
// The Scalable High-performance Algorithms and Data Structure Library
//
//===----------------------------------------------------------------------===//
//
// Copyright 2018 Battelle Memorial Institute
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
//===----------------------------------------------------------------------===//
#ifndef INCLUDE_SHAD_EXTENSIONS_GRAPH_LIBRARY_LOCAL_EDGE_INDEX_H_
#define INCLUDE_SHAD_EXTENSIONS_GRAPH_LIBRARY_LOCAL_EDGE_INDEX_H_
#include <algorithm>
#include <atomic>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
#include "shad/data_structures/compare_and_hash_utils.h"
#include "shad/data_structures/local_hashmap.h"
#include "shad/data_structures/local_set.h"
#include "shad/runtime/runtime.h"
namespace shad {
template <typename T>
class IDCmp {
public:
bool operator()(const T* first, const T* sec) const { return *first != *sec; }
};
template <typename SrcT, typename DestT,
typename NeighborsStorageT = LocalSet<DestT>>
class DefaultEdgeIndexStorage {
public:
struct EmptyAttr {};
using SrcAttributesT = EmptyAttr;
explicit DefaultEdgeIndexStorage(const size_t numVertices)
: edgeList_(std::max(numVertices / constants::kDefaultNumEntriesPerBucket,
1lu)) {}
DefaultEdgeIndexStorage(const size_t numVertices, const SrcAttributesT&)
: edgeList_(std::max(numVertices / constants::kDefaultNumEntriesPerBucket,
1lu)) {}
static constexpr size_t kEdgeListChunkSize_ = 3072 / sizeof(DestT);
struct LocalEdgeListChunk {
LocalEdgeListChunk(size_t _numDest, bool _ow, DestT* _dest)
: numDest(_numDest), overwrite(_ow) {
memcpy(destinations.data(), _dest,
std::min(numDest, destinations.size()) * sizeof(DestT));
}
size_t numDest;
size_t chunkSize;
bool overwrite;
std::array<DestT, kEdgeListChunkSize_> destinations;
};
struct FlatEdgeList {
const DestT* values;
size_t numValues;
bool overwrite;
};
struct ElementInserter {
void operator()(NeighborsStorageT* const lhs, const NeighborsStorageT&) {}
static bool Insert(NeighborsStorageT* const lhs, const DestT value, bool) {
lhs->Insert(value);
return true;
}
static bool Insert(NeighborsStorageT* const lhs,
const FlatEdgeList values, bool) {
if (values.overwrite) lhs->Reset(values.numValues);
for (size_t i = 0; i < values.numValues; i++) {
lhs->Insert(values.values[i]);
}
return true;
}
static bool Insert(NeighborsStorageT* const lhs,
const LocalEdgeListChunk& chunk, bool) {
if (chunk.overwrite) lhs->Reset(chunk.numDest);
size_t chunkSize = std::min(chunk.numDest, chunk.destinations.size());
for (size_t i = 0; i < chunkSize; i++) {
lhs->Insert(chunk.destinations[i]);
}
return true;
}
};
template <typename ApplyFunT, typename... Args>
void ForEachAttributedVertexNeighbor(const SrcT& src, ApplyFunT&& function,
Args... args);
template <typename ApplyFunT, typename... Args>
void AsyncForEachAttributedVertexNeighbor(rt::Handle& handle, const SrcT& src,
ApplyFunT&& function, Args... args);
template <typename ApplyFunT, typename... Args>
void ForEachAttributedVertex(ApplyFunT&& function, Args... args);
template <typename ApplyFunT, typename... Args>
void AsyncForEachAttributedVertex(rt::Handle& handle, ApplyFunT&& function,
Args... args);
SrcAttributesT* GetVertexAttributes(const SrcT& src) {
printf(
"WARNING: Trying to lookup attributes from"
" a non attributed graph\n");
return nullptr;
}
bool GetVertexAttributes(const SrcT& src, SrcAttributesT* attr) {
return false;
}
template <typename ApplyFunT, typename... Args>
void VertexAttributesApply(const SrcT& src, ApplyFunT&& function,
Args... args) {
printf("WARNING: Function not implemented for non attributed graphs\n");
}
using NeighborListStorageT = NeighborsStorageT;
using EdgeListStorageT =
LocalHashmap<SrcT, NeighborsStorageT, IDCmp<SrcT>, ElementInserter>;
EdgeListStorageT edgeList_;
template <typename ApplyFunT, typename... Args, std::size_t... is>
static void CallVertexAttributesApplyFun(
DefaultEdgeIndexStorage<SrcT, DestT, NeighborListStorageT>* stPtr,
const SrcT& key, ApplyFunT function, std::tuple<Args...>& args,
std::index_sequence<is...>) {
printf("WARNING: Function not implemented for non attributed graphs\n");
}
};
template <typename SrcT, typename DestT,
typename StorageT = DefaultEdgeIndexStorage<SrcT, DestT>>
class LocalEdgeIndex {
public:
template <typename, typename>
friend class LocalSet;
explicit LocalEdgeIndex(const size_t numVertices)
: edges_(numVertices), numEdges_(0) {}
LocalEdgeIndex(const size_t numVertices,
const typename StorageT::SrcAttributesT& initAttr)
: edges_(numVertices, initAttr), numEdges_(0) {}
size_t Size() const { return edges_.edgeList_.Size(); }
size_t UpdateNumEdges() {
size_t numEdges(0);
size_t* cntPtr = &numEdges;
LocalEdgeIndex<SrcT, DestT, StorageT>* eiptr = this;
auto countLambda = [](const SrcT& src,
LocalEdgeIndex<SrcT, DestT, StorageT>*& eiptr,
size_t*& edgeCntPtr) {
auto neigh = eiptr->edges_.edgeList_.Lookup(src);
size_t nsize = neigh->Size();
__sync_fetch_and_add(edgeCntPtr, nsize);
};
edges_.edgeList_.ForEachKey(countLambda, eiptr, cntPtr);
// FIXME : This is should be atomic.
numEdges_ = numEdges;
return numEdges_;
}
void Insert(const SrcT& src, const DestT& dest) {
edges_.edgeList_.Insert(src, dest);
}
void Insert(const SrcT& src,
const typename StorageT::LocalEdgeListChunk& chunk) {
edges_.edgeList_.Insert(src, chunk);
}
void AsyncInsert(rt::Handle& handle, const SrcT& src,
const typename StorageT::LocalEdgeListChunk& chunk) {
edges_.edgeList_.AsyncInsert(handle, src, chunk);
}
void InsertEdgeList(const SrcT& src, const DestT* destinations,
size_t numDest, bool overwrite = true) {
typename StorageT::FlatEdgeList dest = {destinations, numDest, overwrite};
edges_.edgeList_.Insert(src, dest);
}
void AsyncInsertEdgeList(rt::Handle& handle, const SrcT& src,
const DestT* destinations, size_t numDest,
bool overwrite = true) {
typename StorageT::FlatEdgeList dest = {destinations, numDest, overwrite};
edges_.edgeList_.AsyncInsert(handle, src, dest);
}
void AsyncInsert(rt::Handle& handle, const SrcT& src, const DestT& dest) {
edges_.edgeList_.AsyncInsert(handle, src, dest);
}
void Erase(const SrcT& src, const DestT& dest) {
auto edgeList = edges_.edgeList_.Lookup(src);
if (edgeList != nullptr) edgeList->Erase(dest);
}
void AsyncErase(rt::Handle& handle, const SrcT& src, const DestT& dest) {
auto edgeList = edges_.edgeList_.Lookup(src);
if (edgeList != nullptr) edgeList->AsyncErase(handle, dest);
}
size_t GetDegree(const SrcT& src) {
auto edgeList = edges_.edgeList_.Lookup(src);
if (edgeList == nullptr) return 0;
return edgeList->Size();
}
typename StorageT::NeighborListStorageT* GetNeighbors(const SrcT& src) {
return edges_.edgeList_.Lookup(src);
}
void AsyncGetNeighbors(rt::Handle& handle, const SrcT src,
typename StorageT::NeighborListStorageT** res) {
edges_.edgeList_.AsyncLookup(handle, src, res);
}
template <typename ApplyFunT, typename... Args>
void ForEachNeighbor(const SrcT& src, ApplyFunT&& function, Args&... args) {
auto edgeList = edges_.edgeList_.Lookup(src);
if (edgeList == nullptr) {
printf("EdgeList is null!!\n");
return;
}
edgeList->ForEachNeighbor(function, src, args...);
}
template <typename ApplyFunT, typename... Args>
void AsyncForEachNeighbor(rt::Handle& handle, const SrcT& src,
ApplyFunT&& function, Args&... args) {
auto edgeList = edges_.edgeList_.Lookup(src);
if (edgeList == nullptr) {
printf("EdgeList is null!!\n");
return;
}
edgeList->AsyncForEachNeighbor(handle, function, src, args...);
}
template <typename ApplyFunT, typename... Args>
void ForEachVertex(ApplyFunT&& function, Args&... args) {
edges_.edgeList_.ForEachKey(function, args...);
}
template <typename ApplyFunT, typename... Args>
void AsyncForEachVertex(rt::Handle& handle, ApplyFunT&& function,
Args&... args) {
edges_.edgeList_.AsyncForEachKey(handle, function, args...);
}
template <typename ApplyFunT, typename... Args>
void ForEachEdge(ApplyFunT&& function, Args&... args) {
using FunctionTy = void (*)(const SrcT& src, const DestT& dest, Args&...);
FunctionTy fn = std::forward<decltype(function)>(function);
auto callFE = [](const SrcT& src,
typename StorageT::NeighborListStorageT& neighbors,
FunctionTy& fun, Args&... args) {
neighbors.ForEachNeighbor(fun, src, args...);
};
edges_.edgeList_.ForEachEntry(callFE, fn, args...);
}
template <typename ApplyFunT, typename... Args>
void AsyncForEachEdge(rt::Handle& handle, ApplyFunT&& function,
Args&... args) {
using FunctionTy = void (*)(rt::Handle & handle, const SrcT& src,
const DestT& dest, Args&...);
FunctionTy fn = std::forward<decltype(function)>(function);
auto callFE = [](rt::Handle& handle, const SrcT& src,
typename StorageT::NeighborListStorageT& neighbors,
FunctionTy& fun, Args&... args) {
neighbors.AsyncForEachNeighbor(handle, fun, src, args...);
};
edges_.edgeList_.AsyncForEachEntry(handle, callFE, fn, args...);
}
template <typename ApplyFunT, typename... Args>
void ForEachAttributedVertexNeighbor(const SrcT& src, ApplyFunT&& function,
Args&... args) {
edges_.ForEachAttributedVertexNeighbor(function, src, args...);
}
template <typename ApplyFunT, typename... Args>
void AsyncForEachAttributedVertexNeighbor(rt::Handle& handle, const SrcT& src,
ApplyFunT&& function,
Args&... args) {
edges_.AsyncForEachAttributedVertexNeighbor(handle, function, src, args...);
}
template <typename ApplyFunT, typename... Args>
void ForEachAttributedVertex(ApplyFunT&& function, Args&... args) {
edges_.ForEachAttributedVertex(function, args...);
}
template <typename ApplyFunT, typename... Args>
void AsyncForEachAttributedVertex(rt::Handle& handle, ApplyFunT&& function,
Args&... args) {
edges_.AsyncForEachAttributedVertex(handle, function, args...);
}
typename StorageT::SrcAttributesT* GetVertexAttributes(const SrcT& src) {
return edges_.GetVertexAttributes(src);
}
bool GetVertexAttributes(const SrcT& src,
typename StorageT::SrcAttributesT* attr) {
return edges_.GetVertexAttributes(src, attr);
}
template <typename ApplyFunT, typename... Args>
void VertexAttributesApply(const SrcT& src, ApplyFunT&& function,
Args&... args) {
edges_.VertexAttributesApply(src, function, args...);
}
StorageT* GetEdgesPtr() { return &edges_; }
private:
size_t numEdges_;
StorageT edges_;
};
} // namespace shad
#endif // INCLUDE_SHAD_EXTENSIONS_GRAPH_LIBRARY_LOCAL_EDGE_INDEX_H_