Transformed dressipi astar into a query.
This commit is contained in:
parent
6e4096d619
commit
266d8ed055
@ -20,7 +20,8 @@ class Db
|
||||
public:
|
||||
using sptr = std::shared_ptr<Db>;
|
||||
|
||||
Db(bool import_snapshot = true);
|
||||
explicit Db(bool import_snapshot = true);
|
||||
Db(const char *name, bool import_snapshot = true);
|
||||
Db(const std::string &name, bool import_snapshot = true);
|
||||
Db(const Db &db) = delete;
|
||||
|
||||
|
@ -4,6 +4,7 @@ project(memgraph_poc)
|
||||
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/poc)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/queries)
|
||||
|
||||
|
||||
add_executable(poc_astar astar.cpp)
|
||||
|
@ -1,3 +1,7 @@
|
||||
#include "queries/astar.cpp"
|
||||
|
||||
#include "barrier/barrier.cpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
@ -28,276 +32,38 @@
|
||||
#include "storage/vertices.hpp"
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
|
||||
const int max_score = 1000000;
|
||||
|
||||
using namespace std;
|
||||
typedef VertexAccessor VertexAccessor;
|
||||
|
||||
void add_scores(Db &db);
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node *parent = {nullptr};
|
||||
type_key_t<TypeGroupVertex, Double> tkey;
|
||||
double cost;
|
||||
int depth = {0};
|
||||
VertexAccessor vacc;
|
||||
|
||||
Node(VertexAccessor vacc, double cost,
|
||||
type_key_t<TypeGroupVertex, Double> tkey)
|
||||
: cost(cost), vacc(vacc), tkey(tkey)
|
||||
{
|
||||
}
|
||||
Node(VertexAccessor vacc, double cost, Node *parent,
|
||||
type_key_t<TypeGroupVertex, Double> tkey)
|
||||
: cost(cost), vacc(vacc), parent(parent), depth(parent->depth + 1),
|
||||
tkey(tkey)
|
||||
{
|
||||
}
|
||||
|
||||
double sum_vertex_score()
|
||||
{
|
||||
auto now = this;
|
||||
double sum = 0;
|
||||
do {
|
||||
sum += (now->vacc.at(tkey).get())->value();
|
||||
now = now->parent;
|
||||
} while (now != nullptr);
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
|
||||
class Score
|
||||
{
|
||||
public:
|
||||
Score() : value(std::numeric_limits<double>::max()) {}
|
||||
Score(double v) : value(v) {}
|
||||
double value;
|
||||
};
|
||||
|
||||
void found_result(Node *res)
|
||||
{
|
||||
double sum = res->sum_vertex_score();
|
||||
|
||||
std::cout << "{score: " << sum << endl;
|
||||
auto bef = res;
|
||||
while (bef != nullptr) {
|
||||
std::cout << " " << *(bef->vacc.operator->()) << endl;
|
||||
bef = bef->parent;
|
||||
}
|
||||
}
|
||||
|
||||
double calc_heuristic_cost_dummy(type_key_t<TypeGroupVertex, Double> tkey,
|
||||
EdgeAccessor &edge, VertexAccessor &vertex)
|
||||
{
|
||||
assert(!vertex.empty());
|
||||
return 1 - vertex.at(tkey).get()->value();
|
||||
}
|
||||
|
||||
typedef bool (*EdgeFilter)(DbAccessor &t, EdgeAccessor &, Node *before);
|
||||
typedef bool (*VertexFilter)(DbAccessor &t, VertexAccessor &, Node *before);
|
||||
|
||||
bool edge_filter_dummy(DbAccessor &t, EdgeAccessor &e, Node *before)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vertex_filter_dummy(DbAccessor &t, VertexAccessor &va, Node *before)
|
||||
{
|
||||
return va.fill();
|
||||
}
|
||||
|
||||
bool vertex_filter_contained_dummy(DbAccessor &t, VertexAccessor &v,
|
||||
Node *before)
|
||||
{
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
auto it = before->vacc.out();
|
||||
for (auto e = it.next(); e.is_present(); e = it.next()) {
|
||||
VertexAccessor va = e.get().to();
|
||||
if (va == v) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (found);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vertex_filter_contained(DbAccessor &t, VertexAccessor &v, Node *before)
|
||||
{
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
} while (v.in_contains(before->vacc));
|
||||
}
|
||||
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.
|
||||
auto a_star(
|
||||
Db &db, int64_t sys_id_start, uint max_depth, EdgeFilter e_filter[],
|
||||
VertexFilter v_filter[],
|
||||
double (*calc_heuristic_cost)(type_key_t<TypeGroupVertex, Double> tkey,
|
||||
EdgeAccessor &edge, VertexAccessor &vertex),
|
||||
int limit)
|
||||
{
|
||||
DbAccessor t(db);
|
||||
type_key_t<TypeGroupVertex, Double> tkey =
|
||||
t.vertex_property_family_get("score")
|
||||
.get(Flags::Double)
|
||||
.type_key<Double>();
|
||||
|
||||
auto best_found = new std::map<Id, Score>[max_depth];
|
||||
|
||||
std::vector<Node *> best;
|
||||
auto cmp = [](Node *left, Node *right) { return left->cost > right->cost; };
|
||||
std::priority_queue<Node *, std::vector<Node *>, decltype(cmp)> queue(cmp);
|
||||
|
||||
auto start_vr = t.vertex_find(sys_id_start);
|
||||
assert(start_vr);
|
||||
start_vr.get().fill();
|
||||
Node *start = new Node(start_vr.take(), 0, tkey);
|
||||
queue.push(start);
|
||||
int count = 0;
|
||||
do {
|
||||
auto now = queue.top();
|
||||
queue.pop();
|
||||
// if(!visited.insert(now)){
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (max_depth <= now->depth) {
|
||||
best.push_back(now);
|
||||
count++;
|
||||
if (count >= limit) {
|
||||
return best;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// { // FOUND FILTER
|
||||
// Score &bef = best_found[now->depth][now->vacc.id()];
|
||||
// if (bef.value <= now->cost) {
|
||||
// continue;
|
||||
// }
|
||||
// bef.value = now->cost;
|
||||
// }
|
||||
|
||||
iter::for_all(now->vacc.out(), [&](auto edge) {
|
||||
if (e_filter[now->depth](t, edge, now)) {
|
||||
VertexAccessor va = edge.to();
|
||||
if (v_filter[now->depth](t, va, now)) {
|
||||
auto cost = calc_heuristic_cost(tkey, edge, va);
|
||||
Node *n = new Node(va, now->cost + cost, now, tkey);
|
||||
queue.push(n);
|
||||
}
|
||||
}
|
||||
});
|
||||
} while (!queue.empty());
|
||||
|
||||
// TODO: GUBI SE MEMORIJA JER SE NODOVI NEBRISU
|
||||
|
||||
t.commit();
|
||||
return best;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
std::srand(time(0));
|
||||
|
||||
auto para = all_arguments(argc, argv);
|
||||
|
||||
Db db("astar");
|
||||
|
||||
EdgeFilter e_filters[] = {&edge_filter_dummy, &edge_filter_dummy,
|
||||
&edge_filter_dummy, &edge_filter_dummy};
|
||||
VertexFilter f_filters[] = {
|
||||
&vertex_filter_contained, &vertex_filter_contained,
|
||||
&vertex_filter_contained, &vertex_filter_contained};
|
||||
|
||||
// CONF
|
||||
std::srand(time(0));
|
||||
auto best_n = 10;
|
||||
auto bench_n = 1000;
|
||||
auto best_print_n = 10;
|
||||
bool pick_best_found =
|
||||
strcmp(get_argument(para, "-p", "true").c_str(), "true") == 0;
|
||||
|
||||
barrier::CodeCPU cp;
|
||||
int bench_n = 1000;
|
||||
double sum = 0;
|
||||
std::vector<Node *> best;
|
||||
for (int i = 0; i < bench_n; i++) {
|
||||
auto start_vertex_index =
|
||||
std::rand() % db.graph.vertices.access().size();
|
||||
|
||||
auto begin = clock();
|
||||
auto found = a_star(db, start_vertex_index, 3, e_filters, f_filters,
|
||||
&calc_heuristic_cost_dummy, best_n);
|
||||
|
||||
code_args_t args;
|
||||
args.push_back(Property(Int64(start_vertex_index), Int64::type));
|
||||
|
||||
cp.run(barrier::trans(db), args, std::cout);
|
||||
|
||||
clock_t end = clock();
|
||||
|
||||
double elapsed_ms = (double(end - begin) / CLOCKS_PER_SEC) * 1000;
|
||||
sum += elapsed_ms;
|
||||
|
||||
if ((best.size() < best_print_n && found.size() > best.size()) ||
|
||||
(pick_best_found && found.size() > 0 &&
|
||||
found.front()->sum_vertex_score() >
|
||||
best.front()->sum_vertex_score())) {
|
||||
best = found;
|
||||
}
|
||||
|
||||
// Just to be safe
|
||||
if (i + 1 == bench_n && best.size() == 0) {
|
||||
bench_n++;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\nSearch for best " << best_n
|
||||
std::cout << "\nSearch for best " << barrier::limit
|
||||
<< " results has runing time of:\n avg: " << sum / bench_n
|
||||
<< " [ms]\n";
|
||||
std::cout << "\nExample of best result:\n";
|
||||
for (int i = 0; i < best_print_n && best.size() > 0; i++) {
|
||||
found_result(best.front());
|
||||
best.erase(best.begin());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Adds property score to all vertices.
|
||||
void add_scores(Db &db)
|
||||
{
|
||||
DbAccessor t(db);
|
||||
|
||||
auto key_score =
|
||||
t.vertex_property_family_get("score").get(Flags::Double).family_key();
|
||||
|
||||
int i = 1;
|
||||
iter::for_all(t.vertex_access(), [&](auto v) {
|
||||
if (v.fill()) {
|
||||
// from Kruno's head :) (could be ALMOST anything else)
|
||||
std::srand(i ^ 0x7482616);
|
||||
v.set(StoredProperty<TypeGroupVertex>(
|
||||
Double((std::rand() % max_score) / (max_score + 0.0)),
|
||||
key_score));
|
||||
i++;
|
||||
}
|
||||
});
|
||||
|
||||
t.commit();
|
||||
}
|
||||
|
143
poc/queries/astar.cpp
Normal file
143
poc/queries/astar.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/i_code_cpu.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
// Dressipi astar query of 4 clicks.
|
||||
|
||||
// BARRIER!
|
||||
namespace barrier
|
||||
{
|
||||
|
||||
using STREAM = std::ostream; // RecordStream<::io::Socket>;
|
||||
|
||||
constexpr size_t max_depth = 3;
|
||||
constexpr size_t limit = 10;
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node *parent = {nullptr};
|
||||
VertexPropertyType<Double> tkey;
|
||||
double cost;
|
||||
int depth = {0};
|
||||
VertexAccessor vacc;
|
||||
|
||||
Node(VertexAccessor vacc, double cost,
|
||||
VertexPropertyType<Double> const &tkey)
|
||||
: cost(cost), vacc(vacc), tkey(tkey)
|
||||
{
|
||||
}
|
||||
Node(VertexAccessor vacc, double cost, Node *parent,
|
||||
VertexPropertyType<Double> const &tkey)
|
||||
: cost(cost), vacc(vacc), parent(parent), depth(parent->depth + 1),
|
||||
tkey(tkey)
|
||||
{
|
||||
}
|
||||
|
||||
double sum_vertex_score()
|
||||
{
|
||||
auto now = this;
|
||||
double sum = 0;
|
||||
do {
|
||||
sum += (now->vacc.at(tkey).get())->value();
|
||||
now = now->parent;
|
||||
} while (now != nullptr);
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
|
||||
bool vertex_filter_contained(DbAccessor &t, VertexAccessor &v, Node *before)
|
||||
{
|
||||
if (v.fill()) {
|
||||
bool found;
|
||||
do {
|
||||
found = false;
|
||||
before = before->parent;
|
||||
if (before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
} while (v.in_contains(before->vacc));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void astar(DbAccessor &t, code_args_t &args, STREAM &stream)
|
||||
{
|
||||
VertexPropertyType<Double> tkey = t.vertex_property_key<Double>("score");
|
||||
|
||||
auto cmp = [](Node *left, Node *right) { return left->cost > right->cost; };
|
||||
std::priority_queue<Node *, std::vector<Node *>, decltype(cmp)> queue(cmp);
|
||||
std::vector<Node *> all_nodes;
|
||||
|
||||
auto start_vr = t.vertex_find(Id(args[0].as<Int64>().value()));
|
||||
if (!start_vr.is_present()) {
|
||||
// stream.write_failure({{}});
|
||||
return;
|
||||
}
|
||||
|
||||
start_vr.get().fill();
|
||||
Node *start = new Node(start_vr.take(), 0, tkey);
|
||||
queue.push(start);
|
||||
all_nodes.push_back(start);
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
auto now = queue.top();
|
||||
queue.pop();
|
||||
|
||||
if (max_depth <= now->depth) {
|
||||
// stream.write_success_empty();
|
||||
// best.push_back(now);
|
||||
count++;
|
||||
if (count >= limit) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
iter::for_all(now->vacc.out(), [&](auto edge) {
|
||||
VertexAccessor va = edge.to();
|
||||
if (vertex_filter_contained(t, va, now)) {
|
||||
auto cost = 1 - va.at(tkey).get()->value();
|
||||
Node *n = new Node(va, now->cost + cost, now, tkey);
|
||||
queue.push(n);
|
||||
all_nodes.push_back(n);
|
||||
}
|
||||
});
|
||||
} while (!queue.empty());
|
||||
|
||||
for (auto n : all_nodes) {
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
|
||||
class CodeCPU : public ICodeCPU<STREAM>
|
||||
{
|
||||
public:
|
||||
bool run(Db &db, code_args_t &args, STREAM &stream) override
|
||||
{
|
||||
DbAccessor t(db);
|
||||
|
||||
astar(t, args, stream);
|
||||
|
||||
return t.commit();
|
||||
}
|
||||
|
||||
~CodeCPU() {}
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" ICodeCPU<barrier::STREAM> *produce()
|
||||
{
|
||||
// BARRIER!
|
||||
return new barrier::CodeCPU();
|
||||
}
|
||||
|
||||
extern "C" void destruct(ICodeCPU<barrier::STREAM> *p) { delete p; }
|
@ -482,6 +482,10 @@ DESTRUCTOR(VertexPropertyKey, PropertyFamilyKey);
|
||||
// ************************* EdgePropertyKey
|
||||
DESTRUCTOR(EdgePropertyKey, PropertyFamilyKey);
|
||||
|
||||
// ************************* VertexPropertyType
|
||||
#define VERTEX_PROPERTY_TYPE(x) template class VertexPropertyType<x>;
|
||||
INSTANTIATE_FOR_PROPERTY(VERTEX_PROPERTY_TYPE)
|
||||
|
||||
// ************************* VertexPropertyFamily
|
||||
OptionPtr<VertexIndex<std::nullptr_t>> VertexPropertyFamily::index()
|
||||
{
|
||||
|
@ -6,7 +6,12 @@
|
||||
|
||||
Db::Db(bool import_snapshot) : Db("default", import_snapshot) {}
|
||||
|
||||
Db::Db(const std::string &name, bool import_snapshot) : name_(name)
|
||||
Db::Db(const std::string &name, bool import_snapshot)
|
||||
: Db(name.c_str(), import_snapshot)
|
||||
{
|
||||
}
|
||||
|
||||
Db::Db(const char *name, bool import_snapshot) : name_(name)
|
||||
{
|
||||
if (import_snapshot) snap_engine.import();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user