├── gremlinxx ├── gremlinxx_utils.h └── gremlinxx.h ├── structure ├── Direction.h ├── Order.h ├── Edge.h ├── Vertex.h ├── Element.h ├── Property.h ├── VertexProperty.h ├── Structure.cpp └── Graph.h ├── traversal ├── Comparison.cpp ├── Comparison.h ├── Scope.h ├── Traverser.cpp ├── Traverser.h ├── PathInfo.h ├── P.h ├── GraphTraversalSource.h ├── Scope.cpp ├── SyntaxHelper.h ├── PathInfo.cpp ├── GraphTraversalSource.cpp └── TraverserSet.h ├── NOTICE ├── strategy ├── HasJoinStrategy.h ├── NoOpRemovalStrategy.h ├── RepeatUnrollStrategy.h ├── BasicPatternExtractionStrategy.h ├── SubgraphStepCompletionStrategy.h ├── RepeatStepCompletionStrategy.h ├── FromToModulatingStrategy.h ├── LimitSupportingStrategy.h ├── ByModulatingStrategy.h ├── TraversalStrategy.cpp ├── NoOpRemovalStrategy.cpp ├── HasJoinStrategy.cpp ├── ByModulatingStrategy.cpp ├── TraversalStrategy.h ├── LimitSupportingStrategy.cpp ├── RepeatUnrollStrategy.cpp ├── SubgraphStepCompletionStrategy.cpp ├── BasicPatternExtractionStrategy.cpp ├── FromToModulatingStrategy.cpp └── RepeatStepCompletionStrategy.cpp ├── step ├── modulate │ ├── ByModulating.h │ ├── ByStep.cpp │ ├── FromToModulating.h │ ├── ByStep.h │ ├── ToStep.cpp │ ├── FromStep.cpp │ ├── FromStep.h │ ├── ToStep.h │ └── ReductionStep.h ├── controlflow │ ├── TimesStep.cpp │ ├── UntilStep.cpp │ ├── EmitStep.cpp │ ├── UntilStep.h │ ├── LoopsStep.h │ ├── TimesStep.h │ ├── EmitStep.h │ ├── InjectStep.h │ ├── CoalesceStep.h │ ├── UnionStep.h │ ├── LoopsStep.cpp │ ├── InjectStep.cpp │ ├── CoalesceStep.cpp │ ├── UnionStep.cpp │ ├── RepeatStep.h │ └── RepeatStep.cpp ├── filter │ ├── LimitSupportingStep.h │ ├── SampleStep.h │ ├── LimitStep.cpp │ ├── LimitStep.h │ ├── IsStep.h │ ├── WhereStep.h │ ├── IsStep.cpp │ ├── SampleStep.cpp │ └── WhereStep.cpp ├── logic │ ├── NoOpStep.cpp │ ├── IdentityStep.h │ ├── IdentityStep.cpp │ ├── NoOpStep.h │ ├── DedupStep.h │ ├── OrderStep.h │ ├── DedupStep.cpp │ └── OrderStep.cpp ├── embedding │ ├── EncodeStep.h │ ├── EmbeddingStep.cpp │ ├── SimilarityStep.h │ ├── EmbeddingStep.h │ ├── LikeStep.h │ ├── EncodeStep.cpp │ ├── SimilarityStep.cpp │ └── LikeStep.cpp ├── graph │ ├── IdStep.h │ ├── VStep.h │ ├── SubgraphStep.h │ ├── SubgraphExtractionStep.h │ ├── VStep.cpp │ ├── SubgraphExtractionStep.cpp │ ├── IdStep.cpp │ └── SubgraphStep.cpp ├── sideeffect │ ├── AsStep.h │ ├── AsStep.cpp │ ├── SideEffectStep.cpp │ ├── SelectStep.h │ ├── SideEffectStep.h │ └── SelectStep.cpp ├── vertex │ ├── AddVertexStep.h │ ├── AddVertexStartStep.h │ ├── DegreeStep.h │ ├── VertexStep.h │ ├── AddVertexStep.cpp │ ├── AddVertexStartStep.cpp │ ├── DegreeStep.cpp │ └── VertexStep.cpp ├── property │ ├── HasNotStep.h │ ├── ValueStep.h │ ├── PropertyStep.h │ ├── ElementMapStep.h │ ├── HasStep.h │ ├── HasNotStep.cpp │ ├── ElementMapStep.cpp │ ├── ValueStep.cpp │ ├── PropertyStep.cpp │ └── HasStep.cpp ├── math │ ├── CountStep.h │ ├── MinStep.h │ ├── GroupCountStep.h │ ├── GroupCountStep.cpp │ ├── MinStep.cpp │ └── CountStep.cpp ├── TraversalStep.h ├── TraversalStep.cpp └── edge │ ├── AddEdgeStep.h │ ├── AddEdgeStartStep.h │ ├── AddEdgeStartStep.cpp │ └── AddEdgeStep.cpp ├── .gitignore ├── step_reference.txt ├── util └── gremlin_utils.h ├── README.md └── CMakeLists.txt /gremlinxx/gremlinxx_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "util/gremlin_utils.h" -------------------------------------------------------------------------------- /structure/Direction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gremlinxx { 4 | 5 | enum Direction {IN, OUT, BOTH}; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /traversal/Comparison.cpp: -------------------------------------------------------------------------------- 1 | #include "traversal/Comparison.h" 2 | 3 | namespace gremlinxx { 4 | namespace comparison { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This software makes use of the Gremlin language, which is licensed under the Apache 2.0 License. 2 | Gremlin is part of the Apache Tinkerpop Project (tinkerpop.apache.org) 3 | 4 | -------------------------------------------------------------------------------- /strategy/HasJoinStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy HasJoinStrategy; 8 | 9 | } -------------------------------------------------------------------------------- /strategy/NoOpRemovalStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy NoOpRemovalStrategy; 8 | 9 | } -------------------------------------------------------------------------------- /structure/Order.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gremlinxx { 4 | 5 | enum Order{ 6 | ASC = 0, 7 | DESC = 1, 8 | SHUFFLE = 2 9 | }; 10 | 11 | } -------------------------------------------------------------------------------- /strategy/RepeatUnrollStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy RepeatUnrollStrategy; 8 | 9 | } -------------------------------------------------------------------------------- /strategy/BasicPatternExtractionStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy BasicPatternExtractionStrategy; 8 | 9 | } -------------------------------------------------------------------------------- /strategy/SubgraphStepCompletionStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy SubgraphStepCompletionStrategy; 8 | 9 | } -------------------------------------------------------------------------------- /strategy/RepeatStepCompletionStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "strategy/TraversalStrategy.h" 4 | 5 | namespace gremlinxx { 6 | 7 | extern TraversalStrategy RepeatStepCompletionStrategy; 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /step/modulate/ByModulating.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace gremlinxx { 6 | 7 | class ByModulating { 8 | public: 9 | virtual void modulate_by(std::any arg) = 0; 10 | }; 11 | 12 | } -------------------------------------------------------------------------------- /step/controlflow/TimesStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/TimesStep.h" 2 | 3 | namespace gremlinxx { 4 | 5 | TimesStep::TimesStep(size_t times) 6 | : TraversalStep(MODULATOR, TIMES_STEP) { 7 | this->times = times; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /strategy/FromToModulatingStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "strategy/TraversalStrategy.h" 6 | 7 | namespace gremlinxx { 8 | 9 | extern TraversalStrategy FromToModulatingStrategy; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /strategy/LimitSupportingStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "strategy/TraversalStrategy.h" 7 | 8 | namespace gremlinxx { 9 | 10 | extern TraversalStrategy LimitSupportingStrategy; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /step/controlflow/UntilStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/UntilStep.h" 2 | 3 | namespace gremlinxx { 4 | 5 | UntilStep::UntilStep(GraphTraversal traversal) 6 | : TraversalStep(MODULATOR, UNTIL_STEP) { 7 | this->traversal = traversal; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /strategy/ByModulatingStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "strategy/TraversalStrategy.h" 5 | #include 6 | #include 7 | 8 | namespace gremlinxx { 9 | 10 | extern TraversalStrategy ByModulatingStrategy; 11 | 12 | } -------------------------------------------------------------------------------- /step/modulate/ByStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/modulate/ByStep.h" 2 | 3 | namespace gremlinxx { 4 | 5 | ByStep::ByStep(std::any arg) 6 | : TraversalStep(MODULATOR, BY_STEP) { 7 | this->arg = arg; 8 | } 9 | 10 | std::string ByStep::getInfo() { 11 | return "ByStep(?)"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /step/filter/LimitSupportingStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace gremlinxx { 7 | 8 | class LimitSupportingStep { 9 | public: 10 | virtual void set_limit(size_t limit) = 0; 11 | virtual std::optional get_limit() = 0; 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /step/modulate/FromToModulating.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gremlinxx { 4 | 5 | class GraphTraversal; 6 | 7 | class FromToModulating { 8 | public: 9 | virtual void modulate_from(GraphTraversal trv) = 0; 10 | virtual void modulate_to(GraphTraversal trv) = 0; 11 | }; 12 | 13 | } -------------------------------------------------------------------------------- /structure/Edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "structure/Element.h" 8 | #include "structure/Vertex.h" 9 | 10 | namespace gremlinxx { 11 | 12 | struct Edge : public Element { 13 | public: 14 | Vertex from; 15 | Vertex to; 16 | }; 17 | 18 | } -------------------------------------------------------------------------------- /structure/Vertex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "structure/Property.h" 7 | #include "structure/VertexProperty.h" 8 | #include "structure/Element.h" 9 | #include "structure/Direction.h" 10 | 11 | namespace gremlinxx { 12 | 13 | struct Vertex : public Element {}; 14 | 15 | } -------------------------------------------------------------------------------- /step/logic/NoOpStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/logic/NoOpStep.h" 2 | 3 | namespace gremlinxx { 4 | 5 | NoOpStep::NoOpStep() 6 | : TraversalStep(MAP, NO_OP_STEP) {} 7 | 8 | std::string NoOpStep::getInfo() { 9 | return "NoOpStep()"; 10 | } 11 | 12 | void NoOpStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers){} 13 | 14 | } -------------------------------------------------------------------------------- /structure/Element.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace gremlinxx { 7 | 8 | /* 9 | The Element Structure 10 | All Elements in gremlin++ are Reference Elements 11 | All Elements must have a uint64_t id, including edges 12 | */ 13 | struct Element { 14 | public: 15 | std::string label = ""; 16 | size_t id = 0; 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /strategy/TraversalStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/TraversalStrategy.h" 2 | 3 | 4 | namespace gremlinxx { 5 | std::unordered_map strategy_type_names = { 6 | {DECORATION, "Decoration"}, 7 | {OPTIMIZATION, "Optimization"}, 8 | {PROVIDER, "Provider"}, 9 | {FINALIZATON, "Finalization"}, 10 | {VERIFICATION, "Verification"} 11 | }; 12 | } -------------------------------------------------------------------------------- /traversal/Comparison.h: -------------------------------------------------------------------------------- 1 | /* 2 | This header contains helper methods for comparisons of various property types. 3 | It is often used in conjunction with the min() and max() steps. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include "maelstrom/storage/datatype.h" 11 | 12 | class Vertex; 13 | 14 | namespace gremlinxx { 15 | namespace comparison { 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dylib 3 | *.dll 4 | *.so 5 | *.a 6 | *.lib 7 | *.exe 8 | *.stackdump 9 | test/test.* 10 | *.out 11 | *.stats 12 | *.xml 13 | prof.txt 14 | gprof.txt 15 | data/facebook.txt 16 | data/twitter.txt 17 | data/cfg_lca.graphml 18 | data/cfg_lca_nodes.txt 19 | data/cfg_lca_edges.txt 20 | data/cfg_lca.clangcppcfg 21 | CMakeFiles/ 22 | CMakeCache.txt 23 | *.cmake 24 | *.ninja_deps 25 | *.ninja_log 26 | *.ninja 27 | .vscode/ 28 | bin/ 29 | -------------------------------------------------------------------------------- /step/controlflow/EmitStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/EmitStep.h" 2 | 3 | namespace gremlinxx { 4 | 5 | EmitStep::EmitStep(GraphTraversal traversal) 6 | : TraversalStep(MODULATOR, EMIT_STEP) { 7 | this->traversal = traversal; 8 | } 9 | 10 | GraphTraversal EmitStep::getTraversal() { return this->traversal; } 11 | 12 | std::string EmitStep::getInfo() { 13 | return "EmitStep{traversal}"; 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /step/controlflow/UntilStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define UNTIL_STEP 0x43 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/GraphTraversal.h" 7 | 8 | namespace gremlinxx { 9 | 10 | class UntilStep: public TraversalStep { 11 | private: 12 | GraphTraversal traversal; 13 | 14 | public: 15 | UntilStep(GraphTraversal traversal); 16 | 17 | inline GraphTraversal getTraversal() { return this->traversal; } 18 | }; 19 | 20 | } -------------------------------------------------------------------------------- /step/modulate/ByStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define BY_STEP 0x92 7 | 8 | #include "traversal/GraphTraversal.h" 9 | #include "step/TraversalStep.h" 10 | 11 | namespace gremlinxx { 12 | 13 | class ByStep : public TraversalStep { 14 | private: 15 | std::any arg; 16 | public: 17 | ByStep(std::any arg); 18 | 19 | inline std::any get() { return arg; } 20 | 21 | using TraversalStep::getInfo; 22 | virtual std::string getInfo(); 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /step/controlflow/LoopsStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define LOOPS_STEP 0x4c 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/GraphTraversal.h" 7 | #include "traversal/Traverser.h" 8 | 9 | namespace gremlinxx { 10 | class LoopsStep: public TraversalStep { 11 | private: 12 | GraphTraversal* traversal; 13 | 14 | public: 15 | LoopsStep(); 16 | 17 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 18 | }; 19 | 20 | } -------------------------------------------------------------------------------- /step/controlflow/TimesStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define TIMES_STEP 0x4b 4 | 5 | #include "step/TraversalStep.h" 6 | 7 | namespace gremlinxx { 8 | 9 | class TimesStep: public TraversalStep { 10 | private: 11 | size_t times; 12 | 13 | public: 14 | TimesStep(size_t times); 15 | 16 | inline size_t get_times() { return this->times; } 17 | 18 | using TraversalStep::getInfo; 19 | virtual std::string getInfo() { return "TimesStep{}"; }; 20 | }; 21 | 22 | } -------------------------------------------------------------------------------- /step/filter/SampleStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SAMPLE_STEP 0x50 4 | 5 | #include "step/TraversalStep.h" 6 | 7 | namespace gremlinxx { 8 | 9 | class SampleStep: public TraversalStep { 10 | private: 11 | size_t count; 12 | 13 | public: 14 | SampleStep(size_t num_traversers); 15 | 16 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 17 | 18 | using TraversalStep::getInfo; 19 | virtual std::string getInfo(); 20 | }; 21 | 22 | } -------------------------------------------------------------------------------- /step/logic/IdentityStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IDENTITY_STEP 0x01 4 | #include "step/TraversalStep.h" 5 | #include "traversal/Traverser.h" 6 | #include "traversal/GraphTraversal.h" 7 | 8 | namespace gremlinxx { 9 | 10 | class IdentityStep: public TraversalStep { 11 | public: 12 | IdentityStep(); 13 | 14 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 15 | 16 | using TraversalStep::getInfo; 17 | virtual std::string getInfo(); 18 | }; 19 | 20 | } -------------------------------------------------------------------------------- /structure/Property.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace gremlinxx { 7 | 8 | /* 9 | Deprecated 10 | */ 11 | class Property { 12 | private: 13 | std::string my_key; 14 | std::any my_value; 15 | 16 | public: 17 | Property(std::string new_key, std::any new_value) { 18 | this->my_key = new_key; 19 | this->my_value = new_value; 20 | } 21 | 22 | virtual std::string key() { 23 | return this->my_key; 24 | } 25 | 26 | virtual std::any value() { 27 | return this->my_value; 28 | } 29 | }; 30 | 31 | } -------------------------------------------------------------------------------- /step/filter/LimitStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/filter/LimitStep.h" 2 | #include 3 | 4 | namespace gremlinxx { 5 | 6 | LimitStep::LimitStep(uint64_t limit) 7 | : TraversalStep(FILTER, LIMIT_STEP) { 8 | this->limit = limit; 9 | } 10 | 11 | std::string LimitStep::getInfo() { return "LimitStep(" + std::to_string(limit) + ")"; } 12 | 13 | void LimitStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 14 | if(limit < traversers.size()) { 15 | traversers.resize(limit); 16 | } 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /traversal/Scope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace gremlinxx { 9 | 10 | enum Scope {local, global}; 11 | 12 | typedef struct ScopeContext { 13 | Scope scope; 14 | std::optional side_effect_key; 15 | } ScopeContext; 16 | 17 | typedef int64_t scope_group_t; 18 | 19 | scope_group_t group_id_from_any(std::any a); 20 | 21 | std::any any_from_group_id(scope_group_t group_id, const std::type_info& out_type); 22 | 23 | } -------------------------------------------------------------------------------- /step/embedding/EncodeStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ENCODE_STEP 0x8c 4 | 5 | #include "step/TraversalStep.h" 6 | 7 | namespace gremlinxx { 8 | 9 | class EncodeStep : public TraversalStep { 10 | private: 11 | std::string emb_name; 12 | public: 13 | EncodeStep(std::string embedding_name); 14 | 15 | using TraversalStep::apply; 16 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 17 | 18 | using TraversalStep::getInfo; 19 | std::string getInfo(); 20 | }; 21 | 22 | } -------------------------------------------------------------------------------- /strategy/NoOpRemovalStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/NoOpRemovalStrategy.h" 2 | #include "step/logic/NoOpStep.h" 3 | 4 | namespace gremlinxx { 5 | 6 | TraversalStrategy NoOpRemovalStrategy = { 7 | OPTIMIZATION, 8 | "NoOpRemovalStrategy", 9 | [](std::vector>& steps){ 10 | for(auto it = steps.begin(); it != steps.end(); ++it) { 11 | auto& step = *it; 12 | if(step->uid == NO_OP_STEP) { 13 | it = steps.erase(it) - 1; 14 | } 15 | } 16 | } 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /step/controlflow/EmitStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define EMIT_STEP 0x44 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/GraphTraversal.h" 7 | 8 | // TODO make the traversal optional 9 | 10 | namespace gremlinxx { 11 | 12 | 13 | class EmitStep: public TraversalStep { 14 | 15 | private: 16 | GraphTraversal traversal; 17 | 18 | public: 19 | EmitStep(GraphTraversal traversal); 20 | 21 | GraphTraversal getTraversal(); 22 | 23 | using TraversalStep::getInfo; 24 | virtual std::string getInfo(); 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /step/graph/IdStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/Traverser.h" 5 | #include "structure/Vertex.h" 6 | #include "structure/Edge.h" 7 | 8 | #define ID_STEP 0x66 9 | 10 | namespace gremlinxx { 11 | 12 | class IdStep : public TraversalStep { 13 | public: 14 | IdStep(); 15 | 16 | using TraversalStep::getInfo; 17 | virtual std::string getInfo(); 18 | 19 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 20 | 21 | }; 22 | 23 | } -------------------------------------------------------------------------------- /step/logic/IdentityStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/logic/IdentityStep.h" 2 | namespace gremlinxx { 3 | 4 | IdentityStep::IdentityStep() 5 | : TraversalStep(MAP, IDENTITY_STEP) {} 6 | 7 | std::string IdentityStep::getInfo() { return "IdentityStep{}"; } 8 | 9 | void IdentityStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers){ 10 | traversers.advance([](auto& data, auto& se, auto& p){ 11 | return std::make_pair( 12 | maelstrom::vector(data), 13 | maelstrom::vector() 14 | ); 15 | }); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /step/sideeffect/AsStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define AS_STEP 0x31 4 | 5 | #include 6 | #include "step/TraversalStep.h" 7 | #include "traversal/Traverser.h" 8 | 9 | namespace gremlinxx { 10 | 11 | class AsStep: public TraversalStep { 12 | private: 13 | std::string sideEffectLabel; 14 | 15 | public: 16 | AsStep(std::string se_label); 17 | 18 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 19 | 20 | using TraversalStep::getInfo; 21 | virtual std::string getInfo(); 22 | }; 23 | 24 | } -------------------------------------------------------------------------------- /step/embedding/EmbeddingStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/embedding/EmbeddingStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Graph.h" 4 | 5 | namespace gremlinxx { 6 | 7 | void EmbeddingStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 8 | Graph* graph = traversal->getGraph(); 9 | auto data = traversers.getTraverserData(); 10 | 11 | graph->set_vertex_embeddings(this->name, data, this->embedding, this->default_value); 12 | } 13 | 14 | std::string EmbeddingStep::getInfo() { 15 | return "EmbeddingStep{" + this->name + "}"; 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /step/vertex/AddVertexStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/Traverser.h" 5 | #include 6 | #include 7 | 8 | #define ADD_VERTEX_STEP 0x71 9 | 10 | namespace gremlinxx { 11 | 12 | class AddVertexStep: public TraversalStep { 13 | private: 14 | std::string label; 15 | bool has_label; 16 | public: 17 | AddVertexStep(std::string label_arg); 18 | 19 | AddVertexStep(); 20 | 21 | using TraversalStep::getInfo; 22 | virtual std::string getInfo(); 23 | 24 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /step/logic/NoOpStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NO_OP_STEP 0x00 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/GraphTraversal.h" 7 | #include "traversal/Traverser.h" 8 | 9 | namespace gremlinxx { 10 | 11 | // Not technically part of Gremlin; just for 12 | // use as a intermediate representation. 13 | // Should not be confused with the identity 14 | // step. 15 | class NoOpStep: public TraversalStep { 16 | public: 17 | NoOpStep(); 18 | 19 | using TraversalStep::getInfo; 20 | virtual std::string getInfo(); 21 | 22 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /step/property/HasNotStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define HAS_NOT_STEP 0x84 4 | 5 | #include "step/TraversalStep.h" 6 | 7 | namespace gremlinxx { 8 | 9 | class HasNotStep : public TraversalStep { 10 | private: 11 | std::string property_key; 12 | public: 13 | HasNotStep(std::string key) 14 | : TraversalStep(FILTER, HAS_NOT_STEP) { 15 | this->property_key = key; 16 | } 17 | 18 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 19 | 20 | using TraversalStep::getInfo; 21 | std::string getInfo(); 22 | }; 23 | 24 | } -------------------------------------------------------------------------------- /step/controlflow/InjectStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define INJECT_STEP 0x74 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/Traverser.h" 7 | #include 8 | #include 9 | 10 | namespace gremlinxx { 11 | 12 | class GraphTraversal; 13 | 14 | class InjectStep : public TraversalStep { 15 | private: 16 | std::vector objects; 17 | 18 | public: 19 | InjectStep(std::vector& injects); 20 | 21 | InjectStep(std::any& b); 22 | 23 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /step/controlflow/CoalesceStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COALESCE_STEP 0x40 4 | 5 | #include 6 | 7 | #include "step/TraversalStep.h" 8 | #include "traversal/Traverser.h" 9 | #include "traversal/GraphTraversal.h" 10 | 11 | namespace gremlinxx { 12 | class CoalesceStep: public TraversalStep { 13 | private: 14 | std::vector traversals; 15 | public: 16 | CoalesceStep(std::vector& traversals); 17 | std::vector& get_traversals(); 18 | virtual void apply(GraphTraversal* parent_traversal, gremlinxx::traversal::TraverserSet& traversers); 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /step/sideeffect/AsStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/sideeffect/AsStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | 4 | namespace gremlinxx { 5 | 6 | AsStep::AsStep(std::string se_label) 7 | : TraversalStep(SIDE_EFFECT, AS_STEP) { 8 | this->sideEffectLabel = se_label; 9 | } 10 | 11 | std::string AsStep::getInfo() { return "AsStep{" + sideEffectLabel + "}"; } 12 | 13 | void AsStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 14 | if(traversers.empty()) return; 15 | 16 | traversers.set_side_effects( 17 | this->sideEffectLabel, 18 | std::move(traversers.getTraverserData()) 19 | ); 20 | } 21 | 22 | 23 | } -------------------------------------------------------------------------------- /step/vertex/AddVertexStartStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class GraphTraversal; 4 | class Traverser; 5 | 6 | #include "step/TraversalStep.h" 7 | #include "traversal/Traverser.h" 8 | 9 | #include 10 | #include 11 | 12 | #define ADD_VERTEX_START_STEP 0x70 13 | 14 | namespace gremlinxx { 15 | 16 | class AddVertexStartStep: public TraversalStep { 17 | private: 18 | std::string label; 19 | bool has_label; 20 | public: 21 | AddVertexStartStep(std::string label_arg); 22 | 23 | AddVertexStartStep(); 24 | 25 | using TraversalStep::getInfo; 26 | virtual std::string getInfo(); 27 | 28 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 29 | }; 30 | 31 | } -------------------------------------------------------------------------------- /step/filter/LimitStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define LIMIT_STEP 0x48 4 | 5 | #include 6 | #include "step/TraversalStep.h" 7 | #include "traversal/Traverser.h" 8 | 9 | namespace gremlinxx { 10 | 11 | class LimitStep: public TraversalStep { 12 | private: 13 | uint64_t limit; 14 | 15 | public: 16 | LimitStep(uint64_t limit); 17 | 18 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 19 | 20 | using TraversalStep::getInfo; 21 | virtual std::string getInfo(); 22 | 23 | inline uint64_t get_limit() { return this->limit; } 24 | }; 25 | 26 | 27 | } -------------------------------------------------------------------------------- /step/graph/VStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "step/TraversalStep.h" 8 | #include "traversal/Traverser.h" 9 | 10 | #define V_STEP 0x81 11 | 12 | namespace gremlinxx { 13 | 14 | class VStep : public TraversalStep { 15 | protected: 16 | maelstrom::vector element_ids; 17 | public: 18 | VStep(std::vector eids); 19 | VStep(maelstrom::vector eids); 20 | 21 | using TraversalStep::getInfo; 22 | virtual std::string getInfo(); 23 | 24 | inline maelstrom::vector& get_element_ids() { return this->element_ids; } 25 | 26 | using TraversalStep::apply; 27 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /step/controlflow/UnionStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define UNION_STEP 0x4a 4 | 5 | #include 6 | 7 | #include "traversal/GraphTraversal.h" 8 | #include "traversal/Traverser.h" 9 | #include "step/TraversalStep.h" 10 | 11 | namespace gremlinxx { 12 | 13 | class UnionStep: public TraversalStep { 14 | private: 15 | std::vector traversals; 16 | public: 17 | UnionStep(std::vector& traversals); 18 | std::vector& get_traversals(); 19 | virtual void apply(GraphTraversal* parent_traversal, gremlinxx::traversal::TraverserSet& traversers); 20 | 21 | using TraversalStep::getInfo; 22 | virtual std::string getInfo(); 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /step/modulate/ToStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/modulate/ToStep.h" 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "traversal/SyntaxHelper.h" 5 | #include "structure/Vertex.h" 6 | 7 | namespace gremlinxx { 8 | 9 | ToStep::ToStep(GraphTraversal to_vertex_traversal) 10 | : TraversalStep(MODULATOR, TO_STEP) { 11 | traversal.emplace(std::move(to_vertex_traversal)); 12 | } 13 | 14 | ToStep::ToStep(std::string side_effect_label) 15 | : TraversalStep(MODULATOR, TO_STEP) { 16 | traversal.emplace(std::move(select(side_effect_label))); 17 | } 18 | 19 | ToStep::ToStep(Vertex to_vertex) 20 | : TraversalStep(MODULATOR, TO_STEP) { 21 | traversal.emplace(std::move(V(to_vertex))); 22 | } 23 | 24 | std::string ToStep::getInfo() { 25 | return "ToStep {?}"; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /step/sideeffect/SideEffectStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/sideeffect/SideEffectStep.h" 2 | 3 | #include "maelstrom/algorithms/set.h" 4 | 5 | namespace gremlinxx { 6 | 7 | void SideEffectStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 8 | maelstrom::vector se_data( 9 | traversers.getCurrentMemType(), 10 | maelstrom::dtype_from_prim_type(maelstrom::prim_type_of(this->value)), 11 | traversers.size() 12 | ); 13 | maelstrom::set(se_data, this->value); 14 | 15 | traversers.set_side_effects( 16 | this->label, 17 | std::move(se_data) 18 | ); 19 | } 20 | 21 | std::string SideEffectStep::getInfo() { 22 | return "SideEffectStep{}"; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /step/sideeffect/SelectStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SELECT_STEP 0x32 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "step/TraversalStep.h" 10 | #include "traversal/Traverser.h" 11 | 12 | namespace gremlinxx { 13 | 14 | class SelectStep: public TraversalStep { 15 | private: 16 | std::string sideEffectLabel; 17 | 18 | public: 19 | SelectStep(std::string se_label); 20 | 21 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 22 | 23 | using TraversalStep::getInfo; 24 | virtual std::string getInfo(); 25 | 26 | inline std::string get_side_effect_label() { return this->sideEffectLabel; } 27 | }; 28 | 29 | } -------------------------------------------------------------------------------- /step/sideeffect/SideEffectStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | 5 | #define SIDE_EFFECT_STEP 0x30 6 | 7 | namespace gremlinxx { 8 | 9 | class SideEffectStep : public TraversalStep { 10 | private: 11 | std::string label; 12 | std::any value; 13 | 14 | public: 15 | SideEffectStep(std::string se_label, std::any se_value) 16 | : TraversalStep(SIDE_EFFECT, SIDE_EFFECT_STEP) { 17 | this->label = se_label; 18 | this->value = se_value; 19 | } 20 | 21 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 22 | 23 | using TraversalStep::getInfo; 24 | virtual std::string getInfo(); 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /step/filter/IsStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IS_STEP 0x46 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/Traverser.h" 7 | #include "traversal/P.h" 8 | #include 9 | #include 10 | 11 | namespace gremlinxx { 12 | 13 | class GraphTraversal; 14 | 15 | class IsStep: public TraversalStep { 16 | private: 17 | P predicate = P(maelstrom::EQUALS, std::any()); 18 | 19 | public: 20 | IsStep(P predicate); 21 | 22 | inline P getPredicate() { return this->predicate; } 23 | 24 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 25 | 26 | using TraversalStep::getInfo; 27 | virtual std::string getInfo(); 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /step/math/CountStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COUNT_STEP 0x61 4 | 5 | #include "step/modulate/ReductionStep.h" 6 | #include "traversal/Traverser.h" 7 | #include 8 | 9 | namespace gremlinxx { 10 | 11 | class CountStep : public ReductionStep { 12 | public: 13 | CountStep(); 14 | 15 | using ReductionStep::getInfo; 16 | virtual std::string getInfo(); 17 | 18 | using ReductionStep::apply_global; 19 | virtual void apply_global(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 20 | 21 | using ReductionStep::apply_local; 22 | virtual void apply_local(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /step/TraversalStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "traversal/TraverserSet.h" 7 | 8 | namespace gremlinxx { 9 | 10 | class GraphTraversal; 11 | enum TraversalStepType {MAP, FILTER, BARRIER, MODULATOR, SIDE_EFFECT}; 12 | 13 | class TraversalStep { 14 | private: 15 | TraversalStepType type; 16 | 17 | public: 18 | unsigned int uid; 19 | bool is_barrier; 20 | TraversalStep(TraversalStepType tsType, unsigned int id); 21 | TraversalStep(bool is_barrier, TraversalStepType tsType, unsigned int id); 22 | virtual std::string getInfo(); 23 | virtual std::string getInfo(size_t indent); 24 | virtual std::string getInfo(GraphTraversal* parent_traversal); 25 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 26 | 27 | }; 28 | 29 | } -------------------------------------------------------------------------------- /step/embedding/SimilarityStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SIMILARITY_STEP 0x8a 4 | 5 | #include "step/TraversalStep.h" 6 | #include "maelstrom/algorithms/similarity.h" 7 | 8 | namespace gremlinxx { 9 | 10 | class SimilarityStep : public TraversalStep { 11 | private: 12 | maelstrom::similarity_t similarity_metric; 13 | std::string name; 14 | maelstrom::vector embeddings; 15 | size_t emb_stride; 16 | 17 | public: 18 | SimilarityStep(std::string emb_name, std::vector& embedding_values, maelstrom::similarity_t metric=maelstrom::COSINE); 19 | 20 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 21 | 22 | using TraversalStep::getInfo; 23 | std::string getInfo(); 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /step/property/ValueStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/Traverser.h" 5 | #include "structure/Property.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #define VALUE_STEP 0x67 11 | 12 | namespace gremlinxx { 13 | 14 | class ValueStep: public TraversalStep { 15 | private: 16 | std::vector keys; //duplicates are allowed, per api 17 | 18 | public: 19 | ValueStep(std::vector property_keys); 20 | 21 | inline std::vector& get_keys() { return keys; } 22 | 23 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 24 | 25 | using TraversalStep::getInfo; 26 | std::string getInfo(); 27 | }; 28 | 29 | } -------------------------------------------------------------------------------- /step/modulate/FromStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/modulate/FromStep.h" 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "structure/Vertex.h" 5 | #include "traversal/SyntaxHelper.h" 6 | 7 | namespace gremlinxx { 8 | 9 | FromStep::FromStep(GraphTraversal from_vertex_traversal) 10 | : TraversalStep(MODULATOR, FROM_STEP) { 11 | traversal.emplace(std::move(from_vertex_traversal)); 12 | } 13 | 14 | FromStep::FromStep(std::string side_effect_label) 15 | : TraversalStep(MODULATOR, FROM_STEP) { 16 | GraphTraversal trv = select(side_effect_label); 17 | traversal.emplace(std::move(trv)); 18 | } 19 | 20 | FromStep::FromStep(Vertex to_vertex) 21 | : TraversalStep(MODULATOR, FROM_STEP) { 22 | GraphTraversal trv = V(to_vertex); 23 | traversal.emplace(std::move(trv)); 24 | } 25 | 26 | std::string FromStep::getInfo() { 27 | return "FromStep {?}"; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /traversal/Traverser.cpp: -------------------------------------------------------------------------------- 1 | #include "traversal/Traverser.h" 2 | 3 | namespace gremlinxx { 4 | 5 | Traverser::Traverser(std::any t) { 6 | my_data = std::any(t); 7 | } 8 | 9 | Traverser::Traverser(std::any t, std::unordered_map& new_side_effects) { 10 | my_data = std::any(t); 11 | this->side_effects = new_side_effects; 12 | } 13 | 14 | Traverser::Traverser() : Traverser(std::any()){} 15 | 16 | std::any Traverser::get() { 17 | return my_data; 18 | } 19 | 20 | void Traverser::replace_data(std::any t) { 21 | my_data = t; 22 | } 23 | 24 | std::unordered_map& Traverser::access_side_effects() { 25 | return this->side_effects; 26 | } 27 | 28 | std::vector& Traverser::access_path() { 29 | return this->path; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /step/graph/SubgraphStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SUBGRAPH_STEP 0x82 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/Traverser.h" 7 | #include "structure/Graph.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define SUBGRAPH_PREFIX std::string("TP_SUBGRAPH_") 14 | 15 | namespace gremlinxx { 16 | 17 | class SubgraphStep: public TraversalStep { 18 | private: 19 | std::string subgraph_name; 20 | 21 | public: 22 | SubgraphStep(std::string name); 23 | 24 | inline std::string get_subgraph_name() { return this->subgraph_name; } 25 | 26 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 27 | 28 | using TraversalStep::getInfo; 29 | virtual std::string getInfo(); 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /step/graph/SubgraphExtractionStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "step/graph/SubgraphStep.h" 5 | #include "traversal/Traverser.h" 6 | 7 | #include 8 | 9 | #define SUBGRAPH_EXTRACTION_STEP 0x65 10 | 11 | namespace gremlinxx { 12 | 13 | class SubgraphExtractionStep : public TraversalStep { 14 | private: 15 | std::unordered_set subgraph_names; 16 | 17 | public: 18 | SubgraphExtractionStep(std::unordered_set sg_names); 19 | 20 | inline std::unordered_set get_subgraph_names() { return this->subgraph_names; } 21 | 22 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 23 | 24 | using TraversalStep::getInfo; 25 | virtual std::string getInfo(); 26 | }; 27 | 28 | } -------------------------------------------------------------------------------- /step/math/MinStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MIN_STEP 0x60 4 | 5 | #include "step/TraversalStep.h" 6 | #include "step/modulate/ReductionStep.h" 7 | #include "traversal/Traverser.h" 8 | #include "traversal/Scope.h" 9 | #include "traversal/Comparison.h" 10 | 11 | #include 12 | 13 | namespace gremlinxx { 14 | 15 | class MinStep : public ReductionStep { 16 | public: 17 | MinStep(); 18 | 19 | using ReductionStep::apply_global; 20 | virtual void apply_global(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 21 | 22 | using ReductionStep::apply_local; 23 | virtual void apply_local(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 24 | 25 | using ReductionStep::getInfo; 26 | virtual std::string getInfo(); 27 | }; 28 | 29 | } -------------------------------------------------------------------------------- /step/vertex/DegreeStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DEGREE_STEP 0x7f 4 | 5 | #include "step/TraversalStep.h" 6 | #include "structure/Direction.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace gremlinxx { 12 | 13 | class DegreeStep: public TraversalStep { 14 | private: 15 | Direction direction; 16 | std::set edge_labels; 17 | 18 | public: 19 | DegreeStep(Direction dir, std::set edge_labels_arg); 20 | 21 | using TraversalStep::getInfo; 22 | virtual std::string getInfo(); 23 | 24 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 25 | 26 | inline virtual Direction get_direction() { return this->direction; } 27 | 28 | inline std::set get_edge_labels() { return this->edge_labels; } 29 | }; 30 | 31 | } -------------------------------------------------------------------------------- /traversal/Traverser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace gremlinxx { 9 | 10 | class Traverser { 11 | private: 12 | std::any my_data; 13 | std::vector path; 14 | std::unordered_map side_effects; 15 | 16 | public: 17 | Traverser(std::any t); 18 | 19 | Traverser(std::any t, std::unordered_map& new_side_effects); 20 | 21 | Traverser(); 22 | 23 | virtual std::any get(); 24 | 25 | virtual void replace_data(std::any t); 26 | 27 | /** 28 | * Returns a reference to this traverser's side effect map. 29 | * **/ 30 | virtual std::unordered_map& access_side_effects(); 31 | 32 | /* 33 | Returns a reference to this traverser's path info. 34 | */ 35 | virtual std::vector& access_path(); 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /step/filter/WhereStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WHERE_STEP 0x45 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/P.h" 7 | #include "traversal/Traverser.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace gremlinxx { 13 | 14 | class GraphTraversal; 15 | 16 | class WhereStep: public TraversalStep { 17 | private: 18 | std::string label; 19 | P predicate = P(maelstrom::EQUALS, std::any()); 20 | 21 | public: 22 | WhereStep(std::string label, P predicate); 23 | 24 | inline std::string getLabel() { return this->label; } 25 | inline P getPredicate() { return this->predicate; } 26 | 27 | using TraversalStep::getInfo; 28 | virtual std::string getInfo(); 29 | 30 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /step/embedding/EmbeddingStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define EMBEDDING_STEP 0x76 4 | 5 | #include "step/TraversalStep.h" 6 | #include "maelstrom/containers/vector.h" 7 | 8 | namespace gremlinxx { 9 | 10 | class EmbeddingStep: public TraversalStep { 11 | private: 12 | std::string name; 13 | maelstrom::vector embedding; 14 | std::any default_value; 15 | 16 | public: 17 | EmbeddingStep(std::string name, maelstrom::vector emb, std::any default_val=std::any()) 18 | : TraversalStep(MAP, EMBEDDING_STEP) { 19 | this->name = name; 20 | this->embedding = std::move(emb); 21 | this->default_value = default_val; 22 | } 23 | 24 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 25 | 26 | using TraversalStep::getInfo; 27 | std::string getInfo(); 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /structure/VertexProperty.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Property.h" 11 | 12 | namespace gremlinxx { 13 | 14 | /* 15 | Deprecated 16 | */ 17 | enum Cardinality {SINGLE, LIST, SET}; 18 | 19 | /* 20 | Deprecated 21 | */ 22 | class VertexProperty: public Property { 23 | private: 24 | // kv pairs 25 | std::unordered_map my_values; 26 | public: 27 | VertexProperty(std::string new_key, std::any new_value) 28 | : Property(new_key, new_value) {} 29 | 30 | VertexProperty(std::string new_key, std::any new_value, std::unordered_map& new_values) 31 | : Property(new_key, new_value) { 32 | my_values = new_values; 33 | } 34 | 35 | virtual std::unordered_map values() { 36 | return my_values; 37 | } 38 | }; 39 | 40 | } -------------------------------------------------------------------------------- /step/modulate/FromStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/GraphTraversal.h" 5 | 6 | #include 7 | #include 8 | 9 | #define FROM_STEP 0x90 10 | 11 | namespace gremlinxx { 12 | class Vertex; 13 | 14 | class FromStep : public TraversalStep { 15 | private: 16 | std::any arg; 17 | std::optional traversal; 18 | public: 19 | FromStep(std::string side_effect_label); 20 | 21 | FromStep(Vertex to_vertex); 22 | 23 | FromStep(GraphTraversal from_vertex_traversal); 24 | 25 | using TraversalStep::getInfo; 26 | virtual std::string getInfo(); 27 | 28 | inline std::any get_arg() { 29 | if(!arg.has_value()) throw std::runtime_error("step does not contain arg"); 30 | return arg; 31 | } 32 | 33 | inline GraphTraversal& get_traversal() { 34 | if(!traversal) throw std::runtime_error("step does not contain traversal"); 35 | return traversal.value(); 36 | } 37 | }; 38 | 39 | } -------------------------------------------------------------------------------- /structure/Structure.cpp: -------------------------------------------------------------------------------- 1 | #include "structure/Element.h" 2 | #include "structure/Vertex.h" 3 | #include "structure/Edge.h" 4 | #include "structure/Direction.h" 5 | #include "structure/Order.h" 6 | 7 | #include "structure/Graph.h" 8 | 9 | #include "maelstrom/algorithms/count_unique.h" 10 | 11 | namespace gremlinxx { 12 | std::pair Graph::degree(maelstrom::vector& current_vertices, std::vector& labels, gremlinxx::Direction dir) { 13 | maelstrom::vector output_origin; 14 | std::tie(std::ignore, output_origin) = this->V(current_vertices, labels, dir); 15 | 16 | maelstrom::vector degrees; 17 | std::tie(output_origin, degrees) = maelstrom::count_unique( 18 | output_origin, 19 | current_vertices.size(), 20 | false 21 | ); 22 | 23 | return std::make_pair( 24 | std::move(degrees), 25 | std::move(output_origin) 26 | ); 27 | } 28 | } -------------------------------------------------------------------------------- /step/graph/VStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/graph/VStep.h" 2 | #include "util/gremlin_utils.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace gremlinxx { 8 | 9 | VStep::VStep(std::vector eids) 10 | : TraversalStep(MAP, V_STEP) { 11 | this->element_ids = std::move( 12 | maelstrom::make_vector_from_anys(maelstrom::PINNED, eids) 13 | ); 14 | } 15 | 16 | VStep::VStep(maelstrom::vector eids) 17 | : TraversalStep(MAP, V_STEP) { 18 | this->element_ids = std::move(eids); 19 | } 20 | 21 | std::string VStep::getInfo() { 22 | std::stringstream sx; 23 | sx << "VStep("; 24 | sx << ((this->element_ids.empty()) ? "" : "..."); 25 | sx << ")"; 26 | 27 | return sx.str(); 28 | } 29 | 30 | void VStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 31 | throw std::runtime_error("Cannot call V() from an anonymous traversal!"); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /step/modulate/ToStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "structure/Vertex.h" 4 | #include "step/TraversalStep.h" 5 | #include "traversal/GraphTraversal.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #define TO_STEP 0x91 11 | 12 | namespace gremlinxx { 13 | 14 | class ToStep : public TraversalStep { 15 | private: 16 | std::any arg; 17 | std::optional traversal = {}; 18 | public: 19 | ToStep(std::string side_effect_label); 20 | 21 | ToStep(Vertex to_vertex); 22 | 23 | ToStep(GraphTraversal to_vertex_traversal); 24 | 25 | inline std::any get_arg() { 26 | if(!arg.has_value()) throw std::runtime_error("Argument is not present!"); 27 | return arg; 28 | } 29 | 30 | inline GraphTraversal& get_traversal() { 31 | if(!traversal) throw std::runtime_error("traversal is not present!"); 32 | return traversal.value(); 33 | } 34 | 35 | using TraversalStep::getInfo; 36 | virtual std::string getInfo(); 37 | }; 38 | 39 | } -------------------------------------------------------------------------------- /strategy/HasJoinStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/HasJoinStrategy.h" 2 | #include "step/property/HasStep.h" 3 | 4 | namespace gremlinxx { 5 | 6 | TraversalStrategy HasJoinStrategy = { 7 | OPTIMIZATION, 8 | "HasJoinStrategy", 9 | [](std::vector>& steps){ 10 | for(auto it = steps.begin(); it != steps.end(); ++it) { 11 | if((*it)->uid == HAS_STEP) { 12 | HasStep* has_step = static_cast(it->get()); 13 | while(it != steps.end() - 1 && (*(it+1))->uid == HAS_STEP) { 14 | HasStep* next_has_step = static_cast((it+1)->get()); 15 | has_step->join(next_has_step); 16 | 17 | it = steps.erase(it+1) - 1; 18 | if(it->get() != has_step) throw std::domain_error("Expected a Has Step"); 19 | } 20 | } 21 | } 22 | } 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /strategy/ByModulatingStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/ByModulatingStrategy.h" 2 | #include "step/TraversalStep.h" 3 | #include "step/modulate/ByModulating.h" 4 | #include "step/modulate/ByStep.h" 5 | #include "step/logic/NoOpStep.h" 6 | 7 | namespace gremlinxx { 8 | 9 | TraversalStrategy ByModulatingStrategy = { 10 | FINALIZATON, 11 | "ByModulatingStrategy", 12 | [](std::vector>& steps){ 13 | if(steps[0]->uid == BY_STEP) throw std::runtime_error("Cannot start a traversal with by()!"); 14 | 15 | for(size_t k = 1; k < steps.size(); ++k) { 16 | if(steps[k]->uid == BY_STEP) { 17 | dynamic_cast(steps[k-1].get())->modulate_by(static_cast(steps[k].get())->get()); 18 | 19 | // replace the step 20 | steps[k] = std::shared_ptr(new NoOpStep()); 21 | } 22 | } 23 | } 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /strategy/TraversalStrategy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "traversal/GraphTraversal.h" 9 | #include "step/TraversalStep.h" 10 | 11 | namespace gremlinxx { 12 | enum TraversalStrategyType { 13 | DECORATION = 0, 14 | OPTIMIZATION = 1, 15 | PROVIDER = 2, 16 | FINALIZATON = 3, 17 | VERIFICATION = 4 18 | }; 19 | 20 | extern std::unordered_map strategy_type_names; 21 | 22 | /* 23 | Traversal Strategies operate on a vector of steps, mutating it as necessary. 24 | */ 25 | struct TraversalStrategy { 26 | public: 27 | TraversalStrategyType type; 28 | std::string name; 29 | std::function>&)> apply; 30 | inline void operator()(std::vector>& steps) { this->apply(steps); } 31 | }; 32 | 33 | } -------------------------------------------------------------------------------- /step_reference.txt: -------------------------------------------------------------------------------- 1 | NO_OP_STEP 0x00 2 | IDENTITY_STEP 0x01 3 | # 0x10 through 0x2f reserved for backends 4 | SIDE_EFFECT_STEP 0x30 5 | AS_STEP 0x31 6 | SELECT_STEP 0x32 7 | MAP_STEP 0x3c 8 | FOLD_STEP 0x3f 9 | COALESCE_STEP 0x40 10 | UNFOLD_STEP 0x41 11 | REPEAT_STEP 0x42 12 | UNTIL_STEP 0x43 13 | EMIT_STEP 0x44 14 | WHERE_STEP 0x45 15 | IS_STEP 0x46 16 | ORDER_STEP 0x47 17 | LIMIT_STEP 0x48 18 | DEDUP_STEP 0x49 19 | UNION_STEP 0x4a 20 | TIMES_STEP 0x4b 21 | LOOPS_STEP 0x4c 22 | SAMPLE_STEP 0x50 23 | MIN_STEP 0x60 24 | COUNT_STEP 0x61 25 | GROUP_COUNT_STEP 0x62 26 | SUBGRAPH_EXTRACTION_STEP 0x65 27 | ID_STEP 0x66 28 | VALUE_STEP 0x67 29 | ELEMENTMAP_STEP 0x68 30 | ADD_VERTEX_START_STEP 0x70 31 | ADD_VERTEX_STEP 0x71 32 | ADD_EDGE_START_STEP 0x72 33 | ADD_EDGE_STEP 0x73 34 | INJECT_STEP 0x74 35 | PROPERTY_STEP 0x75 36 | EMBEDDING_STEP 0x76 37 | DEGREE_STEP 0x7f 38 | VERTEX_STEP 0x80 39 | V_STEP 0x81 40 | SUBGRAPH_STEP 0x82 41 | HAS_STEP 0x83 42 | HAS_NOT_STEP 0x84 43 | SIMILARITY_STEP 0x8a 44 | LIKE_STEP 0x8b 45 | ENCODE_STEP 0x8c 46 | FROM_STEP 0x90 47 | TO_STEP 0x91 48 | BY_STEP 0x92 -------------------------------------------------------------------------------- /step/logic/DedupStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DEDUP_STEP 0x49 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "step/TraversalStep.h" 10 | #include "step/modulate/ByModulating.h" 11 | #include "traversal/Traverser.h" 12 | 13 | namespace gremlinxx { 14 | 15 | // In the future this may get optimized away for most traversals by moving 16 | // the barrier to the left of the step and testing each element upon appearance 17 | class DedupStep: public TraversalStep, virtual public ByModulating { 18 | private: 19 | std::optional dedup_by_key; // TODO make this actually do something 20 | 21 | public: 22 | // This is a barrier step 23 | DedupStep(); 24 | 25 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 26 | 27 | using TraversalStep::getInfo; 28 | virtual std::string getInfo(); 29 | 30 | virtual void modulate_by(std::any arg); 31 | }; 32 | 33 | } -------------------------------------------------------------------------------- /strategy/LimitSupportingStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/LimitSupportingStrategy.h" 2 | #include "step/filter/LimitStep.h" 3 | #include "step/filter/LimitSupportingStep.h" 4 | #include "step/logic/NoOpStep.h" 5 | 6 | namespace gremlinxx { 7 | 8 | TraversalStrategy LimitSupportingStrategy = { 9 | OPTIMIZATION, 10 | "LimitSupportingStrategy", 11 | [](std::vector>& steps) { 12 | for(size_t k = 1; k < steps.size(); ++k) { 13 | if(steps[k]->uid == LIMIT_STEP) { 14 | LimitStep* ls = static_cast(steps[k].get()); 15 | LimitSupportingStep* lss = dynamic_cast(steps[k-1].get()); 16 | if(lss != nullptr) { 17 | lss->set_limit(ls->get_limit()); 18 | steps[k] = std::move( 19 | std::shared_ptr(new NoOpStep()) 20 | ); 21 | } 22 | } 23 | } 24 | } 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /step/TraversalStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/TraversalStep.h" 2 | 3 | #include "traversal/Traverser.h" 4 | #include "traversal/GraphTraversal.h" 5 | 6 | namespace gremlinxx { 7 | 8 | TraversalStep::TraversalStep(bool is_barrier, TraversalStepType tsType, unsigned int id) { 9 | this->type = tsType; 10 | this->uid = id; 11 | this->is_barrier = is_barrier; 12 | } 13 | 14 | TraversalStep::TraversalStep(TraversalStepType tsType, unsigned int id) : TraversalStep(false, tsType, id){} 15 | 16 | std::string TraversalStep::getInfo() { 17 | return "UnknownTraversalStep{}"; 18 | } 19 | 20 | std::string TraversalStep::getInfo(GraphTraversal* parent_traversal) { 21 | return this->getInfo(); 22 | } 23 | 24 | std::string TraversalStep::getInfo(size_t indent) { 25 | std::string s = ""; 26 | for(size_t k = 0; k < indent; ++k) s += " "; 27 | 28 | return s + getInfo(); 29 | } 30 | 31 | void TraversalStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 32 | throw std::runtime_error("Non-executable traversal step! (" + std::to_string(uid) + ")"); 33 | }; 34 | 35 | } -------------------------------------------------------------------------------- /strategy/RepeatUnrollStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/RepeatUnrollStrategy.h" 2 | #include "step/controlflow/RepeatStep.h" 3 | 4 | namespace gremlinxx { 5 | 6 | TraversalStrategy RepeatUnrollStrategy = { 7 | OPTIMIZATION, 8 | "RepeatUnrollStrategy", 9 | [](std::vector>& steps){ 10 | for(auto it = steps.begin(); it != steps.end(); ++it) { 11 | auto& step = *it; 12 | if(step->uid == REPEAT_STEP) { 13 | RepeatStep* rs = static_cast(step.get()); 14 | if(!rs->hasEmitTraversal() && !rs->hasUntilTraversal() && rs->hasTimes()) { 15 | size_t times = rs->getTimes(); 16 | auto new_steps = rs->getActionTraversal().getSteps(); 17 | 18 | for(size_t k = 0; k < times; ++k) { 19 | it = steps.insert(it + 1, new_steps.begin(), new_steps.end()) - 1; 20 | } 21 | it = steps.erase(it); 22 | } 23 | } 24 | } 25 | } 26 | }; 27 | 28 | } -------------------------------------------------------------------------------- /step/controlflow/LoopsStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/LoopsStep.h" 2 | #include "step/controlflow/RepeatStep.h" 3 | #include "maelstrom/algorithms/set.h" 4 | 5 | namespace gremlinxx { 6 | 7 | LoopsStep::LoopsStep() 8 | : TraversalStep(MAP, LOOPS_STEP) {} 9 | 10 | void LoopsStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 11 | size_t loops = std::any_cast( 12 | traversal->getTraversalProperty(LOOPS_TRAVERSAL_PROPERTY) 13 | ); 14 | 15 | traversers.advance([loops](maelstrom::vector& traverser_data, std::unordered_map& side_effects, gremlinxx::traversal::PathInfo& path_info){ 16 | maelstrom::vector new_traverser_data( 17 | traverser_data.get_mem_type(), 18 | maelstrom::uint64, 19 | traverser_data.size() 20 | ); 21 | 22 | maelstrom::set(new_traverser_data, static_cast(loops)); 23 | 24 | return std::make_pair( 25 | new_traverser_data, 26 | maelstrom::vector() 27 | ); 28 | }); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /step/property/PropertyStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PROPERTY_STEP 0x75 4 | #define PROPERTY_STEP_SIDE_EFFECT_KEY "__PropertyStep__originating_traverser__" 5 | 6 | #include "step/TraversalStep.h" 7 | #include "structure/VertexProperty.h" 8 | #include "traversal/Scope.h" 9 | #include "traversal/Traverser.h" 10 | 11 | namespace gremlinxx { 12 | 13 | class MinStep; 14 | class Element; 15 | class Vertex; 16 | 17 | // Edge properties currently not supported. 18 | class PropertyStep : public TraversalStep { 19 | private: 20 | Cardinality cardinality; 21 | std::string key; 22 | std::any value; 23 | public: 24 | PropertyStep(std::string property_key, std::any value); 25 | 26 | PropertyStep(Cardinality card, std::string property_key, std::any value); 27 | 28 | inline Cardinality get_cardinality() { return this->cardinality; } 29 | 30 | inline std::string get_key() { return this->key; } 31 | 32 | inline std::any get_value() { return this->value; }; 33 | 34 | virtual void apply(GraphTraversal* current_traversal, gremlinxx::traversal::TraverserSet& traversers); 35 | 36 | using TraversalStep::getInfo; 37 | virtual std::string getInfo(); 38 | }; 39 | 40 | } -------------------------------------------------------------------------------- /strategy/SubgraphStepCompletionStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/SubgraphStepCompletionStrategy.h" 2 | #include "step/graph/SubgraphStep.h" 3 | #include "step/graph/SubgraphExtractionStep.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace gremlinxx { 9 | 10 | TraversalStrategy SubgraphStepCompletionStrategy = { 11 | FINALIZATON, 12 | "SubgraphStepCompletionStrategy", 13 | [](std::vector>& steps) { 14 | std::unordered_set names; 15 | for(auto it = steps.begin(); it != steps.end(); ++it) { 16 | auto& step = *it; 17 | if(step->uid == SUBGRAPH_STEP) { 18 | names.insert( 19 | static_cast(step.get())->get_subgraph_name() 20 | ); 21 | } 22 | } 23 | 24 | if(!names.empty()) { 25 | steps.push_back( 26 | std::shared_ptr( 27 | new SubgraphExtractionStep(std::move(names)) 28 | ) 29 | ); 30 | } 31 | } 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /step/sideeffect/SelectStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/sideeffect/SelectStep.h" 2 | #include 3 | #include 4 | 5 | namespace gremlinxx { 6 | 7 | SelectStep::SelectStep(std::string se_label) 8 | : TraversalStep(SIDE_EFFECT, SELECT_STEP) { 9 | this->sideEffectLabel = se_label; 10 | } 11 | 12 | void SelectStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 13 | std::string& se_label = this->sideEffectLabel; 14 | 15 | if(traversers.empty()) return; 16 | 17 | traversers.advance([se_label](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 18 | if(traverser_se.find(se_label) == traverser_se.end()) { 19 | std::stringstream sx; 20 | sx << "Invalid side effect key " << se_label; 21 | throw std::runtime_error(sx.str()); 22 | } 23 | 24 | return std::make_pair( 25 | traverser_se[se_label], 26 | maelstrom::vector() 27 | ); 28 | }); 29 | } 30 | 31 | std::string SelectStep::getInfo() { 32 | return "SelectStep(" + this->sideEffectLabel + ")"; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /step/vertex/VertexStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "step/TraversalStep.h" 8 | #include "structure/Direction.h" 9 | 10 | #define VERTEX_STEP 0x80 11 | 12 | namespace gremlinxx { 13 | 14 | enum VertexStepType{ 15 | VERTEX_TO_VERTEX = 0, 16 | VERTEX_TO_EDGE = 1, 17 | EDGE_TO_VERTEX = 2 18 | }; 19 | 20 | class VertexStep : public TraversalStep { 21 | private: 22 | Direction direction; 23 | std::set edge_labels; 24 | VertexStepType vsType; 25 | public: 26 | VertexStep(Direction dir, std::vector edge_labels_arg, VertexStepType vs_type); 27 | 28 | VertexStep(Direction dir, VertexStepType vs_type); 29 | 30 | inline Direction get_direction() { 31 | return this->direction; 32 | } 33 | 34 | inline std::set get_labels() { 35 | return this->edge_labels; 36 | } 37 | 38 | inline VertexStepType get_type() { 39 | return this->vsType; 40 | } 41 | 42 | using TraversalStep::getInfo; 43 | virtual std::string getInfo(); 44 | 45 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 46 | }; 47 | 48 | } -------------------------------------------------------------------------------- /step/property/ElementMapStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ELEMENTMAP_STEP 0x68 4 | #define ELEMENTMAP_ID_KEY "id" 5 | #define ElEMENTMAP_LABEL_KEY "label" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "step/TraversalStep.h" 12 | #include "step/modulate/ByModulating.h" 13 | 14 | namespace gremlinxx { 15 | 16 | /* 17 | Unlike the original ElementMapStep, in gremlin++, this step will throw out 18 | any vertices that don't have the given keys and output the element map 19 | as side effects. Providing no keys will result in just the id and label 20 | going into the map. 21 | */ 22 | class ElementMapStep: public TraversalStep, virtual public ByModulating { 23 | private: 24 | std::vector keys; 25 | GraphTraversal* by_traversal = nullptr; 26 | 27 | public: 28 | ElementMapStep(std::vector& keys); 29 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 30 | 31 | virtual void modulate_by(std::any arg); 32 | 33 | using TraversalStep::getInfo; 34 | std::string getInfo(); 35 | }; 36 | 37 | } -------------------------------------------------------------------------------- /step/filter/IsStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/filter/IsStep.h" 2 | #include "traversal/Traverser.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "traversal/GraphTraversalSource.h" 5 | 6 | #include "maelstrom/storage/comparison.h" 7 | #include "maelstrom/algorithms/filter.h" 8 | #include "maelstrom/algorithms/select.h" 9 | 10 | namespace gremlinxx { 11 | 12 | IsStep::IsStep(P predicate) 13 | : TraversalStep(FILTER, IS_STEP) { 14 | this->predicate = predicate; 15 | } 16 | 17 | std::string IsStep::getInfo() { 18 | std::string info = "IsStep{}"; 19 | 20 | return info; 21 | } 22 | 23 | void IsStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 24 | std::any val = this->predicate.operand; 25 | auto cmp = this->predicate.comparison; 26 | 27 | traversers.advance([cmp, val](auto& data, auto& se, auto& paths){ 28 | maelstrom::vector ix = maelstrom::filter( 29 | data, 30 | cmp, 31 | val 32 | ); 33 | 34 | return std::make_pair( 35 | std::move(maelstrom::select(data, ix)), 36 | std::move(ix) 37 | ); 38 | }); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /step/filter/SampleStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/filter/SampleStep.h" 2 | 3 | #include "maelstrom/algorithms/randperm.h" 4 | #include "maelstrom/algorithms/select.h" 5 | 6 | namespace gremlinxx { 7 | 8 | SampleStep::SampleStep(size_t num_traversers) 9 | : TraversalStep(FILTER, SAMPLE_STEP) { 10 | this->count = num_traversers; 11 | } 12 | 13 | void SampleStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 14 | if(traversers.empty()) return; 15 | 16 | size_t N = this->count; 17 | traversers.advance([N](auto& data, auto& side_effects, auto& paths){ 18 | // FIXME properly set random seed 19 | auto perm = maelstrom::randperm( 20 | data.get_mem_type(), 21 | data.size(), 22 | (N < data.size()) ? N : data.size() 23 | ); 24 | 25 | auto new_data = maelstrom::select(data, perm); 26 | return std::make_pair( 27 | std::move(new_data), 28 | std::move(perm) 29 | ); 30 | }); 31 | } 32 | 33 | std::string SampleStep::getInfo() { 34 | std::stringstream sx; 35 | sx << "SampleStep{" << this->count << "}"; 36 | return sx.str(); 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /step/logic/OrderStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ORDER_STEP 0x47 4 | #define ORDER_STEP_SIDE_EFFECT_KEY "__OrderStep__originating_traverser__" 5 | 6 | #include 7 | #include 8 | 9 | #include "structure/Order.h" 10 | #include "step/TraversalStep.h" 11 | #include "traversal/GraphTraversal.h" 12 | #include "traversal/Traverser.h" 13 | #include "step/modulate/ByModulating.h" 14 | 15 | namespace gremlinxx { 16 | // In the future this may get optimized away for most traversals by moving 17 | // the barrier to the left of the step and testing each element upon appearance 18 | class OrderStep: public TraversalStep, virtual public ByModulating { 19 | private: 20 | std::optional order_traversal; 21 | std::optional order; 22 | 23 | public: 24 | // This is a barrier step 25 | OrderStep(); 26 | 27 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 28 | 29 | using TraversalStep::getInfo; 30 | virtual std::string getInfo(); 31 | virtual std::string getInfo(GraphTraversal* parent_traversal); 32 | 33 | virtual void modulate_by(std::any arg); 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /step/math/GroupCountStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define GROUP_COUNT_STEP 0x62 4 | 5 | #include "step/TraversalStep.h" 6 | #include "traversal/Traverser.h" 7 | #include "traversal/GraphTraversalSource.h" 8 | #include 9 | 10 | namespace gremlinxx { 11 | 12 | class GroupCountStep : public TraversalStep { 13 | private: 14 | const std::string DEFAULT_KEY = "GROUP"; 15 | std::optional by_key; 16 | 17 | public: 18 | GroupCountStep(); 19 | 20 | inline void set_by_key(std::string by_key) { this->by_key = by_key; } 21 | 22 | inline std::optional get_by_key() { return this->by_key; } 23 | 24 | using TraversalStep::getInfo; 25 | virtual std::string getInfo(); 26 | 27 | /* 28 | There are some important semantic differences with the GroupCount step in Gremlin++: 29 | (1) All paths and side effects are invalidated upon calling this step. 30 | (2) Each output traverser is a size_t with a single side effect (the by key). 31 | (3) If there was no by key, the side effect key is "GROUP" 32 | */ 33 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 34 | 35 | }; 36 | 37 | } -------------------------------------------------------------------------------- /step/vertex/AddVertexStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/vertex/AddVertexStep.h" 2 | #include "traversal/Traverser.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "structure/Graph.h" 5 | 6 | namespace gremlinxx { 7 | 8 | AddVertexStep::AddVertexStep(std::string label_arg) 9 | : TraversalStep(MAP, ADD_VERTEX_STEP) { 10 | this->label = label_arg; 11 | this->has_label = true; 12 | } 13 | 14 | AddVertexStep::AddVertexStep() 15 | : TraversalStep(MAP, ADD_VERTEX_STEP) { 16 | this->has_label = false; 17 | } 18 | 19 | std::string AddVertexStep::getInfo() { 20 | std::string info = "AddVertexStep("; 21 | info += has_label ? label : ""; 22 | info += ")"; 23 | return info; 24 | } 25 | 26 | void AddVertexStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 27 | auto graph = traversal->getGraph(); 28 | std::string label_str = this->label; 29 | 30 | // For each traverser, a new Vertex should be created and replace the original traverser 31 | traversers.advance([&graph, label_str](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 32 | return std::make_pair( 33 | std::move(graph->add_vertices(traverser_data.size(), label_str)), 34 | maelstrom::vector() 35 | ); 36 | }); 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /step/graph/SubgraphExtractionStep.cpp: -------------------------------------------------------------------------------- 1 | #include "structure/Graph.h" 2 | #include "step/graph/SubgraphExtractionStep.h" 3 | 4 | namespace gremlinxx { 5 | 6 | SubgraphExtractionStep::SubgraphExtractionStep(std::unordered_set sg_names) 7 | : TraversalStep(SIDE_EFFECT, SUBGRAPH_EXTRACTION_STEP) { 8 | this->subgraph_names = sg_names; 9 | } 10 | 11 | void SubgraphExtractionStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 12 | for(std::string name : this->subgraph_names) { 13 | auto edges = std::any_cast(traversal->removeTraversalProperty(SUBGRAPH_PREFIX + name)); 14 | auto subgraph = traversal->getGraph()->subgraph(edges); 15 | 16 | bool set = traversal->setTraversalProperty(name, std::move(subgraph)); 17 | if(!set) { 18 | throw std::runtime_error("Unable to set subgraph traversal property for " + name); 19 | } 20 | } 21 | } 22 | 23 | std::string SubgraphExtractionStep::getInfo() { 24 | std::stringstream sx; 25 | sx << "SubgraphExtractionStep{"; 26 | for(auto it = this->subgraph_names.begin(); it != this->subgraph_names.end(); ++it){ 27 | sx << *it << ","; 28 | } 29 | 30 | std::string info = sx.str(); 31 | info = info.substr(0, info.size() - 1) + "}"; 32 | return info; 33 | } 34 | } -------------------------------------------------------------------------------- /step/modulate/ReductionStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/Traverser.h" 5 | #include "traversal/Scope.h" 6 | #include "traversal/Comparison.h" 7 | 8 | #include 9 | 10 | namespace gremlinxx { 11 | 12 | class ReductionStep : public TraversalStep { 13 | protected: 14 | std::optional scope_context; 15 | 16 | public: 17 | 18 | ReductionStep(unsigned int id) 19 | : TraversalStep(true, MAP, id) {} 20 | 21 | inline void set_scope_context(ScopeContext sc) { this->scope_context = sc; } 22 | 23 | inline std::optional get_scope_context() { return this->scope_context; } 24 | 25 | virtual void apply_global(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) = 0; 26 | 27 | virtual void apply_local(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) = 0; 28 | 29 | using TraversalStep::apply; 30 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 31 | if(!scope_context || scope_context->scope == global) apply_global(traversal, traversers); 32 | else apply_local(traversal, traversers); 33 | } 34 | 35 | using TraversalStep::getInfo; 36 | virtual std::string getInfo() = 0; 37 | 38 | }; 39 | 40 | } -------------------------------------------------------------------------------- /step/edge/AddEdgeStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "step/TraversalStep.h" 5 | #include "step/modulate/FromToModulating.h" 6 | #include "traversal/Traverser.h" 7 | #include 8 | #include 9 | 10 | #define ADD_EDGE_STEP 0x73 11 | 12 | namespace gremlinxx { 13 | 14 | class AddEdgeStep: public TraversalStep, virtual public FromToModulating { 15 | private: 16 | std::string label; 17 | std::optional out_vertex_traversal = {}; // filled in at runtime 18 | std::optional in_vertex_traversal = {}; // filled in at runtime 19 | public: 20 | AddEdgeStep(std::string label_arg); 21 | 22 | using TraversalStep::getInfo; 23 | virtual std::string getInfo(); 24 | 25 | inline GraphTraversal& get_out_traversal() { 26 | if(!this->out_vertex_traversal) throw std::runtime_error("This traversal does not have an out vertex traversal!"); 27 | return this->out_vertex_traversal.value(); 28 | } 29 | inline GraphTraversal& get_in_traversal() { 30 | if(!this->in_vertex_traversal) throw std::runtime_error("This traversal does not have an in vertex traversal!"); 31 | return this->in_vertex_traversal.value(); 32 | } 33 | inline std::string get_label() { return this->label; } 34 | 35 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 36 | 37 | virtual void modulate_from(GraphTraversal trv); 38 | 39 | virtual void modulate_to(GraphTraversal trv); 40 | }; 41 | 42 | } -------------------------------------------------------------------------------- /traversal/PathInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "maelstrom/containers/vector.h" 4 | 5 | namespace gremlinxx { 6 | namespace traversal { 7 | 8 | typedef uint32_t path_length_t; 9 | 10 | class PathInfo { 11 | public: 12 | std::vector paths; 13 | maelstrom::vector path_lengths; 14 | 15 | /* 16 | Appends prev_traverser_data to the paths. Then, if origin is set, 17 | properly transforms the original paths based on the originating 18 | traversers of interest. If not set, no transformation is performed. 19 | */ 20 | void advance(maelstrom::vector prev_traverser_data, maelstrom::vector origin=maelstrom::vector()); 21 | 22 | /* 23 | For each traverser's path info p, creates a new PathInfo object 24 | consisting only of the path info in p. Returns a vector with the 25 | new PathInfo objects. 26 | */ 27 | std::vector unpack(); 28 | 29 | /* 30 | Adds the path data in the other path info to this 31 | path info object. 32 | */ 33 | void add_paths(PathInfo& other_path_info); 34 | 35 | /* 36 | Clears all data from this path info object. 37 | */ 38 | void clear(); 39 | }; 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /step/graph/IdStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/graph/IdStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Graph.h" 4 | 5 | #include "maelstrom/algorithms/arange.h" 6 | 7 | namespace gremlinxx { 8 | 9 | IdStep::IdStep() 10 | : TraversalStep(MAP, ID_STEP) {} 11 | 12 | std::string IdStep::getInfo() { 13 | return "IdStep()"; 14 | } 15 | 16 | void IdStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 17 | traversers.advance([trv](maelstrom::vector& traverser_data, std::unordered_map& traverser_side_effects, gremlinxx::traversal::PathInfo& traverser_paths){ 18 | if(traverser_data.get_dtype() == trv->getGraph()->get_vertex_dtype()) { 19 | // In gremlin++, vertices in a traversal are represented by IDs, not pointers. 20 | // Therefore, this step only casts to the primitive type. 21 | // Also note that in gremlin++, vertex/edge ids have to be size_t, even though internally they are allowed to be arbitrary type 22 | 23 | return std::make_pair( 24 | std::move(traverser_data.astype(maelstrom::uint64)), 25 | std::move(maelstrom::arange(traverser_data.get_mem_type(), static_cast(0), static_cast(traverser_data.size()))) 26 | ); 27 | 28 | } else { 29 | throw std::runtime_error("Only vertices are currently supported by Id Step!"); 30 | } 31 | }); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /step/embedding/LikeStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define LIKE_STEP 0x8b 4 | 5 | #include "step/TraversalStep.h" 6 | 7 | #include "maelstrom/algorithms/similarity.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace gremlinxx { 13 | 14 | class LikeStep : public TraversalStep { 15 | private: 16 | maelstrom::vector embeddings; 17 | std::string emb_name; 18 | size_t emb_stride; 19 | std::optional match_threshold; 20 | std::optional count; 21 | maelstrom::similarity_t similarity_metric; 22 | 23 | public: 24 | LikeStep(std::string emb_name, std::vector& embs, std::optional threshold, std::optional count=std::nullopt, maelstrom::similarity_t metric=maelstrom::COSINE); 25 | 26 | virtual void apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers); 27 | 28 | inline maelstrom::vector get_embeddings() { return this->embeddings; } 29 | inline std::string get_embedding_name() { return this->emb_name; } 30 | inline size_t get_embedding_stride() { return this->emb_stride; } 31 | inline std::optional get_match_threshold() { return this->match_threshold; } 32 | inline std::optional get_count() { return this->count; } 33 | inline maelstrom::similarity_t get_metric() { return this->similarity_metric; } 34 | 35 | using TraversalStep::getInfo; 36 | std::string getInfo(); 37 | }; 38 | 39 | } -------------------------------------------------------------------------------- /step/logic/DedupStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/logic/DedupStep.h" 2 | #include "traversal/GraphTraversalSource.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "maelstrom/algorithms/unique.h" 5 | #include "maelstrom/algorithms/sort.h" 6 | #include "maelstrom/algorithms/select.h" 7 | 8 | namespace gremlinxx { 9 | 10 | // This is a barrier step 11 | // it should become a reduction step 12 | DedupStep::DedupStep() 13 | : TraversalStep(true, FILTER, DEDUP_STEP) {} 14 | 15 | void DedupStep::modulate_by(std::any arg) { 16 | this->dedup_by_key = std::any_cast(arg); 17 | } 18 | 19 | void DedupStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 20 | traversers.advance([](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 21 | maelstrom::vector sorted_data(traverser_data, false); 22 | maelstrom::vector sorted_indices = maelstrom::sort(sorted_data); 23 | maelstrom::vector unique_indices = maelstrom::unique(sorted_data, true); 24 | 25 | sorted_data.clear(); 26 | unique_indices = maelstrom::select(sorted_indices, unique_indices); 27 | sorted_indices.clear(); 28 | 29 | return std::make_pair( 30 | std::move(maelstrom::select(traverser_data, unique_indices)), 31 | std::move(unique_indices) 32 | ); 33 | }); 34 | } 35 | 36 | std::string DedupStep::getInfo() { 37 | return "DedupStep(" + this->dedup_by_key.value_or("") + ")"; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /step/edge/AddEdgeStartStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ADD_EDGE_START_STEP 0x72 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "step/modulate/FromToModulating.h" 10 | #include "step/TraversalStep.h" 11 | 12 | #include "traversal/GraphTraversalSource.h" 13 | #include "traversal/GraphTraversal.h" 14 | #include "traversal/Traverser.h" 15 | 16 | namespace gremlinxx { 17 | 18 | class AddEdgeStartStep: public TraversalStep, virtual public FromToModulating { 19 | private: 20 | std::string label; 21 | std::optional out_vertex_traversal = {}; // filled in at runtime 22 | std::optional in_vertex_traversal = {}; // filled in at runtime 23 | public: 24 | AddEdgeStartStep(std::string label_arg); 25 | 26 | using TraversalStep::getInfo; 27 | virtual std::string getInfo(); 28 | 29 | 30 | inline GraphTraversal& get_out_traversal() { 31 | if(!this->out_vertex_traversal) throw std::runtime_error("Traversal does not have an out traversal!"); 32 | 33 | return this->out_vertex_traversal.value(); 34 | } 35 | inline GraphTraversal& get_in_traversal() { 36 | if(!this->in_vertex_traversal) throw std::runtime_error("Traversal does not have an in traversal!"); 37 | return this->in_vertex_traversal.value(); 38 | } 39 | inline std::string get_label() { return this->label; } 40 | 41 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 42 | 43 | virtual void modulate_from(GraphTraversal arg); 44 | 45 | virtual void modulate_to(GraphTraversal arg); 46 | }; 47 | 48 | } -------------------------------------------------------------------------------- /step/controlflow/InjectStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/InjectStep.h" 2 | #include "traversal/Traverser.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "traversal/GraphTraversalSource.h" 5 | 6 | #include 7 | 8 | namespace gremlinxx { 9 | 10 | InjectStep::InjectStep(std::vector& injects) : TraversalStep(SIDE_EFFECT, INJECT_STEP) { 11 | std::copy(injects.begin(), injects.end(), std::back_inserter(objects)); 12 | } 13 | 14 | InjectStep::InjectStep(std::any& b) : TraversalStep(SIDE_EFFECT, INJECT_STEP) { 15 | objects.push_back(b); 16 | } 17 | 18 | void InjectStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 19 | if(this->objects.empty()) return; 20 | 21 | maelstrom::dtype_t dtype = trv->getTraversalSource()->get_dtype(this->objects.front()); 22 | maelstrom::vector obj_vector = maelstrom::make_vector_from_anys( 23 | maelstrom::HOST, 24 | dtype, 25 | this->objects 26 | ); 27 | 28 | GraphTraversal empty_trv(trv->getTraversalSource()); 29 | empty_trv.getTraverserSet().advance([&obj_vector](maelstrom::vector& data, std::unordered_map& side_effects, gremlinxx::traversal::PathInfo& path_info){ 30 | return std::make_pair( 31 | obj_vector, 32 | maelstrom::vector() 33 | ); 34 | }); 35 | 36 | // TODO might want to make sure memory type is what the backend expects 37 | traversers.addTraversers(empty_trv.getTraverserSet()); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /step/vertex/AddVertexStartStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/vertex/AddVertexStartStep.h" 2 | #include "traversal/Traverser.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "structure/Graph.h" 5 | 6 | namespace gremlinxx { 7 | 8 | AddVertexStartStep::AddVertexStartStep(std::string label_arg) 9 | : TraversalStep(MAP, ADD_VERTEX_START_STEP) { 10 | this->label = label_arg; 11 | this->has_label = true; 12 | } 13 | 14 | AddVertexStartStep::AddVertexStartStep() 15 | : TraversalStep(MAP, ADD_VERTEX_START_STEP) { 16 | has_label = false; 17 | } 18 | 19 | std::string AddVertexStartStep::getInfo() { 20 | std::string info = "AddVertexStartStep("; 21 | info += has_label ? label : ""; 22 | info += ")"; 23 | return info; 24 | } 25 | 26 | void AddVertexStartStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 27 | Vertex v = this->has_label ? trv->getGraph()->add_vertex(this->label) : trv->getGraph()->add_vertex(); 28 | auto vertex_dtype = trv->getTraversalSource()->get_dtype(v); 29 | std::vector anys = {vertex_dtype.serialize(v)}; // Vertex isn't castable to a primitive so calling serialize manually is necessary 30 | 31 | traversers.reinitialize( 32 | std::move(maelstrom::make_vector_from_anys(traversers.getCurrentMemType(), trv->getTraversalSource()->get_dtype(v), anys)), 33 | std::move(std::unordered_map()), 34 | std::move(gremlinxx::traversal::PathInfo()) 35 | ); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /step/embedding/EncodeStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/embedding/EncodeStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Graph.h" 4 | 5 | #include "maelstrom/containers/vector.h" 6 | #include "maelstrom/algorithms/arange.h" 7 | #include "maelstrom/algorithms/increment.h" 8 | 9 | #include "maelstrom/util/any_utils.h" 10 | 11 | namespace gremlinxx { 12 | 13 | EncodeStep::EncodeStep(std::string embedding_name) 14 | : TraversalStep(MAP, ENCODE_STEP) { 15 | this->emb_name = embedding_name; 16 | } 17 | 18 | void EncodeStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 19 | Graph* graph = traversal->getGraph(); 20 | 21 | if(traversers.getCurrentDataType() != graph->get_vertex_dtype()) { 22 | throw std::runtime_error("Can only encode vertices."); 23 | } 24 | 25 | std::string& name = this->emb_name; 26 | traversers.advance([&graph, name](auto& data, auto& se, auto& paths){ 27 | auto emb = graph->get_vertex_embeddings(name, data); 28 | const size_t emb_stride = emb.size() / graph->num_vertices(); 29 | 30 | auto ix = maelstrom::arange(data.get_mem_type(), static_cast(0), static_cast(emb_stride * data.size())); 31 | maelstrom::increment(ix, emb_stride, maelstrom::DIVIDE); 32 | 33 | return std::make_pair( 34 | std::move(emb), 35 | std::move(ix) 36 | ); 37 | }); 38 | 39 | } 40 | 41 | std::string EncodeStep::getInfo() { 42 | return "EncodeStep{" + this->emb_name + "}"; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /step/controlflow/CoalesceStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/CoalesceStep.h" 2 | 3 | #include "traversal/Traverser.h" 4 | #include "traversal/GraphTraversal.h" 5 | #include "step/TraversalStep.h" 6 | 7 | namespace gremlinxx { 8 | CoalesceStep::CoalesceStep(std::vector& traversals) 9 | : TraversalStep(MAP, COALESCE_STEP) { 10 | for(GraphTraversal& trv : traversals) { 11 | this->traversals.push_back(GraphTraversal(trv)); 12 | } 13 | } 14 | 15 | std::vector& CoalesceStep::get_traversals() { 16 | return this->traversals; 17 | } 18 | 19 | void CoalesceStep::apply(GraphTraversal* parent_traversal, gremlinxx::traversal::TraverserSet& traversers) { 20 | for(auto it = this->traversals.begin(); it != this->traversals.end(); ++it) { 21 | GraphTraversal current_coalesce_traversal = *it; 22 | GraphTraversal executing_traversal(parent_traversal->getTraversalSource(), current_coalesce_traversal); 23 | 24 | executing_traversal.setInitialTraversers(traversers); 25 | executing_traversal.iterate(); 26 | 27 | gremlinxx::traversal::TraverserSet& new_traverser_set = executing_traversal.getTraverserSet(); 28 | 29 | if(new_traverser_set.size() > 0) { 30 | traversers.clear(); 31 | traversers.addTraversers(new_traverser_set); 32 | new_traverser_set.clear(); 33 | return; 34 | } 35 | } 36 | 37 | // If all coalesce traversals return nothing, the traverser set should be empty. 38 | traversers.clear(); 39 | } 40 | } -------------------------------------------------------------------------------- /step/controlflow/UnionStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/UnionStep.h" 2 | #include "traversal/Traverser.h" 3 | 4 | namespace gremlinxx { 5 | 6 | std::string UnionStep::getInfo() { 7 | std::string info = "UnionStep{}"; 8 | 9 | return info; 10 | } 11 | 12 | UnionStep::UnionStep(std::vector& traversals) 13 | : TraversalStep(MAP, UNION_STEP) { 14 | for(auto it = traversals.begin(); it != traversals.end(); ++it) this->traversals.push_back(GraphTraversal(*it)); 15 | } 16 | 17 | std::vector& UnionStep::get_traversals() { 18 | return this->traversals; 19 | } 20 | 21 | void UnionStep::apply(GraphTraversal* parent_traversal, gremlinxx::traversal::TraverserSet& traversers) { 22 | GraphTraversal bogus_traversal(parent_traversal->getTraversalSource()); 23 | gremlinxx::traversal::TraverserSet& new_traversers = bogus_traversal.getTraverserSet(); 24 | 25 | for(auto it = this->traversals.begin(); it != this->traversals.end(); ++it) { 26 | GraphTraversal& current_union_traversal = *it; 27 | 28 | GraphTraversal executing_traversal(parent_traversal->getTraversalSource(), current_union_traversal); 29 | executing_traversal.setInitialTraversers(traversers); 30 | executing_traversal.iterate(); 31 | 32 | auto& output_traversers = executing_traversal.getTraverserSet(); 33 | new_traversers.addTraversers(output_traversers); 34 | output_traversers.clear(); 35 | } 36 | 37 | traversers.clear(); 38 | traversers.addTraversers(new_traversers); 39 | new_traversers.clear(); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /step/graph/SubgraphStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/graph/SubgraphStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Vertex.h" 4 | #include "structure/Edge.h" 5 | 6 | #include "maelstrom/algorithms/sort.h" 7 | #include "maelstrom/algorithms/unique.h" 8 | #include "maelstrom/algorithms/select.h" 9 | 10 | namespace gremlinxx { 11 | SubgraphStep::SubgraphStep(std::string name) : TraversalStep(SIDE_EFFECT, SUBGRAPH_STEP) { 12 | this->subgraph_name = name; 13 | } 14 | 15 | void SubgraphStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 16 | auto traverser_data_copy = traversers.getTraverserData(); 17 | if(traverser_data_copy.get_dtype() != traversal->getGraph()->get_edge_dtype()) { 18 | throw std::invalid_argument("subgraph() can only be called on edges"); 19 | } 20 | 21 | std::any subgraph_property = traversal->removeTraversalProperty(SUBGRAPH_PREFIX + subgraph_name); 22 | if(subgraph_property.has_value()) { 23 | traverser_data_copy.insert(std::any_cast(subgraph_property)); 24 | } 25 | 26 | maelstrom::sort(traverser_data_copy); 27 | auto ix = maelstrom::unique(traverser_data_copy, true); 28 | bool set = traversal->setTraversalProperty( 29 | SUBGRAPH_PREFIX + subgraph_name, 30 | std::move(maelstrom::select(traverser_data_copy, ix)) 31 | ); 32 | 33 | if(!set) throw std::runtime_error("An error occured setting a traversal property for subgraph " + subgraph_name); 34 | } 35 | 36 | std::string SubgraphStep::getInfo() { 37 | return "SubgraphStep{" + this->subgraph_name + "}"; 38 | } 39 | } -------------------------------------------------------------------------------- /step/vertex/DegreeStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/vertex/DegreeStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Graph.h" 4 | 5 | #include 6 | 7 | namespace gremlinxx { 8 | 9 | DegreeStep::DegreeStep(Direction dir, std::set edge_labels_arg) 10 | : TraversalStep(MAP, DEGREE_STEP) { 11 | this->direction = dir; 12 | this->edge_labels = edge_labels_arg; 13 | } 14 | 15 | std::string DegreeStep::getInfo() { 16 | std::string dir_string = (this->direction == IN ? "IN" : this->direction == OUT ? "OUT" : "BOTH"); 17 | std::stringstream sx; 18 | sx << "DegreeStep(" << dir_string << ", " << "["; 19 | 20 | if(this->edge_labels.empty()) { 21 | return sx.str() + "])"; 22 | } else { 23 | for(std::string s : this->edge_labels) sx << s << ", "; 24 | auto output_str = sx.str(); 25 | return output_str.substr(0, output_str.size() - 2) + "])"; 26 | } 27 | } 28 | 29 | void DegreeStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 30 | std::vector label_vec(this->edge_labels.begin(), this->edge_labels.end()); 31 | auto dir = this->direction; 32 | 33 | traversers.advance([&label_vec, traversal, dir](auto data, auto side_effects, auto paths){ 34 | maelstrom::vector degrees; 35 | maelstrom::vector origins; 36 | 37 | std::tie(degrees, origins) = traversal->getGraph()->degree( 38 | data, 39 | label_vec, 40 | dir 41 | ); 42 | 43 | return std::make_pair( 44 | std::move(degrees), 45 | std::move(origins) 46 | ); 47 | }); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /strategy/BasicPatternExtractionStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/BasicPatternExtractionStrategy.h" 2 | #include "step/vertex/VertexStep.h" 3 | #include "step/math/CountStep.h" 4 | #include "step/vertex/DegreeStep.h" 5 | 6 | namespace gremlinxx { 7 | 8 | TraversalStrategy BasicPatternExtractionStrategy = { 9 | OPTIMIZATION, 10 | "BasicPatternExtractionStrategy", 11 | [](std::vector>& steps){ 12 | for(auto it = steps.begin(); it != steps.end(); ++it) { 13 | // Degree Pattern 14 | if((*it)->uid == VERTEX_STEP) { 15 | auto vertex_step = static_cast(it->get()); 16 | if(vertex_step->get_type() == VERTEX_TO_VERTEX || vertex_step->get_type() == VERTEX_TO_EDGE) { 17 | if(it != steps.end() - 1 && (*(it+1))->uid == COUNT_STEP) { 18 | auto count_step = static_cast((it+1)->get()); 19 | if(count_step->get_scope_context().has_value() && count_step->get_scope_context().value().scope == local) { 20 | // matched degree pattern 21 | std::shared_ptr degree_step( 22 | new DegreeStep(vertex_step->get_direction(), vertex_step->get_labels()) 23 | ); 24 | 25 | // erase after accessing what could be the last shared pointer to the vertex step 26 | it = steps.erase(it); 27 | *it = degree_step; 28 | it -= 1; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | }; 36 | 37 | } -------------------------------------------------------------------------------- /strategy/FromToModulatingStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/FromToModulatingStrategy.h" 2 | #include "step/TraversalStep.h" 3 | #include "step/modulate/FromStep.h" 4 | #include "step/modulate/ToStep.h" 5 | #include "step/logic/NoOpStep.h" 6 | #include "step/modulate/FromToModulating.h" 7 | #include 8 | 9 | namespace gremlinxx { 10 | 11 | TraversalStrategy FromToModulatingStrategy = { 12 | FINALIZATON, 13 | "FromToModulatingStrategy", 14 | [](std::vector>& steps){ 15 | if(steps[0]->uid == FROM_STEP || steps[0]->uid == TO_STEP) { 16 | throw std::runtime_error("Cannot start a traversal with from() or to()!"); 17 | } 18 | 19 | for(int k = 1; k < steps.size(); k++) { 20 | TraversalStep* currentStep = steps[k].get(); 21 | if(currentStep->uid == FROM_STEP) { 22 | int i = k - 1; while(steps[i]->uid == NO_OP_STEP) --i; 23 | auto base_step = dynamic_cast(steps[i].get()); 24 | auto from_modulator = static_cast(currentStep); 25 | GraphTraversal trv(from_modulator->get_traversal()); 26 | base_step->modulate_from(std::move(trv)); 27 | 28 | steps[k] = std::shared_ptr(new NoOpStep()); 29 | } else if(currentStep->uid == TO_STEP) { 30 | int i = k-1; while(steps[i]->uid == NO_OP_STEP) --i; 31 | auto base_step = dynamic_cast(steps[i].get()); 32 | auto to_modulator = static_cast(currentStep); 33 | GraphTraversal trv(to_modulator->get_traversal()); 34 | base_step->modulate_to(std::move(trv)); 35 | 36 | steps[k] = std::shared_ptr(new NoOpStep()); 37 | } 38 | } 39 | } 40 | }; 41 | 42 | } -------------------------------------------------------------------------------- /util/gremlin_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef std::unordered_map valuemap_t; 10 | typedef std::vector anyvec_t; 11 | 12 | inline std::string string_any(std::any a) { 13 | auto& id = a.type(); 14 | if(id == typeid(int)) return std::to_string(std::any_cast(a)); 15 | else if (id == typeid(long)) return std::to_string(std::any_cast(a)); 16 | else if(id == typeid(unsigned int)) return std::to_string(std::any_cast(a)); 17 | else if(id == typeid(unsigned long)) return std::to_string(std::any_cast(a)); 18 | else if(id == typeid(float)) return std::to_string(std::any_cast(a)); 19 | else if(id == typeid(double)) return std::to_string(std::any_cast(a)); 20 | else if(id == typeid(std::string)) return std::any_cast(a); 21 | //else if(id == typeid(unsigned char*)) return std::string(std::any_cast(a)); 22 | else if(id == typeid(char*)) return std::string(std::any_cast(a)); 23 | else if(id == typeid(const char*)) return std::string(std::any_cast(a)); 24 | else return std::string("?"); 25 | } 26 | 27 | inline void print_any(std::any a) { 28 | std::cout << string_any(a) << std::endl; 29 | } 30 | 31 | inline void print_valuemap(std::any vm) { 32 | std::cout << "{"; 33 | for(auto p : std::any_cast(vm)) { 34 | std::cout << p.first << ": "; 35 | if(typeid(anyvec_t) == p.second.type()) { 36 | anyvec_t av = std::any_cast(p.second); 37 | std::cout << "["; 38 | for(std::any& b : av) { 39 | print_any(b); 40 | std::cout << ","; 41 | } 42 | std::cout << "]"; 43 | } else { 44 | print_any(p.second); 45 | } 46 | std::cout << "; "; 47 | } 48 | std::cout << "}" << std::endl; 49 | } 50 | -------------------------------------------------------------------------------- /step/math/GroupCountStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/math/GroupCountStep.h" 2 | #include "traversal/GraphTraversalSource.h" 3 | #include "traversal/Traverser.h" 4 | #include "traversal/GraphTraversal.h" 5 | 6 | #include "maelstrom/algorithms/sort.h" 7 | #include "maelstrom/algorithms/select.h" 8 | #include "maelstrom/algorithms/count_unique.h" 9 | 10 | #include 11 | 12 | namespace gremlinxx { 13 | 14 | GroupCountStep::GroupCountStep() 15 | : TraversalStep(true, MAP, GROUP_COUNT_STEP) {} 16 | 17 | std::string GroupCountStep::getInfo() { 18 | return std::string("GroupCount{}"); 19 | } 20 | 21 | void GroupCountStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 22 | if(by_key) { 23 | std::string key = *(this->by_key); 24 | traversers.advance([key](auto& traverser_data, auto& traverser_se, auto& traverser_paths){ 25 | if(traverser_se.find(key) == traverser_se.end()) { 26 | std::stringstream sx; 27 | sx << "Invalid side effect key " << key; 28 | throw std::runtime_error(sx.str()); 29 | } 30 | maelstrom::vector keys = std::move(traverser_se[key]); 31 | 32 | traverser_se.clear(); 33 | traverser_paths.clear(); 34 | 35 | maelstrom::sort(keys); 36 | 37 | return maelstrom::count_unique( 38 | keys, 39 | true 40 | ); 41 | }); 42 | 43 | traversers.trim_paths(0,0); 44 | } else { 45 | traversers.advance([](auto& traverser_data, auto& traverser_se, auto& traverser_paths){ 46 | traverser_se.clear(); 47 | traverser_paths.clear(); 48 | 49 | maelstrom::sort(traverser_data); 50 | 51 | return maelstrom::count_unique( 52 | traverser_data, 53 | true 54 | ); 55 | }); 56 | 57 | traversers.trim_paths(0,0); 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /step/property/HasStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Vertex; 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "step/TraversalStep.h" 11 | #include "traversal/P.h" 12 | #include "traversal/Traverser.h" 13 | #include "traversal/GraphTraversal.h" 14 | #include "traversal/GraphTraversalSource.h" 15 | #include "structure/Vertex.h" 16 | #include "structure/Edge.h" 17 | #include "structure/VertexProperty.h" 18 | 19 | #define HAS_STEP 0x83 20 | 21 | namespace gremlinxx { 22 | 23 | enum filter_policy_t { 24 | BY_ENTRY_COUNT = 0, // Will filter by # of entries in ascending order (usually best) 25 | BY_ENTRY_COUNT_REVERSE = 1, // Will filter by # of entries in reverse order (usually slow) 26 | BY_SPECIFIED_ORDER = 2 // Will filter in the order specified by the user 27 | }; 28 | 29 | class HasStep : public TraversalStep { 30 | private: 31 | std::vector> predicates; 32 | 33 | public: 34 | static filter_policy_t FILTER_POLICY; 35 | 36 | HasStep(std::string property_key_or_label, P predicate); 37 | 38 | using TraversalStep::getInfo; 39 | virtual std::string getInfo(); 40 | 41 | inline std::string get_key() { 42 | if(this->predicates.size() == 1) { 43 | return this->predicates.front().first; 44 | } 45 | 46 | throw std::runtime_error("This HasStep contains more than one predicate"); 47 | } 48 | 49 | inline std::any get_value() { 50 | if(this->predicates.size() == 1) { 51 | return this->predicates.front().second.operand; 52 | } 53 | 54 | throw std::runtime_error("This HasStep contains more than one predicate"); 55 | } 56 | 57 | inline P get_predicate() { 58 | if(this->predicates.size() == 1) { 59 | return this->predicates.front().second; 60 | } 61 | 62 | throw std::runtime_error("This HasStep contains more than one predicate"); 63 | } 64 | 65 | inline std::vector> get_predicates() { 66 | return predicates; 67 | } 68 | 69 | void join(HasStep* other); 70 | 71 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 72 | }; 73 | 74 | } -------------------------------------------------------------------------------- /strategy/RepeatStepCompletionStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "strategy/RepeatStepCompletionStrategy.h" 2 | #include "step/TraversalStep.h" 3 | #include "step/controlflow/RepeatStep.h" 4 | #include "step/controlflow/UntilStep.h" 5 | #include "step/controlflow/EmitStep.h" 6 | #include "step/controlflow/TimesStep.h" 7 | #include "step/logic/NoOpStep.h" 8 | #include 9 | 10 | namespace gremlinxx { 11 | 12 | bool acquire_step(std::vector>& steps, size_t idx, RepeatStep* repeatStep) { 13 | if(idx >= steps.size()) return false; 14 | 15 | auto uid = steps[idx]->uid; 16 | if(uid == UNTIL_STEP || uid == EMIT_STEP || uid == TIMES_STEP) { 17 | if(uid == UNTIL_STEP) { 18 | UntilStep* untilStep = static_cast(steps[idx].get()); 19 | repeatStep->setUntilTraversal(untilStep->getTraversal()); 20 | } else if(uid == EMIT_STEP) { 21 | EmitStep* emitStep = static_cast(steps[idx].get()); 22 | repeatStep->setEmitTraversal(emitStep->getTraversal()); 23 | } else { 24 | TimesStep* timesStep = static_cast(steps[idx].get()); 25 | repeatStep->setTimes(timesStep->get_times()); 26 | } 27 | // replace the step 28 | steps[idx] = std::shared_ptr(new NoOpStep()); 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | TraversalStrategy RepeatStepCompletionStrategy = { 36 | FINALIZATON, 37 | "RepeatStepCompletionStrategy", 38 | [](std::vector>& steps) { 39 | for(size_t k = 0; k < steps.size(); ++k) { 40 | if(steps[k]->uid == REPEAT_STEP) { 41 | if(acquire_step(steps, k-1, static_cast(steps[k].get()))) acquire_step(steps, k-1, static_cast(steps[k].get())); 42 | if(acquire_step(steps, k+1, static_cast(steps[k].get()))) acquire_step(steps, k+1, static_cast(steps[k].get())); 43 | // TODO might be an issue w/ stacked repeats, but why would you ever do that? 44 | } 45 | } 46 | } 47 | }; 48 | 49 | } -------------------------------------------------------------------------------- /traversal/P.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "maelstrom/storage/comparison.h" 11 | #include "util/gremlin_utils.h" 12 | 13 | namespace gremlinxx { 14 | 15 | /** 16 | Equivalent of P in Java-Gremlin. 17 | **/ 18 | class P { 19 | public: 20 | maelstrom::comparator comparison; 21 | std::any operand; 22 | 23 | P(maelstrom::comparator comparison, std::any operand) { 24 | this->comparison = comparison; 25 | 26 | if(operand.type() == typeid(const char*)) { 27 | operand = std::string( 28 | std::any_cast(operand) 29 | ); 30 | } 31 | this->operand = operand; 32 | } 33 | 34 | inline std::string getInfo() { 35 | std::stringstream sx; 36 | sx << "P<" << "'" << maelstrom::comparator_names[this->comparison] << "' " << string_any(operand) << ">"; 37 | return sx.str(); 38 | } 39 | 40 | inline static P eq(std::any t) { 41 | return P(maelstrom::EQUALS, t); 42 | } 43 | 44 | inline static P neq(std::any t) { 45 | return P(maelstrom::NOT_EQUALS, t); 46 | } 47 | 48 | inline static P gt(std::any t) { 49 | return P(maelstrom::GREATER_THAN, t); 50 | } 51 | 52 | inline static P gte(std::any t) { 53 | return P(maelstrom::GREATER_THAN_OR_EQUAL, t); 54 | } 55 | 56 | inline static P lt(std::any t) { 57 | return P(maelstrom::LESS_THAN, t); 58 | } 59 | 60 | inline static P lte(std::any t) { 61 | return P(maelstrom::LESS_THAN_OR_EQUAL, t); 62 | } 63 | 64 | inline static P between(std::any t, std::any u) { 65 | return P(maelstrom::BETWEEN, std::make_pair(t,u)); 66 | } 67 | 68 | inline static P inside(std::any t, std::any u) { 69 | return P(maelstrom::INSIDE, std::make_pair(t,u)); 70 | } 71 | 72 | inline static P outside(std::any t, std::any u) { 73 | return P(maelstrom::OUTSIDE, std::make_pair(t,u)); 74 | } 75 | 76 | inline static P within(std::any b...) { 77 | throw std::runtime_error("Within is currently unsupported in gremlin++"); 78 | } 79 | 80 | inline static P without(std::any b...) { 81 | throw std::runtime_error("Without is currently unsupported in gremlinx++"); 82 | } 83 | 84 | }; 85 | 86 | } 87 | -------------------------------------------------------------------------------- /step/filter/WhereStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/filter/WhereStep.h" 2 | #include "traversal/Traverser.h" 3 | #include "traversal/P.h" 4 | #include "traversal/GraphTraversal.h" 5 | #include "traversal/GraphTraversalSource.h" 6 | 7 | #include "maelstrom/containers/vector.h" 8 | #include "maelstrom/storage/comparison.h" 9 | #include "maelstrom/algorithms/select.h" 10 | #include "maelstrom/algorithms/filter.h" 11 | #include "maelstrom/algorithms/compare.h" 12 | 13 | #include 14 | 15 | namespace gremlinxx { 16 | 17 | WhereStep::WhereStep(std::string label, P predicate) 18 | : TraversalStep(FILTER, WHERE_STEP) { 19 | this->label = label; 20 | this->predicate = predicate; 21 | } 22 | 23 | std::string WhereStep::getInfo() { 24 | std::stringstream sx; 25 | sx << "WhereStep{" << this->label << "; " << this->predicate.getInfo() << "}"; 26 | return sx.str(); 27 | } 28 | 29 | void WhereStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 30 | if(traversers.empty()) return; 31 | 32 | GraphTraversalSource* src = traversal->getTraversalSource(); 33 | 34 | auto label = this->label; 35 | auto predicate = this->predicate; 36 | traversers.advance([label, predicate](auto& traverser_data, auto& side_effects, auto& path_info){ 37 | maelstrom::vector ix; 38 | if(predicate.operand.type() == typeid(std::string) && side_effects.find(std::any_cast(predicate.operand)) != side_effects.end()) { 39 | std::string other_label = std::any_cast(predicate.operand); 40 | ix = maelstrom::compare( 41 | side_effects[label], 42 | side_effects[std::any_cast(predicate.operand)], 43 | predicate.comparison 44 | ); 45 | 46 | ix = maelstrom::filter(ix, maelstrom::EQUALS, (uint8_t)1); 47 | } else { 48 | ix = maelstrom::filter( 49 | side_effects[label], 50 | predicate.comparison, 51 | predicate.operand 52 | ); 53 | } 54 | 55 | return std::make_pair( 56 | std::move(maelstrom::select(traverser_data, ix)), 57 | std::move(ix) 58 | ); 59 | }); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /step/embedding/SimilarityStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/embedding/SimilarityStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "structure/Graph.h" 4 | 5 | #include "maelstrom/algorithms/arange.h" 6 | 7 | 8 | namespace gremlinxx { 9 | 10 | SimilarityStep::SimilarityStep(std::string emb_name, std::vector& embedding_values, maelstrom::similarity_t metric) 11 | : TraversalStep(MAP, SIMILARITY_STEP) { 12 | this->similarity_metric = metric; 13 | this->name = emb_name; 14 | 15 | this->embeddings = maelstrom::vector( 16 | embedding_values[0].get_mem_type(), 17 | embedding_values[0].get_dtype() 18 | ); 19 | 20 | this->emb_stride = embedding_values[0].size(); 21 | this->embeddings.reserve(this->emb_stride * embedding_values.size()); 22 | 23 | for(maelstrom::vector& vec : embedding_values) { 24 | if(vec.size() != this->emb_stride) { 25 | throw std::invalid_argument("Embedding lengths do not match"); 26 | } 27 | this->embeddings.insert(vec); 28 | } 29 | } 30 | 31 | void SimilarityStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 32 | if(traversers.empty()) { 33 | return; 34 | } 35 | 36 | Graph* graph = traversal->getGraph(); 37 | traversers.advance([this, &graph](auto& data, auto& se, auto& paths){ 38 | auto trv_emb = graph->get_vertex_embeddings(this->name, data); 39 | 40 | if(trv_emb.size() % data.size() != 0 || trv_emb.size() / data.size() != this->emb_stride) { 41 | throw std::invalid_argument("Invalid embedding stride"); 42 | } 43 | 44 | maelstrom::vector empty; 45 | auto sim_vals = maelstrom::similarity( 46 | this->similarity_metric, 47 | trv_emb, 48 | empty, 49 | this->embeddings, 50 | this->emb_stride 51 | ); 52 | 53 | return std::make_pair( 54 | std::move(sim_vals), 55 | std::move( 56 | maelstrom::arange(data.get_mem_type(), data.size()) 57 | ) 58 | ); 59 | }); 60 | } 61 | 62 | std::string SimilarityStep::getInfo() { 63 | return "SimilarityStep{}"; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /traversal/GraphTraversalSource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "maelstrom/storage/datatype.h" 12 | #include "traversal/TraverserSet.h" 13 | #include "strategy/TraversalStrategy.h" 14 | 15 | namespace gremlinxx { 16 | class Graph; 17 | class Vertex; 18 | class Edge; 19 | class TraversalStep; 20 | class GraphTraversal; 21 | typedef std::function compare_func_t; 22 | typedef std::function equals_func_t; 23 | typedef std::function hash_func_t; 24 | 25 | class GraphTraversalSource { 26 | private: 27 | Graph* graph; 28 | 29 | protected: 30 | std::vector strategies; 31 | std::unordered_map type_registrations; 32 | std::unordered_map options; 33 | 34 | public: 35 | GraphTraversalSource(Graph* gr); 36 | 37 | virtual Graph* getGraph(); 38 | 39 | /* 40 | Constructs and returns a new traverser set object. 41 | */ 42 | virtual gremlinxx::traversal::TraverserSet* getNewTraverserSet(); 43 | 44 | virtual GraphTraversalSource* withStrategy(TraversalStrategy strategy); 45 | virtual GraphTraversalSource* withoutStrategy(TraversalStrategy strategy); 46 | virtual GraphTraversalSource* withoutStrategies(); 47 | virtual GraphTraversalSource* withTypeRegistration(std::type_index tid, maelstrom::dtype_t dtype); 48 | //GraphTraversalSource* withoutTypeRegistration(typeid_t tid); TODO 49 | 50 | virtual GraphTraversalSource* withAdminOption(std::string option_name, std::string value); 51 | virtual std::string getOptionValue(std::string option_name); 52 | 53 | virtual maelstrom::dtype_t get_dtype(std::any obj); 54 | 55 | virtual std::vector& getStrategies(); 56 | 57 | virtual GraphTraversal V(); 58 | virtual GraphTraversal V(maelstrom::vector vertices); 59 | virtual GraphTraversal V(std::vector vertices); 60 | virtual GraphTraversal V(std::vector v_ids); 61 | virtual GraphTraversal V(Vertex v); 62 | virtual GraphTraversal V(std::any v_id); 63 | virtual GraphTraversal E(); 64 | virtual GraphTraversal addV(); 65 | virtual GraphTraversal addV(std::string label); 66 | virtual GraphTraversal addE(std::string label); 67 | virtual GraphTraversal inject(std::vector injects); 68 | }; 69 | 70 | } -------------------------------------------------------------------------------- /step/controlflow/RepeatStep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "step/TraversalStep.h" 4 | #include "traversal/GraphTraversal.h" 5 | 6 | #include 7 | 8 | #define REPEAT_STEP 0x42 9 | #define LOOPS_TRAVERSAL_PROPERTY std::string("TRV_LOOPS") 10 | 11 | namespace gremlinxx { 12 | 13 | class RepeatStep: public TraversalStep { 14 | private: 15 | // Will emit anything out of the loop that passes through this traversal. 16 | std::optional emitTraversal; 17 | 18 | // Will end the loop when this traversal is completed. 19 | std::optional untilTraversal; 20 | 21 | // The action to be repeated. 22 | GraphTraversal actionTraversal; 23 | 24 | // The # of times to run the loop 25 | std::optional times; 26 | 27 | public: 28 | RepeatStep(GraphTraversal actionTraversal); 29 | 30 | inline GraphTraversal& getActionTraversal() { 31 | return this->actionTraversal; 32 | } 33 | 34 | inline void setEmitTraversal(GraphTraversal emitTraversal) { this->emitTraversal.emplace(emitTraversal); } 35 | inline GraphTraversal& getEmitTraversal() { 36 | if(!this->emitTraversal) throw std::runtime_error("Traversal does not have an emit traversal!"); 37 | return this->emitTraversal.value(); 38 | } 39 | inline bool hasEmitTraversal() { return emitTraversal.has_value(); } 40 | 41 | inline void setUntilTraversal(GraphTraversal untilTraversal) { this->untilTraversal.emplace(untilTraversal); } 42 | inline GraphTraversal& getUntilTraversal() { 43 | if(!this->untilTraversal) throw std::runtime_error("Traversal does not have an until traversal!"); 44 | return this->untilTraversal.value(); 45 | } 46 | inline bool hasUntilTraversal() { return untilTraversal.has_value(); } 47 | 48 | inline void setTimes(size_t times) { this->times.emplace(times); } 49 | inline size_t getTimes() { 50 | if(!this->times) throw std::runtime_error("Traversal does not have a times parameter!"); 51 | return this->times.value(); 52 | } 53 | inline bool hasTimes() { return times.has_value(); } 54 | 55 | 56 | virtual void apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers); 57 | 58 | using TraversalStep::getInfo; 59 | virtual std::string getInfo(); 60 | 61 | 62 | }; 63 | 64 | } -------------------------------------------------------------------------------- /step/edge/AddEdgeStartStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/edge/AddEdgeStartStep.h" 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "step/TraversalStep.h" 5 | #include "traversal/Traverser.h" 6 | #include "structure/Graph.h" 7 | #include "structure/Vertex.h" 8 | #include "structure/Edge.h" 9 | 10 | namespace gremlinxx { 11 | AddEdgeStartStep::AddEdgeStartStep(std::string label_arg) 12 | : TraversalStep(MAP, ADD_EDGE_START_STEP) { 13 | this->label = label_arg; 14 | this->out_vertex_traversal; 15 | this->in_vertex_traversal; 16 | } 17 | 18 | std::string AddEdgeStartStep::getInfo() { 19 | std::string info = "AddEdgeStartStep("; 20 | info += label + ")"; 21 | return info; 22 | } 23 | 24 | void AddEdgeStartStep::modulate_from(GraphTraversal t_from) { 25 | this->out_vertex_traversal.emplace(std::move(t_from)); 26 | } 27 | 28 | void AddEdgeStartStep::modulate_to(GraphTraversal t_to) { 29 | this->in_vertex_traversal.emplace(std::move(t_to)); 30 | } 31 | 32 | void AddEdgeStartStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 33 | // Need to check if there is enough info to add the Edge, then add it 34 | // if we can. 35 | // from() and to() are both always required here. 36 | GraphTraversalSource* my_traversal_source = trv->getTraversalSource(); 37 | if(my_traversal_source == NULL) throw std::runtime_error("Cannot call this step from an anonymous traversal!\n"); 38 | 39 | GraphTraversal from_traversal(my_traversal_source, this->out_vertex_traversal.value()); 40 | GraphTraversal to_traversal(my_traversal_source, this->in_vertex_traversal.value()); 41 | 42 | Vertex from_vertex = std::any_cast(from_traversal.next()); 43 | Vertex to_vertex = std::any_cast(to_traversal.next()); 44 | 45 | auto edge_dtype = my_traversal_source->getGraph()->get_edge_dtype(); 46 | Edge new_edge = trv->getGraph()->add_edge(from_vertex, to_vertex, label); 47 | std::any new_edge_repr = edge_dtype.serialize(new_edge); // Have to do this since Edge isn't castable to a primitive 48 | 49 | traversers.advance([edge_dtype, new_edge_repr, my_traversal_source](maelstrom::vector& data, std::unordered_map& se, gremlinxx::traversal::PathInfo& paths){ 50 | std::vector any_vec = {new_edge_repr}; 51 | return std::make_pair( 52 | maelstrom::make_vector_from_anys( 53 | data.get_mem_type(), 54 | edge_dtype, 55 | any_vec 56 | ), 57 | maelstrom::vector() 58 | ); 59 | }); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /step/math/MinStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/math/MinStep.h" 2 | #include 3 | 4 | #include "maelstrom/algorithms/reduce.h" 5 | #include "maelstrom/algorithms/reduce_by_key.h" 6 | #include "maelstrom/algorithms/set.h" 7 | #include "maelstrom/algorithms/sort.h" 8 | #include "maelstrom/algorithms/select.h" 9 | 10 | namespace gremlinxx { 11 | 12 | MinStep::MinStep() 13 | : ReductionStep(MIN_STEP) {} 14 | 15 | void MinStep::apply_global(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 16 | if(traversers.empty()) return; 17 | 18 | traversers.advance([](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 19 | std::any min; 20 | size_t ix; 21 | 22 | std::tie(min, ix) = maelstrom::reduce(traverser_data, maelstrom::reductor::MIN); 23 | 24 | maelstrom::vector output_result( 25 | traverser_data.get_mem_type(), 26 | traverser_data.get_dtype(), 27 | 1 28 | ); 29 | maelstrom::set(output_result, min); 30 | 31 | maelstrom::vector output_origin( 32 | traverser_data.get_mem_type(), 33 | maelstrom::uint64, 34 | 1 35 | ); 36 | maelstrom::set(output_origin, ix); 37 | 38 | return std::make_pair( 39 | std::move(output_result), 40 | std::move(output_origin) 41 | ); 42 | }); 43 | } 44 | 45 | void MinStep::apply_local(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 46 | std::string key = *this->scope_context.value().side_effect_key; 47 | 48 | if(traversers.empty()) return; 49 | 50 | traversers.advance([key](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 51 | // sort 52 | auto se = traverser_se[key]; 53 | auto ix = maelstrom::sort(se); 54 | auto data_copy = maelstrom::select(traverser_data, ix); 55 | 56 | maelstrom::vector reduced_values; 57 | maelstrom::vector reduced_indices; 58 | std::tie(reduced_values, reduced_indices) = maelstrom::reduce_by_key( 59 | se, 60 | data_copy, 61 | maelstrom::reductor::MIN, 62 | true 63 | ); 64 | data_copy.clear(); 65 | 66 | reduced_indices = maelstrom::select(ix, reduced_indices); 67 | 68 | return std::make_pair( 69 | std::move(reduced_values), 70 | std::move(reduced_indices) 71 | ); 72 | }); 73 | } 74 | 75 | std::string MinStep::getInfo() { 76 | std::string info = "MinStep{}"; 77 | 78 | return info; 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Version 1.1.0 (December 2024) 2 | 3 | This release of Gremlin++ adds better support for traversal strategies as well as Python bindings. 4 | These improvements are documented in the paper "Accelerating Graph Query Languages for Machine 5 | Learning and Retrieval Augmented Generation", published at KGBigData at IEEE BigData 2024. 6 | 7 | --------------------------------------------------------------- 8 | 9 | Version 1.0.0 (September 26, 2023) 10 | 11 | This is a major overhaul of Gremlin++, replacing the original _Traverser_ structure 12 | with virtual objects managed by _Maelstrom_ vectors. Every aspect of Gremlin++ 13 | has been almost completely rewritten as a series of Maelstrom operations. 14 | The OLAP behavior of Gremlin++ has also been standardized, and should roughly 15 | match that of OLAP Gremlin. Major performance and memory usage improvements are 16 | available in this release. 17 | 18 | --------------------------------------------------------------- 19 | 20 | Version 0.6.1 (October 11, 2022) 21 | 22 | Gremlin++ is the core of a C++ interpreter for the Gremlin language. 23 | It is licensed under the Apache license. Version 0.6.1 makes some 24 | semantic changes to accelerate traversals, most importantly the 25 | reconceptualization of *scopes*. 26 | 27 | Gremlin++ is a platform-independent header library. To use Gremlin++ 28 | in your project, simply set it as an include directory. 29 | 30 | Gremlin++ mostly follows the semantics of Gremlin, but with some 31 | key differences (some steps are always barriers, scopes have a 32 | different meaning, etc.) These differences will be documented 33 | in an upcoming paper. 34 | 35 | -------------------------------------------------------------- 36 | 37 | Version 0.6.0 (June 11, 2022) 38 | 39 | Gremlin++ is the core of a C++ interpreter for the Gremlin language. 40 | It is licensed under the Apache license. Version 0.6.0 overhauls the 41 | performance of the interpreter and adds additional steps, primarily 42 | to support the BitGraph project. A 1.0 release is targeted for later 43 | this year. 44 | 45 | Gremlin++ is a platform-independent header library. To use Gremlin++ 46 | in your project, simply set it as an include directory. 47 | 48 | While the goal of Gremlin++ is to support the same semantics as 49 | standard Gremlin, there are currently a few steps that differ, 50 | particularly the Repeat Step. Work is currently underway to 51 | improve documentation of these differences. 52 | 53 | -------------------------------------------------------------- 54 | Version 0.1.0 (October 18, 2019) 55 | 56 | Gremlin++ is the core of a C++ interpreter for the Gremlin language. 57 | It is licensed under the Apache license. 58 | 59 | Currently Gremlin++ supports the following platforms: 60 | - Windows (Cygwin64) 61 | - Linux 62 | 63 | Gremlin++ is a header library, so setting the include directory will 64 | suffice. 65 | 66 | -------------------------------------------------------------------------------- /step/property/HasNotStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/property/HasNotStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "traversal/GraphTraversalSource.h" 4 | #include "structure/Graph.h" 5 | 6 | #include "maelstrom/algorithms/remove_if.h" 7 | #include "maelstrom/algorithms/assign.h" 8 | #include "maelstrom/algorithms/arange.h" 9 | #include "maelstrom/algorithms/set.h" 10 | #include "maelstrom/algorithms/select.h" 11 | 12 | namespace gremlinxx { 13 | 14 | void HasNotStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 15 | if(traversers.empty()) return; 16 | 17 | GraphTraversalSource* g = traversal->getTraversalSource(); 18 | bool vertex = (traversers.getCurrentDataType() == g->getGraph()->get_vertex_dtype()); 19 | if(!vertex && traversers.getCurrentDataType() != g->getGraph()->get_edge_dtype()) { 20 | throw std::domain_error("Can't get an element map for something other than a vertex or edge"); 21 | } 22 | 23 | auto prop_name = this->property_key; 24 | traversers.advance([&g, prop_name, vertex](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 25 | maelstrom::vector ix_found; 26 | 27 | if(vertex) { 28 | std::tie( 29 | std::ignore, 30 | ix_found 31 | ) = g->getGraph()->get_vertex_properties(prop_name, traverser_data, false); 32 | } else { 33 | std::tie( 34 | std::ignore, 35 | ix_found 36 | ) = g->getGraph()->get_edge_properties(prop_name, traverser_data, false); 37 | } 38 | 39 | maelstrom::vector stencil( 40 | traverser_data.get_mem_type(), 41 | maelstrom::uint64, 42 | traverser_data.size() 43 | ); 44 | maelstrom::set(stencil, (size_t)0); 45 | 46 | maelstrom::vector ones( 47 | traverser_data.get_mem_type(), 48 | maelstrom::uint64, 49 | ix_found.size() 50 | ); 51 | maelstrom::set(ones, (size_t)1); 52 | 53 | maelstrom::assign(stencil, ix_found, ones); 54 | ix_found.clear(); 55 | ones.clear(); 56 | 57 | auto origin = maelstrom::arange(traverser_data.get_mem_type(), traverser_data.size()); 58 | maelstrom::remove_if(origin, stencil); 59 | stencil.clear(); 60 | 61 | auto found_elements = maelstrom::select(traverser_data, origin); 62 | 63 | return std::make_pair( 64 | std::move(found_elements), 65 | std::move(ix_found) 66 | ); 67 | }); 68 | } 69 | 70 | std::string HasNotStep::getInfo() { 71 | return "HasNotStep(" + this->property_key + ")"; 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /step/math/CountStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/math/CountStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | 4 | #include "maelstrom/algorithms/set.h" 5 | #include "maelstrom/algorithms/sort.h" 6 | #include "maelstrom/algorithms/arange.h" 7 | #include "maelstrom/algorithms/reduce_by_key.h" 8 | #include "maelstrom/algorithms/select.h" 9 | 10 | namespace gremlinxx { 11 | 12 | CountStep::CountStep() 13 | : ReductionStep(COUNT_STEP) {} 14 | 15 | std::string CountStep::getInfo() { 16 | return std::string("CountStep{}"); 17 | } 18 | 19 | void CountStep::apply_global(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 20 | traversers.advance([](auto& traverser_data, auto& traverser_se, auto& traverser_paths){ 21 | size_t sz = traverser_data.size(); 22 | maelstrom::vector new_data( 23 | traverser_data.get_mem_type(), 24 | maelstrom::uint64, 25 | 1 26 | ); 27 | maelstrom::set(new_data, sz); 28 | 29 | if(sz > 0) { 30 | maelstrom::vector output_origin( 31 | traverser_data.get_mem_type(), 32 | maelstrom::uint64, 33 | 1 34 | ); 35 | maelstrom::set(output_origin, static_cast(0)); 36 | 37 | return std::make_pair( 38 | std::move(new_data), 39 | std::move(output_origin) 40 | ); 41 | } 42 | 43 | return std::make_pair( 44 | std::move(new_data), 45 | maelstrom::vector(traverser_data.get_mem_type(), maelstrom::uint64) 46 | ); 47 | }); 48 | } 49 | 50 | void CountStep::apply_local(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 51 | if(traversers.empty()) return; 52 | 53 | std::string key = *this->scope_context.value().side_effect_key; 54 | traversers.advance([key](auto& traverser_data, auto& traverser_se, auto& traverser_paths){ 55 | // count_unique doesn't work since the keys aren't guaranteed to be contiguous 56 | auto se = traverser_se[key]; 57 | 58 | auto c = maelstrom::vector(se.get_mem_type(), maelstrom::uint64, se.size()); 59 | maelstrom::set(c, 1); 60 | 61 | maelstrom::vector reduced_values; 62 | maelstrom::vector reduced_indices; 63 | std::tie(reduced_values, reduced_indices) = maelstrom::reduce_by_key( 64 | se, 65 | c, 66 | maelstrom::reductor::SUM, 67 | false // not sorted 68 | ); 69 | c.clear(); 70 | 71 | return std::make_pair( 72 | std::move(reduced_values), 73 | std::move(reduced_indices) 74 | ); 75 | }); 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /gremlinxx/gremlinxx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "structure/Direction.h" 4 | #include "structure/Property.h" 5 | #include "structure/VertexProperty.h" 6 | #include "structure/Element.h" 7 | #include "structure/Vertex.h" 8 | #include "structure/Edge.h" 9 | #include "structure/Graph.h" 10 | 11 | #include "traversal/Traverser.h" 12 | #include "traversal/GraphTraversalSource.h" 13 | #include "traversal/GraphTraversal.h" 14 | #include "traversal/Comparison.h" 15 | #include "traversal/P.h" 16 | #include "traversal/Scope.h" 17 | #include "traversal/SyntaxHelper.h" 18 | 19 | #include "step/TraversalStep.h" 20 | #include "step/controlflow/CoalesceStep.h" 21 | #include "step/controlflow/EmitStep.h" 22 | #include "step/controlflow/InjectStep.h" 23 | #include "step/controlflow/LoopsStep.h" 24 | #include "step/controlflow/RepeatStep.h" 25 | #include "step/controlflow/TimesStep.h" 26 | #include "step/controlflow/UnionStep.h" 27 | #include "step/controlflow/UntilStep.h" 28 | 29 | #include "step/edge/AddEdgeStartStep.h" 30 | #include "step/edge/AddEdgeStep.h" 31 | 32 | #include "step/filter/IsStep.h" 33 | #include "step/filter/LimitStep.h" 34 | #include "step/filter/LimitSupportingStep.h" 35 | #include "step/filter/WhereStep.h" 36 | #include "step/filter/SampleStep.h" 37 | 38 | #include "step/graph/VStep.h" 39 | #include "step/graph/IdStep.h" 40 | #include "step/graph/SubgraphExtractionStep.h" 41 | #include "step/graph/SubgraphStep.h" 42 | 43 | #include "step/logic/DedupStep.h" 44 | #include "step/logic/IdentityStep.h" 45 | #include "step/logic/NoOpStep.h" 46 | #include "step/logic/OrderStep.h" 47 | 48 | #include "step/math/CountStep.h" 49 | #include "step/math/MinStep.h" 50 | #include "step/math/GroupCountStep.h" 51 | 52 | #include "step/modulate/ByModulating.h" 53 | #include "step/modulate/ByStep.h" 54 | #include "step/modulate/FromStep.h" 55 | #include "step/modulate/FromToModulating.h" 56 | #include "step/modulate/ToStep.h" 57 | #include "step/modulate/ReductionStep.h" 58 | 59 | #include "step/property/PropertyStep.h" 60 | #include "step/property/HasStep.h" 61 | #include "step/property/PropertyStep.h" 62 | #include "step/property/ValueStep.h" 63 | #include "step/property/ElementMapStep.h" 64 | 65 | #include "step/sideeffect/AsStep.h" 66 | #include "step/sideeffect/SelectStep.h" 67 | 68 | #include "step/vertex/AddVertexStartStep.h" 69 | #include "step/vertex/AddVertexStep.h" 70 | #include "step/vertex/VertexStep.h" 71 | #include "step/vertex/DegreeStep.h" 72 | 73 | #include "step/embedding/EmbeddingStep.h" 74 | #include "step/embedding/LikeStep.h" 75 | #include "step/embedding/SimilarityStep.h" 76 | 77 | #include "strategy/TraversalStrategy.h" 78 | #include "strategy/ByModulatingStrategy.h" 79 | #include "strategy/FromToModulatingStrategy.h" 80 | #include "strategy/RepeatStepCompletionStrategy.h" 81 | #include "strategy/SubgraphStepCompletionStrategy.h" 82 | #include "strategy/LimitSupportingStrategy.h" 83 | #include "strategy/BasicPatternExtractionStrategy.h" 84 | #include "strategy/HasJoinStrategy.h" 85 | #include "strategy/NoOpRemovalStrategy.h" 86 | #include "strategy/RepeatUnrollStrategy.h" -------------------------------------------------------------------------------- /step/embedding/LikeStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/embedding/LikeStep.h" 2 | #include "structure/Graph.h" 3 | #include "traversal/GraphTraversal.h" 4 | 5 | #include "maelstrom/algorithms/filter.h" 6 | #include "maelstrom/algorithms/select.h" 7 | #include "maelstrom/algorithms/topk.h" 8 | 9 | namespace gremlinxx { 10 | 11 | LikeStep::LikeStep(std::string name, std::vector& embs, std::optional threshold, std::optional count, maelstrom::similarity_t metric) 12 | : TraversalStep(FILTER, LIKE_STEP) { 13 | if(!threshold && !count) { 14 | throw std::invalid_argument("Either threshold, count, or both must be provided for LikeStep"); 15 | } 16 | 17 | this->emb_name = name; 18 | this->match_threshold = threshold; 19 | this->count = count; 20 | this->similarity_metric = metric; 21 | 22 | this->emb_stride = embs[0].size(); 23 | this->embeddings = maelstrom::vector( 24 | embs[0].get_mem_type(), 25 | embs[0].get_dtype() 26 | ); 27 | this->embeddings.reserve(this->emb_stride * embs.size()); 28 | 29 | for(maelstrom::vector& vec : embs) { 30 | if(vec.size() != this->emb_stride) { 31 | throw std::invalid_argument("Embedding lengths do not match"); 32 | } 33 | this->embeddings.insert(vec); 34 | } 35 | } 36 | 37 | void LikeStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 38 | Graph* graph = traversal->getGraph(); 39 | 40 | traversers.advance([this, &graph](auto& data, auto& se, auto& paths){ 41 | auto src_emb = graph->get_vertex_embeddings(this->emb_name, data); 42 | 43 | maelstrom::vector empty; 44 | auto sim = maelstrom::similarity( 45 | this->similarity_metric, 46 | src_emb, 47 | empty, 48 | this->embeddings, 49 | this->emb_stride 50 | ); 51 | 52 | maelstrom::vector z, ix; 53 | if(this->match_threshold) { 54 | ix = maelstrom::filter( 55 | sim, 56 | maelstrom::GREATER_THAN_OR_EQUAL, 57 | this->match_threshold 58 | ); 59 | 60 | z = maelstrom::select( 61 | data, 62 | ix 63 | ); 64 | } 65 | 66 | if(this->count) { 67 | if(this->match_threshold) { 68 | auto tix = maelstrom::topk(z, this->count.value()); 69 | z = maelstrom::select(z, tix); 70 | ix = maelstrom::select(ix, tix); 71 | } else { 72 | ix = maelstrom::topk(sim, this->count.value()); 73 | z = maelstrom::select(data, ix); 74 | } 75 | } 76 | 77 | return std::make_pair( 78 | std::move(z), 79 | std::move(ix) 80 | ); 81 | }); 82 | } 83 | 84 | std::string LikeStep::getInfo() { 85 | return "LikeStep{}"; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /traversal/Scope.cpp: -------------------------------------------------------------------------------- 1 | #include "traversal/Scope.h" 2 | 3 | #include 4 | 5 | namespace gremlinxx { 6 | 7 | scope_group_t group_id_from_any(std::any a) { 8 | auto& id = a.type(); 9 | if(id == typeid(int)) return static_cast(std::any_cast(a)); 10 | else if (id == typeid(long)) return static_cast(std::any_cast(a)); 11 | else if(id == typeid(unsigned int)) return static_cast(std::any_cast(a)); 12 | else if(id == typeid(unsigned long)) return static_cast(std::any_cast(a)); 13 | else if(id == typeid(char)) return static_cast(std::any_cast(a)); 14 | else if(id == typeid(unsigned char)) return static_cast(std::any_cast(a)); 15 | else if(id == typeid(short)) return static_cast(std::any_cast(a)); 16 | else if(id == typeid(unsigned short)) return static_cast(std::any_cast(a)); 17 | else if(id == typeid(float)) throw std::runtime_error("Float type not supported for scope groups"); 18 | else if(id == typeid(double)) throw std::runtime_error("Double type not supported for scope groups"); 19 | else if(id == typeid(std::string)) throw std::runtime_error("String type not supported for scope groups"); 20 | else if(id == typeid(char*)) throw std::runtime_error("Char array type not supported for scope groups"); 21 | else if(id == typeid(const char*)) throw std::runtime_error("Char array type not supported for scope groups"); 22 | else throw std::runtime_error("Unknown type not supported for scope groups"); 23 | } 24 | 25 | std::any any_from_group_id(scope_group_t group_id, const std::type_info& out_type) { 26 | if(out_type == typeid(int)) return std::any(static_cast(group_id)); 27 | else if (out_type == typeid(long)) return std::any(static_cast(group_id)); 28 | else if(out_type == typeid(unsigned int)) return std::any(static_cast(group_id)); 29 | else if(out_type == typeid(unsigned long)) return std::any(static_cast(group_id)); 30 | else if(out_type == typeid(char)) return std::any(static_cast(group_id)); 31 | else if(out_type == typeid(unsigned char)) return std::any(static_cast(group_id)); 32 | else if(out_type == typeid(short)) return std::any(static_cast(group_id)); 33 | else if(out_type == typeid(unsigned short)) return std::any(static_cast(group_id)); 34 | else if(out_type == typeid(float)) throw std::runtime_error("Float type not supported for scope groups"); 35 | else if(out_type == typeid(double)) throw std::runtime_error("Double type not supported for scope groups"); 36 | else if(out_type == typeid(std::string)) throw std::runtime_error("String type not supported for scope groups"); 37 | else if(out_type == typeid(char*)) throw std::runtime_error("Char array type not supported for scope groups"); 38 | else if(out_type == typeid(const char*)) throw std::runtime_error("Char array type not supported for scope groups"); 39 | else throw std::runtime_error("Unknown type not supported for scope groups"); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /step/property/ElementMapStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/property/ElementMapStep.h" 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "step/TraversalStep.h" 5 | #include "structure/Property.h" 6 | #include "structure/Vertex.h" 7 | #include "structure/Edge.h" 8 | #include "structure/Graph.h" 9 | #include "util/gremlin_utils.h" 10 | 11 | #include "maelstrom/algorithms/intersection.h" 12 | #include "maelstrom/algorithms/select.h" 13 | 14 | namespace gremlinxx { 15 | 16 | ElementMapStep::ElementMapStep(std::vector& keys) 17 | : TraversalStep(MAP, ELEMENTMAP_STEP) { 18 | this->keys = std::vector(keys.begin(), keys.end()); 19 | } 20 | 21 | void ElementMapStep::modulate_by(std::any arg) { 22 | this->by_traversal = std::any_cast(arg); 23 | } 24 | 25 | std::string ElementMapStep::getInfo() { 26 | std::string s = "ElementMapStep{"; 27 | for(std::string key : this->keys) s += key + ","; 28 | s += "}"; 29 | return s; 30 | } 31 | 32 | void ElementMapStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 33 | if(traversers.empty()) return; 34 | 35 | auto graph = traversal->getGraph(); 36 | auto& prop_keys = this->keys; 37 | 38 | auto traverser_data = traversers.getTraverserData(); 39 | 40 | std::vector values; 41 | maelstrom::vector origin; 42 | 43 | bool vertex = (traverser_data.get_dtype() == graph->get_vertex_dtype()); 44 | if(!vertex && traverser_data.get_dtype() != graph->get_edge_dtype()) { 45 | throw std::domain_error("Can't get an element map for something other than a vertex or edge"); 46 | } 47 | 48 | for(std::string key : prop_keys) { 49 | maelstrom::vector next_values; 50 | maelstrom::vector ix; 51 | 52 | if(vertex) { 53 | std::tie(next_values, ix) = graph->get_vertex_properties(key, traverser_data, true); 54 | } else { 55 | std::tie(next_values, ix) = graph->get_edge_properties(key, traverser_data, true); 56 | } 57 | 58 | traverser_data = std::move(maelstrom::select(traverser_data, ix)); 59 | 60 | if(origin.empty()) { 61 | origin = std::move(ix); 62 | } else { 63 | origin = maelstrom::select(origin, ix); 64 | for(maelstrom::vector& v : values) v = maelstrom::select(v, ix); 65 | } 66 | 67 | values.push_back(std::move(next_values)); 68 | } 69 | 70 | // Use advance to reorder the traversers 71 | traversers.advance([&origin, &traverser_data](auto& old_traverser_data, auto& traverser_se, auto& traverser_paths){ 72 | return std::make_pair( 73 | std::move(traverser_data), 74 | std::move(origin) 75 | ); 76 | }); 77 | 78 | traverser_data = std::move(traversers.getTraverserData()); 79 | 80 | traversers.set_side_effects(ELEMENTMAP_ID_KEY, std::move(maelstrom::vector(traverser_data, false))); 81 | 82 | traversers.set_side_effects( 83 | ElEMENTMAP_LABEL_KEY, 84 | vertex ? std::move(graph->get_vertex_labels(traverser_data)) : std::move(graph->get_edge_labels(traverser_data)) 85 | ); 86 | 87 | for(size_t i = 0; i < prop_keys.size(); ++i) traversers.set_side_effects(prop_keys[i], std::move(values[i])); 88 | 89 | } 90 | } -------------------------------------------------------------------------------- /step/property/ValueStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/property/ValueStep.h" 2 | 3 | #include "traversal/GraphTraversal.h" 4 | #include "traversal/GraphTraversalSource.h" 5 | 6 | #include "maelstrom/algorithms/intersection.h" 7 | #include "maelstrom/algorithms/sort.h" 8 | #include "maelstrom/algorithms/select.h" 9 | 10 | #include "structure/Vertex.h" 11 | #include "structure/Edge.h" 12 | #include "structure/Graph.h" 13 | 14 | #include 15 | 16 | namespace gremlinxx { 17 | 18 | ValueStep::ValueStep(std::vector property_keys) 19 | : TraversalStep(MAP, VALUE_STEP) { 20 | this->keys = property_keys; 21 | } 22 | 23 | std::string ValueStep::getInfo() { 24 | std::stringstream sx; 25 | sx << "ValueStep{"; 26 | for(std::string s : this->keys) sx << s << ", "; 27 | sx << "}"; 28 | 29 | return sx.str(); 30 | } 31 | 32 | void ValueStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 33 | if(traversers.empty()) return; 34 | 35 | auto g = traversal->getTraversalSource(); 36 | auto& prop_names = this->keys; 37 | 38 | traversers.advance([&g, &prop_names](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 39 | // TODO efficiently get multiple properties at once 40 | // TODO sort 41 | 42 | // Sort a copy of the traverser data 43 | auto traverser_data_copy = maelstrom::vector(traverser_data, false); 44 | if(!traverser_data_copy.empty()) { 45 | auto original_unsorted_ix = maelstrom::sort(traverser_data_copy); 46 | } 47 | 48 | maelstrom::vector values; 49 | maelstrom::vector output_origin; 50 | 51 | bool vertex = (traverser_data_copy.get_dtype() == g->getGraph()->get_vertex_dtype()); 52 | if(!vertex && traverser_data_copy.get_dtype() != g->getGraph()->get_edge_dtype()) { 53 | throw std::domain_error("Can't get a property for something other than a vertex or edge"); 54 | } 55 | 56 | for(std::string key : prop_names) { 57 | maelstrom::vector current_origin; 58 | maelstrom::vector current_values; 59 | 60 | if(vertex) { 61 | std::tie( 62 | current_values, 63 | current_origin 64 | ) = g->getGraph()->get_vertex_properties( 65 | key, 66 | traverser_data_copy, 67 | true 68 | ); 69 | } else { 70 | std::tie( 71 | current_values, 72 | current_origin 73 | ) = g->getGraph()->get_edge_properties( 74 | key, 75 | traverser_data_copy, 76 | true 77 | ); 78 | } 79 | 80 | if(values.empty()) { 81 | values = std::move(current_values); 82 | output_origin = std::move(current_origin); 83 | } else { 84 | if(values.get_dtype() != current_values.get_dtype()) { 85 | auto current_dtype = current_values.get_dtype(); 86 | auto global_dtype = values.get_dtype(); 87 | // Promote to larger dtype, up to user to make sure this is ok 88 | auto new_dtype = (maelstrom::size_of(global_dtype) < maelstrom::size_of(current_dtype)) ? current_dtype : global_dtype; 89 | if(current_dtype != new_dtype) current_values = current_values.astype(new_dtype); 90 | if(global_dtype != new_dtype) values = values.astype(new_dtype); 91 | } 92 | 93 | values.insert(values.size(), current_values); 94 | output_origin.insert(values.size(), current_origin); 95 | } 96 | 97 | } 98 | 99 | return std::make_pair( 100 | std::move(values), 101 | std::move(output_origin) 102 | ); 103 | }); 104 | } 105 | 106 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project( 4 | GREMLINXX 5 | VERSION 1.0.0 6 | LANGUAGES CXX 7 | ) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED True) 11 | 12 | set(POSITION_INDEPENDENT_CODE True) 13 | set(INTERFACE_POSITION_INDEPENDENT_CODE True) 14 | 15 | find_package(Python 3.10 COMPONENTS Interpreter Development.Module REQUIRED) 16 | 17 | add_library( 18 | gremlinxx SHARED 19 | 20 | step/TraversalStep.cpp 21 | 22 | step/controlflow/CoalesceStep.cpp 23 | step/controlflow/EmitStep.cpp 24 | step/controlflow/InjectStep.cpp 25 | step/controlflow/LoopsStep.cpp 26 | step/controlflow/RepeatStep.cpp 27 | step/controlflow/TimesStep.cpp 28 | step/controlflow/UnionStep.cpp 29 | step/controlflow/UntilStep.cpp 30 | 31 | step/edge/AddEdgeStartStep.cpp 32 | step/edge/AddEdgeStep.cpp 33 | 34 | step/filter/IsStep.cpp 35 | step/filter/LimitStep.cpp 36 | step/filter/WhereStep.cpp 37 | step/filter/SampleStep.cpp 38 | 39 | step/graph/VStep.cpp 40 | step/graph/IdStep.cpp 41 | step/graph/SubgraphStep.cpp 42 | step/graph/SubgraphExtractionStep.cpp 43 | 44 | step/logic/DedupStep.cpp 45 | step/logic/IdentityStep.cpp 46 | step/logic/NoOpStep.cpp 47 | step/logic/OrderStep.cpp 48 | 49 | step/math/CountStep.cpp 50 | step/math/GroupCountStep.cpp 51 | step/math/MinStep.cpp 52 | 53 | step/modulate/ByStep.cpp 54 | step/modulate/FromStep.cpp 55 | step/modulate/ToStep.cpp 56 | 57 | step/property/HasStep.cpp 58 | step/property/HasNotStep.cpp 59 | step/property/PropertyStep.cpp 60 | step/property/ElementMapStep.cpp 61 | step/property/ValueStep.cpp 62 | 63 | step/embedding/EmbeddingStep.cpp 64 | step/embedding/SimilarityStep.cpp 65 | step/embedding/LikeStep.cpp 66 | step/embedding/EncodeStep.cpp 67 | 68 | step/sideeffect/SideEffectStep.cpp 69 | step/sideeffect/AsStep.cpp 70 | step/sideeffect/SelectStep.cpp 71 | 72 | step/vertex/AddVertexStartStep.cpp 73 | step/vertex/AddVertexStep.cpp 74 | step/vertex/VertexStep.cpp 75 | step/vertex/DegreeStep.cpp 76 | 77 | strategy/TraversalStrategy.cpp 78 | strategy/ByModulatingStrategy.cpp 79 | strategy/FromToModulatingStrategy.cpp 80 | strategy/RepeatStepCompletionStrategy.cpp 81 | strategy/RepeatUnrollStrategy.cpp 82 | strategy/SubgraphStepCompletionStrategy.cpp 83 | strategy/LimitSupportingStrategy.cpp 84 | strategy/NoOpRemovalStrategy.cpp 85 | strategy/HasJoinStrategy.cpp 86 | strategy/BasicPatternExtractionStrategy.cpp 87 | 88 | traversal/Comparison.cpp 89 | traversal/GraphTraversal.cpp 90 | traversal/GraphTraversalSource.cpp 91 | traversal/Scope.cpp 92 | traversal/Traverser.cpp 93 | traversal/BasicTraverserSet.cpp 94 | traversal/PathInfo.cpp 95 | 96 | structure/Structure.cpp 97 | ) 98 | 99 | target_compile_options( 100 | gremlinxx 101 | PUBLIC 102 | -O3 103 | -funsafe-math-optimizations 104 | -frename-registers 105 | -funroll-loops 106 | -fsized-deallocation 107 | ) 108 | 109 | target_include_directories( 110 | gremlinxx 111 | PUBLIC 112 | "." # gremlinxx path 113 | "../maelstrom/include" # maelstrom path 114 | ) 115 | 116 | if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 117 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 118 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") 119 | endif() 120 | 121 | # Detect the installed nanobind package and import it into CMake 122 | execute_process( 123 | COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir 124 | OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR) 125 | list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}") 126 | find_package(nanobind CONFIG REQUIRED) 127 | 128 | nanobind_add_module(pygremlinxx bindings/PyGremlin.cpp) 129 | target_link_libraries( 130 | pygremlinxx 131 | PRIVATE 132 | gremlinxx 133 | maelstrom 134 | ) 135 | target_link_directories( 136 | pygremlinxx 137 | PRIVATE 138 | "../maelstrom/" 139 | "." 140 | ) 141 | target_include_directories( 142 | pygremlinxx 143 | PRIVATE 144 | "." 145 | "../maelstrom/include" 146 | ) -------------------------------------------------------------------------------- /step/property/PropertyStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/property/PropertyStep.h" 2 | 3 | #include "step/math/MinStep.h" 4 | 5 | #include "structure/Element.h" 6 | #include "structure/Vertex.h" 7 | 8 | #include "traversal/GraphTraversal.h" 9 | #include "traversal/GraphTraversalSource.h" 10 | #include "structure/Graph.h" 11 | 12 | #include "maelstrom/algorithms/arange.h" 13 | #include "maelstrom/algorithms/select.h" 14 | #include "maelstrom/algorithms/unique.h" 15 | #include "maelstrom/algorithms/set.h" 16 | 17 | #include 18 | 19 | namespace gremlinxx { 20 | 21 | PropertyStep::PropertyStep(std::string property_key, std::any value) 22 | : TraversalStep(MAP, PROPERTY_STEP) { 23 | this->cardinality = SINGLE; 24 | this->key = std::string(property_key); 25 | this->value = std::any(value); 26 | } 27 | 28 | PropertyStep::PropertyStep(Cardinality card, std::string property_key, std::any value) 29 | : TraversalStep(MAP, PROPERTY_STEP) { 30 | this->cardinality = card; 31 | this->key = std::string(property_key); 32 | this->value = std::any(value); 33 | } 34 | 35 | void PropertyStep::apply(GraphTraversal* current_traversal, gremlinxx::traversal::TraverserSet& traversers) { 36 | if(traversers.empty()) return; 37 | 38 | auto g = current_traversal->getTraversalSource(); 39 | auto current_data_type = traversers.getCurrentDataType(); 40 | if(current_data_type != g->getGraph()->get_vertex_dtype() && current_data_type != g->getGraph()->get_edge_dtype()) { 41 | throw std::domain_error("Can't add a property to something other than a vertex or edge!"); 42 | } 43 | 44 | if(this->value.type() == typeid(GraphTraversal)) { 45 | GraphTraversal ap_anonymous_trv = std::any_cast(value); 46 | 47 | for(auto& step : ap_anonymous_trv.getSteps()) { 48 | auto reduction_step = dynamic_cast(step.get()); 49 | if(reduction_step != nullptr) { 50 | reduction_step->set_scope_context(ScopeContext{Scope::local, PROPERTY_STEP_SIDE_EFFECT_KEY}); 51 | } 52 | } 53 | 54 | GraphTraversal new_trv(current_traversal->getTraversalSource(), ap_anonymous_trv); 55 | new_trv.setInitialTraversers(traversers); 56 | 57 | // Need to initialize the scope context side effect 58 | auto indv = maelstrom::arange(traversers.getCurrentMemType(), traversers.size()); 59 | new_trv.getTraverserSet().set_side_effects(PROPERTY_STEP_SIDE_EFFECT_KEY, std::move(indv)); 60 | 61 | // Iterate the traversal 62 | new_trv.iterate(); 63 | auto& retrieved_traversers = new_trv.getTraverserSet(); 64 | 65 | // Will not update vertices or edges without a given property value 66 | 67 | maelstrom::vector original_keys = std::move(retrieved_traversers.getSideEffects()[PROPERTY_STEP_SIDE_EFFECT_KEY]); 68 | maelstrom::vector property_vals = retrieved_traversers.getTraverserData(); 69 | retrieved_traversers.clear(); 70 | 71 | auto unique_ix = maelstrom::unique(original_keys); 72 | original_keys = maelstrom::select(original_keys, unique_ix); 73 | property_vals = maelstrom::select(property_vals, unique_ix); 74 | 75 | maelstrom::vector elements = traversers.getTraverserData(); 76 | elements = maelstrom::select(elements, original_keys); 77 | original_keys.clear(); 78 | 79 | if(current_data_type == g->getGraph()->get_vertex_dtype()) { 80 | g->getGraph()->set_vertex_properties(this->key, elements, property_vals); 81 | } else { 82 | g->getGraph()->set_edge_properties(this->key, elements, property_vals); 83 | } 84 | 85 | } 86 | else { 87 | // Store the property 88 | auto elements = traversers.getTraverserData(); 89 | auto unique_ix = maelstrom::unique(elements); 90 | elements = maelstrom::select(elements, unique_ix); 91 | unique_ix.clear(); 92 | // FIXME deduplication may not be necessary but technically it is an API requirement 93 | // more research needs to be done on dropping that requirement 94 | 95 | maelstrom::vector val_vector( 96 | elements.get_mem_type(), 97 | g->get_dtype(this->value), 98 | elements.size() 99 | ); 100 | maelstrom::set(val_vector, this->value); 101 | 102 | if(current_data_type == g->getGraph()->get_vertex_dtype()) { 103 | g->getGraph()->set_vertex_properties(this->key, elements, val_vector); 104 | } else { 105 | g->getGraph()->set_edge_properties(this->key, elements, val_vector); 106 | } 107 | } 108 | 109 | // Traversers aren't modified in this step. 110 | } 111 | 112 | std::string PropertyStep::getInfo() { 113 | std::stringstream sx; 114 | sx << "PropertyStep{" << this->key << "}"; 115 | return sx.str(); 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /step/vertex/VertexStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/vertex/VertexStep.h" 2 | 3 | #include "traversal/Traverser.h" 4 | #include "traversal/GraphTraversal.h" 5 | #include "structure/Vertex.h" 6 | #include "structure/Edge.h" 7 | #include "structure/Graph.h" 8 | 9 | namespace gremlinxx { 10 | 11 | VertexStep::VertexStep(Direction dir, std::vector edge_labels_arg, VertexStepType gsType_arg) 12 | : TraversalStep(MAP, VERTEX_STEP) { 13 | direction = dir; 14 | std::for_each(edge_labels_arg.begin(), edge_labels_arg.end(), [&](std::string str){ this->edge_labels.insert(str); }); 15 | this->vsType = gsType_arg; 16 | } 17 | 18 | VertexStep::VertexStep(Direction dir, VertexStepType gsType_arg) 19 | : TraversalStep(MAP, VERTEX_STEP) { 20 | direction = dir; 21 | this->vsType = gsType_arg; 22 | } 23 | 24 | std::string VertexStep::getInfo() { 25 | std::string info = "VertexStep("; 26 | info += (direction == IN ? "IN" : direction == OUT ? "OUT" : "BOTH"); 27 | info += ", "; 28 | if(!edge_labels.empty()) { 29 | info += "{"; 30 | auto p = edge_labels.begin(); 31 | for(int k = 0; k < edge_labels.size() - 1; k++) info = info + *(p++) + ", "; 32 | info = info + *p + "}"; 33 | } 34 | else info += "{}"; 35 | info = info + ", " + (vsType == VERTEX_TO_VERTEX ? "VERTEX" : "EDGE"); 36 | return info + ")"; 37 | } 38 | 39 | void VertexStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 40 | auto vs_type = this->vsType; 41 | auto graph = traversal->getGraph(); 42 | std::vector labels(this->edge_labels.begin(), this->edge_labels.end()); 43 | auto dir = this->direction; 44 | 45 | traversers.advance([&graph, vs_type, &labels, dir](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 46 | maelstrom::vector successors; 47 | maelstrom::vector output_origin; 48 | switch(vs_type) { 49 | case VERTEX_TO_VERTEX: { 50 | if(traverser_data.empty()) { 51 | successors = maelstrom::vector(traverser_data.get_mem_type(), graph->get_vertex_dtype()); 52 | output_origin = maelstrom::vector(); 53 | } else { 54 | if(traverser_data.get_dtype() != graph->get_vertex_dtype()) throw std::domain_error("Can only call out()/in() on vertices!"); 55 | std::tie( 56 | successors, 57 | output_origin 58 | ) = graph->V(traverser_data, labels, dir); 59 | } 60 | break; 61 | } 62 | case VERTEX_TO_EDGE: { 63 | if(traverser_data.empty()) { 64 | successors = maelstrom::vector(traverser_data.get_mem_type(), graph->get_edge_dtype()); 65 | output_origin = maelstrom::vector(); 66 | } else { 67 | if(traverser_data.get_dtype() != graph->get_vertex_dtype()) throw std::domain_error("Can only call outE()/inE() on vertices!"); 68 | std::tie( 69 | successors, 70 | output_origin 71 | ) = graph->E(traverser_data, labels, dir); 72 | } 73 | break; 74 | } 75 | case EDGE_TO_VERTEX: { 76 | if(traverser_data.empty()) { 77 | successors = maelstrom::vector(traverser_data.get_mem_type(), graph->get_vertex_dtype()); 78 | output_origin = maelstrom::vector(); 79 | } else { 80 | if(traverser_data.get_dtype() != graph->get_edge_dtype()) throw std::domain_error("Can only call outV()/inV() on edges!"); 81 | std::tie( 82 | successors, 83 | output_origin 84 | ) = graph->toV(traverser_data, dir); 85 | } 86 | break; 87 | } 88 | default: { 89 | throw std::runtime_error("Invalid vertex step type"); 90 | } 91 | } 92 | 93 | return std::make_pair( 94 | std::move(successors), 95 | std::move(output_origin) 96 | ); 97 | }); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /step/edge/AddEdgeStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/edge/AddEdgeStep.h" 2 | #include "structure/Graph.h" 3 | #include "traversal/Traverser.h" 4 | #include "traversal/GraphTraversal.h" 5 | #include "traversal/GraphTraversalSource.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace gremlinxx { 11 | 12 | AddEdgeStep::AddEdgeStep(std::string label_arg) 13 | : TraversalStep(MAP, ADD_EDGE_STEP) { 14 | label = label_arg; 15 | } 16 | 17 | std::string AddEdgeStep::getInfo() { 18 | std::string info = "AddEdgeStep("; 19 | info += label + ")"; 20 | return info; 21 | } 22 | 23 | void AddEdgeStep::modulate_from(GraphTraversal t_from) { 24 | this->out_vertex_traversal.emplace(t_from); 25 | } 26 | 27 | void AddEdgeStep::modulate_to(GraphTraversal t_to) { 28 | this->in_vertex_traversal.emplace(t_to); 29 | } 30 | 31 | void AddEdgeStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 32 | // TODO run the traversals on everything at once - don't unpack anything, instead use the final traversal results 33 | // TODO allow multiple src/dst outputted by the traversal 34 | 35 | GraphTraversalSource* src = traversal->getTraversalSource(); 36 | Graph* graph = traversal->getGraph(); 37 | 38 | if(src == nullptr) throw std::runtime_error("Cannot call AddEdgeStep from an anonymous traversal!"); 39 | if(graph == nullptr) throw std::runtime_error("Cannot add edges without access to the graph!"); 40 | 41 | auto unpacked_traversers = traversers.unpack(); 42 | std::vector added_edges; 43 | added_edges.reserve(traversers.size()); 44 | for(auto it = unpacked_traversers.begin(); it != unpacked_traversers.end(); ++it) { 45 | Vertex from_vertex; 46 | Vertex to_vertex; 47 | bool used_current_traverser = false; 48 | 49 | if(!this->out_vertex_traversal) { 50 | try { 51 | from_vertex = std::any_cast(std::get<0>(*it).get(0)); 52 | } catch(std::bad_any_cast& exc) { throw std::runtime_error("Attempted to add an edge from something that is not a Vertex!"); } 53 | catch(std::out_of_range& exr) { throw std::runtime_error("Attempted to add an edge but incoming traversal was empty!"); } 54 | 55 | used_current_traverser = true; 56 | } else { 57 | GraphTraversal from_traversal(src, out_vertex_traversal.value()); 58 | from_traversal.getTraverserSet().reinitialize( 59 | std::move(std::get<0>(*it)), 60 | std::move(std::get<1>(*it)), 61 | std::move(std::get<2>(*it)) 62 | ); 63 | 64 | from_vertex = std::any_cast(from_traversal.next()); 65 | } 66 | 67 | if(!this->in_vertex_traversal) { 68 | if(used_current_traverser) throw std::runtime_error("No from/to step was provided."); 69 | 70 | try { 71 | to_vertex = std::any_cast(std::get<0>(*it).get(0)); 72 | } catch(std::bad_any_cast& exc) { throw std::runtime_error("Attempted to add an edge to something that is not a Vertex!"); } 73 | catch(std::out_of_range& exr) { throw std::runtime_error("Attempted to add an edge but incoming traversal was empty!"); } 74 | } else { 75 | GraphTraversal to_traversal(src, in_vertex_traversal.value()); 76 | to_traversal.getTraverserSet().reinitialize( 77 | std::move(std::get<0>(*it)), 78 | std::move(std::get<1>(*it)), 79 | std::move(std::get<2>(*it)) 80 | ); 81 | 82 | to_vertex = std::any_cast(to_traversal.next()); 83 | } 84 | 85 | added_edges.push_back( 86 | graph->add_edge(from_vertex, to_vertex, label).id 87 | ); 88 | } 89 | 90 | traversers.advance([&added_edges, graph](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 91 | auto m_edges = maelstrom::make_vector_from_anys( 92 | traverser_data.get_mem_type(), 93 | added_edges 94 | ); 95 | m_edges = m_edges.astype(graph->get_edge_dtype()); 96 | 97 | 98 | return std::make_pair( 99 | m_edges, 100 | maelstrom::vector() 101 | ); 102 | }); 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /step/controlflow/RepeatStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/controlflow/RepeatStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | 4 | namespace gremlinxx { 5 | 6 | RepeatStep::RepeatStep(GraphTraversal actionTraversal) 7 | : TraversalStep(true, MAP, REPEAT_STEP) { 8 | this->actionTraversal = actionTraversal; 9 | } 10 | 11 | std::string RepeatStep::getInfo() { 12 | std::string info = "RepeatStep{" + this->actionTraversal.info() ; 13 | //if(this->emitTraversal != nullptr) info += ",\nemit = " + emitTraversal->explain(); 14 | //if(this->untilTraversal != nullptr) info += ",\nuntil = " + untilTraversal->explain(); 15 | info += "}"; 16 | 17 | return info; 18 | } 19 | 20 | // TODO for now "until" is checked only at the end, but per TinkerPop3 standard it can be either pre- or post-loop. 21 | // TODO emit is also pre- or post-loop; right now it is pre-loop. 22 | void RepeatStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 23 | GraphTraversalSource* src = trv->getTraversalSource(); 24 | GraphTraversal emissionTraversal(src); 25 | 26 | bool cont = true; 27 | size_t loops = 0; 28 | do { 29 | if(this->times && loops >= this->times.value()) break; 30 | 31 | // Build and evaulate the until traversal 32 | if(this->untilTraversal) { 33 | GraphTraversal currentUntilTraversal(src, untilTraversal.value()); 34 | currentUntilTraversal.setTraversalProperty(LOOPS_TRAVERSAL_PROPERTY, loops); 35 | currentUntilTraversal.setInitialTraversers(traversers); 36 | cont = currentUntilTraversal.hasNext(); 37 | } 38 | 39 | // Build and evalulate the emit traversals 40 | if(this->emitTraversal && !traversers.empty()) { 41 | // TODO allow using streams to do this (somehow) 42 | gremlinxx::traversal::TraverserSet& emitted_traversers = emissionTraversal.getTraverserSet(); 43 | 44 | auto unpacked_traversers = traversers.unpack(); 45 | for(size_t i = 0; i < unpacked_traversers.size(); ++i) { 46 | auto& t = unpacked_traversers[i]; 47 | GraphTraversal currentEmitTraversal(src, emitTraversal.value()); 48 | currentEmitTraversal.setTraversalProperty(LOOPS_TRAVERSAL_PROPERTY, loops); 49 | 50 | // Should copy the data in t, not move it 51 | std::unordered_map temp_se; 52 | for(auto& p : std::get<1>(t)) temp_se[p.first] = maelstrom::vector(p.second); 53 | 54 | gremlinxx::traversal::PathInfo temp_path_info; 55 | temp_path_info.paths = std::vector(std::get<2>(t).paths.begin(), std::get<2>(t).paths.end()); 56 | temp_path_info.path_lengths = maelstrom::vector(std::get<2>(t).path_lengths); 57 | 58 | currentEmitTraversal.getTraverserSet().reinitialize( 59 | std::get<0>(t), //should not be a move! 60 | std::move(temp_se), 61 | std::move(temp_path_info) 62 | ); 63 | 64 | if(currentEmitTraversal.hasNext()) { 65 | GraphTraversal bogusEmissionTraversal(src); 66 | // Should move the data in t, not copy it 67 | bogusEmissionTraversal.getTraverserSet().reinitialize( 68 | std::move(std::get<0>(t)), 69 | std::move(std::get<1>(t)), 70 | std::move(std::get<2>(t)) 71 | ); 72 | 73 | emitted_traversers.addTraversers(bogusEmissionTraversal.getTraverserSet()); 74 | } 75 | } 76 | 77 | } 78 | 79 | // Build and evaulate the action traversal 80 | GraphTraversal currentActionTraversal(src, actionTraversal); 81 | currentActionTraversal.setTraversalProperty(LOOPS_TRAVERSAL_PROPERTY, loops); 82 | currentActionTraversal.setInitialTraversers(traversers); 83 | traversers.clear(); 84 | 85 | currentActionTraversal.iterate(); 86 | if(!currentActionTraversal.getTraverserSet().empty()) { 87 | traversers.addTraversers( 88 | currentActionTraversal.getTraverserSet() 89 | ); 90 | } 91 | 92 | ++loops; 93 | } while(traversers.size() > 0 && cont); 94 | 95 | traversers.addTraversers(emissionTraversal.getTraverserSet()); 96 | emissionTraversal.getTraverserSet().clear(); // not necessary but better to be explicit sometimes 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /step/property/HasStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/property/HasStep.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "traversal/GraphTraversalSource.h" 4 | 5 | #include "structure/Vertex.h" 6 | #include "structure/Graph.h" 7 | 8 | #include "maelstrom/algorithms/intersection.h" 9 | #include "maelstrom/algorithms/filter.h" 10 | #include "maelstrom/algorithms/select.h" 11 | #include "maelstrom/algorithms/arange.h" 12 | 13 | namespace gremlinxx { 14 | 15 | // Initialize the default filter policy 16 | filter_policy_t HasStep::FILTER_POLICY = BY_ENTRY_COUNT; 17 | 18 | HasStep::HasStep(std::string property_key_or_label, P predicate) 19 | : TraversalStep(FILTER, HAS_STEP) { 20 | this->predicates.push_back(std::make_pair( 21 | property_key_or_label, 22 | predicate 23 | )); 24 | } 25 | 26 | void HasStep::join(HasStep* other) { 27 | this->predicates.insert(this->predicates.end(), other->predicates.begin(), other->predicates.end()); 28 | } 29 | 30 | std::string HasStep::getInfo() { 31 | std::stringstream sx; 32 | sx << "HasStep("; 33 | for(auto it = this->predicates.begin(); it != this->predicates.end(); ++it) { 34 | sx << it->first << " " << it->second.getInfo(); 35 | if(it != this->predicates.end() - 1) sx << ", "; 36 | } 37 | sx << ")"; 38 | 39 | return sx.str(); 40 | } 41 | 42 | void HasStep::apply(GraphTraversal* trv, gremlinxx::traversal::TraverserSet& traversers) { 43 | GraphTraversalSource* g = trv->getTraversalSource(); 44 | bool vertex = (traversers.getCurrentDataType() == g->getGraph()->get_vertex_dtype()); 45 | if(!vertex && traversers.getCurrentDataType() != g->getGraph()->get_edge_dtype()) { 46 | throw std::domain_error("Can't get an element map for something other than a vertex or edge"); 47 | } 48 | 49 | if(traversers.empty()) return; 50 | 51 | // sort to pick the property with the lowest number of entries 52 | auto filter_policy = HasStep::FILTER_POLICY; 53 | if(filter_policy != BY_SPECIFIED_ORDER) { 54 | std::sort( 55 | this->predicates.begin(), 56 | this->predicates.end(), 57 | [g, vertex, filter_policy](auto p, auto q){ 58 | const size_t first_size = vertex ? g->getGraph()->get_vertex_property_num_entries(p.first) : g->getGraph()->get_edge_property_num_entries(p.first); 59 | const size_t second_size = vertex ? g->getGraph()->get_vertex_property_num_entries(q.first) : g->getGraph()->get_edge_property_num_entries(q.first); 60 | return (filter_policy == BY_ENTRY_COUNT) ? std::less()(first_size, second_size) : std::greater()(first_size, second_size); 61 | } 62 | ); 63 | } 64 | 65 | auto preds = this->predicates; 66 | traversers.advance([&g, preds, vertex](auto& traverser_data, auto& traverser_se, auto& traverser_path_info){ 67 | auto ix_found = maelstrom::arange(traverser_data.get_mem_type(), traverser_data.size()); 68 | 69 | for(auto& pred : preds) { 70 | maelstrom::vector found_values; 71 | maelstrom::vector ix_found_found; 72 | auto search_keys = maelstrom::select(traverser_data, ix_found); 73 | if(vertex) { 74 | std::tie( 75 | found_values, 76 | ix_found_found 77 | ) = g->getGraph()->get_vertex_properties(pred.first, search_keys, pred.second.operand.has_value()); 78 | } else { 79 | std::tie( 80 | found_values, 81 | ix_found_found 82 | ) = g->getGraph()->get_edge_properties(pred.first, search_keys, pred.second.operand.has_value()); 83 | } 84 | 85 | if(pred.second.operand.has_value()) { 86 | // filter down found_vertices using found_values 87 | auto ix_matches = maelstrom::filter( 88 | found_values, 89 | pred.second.comparison, 90 | pred.second.operand 91 | ); 92 | found_values.clear(); 93 | 94 | ix_found_found = maelstrom::select(ix_found_found, ix_matches); 95 | ix_found = maelstrom::select(ix_found, ix_found_found); 96 | } 97 | } 98 | 99 | auto found_elements = maelstrom::select(traverser_data, ix_found); 100 | return std::make_pair( 101 | std::move(found_elements), 102 | std::move(ix_found) 103 | ); 104 | }); 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /traversal/SyntaxHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO split these steps into their own files and remove this header 4 | 5 | namespace gremlinxx { 6 | 7 | inline GraphTraversal addE(std::string label) { return GraphTraversal().addE(label); } 8 | inline GraphTraversal addV(std::string label) { return GraphTraversal().addV(label); } 9 | inline GraphTraversal addV() { return GraphTraversal().addV(); } 10 | inline GraphTraversal property(std::string property_key, std::any value) { return GraphTraversal().property(property_key, value); } 11 | inline GraphTraversal as(std::string sideEffectLabel) { return GraphTraversal().as(sideEffectLabel); } 12 | inline GraphTraversal by(std::any arg) { return GraphTraversal().by(arg); } 13 | inline GraphTraversal cap(std::string sideEffectLabel) { return GraphTraversal().cap(sideEffectLabel); } 14 | inline GraphTraversal coalesce(std::vector traversals) { return GraphTraversal().coalesce(std::move(traversals)); } 15 | inline GraphTraversal count() { return GraphTraversal().count(); } 16 | inline GraphTraversal dedup() { return GraphTraversal().dedup(); } 17 | inline GraphTraversal emit() { return GraphTraversal().emit(); } 18 | inline GraphTraversal emit(GraphTraversal emitTraversal) { return GraphTraversal().emit(emitTraversal); } 19 | inline GraphTraversal from(std::string sideEffectLabel) { return GraphTraversal().from(sideEffectLabel); } 20 | inline GraphTraversal from(Vertex fromVertex) { return GraphTraversal().from(fromVertex); } 21 | inline GraphTraversal V() { return GraphTraversal().V(); } 22 | inline GraphTraversal V(Vertex vertex) { return GraphTraversal().V(vertex); } 23 | inline GraphTraversal V(std::vector vertices) { return GraphTraversal().V(vertices); } 24 | inline GraphTraversal V(std::any v_id) { return GraphTraversal().V(v_id); } 25 | inline GraphTraversal groupCount() { return GraphTraversal().groupCount(); } 26 | inline GraphTraversal has(std::string key, P pred) { return GraphTraversal().has(key, pred); } 27 | inline GraphTraversal has(std::string key, std::any value) { return GraphTraversal().has(key, value); } 28 | inline GraphTraversal has(std::string key) { return GraphTraversal().has(key); } 29 | inline GraphTraversal id() { return GraphTraversal().id(); } 30 | inline GraphTraversal identity() { return GraphTraversal().identity(); } 31 | inline GraphTraversal inject(std::vector objects) { return GraphTraversal().inject(objects); } 32 | inline GraphTraversal is(std::any val) { return GraphTraversal().is(val); } 33 | inline GraphTraversal is(P predicate) { return GraphTraversal().is(predicate); } 34 | inline GraphTraversal limit(uint64_t the_limit) { return GraphTraversal().limit(the_limit); } 35 | inline GraphTraversal loops() { return GraphTraversal().loops(); } 36 | inline GraphTraversal min() { return GraphTraversal().min(); } 37 | inline GraphTraversal order() { return GraphTraversal().order(); } 38 | inline GraphTraversal repeat(GraphTraversal repeatTraversal) { return GraphTraversal().repeat(repeatTraversal); } 39 | inline GraphTraversal select(std::string sideEffectLabel) { return GraphTraversal().select(sideEffectLabel); } 40 | inline GraphTraversal subgraph(std::string sideEffectLabel) { return GraphTraversal().subgraph(sideEffectLabel); } 41 | inline GraphTraversal to(std::string sideEffectLabel) { return GraphTraversal().to(sideEffectLabel); } 42 | inline GraphTraversal to(Vertex toVertex) { return GraphTraversal().to(toVertex); } 43 | inline GraphTraversal _union(std::vector unionTraversals) { return GraphTraversal()._union(std::move(unionTraversals)); } 44 | inline GraphTraversal until(GraphTraversal untilTraversal) { return GraphTraversal().until(untilTraversal); } 45 | inline GraphTraversal elementMap(std::vector labels) { return GraphTraversal().elementMap(labels); } 46 | inline GraphTraversal values(std::vector labels) { return GraphTraversal().values(labels); } 47 | inline GraphTraversal values(std::string label) { return GraphTraversal().values(label); } 48 | inline GraphTraversal both() { return GraphTraversal().both(); } 49 | inline GraphTraversal both(std::vector labels) { return GraphTraversal().both(labels); } 50 | inline GraphTraversal bothE() { return GraphTraversal().bothE(); } 51 | inline GraphTraversal bothE(std::vector labels) { return GraphTraversal().bothE(labels); } 52 | inline GraphTraversal out() { return GraphTraversal().out(); } 53 | inline GraphTraversal out(std::vector labels) { return GraphTraversal().out(labels); } 54 | inline GraphTraversal in() { return GraphTraversal().in(); } 55 | inline GraphTraversal in(std::vector labels) { return GraphTraversal().in(labels); } 56 | inline GraphTraversal outE() { return GraphTraversal().outE(); } 57 | inline GraphTraversal outE(std::vector labels) { return GraphTraversal().outE(labels); } 58 | inline GraphTraversal inE() { return GraphTraversal().inE(); } 59 | inline GraphTraversal inE(std::vector labels) { return GraphTraversal().inE(labels); } 60 | inline GraphTraversal times(size_t times) { return GraphTraversal().times(times); } 61 | inline GraphTraversal where(std::string label, P predicate) { return GraphTraversal().where(label, predicate); } 62 | 63 | } -------------------------------------------------------------------------------- /traversal/PathInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "traversal/PathInfo.h" 2 | #include "maelstrom/algorithms/remove_if.h" 3 | #include "maelstrom/algorithms/select.h" 4 | #include "maelstrom/algorithms/increment.h" 5 | #include "maelstrom/algorithms/set.h" 6 | #include "maelstrom/algorithms/unpack.h" 7 | 8 | namespace gremlinxx { 9 | namespace traversal { 10 | 11 | void PathInfo::advance(maelstrom::vector prev_traverser_data, maelstrom::vector origin) { 12 | if(prev_traverser_data.empty()) { 13 | this->paths.clear(); 14 | this->path_lengths.clear(); 15 | } 16 | 17 | bool empty_start = false; 18 | if(paths.empty()) { 19 | empty_start = true; 20 | } else if(prev_traverser_data.size() != paths[0].size()) { 21 | throw std::runtime_error("next vector size must match path size"); 22 | } 23 | 24 | this->paths.push_back(std::move(prev_traverser_data)); 25 | 26 | // Step 1: update path lengths 27 | if(!empty_start) { 28 | if(!origin.empty()) { 29 | maelstrom::vector new_path_lengths = maelstrom::select( 30 | this->path_lengths, 31 | origin 32 | ); 33 | 34 | maelstrom::increment(new_path_lengths, static_cast(1)); 35 | this->path_lengths.clear(); 36 | this->path_lengths = std::move(new_path_lengths); 37 | } else { 38 | maelstrom::increment(this->path_lengths, static_cast(1)); 39 | } 40 | } else { 41 | size_t starting_size = origin.empty() ? prev_traverser_data.size() : origin.size(); 42 | this->path_lengths.resize(starting_size); 43 | maelstrom::set( 44 | this->path_lengths, 45 | 0, 46 | this->path_lengths.size(), 47 | static_cast(1) 48 | ); 49 | } 50 | 51 | if(origin.empty()) return; 52 | 53 | // Step 2: perform selection 54 | for(size_t k = 0; k < this->paths.size(); ++k) { 55 | maelstrom::vector selected_traversers = maelstrom::select( 56 | this->paths[k], 57 | origin 58 | ); 59 | 60 | this->paths[k].clear(); 61 | this->paths[k] = std::move(selected_traversers); 62 | } 63 | 64 | } 65 | 66 | std::vector PathInfo::unpack() { 67 | std::vector> unpacked_paths; 68 | unpacked_paths.resize(this->path_lengths.size()); 69 | for(size_t k = 0; k < this->paths.size(); ++k) { 70 | unpacked_paths[k] = maelstrom::unpack(this->paths[k]); 71 | } 72 | 73 | auto unpacked_path_lengths = maelstrom::unpack(this->path_lengths); 74 | 75 | std::vector unpacked_path_info; 76 | unpacked_path_info.resize(this->path_lengths.size()); 77 | for(size_t k = 0; k < this->path_lengths.size(); ++k) { 78 | for(size_t p = 0; p < this->paths.size(); ++p) { 79 | unpacked_path_info[k].paths[p] = std::move(unpacked_paths[p][k]); 80 | } 81 | unpacked_path_info[k].path_lengths = std::move(unpacked_path_lengths[k]); 82 | } 83 | 84 | return unpacked_path_info; 85 | } 86 | 87 | void PathInfo::add_paths(PathInfo& other_path_info) { 88 | if(other_path_info.paths.size() == 0) return; 89 | 90 | size_t sz = (this->paths.size() > 0) ? this->paths[0].size() : 0; 91 | size_t other_sz = other_path_info.paths[0].size(); 92 | 93 | if(this->paths.size() < other_path_info.paths.size()) { 94 | size_t d = other_path_info.paths.size() - sz; 95 | 96 | for(size_t k = 0; k < d; ++k) { 97 | auto dummy_path = maelstrom::make_vector_like(other_path_info.paths[k]); 98 | dummy_path.resize(sz); 99 | this->paths.insert( 100 | this->paths.begin() + k, 101 | std::move(dummy_path) 102 | ); 103 | } 104 | } 105 | 106 | // add from back to front even though k is being incremented 107 | for(size_t k = 0; k < other_path_info.paths.size(); ++k) { 108 | maelstrom::vector& current_path = this->paths[this->paths.size() - k - 1]; 109 | maelstrom::vector& other_current_path = other_path_info.paths[other_path_info.paths.size() - k - 1]; 110 | 111 | if(current_path.get_dtype() != other_current_path.get_dtype()) { 112 | throw std::runtime_error("Can't merge paths with different data types!"); 113 | } 114 | 115 | current_path.insert( 116 | current_path.size(), 117 | other_current_path 118 | ); 119 | } 120 | 121 | if(other_path_info.paths.size() < this->paths.size()) { 122 | size_t d = this->paths.size() - other_path_info.paths.size(); 123 | for(size_t k = 0; k < d; ++k) { 124 | this->paths[k].resize(sz + other_sz); 125 | } 126 | } 127 | 128 | this->path_lengths.insert( 129 | this->path_lengths.size(), 130 | other_path_info.path_lengths 131 | ); 132 | 133 | } 134 | 135 | void PathInfo::clear() { 136 | this->path_lengths.clear(); 137 | this->paths.clear(); 138 | } 139 | 140 | } 141 | } -------------------------------------------------------------------------------- /structure/Graph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "structure/Edge.h" 7 | #include "structure/Vertex.h" 8 | #include "maelstrom/storage/datatype.h" 9 | #include "maelstrom/containers/vector.h" 10 | 11 | namespace gremlinxx { 12 | 13 | class GraphTraversalSource; 14 | 15 | class Graph { 16 | public: 17 | Graph(){} 18 | 19 | virtual GraphTraversalSource* traversal() = 0; 20 | 21 | /** 22 | * Returns a copy of this Graph's vertices. 23 | **/ 24 | virtual std::vector vertices() = 0; 25 | 26 | /* 27 | Returns the number of vertices in this Graph. 28 | */ 29 | virtual size_t num_vertices() = 0; 30 | 31 | /** 32 | * Returns a copy of this Graph's edges. 33 | **/ 34 | virtual std::vector edges() = 0; 35 | 36 | /* 37 | Returns the number of edges in this Graph. 38 | */ 39 | virtual size_t num_edges() = 0; 40 | 41 | // Vertex labels are optional, implementer should check if the label is empty and react appropriately 42 | virtual Vertex add_vertex(std::string label="") = 0; 43 | virtual maelstrom::vector add_vertices(size_t n_new_vertices, std::string label="") = 0; 44 | 45 | // Edge labels are always required 46 | virtual Edge add_edge(Vertex from_vertex, Vertex to_vertex, std::string label) = 0; 47 | virtual maelstrom::vector add_edges(maelstrom::vector& from_vertices, maelstrom::vector& to_vertices, std::string label) = 0; 48 | 49 | // Traverses vertices to their neighbors. Returns the resulting vertices (first element) and originating index (second element). 50 | virtual std::pair V(maelstrom::vector& current_vertices, std::vector& labels, Direction direction) = 0; 51 | 52 | // Traverses vertices to their edges. Returns the resulting edges (first element) and originating index (second element). 53 | virtual std::pair E(maelstrom::vector& current_vertices, std::vector& labels, Direction direction) = 0; 54 | 55 | // Traverses edges to their vertices. Returns the resulting vertices (first element) and originating index (second element). 56 | virtual std::pair toV(maelstrom::vector& current_edges, Direction direction) = 0; 57 | 58 | // Returns the degree of the given vertices (first element) and originating index (second element). Has a default implementation of calling V and doing a group count. 59 | virtual std::pair degree(maelstrom::vector& current_vertices, std::vector& labels, Direction direction); 60 | 61 | // Constructs an independent edge-induced subgraph from the given edges. 62 | virtual std::shared_ptr subgraph(maelstrom::vector& edges) = 0; 63 | 64 | /* 65 | Sets the vertex properties of the given vertices to the given values. 66 | */ 67 | virtual void set_vertex_properties(std::string property_name, maelstrom::vector& vertices, maelstrom::vector& property_values) = 0; 68 | 69 | /* 70 | Gets the vertex properties of the given vertices. 71 | Returns a pair where the first vector consists of the property values 72 | and the second vector consists of the originating indices. 73 | 74 | If return_values is true, the values (first element in pair) are returned. 75 | If return_values is false, an empty vector is returned in place of the values. 76 | */ 77 | virtual std::pair get_vertex_properties(std::string property_name, maelstrom::vector& vertices, bool return_values=true) = 0; 78 | 79 | virtual std::vector get_vertex_property_names() = 0; 80 | 81 | /* 82 | Returns the number of vertices that have the given property. 83 | */ 84 | virtual size_t get_vertex_property_num_entries(std::string property_name) = 0; 85 | 86 | /* 87 | Returns the number of edges that have the given property. 88 | */ 89 | virtual size_t get_edge_property_num_entries(std::string property_name) = 0; 90 | 91 | /* 92 | Sets the edge properties of the given edges to the given values. 93 | */ 94 | virtual void set_edge_properties(std::string property_name, maelstrom::vector& edges, maelstrom::vector& property_values) = 0; 95 | 96 | /* 97 | Gets the edge properties of the given edges. 98 | Returns a pair where the first vector consists of the property values 99 | and the second vector consists of the originating indices. 100 | 101 | If return_values is true, the values (first element in pair) are returned. 102 | If return_values is false, an empty vector is returned in place of the values. 103 | */ 104 | virtual std::pair get_edge_properties(std::string property_name, maelstrom::vector& edges, bool return_values=true) = 0; 105 | 106 | virtual std::vector get_edge_property_names() = 0; 107 | 108 | virtual maelstrom::vector get_vertex_labels(maelstrom::vector& vertices) = 0; 109 | virtual maelstrom::vector get_edge_labels(maelstrom::vector& edges) = 0; 110 | 111 | /* 112 | Sets the embedding of the specified vertices. An embedding is a (# vertices) x (embedding dim) tensor. 113 | If there is no embedding with the given name, a new embedding is automatically created and populated 114 | with the default value for unspecified vertices. 115 | */ 116 | virtual void set_vertex_embeddings(std::string emb_name, maelstrom::vector& vertices, maelstrom::vector& embeddings, std::any default_val=0) = 0; 117 | 118 | /* 119 | Sets the embeddings of the specified contiguous chunk of vertices (from v_start, inclusive to v_end, inclusive). 120 | */ 121 | virtual void set_vertex_embeddings(std::string emb_name, size_t v_start, size_t v_end, maelstrom::vector& embeddings, std::any default_value = 0) = 0; 122 | 123 | /* 124 | Returns the embedding with the given name, if it exists. Throws an error if it does not exist. 125 | */ 126 | virtual maelstrom::vector get_vertex_embeddings(std::string emb_name, maelstrom::vector& vertices) = 0; 127 | 128 | virtual maelstrom::dtype_t get_vertex_dtype() = 0; 129 | virtual maelstrom::dtype_t get_edge_dtype() = 0; 130 | 131 | }; 132 | 133 | } 134 | 135 | #include "traversal/GraphTraversalSource.h" -------------------------------------------------------------------------------- /traversal/GraphTraversalSource.cpp: -------------------------------------------------------------------------------- 1 | #include "traversal/GraphTraversalSource.h" 2 | #include "traversal/GraphTraversal.h" 3 | #include "strategy/TraversalStrategy.h" 4 | #include "structure/Graph.h" 5 | #include "structure/Vertex.h" 6 | #include "structure/Edge.h" 7 | #include "strategy/RepeatStepCompletionStrategy.h" 8 | #include "strategy/RepeatUnrollStrategy.h" 9 | #include "strategy/ByModulatingStrategy.h" 10 | #include "strategy/FromToModulatingStrategy.h" 11 | #include "strategy/LimitSupportingStrategy.h" 12 | #include "strategy/NoOpRemovalStrategy.h" 13 | #include "strategy/SubgraphStepCompletionStrategy.h" 14 | #include "strategy/HasJoinStrategy.h" 15 | #include "strategy/BasicPatternExtractionStrategy.h" 16 | 17 | #include "traversal/BasicTraverserSet.h" 18 | #include "step/graph/VStep.h" 19 | #include "step/vertex/AddVertexStartStep.h" 20 | #include "step/edge/AddEdgeStartStep.h" 21 | #include "step/controlflow/InjectStep.h" 22 | 23 | 24 | namespace gremlinxx { 25 | 26 | GraphTraversalSource::GraphTraversalSource(Graph* gr) { 27 | graph = gr; 28 | this->withStrategy(RepeatStepCompletionStrategy); 29 | this->withStrategy(RepeatUnrollStrategy); 30 | this->withStrategy(ByModulatingStrategy); 31 | this->withStrategy(FromToModulatingStrategy); 32 | this->withStrategy(HasJoinStrategy); 33 | this->withStrategy(LimitSupportingStrategy); 34 | this->withStrategy(NoOpRemovalStrategy); 35 | this->withStrategy(BasicPatternExtractionStrategy); 36 | this->withStrategy(SubgraphStepCompletionStrategy); 37 | 38 | this->withTypeRegistration(std::type_index(typeid(uint64_t)), maelstrom::uint64); 39 | this->withTypeRegistration(std::type_index(typeid(uint32_t)), maelstrom::uint32); 40 | this->withTypeRegistration(std::type_index(typeid(uint8_t)), maelstrom::uint8); 41 | this->withTypeRegistration(std::type_index(typeid(int64_t)), maelstrom::int64); 42 | this->withTypeRegistration(std::type_index(typeid(int32_t)), maelstrom::int32); 43 | this->withTypeRegistration(std::type_index(typeid(int8_t)), maelstrom::int8); 44 | this->withTypeRegistration(std::type_index(typeid(double)), maelstrom::float64); 45 | this->withTypeRegistration(std::type_index(typeid(float)), maelstrom::float32); 46 | 47 | this->withTypeRegistration(std::type_index(typeid(Vertex)), graph->get_vertex_dtype()); 48 | this->withTypeRegistration(std::type_index(typeid(Edge)), graph->get_edge_dtype()); 49 | } 50 | 51 | GraphTraversalSource* GraphTraversalSource::withStrategy(TraversalStrategy strategy) { 52 | this->strategies.push_back(strategy); 53 | return this; 54 | } 55 | 56 | GraphTraversalSource* GraphTraversalSource::withoutStrategy(TraversalStrategy strategy) { 57 | auto it = std::find_if( 58 | this->strategies.begin(), 59 | this->strategies.end(), 60 | [&strategy](TraversalStrategy& ts){return (ts.name == strategy.name);} 61 | ); 62 | this->strategies.erase(it); 63 | 64 | return this; 65 | } 66 | 67 | GraphTraversalSource* GraphTraversalSource::withoutStrategies() { 68 | this->strategies.clear(); 69 | return this; 70 | } 71 | 72 | GraphTraversalSource* GraphTraversalSource::withTypeRegistration(std::type_index tid, maelstrom::dtype_t dtype) { 73 | this->type_registrations[tid] = dtype; 74 | return this; 75 | } 76 | 77 | GraphTraversalSource* GraphTraversalSource::withAdminOption(std::string option_name, std::string value) { 78 | this->options[option_name] = value; 79 | return this; 80 | } 81 | 82 | std::string GraphTraversalSource::getOptionValue(std::string option_name) { 83 | auto kv = this->options.find(option_name); 84 | if(kv == this->options.end()) return ""; 85 | else return kv->second; 86 | } 87 | 88 | maelstrom::dtype_t GraphTraversalSource::get_dtype(std::any obj) { 89 | const std::type_index type = std::type_index(obj.type()); 90 | auto z = this->type_registrations.find(type); 91 | if(z == this->type_registrations.end()) { 92 | throw std::runtime_error("Could not find type!"); 93 | } 94 | 95 | return z->second; 96 | } 97 | 98 | std::vector& GraphTraversalSource::getStrategies() { 99 | return this->strategies; 100 | } 101 | 102 | Graph* GraphTraversalSource::getGraph() { 103 | return graph; 104 | } 105 | 106 | gremlinxx::traversal::TraverserSet* GraphTraversalSource::getNewTraverserSet() { 107 | return new gremlinxx::traversal::BasicTraverserSet(); 108 | } 109 | 110 | GraphTraversal GraphTraversalSource::V() { 111 | std::vector empty; 112 | GraphTraversal trv(this); 113 | trv.appendStep(new VStep(empty)); 114 | return trv; 115 | } 116 | 117 | GraphTraversal GraphTraversalSource::V(Vertex v) { 118 | GraphTraversal trv(this); 119 | trv.appendStep(new VStep({v.id})); 120 | return trv; 121 | } 122 | 123 | GraphTraversal GraphTraversalSource::V(std::any v_id) { 124 | GraphTraversal trv(this); 125 | trv.appendStep(new VStep( {v_id})); 126 | return trv; 127 | } 128 | 129 | GraphTraversal GraphTraversalSource::V(maelstrom::vector vertices) { 130 | GraphTraversal trv(this); 131 | 132 | trv.appendStep(new VStep(vertices)); 133 | return trv; 134 | } 135 | 136 | GraphTraversal GraphTraversalSource::V(std::vector vertices) { 137 | GraphTraversal trv(this); 138 | 139 | std::vector v_ids; 140 | v_ids.reserve(vertices.size()); 141 | for(Vertex& v : vertices) v_ids.push_back(v.id); 142 | 143 | trv.appendStep(new VStep(v_ids)); 144 | return trv; 145 | } 146 | 147 | GraphTraversal GraphTraversalSource::V(std::vector v_ids) { 148 | GraphTraversal trv(this); 149 | trv.appendStep(new VStep(v_ids)); 150 | return trv; 151 | } 152 | 153 | GraphTraversal GraphTraversalSource::E() { 154 | // FIXME should call a step with this as the default implementation 155 | return this->V().outE(); 156 | } 157 | 158 | GraphTraversal GraphTraversalSource::addV() { 159 | GraphTraversal trv(this); 160 | trv.appendStep(new AddVertexStartStep()); 161 | return trv; 162 | } 163 | 164 | GraphTraversal GraphTraversalSource::addV(std::string label) { 165 | GraphTraversal trv(this); 166 | trv.appendStep(new AddVertexStartStep(label)); 167 | return trv; 168 | } 169 | 170 | GraphTraversal GraphTraversalSource::addE(std::string label) { 171 | GraphTraversal trv(this); 172 | trv.appendStep(new AddEdgeStartStep(label)); 173 | return trv; 174 | } 175 | 176 | GraphTraversal GraphTraversalSource::inject(std::vector injects) { 177 | GraphTraversal trv(this); 178 | return trv.appendStep(new InjectStep(injects)); 179 | } 180 | 181 | } -------------------------------------------------------------------------------- /traversal/TraverserSet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "traversal/Traverser.h" 3 | #include "traversal/PathInfo.h" 4 | #include "maelstrom/containers/vector.h" 5 | 6 | #include 7 | 8 | namespace gremlinxx { 9 | namespace traversal { 10 | 11 | class TraverserSet { 12 | public: 13 | /* 14 | Enables path persistence (keeping track of each traversers's whole path) 15 | */ 16 | virtual void enable_path_persistence() = 0; 17 | 18 | /* 19 | Disables path persistence (keeping track of each traversers's whole path) 20 | */ 21 | virtual void disable_path_persistence() = 0; 22 | 23 | /* 24 | Realizes all traversers, and returns them. 25 | */ 26 | virtual std::vector toTraversers() = 0; 27 | 28 | /* 29 | Realizes and returns the ith traverser. 30 | */ 31 | virtual Traverser getTraverser(size_t i) = 0; 32 | 33 | /* 34 | Returns a copy of data associated with each traverser in this traverser set. 35 | */ 36 | virtual maelstrom::vector getTraverserData() = 0; 37 | 38 | /* 39 | Returns the datatype of the currently-traversed objects in this traverser set. 40 | */ 41 | virtual maelstrom::dtype_t getCurrentDataType() = 0; 42 | 43 | /* 44 | Returns the memory type of the currently-traversed objects in this traverser set. 45 | */ 46 | virtual maelstrom::storage getCurrentMemType() = 0; 47 | 48 | /* 49 | Gets the data stored in the ith traverser. 50 | */ 51 | virtual std::any getData(size_t i) = 0; 52 | 53 | /* 54 | Returns a copy of the side effects of each traverser in this traverser set. 55 | */ 56 | virtual std::unordered_map getSideEffects() = 0; 57 | 58 | /* 59 | Returns a copy of the paths in this traverser set. 60 | */ 61 | virtual gremlinxx::traversal::PathInfo getPathInfo() = 0; 62 | 63 | /* 64 | Returns the maximum path length in this traverser set. 65 | */ 66 | virtual size_t getPathLength() = 0; 67 | 68 | /* 69 | Reinitializes this traverser set with the given data, side effects, and paths. 70 | Often used in conjunction with unpack(). 71 | */ 72 | virtual void reinitialize(maelstrom::vector new_data, std::unordered_map side_effects, gremlinxx::traversal::PathInfo path_info) = 0; 73 | 74 | /* 75 | Resizes this traverser set. The new size cannot be larger than the current size. 76 | Will delete any extra traversers to fit the new size. 77 | */ 78 | virtual void resize(size_t new_size) = 0; 79 | 80 | /* 81 | Advances the traversers in this traverser set. 82 | The given input function will be passed the traverser data, traverser side effects, and traverser paths. 83 | The input function must return the new traverser data and the originating traversers (in order to preserve paths if enabled). 84 | Modifying side effects is allowed, but the traverser data and paths should not be changed. 85 | 86 | Arguments 87 | --------- 88 | func: std::function 89 | It should take the following parameters: 90 | maelstrom::vector& traverser_data 91 | std::unordered_map& traverser_side_effects 92 | gremlinxx::traversal::PathInfo& paths 93 | 94 | Returns 95 | ------- 96 | std::pair 97 | First element: maelstrom::vector of new traverser data 98 | Second element: maelstrom::vector of originating traversers. 99 | If empty, it's assumed that the index of the new traversers corresponds to the index 100 | of the old traversers (and the sizes must match in that case). 101 | */ 102 | virtual void advance(std::function(maelstrom::vector&, std::unordered_map&, gremlinxx::traversal::PathInfo&)> func) = 0; 103 | 104 | /* 105 | Splits the data, side effects, and paths of this dataset. Each element of the returned vector corresponds to those values 106 | for a single traverser. 107 | */ 108 | virtual std::vector, gremlinxx::traversal::PathInfo>> unpack() = 0; 109 | 110 | /* 111 | Trims the path structure so that it only contains paths from [ix_start, ix_end). 112 | */ 113 | virtual void trim_paths(size_t ix_start, size_t ix_end) = 0; 114 | 115 | /* 116 | Updates the side effects for all traversers for the given key. 117 | */ 118 | virtual void set_side_effects(std::string se_key, maelstrom::vector values) = 0; 119 | 120 | /* 121 | Inserts additional traversers into this traverser set. 122 | */ 123 | virtual void addTraversers(maelstrom::vector& other_traverser_data, std::unordered_map& other_side_effects, gremlinxx::traversal::PathInfo& other_paths) = 0; 124 | 125 | /* 126 | Inserts additional traversers into this traverser set. 127 | The data added is a copy of the data in the provided traverser set. 128 | */ 129 | virtual void addTraversers(TraverserSet& other_traversers) = 0; 130 | 131 | /* 132 | Returns the number of traversers. 133 | */ 134 | virtual size_t size() = 0; 135 | 136 | /* 137 | Clears all traversers. 138 | */ 139 | virtual void clear() = 0; 140 | 141 | /* 142 | Returns true if this traverser set is empty, false otherwise. 143 | */ 144 | virtual bool empty() = 0; 145 | 146 | /* 147 | Erases the ith traverser. 148 | */ 149 | virtual void erase(size_t i) = 0; 150 | }; 151 | 152 | } 153 | } -------------------------------------------------------------------------------- /step/logic/OrderStep.cpp: -------------------------------------------------------------------------------- 1 | #include "step/logic/OrderStep.h" 2 | #include "step/modulate/ReductionStep.h" 3 | #include "traversal/GraphTraversal.h" 4 | #include "traversal/GraphTraversalSource.h" 5 | 6 | #include "maelstrom/algorithms/arange.h" 7 | #include "maelstrom/algorithms/sort.h" 8 | #include "maelstrom/algorithms/select.h" 9 | #include "maelstrom/algorithms/unique.h" 10 | #include "maelstrom/algorithms/reverse.h" 11 | #include "maelstrom/algorithms/randperm.h" 12 | 13 | namespace gremlinxx { 14 | 15 | // This is a barrier step 16 | OrderStep::OrderStep() 17 | : TraversalStep(true, MAP, ORDER_STEP) {} 18 | 19 | 20 | void OrderStep::modulate_by(std::any arg) { 21 | if(arg.type() == typeid(std::pair)) { 22 | auto p = std::any_cast>(arg); 23 | this->order_traversal.emplace(std::any_cast(p.first)); 24 | this->order.emplace(p.second); 25 | } else { 26 | this->order_traversal.emplace(std::any_cast(arg)); 27 | } 28 | } 29 | 30 | void update_reduction_steps(GraphTraversal& order_traversal) { 31 | for(auto& step : order_traversal.getSteps()) { 32 | auto reduction_step = dynamic_cast(step.get()); 33 | if(reduction_step != nullptr) { 34 | reduction_step->set_scope_context(ScopeContext{Scope::local, ORDER_STEP_SIDE_EFFECT_KEY}); 35 | } 36 | } 37 | } 38 | 39 | void apply_with_traversal(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers, GraphTraversal& order_traversal, gremlinxx::Order sort_order) { 40 | update_reduction_steps(order_traversal); 41 | 42 | GraphTraversal exc_trv(traversal->getTraversalSource(), order_traversal); 43 | exc_trv.setInitialTraversers(traversers); 44 | 45 | // Need to initialize the scope context side effect 46 | auto indv = maelstrom::arange(traversers.getCurrentMemType(), traversers.size()); 47 | exc_trv.getTraverserSet().set_side_effects(ORDER_STEP_SIDE_EFFECT_KEY, std::move(indv)); 48 | 49 | // Iterate the traversal 50 | exc_trv.iterate(); 51 | auto& retrieved_traversers = exc_trv.getTraverserSet(); 52 | 53 | auto order_vals = retrieved_traversers.getTraverserData(); 54 | auto output_origin = std::move(retrieved_traversers.getSideEffects()[ORDER_STEP_SIDE_EFFECT_KEY]); 55 | auto sort_ix = maelstrom::sort(output_origin); 56 | output_origin = std::move(maelstrom::select(output_origin, sort_ix)); 57 | order_vals = std::move(maelstrom::select(order_vals, sort_ix)); 58 | sort_ix.clear(); 59 | 60 | traversers.advance([&output_origin, &order_vals, sort_order](auto& data, auto& se, auto& paths){ 61 | // deduplicate (arbitrary deduplication) 62 | // TODO allow users to throw an exception instead of using arbitrary deduplication 63 | auto ix = maelstrom::unique(output_origin, true); 64 | 65 | // The output of unique() should be sorted since the input was sorted 66 | // It should be <= the # of traversers being ordered, or there is a problem. 67 | // Per Gremlin standard, traversers that evaluate to nothing get dropped. 68 | if(ix.size() > data.size()) { 69 | throw std::range_error("More keys than traversers were returned."); 70 | } 71 | 72 | output_origin = std::move(maelstrom::select(output_origin, ix)); 73 | order_vals = std::move(maelstrom::select(order_vals, ix)); 74 | 75 | if(sort_order == SHUFFLE) { 76 | output_origin = maelstrom::randperm(order_vals.get_mem_type(), order_vals.size(), order_vals.size()); 77 | } else { 78 | ix = std::move(maelstrom::sort(order_vals)); 79 | if(sort_order == DESC) { 80 | maelstrom::reverse(ix); 81 | } 82 | order_vals.clear(); 83 | 84 | output_origin = std::move(maelstrom::select(output_origin, ix)); 85 | ix.clear(); 86 | } 87 | 88 | return std::make_pair( 89 | std::move(maelstrom::select(data, output_origin)), 90 | std::move(output_origin) 91 | ); 92 | }); 93 | 94 | // Erase 1 level of paths (this is efficient chopping from the right like we're doing here) 95 | if(traversers.getPathLength() > 0) { 96 | traversers.trim_paths(0, traversers.getPathLength() - 1); 97 | } 98 | } 99 | 100 | void OrderStep::apply(GraphTraversal* traversal, gremlinxx::traversal::TraverserSet& traversers) { 101 | if(this->order_traversal) { 102 | return apply_with_traversal(traversal, traversers, *this->order_traversal, this->order.value_or(ASC)); 103 | } 104 | 105 | auto sort_order = this->order.value_or(ASC); 106 | traversers.advance([sort_order](auto& traverser_data, auto& traverser_se, auto& traverser_paths){ 107 | maelstrom::vector sorted_data(traverser_data); 108 | 109 | maelstrom::vector perm; 110 | if(sort_order == SHUFFLE) { 111 | perm = maelstrom::randperm(sorted_data.get_mem_type(), sorted_data.size(), sorted_data.size()); 112 | sorted_data = std::move(maelstrom::select(sorted_data, perm)); 113 | } else { 114 | perm = std::move(maelstrom::sort(sorted_data)); 115 | if(sort_order == DESC) { 116 | maelstrom::reverse(perm); 117 | maelstrom::reverse(sorted_data); 118 | } 119 | } 120 | 121 | return std::make_pair( 122 | std::move(sorted_data), 123 | std::move(perm) 124 | ); 125 | }); 126 | 127 | // Erase 1 level of paths (this is efficient chopping from the right like we're doing here) 128 | if(traversers.getPathLength() > 0) { 129 | traversers.trim_paths(0, traversers.getPathLength() - 1); 130 | } 131 | 132 | } 133 | 134 | std::string OrderStep::getInfo(GraphTraversal* parent_traversal) { 135 | std::stringstream sx; 136 | sx << "OrderStep("; 137 | 138 | if(this->order_traversal.has_value()) { 139 | sx << this->order_traversal->info() << " -> "; 140 | GraphTraversal dt(parent_traversal->getTraversalSource(), this->order_traversal.value()); 141 | update_reduction_steps(dt); 142 | dt.getInitialTraversal(); 143 | sx << (dt.info()); 144 | if(this->order.has_value()) sx << ", "; 145 | } 146 | 147 | if(this->order.has_value()) { 148 | sx << (this->order.value() == ASC) ? "ascending" : ((this->order.value() == DESC) ? "descending" : "shuffle"); 149 | } 150 | sx << ")"; 151 | 152 | return sx.str(); 153 | } 154 | 155 | std::string OrderStep::getInfo() { 156 | std::stringstream sx; 157 | sx << "OrderStep("; 158 | 159 | if(this->order_traversal.has_value()) { 160 | sx << this->order_traversal->info(); 161 | if(this->order.has_value()) sx << ", "; 162 | } 163 | 164 | if(this->order.has_value()) { 165 | sx << (this->order.value() == ASC) ? "ascending" : ((this->order.value() == DESC) ? "descending" : "shuffle"); 166 | } 167 | sx << ")"; 168 | 169 | return sx.str(); 170 | } 171 | 172 | } --------------------------------------------------------------------------------