diff --git a/.gitignore b/.gitignore
index dfef3803..c54d8736 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,5 @@ recentMorphStoreProjectConf.log
Dockerfile
.DS_Store
doc/doxygen/latex
-doc/doxygen/html
\ No newline at end of file
+doc/doxygen/html
+.vscode/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c54c35c0..298a25b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required( VERSION 3.10 )
project( MorphStore )
-set( CMAKE_CXX_STANDARD 14 )
+set( CMAKE_CXX_STANDARD 17 )
macro(morph_flag)
add_definitions(${ARGN})
@@ -28,9 +28,11 @@ set( LOG_FILE "recentMorphStoreProjectConf.log" )
IF(CMAKE_BUILD_TYPE MATCHES Debug)
morph_flag(-g)
+ morph_flag(-DDEBUG)
message(STATUS "MorphStore is configured in DEBUG mode.")
ELSEIF(CMAKE_BUILD_TYPE MATCHES Release)
morph_flag(-O2)
+ morph_flag(-DNDEBUG)
message(STATUS "MorphStore is configured in RELEASE mode.")
ELSEIF(CMAKE_BUILD_TYPE MATCHES HighPerf)
morph_flag(-O3)
@@ -93,6 +95,10 @@ ENDIF(CODROID)
# remove build type to allow for custom flag handling
set(CMAKE_BUILD_TYPE "")
+# add resource directory for ldbc graph
+# (see https://github.com/ldbc/ldbc_snb_datagen for further instructions)
+morph_flag(-DLDBC_DIR="$ENV{HOME}/ldbc_snb_datagen/social_network/")
+
# general compiler settings, meant for all subdirectories and tests
morph_flag(-Werror)
morph_flag(-pedantic)
diff --git a/doc/doxygen/pages/tutorials/quick_start.md b/doc/doxygen/pages/tutorials/quick_start.md
index 958c1415..a4809f83 100644
--- a/doc/doxygen/pages/tutorials/quick_start.md
+++ b/doc/doxygen/pages/tutorials/quick_start.md
@@ -23,7 +23,7 @@ Ensure that you have the following tools installed before trying to build:
- g++ >= version 8.2
- cmake >= version 3.10
-Older versions may not build all test cases. Note that C++14 is necessary.
+Older versions may not build all test cases. Note that C++17 is necessary.
To facilitate building and testing MorphStore, there is a script build.sh in the root folder.
@@ -42,9 +42,29 @@ build/src/examples/example_query
~~~
This builds some example queries in debug mode and runs them. The source code of these queries can be found in the folder src/examples.
-They are runnig in scalar mode. Thus, every system providing C++14 support should be able to build and run them regardless of any (not)
+They are runnig in scalar mode. Thus, every system providing C++17 support should be able to build and run them regardless of any (not)
available vector extensions.
+
+The Graph Module
+======================
+
+The graph module mainly contains the two different graph storage formats `Compressed Sparse Row (CSR)` and `Adjacency-List`, which differ in their representation of the graph topology .
+These underlying graph model is a multi-graph, with properties for vertices and edges as well as types for both.
+The model is very similar to the Property-Graph model, except that vertices can only have one type (instead of multiple labels).
+
+The columns describing the graph topology can be compressed using formats from the MorphStore.
+Besides there exists simple implementations of the graph algorithms `breadth-first search (bfs)` and `PageRank`.
+
+
+To run all the test and micro-benchmarks, a LDBC graph has to be generated.
+Instructions of how to generate the graph, can be found at `https://github.com/ldbc/ldbc_snb_datagen`.
+By default the ldbc graph is expected to be at `"$HOME/ldbc_snb_datagen/social_network/"`.
+This can be changed at `/Morphstore/Engine/CMakeLists.txt`.
+
+
+
+
Test Vector Extensions
======================
diff --git a/include/core/morphing/decompress_column_block.h b/include/core/morphing/decompress_column_block.h
new file mode 100644
index 00000000..5b244181
--- /dev/null
+++ b/include/core/morphing/decompress_column_block.h
@@ -0,0 +1,95 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file decompress_column_block.h
+ * @brief Decompressing single blocks of a column based on column_with_blockoffsets.
+ */
+
+#ifndef MORPHSTORE_CORE_MORPHING_DECOMPRESS_COLUMN_BLOCK_H
+#define MORPHSTORE_CORE_MORPHING_DECOMPRESS_COLUMN_BLOCK_H
+
+#include
+#include
+#include
+
+#include
+
+namespace morphstore {
+
+ /**
+ * @brief Decompressing a range column blocks (inclusive range)
+ *
+ * @param inCol The column with block-offsets
+ * @param start index of blocks to be decompressed
+ * @param end index of blocks to be decompressed
+ * @return Specified blocks uncompressed in a new column
+ */
+ template
+ const column *decompress_column_blocks(column_with_blockoffsets *inCol, uint64_t start,
+ uint64_t end) {
+ static_assert(compr_f::m_BlockSize != 1, "Decompressing column blocks of size 1 is not allowed");
+
+ auto block_size = compr_f::m_BlockSize;
+ auto block_count = inCol->get_block_offsets()->size();
+ auto inCol_value_count = inCol->get_column()->get_count_values();
+
+ // validating range
+ assert(start <= end);
+ assert(start < block_count);
+ assert(end < block_count);
+
+ bool last_block_uncompressed = !inCol->last_block_compressed();
+ bool last_block_included = end == (block_count - 1);
+
+ // pessimistic value_count (assuming all blocks are complete)
+ auto value_count = (end - start + 1) * block_size;
+
+ if (last_block_included && last_block_uncompressed) {
+ // correcting value_count estimation
+ value_count -= block_size - inCol_value_count % block_size;
+ }
+
+ // TODO: should actually be base_t?
+ auto alloc_size = value_count * sizeof(uint64_t);
+
+ auto decompr_col_blocks = new column(alloc_size);
+ decompr_col_blocks->set_meta_data(value_count, alloc_size);
+ uint8_t *out8 = decompr_col_blocks->get_data();
+
+ for (uint64_t block = start; block <= end; block++) {
+ const uint8_t *block_offset = inCol->get_block_offset(block);
+
+ if (block == end && last_block_included && last_block_uncompressed) {
+ // handle uncompressed part
+ morph_batch(block_offset, out8, inCol_value_count % block_size);
+ } else {
+ morph_batch(block_offset, out8, block_size);
+ }
+ }
+
+ return decompr_col_blocks;
+ }
+
+ template
+ const column *decompress_column_block(column_with_blockoffsets *inCol, uint64_t block_index) {
+ return decompress_column_blocks(inCol, block_index, block_index);
+ }
+
+} // namespace morphstore
+
+#endif // MORPHSTORE_CORE_MORPHING_DECOMPRESS_COLUMN_BLOCK_H
diff --git a/include/core/morphing/graph/morph_graph_col.h b/include/core/morphing/graph/morph_graph_col.h
new file mode 100644
index 00000000..989c93f2
--- /dev/null
+++ b/include/core/morphing/graph/morph_graph_col.h
@@ -0,0 +1,135 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file morph_graph_col.h
+ * @brief helper for morphing graph columns (template-free columns). Basically need to cast to template column as it
+ * cannot be derieved
+ * @todo Remove this helper and make graph formats accept templates (can use normal morph() then)
+ */
+
+#ifndef MORPHSTORE_GRAPH_MORPH_GRAPH_COL_H
+#define MORPHSTORE_GRAPH_MORPH_GRAPH_COL_H
+
+#include
+#include
+#include
+
+#include
+
+namespace morphstore {
+ using column_uncompr = column;
+ using column_dyn_vbp = column;
+ using column_delta = column;
+ using column_for = column;
+
+ // casting the column to the actual column type before morphing (as compiler could not derive it)
+ // delete_old_col -> delete input column after morphing (if the result is not the input column)
+ const column_base *morph_graph_col(const column_base *column, const GraphCompressionFormat src_f,
+ const GraphCompressionFormat trg_f, bool delete_in_col = false) {
+ if (src_f == trg_f) {
+ return column;
+ }
+
+ const column_base *result = column;
+
+ switch (src_f) {
+ case GraphCompressionFormat::UNCOMPRESSED: {
+ const column_uncompr *old_col = dynamic_cast(column);
+ switch (trg_f) {
+ case GraphCompressionFormat::DELTA:
+ result = morph(old_col);
+ break;
+ case GraphCompressionFormat::FOR:
+ result = morph(old_col);
+ break;
+ case GraphCompressionFormat::DYNAMIC_VBP:
+ result = morph(old_col);
+ break;
+ case GraphCompressionFormat::UNCOMPRESSED:
+ // handled by src_f == trg_f
+ break;
+ }
+ break;
+ }
+ case GraphCompressionFormat::DELTA: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ const column_delta *old_col = dynamic_cast(column);
+ result = morph(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_graph_col(column, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ result = morph_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ case GraphCompressionFormat::FOR: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ const column_for *old_col = dynamic_cast(column);
+ result = morph(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_graph_col(column, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ result = morph_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ case GraphCompressionFormat::DYNAMIC_VBP: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ const column_dyn_vbp *old_col = dynamic_cast(column);
+ result = morph(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_graph_col(column, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ // delete_in_col = true as temporary uncompr_col should always be deleted
+ result = morph_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ }
+
+ // free input column if possible
+ if (result != column && delete_in_col) {
+ delete column;
+ }
+
+ if (result == nullptr) {
+ throw std::runtime_error("Did not handle src: " + graph_compr_f_to_string(src_f) +
+ " trg: " + graph_compr_f_to_string(trg_f));
+ }
+
+ return result;
+ }
+
+ const column_uncompr *decompress_graph_col(const column_base *column, const GraphCompressionFormat src_f) {
+ return static_cast(
+ morph_graph_col(column, src_f, GraphCompressionFormat::UNCOMPRESSED, false));
+ }
+
+ double compression_ratio(const column_base *col, GraphCompressionFormat col_format) {
+ auto uncompr_col = decompress_graph_col(col, col_format);
+ auto ratio = uncompr_col->get_size_used_byte() / (double)col->get_size_used_byte();
+
+ if (col != uncompr_col) {
+ delete uncompr_col;
+ }
+
+ return ratio;
+ }
+} // namespace morphstore
+
+#endif // MORPHSTORE_GRAPH_MORPH_GRAPH_COL_H
\ No newline at end of file
diff --git a/include/core/morphing/graph/morph_saving_offsets_graph_col.h b/include/core/morphing/graph/morph_saving_offsets_graph_col.h
new file mode 100644
index 00000000..68c51167
--- /dev/null
+++ b/include/core/morphing/graph/morph_saving_offsets_graph_col.h
@@ -0,0 +1,175 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file morph_saving_offsets_graph_col.h
+ * @brief helper for `morph_saving_offsets()` graph column (template-free column). Basically need to cast to template
+ * column as it cannot be derieved
+ * @todo Remove this helper and make graph formats accept templates (can use normal `morph_saving_offsets()` then)
+ */
+
+#ifndef MORPHSTORE_GRAPH_MORPH_SAVING_OFFSETS_GRAPH_COL_H
+#define MORPHSTORE_GRAPH_MORPH_SAVING_OFFSETS_GRAPH_COL_H
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+namespace morphstore {
+ using column_uncompr = column;
+ using column_with_offsets_uncompr = column_with_blockoffsets;
+ using column__with_offsets_dyn_vbp = column_with_blockoffsets;
+ using column_with_offsets_delta = column_with_blockoffsets;
+ using column_with_offsets_for = column_with_blockoffsets;
+
+ // casting the column to the actual column type before morphing (as compiler could not derive it)
+ // delete_old_col -> delete input column after morphing (if the result is not the input column)
+ column_with_blockoffsets_base *morph_saving_offsets_graph_col(column_with_blockoffsets_base *col,
+ const GraphCompressionFormat src_f,
+ const GraphCompressionFormat trg_f,
+ bool delete_in_col = false) {
+ if (src_f == trg_f) {
+ return col;
+ }
+
+ auto result = col;
+
+ switch (src_f) {
+ case GraphCompressionFormat::UNCOMPRESSED: {
+ auto old_col = dynamic_cast(col);
+ switch (trg_f) {
+ case GraphCompressionFormat::DELTA:
+ result = morph_saving_offsets(old_col);
+ break;
+ case GraphCompressionFormat::FOR:
+ result = morph_saving_offsets(old_col);
+ break;
+ case GraphCompressionFormat::DYNAMIC_VBP:
+ result = morph_saving_offsets(old_col);
+ break;
+ case GraphCompressionFormat::UNCOMPRESSED:
+ // handled by src_f == trg_f
+ break;
+ }
+ break;
+ }
+ case GraphCompressionFormat::DELTA: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ auto old_col = dynamic_cast(col);
+ result = morph_saving_offsets(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_saving_offsets_graph_col(col, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ result =
+ morph_saving_offsets_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ case GraphCompressionFormat::FOR: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ auto old_col = dynamic_cast(col);
+ result = morph_saving_offsets(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_saving_offsets_graph_col(col, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ result =
+ morph_saving_offsets_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ case GraphCompressionFormat::DYNAMIC_VBP: {
+ if (trg_f == GraphCompressionFormat::UNCOMPRESSED) {
+ auto old_col = dynamic_cast(col);
+ result = morph_saving_offsets(old_col);
+ } else {
+ // as direct morphing is not yet supported .. go via decompressing first
+ auto uncompr_col = morph_saving_offsets_graph_col(col, src_f, GraphCompressionFormat::UNCOMPRESSED, false);
+ // delete_in_col = true as temporary uncompr_col should always be deleted
+ result =
+ morph_saving_offsets_graph_col(uncompr_col, GraphCompressionFormat::UNCOMPRESSED, trg_f, true);
+ }
+ break;
+ }
+ }
+
+ // free input column if possible
+ if (result != col && delete_in_col) {
+ delete col;
+ }
+
+ if (result == nullptr) {
+ throw std::runtime_error("Did not handle src: " + graph_compr_f_to_string(src_f) +
+ " trg: " + graph_compr_f_to_string(trg_f));
+ }
+
+ return result;
+ }
+
+ const column_uncompr *decompress_column_blocks(column_with_blockoffsets_base *col,
+ const GraphCompressionFormat src_f, uint64_t start, uint64_t end) {
+ switch (src_f) {
+ case GraphCompressionFormat::DELTA: {
+ auto casted_col = dynamic_cast(col);
+ return decompress_column_blocks(casted_col, start, end);
+ }
+ case GraphCompressionFormat::FOR: {
+ auto casted_col = dynamic_cast(col);
+ return decompress_column_blocks(casted_col, start, end);
+ }
+ case GraphCompressionFormat::DYNAMIC_VBP: {
+ auto casted_col = dynamic_cast(col);
+ return decompress_column_blocks(casted_col, start, end);
+ }
+ case GraphCompressionFormat::UNCOMPRESSED: {
+ throw std::runtime_error("Decompress a single block of size 1 is meaningless .. access directly");
+ }
+ default:
+ throw std::runtime_error("Unexpected compression format" + graph_compr_f_to_string(src_f));
+ }
+ }
+
+ const column_uncompr *decompress_column_block(column_with_blockoffsets_base *col,
+ const GraphCompressionFormat src_f, uint64_t block) {
+ return decompress_column_blocks(col, src_f, block, block);
+ }
+
+ column_with_offsets_uncompr *decompress_graph_col(column_with_blockoffsets_base *col,
+ const GraphCompressionFormat src_f) {
+ return static_cast(
+ morph_saving_offsets_graph_col(col, src_f, GraphCompressionFormat::UNCOMPRESSED, false));
+ }
+
+ // TODO: also consider size of blockoffset vector?
+ double compression_ratio(column_with_blockoffsets_base *col_with_offsets, GraphCompressionFormat col_format) {
+ auto uncompr_col = decompress_graph_col(col_with_offsets, col_format)->get_column();
+ auto col = col_with_offsets->get_column();
+ auto ratio = uncompr_col->get_size_used_byte() / (double)col->get_size_used_byte();
+
+ if (col != uncompr_col) {
+ delete uncompr_col;
+ }
+
+ return ratio;
+ }
+} // namespace morphstore
+
+#endif // MORPHSTORE_GRAPH_MORPH_SAVING_OFFSETS_GRAPH_COL_H
\ No newline at end of file
diff --git a/include/core/morphing/morph_saving_offsets.h b/include/core/morphing/morph_saving_offsets.h
new file mode 100644
index 00000000..e89495f6
--- /dev/null
+++ b/include/core/morphing/morph_saving_offsets.h
@@ -0,0 +1,231 @@
+/**********************************************************************************************
+ * Copyright (C) 2019 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file morph_saving_offset.h
+ * @brief based on morph.h, just calling morph_batch_t for every block and saving its offset (if blocksize > 1)
+ */
+
+#ifndef MORPHSTORE_CORE_MORPHING_MORPH_SAVING_OFFSETS_H
+#define MORPHSTORE_CORE_MORPHING_MORPH_SAVING_OFFSETS_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace morphstore {
+
+ // ****************************************************************************
+ // Column-level
+ // ****************************************************************************
+
+ // ----------------------------------------------------------------------------
+ // General interface
+ // ----------------------------------------------------------------------------
+
+ /**
+ * @brief A struct wrapping the actual morph_saving_offsets-operator.
+ *
+ * This is necessary to enable partial template specialization, which is
+ * required, since some compressed formats have their own template parameters.
+ */
+ template struct morph_saving_offsets_t {
+ /**
+ * @brief Morph_with_offsets-operator. Changes the (compressed) format of the given
+ * column from the source format `t_src_f` to the destination format
+ * `t_dst_f` without logically changing the data.
+ *
+ * This function is deleted by default, to guarantee that using this struct
+ * with a format combination it is not specialized for causes a compiler
+ * error, not a linker error.
+ *
+ * @param inCol The data represented in the source format + previous block_offsets.
+ * @return The same data represented in the destination format.
+ */
+ static column_with_blockoffsets *apply(column_with_blockoffsets *inCol) = delete;
+ };
+
+ /**
+ * A convenience function wrapping the morph-saving-offset-operator.
+ * ! Only works if the block-size = 1 (as otherwise invalid blockoffsets)
+ *
+ * Changes the (compressed) format of the given column from the source format
+ * `t_src_f` to the destination format `t_dst_f` without logically changing the
+ * data.
+ *
+ * @param inCol The data represented in the source format.
+ * @return The same data represented in the destination format.
+ */
+ template
+ column_with_blockoffsets *morph_saving_offsets(const column *inCol) {
+ return morph_saving_offsets(new column_with_blockoffsets(inCol));
+ }
+
+ /**
+ * A convenience function wrapping the morph-operator.
+ *
+ * Changes the (compressed) format of the given column from the source format
+ * `t_src_f` to the destination format `t_dst_f` without logically changing the
+ * data.
+ *
+ * @param inCol The data represented in the source format.
+ * @return The same data represented in the destination format.
+ */
+ template
+ column_with_blockoffsets *morph_saving_offsets(column_with_blockoffsets *inCol) {
+ return morph_saving_offsets_t::apply(inCol);
+ }
+
+ // ----------------------------------------------------------------------------
+ // Partial specialization for morphing from a format to itself
+ // ----------------------------------------------------------------------------
+
+ /**
+ * @brief A template specialization of the morph-operator handling the case
+ * when the source and the destination format are the same.
+ *
+ * It merely returns the given column without doing any work.
+ */
+ template struct morph_saving_offsets_t {
+ static column_with_blockoffsets *apply(column_with_blockoffsets *inCol) { return inCol; };
+ };
+
+ /**
+ * @brief A template specialization of the morph-operator handling the case
+ * when the source and the destination format are both uncompressed.
+ *
+ * We need to make this case explicit, since otherwise, the choice of the
+ * right partial template specialization is ambiguous for the compiler.
+ */
+ template struct morph_saving_offsets_t {
+ static column_with_blockoffsets *apply(column_with_blockoffsets *inCol) {
+ return inCol;
+ };
+ };
+
+ // ----------------------------------------------------------------------------
+ // Partial specialization for all compressing morph operators
+ // ----------------------------------------------------------------------------
+
+ template
+ struct morph_saving_offsets_t {
+ using src_f = uncompr_f;
+
+ // saving the offsets for every value would have an unacceptable overhead
+ static_assert(t_dst_f::m_BlockSize != 1,
+ "Blocksize of 1 is only expected for uncompr_f .. block-wise morph is useless in this case");
+
+ static column_with_blockoffsets *apply(column_with_blockoffsets *inCol_with_offsets) {
+
+ const size_t t_BlockSize = t_dst_f::m_BlockSize;
+
+ auto inCol = inCol_with_offsets->get_column();
+
+ std::vector *block_offsets = new std::vector();
+
+ const size_t countLog = inCol->get_count_values();
+ const size_t outCountLogCompr = round_down_to_multiple(countLog, t_BlockSize);
+ const size_t outSizeRestByte = uncompr_f::get_size_max_byte(countLog - outCountLogCompr);
+
+ const uint8_t *in8 = inCol->get_data();
+
+ auto outCol = new column(get_size_max_byte_any_len(countLog));
+ uint8_t *out8 = outCol->get_data();
+ const uint8_t *const initOut8 = out8;
+
+ const size_t countBlocks = countLog / t_BlockSize;
+ block_offsets->reserve(countBlocks);
+
+ // morphing each block and save the offset
+ for (size_t blockIdx = 0; blockIdx < countBlocks; blockIdx++) {
+ // saving the start address of the block
+ block_offsets->push_back(out8);
+
+ // only t_BlockSizeLog as only on block at a time should be morphed
+ morph_batch(in8, out8, t_BlockSize);
+ }
+
+ const size_t sizeComprByte = out8 - initOut8;
+
+ // needed for last block (if incomplete data stays uncompressed)
+ if (outSizeRestByte) {
+ out8 = column::create_data_uncompr_start(out8);
+ block_offsets->push_back(out8);
+ memcpy(out8, in8, outSizeRestByte);
+ }
+
+ outCol->set_meta_data(countLog, out8 - initOut8 + outSizeRestByte, sizeComprByte);
+
+ return new column_with_blockoffsets(outCol, block_offsets);
+ }
+ };
+
+ // ----------------------------------------------------------------------------
+ // Partial specialization for all decompressing morph operators
+ // ----------------------------------------------------------------------------
+
+ // as uncompressed has a blocksize of 1 --> no need to save blockoffsets
+ template
+ struct morph_saving_offsets_t {
+ using dst_f = uncompr_f;
+
+ static column_with_blockoffsets *apply(column_with_blockoffsets *inCol_with_offset) {
+ // TODO: morph_batch each block independently (see above)
+ auto inCol = inCol_with_offset->get_column();
+ auto block_offsets = inCol_with_offset->get_block_offsets();
+
+ const size_t countLog = inCol->get_count_values();
+
+ const size_t outSizeByte = dst_f::get_size_max_byte(countLog);
+ auto outCol = new column(outSizeByte);
+ uint8_t *out8 = outCol->get_data();
+
+ // !! need to decompress each block seperatly
+ // example problem:
+ // delta: morphing multi blocks at once -> block start value = diff to previous block
+ // morphing one block at a time -> block start value = first actual value of the block
+ // example: col 0..2047
+ // --> morph(): start-values: 0 ; 1
+ // --> morph_saving_offsets(): start-values: 0 ; 1024
+ for (uint64_t i = 0; i < block_offsets->size(); i++) {
+ auto offset = block_offsets->at(i);
+
+ // uncompressed last block
+ if ((i == block_offsets->size() - 1) && !inCol_with_offset->last_block_compressed()) {
+ memcpy(out8, offset, uncompr_f::get_size_max_byte(countLog % t_src_f::m_BlockSize));
+ } else {
+ morph_batch(offset, out8, t_src_f::m_BlockSize);
+ }
+ }
+
+ outCol->set_meta_data(countLog, outSizeByte);
+
+ return new column_with_blockoffsets(outCol);
+ }
+ };
+
+} // namespace morphstore
+
+#endif // MORPHSTORE_CORE_MORPHING_MORPH_SAVING_OFFSETS_H
diff --git a/include/core/operators/graph/degree_measurement.h b/include/core/operators/graph/degree_measurement.h
new file mode 100644
index 00000000..886a235d
--- /dev/null
+++ b/include/core/operators/graph/degree_measurement.h
@@ -0,0 +1,87 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file degree_measurement.h
+ * @brief computing a degree distribution of a given graph
+ * @todo multi-threaded impl? ; add tests
+ */
+
+#ifndef MORPHSTORE_DEGREE_MEASUREMENT
+#define MORPHSTORE_DEGREE_MEASUREMENT
+
+#include
+
+#include
+
+namespace morphstore {
+
+ class DegreeMeasurement {
+
+ public:
+ // function to return a list of pair < vertex id, degree > DESC:
+ static std::vector> get_list_of_degree_DESC(std::shared_ptr &graph) {
+ std::vector> vertexDegreeList;
+ auto vertex_count = graph->getVertexCount();
+ vertexDegreeList.reserve(vertex_count);
+
+ // fill the vector with every vertex key and his degree
+ for (uint64_t i = 0; i < vertex_count; ++i) {
+#if DEBUG
+ if (i % 10000 == 0) {
+ std::cout << "Degree-List - Current Progress" << i << "/" << vertex_count << std::endl;
+ }
+#endif
+ vertexDegreeList.push_back({i, graph->get_out_degree(i)});
+ }
+
+ // sort the vector on degree DESC
+ std::sort(vertexDegreeList.begin(), vertexDegreeList.end(),
+ [](const std::pair &left, const std::pair &right) {
+ return left.second > right.second;
+ });
+
+ return vertexDegreeList;
+ }
+
+ // function to measure graph characteristics (degree and count) and write the result to a given file:
+ static void measure_degree_count(std::shared_ptr graph, std::string filePath) {
+ std::vector> verticesDegree = get_list_of_degree_DESC(graph);
+ // unordered map for mapping degree to count:
+ std::unordered_map results;
+
+ for (uint64_t i = 0; i < verticesDegree.size(); ++i) {
+ // increment count in results for a given degree:
+ results[verticesDegree[i].second]++;
+ }
+
+ // write to file:
+ std::ofstream fs;
+ std::stringstream ss;
+ // open file for writing and delete existing stuff:
+ fs.open(filePath, std::fstream::out | std::ofstream::trunc);
+
+ for (auto const &m : results) {
+ ss << m.first << "," << m.second << "\n";
+ }
+ fs << ss.str();
+ fs.close();
+ }
+ };
+} // namespace morphstore
+
+#endif // MORPHSTORE_DEGREE_MEASUREMENT
diff --git a/include/core/operators/graph/page_rank.h b/include/core/operators/graph/page_rank.h
new file mode 100644
index 00000000..8512897b
--- /dev/null
+++ b/include/core/operators/graph/page_rank.h
@@ -0,0 +1,114 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file page_rank.h
+ * @brief naive page-rank implementation (based on https://en.wikipedia.org/wiki/PageRank)
+ * @todo multi-threaded impl? ; add tests; weighted implementation
+ */
+
+#ifndef MORPHSTORE_PAGE_RANK
+#define MORPHSTORE_PAGE_RANK
+
+#include
+
+// for equal with tolerance
+#include
+// for std::abs
+#include
+
+namespace morphstore {
+
+ struct PageRankResult {
+ // input parameters
+ uint64_t max_iterations;
+ float damping_factor, tolerance;
+
+ uint64_t ran_iterations = 0;
+ // terminated as scores converged?
+ bool converged;
+ // i-th entry for vertex with id i
+ std::vector scores;
+
+ // leaving out the scores
+ std::string describe() {
+ std::string converged_str = converged ? "True" : "False";
+ return "Input-Parameters: { damping-factor: " + std::to_string(damping_factor) +
+ ", max-iterations: " + std::to_string(max_iterations) +
+ ", tolerance: " + std::to_string(tolerance) + "} \n\t\t\t" +
+ "Computed: { converged: " + converged_str + ", ran_iterations: " + std::to_string(ran_iterations) +
+ "}";
+ }
+ };
+
+ class PageRank {
+
+ public:
+ // assuming a consecutive vertex id-space
+ static PageRankResult compute(std::shared_ptr graph, const uint64_t max_iterations = 20,
+ const float damping_factor = 0.85, const float tolerance = 0.0001) {
+ // init score vector with 1/vertex_count;
+ const uint64_t vertex_count = graph->getVertexCount();
+ std::vector scores(vertex_count, 1.0 / vertex_count);
+
+ uint64_t iteration;
+ bool converged = false;
+
+ for (iteration = 0; iteration < max_iterations; iteration++) {
+ // init scores of current iteration
+ std::vector new_scores(vertex_count, (1.0 - damping_factor) / vertex_count);
+
+ // loop over all vertices
+ for (uint64_t i = 0; i < vertex_count; ++i) {
+ const auto neighbors = graph->get_neighbors_ids(i);
+
+ // damping_factor * (prev-it-PR(i) / degr(i))
+ const auto value_to_propagate = damping_factor * (scores[i] / neighbors.size());
+
+ // propagate score to its neighbours
+ for (auto neighbor_id : neighbors) {
+ new_scores[neighbor_id] += value_to_propagate;
+ }
+ }
+
+ if (std::equal(scores.begin(), scores.end(), new_scores.begin(), new_scores.end(),
+ [tolerance](float score, float other_score) {
+ return std::abs(score - other_score) < tolerance;
+ })) {
+ converged = true;
+ break;
+ }
+
+ scores = new_scores;
+ }
+
+ // build result;
+ PageRankResult result;
+ result.damping_factor = damping_factor;
+ result.max_iterations = max_iterations;
+ result.tolerance = tolerance;
+
+ result.converged = converged;
+ result.ran_iterations = iteration;
+ result.scores = scores;
+
+ return result;
+ }
+ };
+} // namespace morphstore
+
+#endif // MORPHSTORE_PAGE_RANK
diff --git a/include/core/operators/graph/top_down_bfs.h b/include/core/operators/graph/top_down_bfs.h
new file mode 100644
index 00000000..3da7129d
--- /dev/null
+++ b/include/core/operators/graph/top_down_bfs.h
@@ -0,0 +1,128 @@
+/**********************************************************************************************
+ * Copyright (C) 2019-2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file top_down_bfs.h
+ * @brief top down BFS implementation to traverse graph
+ * @todo implement vectorized BFS (AVX2, AVX-512) ; return list of visited nodes + visiting depth maybe
+ */
+
+#ifndef MORPHSTORE_TOP_DOWN_BFS
+#define MORPHSTORE_TOP_DOWN_BFS
+
+#include
+#include
+
+#include
+
+namespace morphstore {
+ class BFS {
+
+ public:
+ // actual BFS algorithm: takes the start-node id and returns the number of explored vertices
+ static uint64_t compute(std::shared_ptr graph, uint64_t startVertex) {
+ std::vector frontier;
+ std::vector next;
+ std::vector visited(graph->getVertexCount(), false);
+ uint64_t exploredVertices = 0;
+
+ frontier.push_back(startVertex);
+ visited[startVertex] = true;
+
+ while (!frontier.empty()) {
+ // Loop through current layer of vertices in the frontier
+ for (uint64_t i = 0; i < frontier.size(); ++i) {
+ uint64_t currentVertex = frontier[i];
+ // get list of a vertex's adjacency
+ std::vector neighbors = graph->get_neighbors_ids(currentVertex);
+
+ // Loop through all of neighbors of current vertex
+ for (uint64_t j = 0; j < neighbors.size(); ++j) {
+ // check if neighbor has been visited, if not -> put into frontier and mark as visit = true
+ if (!visited[neighbors[j]]) {
+ next.push_back(neighbors[j]);
+ visited[neighbors[j]] = true;
+ ++exploredVertices;
+ }
+ }
+ }
+ // swap frontier with next
+ frontier.swap(next);
+ // clear next: swap with an empty container is faster
+ std::vector().swap(next);
+ }
+ return exploredVertices;
+ }
+
+ // ------------------------------------------ Measurement stuff ------------------------------------------
+
+ // function that measures the number of explored vertices and time in ms:
+ // results are written into a file; cycle determines the ith vertex from list
+ static void do_measurements(std::shared_ptr graph, uint64_t cycle, std::string pathToFile) {
+ // list of measurement candidates: the parameter means the ith vertex in total
+ std::vector candidates = get_list_of_every_ith_vertex(graph, cycle);
+
+ // Intermediate data structure: (explored vertices, time in ms)
+ std::vector> results;
+ results.reserve(candidates.size());
+
+ for (uint64_t i = 0; i < candidates.size(); ++i) {
+ // start measuring bfs time:
+ auto startBFSTime = std::chrono::high_resolution_clock::now();
+
+ uint64_t exploredVertices = compute(graph, candidates[i]);
+
+ auto finishBFSTime = std::chrono::high_resolution_clock::now(); // For measuring the execution time
+ auto elapsedBFSTime =
+ std::chrono::duration_cast(finishBFSTime - startBFSTime).count();
+
+ // write to intermediate array:
+ results.push_back({exploredVertices, elapsedBFSTime});
+ }
+
+ // WRITE INTERMEDIATES TO FILE:
+ std::ofstream fs;
+ std::stringstream ss;
+ std::string filename = pathToFile;
+ // open file for writing and delete existing stuff:
+ fs.open(filename, std::fstream::out | std::ofstream::trunc);
+
+ ss << "explored vertices | time in ms \n";
+
+ for (uint64_t j = 0; j < results.size(); j++) {
+ ss << results[j].first << "," << results[j].second << "\n";
+ }
+ fs << ss.str();
+
+ fs.close();
+ }
+
+ // function which returns a list of every ith vertex which is sorted by degree DESC
+ // TODO: could be seen as a generell helper function -> move into seperate header
+ static std::vector get_list_of_every_ith_vertex(std::shared_ptr graph, uint64_t cycle) {
+ std::vector measurementCandidates;
+ std::vector> totalListOfVertices =
+ DegreeMeasurement::get_list_of_degree_DESC(graph);
+ for (uint64_t i = 0; i < totalListOfVertices.size(); i = i + cycle) {
+ measurementCandidates.push_back(totalListOfVertices[i].first);
+ }
+ return measurementCandidates;
+ }
+ };
+} // namespace morphstore
+
+#endif // MORPHSTORE_TOP_DOWN_BFS
diff --git a/include/core/storage/column.h b/include/core/storage/column.h
index e590595f..45a7ecc4 100644
--- a/include/core/storage/column.h
+++ b/include/core/storage/column.h
@@ -42,8 +42,31 @@ enum class storage_persistence_type {
queryScope
};
+// template-free base class
+// use-case: graph formats can change their column format at run-time via `compress(Format f)`
+class column_base {
+ public:
+ virtual ~column_base() {}
+ // todo: find a way to specify `inline`
+ virtual voidptr_t get_data( void ) const = 0;
+ virtual size_t get_count_values( void ) const = 0;
+ virtual void set_count_values( size_t p_CountValues ) = 0;
+ virtual size_t get_size_used_byte( void ) const = 0;
+ virtual void set_size_used_byte( size_t p_SizeUsedByte ) = 0;
+ virtual size_t get_size_compr_byte( void ) const = 0;
+ virtual void set_size_compr_byte( size_t p_SizeComprByte ) = 0;
+ virtual void set_meta_data( size_t p_CountValues, size_t p_SizeUsedByte, size_t p_SizeComprByte ) = 0;
+ virtual void set_meta_data( size_t p_CountValues, size_t p_SizeUsedByte) = 0;
+
+ virtual const voidptr_t get_data_uncompr_start() const = 0;
+ virtual size_t get_count_values_uncompr() const = 0;
+ virtual size_t get_count_values_compr() const = 0;
+ // this is a template-method and cannot be defined here?
+ //virtual bool prepare_for_random_access() const = 0;
+};
+
template< class F >
-class column {
+class column : public column_base {
static_assert(
std::is_base_of< format, F >::value,
"column: template parameter F must be a subclass of format"
@@ -285,7 +308,5 @@ class column {
);
}
};
-
-
}
#endif //MORPHSTORE_CORE_STORAGE_COLUMN_H
diff --git a/include/core/storage/column_gen.h b/include/core/storage/column_gen.h
index f7e51bec..5dd2c154 100644
--- a/include/core/storage/column_gen.h
+++ b/include/core/storage/column_gen.h
@@ -47,12 +47,13 @@ namespace morphstore {
* elements.
*
* @param vec The vector to initialize the column with.
+ * @param sudo Overrule limit of 20
* @return An uncompressed column containing a copy of the data in the given
* vector.
*/
-const column * make_column(const std::vector & vec) {
+const column * make_column(const std::vector & vec, bool sudo = false) {
const size_t count = vec.size();
- if(count > 20)
+ if(count > 20 && !sudo)
throw std::runtime_error(
"make_column() is an inefficient convenience function and "
"should only be used for very small columns"
@@ -64,8 +65,8 @@ const column * make_column(const std::vector & vec) {
return resCol;
}
-const column * make_column(uint64_t const * const vec, size_t count) {
- if(count > 400)
+const column * make_column(uint64_t const * const vec, size_t count, bool sudo = false) {
+ if(count > 400 && !sudo)
throw std::runtime_error(
"make_column() is an inefficient convenience function and "
"should only be used for very small columns"
diff --git a/include/core/storage/column_with_blockoffsets.h b/include/core/storage/column_with_blockoffsets.h
new file mode 100644
index 00000000..35aa20dc
--- /dev/null
+++ b/include/core/storage/column_with_blockoffsets.h
@@ -0,0 +1,84 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file column_with_blockoffsets.h
+ * @brief Wrapper around column + its block-offsets
+ */
+
+#ifndef MORPHSTORE_CORE_STORAGE_COLUMN_WITH_BLOCKOFFSETS_H
+#define MORPHSTORE_CORE_STORAGE_COLUMN_WITH_BLOCKOFFSETS_H
+
+#include
+
+namespace morphstore {
+
+// interface (needed as current Graph formats don't use templates)
+class column_with_blockoffsets_base {
+ public:
+ virtual ~column_with_blockoffsets_base() {}
+
+ virtual const std::vector *get_block_offsets() = 0;
+ virtual const uint8_t *get_block_offset(size_t block_number) = 0;
+ virtual const column_base *get_column() = 0;
+ virtual size_t get_block_size() = 0;
+
+ size_t get_size_used_byte() {
+ return get_column()->get_size_used_byte() + (get_block_offsets()->size() * sizeof(uint8_t *));
+ }
+
+ bool last_block_compressed() {
+ return get_column()->get_count_values_uncompr() == 0;
+ }
+};
+
+// used to allow only partial decompression of column blocks (for random access)
+// blockoffsets should only be saved, if blocksize > 1
+template class column_with_blockoffsets : public column_with_blockoffsets_base {
+ static_assert(std::is_base_of::value, "column: template parameter F must be a subclass of format");
+
+ private:
+ const column *col;
+ // TODO: use std::optional
+ const std::vector *block_offsets;
+
+ public:
+ column_with_blockoffsets(const column *c)
+ : column_with_blockoffsets(c, new std::vector()) {
+ static_assert(F::m_BlockSize == 1, "need block offsets if block-size > 1");
+ }
+
+ column_with_blockoffsets(const column *c, std::vector *offsets) {
+ col = c;
+ block_offsets = offsets;
+ }
+
+ ~column_with_blockoffsets() {
+ // ? deleting the column might be not always wanted
+ delete col;
+ delete block_offsets;
+ }
+
+ const std::vector *get_block_offsets() { return block_offsets; }
+ const uint8_t *get_block_offset(size_t block_number) { return block_offsets->at(block_number); }
+
+ const column *get_column() { return col; }
+
+ inline size_t get_block_size() { return F::m_BlockSize; }
+};
+} // namespace morphstore
+#endif //MORPHSTORE_CORE_STORAGE_COLUMN_WITH_BLOCKOFFSETS_H
diff --git a/include/core/storage/graph/edge/edge.h b/include/core/storage/graph/edge/edge.h
new file mode 100644
index 00000000..b6d4e60a
--- /dev/null
+++ b/include/core/storage/graph/edge/edge.h
@@ -0,0 +1,178 @@
+/**********************************************************************************************
+ * Copyright (C) 2019 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file edge.h
+ * @brief Edge class which represents an edge object between two vertices
+ * @todo
+ */
+
+#ifndef MORPHSTORE_EDGE_H
+#define MORPHSTORE_EDGE_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace morphstore {
+
+ // for loading a graph
+ class Edge {
+
+ protected:
+ // Edge characteristics
+ uint64_t sourceId, targetId;
+ unsigned short int type;
+
+ public:
+ Edge() {}
+
+ virtual ~Edge() = default;
+
+ Edge(uint64_t sourceId, uint64_t targetId, unsigned short int type) {
+ this->sourceId = sourceId;
+ this->targetId = targetId;
+ this->type = type;
+ }
+
+ // --------------- Getter and Setter ---------------
+
+ uint64_t getSourceId() const { return sourceId; }
+
+ uint64_t getTargetId() const { return targetId; }
+
+ unsigned short getType() const { return type; }
+
+ // function for sorting algorithms in the ldbc-importer:
+ // compare target-ids and return if it's "lower" (we need the sorting for the CSR)
+ bool operator<(const Edge &e) const { return getTargetId() < e.getTargetId(); }
+
+ // get size of edge object in bytes:
+ static size_t size_in_bytes() {
+ size_t size = 0;
+ size += sizeof(uint64_t) * 2; // source- and target-id
+ size += sizeof(unsigned short int); // type
+ return size;
+ }
+
+ virtual std::string to_string() const {
+ return "(" + std::to_string(this->sourceId) + "->" + std::to_string(this->targetId) + ")";
+ }
+ };
+
+ // for internal usage (inside the edges-container)
+ class EdgeWithId : public Edge {
+ private:
+ uint64_t id;
+
+ // delete flag
+ // TODO: put as a std::bitset in vectorarray_container (as hashmap-container does not need the valid flag)
+ bool valid = false;
+
+ public:
+ // default constr. needed for EdgeWithProperties constructor
+ EdgeWithId() {}
+
+ EdgeWithId(uint64_t id, uint64_t sourceId, uint64_t targetId, unsigned short int type)
+ : Edge(sourceId, targetId, type) {
+ this->id = id;
+ this->valid = true;
+ }
+
+ EdgeWithId(uint64_t id, Edge edge) : Edge(edge.getSourceId(), edge.getTargetId(), edge.getType()) {
+ this->id = id;
+ this->valid = true;
+ }
+
+ uint64_t getId() const { return id; }
+
+ bool isValid() const { return valid; }
+
+ // this is needed for edges_container when doing edges[id] = edge
+ EdgeWithId &operator=(const EdgeWithId &edge) {
+ // self-assignment guard
+ if (this == &edge)
+ return *this;
+
+ // do the copy
+ this->sourceId = edge.getSourceId();
+ this->targetId = edge.getTargetId();
+ this->type = edge.getType();
+ this->id = edge.getId();
+ this->valid = edge.isValid();
+
+ // return the existing object so we can chain this operator
+ return *this;
+ }
+
+ // edge size + id and valid flag
+ static size_t size_in_bytes() { return Edge::size_in_bytes() + sizeof(uint64_t) + sizeof(bool); }
+
+ std::string to_string() const override {
+ return "(id:" + std::to_string(this->id) + " ," + "valid: " + std::to_string(this->valid) +
+ Edge::to_string() + ")";
+ }
+ };
+
+ // for loading
+ class EdgeWithProperties {
+ private:
+ std::unordered_map properties;
+ // not using inheritance as vector elements could not get cast to EdgeWithProperties
+ Edge edge;
+
+ public:
+ EdgeWithProperties(uint64_t sourceId, uint64_t targetId, unsigned short int type,
+ const std::unordered_map properties) {
+ this->edge = Edge(sourceId, targetId, type);
+ this->properties = properties;
+ }
+
+ EdgeWithProperties(uint64_t sourceId, uint64_t targetId, unsigned short int type) {
+ this->edge = Edge(sourceId, targetId, type);
+ }
+
+ Edge getEdge() const { return edge; }
+
+ std::unordered_map getProperties() { return properties; }
+
+ bool operator<(const EdgeWithProperties &e) const { return edge.getTargetId() < e.getEdge().getTargetId(); }
+ };
+
+ // for returning an edge to the user
+ class EdgeWithIdAndProperties {
+ private:
+ std::unordered_map properties;
+ EdgeWithId edge;
+
+ public:
+ EdgeWithIdAndProperties(EdgeWithId edge, const std::unordered_map properties) {
+ this->edge = edge;
+ this->properties = properties;
+ }
+ EdgeWithId getEdge() { return edge; }
+
+ std::unordered_map getProperties() { return properties; }
+ };
+} // namespace morphstore
+
+#endif // MORPHSTORE_EDGE_H
diff --git a/include/core/storage/graph/edge/edges_container.h b/include/core/storage/graph/edge/edges_container.h
new file mode 100644
index 00000000..62f4897b
--- /dev/null
+++ b/include/core/storage/graph/edge/edges_container.h
@@ -0,0 +1,167 @@
+/**********************************************************************************************
+ * Copyright (C) 2020 by MorphStore-Team *
+ * *
+ * This file is part of MorphStore - a compression aware vectorized column store. *
+ * *
+ * This program is free software: you can redistribute it and/or modify it under the *
+ * terms of the GNU General Public License as published by the Free Software Foundation, *
+ * either version 3 of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along with this program. *
+ * If not, see . *
+ **********************************************************************************************/
+
+/**
+ * @file edges_container.h
+ * @brief abstract class for storing edges
+ * @todo an EntityContainer abstraction (reduce duplicated code to vertices_container.h)
+ */
+
+#ifndef MORPHSTORE_EDGES_CONTAINER_H
+#define MORPHSTORE_EDGES_CONTAINER_H
+
+#include
+#include
+
+#include
+#include