#include <fstream> #include <iostream> #include <queue> #include <regex> #include <sstream> #include <string> #include <vector> #include "database/db.hpp" using namespace std; void load_graph_dummy(Db &db); void load_csv(Db &db, char *file_path, char *edge_file_path); class Node { public: Node *parent = {nullptr}; double cost; int depth = {0}; Vertex *vertex; Node(Vertex *va, double cost) : cost(cost), vertex(va) {} Node(Vertex *va, double cost, Node *parent) : cost(cost), vertex(va), parent(parent), depth(parent->depth + 1) { } }; // class Iterator : public Crtp<Iterator> // { // public: // Vertex *operator*() // { // assert(head != nullptr); // return head->vertex; // } // // Vertex *operator->() // { // assert(head != nullptr); // return head->vertex; // } // // Iterator &operator++() // { // assert(head != nullptr); // head = head->parent; // return this->derived(); // } // // Iterator &operator++(int) { return operator++(); } // // friend bool operator==(const Iterator &a, const Iterator &b) // { // return a.head == b.head; // } // // friend bool operator!=(const Iterator &a, const Iterator &b) // { // return !(a == b); // } // // Iterator end() { return Iterator(); } // // private: // Node *head; // }; void found_result(Node *bef) { std::cout << "{score: " << bef->cost << endl; while (bef != nullptr) { std::cout << " " << *(bef->vertex) << endl; bef = bef->parent; } } double calc_heuristic_cost_dummy(Edge *edge, Vertex *vertex) { return 1 - vertex->data.props.at("score").as<Double>().value; } typedef bool (*EdgeFilter)(tx::Transaction &t, Edge *, Node *before); typedef bool (*VertexFilter)(tx::Transaction &t, Vertex *, Node *before); bool edge_filter_dummy(tx::Transaction &t, Edge *e, Node *before) { return true; } bool vertex_filter_dummy(tx::Transaction &t, Vertex *v, Node *before) { return true; } bool vertex_filter_contained_dummy(tx::Transaction &t, Vertex *v, Node *before) { bool found; do { found = false; before = before->parent; if (before == nullptr) { return true; } for (auto e : before->vertex->data.out) { Edge *edge = e->find(t); Vertex *e_v = edge->data.to->find(t); if (e_v == v) { found = true; break; } } } while (found); return false; } // Vertex filter ima max_depth funkcija te edge filter ima max_depth funkcija. // Jedan za svaku dubinu. // Filtri vracaju true ako element zadovoljava uvjete. void a_star(Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[], VertexFilter v_filter[], double (*calc_heuristic_cost)(Edge *edge, Vertex *vertex), int limit) { auto &t = db.tx_engine.begin(); auto cmp = [](Node *left, Node *right) { return left->cost > right->cost; }; std::priority_queue<Node *, std::vector<Node *>, decltype(cmp)> queue(cmp); Node *start = new Node(db.graph.vertices.find(t, sys_id_start).vlist->find(t), 0); queue.push(start); int count = 0; do { auto now = queue.top(); queue.pop(); if (max_depth <= now->depth) { found_result(now); count++; if (count >= limit) { return; } continue; } for (auto e : now->vertex->data.out) { Edge *edge = e->find(t); if (e_filter[now->depth](t, edge, now)) { Vertex *v = edge->data.to->find(t); if (v_filter[now->depth](t, v, now)) { Node *n = new Node( v, now->cost + calc_heuristic_cost(edge, v), now); queue.push(n); } } } } while (!queue.empty()); // GUBI SE MEMORIJA JER SE NODOVI NEBRISU t.commit(); } int main() { Db db; load_csv(db, "neo4j_nodes_export_2000.csv", "neo4j_edges_export_2000.csv"); // // load_graph_dummy(db); // EdgeFilter e_filters[] = {&edge_filter_dummy, &edge_filter_dummy, &edge_filter_dummy, &edge_filter_dummy}; VertexFilter f_filters[] = {&vertex_filter_dummy, &vertex_filter_dummy, &vertex_filter_dummy, &vertex_filter_dummy}; a_star(db, 0, 3, e_filters, f_filters, &calc_heuristic_cost_dummy, 10); return 0; } void split(const string &s, char delim, vector<string> &elems) { stringstream ss(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } } vector<string> split(const string &s, char delim) { vector<string> elems; split(s, delim, elems); return elems; } void load_csv(Db &db, char *file_path, char *edge_file_path) { std::fstream file(file_path); std::fstream e_file(edge_file_path); std::string line; auto &t = db.tx_engine.begin(); int max_score = 1000000; // VERTEX import int start_vertex_id = -1; auto v = [&](auto id, auto labels, auto gar_id, auto cat_id) { if (start_vertex_id < 0) { start_vertex_id = id; } auto vertex_accessor = db.graph.vertices.insert(t); vertex_accessor.property("id", std::make_shared<Int32>(id)); vertex_accessor.property("garment_id", std::make_shared<Int32>(gar_id)); vertex_accessor.property("garment_category_id", std::make_shared<Int32>(cat_id)); std::srand(id ^ 0x7482616); vertex_accessor.property( "score", std::make_shared<Double>((std::rand() % max_score) / (max_score + 0.0))); for (auto l_name : labels) { auto &label = db.graph.label_store.find_or_create(l_name); vertex_accessor.add_label(label); } return vertex_accessor.id(); }; std::getline(file, line); vector<Vertex::Accessor> va; int v_count = 0; while (std::getline(file, line)) { v_count++; line.erase(std::remove(line.begin(), line.end(), '['), line.end()); line.erase(std::remove(line.begin(), line.end(), ']'), line.end()); line.erase(std::remove(line.begin(), line.end(), '\"'), line.end()); line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); auto splited = split(line, ','); vector<string> labels(splited.begin() + 1, splited.begin() + splited.size() - 2); auto id = v(stoi(splited[0]), labels, stoi(splited[splited.size() - 2]), stoi(splited[splited.size() - 1])); assert(va.size() == (uint64_t)id); va.push_back(db.graph.vertices.find(t, id)); } // EDGE IMPORT auto e = [&](auto from, auto type, auto to) { auto v1 = va[from - start_vertex_id]; auto v2 = va[to - start_vertex_id]; auto edge_accessor = db.graph.edges.insert(t); v1.vlist->update(t)->data.out.add(edge_accessor.vlist); v2.vlist->update(t)->data.in.add(edge_accessor.vlist); edge_accessor.from(v1.vlist); edge_accessor.to(v2.vlist); auto &edge_type = db.graph.edge_type_store.find_or_create(type); edge_accessor.edge_type(edge_type); }; std::getline(e_file, line); long count = 0; while (std::getline(e_file, line)) { auto splited = split(line, ','); count++; e(stoi(splited[2]), splited[1], stoi(splited[3])); } cout << "Loaded:\n Vertices: " << v_count << "\n Edges: " << count << endl; t.commit(); } void load_graph_dummy(Db &db) { auto &t = db.tx_engine.begin(); auto v = [&](auto id, auto score) { auto vertex_accessor = db.graph.vertices.insert(t); vertex_accessor.property("id", std::make_shared<Int32>(id)); vertex_accessor.property("score", std::make_shared<Double>(score)); return vertex_accessor.id(); }; Id va[] = { v(0, 0.5), v(1, 1), v(2, 0.3), v(3, 0.15), v(4, 0.8), v(5, 0.8), }; auto e = [&](auto from, auto type, auto to) { auto v1 = db.graph.vertices.find(t, va[from]); auto v2 = db.graph.vertices.find(t, va[to]); auto edge_accessor = db.graph.edges.insert(t); v1.vlist->update(t)->data.out.add(edge_accessor.vlist); v2.vlist->update(t)->data.in.add(edge_accessor.vlist); edge_accessor.from(v1.vlist); edge_accessor.to(v2.vlist); auto &edge_type = db.graph.edge_type_store.find_or_create(type); edge_accessor.edge_type(edge_type); }; e(0, "ok", 3); e(0, "ok", 2); e(0, "ok", 4); e(1, "ok", 3); e(2, "ok", 1); e(2, "ok", 4); e(3, "ok", 4); e(3, "ok", 5); e(4, "ok", 0); e(4, "ok", 1); e(5, "ok", 2); t.commit(); }