diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..cea539388 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,67 @@ + +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node +{ + "name": "Vineyard", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "registry.cn-hongkong.aliyuncs.com/graphscope/graphscope-dev:latest", + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/common-utils:2":{ + "installZsh": "true", + "configureZshAsDefaultShell": "true", + "installOhMyZsh": true, + "upgradePackages": "false" + } + }, + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "settings": {}, + "extensions": [ + "streetsidesoftware.code-spell-checker", + "eamodio.gitlens" + ] + } + }, + + // Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "root" + + // Uncomment this to enable C++ and Rust debugging in containers + // "capAdd": ["SYS_PTRACE"], + // "securityOpt": ["seccomp=unconfined"], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [3000], + + // Use 'portsAttributes' to set default properties for specific forwarded ports. + // More info: https://containers.dev/implementors/json_reference/#port-attributes + // "portsAttributes": { + // "9000": { + // "label": "Hello Remote World", + // "onAutoForward": "notify" + // } + // }, + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install" + + // Improve performance + + // Uncomment these to mount a folder to a volume + // https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-a-targeted-named-volume + // "mounts": [ + // "source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume" + // ], + // "postCreateCommand": "sudo chown graphscope node_modules" + + + // Uncomment these to use a named volume for your entire source tree + // https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-a-named-volume-for-your-entire-source-tree + // "workspaceMount": "source=gs,target=/workspace,type=volume", + // "workspaceFolder": "/workspace" + // "postCreateCommand": "sudo chown -R graphscope:graphscope /workspace" +} diff --git a/.gitmodules b/.gitmodules index 63ca4a1e9..a233207bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -54,3 +54,6 @@ path = modules/graph/thirdparty/libgrape-lite url = https://github.com/alibaba/libgrape-lite.git shallow = true +[submodule "modules/graph/grin/include"] + path = modules/graph/grin/include + url = https://github.com/GraphScope/GRIN.git diff --git a/modules/basic/ds/arrow_utils.cc b/modules/basic/ds/arrow_utils.cc index 962885fcb..279a4651f 100644 --- a/modules/basic/ds/arrow_utils.cc +++ b/modules/basic/ds/arrow_utils.cc @@ -743,6 +743,62 @@ const void* get_arrow_array_data(std::shared_ptr const& array) { } } +const void* get_arrow_array_data_element(std::shared_ptr const& array, unsigned offset) { + if (array->type()->Equals(arrow::int8())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::uint8())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::int16())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::uint16())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::int32())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::uint32())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::int64())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::uint64())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::float32())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::float64())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array)->raw_values() + offset); + } else if (array->type()->Equals(arrow::utf8())) { + return reinterpret_cast(new std::string( + std::dynamic_pointer_cast(array).get()->GetView(offset))); + } else if (array->type()->Equals(arrow::large_utf8())) { + return reinterpret_cast(new std::string( + std::dynamic_pointer_cast(array).get()->GetView(offset))); + } else if (array->type()->id() == arrow::Type::LIST) { + return reinterpret_cast( + std::dynamic_pointer_cast(array).get() + offset); + } else if (array->type()->id() == arrow::Type::LARGE_LIST) { + return reinterpret_cast( + std::dynamic_pointer_cast(array).get() + offset); + } else if (array->type()->id() == arrow::Type::FIXED_SIZE_LIST) { + return reinterpret_cast( + std::dynamic_pointer_cast(array).get() + offset); + } else if (array->type()->Equals(arrow::null())) { + return reinterpret_cast( + std::dynamic_pointer_cast(array).get() + offset); + } else { + LOG(ERROR) << "Unsupported arrow array type '" << array->type()->ToString() + << "', type id: " << array->type()->id(); + return NULL; + } +} + Status TypeLoosen(const std::vector>& schemas, std::shared_ptr& schema) { int field_num = -1; diff --git a/modules/basic/ds/arrow_utils.h b/modules/basic/ds/arrow_utils.h index 98ddec8ca..c30dc2aea 100644 --- a/modules/basic/ds/arrow_utils.h +++ b/modules/basic/ds/arrow_utils.h @@ -285,6 +285,8 @@ std::string type_name_from_arrow_type( const void* get_arrow_array_data(std::shared_ptr const& array); +const void* get_arrow_array_data_element(std::shared_ptr const& array, unsigned offset); + Status TypeLoosen(const std::vector>& schemas, std::shared_ptr& schema); diff --git a/modules/graph/CMakeLists.txt b/modules/graph/CMakeLists.txt index b00b9bdb8..29c1bf1ad 100644 --- a/modules/graph/CMakeLists.txt +++ b/modules/graph/CMakeLists.txt @@ -8,6 +8,13 @@ file(GLOB_RECURSE VINEYARD_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}" "*.h") find_package(MPI REQUIRED) +find_package(libgrapelite REQUIRED) + +find_package(Protobuf REQUIRED) +include_directories(${Protobuf_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/grin/include/proto/graph.proto) + if(VINEYARD_MOD_SRCS) vineyard_generate( @@ -48,6 +55,8 @@ file(GLOB_RECURSE GRAPH_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}" "fragment/*.cc" "writer/*.cc" ) +message(${GRAPH_SRC_FILES}) + add_library(vineyard_graph ${GRAPH_SRC_FILES}) target_add_debuginfo(vineyard_graph) target_compile_options(vineyard_graph PUBLIC "-fopenmp") @@ -148,6 +157,7 @@ add_dependencies(vineyard_tests vineyard_graph_tests) if(BUILD_VINEYARD_TESTS) enable_testing() file(GLOB TEST_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/test" "${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc") + list(REMOVE_ITEM TEST_FILES "grin_test.cc") foreach(f ${TEST_FILES}) string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${f}) set(T_NAME ${CMAKE_MATCH_1}) @@ -168,3 +178,36 @@ if(BUILD_VINEYARD_TESTS) add_dependencies(vineyard_graph_tests ${T_NAME}) endforeach() endif() + +# grin lib +file(GLOB_RECURSE GRIN_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}" "grin/*.cc") +add_library(vineyard_grin ${GRIN_SRC_FILES} ${PROTO_SRCS} ${PROTO_HDRS}) +target_link_libraries(vineyard_grin PRIVATE vineyard_graph ${Protobuf_LIBRARIES}) +install_vineyard_target(vineyard_grin) + + +# grin test +if(BUILD_VINEYARD_TESTS) + enable_testing() + file(GLOB TEST_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/test" "${CMAKE_CURRENT_SOURCE_DIR}/test/grin_*.cc") + foreach(f ${TEST_FILES}) + string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${f}) + set(T_NAME ${CMAKE_MATCH_1}) + message(STATUS "Found unit_test - " ${T_NAME}) + if(BUILD_VINEYARD_TESTS_ALL) + add_executable(${T_NAME} test/${T_NAME}.cc) + else() + add_executable(${T_NAME} EXCLUDE_FROM_ALL test/${T_NAME}.cc) + endif() + target_link_libraries(${T_NAME} PRIVATE + vineyard_graph + vineyard_grin + ${Protobuf_LIBRARIES} + ${ARROW_SHARED_LIB} + ${MPI_CXX_LIBRARIES}) + if(${LIBUNWIND_FOUND}) + target_link_libraries(${T_NAME} PRIVATE ${LIBUNWIND_LIBRARIES}) + endif() + add_test(${T_NAME}, ${T_NAME}) + endforeach() +endif() \ No newline at end of file diff --git a/modules/graph/fragment/arrow_fragment.grin.h b/modules/graph/fragment/arrow_fragment.grin.h new file mode 100644 index 000000000..605d8dbe3 --- /dev/null +++ b/modules/graph/fragment/arrow_fragment.grin.h @@ -0,0 +1,684 @@ +/** Copyright 2020-2023 Alibaba Group Holding Limited. + +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 MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H +#define MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H + +#include +#include +#include +#include +#include +#include +#include + +#include "arrow/api.h" +#include "arrow/io/api.h" + +#include "grape/fragment/fragment_base.h" +#include "grape/graph/adj_list.h" +#include "grape/utils/vertex_array.h" + +#include "client/ds/core_types.h" +#include "client/ds/object_meta.h" + +#include "basic/ds/arrow.h" +#include "basic/ds/arrow_utils.h" +#include "common/util/typename.h" + +#include "graph/fragment/arrow_fragment_base.h" +#include "graph/fragment/fragment_traits.h" +#include "graph/fragment/graph_schema.h" +#include "graph/fragment/property_graph_types.h" +#include "graph/utils/error.h" +#include "graph/vertex_map/arrow_local_vertex_map.h" +#include "graph/vertex_map/arrow_vertex_map.h" + +#include "graph/grin/include/topology/structure.h" +#include "graph/grin/include/topology/vertexlist.h" +#include "graph/grin/include/topology/adjacentlist.h" +#include "graph/grin/include/partition/partition.h" +#include "graph/grin/include/partition/topology.h" +#include "graph/grin/include/partition/reference.h" +#include "graph/grin/include/property/type.h" +#include "graph/grin/include/property/property.h" +#include "graph/grin/include/property/propertylist.h" +#include "graph/grin/include/property/propertytable.h" +#include "graph/grin/include/property/topology.h" +#include "graph/grin/include/index/order.h" + +#include "graph/grin/src/predefine.h" + +namespace vineyard { + +std::shared_ptr GetArrowDataType(GRIN_DATATYPE type) { + switch (type) { + case GRIN_DATATYPE::Undefined: + return arrow::null(); + case GRIN_DATATYPE::Int32: + return arrow::int32(); + case GRIN_DATATYPE::UInt32: + return arrow::uint32(); + case GRIN_DATATYPE::Int64: + return arrow::int64(); + case GRIN_DATATYPE::UInt64: + return arrow::uint64(); + case GRIN_DATATYPE::Float: + return arrow::float32(); + case GRIN_DATATYPE::Double: + return arrow::float64(); + case GRIN_DATATYPE::String: + return arrow::large_utf8(); + case GRIN_DATATYPE::Date32: + return arrow::int32(); + case GRIN_DATATYPE::Date64: + return arrow::int64(); + default: + return arrow::null(); + } +} + + +struct GRIN_Nbr { + public: + GRIN_Nbr() : g_{nullptr}, al_(nullptr), cur_(0), ept_(nullptr) {} + GRIN_Nbr(GRIN_GRAPH g, GRIN_ADJACENT_LIST al, size_t cur, GRIN_EDGE_PROPERTY_TABLE ept) + : g_{g}, al_(al), cur_(cur), ept_(ept) {} + GRIN_Nbr(GRIN_Nbr& rhs) : g_{rhs.g_}, al_(rhs.al_), cur_(rhs.cur_), ept_(rhs.ept_) {} + + GRIN_Nbr& operator=(const GRIN_Nbr& rhs) { + g_ = rhs.g_; + al_ = rhs.al_; + cur_ = rhs.cur_; + ept_ = rhs.ept_; + return *this; + } + + GRIN_Nbr& operator=(GRIN_Nbr&& rhs) { + g_ = rhs.g_; + al_ = rhs.al_; + cur_ = rhs.cur_; + ept_ = rhs.ept_; + return *this; + } + + GRIN_VERTEX neighbor() { + return grin_get_neighbor_from_adjacent_list(g_, al_, cur_); + } + + GRIN_VERTEX get_neighbor() { + return grin_get_neighbor_from_adjacent_list(g_, al_, cur_); + } + + GRIN_EDGE get_edge() { + return grin_get_edge_from_adjacent_list(g_, al_, cur_); + } + + template + T get_data(GRIN_EDGE_PROPERTY prop) const { + auto _e = grin_get_edge_from_adjacent_list(g_, al_, cur_); + auto value = grin_get_value_from_edge_property_table(g_, ept_, _e, prop); + return property_graph_utils::ValueGetter::Value(value, 0); + } + + std::string get_str(GRIN_EDGE_PROPERTY prop) const { + auto _e = grin_get_edge_from_adjacent_list(g_, al_, cur_); + auto value = grin_get_value_from_edge_property_table(g_, ept_, _e, prop); + return property_graph_utils::ValueGetter::Value(value, 0); + } + + double get_double(GRIN_EDGE_PROPERTY prop) const { + auto _e = grin_get_edge_from_adjacent_list(g_, al_, cur_); + auto value = grin_get_value_from_edge_property_table(g_, ept_, _e, prop); + return property_graph_utils::ValueGetter::Value(value, 0); + } + + int64_t get_int(GRIN_EDGE_PROPERTY prop) const { + auto _e = grin_get_edge_from_adjacent_list(g_, al_, cur_); + auto value = grin_get_value_from_edge_property_table(g_, ept_, _e, prop); + return property_graph_utils::ValueGetter::Value(value, 0); + } + + inline GRIN_Nbr& operator++() { + cur_++; + return *this; + } + + inline GRIN_Nbr operator++(int) { + cur_++; + return *this; + } + + inline GRIN_Nbr& operator--() { + cur_--; + return *this; + } + + inline GRIN_Nbr operator--(int) { + cur_--; + return *this; + } + + inline bool operator==(const GRIN_Nbr& rhs) const { + return al_ == rhs.al_ && cur_ == rhs.cur_; + } + inline bool operator!=(const GRIN_Nbr& rhs) const { + return al_ != rhs.al_ || cur_ != rhs.cur_; + } + + inline bool operator<(const GRIN_Nbr& rhs) const { + return al_ == rhs.al_ && cur_ < rhs.cur_; + } + + inline GRIN_Nbr& operator*() { return *this; } + + private: + GRIN_GRAPH g_; + GRIN_ADJACENT_LIST al_; + size_t cur_; + GRIN_EDGE_PROPERTY_TABLE ept_; +}; + + +class GRIN_AdjList { + public: + GRIN_AdjList(): g_(nullptr), adj_list_(nullptr), ept_(nullptr), begin_(0), end_(0) {} + GRIN_AdjList(GRIN_GRAPH g, GRIN_ADJACENT_LIST adj_list, GRIN_EDGE_PROPERTY_TABLE ept, size_t begin, size_t end) + : g_{g}, adj_list_(adj_list), ept_(ept), begin_(begin), end_(end) {} + + inline GRIN_Nbr begin() const { + return GRIN_Nbr(g_, adj_list_, begin_, ept_); + } + + inline GRIN_Nbr end() const { + return GRIN_Nbr(g_, adj_list_, end_, ept_); + } + + inline size_t Size() const { return end_ - begin_; } + + inline bool Empty() const { return begin_ == end_; } + + inline bool NotEmpty() const { return begin_ < end_; } + + size_t size() const { return end_ - begin_; } + + private: + GRIN_GRAPH g_; + GRIN_ADJACENT_LIST adj_list_; + GRIN_EDGE_PROPERTY_TABLE ept_; + size_t begin_; + size_t end_; +}; + + +class GRIN_VertexRange { + public: + GRIN_VertexRange() {} + GRIN_VertexRange(GRIN_GRAPH g, GRIN_VERTEX_LIST vl, const size_t begin, const size_t end) + : g_(g), vl_(vl), begin_(begin), end_(end) {} + GRIN_VertexRange(const GRIN_VertexRange& r) : g_(r.g_), vl_(r.vl_), begin_(r.begin_), end_(r.end_) {} + + class iterator { + using reference_type = GRIN_VERTEX; + + private: + GRIN_GRAPH g_; + GRIN_VERTEX_LIST vl_; + size_t cur_; + + public: + iterator() noexcept : g_(nullptr), vl_(nullptr), cur_() {} + explicit iterator(GRIN_GRAPH g, GRIN_VERTEX_LIST vl, size_t idx) noexcept : g_(g), vl_(vl), cur_(idx) {} + + reference_type operator*() noexcept { return grin_get_vertex_from_list(g_, vl_, cur_); } + + iterator& operator++() noexcept { + ++cur_; + return *this; + } + + iterator operator++(int) noexcept { + return iterator(g_, vl_, cur_ + 1); + } + + iterator& operator--() noexcept { + --cur_; + return *this; + } + + iterator operator--(int) noexcept { + return iterator(g_, vl_, cur_--); + } + + iterator operator+(size_t offset) const noexcept { + return iterator(g_, vl_, cur_ + offset); + } + + bool operator==(const iterator& rhs) const noexcept { + return cur_ == rhs.cur_; + } + + bool operator!=(const iterator& rhs) const noexcept { + return cur_ != rhs.cur_; + } + + bool operator<(const iterator& rhs) const noexcept { + return vl_ == rhs.vl_ && cur_ < rhs.cur_; + } + }; + + iterator begin() const { return iterator(g_, vl_, begin_); } + + iterator end() const { return iterator(g_, vl_, end_); } + + size_t size() const { return end_ - begin_; } + + void Swap(GRIN_VertexRange& rhs) { + std::swap(begin_, rhs.begin_); + std::swap(end_, rhs.end_); + } + + void SetRange(const size_t begin, const size_t end) { + begin_ = begin; + end_ = end; + } + + const size_t begin_value() const { return begin_; } + + const size_t end_value() const { return end_; } + + private: + GRIN_GRAPH g_; + GRIN_VERTEX_LIST vl_; + size_t begin_; + size_t end_; +}; + + +class GRIN_ArrowFragment { + public: + using vertex_range_t = GRIN_VertexRange; + using adj_list_t = GRIN_AdjList; + + public: + ~GRIN_ArrowFragment() = default; + + void init(GRIN_PARTITIONED_GRAPH partitioned_graph, GRIN_PARTITION partition) { + pg_ = partitioned_graph; + partition_ = partition; + g_ = grin_get_local_graph_by_partition(pg_, partition_); + } + + bool directed() const { + return grin_is_directed(g_); + } + + bool multigraph() const { + return grin_is_multigraph(g_); + } + + const std::string oid_typename() const { + auto dt = grin_get_vertex_original_id_type(g_); + return GetDataTypeName(dt); + } + + size_t fnum() const { return grin_get_total_partitions_number(pg_); } + + GRIN_VERTEX_TYPE vertex_label(GRIN_VERTEX v) { + return grin_get_vertex_type(g_, v); + } + + size_t vertex_label_num() const { + auto vtl = grin_get_vertex_type_list(g_); + return grin_get_vertex_type_list_size(g_, vtl); + } + + size_t edge_label_num() const { + auto etl = grin_get_edge_type_list(g_); + return grin_get_edge_type_list_size(g_, etl); + } + + size_t vertex_property_num(GRIN_VERTEX_TYPE label) const { + auto vpl = grin_get_vertex_property_list_by_type(g_, label); + return grin_get_vertex_property_list_size(g_, vpl); + } + + std::shared_ptr vertex_property_type(GRIN_VERTEX_PROPERTY prop) const { + auto dt = grin_get_vertex_property_data_type(g_, prop); + return GetArrowDataType(dt); + } + + size_t edge_property_num(GRIN_EDGE_TYPE label) const { + auto epl = grin_get_edge_property_list_by_type(g_, label); + return grin_get_edge_property_list_size(g_, epl); + } + + std::shared_ptr edge_property_type(GRIN_EDGE_PROPERTY prop) const { + auto dt = grin_get_edge_property_data_type(g_, prop); + return GetArrowDataType(dt); + } + + vertex_range_t Vertices(GRIN_VERTEX_TYPE label) const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto sz = grin_get_vertex_list_size(g_, vl1); + return vertex_range_t(g_, vl1, 0, sz); + } + + vertex_range_t InnerVertices(GRIN_VERTEX_TYPE label) const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto vl2 = grin_filter_master_for_vertex_list(g_, vl1); + auto sz = grin_get_vertex_list_size(g_, vl2); + return vertex_range_t(g_, vl2, 0, sz); + } + + vertex_range_t OuterVertices(GRIN_VERTEX_TYPE label) const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto vl2 = grin_filter_mirror_for_vertex_list(g_, vl1); + auto sz = grin_get_vertex_list_size(g_, vl2); + return vertex_range_t(g_, vl2, 0, sz); + } + + vertex_range_t InnerVerticesSlice(GRIN_VERTEX_TYPE label, size_t start, size_t end) + const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto vl2 = grin_filter_master_for_vertex_list(g_, vl1); + auto _end = grin_get_vertex_list_size(g_, vl2); + CHECK(start <= end && start <= _end); + if (end <= _end) { + return vertex_range_t(g_, vl2, start, end); + } else { + return vertex_range_t(g_, vl2, start, _end); + } + } + + inline size_t GetVerticesNum(GRIN_VERTEX_TYPE label) const { + return grin_get_vertex_num_by_type(g_, label); + } + + template + bool GetVertex(GRIN_VERTEX_TYPE label, T& oid, GRIN_VERTEX v) { + if (GRIN_DATATYPE_ENUM::value != grin_get_vertex_original_id_type(g_)) return false; + v = grin_get_vertex_by_original_id_by_type(g_, label, (GRIN_VERTEX_ORIGINAL_ID)(&oid)); + return v != NULL; + } + + template + bool GetId(GRIN_VERTEX v, T& oid) { + if (GRIN_DATATYPE_ENUM::value != grin_get_vertex_original_id_type(g_)) return false; + auto _id = grin_get_vertex_original_id(g_, v); + if (_id == NULL) return false; + auto _oid = static_cast(_id); + oid = *_oid; + return true; + } + +#ifdef GRIN_NATURAL_PARTITION_ID_TRAIT + GRIN_PARTITION_ID GetPartition(GRIN_VERTEX u) const { + auto vref = grin_get_vertex_ref_by_vertex(g_, u); + auto partition = grin_get_master_partition_from_vertex_ref(g_, vref); + return grin_get_partition_id(pg_, partition); + } +#endif + + size_t GetTotalNodesNum() const { + return GetTotalVerticesNum(); + } + + size_t GetTotalVerticesNum() const { + return grin_get_vertex_num(g_); + } + + size_t GetTotalVerticesNum(GRIN_VERTEX_TYPE label) const { + return grin_get_vertex_num_by_type(g_, label); + } + + size_t GetEdgeNum() const { return grin_get_edge_num(g_, GRIN_DIRECTION::BOTH); } + size_t GetInEdgeNum() const { return grin_get_edge_num(g_, GRIN_DIRECTION::IN); } + size_t GetOutEdgeNum() const { return grin_get_edge_num(g_, GRIN_DIRECTION::OUT); } + + template + bool GetData(GRIN_VERTEX v, GRIN_VERTEX_PROPERTY prop, T& value) const { + if (GRIN_DATATYPE_ENUM::value != grin_get_vertex_property_data_type(g_, prop)) return false; + auto vtype = grin_get_vertex_type(g_, v); + auto vpt = grin_get_vertex_property_table_by_type(g_, vtype); + auto _value = grin_get_value_from_vertex_property_table(g_, vpt, v, prop); + if (_value != NULL) { + value = *(static_cast(_value)); + return true; + } + return false; + } + + template + bool GetData(GRIN_VERTEX_PROPERTY_TABLE vpt, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY prop, T& value) const { + if (GRIN_DATATYPE_ENUM::value != grin_get_vertex_property_data_type(g_, prop)) return false; + auto _value = grin_get_value_from_vertex_property_table(g_, vpt, v, prop); + if (_value != NULL) { + value = *(static_cast(_value)); + return true; + } + return false; + } + + GRIN_VERTEX_PROPERTY_TABLE GetVertePropertyTable(GRIN_VERTEX_TYPE label) { + return grin_get_vertex_property_table_by_type(g_, label); + } + + bool HasChild(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) const { + return GetLocalOutDegree(v, e_label) != 0; + } + + bool HasParent(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) const { + return GetLocalInDegree(v, e_label) != 0; + } + + int GetLocalOutDegree(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) const { + return GetOutgoingAdjList(v, e_label).Size(); + } + + int GetLocalInDegree(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) const { + return GetIncomingAdjList(v, e_label).Size(); + } + + + inline size_t GetInnerVerticesNum(GRIN_VERTEX_TYPE label) const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto vl2 = grin_filter_master_for_vertex_list(g_, vl1); + return grin_get_vertex_list_size(g_, vl2); + } + + inline size_t GetOuterVerticesNum(GRIN_VERTEX_TYPE label) const { + auto vl = grin_get_vertex_list(g_); + auto vl1 = grin_filter_type_for_vertex_list(g_, label, vl); + auto vl2 = grin_filter_mirror_for_vertex_list(g_, vl1); + return grin_get_vertex_list_size(g_, vl2); + } + + inline bool IsInnerVertex(GRIN_VERTEX v) const { + return grin_is_master_vertex(g_, v); + } + + inline bool IsOuterVertex(GRIN_VERTEX v) const { + return grin_is_mirror_vertex(g_, v); + } + + inline adj_list_t GetIncomingAdjList(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) + const { + auto al = grin_get_adjacent_list(g_, GRIN_DIRECTION::IN, v); + auto al1 = grin_filter_edge_type_for_adjacent_list(g_, e_label, al); + auto sz = grin_get_adjacent_list_size(g_, al1); + auto ept = grin_get_edge_property_table_by_type(g_, e_label); + return adj_list_t(g_, al1, ept, 0, sz); + } + + inline adj_list_t GetOutgoingAdjList(GRIN_VERTEX v, GRIN_EDGE_TYPE e_label) + const { + auto al = grin_get_adjacent_list(g_, GRIN_DIRECTION::OUT, v); + auto al1 = grin_filter_edge_type_for_adjacent_list(g_, e_label, al); + auto sz = grin_get_adjacent_list_size(g_, al1); + auto ept = grin_get_edge_property_table_by_type(g_, e_label); + return adj_list_t(g_, al1, ept, 0, sz); + } + + GRIN_GRAPH get_graph() { return g_; } + + // pos means the vertex position in the inner vertex list under vertex type + inline grape::DestList IEDests(GRIN_VERTEX_TYPE v_label, size_t pos, GRIN_EDGE_TYPE e_label) const { +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + auto vtype = static_cast(v_label); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + auto etype = static_cast(e_label); +#endif + + return grape::DestList(idoffset_[*vtype][*etype][pos], + idoffset_[*vtype][*etype][pos + 1]); + } + + inline grape::DestList OEDests(GRIN_VERTEX_TYPE v_label, size_t pos, GRIN_EDGE_TYPE e_label) const { +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + auto vtype = static_cast(v_label); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + auto etype = static_cast(e_label); +#endif + + return grape::DestList(odoffset_[*vtype][*etype][pos], + odoffset_[*vtype][*etype][pos + 1]); + } + + inline grape::DestList IOEDests(GRIN_VERTEX_TYPE v_label, size_t pos, GRIN_EDGE_TYPE e_label) const { +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + auto vtype = static_cast(v_label); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + auto etype = static_cast(e_label); +#endif + + return grape::DestList(iodoffset_[*vtype][*etype][pos], + iodoffset_[*vtype][*etype][pos + 1]); + } + + void initDestFidList( + bool in_edge, bool out_edge, + std::vector>>& fid_lists, + std::vector>>& fid_lists_offset) { + auto vtl = grin_get_vertex_type_list(g_); + auto vtl_sz = grin_get_vertex_type_list_size(g_, vtl); + auto etl = grin_get_edge_type_list(g_); + auto etl_sz = grin_get_edge_type_list_size(g_, etl); + + for (auto vti = 0; vti < vtl_sz; vti++) { + auto vtype = grin_get_vertex_type_from_list(g_, vtl, vti); + auto inner_vertices = InnerVertices(vtype); + auto ivnum_ = inner_vertices.size(); + + for (auto eti = 0; eti < etl_sz; eti++) { + std::vector id_num(ivnum_, 0); + std::set dstset; + + auto etype = grin_get_edge_type_from_list(g_, etl, eti); + auto v = inner_vertices.begin(); + auto& fid_list = fid_lists[vti][eti]; + auto& fid_list_offset = fid_lists_offset[vti][eti]; + + if (!fid_list_offset.empty()) { + return; + } + fid_list_offset.resize(ivnum_ + 1, NULL); + for (auto i = 0; i < ivnum_; ++i) { + dstset.clear(); + + if (in_edge) { + auto es = GetIncomingAdjList(*v, etype); + for (auto& e : es) { + auto vref = grin_get_vertex_ref_by_vertex(g_, e.neighbor()); + auto p = grin_get_master_partition_from_vertex_ref(g_, vref); + + if (!grin_equal_partition(g_, p, partition_)) { +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION + auto f = static_cast(p); + dstset.insert(*f); +#else + // todo +#endif + } + } + } + if (out_edge) { + auto es = GetOutgoingAdjList(*v, etype); + for (auto& e : es) { + auto vref = grin_get_vertex_ref_by_vertex(g_, e.neighbor()); + auto p = grin_get_master_partition_from_vertex_ref(g_, vref); + + if (!grin_equal_partition(g_, p, partition_)) { +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION + auto f = static_cast(p); + dstset.insert(*f); +#else + // todo +#endif + } + } + } + id_num[i] = dstset.size(); + for (auto fid : dstset) { + fid_list.push_back(fid); + } + ++v; + } + + fid_list.shrink_to_fit(); + fid_list_offset[0] = fid_list.data(); + for (auto i = 0; i < ivnum_; ++i) { + fid_list_offset[i + 1] = fid_list_offset[i] + id_num[i]; + } + } + } + } + + void PrepareToRunApp(const grape::CommSpec& comm_spec, grape::PrepareConf conf) { + if (conf.message_strategy == + grape::MessageStrategy::kAlongEdgeToOuterVertex) { + initDestFidList(true, true, iodst_, iodoffset_); + } else if (conf.message_strategy == + grape::MessageStrategy::kAlongIncomingEdgeToOuterVertex) { + initDestFidList(true, false, idst_, idoffset_); + } else if (conf.message_strategy == + grape::MessageStrategy::kAlongOutgoingEdgeToOuterVertex) { + initDestFidList(false, true, odst_, odoffset_); + } + } + + private: + GRIN_PARTITIONED_GRAPH pg_; + GRIN_GRAPH g_; + GRIN_PARTITION partition_; + std::vector>> idst_, odst_, iodst_; + std::vector>> idoffset_, odoffset_, + iodoffset_; +}; + +} // namespace vineyard + +#endif // MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H diff --git a/modules/graph/fragment/arrow_fragment.grin.idea b/modules/graph/fragment/arrow_fragment.grin.idea new file mode 100644 index 000000000..30ad8ba1c --- /dev/null +++ b/modules/graph/fragment/arrow_fragment.grin.idea @@ -0,0 +1,1026 @@ +/** Copyright 2020-2023 Alibaba Group Holding Limited. + +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 MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H +#define MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H + +#include +#include +#include +#include +#include +#include +#include + +#include "arrow/api.h" +#include "arrow/io/api.h" + +#include "grape/fragment/fragment_base.h" +#include "grape/graph/adj_list.h" +#include "grape/utils/vertex_array.h" + +#include "client/ds/core_types.h" +#include "client/ds/object_meta.h" + +#include "basic/ds/arrow.h" +#include "basic/ds/arrow_utils.h" +#include "common/util/typename.h" + +#include "graph/fragment/arrow_fragment_base.h" +#include "graph/fragment/fragment_traits.h" +#include "graph/fragment/graph_schema.h" +#include "graph/fragment/property_graph_types.h" +#include "graph/utils/error.h" +#include "graph/vertex_map/arrow_local_vertex_map.h" +#include "graph/vertex_map/arrow_vertex_map.h" + +extern "C" { +#include "graph/grin/include/topology/structure.h" +#include "graph/grin/include/topology/vertexlist.h" +#include "graph/grin/include/topology/edgelist.h" +#include "graph/grin/include/topology/adjacentlist.h" +#include "graph/grin/include/partition/partition.h" +#include "graph/grin/include/propertygraph/label.h" +#include "graph/grin/include/propertygraph/property.h" +#include "graph/grin/include/propertygraph/propertygraph.h" +} + +namespace gs { + +template +class ArrowProjectedFragment; + +} // namespace gs + +namespace vineyard { + +template +struct GRIN_Nbr { + private: + using vid_t = VID_T; + using eid_t = EID_T; + using prop_id_t = property_graph_types::PROP_ID_TYPE; + + public: + GRIN_Nbr(void* g, void* edge_label, void* adj_list, size_t current) { + g_ = g; + edge_label_ = edge_label; + adj_list_ = adj_list; + current_ = current; + if (current_ == 0) { + adj_list_iter_ = get_adjacent_list_begin(adj_list_); + property_list_ = get_all_edge_properties_from_label(edge_label_); + } else { + adj_list_iter_ = nullptr; + } + } + + grape::Vertex neighbor() const { + return grape::Vertex(neighbor_); + } + + grape::Vertex get_neighbor() const { + return grape::Vertex(neighbor_); + } + + EID_T edge_id() const { return eid_; } + + void* get_data(prop_id_t prop_id) const { + void* _row = get_edge_row(g_, edge_, property_list_); + void* _property = get_edge_property_from_id(edge_label_, prop_id); + return get_property_value_from_row(_row, _property); + } + + template + T get_data(prop_id_t prop_id) const { + void* _data = get_data(prop_id); + return *(static_cast(_data)); + } + + std::string get_str(prop_id_t prop_id) const { + void* _data = get_data(prop_id); + return *(static_cast(_data)); + } + + double get_double(prop_id_t prop_id) const { + void* _data = get_data(prop_id); + return *(static_cast(_data)); + } + + int64_t get_int(prop_id_t prop_id) const { + void* _data = get_data(prop_id); + return *(static_cast(_data)); + } + + inline const GRIN_Nbr& operator++() const { + ++current_; + add_current_value(); + return *this; + } + + inline bool operator==(const GRIN_Nbr& rhs) const { + return (current_ == rhs.current_) && (adj_list_ == rhs.adj_list_); + } + + inline bool operator!=(const GRIN_Nbr& rhs) const { + return (current_ != rhs.current_) || (adj_list_ != rhs.adj_list_); + } + + inline bool operator<(const GRIN_Nbr& rhs) const { + return (current_ < rhs.current_) && (adj_list_ == rhs.adj_list_);; + } + + inline const GRIN_Nbr& operator*() const { return *this; } + + private: + void add_current_value() { + adj_list_iter_ = get_next_adjacent_iter(adj_list_, adj_list_iter_); + void* _v = get_neighbor_from_iter(adj_list_, adj_list_iter_); + void* _vid = get_vertex_id(_v); + neighbor_ = *(static_cast(_vid)); + edge_ = get_edge_from_iter(adj_list_, adj_list_iter); + } + + void* g_; + void* edge_label_; + void* property_list_; + void* adj_list_; + void* adj_list_iter_; + size_t current_; + VID_T neighbor_; + void* edge_; +}; + +template +using GRIN_NbrDefault = GRIN_Nbr; + +template +class GRIN_AdjList { + public: + GRIN_AdjList() : g_(NULL), edge_label_(NULL), adj_list_(NULL), sz_(0), begin_(0), end_(0) {} + GRIN_AdjList(void* g, void* edge_label, void* adj_list, size_t sz) + : g_(g), edge_label_(edge_label), adj_list_(adj_list), sz_(sz), begin_(0), end_(sz) {} + + inline GRIN_Nbr begin() const { + return GRIN_Nbr(g_, edge_label_, adj_list_, begin_); + } + + inline GRIN_Nbr end() const { + return GRIN_Nbr(g_, edge_label_, adj_list_, end_); + } + + inline size_t Size() const { return sz_; } + + inline bool Empty() const { return sz_ == 0; } + + inline bool NotEmpty() const { return sz_ > 0; } + + size_t size() const { return sz_; } + + //inline const NbrUnit* begin_unit() const { return begin_; } + + //inline const NbrUnit* end_unit() const { return end_; } + + private: + const void* g_; + const void* edge_label_; + const void* adj_list_; + const size_t sz_; + const size_t begin_; + const size_t end_; +}; + +template +using GRIN_AdjListDefault = AdjList; + + +inline std::string generate_name_with_suffix( + const std::string& prefix, property_graph_types::LABEL_ID_TYPE label) { + return prefix + "_" + std::to_string(label); +} + +inline std::string generate_name_with_suffix( + const std::string& prefix, property_graph_types::LABEL_ID_TYPE v_label, + property_graph_types::LABEL_ID_TYPE e_label) { + return prefix + "_" + std::to_string(v_label) + "_" + std::to_string(e_label); +} + +template +class ArrowFragmentBaseBuilder; + +template ::type, VID_T>> +class __attribute__((annotate("vineyard"))) GRIN_ArrowFragment + : public ArrowFragmentBase, + public vineyard::BareRegistered< + ArrowFragment> { +public: + using oid_t = OID_T; + using vid_t = VID_T; + using internal_oid_t = typename InternalType::type; + using eid_t = property_graph_types::EID_TYPE; + using prop_id_t = property_graph_types::PROP_ID_TYPE; + using label_id_t = property_graph_types::LABEL_ID_TYPE; + using vertex_range_t = grape::VertexRange; + using inner_vertices_t = vertex_range_t; + using outer_vertices_t = vertex_range_t; + using vertices_t = vertex_range_t; + using nbr_t = property_graph_utils::Nbr; + using nbr_unit_t = property_graph_utils::NbrUnit; + using adj_list_t = property_graph_utils::AdjList; + using raw_adj_list_t = property_graph_utils::RawAdjList; + using vertex_map_t = VERTEX_MAP_T; + using vertex_t = grape::Vertex; + + using ovg2l_map_t = + ska::flat_hash_map::KeyHash>; + + using vid_array_t = ArrowArrayType; + using vid_vineyard_array_t = ArrowVineyardArrayType; + using vid_vineyard_builder_t = ArrowVineyardBuilderType; + using eid_array_t = ArrowArrayType; + using eid_vineyard_array_t = ArrowVineyardArrayType; + using eid_vineyard_builder_t = ArrowVineyardBuilderType; + + using vid_builder_t = ArrowBuilderType; + + template + using vertex_array_t = grape::VertexArray; + + template + using inner_vertex_array_t = grape::VertexArray; + + template + using outer_vertex_array_t = grape::VertexArray; + + static constexpr grape::LoadStrategy load_strategy = + grape::LoadStrategy::kBothOutIn; + + public: + ~GRIN_ArrowFragment() = default; + // hide vertex_map + // vineyard::ObjectID vertex_map_id() const override { return vm_ptr_->id(); } + + void init(void* partitioned_graph) { + pg_ = partitioned_graph; + assert(get_partition_list_size(pg_) == 1); + auto pl = get_local_partitions(pg_); + auto p = get_partition_from_list(pl, 0); + g_ = get_local_graph_from_partition(pg_, p); + + directed_ = is_directed(g_); + is_multigraph_ = is_multigraph(g_); + fid_ = p; + fnum_ = get_total_partitions_number(pg_); + } + + bool directed() const override { + return directed_; + } + + bool is_multigraph() const override { + return is_multigraph_; + } + + const std::string vid_typename() const override { + auto dt = get_vertex_id_data_type(g_); + return GetDataTypeName(dt); + } + + const std::string oid_typename() const override { + auto dt = DataTypeEnum::value(); + return GetDataTypeName(dt); + } + + fid_t fid() const { return fid_; } + + fid_t fnum() const { return fnum_; } + + void* vertex_label(const void* v) { + return get_vertex_label(g_, v); + } + + label_id_t vertex_label(const vertex_t& v) const { + void* _v = get_vertex_from_id(v.GetValue()); + void* _label = vertex_label(_v); + void* _label_id = get_label_id(g_, _label); + return *(static_cast(_label_id)) + } + +// int64_t vertex_offset(const vertex_t& v) const { +// // to remove ---- +// return vid_parser_.GetOffset(v.GetValue()); +// } + + label_id_t vertex_label_num() const { + void* vll = get_vertex_labels(g_); + return get_vertex_label_list_size(vll); + } + + label_id_t edge_label_num() const { + void* ell = get_edge_labels(g_); + return get_edge_label_list_size(ell); + } + + prop_id_t vertex_property_num(label_id_t label) const { + void* _label = get_vertex_label_from_id((void*)(&label)); + void* vpl = get_all_vertex_properties_from_label(g_, _label); + return get_property_list_size(vpl); + } + + std::shared_ptr vertex_property_type(label_id_t label, + prop_id_t prop) const { + void* _label = get_vertex_label_from_id(label) + void* _property = get_vertex_property_from_id(_label, prop); + auto dt = get_property_type(_g, _property); + return GetArrowDataType(dt); + } + + prop_id_t edge_property_num(label_id_t label) const { + void* _label = get_edge_label_from_id((void*)(&label)); + void* epl = get_all_edge_properties_from_label(g_, _label); + return get_property_list_size(epl); + } + + std::shared_ptr edge_property_type(label_id_t label, + prop_id_t prop) const { + void* _label = get_edge_label_from_id(label) + void* _property = get_edge_property_from_id(_label, prop); + auto dt = get_property_type(_g, _property); + return GetArrowDataType(dt); + } + +// std::shared_ptr vertex_data_table(label_id_t i) const { +// // maybe we should get rid of the method +// // there is no way we can provide the whole data with a C-style api +// return vertex_tables_[i]->GetTable(); +// } + +// std::shared_ptr edge_data_table(label_id_t i) const { +// // Ditto. +// return edge_tables_[i]->GetTable(); +// } + +// template +// property_graph_utils::EdgeDataColumn edge_data_column( +// label_id_t label, prop_id_t prop) const { +// // get rid of this method and EdgeDataColumn structure +// // this structure actually serves to get a specific property of an edge +// // and it can be replaced by grin property get_edge_row +// if (edge_tables_[label]->num_rows() == 0) { +// return property_graph_utils::EdgeDataColumn(); +// } else { +// // the finalized etables are guaranteed to have been concatenated +// return property_graph_utils::EdgeDataColumn( +// edge_tables_[label]->column(prop)->chunk(0)); +// } +// } + +// template +// property_graph_utils::VertexDataColumn vertex_data_column( +// label_id_t label, prop_id_t prop) const { +// // Ditto. it can be replaced by grin property get_vertex_row && get_property_value_from_row +// if (vertex_tables_[label]->num_rows() == 0) { +// return property_graph_utils::VertexDataColumn( +// InnerVertices(label)); +// } else { +// // the finalized vtables are guaranteed to have been concatenated +// return property_graph_utils::VertexDataColumn( +// InnerVertices(label), vertex_tables_[label]->column(prop)->chunk(0)); +// } +// } + + vertex_range_t Vertices(label_id_t label_id) const { + //continuous vid trait + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_vertex_list_by_label(pg_, fid_, _label); + void* beginh = get_begin_vertex_id_from_list(vlh); + VID_T* begin = static_cast(beginh); + void* endh = get_end_vertex_id_from_list(vlh); + VID_T* end = static_cast(endh); + return vertex_range_t(*begin, *end); + } + + vertex_range_t InnerVertices(label_id_t label_id) const { + //continuous vid trait + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_local_vertices_by_label(pg_, fid_, _label); + void* beginh = get_begin_vertex_id_from_list(vlh); + VID_T* begin = static_cast(beginh); + void* endh = get_end_vertex_id_from_list(vlh); + VID_T* end = static_cast(endh); + return vertex_range_t(*begin, *end); + } + + vertex_range_t OuterVertices(label_id_t label_id) const { + //continuous vid trait + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_remote_vertices_by_label(pg_, fid_, _label); + void* beginh = get_begin_vertex_id_from_list(vlh); + VID_T* begin = static_cast(beginh); + void* endh = get_end_vertex_id_from_list(vlh); + VID_T* end = static_cast(endh); + return vertex_range_t(*begin, *end); + } + + vertex_range_t InnerVerticesSlice(label_id_t label_id, vid_t start, vid_t end) + const { + // continuous_vid_traits + vertex_range_t vr = InnerVertices(label_id); + size_t _end = vr.size(); + CHECK(start <= end && start <= _end); + if (end <= _end) { + return vr.SetRange(start, end); + } else { + return vr.SetRange(start, _end); + } + } + + inline vid_t GetVerticesNum(label_id_t label_id) const { + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_vertex_list_by_label(pg_, fid_, _label); + return get_vertex_list_size(vlh); + } + + bool GetVertex(label_id_t label, const oid_t& oid, vertex_t& v) const { + void* _label = get_vertex_label_from_id((void*)(&label)); + void* _v = get_vertex_from_label_origin_id(_label, (void*)(&oid)); + if (_v == NULL_VERTEX) { + return false; + } + void* _id = get_vertex_id(_v); + v.SetValue(*(static_cast(_id))); + return true; + } + + oid_t GetId(const vertex_t& v) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _id = get_vertex_origin_id(_v); + return *(static_cast(_id)); + } + +// internal_oid_t GetInternalId(const vertex_t& v) const { +// return IsInnerVertex(v) ? GetInnerVertexInternalId(v) +// : GetOuterVertexInternalId(v); +// } + + fid_t GetFragId(const vertex_t& u) const { + auto rp = get_master_partition_for_vertex(pg_, fid_, (void*)(&u)); + if (rp == NULL_REMOTE_PARTITION) { + return fid_; + } + return rp; + } + + size_t GetTotalNodesNum() const { + // secondary + return GetTotalVerticesNum() + } + size_t GetTotalVerticesNum() const { + void* vl = get_vertex_list(g_); + return get_vertex_list_size(vl); + } + size_t GetTotalVerticesNum(label_id_t label) const { + void* _label = get_vertex_label_from_id((void*)(&label)); + void* vl = get_vertex_list_by_label(_label); + return get_vertex_list_size(vl); + } + + // secondary + size_t GetEdgeNum() const { return directed_ ? oenum_ + ienum_ : oenum_; } + // secondary + size_t GetInEdgeNum() const { return ienum_; } + // secondary + size_t GetOutEdgeNum() const { return oenum_; } + + template + T GetData(const vertex_t& v, prop_id_t prop_id) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _label = get_vertex_label(g_, _v); + void* _property = get_vertex_property_from_id(_lable, (void*)(&prop_id)); + void* _pl = get_all_vertex_properties_from_label(g_, _label); + void* _row = get_vertex_row(g_, _v, _pl); + void* _value = get_property_value_from_row(_row, _property); + return *(static_cast(_value)); + } + + bool HasChild(const vertex_t& v, label_id_t e_label) const { + // secondary + return GetLocalOutDegree(v, e_label) != 0; + } + + bool HasParent(const vertex_t& v, label_id_t e_label) const { + // secondary + return GetLocalInDegree(v, e_label) != 0; + } + + int GetLocalOutDegree(const vertex_t& v, label_id_t e_label) const { + // secondary + return GetOutgoingAdjList(v, e_label).Size(); + } + + int GetLocalInDegree(const vertex_t& v, label_id_t e_label) const { + // secondary + return GetIncomingAdjList(v, e_label).Size(); + } + + // FIXME: grape message buffer compatibility + bool Gid2Vertex(const vid_t& gid, vertex_t& v) const { + std::stringstream ss; + ss << gid; + void* vh = get_vertex_from_deserialization(pg_, fid_, ss.str().c_str()); + if (vh == NULL_VERTEX) { + return false; + } + vertex_t* _v = static_cast(vh); + v.SetValue(_v->GetValue()); + return true; + } + + vid_t Vertex2Gid(const vertex_t& v) const { + // secondary + return IsInnerVertex(v) ? GetInnerVertexGid(v) : GetOuterVertexGid(v); + } + + inline vid_t GetInnerVerticesNum(label_id_t label_id) const { + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_local_vertices_by_label(pg_, fid_, _label); + return get_vertex_list_size(vlh); + } + + inline vid_t GetOuterVerticesNum(label_id_t label_id) const { + void* _label = get_vertex_label_from_id((void*)(&label_id)); + void* vlh = get_remote_vertices_by_label(pg_, fid_, _label); + return get_vertex_list_size(vlh); + } + + inline bool IsInnerVertex(const vertex_t& v) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + return is_local_vertex(pg_, fid_, _v); + } + + inline bool IsOuterVertex(const vertex_t& v) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + return is_remote_vertex(pg_, fid_, _v); + } + + bool GetInnerVertex(label_id_t label, const oid_t& oid, vertex_t& v) const { + return GetVertex(label, oid, v); + // vid_t gid; + // if (vm_ptr_->GetGid(label, internal_oid_t(oid), gid)) { + // if (vid_parser_.GetFid(gid) == fid_) { + // v.SetValue(vid_parser_.GetLid(gid)); + // return true; + // } + // } + // return false; + } + + bool GetOuterVertex(label_id_t label, const oid_t& oid, vertex_t& v) const { + return GetVertex(label, oid, v); + // vid_t gid; + // if (vm_ptr_->GetGid(label, internal_oid_t(oid), gid)) { + // return OuterVertexGid2Vertex(gid, v); + // } + // return false; + } + + inline oid_t GetVertexOriginId(const vertex_t& v) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _id = get_vertex_origin_id(g_, _v); + return *(static_cast(_id)); + } + + inline oid_t GetInnerVertexId(const vertex_t& v) const { + return GetVertexOriginId(v); + // return oid_t(GetInnerVertexInternalId(v)); + } + +// inline internal_oid_t GetInnerVertexInternalId(const vertex_t& v) const { +// internal_oid_t internal_oid; +// vid_t gid = +// vid_parser_.GenerateId(fid_, vid_parser_.GetLabelId(v.GetValue()), +// vid_parser_.GetOffset(v.GetValue())); +// CHECK(vm_ptr_->GetOid(gid, internal_oid)); +// return internal_oid; +// } + + inline oid_t GetOuterVertexId(const vertex_t& v) const { + return GetVertexOriginId(v); + // return oid_t(GetOuterVertexInternalId(v)); + } + +// inline internal_oid_t GetOuterVertexInternalId(const vertex_t& v) const { +// vid_t gid = GetOuterVertexGid(v); +// internal_oid_t internal_oid; +// CHECK(vm_ptr_->GetOid(gid, internal_oid)); +// return internal_oid; +// } + + inline oid_t Gid2Oid(const vid_t& gid) const { + vertex_t v; + Gid2Vertex(gid, v); + return GetVertexOriginId(v); + // internal_oid_t internal_oid; + // CHECK(vm_ptr_->GetOid(gid, internal_oid)); + // return oid_t(internal_oid); + } + + inline bool Oid2Gid(label_id_t label, const oid_t& oid, vid_t& gid) const { + vertex_t v; + if (!GetVertex(label, oid, v)) { + return false; + } + gid = Vertex2Gid(v); + return true; + // return vm_ptr_->GetGid(label, internal_oid_t(oid), gid); + } + + inline bool Oid2Gid(label_id_t label, const oid_t& oid, vertex_t& v) const { + vid_t gid; +// if (vm_ptr_->GetGid(label, internal_oid_t(oid), gid)) { + if (Oid2Gid(label, oid, gid)) { + v.SetValue(gid); + return true; + } + return false; + } + + inline bool InnerVertexGid2Vertex(const vid_t& gid, vertex_t& v) const { + return Gid2Vertex(gid, v); + // v.SetValue(vid_parser_.GetLid(gid)); + // return true; + } + + inline bool OuterVertexGid2Vertex(const vid_t& gid, vertex_t& v) const { + return Gid2Vertex(gid, v); + // auto map = ovg2l_maps_ptr_[vid_parser_.GetLabelId(gid)]; + // auto iter = map->find(gid); + // if (iter != map->end()) { + // v.SetValue(iter->second); + // return true; + // } else { + // return false; + // } + } + + inline vid_t GetOuterVertexGid(const vertex_t& v) const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _mv = get_master_vertex_for_vertex(pg_, fid_, _v); + void* _id = get_vertex_id(_mv); + return *(static_cast(_id)); + // label_id_t v_label = vid_parser_.GetLabelId(v.GetValue()); + // return ovgid_lists_ptr_[v_label][vid_parser_.GetOffset(v.GetValue()) - + // static_cast(ivnums_[v_label])]; + } + inline vid_t GetInnerVertexGid(const vertex_t& v) const { + std::stringstream ss(serialize_remote_vertex(pg_, (void*)(&v))); + VID_T gid; + ss >> gid; + return gid; + // return vid_parser_.GenerateId(fid_, vid_parser_.GetLabelId(v.GetValue()), + // vid_parser_.GetOffset(v.GetValue())); + } + + inline adj_list_t GetIncomingAdjList(const vertex_t& v, label_id_t e_label) + const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _label = get_edge_label_from_id((void*)(&e_label)); + void* al = get_adjacent_list_by_edge_label(g_, Direction::IN, (void*)(&v), _label); + return adj_list_t(g_, _label, al, get_adjacent_list_size(al)); + // // grin vertexlist continous_vid_trait get_vertex_from_vid ++++ + // vid_t vid = v.GetValue(); + // label_id_t v_label = vid_parser_.GetLabelId(vid); + // int64_t v_offset = vid_parser_.GetOffset(vid); + // const int64_t* offset_array = ie_offsets_ptr_lists_[v_label][e_label]; + // const nbr_unit_t* ie = ie_ptr_lists_[v_label][e_label]; + // return adj_list_t(&ie[offset_array[v_offset]], + // &ie[offset_array[v_offset + 1]], + // flatten_edge_tables_columns_[e_label]); + } + +// inline raw_adj_list_t GetIncomingRawAdjList(const vertex_t& v, +// label_id_t e_label) const { +// vid_t vid = v.GetValue(); +// label_id_t v_label = vid_parser_.GetLabelId(vid); +// int64_t v_offset = vid_parser_.GetOffset(vid); +// const int64_t* offset_array = ie_offsets_ptr_lists_[v_label][e_label]; +// const nbr_unit_t* ie = ie_ptr_lists_[v_label][e_label]; +// return raw_adj_list_t(&ie[offset_array[v_offset]], +// &ie[offset_array[v_offset + 1]]); +// } + + inline adj_list_t GetOutgoingAdjList(const vertex_t& v, label_id_t e_label) + const { + void* _v = get_vertex_from_id((void*)(&v.GetValue())); + void* _label = get_edge_label_from_id((void*)(&e_label)); + void* al = get_adjacent_list_by_edge_label(g_, Direction::OUT, (void*)(&v), _label); + return adj_list_t(g_, _label, al, get_adjacent_list_size(al)); + // vid_t vid = v.GetValue(); + // label_id_t v_label = vid_parser_.GetLabelId(vid); + // int64_t v_offset = vid_parser_.GetOffset(vid); + // const int64_t* offset_array = oe_offsets_ptr_lists_[v_label][e_label]; + // const nbr_unit_t* oe = oe_ptr_lists_[v_label][e_label]; + // return adj_list_t(&oe[offset_array[v_offset]], + // &oe[offset_array[v_offset + 1]], + // flatten_edge_tables_columns_[e_label]); + } + +// inline raw_adj_list_t GetOutgoingRawAdjList(const vertex_t& v, +// label_id_t e_label) const { +// vid_t vid = v.GetValue(); +// label_id_t v_label = vid_parser_.GetLabelId(vid); +// int64_t v_offset = vid_parser_.GetOffset(vid); +// const int64_t* offset_array = oe_offsets_ptr_lists_[v_label][e_label]; +// const nbr_unit_t* oe = oe_ptr_lists_[v_label][e_label]; +// return raw_adj_list_t(&oe[offset_array[v_offset]], +// &oe[offset_array[v_offset + 1]]); +// } + +// /** +// * N.B.: as an temporary solution, for POC of graph-learn, will be removed +// * later. +// */ + +// inline const int64_t* GetIncomingOffsetArray(label_id_t v_label, +// label_id_t e_label) const { +// return ie_offsets_ptr_lists_[v_label][e_label]; +// } + +// inline const int64_t* GetOutgoingOffsetArray(label_id_t v_label, +// label_id_t e_label) const { +// return oe_offsets_ptr_lists_[v_label][e_label]; +// } + +// inline int64_t GetIncomingOffsetLength(label_id_t v_label, label_id_t e_label) +// const { +// return ie_offsets_lists_[v_label][e_label]->length(); +// } + +// inline int64_t GetOutgoingOffsetLength(label_id_t v_label, label_id_t e_label) +// const { +// return oe_offsets_lists_[v_label][e_label]->length(); +// } + +// inline std::pair GetOutgoingAdjOffsets( +// const vertex_t& v, label_id_t e_label) const { +// vid_t vid = v.GetValue(); +// label_id_t v_label = vid_parser_.GetLabelId(vid); +// int64_t v_offset = vid_parser_.GetOffset(vid); +// const int64_t* offset_array = oe_offsets_ptr_lists_[v_label][e_label]; +// return std::make_pair(offset_array[v_offset], offset_array[v_offset + 1]); +// } + + inline grape::DestList IEDests(const vertex_t& v, label_id_t e_label) const { + void* _v = get_vertex_from_id((void*)(v.GetValue())); + void* _vertex_label = get_vertex_label(_v); + int64_t offset = v.GetValue() - InnerVertices(_vertex_label).begin_value(); + + return grape::DestList(idoffset_[v_label][e_label][offset], + idoffset_[v_label][e_label][offset + 1]); + } + + inline grape::DestList OEDests(const vertex_t& v, label_id_t e_label) const { + void* _v = get_vertex_from_id((void*)(v.GetValue())); + void* _vertex_label = get_vertex_label(_v); + int64_t offset = v.GetValue() - InnerVertices(_vertex_label).begin_value(); + + return grape::DestList(odoffset_[v_label][e_label][offset], + odoffset_[v_label][e_label][offset + 1]); + } + + inline grape::DestList IOEDests(const vertex_t& v, label_id_t e_label) const { + void* _v = get_vertex_from_id((void*)(v.GetValue())); + void* _vertex_label = get_vertex_label(_v); + int64_t offset = v.GetValue() - InnerVertices(_vertex_label).begin_value(); + + return grape::DestList(iodoffset_[v_label][e_label][offset], + iodoffset_[v_label][e_label][offset + 1]); + } + +// std::shared_ptr GetVertexMap() { return vm_ptr_; } + +// const PropertyGraphSchema& schema() const override { return schema_; } + + void PrepareToRunApp(const grape::CommSpec& comm_spec, + grape::PrepareConf conf); +/* mutable functions are not supported in grin 0.1 + boost::leaf::result AddVerticesAndEdges( + Client & client, + std::map> && vertex_tables_map, + std::map> && edge_tables_map, + ObjectID vm_id, + const std::vector>>& + edge_relations, + int concurrency); + + boost::leaf::result AddVertices( + Client & client, + std::map> && vertex_tables_map, + ObjectID vm_id); + + boost::leaf::result AddEdges( + Client & client, + std::map> && edge_tables_map, + const std::vector>>& + edge_relations, + int concurrency); + + /// Add a set of new vertex labels and a set of new edge labels to graph. + /// Vertex label id started from vertex_label_num_, and edge label id + /// started from edge_label_num_. + boost::leaf::result AddNewVertexEdgeLabels( + Client & client, + std::vector> && vertex_tables, + std::vector> && edge_tables, ObjectID vm_id, + const std::vector>>& + edge_relations, + int concurrency); + + /// Add a set of new vertex labels to graph. Vertex label id started from + /// vertex_label_num_. + boost::leaf::result AddNewVertexLabels( + Client & client, + std::vector> && vertex_tables, + ObjectID vm_id); + + /// Add a set of new edge labels to graph. Edge label id started from + /// edge_label_num_. + boost::leaf::result AddNewEdgeLabels( + Client & client, + std::vector> && edge_tables, + const std::vector>>& + edge_relations, + int concurrency); + + boost::leaf::result AddVertexColumns( + vineyard::Client & client, + const std::map< + label_id_t, + std::vector>>> + columns, + bool replace = false) override; + + boost::leaf::result AddVertexColumns( + vineyard::Client & client, + const std::map>>> + columns, + bool replace = false) override; + + template + boost::leaf::result AddVertexColumnsImpl( + vineyard::Client & client, + const std::map< + label_id_t, + std::vector>>> + columns, + bool replace = false); + + boost::leaf::result AddEdgeColumns( + vineyard::Client & client, + const std::map< + label_id_t, + std::vector>>> + columns, + bool replace = false) override; + + boost::leaf::result AddEdgeColumns( + vineyard::Client & client, + const std::map>>> + columns, + bool replace = false) override; + + template + boost::leaf::result AddEdgeColumnsImpl( + vineyard::Client & client, + const std::map< + label_id_t, + std::vector>>> + columns, + bool replace = false); + + boost::leaf::result Project( + vineyard::Client & client, + std::map> vertices, + std::map> edges); + + boost::leaf::result TransformDirection( + vineyard::Client & client, int concurrency); + + boost::leaf::result ConsolidateVertexColumns( + vineyard::Client & client, const label_id_t vlabel, + std::vector const& prop_names, + std::string const& consolidate_name); + + boost::leaf::result ConsolidateVertexColumns( + vineyard::Client & client, const label_id_t vlabel, + std::vector const& props, std::string const& consolidate_name); + + boost::leaf::result ConsolidateEdgeColumns( + vineyard::Client & client, const label_id_t elabel, + std::vector const& prop_names, + std::string const& consolidate_name); + + boost::leaf::result ConsolidateEdgeColumns( + vineyard::Client & client, const label_id_t elabel, + std::vector const& props, std::string const& consolidate_name); +*/ + // we support projection by providing a "view" graph + void* Project( + vineyard::Client & client, + std::map> vertices, + std::map> edges) { + void* new_g; + for (auto& pair : vertices) { + void* vertex_label = get_vetex_label_from_id((void*)(&pair.first)); + void* property_list = create_property_list(); + for (auto& prop_id: pair.second) { + void* property = get_property_by_id(vertex_label, prop_id); + insert_property_to_list(property_list, property); + } + new_g = select_vertex_properties_for_label(g_, propertylist, vertex_label); + } + // same for edge + } + // use grin property "select" + private: + void initPointers(); + + void initDestFidList( + bool in_edge, bool out_edge, + std::vector>>& fid_lists, + std::vector>>& fid_lists_offset); + + __attribute__((annotate("shared"))) fid_t fid_, fnum_; + __attribute__((annotate("shared"))) bool directed_; + __attribute__((annotate("shared"))) bool is_multigraph_; + __attribute__((annotate("shared"))) property_graph_types::LABEL_ID_TYPE vertex_label_num_; + __attribute__((annotate("shared"))) property_graph_types::LABEL_ID_TYPE edge_label_num_; + size_t oenum_, ienum_; // FIXME: should be pre-computable + + __attribute__((annotate("shared"))) String oid_type, vid_type; + + __attribute__((annotate("shared"))) vineyard::Array ivnums_, ovnums_, tvnums_; + + __attribute__((annotate("shared"))) List> vertex_tables_; + std::vector> vertex_tables_columns_; + + __attribute__((annotate("shared"))) List> ovgid_lists_; + std::vector ovgid_lists_ptr_; + + __attribute__((annotate("shared"))) List>> ovg2l_maps_; + std::vector*> ovg2l_maps_ptr_; + + __attribute__((annotate("shared"))) List> edge_tables_; + std::vector> edge_tables_columns_; + std::vector flatten_edge_tables_columns_; + + __attribute__((annotate("shared"))) List>> ie_lists_, + oe_lists_; + std::vector> ie_ptr_lists_, oe_ptr_lists_; + __attribute__((annotate("shared"))) List>> ie_offsets_lists_, + oe_offsets_lists_; + std::vector> ie_offsets_ptr_lists_, + oe_offsets_ptr_lists_; + + std::vector>> idst_, odst_, iodst_; + std::vector>> idoffset_, odoffset_, + iodoffset_; + + __attribute__((annotate("shared"))) std::shared_ptr vm_ptr_; + + vineyard::IdParser vid_parser_; + + __attribute__((annotate("shared"))) json schema_json_; + PropertyGraphSchema schema_; + + friend class ArrowFragmentBaseBuilder; + + template + friend class gs::ArrowProjectedFragment; +}; + +} // namespace vineyard + +// vim: syntax=cpp + +#endif // MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GRIN_H diff --git a/modules/graph/fragment/arrow_fragment_group.cc b/modules/graph/fragment/arrow_fragment_group.cc index 21606662f..4946009f2 100644 --- a/modules/graph/fragment/arrow_fragment_group.cc +++ b/modules/graph/fragment/arrow_fragment_group.cc @@ -94,4 +94,4 @@ Status ArrowFragmentGroupBuilder::_Seal( return Status::OK(); } -} // namespace vineyard +} // namespace vineyard \ No newline at end of file diff --git a/modules/graph/fragment/arrow_fragment_group.h b/modules/graph/fragment/arrow_fragment_group.h index aa957b7c9..180d26c75 100644 --- a/modules/graph/fragment/arrow_fragment_group.h +++ b/modules/graph/fragment/arrow_fragment_group.h @@ -94,4 +94,4 @@ class ArrowFragmentGroupBuilder : public ObjectBuilder { } // namespace vineyard -#endif // MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GROUP_H_ +#endif // MODULES_GRAPH_FRAGMENT_ARROW_FRAGMENT_GROUP_H_ \ No newline at end of file diff --git a/modules/graph/grin/.gitignore b/modules/graph/grin/.gitignore new file mode 100644 index 000000000..7fde7df1f --- /dev/null +++ b/modules/graph/grin/.gitignore @@ -0,0 +1,3 @@ +/docs/_build/ +/docs/Doxyfile.bak +/c/ \ No newline at end of file diff --git a/modules/graph/grin/c/test.c b/modules/graph/grin/c/test.c new file mode 100644 index 000000000..4cef3eeb5 --- /dev/null +++ b/modules/graph/grin/c/test.c @@ -0,0 +1,1139 @@ +#include +#include "../include/common/error.h" +#include "../include/index/label.h" +#include "../include/index/order.h" +#include "../include/index/original_id.h" +#include "../include/partition/partition.h" +#include "../include/partition/reference.h" +#include "../include/partition/topology.h" +#include "../include/property/partition.h" +#include "../include/property/primarykey.h" +#include "../include/property/property.h" +#include "../include/property/propertylist.h" +#include "../include/property/row.h" +#include "../include/property/topology.h" +#include "../include/property/type.h" +#include "../include/topology/adjacentlist.h" +#include "../include/topology/edgelist.h" +#include "../include/topology/structure.h" +#include "../include/topology/vertexlist.h" + +GRIN_GRAPH get_graph(int argc, char** argv) { +#ifdef GRIN_ENABLE_GRAPH_PARTITION + GRIN_PARTITIONED_GRAPH pg = + grin_get_partitioned_graph_from_storage(argc - 1, &(argv[1])); + GRIN_PARTITION_LIST local_partitions = grin_get_local_partition_list(pg); + GRIN_PARTITION partition = + grin_get_partition_from_list(pg, local_partitions, 0); + GRIN_PARTITION_ID partition_id = grin_get_partition_id(pg, partition); + GRIN_PARTITION p1 = grin_get_partition_by_id(pg, partition_id); + if (!grin_equal_partition(pg, partition, p1)) { + printf("partition not match\n"); + } + grin_destroy_partition(pg, p1); + GRIN_GRAPH g = grin_get_local_graph_by_partition(pg, partition); + grin_destroy_partition(pg, partition); + grin_destroy_partition_list(pg, local_partitions); + grin_destroy_partitioned_graph(pg); +#else + GRIN_GRAPH g = grin_get_graph_from_storage(argc - 1, &(argv[1])); +#endif + return g; +} + + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +GRIN_PARTITION get_partition(int argc, char** argv) { + GRIN_PARTITIONED_GRAPH pg = + grin_get_partitioned_graph_from_storage(argc - 1, &(argv[1])); + GRIN_PARTITION_LIST local_partitions = grin_get_local_partition_list(pg); + GRIN_PARTITION partition = + grin_get_partition_from_list(pg, local_partitions, 0); + grin_destroy_partition_list(pg, local_partitions); + grin_destroy_partitioned_graph(pg); + return partition; +} +#endif + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +GRIN_PARTITIONED_GRAPH get_partitioend_graph(int argc, char** argv) { + GRIN_PARTITIONED_GRAPH pg = + grin_get_partitioned_graph_from_storage(argc - 1, &(argv[1])); + return pg; +} +#endif + +GRIN_VERTEX_TYPE get_one_vertex_type(GRIN_GRAPH g) { + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, 0); + grin_destroy_vertex_type_list(g, vtl); + return vt; +} + +GRIN_EDGE_TYPE get_one_edge_type(GRIN_GRAPH g) { + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, 0); + grin_destroy_edge_type_list(g, etl); + return et; +} + +GRIN_VERTEX get_one_vertex(GRIN_GRAPH g) { + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + GRIN_VERTEX v = grin_get_vertex_from_list(g, vl, 0); +#else + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, vl); + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + grin_destroy_vertex_list_iter(g, vli); +#endif + grin_destroy_vertex_list(g, vl); + return v; +} + +GRIN_VERTEX get_vertex_marco(GRIN_GRAPH g) { + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + GRIN_VERTEX v = grin_get_vertex_from_list(g, vl, 3); +#else + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, vl); + for (int i = 0; i < 3; ++i) { + grin_get_next_vertex_list_iter(g, vli); + } + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + grin_destroy_vertex_list_iter(g, vli); +#endif + grin_destroy_vertex_list(g, vl); + return v; +} + +void test_property_type(int argc, char** argv) { + printf("+++++++++++++++++++++ Test property/type +++++++++++++++++++++\n"); + + GRIN_GRAPH g = get_graph(argc, argv); + + printf("------------ Vertex Type ------------\n"); + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + printf("vertex type list size: %zu\n", vtl_size); + + for (size_t i = 0; i < vtl_size; ++i) { + printf("------------ Iterate the %zu-th vertex type ------------\n", i); + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); +#ifdef GRIN_WITH_VERTEX_TYPE_NAME + const char* vt_name = grin_get_vertex_type_name(g, vt); + printf("vertex type name: %s\n", vt_name); + GRIN_VERTEX_TYPE vt0 = grin_get_vertex_type_by_name(g, vt_name); + // grin_destroy_name(g, vt_name); + if (!grin_equal_vertex_type(g, vt, vt0)) { + printf("vertex type name not match\n"); + } + grin_destroy_vertex_type(g, vt0); +#endif +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + printf("vertex type id: %u\n", grin_get_vertex_type_id(g, vt)); + GRIN_VERTEX_TYPE vt1 = + grin_get_vertex_type_by_id(g, grin_get_vertex_type_id(g, vt)); + if (!grin_equal_vertex_type(g, vt, vt1)) { + printf("vertex type id not match\n"); + } + grin_destroy_vertex_type(g, vt1); +#endif + } + grin_destroy_vertex_type_list(g, vtl); + + printf( + "------------ Create a vertex type list of one type \"person\" " + "------------\n"); + GRIN_VERTEX_TYPE_LIST vtl2 = grin_create_vertex_type_list(g); +#ifdef GRIN_WITH_VERTEX_TYPE_NAME + GRIN_VERTEX_TYPE vt2_w = grin_get_vertex_type_by_name(g, "knows"); + if (vt2_w == GRIN_NULL_VERTEX_TYPE) { + printf("(Correct) vertex type of knows does not exists\n"); + } + GRIN_VERTEX_TYPE vt2 = grin_get_vertex_type_by_name(g, "person"); + if (vt2 == GRIN_NULL_VERTEX_TYPE) { + printf("(Wrong) vertex type of person can not be found\n"); + } else { + const char* vt2_name = grin_get_vertex_type_name(g, vt2); + printf("vertex type name: %s\n", vt2_name); + // grin_destroy_name(g, vt2_name); + } +#else + GRIN_VERTEX_TYPE vt2 = get_one_vertex_type(g); +#endif + grin_insert_vertex_type_to_list(g, vtl2, vt2); + size_t vtl2_size = grin_get_vertex_type_list_size(g, vtl2); + printf("created vertex type list size: %zu\n", vtl2_size); + GRIN_VERTEX_TYPE vt3 = grin_get_vertex_type_from_list(g, vtl2, 0); + if (!grin_equal_vertex_type(g, vt2, vt3)) { + printf("vertex type not match\n"); + } + grin_destroy_vertex_type(g, vt2); + grin_destroy_vertex_type(g, vt3); + grin_destroy_vertex_type_list(g, vtl2); + + // edge + printf("------------ Edge Type ------------\n"); + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_size = grin_get_edge_type_list_size(g, etl); + printf("edge type list size: %zu\n", etl_size); + + for (size_t i = 0; i < etl_size; ++i) { + printf("------------ Iterate the %zu-th edge type ------------\n", i); + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); +#ifdef GRIN_WITH_EDGE_TYPE_NAME + const char* et_name = grin_get_edge_type_name(g, et); + printf("edge type name: %s\n", et_name); + GRIN_EDGE_TYPE et0 = grin_get_edge_type_by_name(g, et_name); + // grin_destroy_name(g, et_name); + if (!grin_equal_edge_type(g, et, et0)) { + printf("edge type name not match\n"); + } + grin_destroy_edge_type(g, et0); +#endif +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + printf("edge type id: %u\n", grin_get_edge_type_id(g, et)); + GRIN_EDGE_TYPE et1 = + grin_get_edge_type_by_id(g, grin_get_edge_type_id(g, et)); + if (!grin_equal_edge_type(g, et, et1)) { + printf("edge type id not match\n"); + } + grin_destroy_edge_type(g, et1); +#endif + // relation + GRIN_VERTEX_TYPE_LIST src_vtl = grin_get_src_types_by_edge_type(g, et); + size_t src_vtl_size = grin_get_vertex_type_list_size(g, src_vtl); + printf("source vertex type list size: %zu\n", src_vtl_size); + + GRIN_VERTEX_TYPE_LIST dst_vtl = grin_get_dst_types_by_edge_type(g, et); + size_t dst_vtl_size = grin_get_vertex_type_list_size(g, dst_vtl); + printf("destination vertex type list size: %zu\n", dst_vtl_size); + + if (src_vtl_size != dst_vtl_size) { + printf("source and destination vertex type list size not match\n"); + } + for (size_t j = 0; j < src_vtl_size; ++j) { + GRIN_VERTEX_TYPE src_vt = grin_get_vertex_type_from_list(g, src_vtl, j); + GRIN_VERTEX_TYPE dst_vt = grin_get_vertex_type_from_list(g, dst_vtl, j); + const char* src_vt_name = grin_get_vertex_type_name(g, src_vt); + const char* dst_vt_name = grin_get_vertex_type_name(g, dst_vt); + const char* et_name = grin_get_edge_type_name(g, et); + printf("edge type name: %s-%s-%s\n", src_vt_name, et_name, dst_vt_name); + // grin_destroy_name(g, src_vt_name); + // grin_destroy_name(g, dst_vt_name); + // grin_destroy_name(g, et_name); + grin_destroy_vertex_type(g, src_vt); + grin_destroy_vertex_type(g, dst_vt); + } + grin_destroy_vertex_type_list(g, src_vtl); + grin_destroy_vertex_type_list(g, dst_vtl); + } + grin_destroy_edge_type_list(g, etl); + + printf( + "------------ Create an edge type list of one type \"created\" " + "------------\n"); + GRIN_EDGE_TYPE_LIST etl2 = grin_create_edge_type_list(g); +#ifdef GRIN_WITH_EDGE_TYPE_NAME + GRIN_EDGE_TYPE et2_w = grin_get_edge_type_by_name(g, "person"); + if (et2_w == GRIN_NULL_EDGE_TYPE) { + printf("(Correct) edge type of person does not exists\n"); + } + GRIN_EDGE_TYPE et2 = grin_get_edge_type_by_name(g, "created"); + if (et2 == GRIN_NULL_EDGE_TYPE) { + printf("(Wrong) edge type of created can not be found\n"); + } else { + const char* et2_name = grin_get_edge_type_name(g, et2); + printf("edge type name: %s\n", et2_name); + // grin_destroy_name(g, et2_name); + } +#else + GRIN_EDGE_TYPE et2 = get_one_edge_type(g); +#endif + grin_insert_edge_type_to_list(g, etl2, et2); + size_t etl2_size = grin_get_edge_type_list_size(g, etl2); + printf("created edge type list size: %zu\n", etl2_size); + GRIN_EDGE_TYPE et3 = grin_get_edge_type_from_list(g, etl2, 0); + if (!grin_equal_edge_type(g, et2, et3)) { + printf("edge type not match\n"); + } + grin_destroy_edge_type(g, et2); + grin_destroy_edge_type(g, et3); + grin_destroy_edge_type_list(g, etl2); + + grin_destroy_graph(g); +} + +void test_property_topology(int argc, char** argv) { + printf( + "+++++++++++++++++++++ Test property/topology +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + GRIN_VERTEX_TYPE vt = get_one_vertex_type(g); + GRIN_EDGE_TYPE et = get_one_edge_type(g); + const char* vt_name = grin_get_vertex_type_name(g, vt); + const char* et_name = grin_get_edge_type_name(g, et); + +#ifdef GRIN_ENABLE_VERTEX_LIST + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + size_t vl_size = grin_get_vertex_list_size(g, vl); + printf("vertex list size: %zu\n", vl_size); +#endif + +#ifdef GRIN_TRAIT_SELECT_TYPE_FOR_VERTEX_LIST + GRIN_VERTEX_LIST typed_vl = grin_select_type_for_vertex_list(g, vt, vl); + size_t typed_vnum = grin_get_vertex_num_by_type(g, vt); + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + size_t typed_vl_size = grin_get_vertex_list_size(g, typed_vl); + printf("vertex number under type: %zu %zu\n", typed_vl_size, typed_vnum); + + for (size_t j = 0; j < typed_vl_size; ++j) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, typed_vl, j); + GRIN_VERTEX_TYPE v_type = grin_get_vertex_type(g, v); + if (!grin_equal_vertex_type(g, v_type, vt)) { + printf("vertex type not match\n"); + } + grin_destroy_vertex_type(g, v_type); + grin_destroy_vertex(g, v); + } +#else + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, typed_vl); + size_t typed_vl_size = 0; + while (grin_is_vertex_list_end(g, vli) == false) { + ++typed_vl_size; + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + GRIN_VERTEX_TYPE v_type = grin_get_vertex_type(g, v); + if (!grin_equal_vertex_type(g, v_type, vt)) { + printf("vertex type not match\n"); + } + grin_destroy_vertex_type(g, v_type); + grin_destroy_vertex(g, v); + grin_get_next_vertex_list_iter(g, vli); + } + printf("vertex number under type: %zu %zu\n", typed_vl_size, typed_vnum); + grin_destroy_vertex_list_iter(g, vli); +#endif + + grin_destroy_vertex_list(g, typed_vl); +#endif + grin_destroy_vertex_list(g, vl); +#endif + +#ifdef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 + GRIN_DATATYPE dt = grin_get_vertex_original_id_datatype(g); + if (dt == Int64) { + long long int v0id = 4; + GRIN_VERTEX v0 = grin_get_vertex_by_original_id_of_int64(g, v0id); + if (v0 == GRIN_NULL_VERTEX) { + printf("(Wrong) vertex of id %lld can not be found\n", v0id); + } else { + printf("vertex of original id %lld found\n", v0id); + long long int oid0 = grin_get_vertex_original_id_of_int64(g, v0); + printf("get vertex original id: %lld\n", oid0); + } + grin_destroy_vertex(g, v0); + } else { + printf("(Wrong) vertex original id type not int64\n"); + } +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST + GRIN_EDGE_LIST el = grin_get_edge_list(g); +#ifdef GRIN_ENABLE_EDGE_LIST_ARRAY + size_t el_size = grin_get_edge_list_size(g, el); + printf("edge list size: %zu\n", el_size); +#endif + +#ifdef GRIN_TRAIT_SELECT_TYPE_FOR_EDGE_LIST + GRIN_EDGE_LIST typed_el = grin_select_type_for_edge_list(g, et, el); + size_t typed_enum = grin_get_edge_num_by_type(g, et); + +#ifdef GRIN_ENABLE_EDGE_LIST_ARRAY + size_t typed_el_size = grin_get_edge_list_size(g, typed_el); + printf("edge number under type: %zu %zu\n", typed_el_size, typed_enum); + + for (size_t j = 0; j < typed_el_size; ++j) { + GRIN_EDGE e = grin_get_edge_from_list(g, typed_el, j); + GRIN_EDGE_TYPE e_type = grin_get_edge_type(g, e); + if (!grin_equal_edge_type(g, e_type, et)) { + printf("edge type not match\n"); + } + grin_destroy_edge_type(g, e_type); + grin_destroy_edge(g, e); + } +#else + GRIN_EDGE_LIST_ITERATOR eli = grin_get_edge_list_begin(g, typed_el); + size_t typed_el_size = 0; + while (grin_is_edge_list_end(g, eli) == false) { + ++typed_el_size; + GRIN_EDGE e = grin_get_edge_from_iter(g, eli); + GRIN_EDGE_TYPE e_type = grin_get_edge_type(g, e); + if (!grin_equal_edge_type(g, e_type, et)) { + printf("edge type not match\n"); + } + grin_destroy_edge_type(g, e_type); + grin_destroy_edge(g, e); + grin_get_next_edge_list_iter(g, eli); + } + printf("edge number under type: %zu %zu\n", typed_el_size, typed_enum); + grin_destroy_edge_list_iter(g, eli); +#endif + + grin_destroy_edge_list(g, typed_el); +#endif + grin_destroy_edge_list(g, el); +#endif + + // grin_destroy_name(g, vt_name); + // grin_destroy_name(g, et_name); + grin_destroy_vertex_type(g, vt); + grin_destroy_edge_type(g, et); + grin_destroy_graph(g); +} + +void test_property_vertex_property_value(int argc, char** argv) { + printf("------------ Test Vertex property value ------------\n"); + GRIN_GRAPH g = get_graph(argc, argv); + + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + for (size_t vt_index = 0; vt_index < vtl_size; ++vt_index) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, vt_index); + + GRIN_VERTEX_PROPERTY_LIST vpl = + grin_get_vertex_property_list_by_type(g, vt); + +#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST + GRIN_VERTEX_LIST all_vl = grin_get_vertex_list(g); + GRIN_VERTEX_LIST vl = grin_select_master_for_vertex_list(g, all_vl); +#else + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); +#endif + GRIN_VERTEX_LIST typed_vl = grin_select_type_for_vertex_list(g, vt, vl); +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + size_t typed_vl_size = grin_get_vertex_list_size(g, typed_vl); +#else + size_t typed_vl_size = grin_get_vertex_num_by_type(g, vt); +#endif + size_t vpl_size = grin_get_vertex_property_list_size(g, vpl); + printf("vertex list size: %zu vertex property list size: %zu\n", + typed_vl_size, vpl_size); + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + for (size_t i = 0; i < typed_vl_size; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, typed_vl, i); +#else + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, typed_vl); + size_t i = 0; + while (grin_is_vertex_list_end(g, vli) == 0) { + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); +#endif + GRIN_ROW row = grin_get_vertex_row(g, v); + for (size_t j = 0; j < vpl_size; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_from_property(g, vp); + if (!grin_equal_vertex_type(g, vt, vt1)) { + printf("vertex type not match by property\n"); + } + grin_destroy_vertex_type(g, vt1); +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + unsigned int id = grin_get_vertex_property_id(g, vt, vp); + GRIN_VERTEX_PROPERTY vp1 = grin_get_vertex_property_by_id(g, vt, id); + if (!grin_equal_vertex_property(g, vp, vp1)) { + printf("vertex property not match by id\n"); + } + grin_destroy_vertex_property(g, vp1); +#else + unsigned int id = ~0; +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + const char* vp_name = grin_get_vertex_property_name(g, vt, vp); + GRIN_VERTEX_PROPERTY vp2 = + grin_get_vertex_property_by_name(g, vt, vp_name); + if (!grin_equal_vertex_property(g, vp, vp2)) { + printf("vertex property not match by name\n"); + } +#else + const char* vp_name = "unknown"; +#endif + GRIN_DATATYPE dt = grin_get_vertex_property_datatype(g, vp); +#ifdef GRIN_TRAIT_CONST_VALUE_PTR + const void* pv = + grin_get_vertex_property_value(g, v, vp); + if (grin_get_last_error_code() == NO_ERROR) { + printf("(Correct) no error\n"); + } else { + printf("(Wrong) error code: %d\n", grin_get_last_error_code()); + } + const void* rv = grin_get_value_from_row(g, row, dt, j); + if (dt == Int64) { + printf("vp_id %u v%zu %s value int64: %ld %ld\n", id, i, vp_name, + *((long int*) pv), *((long int*) rv)); + } else if (dt == String) { + printf("vp_id %u v%zu %s value string: %s %s\n", id, i, vp_name, (char*) pv, + (char*) rv); + } else if (dt == Int32) { + printf("vp_id %u v%zu %s value int32: %d %d\n", id, i, vp_name, *((int*)pv), + *((int*)rv)); + } + // grin_destroy_value(g, dt, pv); + // grin_destroy_value(g, dt, rv); +#else + if (dt == Int64) { + long long int pv = + grin_get_vertex_property_value_of_int64(g, v, vp); + if (grin_get_last_error_code() == NO_ERROR) { + printf("(Correct) no error\n"); + } else { + printf("(Wrong) error code: %d\n", grin_get_last_error_code()); + } + long long int rv = grin_get_int64_from_row(g, row, j); + printf("vp_id %u v%zu %s value: %lld %lld\n", id, i, vp_name, pv, rv); + } else if (dt == String) { + const char* pv = + grin_get_vertex_property_value_of_string(g, v, vp); + if (grin_get_last_error_code() == NO_ERROR) { + printf("(Correct) no error\n"); + } else { + printf("(Wrong) error code: %d\n", grin_get_last_error_code()); + } + const char* rv = grin_get_string_from_row(g, row, j); + printf("vp_id %u v%zu %s value: %s %s\n", id, i, vp_name, pv, rv); + grin_destroy_string_value(g, pv); + grin_destroy_string_value(g, rv); + } +#endif + grin_destroy_vertex_property(g, vp); + } + grin_destroy_row(g, row); + grin_destroy_vertex(g, v); +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + } +#else + grin_get_next_vertex_list_iter(g, vli); + ++i; + } + grin_destroy_vertex_list_iter(g, vli); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + GRIN_VERTEX_PROPERTY vp3 = grin_get_vertex_property_by_id(g, vt, vpl_size); + if (vp3 == GRIN_NULL_VERTEX_PROPERTY) { + printf("(Correct) vertex property of id %zu does not exist\n", vpl_size); + } else { + printf("(Wrong) vertex property of id %zu exists\n", vpl_size); + grin_destroy_vertex_property(g, vp3); + } +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + GRIN_VERTEX_PROPERTY vp4 = + grin_get_vertex_property_by_name(g, vt, "unknown"); + if (vp4 == GRIN_NULL_VERTEX_PROPERTY) { + printf("(Correct) vertex property of name \"unknown\" does not exist\n"); + } else { + printf("(Wrong) vertex property of name \"unknown\" exists\n"); + grin_destroy_vertex_property(g, vp4); + } + + GRIN_VERTEX_PROPERTY_LIST vpl1 = + grin_get_vertex_properties_by_name(g, "unknown"); + if (vpl1 == GRIN_NULL_LIST) { + printf( + "(Correct) vertex properties of name \"unknown\" does not exist\n"); + } else { + printf("(Wrong) vertex properties of name \"unknown\" exists\n"); + grin_destroy_vertex_property_list(g, vpl1); + } + + GRIN_VERTEX_PROPERTY_LIST vpl2 = + grin_get_vertex_properties_by_name(g, "name"); + if (vpl2 == GRIN_NULL_LIST) { + printf("(Wrong) vertex properties of name \"name\" does not exist\n"); + } else { + printf("(Correct) vertex properties of name \"name\" exists\n"); + size_t vpl2_size = grin_get_vertex_property_list_size(g, vpl2); + for (size_t i = 0; i < vpl2_size; ++i) { + GRIN_VERTEX_PROPERTY vp5 = + grin_get_vertex_property_from_list(g, vpl2, i); + GRIN_VERTEX_TYPE vt5 = grin_get_vertex_type_from_property(g, vp5); + const char* vp5_name = grin_get_vertex_property_name(g, vt5, vp5); + const char* vt5_name = grin_get_vertex_type_name(g, vt5); + printf("vertex type name: %s, vertex property name: %s\n", vt5_name, + vp5_name); + grin_destroy_vertex_property(g, vp5); + grin_destroy_vertex_type(g, vt5); + // grin_destroy_name(g, vt5_name); + // grin_destroy_name(g, vp5_name); + } + grin_destroy_vertex_property_list(g, vpl2); + } +#endif + + grin_destroy_vertex_list(g, typed_vl); + grin_destroy_vertex_list(g, vl); + grin_destroy_vertex_property_list(g, vpl); + } + grin_destroy_vertex_type_list(g, vtl); + grin_destroy_graph(g); +} + +void test_property_edge_property_value(int argc, char** argv) { + printf("------------ Test Edge property value ------------\n"); + GRIN_GRAPH g = get_graph(argc, argv); + // edge + GRIN_VERTEX v = get_vertex_marco(g); + GRIN_VERTEX_TYPE vt = grin_get_vertex_type(g, v); + GRIN_ADJACENT_LIST al = grin_get_adjacent_list(g, OUT, v); +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY + printf("adjacent list size: %zu\n", grin_get_adjacent_list_size(g, al)); +#endif + + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_size = grin_get_edge_type_list_size(g, etl); + printf("edge type list size: %zu\n", etl_size); + + for (size_t i = 0; i < etl_size; ++i) { + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); + GRIN_EDGE_PROPERTY_LIST epl = grin_get_edge_property_list_by_type(g, et); + size_t epl_size = grin_get_edge_property_list_size(g, epl); + printf("edge property list size: %zu\n", epl_size); + +#ifdef GRIN_TRAIT_SELECT_EDGE_TYPE_FOR_ADJACENT_LIST + GRIN_ADJACENT_LIST al1 = grin_select_edge_type_for_adjacent_list(g, et, al); + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY + size_t al1_size = grin_get_adjacent_list_size(g, al1); + printf("selected adjacent list size: %zu\n", al1_size); +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY + for (size_t j = 0; j < al1_size; ++j) { + GRIN_EDGE e = grin_get_edge_from_adjacent_list(g, al1, j); +#else + GRIN_ADJACENT_LIST_ITERATOR ali = grin_get_adjacent_list_begin(g, al1); + size_t j = 0; + while (grin_is_adjacent_list_end(g, ali) == false) { + GRIN_EDGE e = grin_get_edge_from_adjacent_list_iter(g, ali); +#endif + GRIN_EDGE_TYPE et1 = grin_get_edge_type(g, e); + if (!grin_equal_edge_type(g, et, et1)) { + printf("edge type does not match\n"); + } + + GRIN_ROW row = grin_get_edge_row(g, e); + for (size_t k = 0; k < epl_size; ++k) { + GRIN_EDGE_PROPERTY ep = grin_get_edge_property_from_list(g, epl, k); + GRIN_EDGE_TYPE et2 = grin_get_edge_type_from_property(g, ep); + if (!grin_equal_edge_type(g, et, et2)) { + printf("edge type does not match\n"); + } + grin_destroy_edge_type(g, et2); + + const char* ep_name = grin_get_edge_property_name(g, et, ep); + printf("edge property name: %s\n", ep_name); + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + unsigned int id = grin_get_edge_property_id(g, et, ep); + GRIN_EDGE_PROPERTY ep1 = grin_get_edge_property_by_id(g, et, id); + if (!grin_equal_edge_property(g, ep, ep1)) { + printf("edge property not match by id\n"); + } + grin_destroy_edge_property(g, ep1); +#else + unsigned int id = ~0; +#endif + GRIN_DATATYPE dt = grin_get_edge_property_datatype(g, ep); +#ifdef GRIN_TRAIT_CONST_VALUE_PTR + const void* pv = grin_get_edge_property_value(g, e, ep); + const void* rv = grin_get_value_from_row(g, row, dt, k); + + if (dt == Int64) { + printf("ep_id %u e%zu %s value: %ld %ld\n", id, j, ep_name, + *((long int*) pv), *((long int*) rv)); + } else if (dt == String) { + printf("ep_id %u e%zu %s value: %s %s\n", id, j, ep_name, (char*) pv, + (char*) rv); + } else if (dt == Double) { + printf("ep_id %u e%zu %s value: %f %f\n", id, j, ep_name, + *((double*) pv), *((double*) rv)); + } + grin_destroy_edge_property(g, ep); + // grin_destroy_name(g, ep_name); + // grin_destroy_value(g, dt, pv); + // grin_destroy_value(g, dt, rv); +#else + if (dt == Int64) { + long long int pv = + grin_get_edge_property_value_of_int64(g, e, ep); + long long int rv = grin_get_int64_from_row(g, row, k); + printf("ep_id %u e%zu %s value: %lld %lld\n", id, j, ep_name, pv, rv); + } else if (dt == String) { + const char* pv = + grin_get_edge_property_value_of_string(g, e, ep); + const char* rv = grin_get_string_from_row(g, row, k); + printf("ep_id %u e%zu %s value: %s %s\n", id, j, ep_name, pv, rv); + grin_destroy_string_value(g, pv); + grin_destroy_string_value(g, rv); + } else if (dt == Double) { + double pv = grin_get_edge_property_value_of_double(g, e, ep); + double rv = grin_get_double_from_row(g, row, k); + printf("ep_id %u e%zu %s value: %f %f\n", id, j, ep_name, pv, rv); + } +#endif + // grin_destroy_name(g, ep_name); + // grin_destroy_value(g, dt, pv); + // grin_destroy_value(g, dt, rv); + } + + grin_destroy_row(g, row); + grin_destroy_edge_type(g, et1); + grin_destroy_edge(g, e); + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY + } +#else + grin_get_next_adjacent_list_iter(g, ali); + ++j; + } + grin_destroy_adjacent_list_iter(g, ali); +#endif + + grin_destroy_adjacent_list(g, al1); +#endif + + for (size_t j = 0; j < epl_size; ++j) { + GRIN_EDGE_PROPERTY ep = grin_get_edge_property_from_list(g, epl, j); + GRIN_EDGE_TYPE et1 = grin_get_edge_type_from_property(g, ep); + if (!grin_equal_edge_type(g, et, et1)) { + printf("edge type does not match\n"); + } + const char* ep_name1 = grin_get_edge_property_name(g, et, ep); + const char* et_name = grin_get_edge_type_name(g, et); + printf("edge property name: %s, edge property type name: %s\n", ep_name1, + et_name); + + grin_destroy_edge_type(g, et1); + // grin_destroy_name(g, ep_name1); + // grin_destroy_name(g, et_name); + +#ifdef GRIN_WITH_EDGE_PROPERTY_NAME + const char* ep_name = grin_get_edge_property_name(g, et, ep); + GRIN_EDGE_PROPERTY ep2 = grin_get_edge_property_by_name(g, et, ep_name); + if (!grin_equal_edge_property(g, ep, ep2)) { + printf("edge property not match by name\n"); + } +#else + const char* ep_name = "unknown"; +#endif + grin_destroy_edge_property(g, ep); + } +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + GRIN_EDGE_PROPERTY ep3 = grin_get_edge_property_by_id(g, et, epl_size); + if (ep3 == GRIN_NULL_EDGE_PROPERTY) { + printf("(Correct) edge property of id %zu does not exist\n", epl_size); + } else { + printf("(Wrong) edge property of id %zu exists\n", epl_size); + grin_destroy_edge_property(g, ep3); + } +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY_NAME + GRIN_EDGE_PROPERTY ep4 = grin_get_edge_property_by_name(g, et, "unknown"); + if (ep4 == GRIN_NULL_EDGE_PROPERTY) { + printf("(Correct) edge property of name \"unknown\" does not exist\n"); + } else { + printf("(Wrong) edge property of name \"unknown\" exists\n"); + grin_destroy_edge_property(g, ep4); + } + + GRIN_EDGE_PROPERTY_LIST epl1 = + grin_get_edge_properties_by_name(g, "unknown"); + if (epl1 == GRIN_NULL_LIST) { + printf("(Correct) edge properties of name \"unknown\" does not exist\n"); + } else { + printf("(Wrong) edge properties of name \"unknown\" exists\n"); + grin_destroy_edge_property_list(g, epl1); + } + + GRIN_EDGE_PROPERTY_LIST epl2 = + grin_get_edge_properties_by_name(g, "weight"); + if (epl2 == GRIN_NULL_LIST) { + printf("(Wrong) edge properties of name \"weight\" does not exist\n"); + } else { + printf("(Correct) edge properties of name \"weight\" exists\n"); + size_t epl2_size = grin_get_edge_property_list_size(g, epl2); + for (size_t i = 0; i < epl2_size; ++i) { + GRIN_EDGE_PROPERTY ep5 = grin_get_edge_property_from_list(g, epl2, i); + GRIN_EDGE_TYPE et5 = grin_get_edge_type_from_property(g, ep5); + const char* ep5_name = grin_get_edge_property_name(g, et5, ep5); + const char* et5_name = grin_get_edge_type_name(g, et5); + printf("edge type name: %s, edge property name: %s\n", et5_name, + ep5_name); + grin_destroy_edge_property(g, ep5); + grin_destroy_edge_type(g, et5); + // grin_destroy_name(g, et5_name); + // grin_destroy_name(g, ep5_name); + } + grin_destroy_edge_property_list(g, epl2); + } +#endif + grin_destroy_edge_type(g, et); + } + + grin_destroy_vertex(g, v); + grin_destroy_vertex_type(g, vt); + grin_destroy_adjacent_list(g, al); + grin_destroy_edge_type_list(g, etl); + grin_destroy_graph(g); +} + +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS +void test_property_primary_key(int argc, char** argv) { + printf( + "+++++++++++++++++++++ Test property/primary key " + "+++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_types_with_primary_keys(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + printf("vertex type list size: %zu\n", vtl_size); + + unsigned id_type[7] = {~0, 0, 0, 1, 0, 1, 0}; + + for (size_t i = 0; i < vtl_size; ++i) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); + const char* vt_name = grin_get_vertex_type_name(g, vt); + printf("vertex type name: %s\n", vt_name); + // grin_destroy_name(g, vt_name); + + GRIN_VERTEX_PROPERTY_LIST vpl = grin_get_primary_keys_by_vertex_type(g, vt); + size_t vpl_size = grin_get_vertex_property_list_size(g, vpl); + printf("primary key list size: %zu\n", vpl_size); + + for (size_t j = 0; j < vpl_size; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + const char* vp_name = grin_get_vertex_property_name(g, vt, vp); + printf("primary key name: %s\n", vp_name); + // grin_destroy_name(g, vp_name); + grin_destroy_vertex_property(g, vp); + } + + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, 0); + GRIN_DATATYPE dt = grin_get_vertex_property_datatype(g, vp); + + for (size_t j = 1; j <= 6; ++j) { + GRIN_ROW r = grin_create_row(g); + if (dt == Int64) { + grin_insert_int64_to_row(g, r, j); + } else { + printf("(Wrong) the primary key type is not int64"); + } + GRIN_VERTEX v = grin_get_vertex_by_primary_keys(g, vt, r); + if (id_type[j] == i) { + if (v == GRIN_NULL_VERTEX) { + printf("(Wrong) vertex of primary keys %zu does not exist\n", j); + } else { + grin_destroy_vertex(g, v); + } + } else { + if (v == GRIN_NULL_VERTEX) { + printf("(Correct) vertex of primary keys %zu does not exist\n", j); + } else { + printf("(Wrong) vertex of primary keys %zu exists\n", j); + grin_destroy_vertex(g, v); + } + } + grin_destroy_row(g, r); + } + + grin_destroy_vertex_property(g, vp); + grin_destroy_vertex_property_list(g, vpl); + grin_destroy_vertex_type(g, vt); + } +} +#endif + +void test_error_code(int argc, char** argv) { + printf("+++++++++++++++++++++ Test error code +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + + GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_TYPE vt2 = grin_get_vertex_type_by_name(g, "software"); + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_by_name(g, vt2, "lang"); + GRIN_VERTEX v = get_one_vertex(g); + +#ifdef GRIN_TRAIT_CONST_VALUE_PTR + const void* value = grin_get_vertex_property_value(g, v, vp); +#else + const char* value = grin_get_vertex_property_value_of_string(g, v, vp); +#endif + if (grin_get_last_error_code() == INVALID_VALUE) { + printf("(Correct) invalid value\n"); + } else { + printf("(Wrong) error code: %d\n", grin_get_last_error_code()); + } +} + +void test_property(int argc, char** argv) { + test_property_type(argc, argv); + test_property_topology(argc, argv); + test_property_vertex_property_value(argc, argv); + test_property_edge_property_value(argc, argv); +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS + test_property_primary_key(argc, argv); +#endif + test_error_code(argc, argv); +} + + +void test_partition_reference(int argc, char** argv) { + printf("+++++++++++++++++++++ Test partition/reference +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + GRIN_PARTITION p0 = get_partition(argc, argv); + +#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST + GRIN_VERTEX_LIST vlist = grin_get_vertex_list(g); + GRIN_VERTEX_LIST mvlist = grin_select_master_for_vertex_list(g, vlist); + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, mvlist); + grin_destroy_vertex_list(g, vlist); +#else + GRIN_VERTEX_LIST mvlist = grin_get_vertex_list(g); + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, mvlist); +#endif + + size_t cnt = 0; + size_t mcnt = 0; + while (!grin_is_vertex_list_end(g, vli)) { + cnt++; + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + GRIN_VERTEX_REF vref = grin_get_vertex_ref_by_vertex(g, v); +#ifdef GRIN_TRAIT_FAST_VERTEX_REF + long long int sref = grin_serialize_vertex_ref_as_int64(g, vref); + GRIN_VERTEX_REF vref1 = grin_deserialize_int64_to_vertex_ref(g, sref); +#else + const char* sref = grin_serialize_vertex_ref(g, vref); + GRIN_VERTEX_REF vref1 = grin_deserialize_vertex_ref(g, sref); + grin_destroy_string_value(g, sref); +#endif + GRIN_VERTEX v1 = grin_get_vertex_from_vertex_ref(g, vref1); + if (!grin_equal_vertex(g, v, v1)) { + printf("vertex not match\n"); + } + + if (grin_is_master_vertex(g, v)) { + mcnt++; + GRIN_PARTITION p = grin_get_master_partition_from_vertex_ref(g, vref); + if (!grin_equal_partition(g, p, p0)) { + printf("(Wrong) partition not match\n"); + } + } else if (grin_is_mirror_vertex(g, v)) { + GRIN_PARTITION p = grin_get_master_partition_from_vertex_ref(g, vref); + if (grin_equal_partition(g, p, p0)) { + printf("(Wrong) partition match\n"); + } + } else { + printf("(Wrong) vertex other than master or mirror\n"); + } + + grin_destroy_vertex_ref(g, vref); + grin_destroy_vertex(g, v); + grin_get_next_vertex_list_iter(g, vli); + } + printf("num of vertex checked: %zu\n", cnt); + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + size_t mvlist_size = grin_get_vertex_list_size(g, mvlist); + if (mvlist_size != mcnt) { + printf("(Wrong) master vertex list size not match\n"); + } else { + printf("Master vertex number: %zu\n", mcnt); + } +#endif + + grin_destroy_vertex_list(g, mvlist); + grin_destroy_graph(g); +} + +void test_partition(int argc, char** argv) { +#ifdef GRIN_ENABLE_GRAPH_PARTITION + test_partition_reference(argc, argv); +#endif +} + + +void test_topology_vertex_list(int argc, char** argv) { + GRIN_GRAPH g = get_graph(argc, argv); + + printf("vnum: %zu, enum: %zu\n", grin_get_vertex_num(g), grin_get_edge_num(g)); + +#ifdef GRIN_ENABLE_GRAPH_PARTITION + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); + GRIN_VERTEX_TYPE vtype = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_LIST svl = grin_select_type_for_vertex_list(g, vtype, vl); + GRIN_VERTEX_LIST mvl = grin_select_master_for_vertex_list(g, svl); + size_t mvl_sz = grin_get_vertex_list_size(g, mvl); + printf("master vertex list size: %zu\n", mvl_sz); +#endif + + grin_destroy_graph(g); +} + +void test_topology_adjacent_list(int argc, char** argv, GRIN_DIRECTION dir) { + printf("+++++++++++++++++++++ Test topology/adjacent_list +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, vl); + grin_destroy_vertex_list(g, vl); + + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_size = grin_get_edge_type_list_size(g, etl); + + while (!grin_is_vertex_list_end(g, vli)) { + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); +#ifdef GRIN_ENABLE_GRAPH_PARTITION + if (!grin_is_master_vertex(g, v)) { + grin_destroy_vertex(g, v); + grin_get_next_vertex_list_iter(g, vli); + continue; + } +#endif + GRIN_ADJACENT_LIST al = grin_get_adjacent_list(g, dir, v); + for (size_t i = 0; i <= etl_size; ++i) { + GRIN_ADJACENT_LIST al1 = al; + if (i < etl_size) { + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); + al1 = grin_select_edge_type_for_adjacent_list(g, et, al); + grin_destroy_edge_type(g, et); + } + + GRIN_ADJACENT_LIST_ITERATOR ali = grin_get_adjacent_list_begin(g, al1); + grin_destroy_adjacent_list(g, al1); + + size_t cnt = 0; + while (!grin_is_adjacent_list_end(g, ali)) { + cnt++; + GRIN_EDGE e = grin_get_edge_from_adjacent_list_iter(g, ali); + GRIN_VERTEX v1 = grin_get_src_vertex_from_edge(g, e); + GRIN_VERTEX v2 = grin_get_dst_vertex_from_edge(g, e); + GRIN_VERTEX u = grin_get_neighbor_from_adjacent_list_iter(g, ali); + + if (dir == OUT) { + if (!grin_equal_vertex(g, v, v1)) { + printf("vertex not match\n"); + } + if (!grin_equal_vertex(g, v2, u)) { + printf("vertex not match\n"); + } + } else { + if (!grin_equal_vertex(g, v, v2)) { + printf("vertex not match\n"); + } + if (!grin_equal_vertex(g, v1, u)) { + printf("vertex not match\n"); + } + } + + grin_destroy_vertex(g, v1); + grin_destroy_vertex(g, v2); + grin_destroy_vertex(g, u); + grin_destroy_edge(g, e); + grin_get_next_adjacent_list_iter(g, ali); + } +#ifdef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 + long long int vid = grin_get_vertex_original_id_of_int64(g, v); + if (dir == OUT) { + if (i < etl_size) { + printf("vertex %lld OUT adjacent list, edgetype: %zu checked num: %zu\n", vid, i, cnt); + } else { + printf("vertex %lld OUT adjacent list, edgetype: all checked num: %zu\n", vid, cnt); + } + } else { + if (i < etl_size) { + printf("vertex %lld IN adjacent list, edgetype: %zu checked num: %zu\n", vid, i, cnt); + } else { + printf("vertex %lld IN adjacent list, edgetype: all checked num: %zu\n", vid, cnt); + } + } +#endif + + grin_destroy_adjacent_list_iter(g, ali); + } + grin_destroy_vertex(g, v); + grin_get_next_vertex_list_iter(g, vli); + } + + grin_destroy_graph(g); +} + +void test_index_order(int argc, char** argv) { + printf("+++++++++++++++++++++ Test index/order +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv); + + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); + size_t vl_sz = grin_get_vertex_list_size(g, vl); + for (size_t i = 0; i < vl_sz; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, vl, i); + size_t p = grin_get_position_of_vertex_from_sorted_list(g, vl, v); + if (p != i) { + printf("vertex position not match\n"); + } + grin_destroy_vertex(g, v); + } + printf("%zu vertices checked\n", vl_sz); + +#ifdef GRIN_ENABLE_GRAPH_PARTITION + GRIN_VERTEX_LIST mvl = grin_select_master_for_vertex_list(g, vl); + size_t mvl_sz = grin_get_vertex_list_size(g, mvl); + for (size_t i = 0; i < mvl_sz; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, mvl, i); + size_t p = grin_get_position_of_vertex_from_sorted_list(g, mvl, v); + if (p != i) { + printf("vertex position not match\n"); + } + grin_destroy_vertex(g, v); + } + printf("%zu vertices checked\n", mvl_sz); + grin_destroy_vertex_list(g, mvl); +#endif + + GRIN_VERTEX_TYPE vtype = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_LIST svl = grin_select_type_for_vertex_list(g, vtype, vl); + size_t svl_sz = grin_get_vertex_list_size(g, svl); + for (size_t i = 0; i < svl_sz; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, svl, i); + size_t p = grin_get_position_of_vertex_from_sorted_list(g, svl, v); + if (p != i) { + printf("vertex position not match\n"); + } + grin_destroy_vertex(g, v); + } + printf("%zu vertices checked\n", svl_sz); + grin_destroy_vertex_list(g, svl); + + grin_destroy_vertex_list(g, vl); + grin_destroy_graph(g); +} + +void test_index(int argc, char** argv) { +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + test_index_order(argc, argv); +#endif +} + +void test_topology(int argc, char** argv) { + test_topology_vertex_list(argc, argv); + test_topology_adjacent_list(argc, argv, OUT); + test_topology_adjacent_list(argc, argv, IN); +} + +int main(int argc, char** argv) { + test_property(argc, argv); + test_partition(argc, argv); + test_topology(argc, argv); + test_index(argc, argv); + return 0; +} diff --git a/modules/graph/grin/docs/Doxyfile b/modules/graph/grin/docs/Doxyfile new file mode 100644 index 000000000..be27d5f55 --- /dev/null +++ b/modules/graph/grin/docs/Doxyfile @@ -0,0 +1,2691 @@ +# Doxyfile 1.9.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = GRIN + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Graph Retrieval Interface" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = _build/doxygen + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = README.md ../include ../predefine.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /