/*
* test_incoming.cu — standalone test for GpuAtomTable incoming-set index (Phase 2a).
*
* Slots: a=0 b=1 c=2 (nodes);
* L1=3 (a,b) L2=4 (b,c) L3=5 (a,b,c) L4=6 (L1,c) [link-of-link]
* Expected incoming sets (link-slots referencing each atom):
* a:{3,5} b:{3,4,5} c:{4,5,6} L1:{6} L2:{} L3:{} L4:{}
*
* Build: nvcc -DHAVE_CUDA -I../../.. test_incoming.cu \
* ../../../opencog/persist/gpu/GpuAtomTable.cu -arch=sm_75 -o test_incoming
*/
#include "opencog/persist/gpu/GpuAtomTable.h"
#include <cstdio>
#include <vector>
#include <algorithm>
static int fails = 0;
static void check_set(const char* name, GpuAtomTable* t, uint32_t slot,
std::vector<uint32_t> expect)
{
uint32_t buf[64]; uint32_t count = 0;
cuda_fetch_incoming(t, slot, buf, 64, &count);
std::vector<uint32_t> got(buf, buf + (count < 64 ? count : 64));
std::sort(got.begin(), got.end());
std::sort(expect.begin(), expect.end());
if (got == expect) { printf("PASS incoming(%s) = {", name);
for (auto x : got) printf("%u ", x); printf("}\n"); }
else { fails++; printf("FAIL incoming(%s): got {", name);
for (auto x : got) printf("%u ", x); printf("} expected {");
for (auto x : expect) printf("%u ", x); printf("}\n"); }
}
int main()
{
printf("=== Phase 2a: GpuAtomTable incoming-set index ===\n\n");
GpuAtomTable t;
if (cuda_table_alloc(&t) != 0) { printf("alloc failed\n"); return 1; }
cuda_store_node(&t, 0, 1, "a", 1);
cuda_store_node(&t, 1, 1, "b", 1);
cuda_store_node(&t, 2, 1, "c", 1);
uint32_t L1[] = {0,1}; cuda_store_link(&t, 3, 2, L1, 2);
uint32_t L2[] = {1,2}; cuda_store_link(&t, 4, 2, L2, 2);
uint32_t L3[] = {0,1,2}; cuda_store_link(&t, 5, 2, L3, 3);
uint32_t L4[] = {3,2}; cuda_store_link(&t, 6, 2, L4, 2); // contains link L1
if (cuda_table_build_incoming(&t) != 0) { printf("build_incoming failed\n"); return 1; }
printf("atom_count=%u in_pool_used=%u in_built=%u\n\n",
t.atom_count, t.in_pool_used, t.in_built);
check_set("a", &t, 0, {3,5});
check_set("b", &t, 1, {3,4,5});
check_set("c", &t, 2, {4,5,6});
check_set("L1", &t, 3, {6});
check_set("L2", &t, 4, {});
check_set("L3", &t, 5, {});
check_set("L4", &t, 6, {});
// GPU-resident JOIN: intersect incoming sets entirely on the GPU.
{
uint32_t buf[64]; uint32_t cnt;
auto chk = [&](const char* nm, uint32_t a, uint32_t b, std::vector<uint32_t> exp) {
cnt = 0; cuda_intersect_incoming(&t, a, b, buf, 64, &cnt);
std::vector<uint32_t> got(buf, buf + (cnt < 64 ? cnt : 64));
std::sort(got.begin(), got.end()); std::sort(exp.begin(), exp.end());
if (got == exp) { printf("PASS intersect(%s) = {", nm);
for (auto x : got) printf("%u ", x); printf("}\n"); }
else { fails++; printf("FAIL intersect(%s)\n", nm); }
};
chk("a,b", 0, 1, {3,5}); // links containing both a and b: L1,L3
chk("b,c", 1, 2, {4,5}); // L2,L3
chk("a,c", 0, 2, {5}); // only L3 contains both a and c
}
cuda_table_free(&t);
printf("\n%s\n", fails ? "SOME CHECKS FAILED" :
"ALL CHECKS PASSED - incoming-set index works on the real GpuAtomTable.");
return fails ? 1 : 0;
}