Files
secondo/Algebras/KeyValueStore/OperatorsQuadTree.cpp
2026-01-23 17:03:45 +08:00

605 lines
17 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2015,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#include "AlgebraOperators.h"
using namespace std;
namespace KVS {
extern KeyValueStoreIPC* kvsIPC;
/* **********************
* Operator: qtcreatedist
*
*/
ListExpr qtcreatedistTM(ListExpr inargs) {
NList args(inargs);
if (args.length() == 3) {
cout << "1:" << args.second().str() << " - "
<< args.second().isSymbol(CcString::BasicType()) << " - "
<< args.second().isAtom() << " - " << args.second().isEmpty() << " - "
<< args.second().length() << "\n";
cout << "2:" << args.third().str() << "\n";
if (args.third().isSymbol(QuadTreeDistributionType::BasicType())) {
NList stream_desc = args.first();
ListExpr attr_desc = args.second().listExpr();
cout << "stream_desc: " << nl->ToString(stream_desc.listExpr()) << "\n";
if (stream_desc.isList() &&
stream_desc.first().isSymbol(Symbol::STREAM()) &&
(stream_desc.length() == 2) &&
(nl->AtomType(attr_desc) == SymbolType)) {
ListExpr tuple_desc = stream_desc.second().listExpr();
string attr_name = nl->SymbolValue(attr_desc);
cout << "tuple_desc: " << nl->ToString(tuple_desc) << "\n";
if (nl->IsEqual(nl->First(tuple_desc), Tuple::BasicType()) &&
nl->ListLength(tuple_desc) == 2) {
ListExpr attrL = nl->Second(tuple_desc);
if (IsTupleDescription(attrL)) {
int attrIndex;
ListExpr attrType;
attrIndex = FindAttribute(attrL, attr_name, attrType);
if (attrIndex > 0) {
return nl->ThreeElemList(
nl->SymbolAtom(Symbol::APPEND()),
nl->OneElemList(nl->IntAtom(attrIndex)),
nl->SymbolAtom(QuadTreeDistributionType::BasicType()));
} else {
return args.typeError(
"input not as expected: Attribute not found in tuple...");
}
} else {
return args.typeError(
"input not as expected: unexpected stream / tuple format");
}
} else {
return args.typeError(
"input not as expected: unexpected tuple format");
}
}
}
}
return args.typeError("input is not (stream(tuple(y))) x ...");
}
int qtcreatedistVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
QuadTreeDistributionType* baseQtd =
static_cast<QuadTreeDistributionType*>(args[2].addr);
int attrIndex = ((CcInt*)(args[3].addr))->GetIntval() - 1;
QuadTreeDistributionType* resultQtd =
(QuadTreeDistributionType*)(qp->ResultStorage(s)).addr;
resultQtd->init(baseQtd);
Stream<Tuple> inTupleStream(args[0]);
inTupleStream.open();
Tuple* tuple;
cout << "Reading Data ..." << endl;
double coords[4];
while ((tuple = inTupleStream.request()) != 0) {
Rectangle<2>* mbb =
static_cast<Rectangle<2>*>(tuple->GetAttribute(attrIndex));
coords[0] = mbb->MinD(0) * 1000;
coords[1] = mbb->MinD(1) * 1000;
coords[2] = mbb->MaxD(0) * 1000;
coords[3] = mbb->MaxD(1) * 1000;
// initialized?
if (resultQtd->root == 0) {
resultQtd->root =
new QuadNode(mbb->MinD(0), mbb->MinD(1), resultQtd->initialWidth,
resultQtd->initialHeight);
}
// fully inside tree?
resultQtd->expand(coords);
// result server ids
set<int> results;
//
resultQtd->insert(resultQtd->root, coords, &results);
delete tuple;
}
inTupleStream.close();
cout << "Reading Data done ..." << endl;
result.addr = resultQtd;
return 0;
}
/* **********************
* Operator: qtserverid
*
*/
ListExpr qtserveridLocalTM(ListExpr args) {
NList type(args);
if (type !=
NList(Rectangle<2>::BasicType(), QuadTreeDistributionType::BasicType())) {
return NList::typeError("Expecting rect x qtdistribution");
}
return NList(Symbol::STREAM(), CcInt::BasicType()).listExpr();
}
int qtserveridLocalVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
struct ServerIdResult {
set<int>::iterator iter;
set<int> outputServerIds;
};
ServerIdResult* res = static_cast<ServerIdResult*>(local.addr);
switch (message) {
case OPEN: {
cout << "qtserverid: OPEN\n";
delete res;
res = new ServerIdResult;
Rectangle<2>* mbb = (Rectangle<2>*)args[0].addr;
QuadTreeDistributionType* qtd =
static_cast<QuadTreeDistributionType*>(args[1].addr);
set<int>* outputSet = &res->outputServerIds;
double coords[4];
coords[0] = mbb->MinD(0) * 1000;
coords[1] = mbb->MinD(1) * 1000;
coords[2] = mbb->MaxD(0) * 1000;
coords[3] = mbb->MaxD(1) * 1000;
if (qtd->root == 0) {
qtd->root = new QuadNode(mbb->MinD(0), mbb->MinD(1), qtd->initialWidth,
qtd->initialHeight);
}
qtd->expand(coords);
qtd->insert(qtd->root, coords, outputSet);
qp->SetModified(qp->GetSon(s, 1));
if (outputSet->size() > 0) {
res->iter = res->outputServerIds.begin();
local.addr = res;
return 0;
} else {
delete res;
return CANCEL;
}
}
case REQUEST: {
cout << "qtserverid: REQUEST\n";
if (!res) {
return CANCEL;
} else {
if (res->iter != res->outputServerIds.end()) {
CcInt* serverId = new CcInt(true, *(res->iter));
result.addr = serverId;
res->iter++;
return YIELD;
} else {
result.addr = 0;
return CANCEL;
}
}
}
case CLOSE: {
cout << "qtserverid: CLOSE\n";
delete res;
local.addr = 0;
}
return 0;
}
return 0;
}
ListExpr qtserveridTM(ListExpr args) {
if (!nl->HasLength(args, 2)) {
return listutils::typeError(
"Expecting 2 arguments [ " + Rectangle<2>::BasicType() +
" x {distribution, text} = (rect, {distribution, distributionName})].");
}
if (!Rectangle<2>::checkType(nl->First(args))) {
return listutils::typeError(
"1st argument should be rectangle(bbox). [ " +
Rectangle<2>::BasicType() +
" x {distribution, text} = (rect, {distribution, distributionName})].");
}
if (!Distribution::checkType(nl->Second(args)) &&
!FText::checkType(nl->Second(args))) {
return listutils::typeError(
"2nd argument should be distribution OR text. [ " +
Rectangle<2>::BasicType() +
" x {distribution, text} = (rect, {distribution, distributionName})].");
}
ListExpr distname;
if (FText::checkType(nl->Second(args))) {
distname = nl->Second(args);
} else {
distname = nl->TextAtom(nl->SymbolValue(nl->Second(args)));
}
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
nl->OneElemList(distname),
NList(Symbol::STREAM(),
CcInt::BasicType())
.listExpr()); // return int stream
}
int qtserveridVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
struct ServerIdResult {
set<int>::iterator iter;
set<int> outputServerIds;
};
ServerIdResult* res = static_cast<ServerIdResult*>(local.addr);
switch (message) {
case OPEN: {
string distributionName = static_cast<FText*>(args[2].addr)->GetValue();
int distRef = kvsIPC->getDistributionRef(distributionName);
if (distRef < 0) {
ListExpr distributionType = qp->GetSupplierTypeExpr(qp->GetSon(s, 2));
if (!FText::checkType(distributionType)) {
Distribution* dist = static_cast<Distribution*>(args[2].addr);
distRef = kvsIPC->getDistributionRef(distributionName, dist->type,
dist->toBin());
} else {
cout << "Error: No Distribution specified";
return CANCEL;
}
}
cout << "qtserverid: OPEN\n";
delete res;
res = new ServerIdResult;
Rectangle<2>* mbb = (Rectangle<2>*)args[0].addr;
set<int>* outputSet = &res->outputServerIds;
double coords[4];
coords[0] = mbb->MinD(0) * 1000;
coords[1] = mbb->MinD(1) * 1000;
coords[2] = mbb->MaxD(0) * 1000;
coords[3] = mbb->MaxD(1) * 1000;
// TODO: Still specific to QuadTree-Distribution. Should be generalized to
// addMbb / addInt and than have Distributions either have support it or
// return false
kvsIPC->qtDistAdd(distRef, 4, coords, outputSet);
if (outputSet->size() > 0) {
res->iter = res->outputServerIds.begin();
local.addr = res;
return 0;
} else {
delete res;
return CANCEL;
}
}
case REQUEST: {
cout << "qtserverid: REQUEST\n";
if (!res) {
return CANCEL;
} else {
if (res->iter != res->outputServerIds.end()) {
CcInt* serverId = new CcInt(true, *(res->iter));
result.addr = serverId;
res->iter++;
return YIELD;
} else {
result.addr = 0;
return CANCEL;
}
}
}
case CLOSE: {
cout << "qtserverid: CLOSE\n";
delete res;
local.addr = 0;
}
return 0;
}
return 0;
}
/* **********************
* Operator: qtintersectsLocal
*
*/
ListExpr qtintersectsLocalTM(ListExpr args) {
if (!nl->HasLength(args, 3)) {
return listutils::typeError(
"3 arguments expected. [rect x rect x qtdistribution = (rectA, rectB, "
"qtdistribution)].");
}
if (!Rectangle<2>::checkType(nl->First(args))) {
return listutils::typeError(
"1st argument should be rectangle. [rect x rect x qtdistribution = "
"(rectA, rectB, qtdistribution)].");
}
if (!Rectangle<2>::checkType(nl->Second(args))) {
return listutils::typeError(
"2nd argument should be rectangle. [rect x rect x qtdistribution = "
"(rectA, rectB, qtdistribution)].");
}
if (!QuadTreeDistributionType::checkType(nl->Third(args))) {
return listutils::typeError(
"3rd argument should be distribution. [rect x rect x qtdistribution = "
"(rectA, rectB, qtdistribution)].");
}
return listutils::basicSymbol<CcBool>();
}
int qtintersectsLocalVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
Rectangle<2>* rectA = static_cast<Rectangle<2>*>(args[0].addr);
Rectangle<2>* rectB = static_cast<Rectangle<2>*>(args[1].addr);
QuadTreeDistributionType* qtd =
static_cast<QuadTreeDistributionType*>(args[2].addr);
result = qp->ResultStorage(s);
CcBool* res = static_cast<CcBool*>(result.addr);
if (!rectA->Intersects(*rectB)) {
res->Set(true, false);
} else {
double min[2];
double max[2];
min[0] = rectA->MinD(0) * 1000;
min[1] = rectA->MinD(1) * 1000;
max[0] = rectA->MaxD(0) * 1000;
max[1] = rectA->MaxD(1) * 1000;
rectA->Set(rectA->IsDefined(), min, max);
min[0] = rectB->MinD(0) * 1000;
min[1] = rectB->MinD(1) * 1000;
max[0] = rectB->MaxD(0) * 1000;
max[1] = rectB->MaxD(1) * 1000;
rectB->Set(rectB->IsDefined(), min, max);
double interx = std::max(rectA->MinD(0), rectB->MinD(0));
double intery = std::max(rectA->MinD(1), rectB->MinD(1));
res->Set(true, kvsIPC->localId == qtd->pointId(interx, intery));
}
return 0;
}
/* **********************
* Operator: qtintersects
*
*/
ListExpr qtintersectsTM(ListExpr args) {
if (!nl->HasLength(args, 3)) {
return listutils::typeError(
"3 arguments expected. [rect x rect x {distribution,text} = (rectA, "
"rectB, distribution)].");
}
if (!Rectangle<2>::checkType(nl->First(args))) {
return listutils::typeError(
"1st argument should be rectangle. [rect x rect x {distribution,text} "
"= (rectA, rectB, distribution)].");
}
if (!Rectangle<2>::checkType(nl->Second(args))) {
return listutils::typeError(
"2nd argument should be rectangle. [rect x rect x {distribution,text} "
"= (rectA, rectB, distribution)].");
}
if (!Distribution::checkType(nl->Third(args)) &&
!FText::checkType(nl->Third(args))) {
return listutils::typeError(
"3rd argument should be distribution OR text. [rect x rect x "
"{distribution,text} = (rectA, rectB, distribution)].");
}
ListExpr distName = nl->Second(args);
return nl->ThreeElemList(
nl->SymbolAtom(Symbol::APPEND()),
nl->OneElemList(nl->TextAtom(nl->SymbolValue(distName))),
listutils::basicSymbol<CcBool>()); // return bool
}
int qtintersectsVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
Rectangle<2>* rectA = static_cast<Rectangle<2>*>(args[0].addr);
Rectangle<2>* rectB = static_cast<Rectangle<2>*>(args[1].addr);
result = qp->ResultStorage(s);
CcBool* res = static_cast<CcBool*>(result.addr);
if (!rectA->Intersects(*rectB)) {
res->Set(true, false);
} else {
string distributionName = static_cast<FText*>(args[3].addr)->GetValue();
int distRef = kvsIPC->getDistributionRef(distributionName);
if (distRef < 0) {
ListExpr distributionType = qp->GetSupplierTypeExpr(qp->GetSon(s, 2));
if (!FText::checkType(distributionType)) {
Distribution* dist = static_cast<Distribution*>(args[2].addr);
distRef = kvsIPC->getDistributionRef(distributionName, dist->type,
dist->toBin());
} else {
cout << "Error: No Distribution specified";
res->Set(false, false);
return 0;
}
}
double min[2];
double max[2];
min[0] = rectA->MinD(0) * 1000;
min[1] = rectA->MinD(1) * 1000;
max[0] = rectA->MaxD(0) * 1000;
max[1] = rectA->MaxD(1) * 1000;
rectA->Set(rectA->IsDefined(), min, max);
min[0] = rectB->MinD(0) * 1000;
min[1] = rectB->MinD(1) * 1000;
max[0] = rectB->MaxD(0) * 1000;
max[1] = rectB->MaxD(1) * 1000;
rectB->Set(rectB->IsDefined(), min, max);
double interx = std::max(rectA->MinD(0), rectB->MinD(0));
double intery = std::max(rectA->MinD(1), rectB->MinD(1));
res->Set(true,
kvsIPC->localId == kvsIPC->qtDistPointId(distRef, interx, intery));
}
return 0;
}
ListExpr qtDistinctTM(ListExpr args) {
if (!nl->HasLength(args, 2)) {
return listutils::typeError(
"2 arguments expected. [{distribution,text} x rect = (distribution, "
"rect)].");
}
if (!QuadTreeDistributionType::checkType(nl->First(nl->First(args))) &&
!FText::checkType(nl->First(nl->First(args)))) {
return listutils::typeError(
"1st argument should be qtdistribution OR text. [{distribution,text} "
"x rect = (distribution, rect)].");
}
if (!Rectangle<2>::checkType(nl->First(nl->Second(args)))) {
return listutils::typeError(
"2nd argument should be rectangle. [{distribution,text} x rect = "
"(distribution, rect)].");
}
if (!kvsIPC->connected()) {
return listutils::typeError(
"IPC-Connection Error: Not connected to Key-Value Store application.");
}
ListExpr dist_name;
if (FText::checkType(nl->First(nl->First(args)))) {
dist_name = nl->Second(nl->First(args)); // ((text 'distname')...)
} else {
dist_name = nl->TextAtom(nl->SymbolValue(
nl->Second(nl->First(args)))); // ( (..) (distribution distname))
}
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
nl->OneElemList(dist_name),
listutils::basicSymbol<CcBool>()); // return bool
}
int qtDistinctVM(Word* args, Word& result, int message, Word& local,
Supplier s) {
result = qp->ResultStorage(s);
CcBool* res = static_cast<CcBool*>(result.addr);
// Distribution:
string distributionName = static_cast<FText*>(args[2].addr)->GetValue();
int distRef = kvsIPC->getDistributionRef(distributionName);
if (distRef < 0) {
ListExpr distributionType = qp->GetSupplierTypeExpr(qp->GetSon(s, 0));
if (Distribution::checkType(distributionType)) {
Distribution* dist = static_cast<Distribution*>(args[0].addr);
distRef = kvsIPC->getDistributionRef(distributionName, dist->type,
dist->toBin());
} else {
cout << "Error: No Distribution specified";
res->Set(true, false);
return CANCEL;
}
}
if (distRef >= 0) {
Rectangle<2>* rect = static_cast<Rectangle<2>*>(args[1].addr);
double x = rect->MinD(0) * 1000;
double y = rect->MinD(1) * 1000;
res->Set(true, kvsIPC->qtDistinct(distRef, x, y));
return 0;
} else {
res->Set(true, false);
return CANCEL;
}
}
}