Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/atomdb/AtomDBUtils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "AtomDBUtils.h"

#include "AtomDBSingleton.h"

using namespace atomdb;

AtomDBUtils::AtomDBUtils() {}

AtomDBUtils::~AtomDBUtils() {}

// -------------------------------------------------------------------------------------------------
// Public methods

void AtomDBUtils::reachable_terminal_set(set<string>& output, const string& handle, bool metta_mapping) {
auto atom = AtomDBSingleton::get_instance()->get_atom(handle);
if (atom != nullptr) {
if (Atom::is_node(atom)) {
output.insert(handle);
} else {
AtomDBUtils::reachable_terminal_set_recursive(
output, dynamic_pointer_cast<Link>(atom), metta_mapping);
}
}
}

// -------------------------------------------------------------------------------------------------
// Private methods

void AtomDBUtils::reachable_terminal_set_recursive(set<string>& output,
shared_ptr<Link> link,
bool metta_mapping) {
bool first_target = true;
for (string& target_handle : link->targets) {
auto atom = AtomDBSingleton::get_instance()->get_atom(target_handle);
if (Atom::is_node(atom)) {
if (!(metta_mapping && first_target)) {
output.insert(atom->handle());
}
} else {
AtomDBUtils::reachable_terminal_set_recursive(
output, dynamic_pointer_cast<Link>(atom), metta_mapping);
}
first_target = false;
}
}
42 changes: 42 additions & 0 deletions src/atomdb/AtomDBUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once
#include <memory>
#include <set>
#include <string>

#include "AtomDB.h"

using namespace std;

namespace atomdb {

/**
*
*/
class AtomDBUtils {
public:
AtomDBUtils();
~AtomDBUtils();

private:
static void reachable_terminal_set_recursive(set<string>& output,
shared_ptr<Link> link,
bool metta_mapping);

public:
/**
* The reachable set of a given Link contains any Node in its target list plus any Node
* reachable through the recursive application of this method to the Links in its
* targets list. The reachable set of a Node is the Node itself.
*
* @param output A std::set where output is supposed to be placed.
* @param handle The handle of the starting link. If a Node handle is passed
* instead, the output will be this single handle.
* @param metta_mapping Optional flag to indicate the use of MeTTa mapping. When MeTTa mapping
* is being used, the first element in a expression is not considered to be put in the output.
*/
static void reachable_terminal_set(set<string>& output,
const string& handle,
bool metta_mapping = false);
};

} // namespace atomdb
12 changes: 12 additions & 0 deletions src/atomdb/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ cc_library(
":atomdb",
":atomdb_api_types",
":atomdb_singleton",
":atomdbutils",
"//atomdb/adapterdb:adapterdb_lib",
"//atomdb/inmemorydb:inmemorydb_lib",
"//atomdb/morkdb:morkdb_lib",
Expand All @@ -26,6 +27,17 @@ cc_library(
],
)

cc_library(
name = "atomdbutils",
srcs = ["AtomDBUtils.cc"],
hdrs = ["AtomDBUtils.h"],
includes = ["."],
deps = [
":atomdb",
":atomdb_singleton",
],
)

cc_library(
name = "atomdb_api_types",
hdrs = ["AtomDBAPITypes.h"],
Expand Down
14 changes: 13 additions & 1 deletion src/commons/atoms/Atom.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,23 @@ class Atom : public HandleTrie::TrieValue {
static bool is_node(const Atom& atom) { return atom.arity() == 0; }

/**
* @brief Returns truee iff the passed atom is a Link (or a LinkSchema, which is a wildcard Link).
* @brief Returns true iff the passed atom is a Link (or a LinkSchema, which is a wildcard Link).
* @return truee iff the passed atom is a Node (or a LinkSchema, which is a wildcard Link).
*/
static bool is_link(const Atom& atom) { return atom.arity() > 0; }

/**
* @brief Returns true iff the passed atom is a Node (or a Variable, which is a wildcard Node).
* @return truee iff the passed atom is a Node (or a Variable, which is a wildcard Node).
*/
static bool is_node(shared_ptr<Atom> atom) { return atom->arity() == 0; }

/**
* @brief Returns true iff the passed atom is a Link (or a LinkSchema, which is a wildcard Link).
* @return truee iff the passed atom is a Node (or a LinkSchema, which is a wildcard Link).
*/
static bool is_link(shared_ptr<Atom> atom) { return atom->arity() > 0; }

// ---------------------------------------------------------------------------------------------
// Default implementation for virtual public API

Expand Down
24 changes: 24 additions & 0 deletions src/tests/cpp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,30 @@ cc_test(
],
)

cc_test(
name = "atomdbutils_test",
size = "small",
srcs = ["atomdbutils_test.cc"],
copts = [
"-Iexternal/gtest/googletest/include",
"-Iexternal/gtest/googletest",
],
linkopts = [
"-L/usr/local/lib",
"-lhiredis_cluster",
"-lhiredis",
"-lmongocxx",
"-lbsoncxx",
],
linkstatic = 1,
deps = [
"//atomdb:atomdb_lib",
"//commons/atoms:atoms_lib",
"//tests/cpp/test_commons:test_atomdb_json_config",
"@com_github_google_googletest//:gtest_main",
],
)

cc_test(
name = "remote_atomdb_test",
size = "small",
Expand Down
129 changes: 129 additions & 0 deletions src/tests/cpp/atomdbutils_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "AtomDBUtils.h"

#include <gtest/gtest.h>

#include "AtomDBSingleton.h"
#include "InMemoryDB.h"
#include "TestAtomDBJsonConfig.h"

using namespace atomdb;
using namespace atoms;
using namespace std;

TEST(AtomDBTest, reachable_terminal_set) {
AtomDBSingleton::init(test_atomdb_json_config());
auto db = AtomDBSingleton::get_instance();

auto A = new Node("Symbol", "A");
auto B = new Node("Symbol", "B");
auto C = new Node("Symbol", "C");
auto D = new Node("Symbol", "D");
auto E = new Node("Symbol", "E");
auto F = new Node("Symbol", "F");
auto G = new Node("Symbol", "G");
auto H = new Node("Symbol", "H");
auto I = new Node("Symbol", "I");
auto J = new Node("Symbol", "J");
auto K = new Node("Symbol", "K");
auto NOT_ADDED = new Node("Symbol", "NOT_ADDED");
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 1" << endl;
db->add_nodes({A, B, C, D, E, F, G, H, I, J, K});
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2" << endl;

auto L6 = new Link("Expression", {I->handle(), J->handle(), K->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3" << endl;
db->add_link(L6);
auto L5 = new Link("Expression", {C->handle(), D->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 4" << endl;
db->add_link(L5);
auto L4 = new Link("Expression", {L5->handle(), E->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5" << endl;
db->add_link(L4);
auto L3 = new Link("Expression", {L4->handle(), F->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6" << endl;
db->add_link(L3);
auto L2 = new Link("Expression", {G->handle(), L6->handle(), H->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 7" << endl;
db->add_link(L2);
auto L1 = new Link("Expression", {A->handle(), B->handle(), L3->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 8" << endl;
db->add_link(L1);
auto L0 = new Link("Expression", {L1->handle(), L2->handle()}, true);
cout << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 9" << endl;
db->add_link(L0);

string a = A->handle();
string b = B->handle();
string c = C->handle();
string d = D->handle();
string e = E->handle();
string f = F->handle();
string g = G->handle();
string h = H->handle();
string i = I->handle();
string j = J->handle();
string k = K->handle();

set<string> handles;

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, NOT_ADDED->handle());
EXPECT_EQ(handles.size(), 0);

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, a);
EXPECT_EQ(handles, set({a}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L1->handle());
EXPECT_EQ(handles, set({a, b, c, d, e, f}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L2->handle());
EXPECT_EQ(handles, set({g, h, i, j, k}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L3->handle());
EXPECT_EQ(handles, set({c, d, e, f}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L4->handle());
EXPECT_EQ(handles, set({c, d, e}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L5->handle());
EXPECT_EQ(handles, set({c, d}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L6->handle());
EXPECT_EQ(handles, set({i, j, k}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L0->handle());
EXPECT_EQ(handles, set({a, b, c, d, e, f, g, h, i, j, k}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L6->handle(), true);
EXPECT_EQ(handles, set({j, k}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L2->handle(), true);
EXPECT_EQ(handles, set({h, j, k}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L4->handle(), true);
EXPECT_EQ(handles, set({d, e}));

handles.clear();
AtomDBUtils::reachable_terminal_set(handles, L1->handle(), true);
EXPECT_EQ(handles, set({b, d, e, f}));

db->delete_links({L0->handle(),
L1->handle(),
L2->handle(),
L3->handle(),
L4->handle(),
L5->handle(),
L6->handle()},
true);
}
Loading