/* ---- 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(args[2].addr); int attrIndex = ((CcInt*)(args[3].addr))->GetIntval() - 1; QuadTreeDistributionType* resultQtd = (QuadTreeDistributionType*)(qp->ResultStorage(s)).addr; resultQtd->init(baseQtd); Stream inTupleStream(args[0]); inTupleStream.open(); Tuple* tuple; cout << "Reading Data ..." << endl; double coords[4]; while ((tuple = inTupleStream.request()) != 0) { Rectangle<2>* mbb = static_cast*>(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 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::iterator iter; set outputServerIds; }; ServerIdResult* res = static_cast(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(args[1].addr); set* 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::iterator iter; set outputServerIds; }; ServerIdResult* res = static_cast(local.addr); switch (message) { case OPEN: { string distributionName = static_cast(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(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* 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(); } int qtintersectsLocalVM(Word* args, Word& result, int message, Word& local, Supplier s) { Rectangle<2>* rectA = static_cast*>(args[0].addr); Rectangle<2>* rectB = static_cast*>(args[1].addr); QuadTreeDistributionType* qtd = static_cast(args[2].addr); result = qp->ResultStorage(s); CcBool* res = static_cast(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()); // return bool } int qtintersectsVM(Word* args, Word& result, int message, Word& local, Supplier s) { Rectangle<2>* rectA = static_cast*>(args[0].addr); Rectangle<2>* rectB = static_cast*>(args[1].addr); result = qp->ResultStorage(s); CcBool* res = static_cast(result.addr); if (!rectA->Intersects(*rectB)) { res->Set(true, false); } else { string distributionName = static_cast(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(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()); // return bool } int qtDistinctVM(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); CcBool* res = static_cast(result.addr); // Distribution: string distributionName = static_cast(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(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*>(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; } } }