4514 lines
143 KiB
C++
4514 lines
143 KiB
C++
|
|
/*
|
||
|
|
----
|
||
|
|
This file is part of SECONDO.
|
||
|
|
|
||
|
|
Copyright (C) 2004, University in Hagen, Department of 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
|
||
|
|
----
|
||
|
|
|
||
|
|
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
|
||
|
|
//[TOC] [\tableofcontents]
|
||
|
|
|
||
|
|
[1] Source File of the Symbolic Trajectory Algebra
|
||
|
|
|
||
|
|
Started March 2012, Fabio Vald\'{e}s
|
||
|
|
|
||
|
|
[TOC]
|
||
|
|
|
||
|
|
\section{Overview}
|
||
|
|
This file contains the operators of the Symbolic Trajectory Algebra.
|
||
|
|
|
||
|
|
\section{Defines and Includes}
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
// #include "Algorithms.h"
|
||
|
|
// #include "RestoreTraj.h"
|
||
|
|
#include "PatternMining.h"
|
||
|
|
|
||
|
|
extern NestedList* nl;
|
||
|
|
extern QueryProcessor *qp;
|
||
|
|
extern AlgebraManager *am;
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
using namespace temporalalgebra;
|
||
|
|
using namespace datetime;
|
||
|
|
|
||
|
|
namespace stj {
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Type Constructors}
|
||
|
|
|
||
|
|
*/
|
||
|
|
GenTC<PatPersistent> patternTC;
|
||
|
|
GenTC<SplSemTraj> splsemtrajTC;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~distance~}
|
||
|
|
|
||
|
|
distance: T x T -> double, where T in {place(s), label(s)}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr distanceTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return NList::typeError("Expecting two arguments.");
|
||
|
|
}
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
ListExpr second = nl->Second(args);
|
||
|
|
if ((Label::checkType(first) && Label::checkType(second)) ||
|
||
|
|
(Labels::checkType(first) && Labels::checkType(second)) ||
|
||
|
|
(Place::checkType(first) && Place::checkType(second)) ||
|
||
|
|
(Places::checkType(first) && Places::checkType(second)) ||
|
||
|
|
(MLabel::checkType(first) && MLabel::checkType(second)) ||
|
||
|
|
(MLabels::checkType(first) && MLabels::checkType(second)) ||
|
||
|
|
(MPlace::checkType(first) && MPlace::checkType(second)) ||
|
||
|
|
(MPlaces::checkType(first) && MPlaces::checkType(second))) {
|
||
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
||
|
|
}
|
||
|
|
return NList::typeError("Expecting T x T, where T in {(m)place(s), "
|
||
|
|
"(m)label(s)}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int distanceSelect(ListExpr args) {
|
||
|
|
if (Label::checkType(nl->First(args))) return 0;
|
||
|
|
if (Labels::checkType(nl->First(args))) return 1;
|
||
|
|
if (Place::checkType(nl->First(args))) return 2;
|
||
|
|
if (Places::checkType(nl->First(args))) return 3;
|
||
|
|
if (MLabel::checkType(nl->First(args))) return 4;
|
||
|
|
if (MLabels::checkType(nl->First(args))) return 5;
|
||
|
|
if (MPlace::checkType(nl->First(args))) return 6;
|
||
|
|
if (MPlaces::checkType(nl->First(args))) return 7;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int distanceVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
T *first = static_cast<T*>(args[0].addr);
|
||
|
|
T *second = static_cast<T*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcReal *res = static_cast<CcReal*>(result.addr);
|
||
|
|
if (first->IsDefined() && second->IsDefined()) {
|
||
|
|
res->Set(true, first->Distance(*second));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct distanceInfo : OperatorInfo {
|
||
|
|
distanceInfo() {
|
||
|
|
name = "distance";
|
||
|
|
signature = "T x T -> bool, where T in {(m)label(s), (m)place(s)}";
|
||
|
|
syntax = "distance(_ , _);";
|
||
|
|
meaning = "Computes a Levenshtein-based distance between the objects. The"
|
||
|
|
" result is normalized to [0,1] for each of the data types.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~distancesym~}
|
||
|
|
|
||
|
|
distance: T x T -> real, where T in {mplace(s), mlabel(s)}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr distancesymTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 3) {
|
||
|
|
return NList::typeError("Expecting three arguments.");
|
||
|
|
}
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
ListExpr second = nl->Second(args);
|
||
|
|
if ((MLabel::checkType(first) && MLabel::checkType(second)) ||
|
||
|
|
(MLabels::checkType(first) && MLabels::checkType(second)) ||
|
||
|
|
(MPlace::checkType(first) && MPlace::checkType(second)) ||
|
||
|
|
(MPlaces::checkType(first) && MPlaces::checkType(second))) {
|
||
|
|
if (CcString::checkType(nl->Third(args))) {
|
||
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NList::typeError("Expecting T x T x string, where T in {mplace(s), "
|
||
|
|
"mlabel(s)}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int distancesymSelect(ListExpr args) {
|
||
|
|
if (MLabel::checkType(nl->First(args))) return 0;
|
||
|
|
if (MLabels::checkType(nl->First(args))) return 1;
|
||
|
|
if (MPlace::checkType(nl->First(args))) return 2;
|
||
|
|
if (MPlaces::checkType(nl->First(args))) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int distancesymVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
T *first = static_cast<T*>(args[0].addr);
|
||
|
|
T *second = static_cast<T*>(args[1].addr);
|
||
|
|
CcString *distfuncc = static_cast<CcString*>(args[2].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcReal *res = static_cast<CcReal*>(result.addr);
|
||
|
|
if (first->IsDefined() && second->IsDefined() && distfuncc->IsDefined()) {
|
||
|
|
DistanceFunSym distfun = Tools::getDistanceFunSym(distfuncc->GetValue());
|
||
|
|
if (distfun != ERROR) {
|
||
|
|
res->Set(true, first->DistanceSym(*second, distfun));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "\'" + distfuncc->GetValue() + "\' is not a valid distance "
|
||
|
|
"function" << endl;
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct distancesymInfo : OperatorInfo {
|
||
|
|
distancesymInfo() {
|
||
|
|
name = "distancesym";
|
||
|
|
signature = "T x T x string -> real, where T in {mlabel(s), mplace(s)}";
|
||
|
|
syntax = "distance(_ , _ , _);";
|
||
|
|
meaning = "Computes a distance between two symbolic trajectories. "
|
||
|
|
"Currently, the following distance functions are available:\n"
|
||
|
|
"\"EQUALLABELS\": returns 0 if the sequences of labels are "
|
||
|
|
"identical; 1 otherwise\n"
|
||
|
|
"\"PREFIX\": returns 0 if the sequences of labels are identical"
|
||
|
|
"; 2 if they have no common prefix; 1/p otherwise, where p is "
|
||
|
|
"the length of the common prefix\n"
|
||
|
|
"\"SUFFIX\": returns 0 if the sequences of labels are identical"
|
||
|
|
"; 2 if they have no common suffix; 1/s otherwise, where s is "
|
||
|
|
"the length of the common suffix\n"
|
||
|
|
"\"PREFIXSUFFIX\": returns 0 if the sequences of labels are "
|
||
|
|
"identical; 2 if they have no common prefix and no common "
|
||
|
|
"suffix; 1/(p+s) otherwise, where p is the length of the common"
|
||
|
|
" prefix and s is the length of the common suffix";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~hybriddistance~}
|
||
|
|
|
||
|
|
distance: T x mpoint x T x mpoint -> real, where T in {mplace, mlabel}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr hybriddistanceTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 4)) {
|
||
|
|
return NList::typeError("Expecting four arguments.");
|
||
|
|
}
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
ListExpr third = nl->Third(args);
|
||
|
|
if ((MLabel::checkType(first) && MLabel::checkType(third)) ||
|
||
|
|
(MPlace::checkType(first) && MPlace::checkType(third)) ||
|
||
|
|
(MLabels::checkType(first) && MLabels::checkType(third))) {
|
||
|
|
if (MPoint::checkType(nl->Second(args)) &&
|
||
|
|
MPoint::checkType(nl->Fourth(args))) {
|
||
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NList::typeError("Expecting T x mpoint x T x mpoint, "
|
||
|
|
"where T in {mlabel, mplace, mlabels}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int hybriddistanceSelect(ListExpr args) {
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
if (MLabel::checkType(first)) return (nl->HasLength(args, 6) ? 0 : 3);
|
||
|
|
if (MPlace::checkType(first)) return (nl->HasLength(args, 6) ? 1 : 4);
|
||
|
|
if (MLabels::checkType(first)) return (nl->HasLength(args, 6) ? 2 : 5);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Instance for storing parameters}
|
||
|
|
|
||
|
|
*/
|
||
|
|
HybridDistanceParameters hdp;
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T, bool hasGeoid>
|
||
|
|
int hybriddistanceVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
T *sym1 = static_cast<T*>(args[0].addr);
|
||
|
|
T *sym2 = static_cast<T*>(args[2].addr);
|
||
|
|
MPoint *mp1 = static_cast<MPoint*>(args[1].addr);
|
||
|
|
MPoint *mp2 = static_cast<MPoint*>(args[3].addr);
|
||
|
|
CcReal *res = static_cast<CcReal*>(result.addr);
|
||
|
|
if (sym1->IsDefined() && sym2->IsDefined() && mp1->IsDefined() &&
|
||
|
|
mp2->IsDefined()) {
|
||
|
|
double symdist = sym1->Distance(*sym2, hdp.distFun, hdp.labelFun);
|
||
|
|
if (symdist <= hdp.threshold) {
|
||
|
|
double geodist = -1.0;
|
||
|
|
if (hdp.geoDistFun >= 0 && hdp.geoDistFun < 3) {
|
||
|
|
geodist = mp1->DistanceStartEnd(*mp2, hdp.geoDistFun, hdp.geoid)
|
||
|
|
/ hdp.scaleFactor;
|
||
|
|
}
|
||
|
|
else if (hdp.geoDistFun == 3) {
|
||
|
|
geodist = mp1->FrechetDistance(mp2, hdp.geoid) / hdp.scaleFactor;
|
||
|
|
}
|
||
|
|
if (geodist < 0.0) { // error case
|
||
|
|
// cout << "GeoDist NEGATIVE" << endl;
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
else if (geodist >= 1.0) {
|
||
|
|
// cout << "symDist = " << symdist << " ===> GeoDist set to 1" << endl;
|
||
|
|
res->Set(true, 1.0);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// cout << "symDist = " << symdist << " ===> GeoDist = " << geodist
|
||
|
|
// << endl;
|
||
|
|
res->Set(true, geodist);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// cout << "symDist = " << symdist << endl;
|
||
|
|
res->Set(true, symdist);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct hybriddistanceInfo : OperatorInfo {
|
||
|
|
hybriddistanceInfo() {
|
||
|
|
name = "hybriddistance";
|
||
|
|
signature = "T x mpoint x T x mpoint x real x real -> real, "
|
||
|
|
"where T in {mlabel, mplace, mlabels}";
|
||
|
|
syntax = "hybriddistance( _ , _ , _ , _ );";
|
||
|
|
meaning = "Computes a distance between two trajectories. First, "
|
||
|
|
"a distance between the symbolic representations is computed. "
|
||
|
|
"If it is below the threshold, the discrete Fréchet distance "
|
||
|
|
"is returned. Otherwise, the result equals the symbolic "
|
||
|
|
"distance divided by the scale factor. Distance function and "
|
||
|
|
"threshold can be changed via the sethybriddistanceparam "
|
||
|
|
"operator.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~gethybriddistanceparams~}
|
||
|
|
|
||
|
|
gethybriddistanceparams: -> stream(tuple(Name: string, InputType: string,
|
||
|
|
Value: string))
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr gethybriddistanceparamsTM(ListExpr args) {
|
||
|
|
if (nl->HasLength(args, 0)) {
|
||
|
|
ListExpr attrList = nl->FiveElemList(
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Name"),
|
||
|
|
nl->SymbolAtom(CcString::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("InputType"),
|
||
|
|
nl->SymbolAtom(CcString::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("DefaultValue"),
|
||
|
|
nl->SymbolAtom(CcString::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("CurrentValue"),
|
||
|
|
nl->SymbolAtom(CcString::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Description"),
|
||
|
|
nl->SymbolAtom(FText::BasicType())));
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
attrList));
|
||
|
|
}
|
||
|
|
return listutils::typeError("No argument expected.");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int gethybriddistanceparamsVM(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s) {
|
||
|
|
// HybridDistanceParameters *hdp = (HybridDistanceParameters*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
// if (hdp) {
|
||
|
|
// delete hdp;
|
||
|
|
// local.addr = 0;
|
||
|
|
// }
|
||
|
|
// hdp = new HybridDistanceParameters();
|
||
|
|
// local.addr = hdp;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
// if (!local.addr) {
|
||
|
|
// result.addr = 0;
|
||
|
|
// return CANCEL;
|
||
|
|
// }
|
||
|
|
// hdp = (HybridDistanceParameters*)local.addr;
|
||
|
|
result.addr = hdp.getNextTuple();
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
// if (local.addr) {
|
||
|
|
// hdp = (HybridDistanceParameters*)local.addr;
|
||
|
|
// delete hdp;
|
||
|
|
// local.addr = 0;
|
||
|
|
// }
|
||
|
|
hdp.memberNo = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct gethybriddistanceparamsInfo : OperatorInfo {
|
||
|
|
gethybriddistanceparamsInfo() {
|
||
|
|
name = "gethybriddistanceparams";
|
||
|
|
signature = "-> stream(tuple(Name: string, InputType: string, DefaultValue:"
|
||
|
|
"string, CurrentValue: string, Description: text))";
|
||
|
|
syntax = "gethybriddistanceparams();";
|
||
|
|
meaning = "Returns the name, input type, default value, current value, "
|
||
|
|
"and description of every parameter applied for the "
|
||
|
|
"hybriddistance operator.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~sethybriddistanceparam~}
|
||
|
|
|
||
|
|
sethybriddistanceparam: string x T -> bool, where T corresponds to the type
|
||
|
|
of the mentioned parameter
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr sethybriddistanceparamTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 2)) {
|
||
|
|
return listutils::typeError("Two arguments expected.");
|
||
|
|
}
|
||
|
|
if (!nl->HasLength(nl->First(args),2) || !nl->HasLength(nl->Second(args),2)) {
|
||
|
|
return listutils::typeError("Argument error.");
|
||
|
|
}
|
||
|
|
string memberName;
|
||
|
|
if (CcString::checkType(nl->First(nl->First(args)))) {
|
||
|
|
memberName = nl->StringValue(nl->Second(nl->First(args)));
|
||
|
|
}
|
||
|
|
else if (FText::checkType(nl->First(nl->First(args)))) {
|
||
|
|
memberName = nl->TextValue(nl->Second(nl->First(args)));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return listutils::typeError("First argument must be a string or a text.");
|
||
|
|
}
|
||
|
|
if (!HybridDistanceParameters::isCorrectType(memberName,
|
||
|
|
nl->First(nl->Second(args)))) {
|
||
|
|
return listutils::typeError("Invalid parameter / type combination.");
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int sethybriddistanceparamSelect(ListExpr args) {
|
||
|
|
if (FText::checkType(nl->First(args))) return 0;
|
||
|
|
if (CcString::checkType(nl->First(args))) return 1;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int sethybriddistanceparamVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
T *memberName = static_cast<T*>(args[0].addr);
|
||
|
|
CcBool *res = static_cast<CcBool*>(result.addr);
|
||
|
|
res->SetDefined(false);
|
||
|
|
if (!memberName->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
std::string name(memberName->GetValue());
|
||
|
|
transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||
|
|
if (name == "labelfun") {
|
||
|
|
if ((static_cast<CcInt*>(args[1].addr))->IsDefined()) {
|
||
|
|
int value = (static_cast<CcInt*>(args[1].addr))->GetValue();
|
||
|
|
res->Set(true, hdp.setLabelFun(value));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (name == "distfun") {
|
||
|
|
if ((static_cast<CcInt*>(args[1].addr))->IsDefined()) {
|
||
|
|
int value = (static_cast<CcInt*>(args[1].addr))->GetValue();
|
||
|
|
res->Set(true, hdp.setDistFun(value));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (name == "geodistfun") {
|
||
|
|
if ((static_cast<CcInt*>(args[1].addr))->IsDefined()) {
|
||
|
|
int value = (static_cast<CcInt*>(args[1].addr))->GetValue();
|
||
|
|
res->Set(true, hdp.setGeoDistFun(value));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (name == "threshold") {
|
||
|
|
if ((static_cast<CcReal*>(args[1].addr))->IsDefined()) {
|
||
|
|
double value = static_cast<CcReal*>(args[1].addr)->GetValue();
|
||
|
|
res->Set(true, hdp.setThreshold(value));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (name == "scalefactor") {
|
||
|
|
if ((static_cast<CcReal*>(args[1].addr))->IsDefined()) {
|
||
|
|
double value = static_cast<CcReal*>(args[1].addr)->GetValue();
|
||
|
|
res->Set(true, hdp.setScaleFactor(value));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (name == "geoid") {
|
||
|
|
if ((static_cast<Geoid*>(args[1].addr))->IsDefined()) {
|
||
|
|
res->Set(true, hdp.setGeoid(static_cast<Geoid*>(args[1].addr)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string sethybriddistanceparamSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> string x T -> bool </text--->"
|
||
|
|
"<text> Sets one of the parameters for the hybriddistance operator.\n"
|
||
|
|
"<text> query sethybriddistanceparam(\"Threshold\", 1909.0) </text--->) )";
|
||
|
|
|
||
|
|
ValueMapping sethybriddistanceparamVMs[] = {sethybriddistanceparamVM<FText>,
|
||
|
|
sethybriddistanceparamVM<CcString>};
|
||
|
|
|
||
|
|
Operator sethybriddistanceparam("sethybriddistanceparam",
|
||
|
|
sethybriddistanceparamSpec, 2, sethybriddistanceparamVMs,
|
||
|
|
sethybriddistanceparamSelect, sethybriddistanceparamTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator ~longestcommonsubsequence~}
|
||
|
|
|
||
|
|
longestcommonsubsequence: mT x mT -> stream(T)
|
||
|
|
|
||
|
|
\subsubsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr longestcommonsubsequenceSymbolicTM(ListExpr args) {
|
||
|
|
if (nl->HasLength(args, 2)) {
|
||
|
|
ListExpr first(nl->First(args)), second(nl->Second(args));
|
||
|
|
if (MLabel::checkType(first) && MLabel::checkType(second)) {
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->SymbolAtom(Label::BasicType()));
|
||
|
|
}
|
||
|
|
if (MPlace::checkType(first) && MPlace::checkType(second)) {
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->SymbolAtom(Place::BasicType()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError("Correct signatures: mlabel x mlabel -> stream("
|
||
|
|
"label), mplace x mplace -> stream(place)");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsubsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int longestcommonsubsequenceSymbolicSelect(ListExpr args) {
|
||
|
|
if (MLabel::checkType(nl->First(args))) return 0;
|
||
|
|
if (MPlace::checkType(nl->First(args))) return 1;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsubsection{Local Info Class}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class B>
|
||
|
|
class LongestcommonsubsequenceLI {
|
||
|
|
public:
|
||
|
|
LongestcommonsubsequenceLI(M *m, NewPair<int, int> pos) :
|
||
|
|
src(true), limits(pos), counter(0) {
|
||
|
|
src.CopyFrom(m);
|
||
|
|
}
|
||
|
|
~LongestcommonsubsequenceLI() {}
|
||
|
|
|
||
|
|
B* getNextValue() {
|
||
|
|
B *value = new B(true);
|
||
|
|
int pos = limits.first + counter;
|
||
|
|
if (pos > limits.second) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
src.GetBasic(pos, *value);
|
||
|
|
counter++;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
M src;
|
||
|
|
NewPair<int, int> limits;
|
||
|
|
int counter;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsubsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class B>
|
||
|
|
int longestcommonsubsequenceSymbolicVM(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s) {
|
||
|
|
LongestcommonsubsequenceLI<M, B> *li =
|
||
|
|
(LongestcommonsubsequenceLI<M, B>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
M* src1 = static_cast<M*>(args[0].addr);
|
||
|
|
M* src2 = static_cast<M*>(args[1].addr);
|
||
|
|
if (src1->IsDefined() && src2->IsDefined()) {
|
||
|
|
NewPair<int, int> limits = src1->LongestCommonSubsequence(*src2);
|
||
|
|
li = new LongestcommonsubsequenceLI<M, B>(src1, limits);
|
||
|
|
}
|
||
|
|
local.addr = li;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->getNextValue() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsubsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct longestcommonsubsequenceSymbolicInfo : OperatorInfo {
|
||
|
|
longestcommonsubsequenceSymbolicInfo() {
|
||
|
|
name = "longestcommonsubsequence";
|
||
|
|
signature = "mT x mT -> stream(T), T in {label, place}";
|
||
|
|
syntax = "longestcommonsubsequence(_, _)";
|
||
|
|
meaning = "Computes the (first) longest common sequence of labels/places "
|
||
|
|
"of the sources with the help of a dynamic programming "
|
||
|
|
"algorithm.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~topattern~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr topatternTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 1)) {
|
||
|
|
return listutils::typeError("one argument expected");
|
||
|
|
}
|
||
|
|
NList type(args);
|
||
|
|
if (type.first() == NList(FText::BasicType())) {
|
||
|
|
return NList(PatPersistent::BasicType()).listExpr();
|
||
|
|
}
|
||
|
|
return NList::typeError("Expecting a text!");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int topatternVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
FText* pText = static_cast<FText*>(args[0].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
PatPersistent* p = static_cast<PatPersistent*>(result.addr);
|
||
|
|
Pattern* pattern = 0;
|
||
|
|
if (pText->IsDefined()) {
|
||
|
|
pattern = Pattern::getPattern(pText->toText(), false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "undefined text" << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (pattern) {
|
||
|
|
p->Set(true, pText->toText());
|
||
|
|
delete pattern;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct topatternInfo : OperatorInfo {
|
||
|
|
topatternInfo() {
|
||
|
|
name = "topattern";
|
||
|
|
signature = " Text -> " + PatPersistent::BasicType();
|
||
|
|
syntax = "_ topattern";
|
||
|
|
meaning = "Creates a Pattern from a Text.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~toclassifier~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr toclassifierTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting stream(tuple(s: text, t: text))";
|
||
|
|
if (nl->HasLength(args, 1)) {
|
||
|
|
if (Stream<Tuple>::checkType(nl->First(args))) {
|
||
|
|
ListExpr dType, pType;
|
||
|
|
if (nl->ListLength(nl->Second(nl->Second(nl->First(args)))) != 2) {
|
||
|
|
return listutils::typeError("Tuple must have exactly 2 attributes");
|
||
|
|
}
|
||
|
|
dType = nl->Second(nl->First(nl->Second(nl->Second(nl->First(args)))));
|
||
|
|
pType = nl->Second(nl->Second(nl->Second(nl->Second(nl->First(args)))));
|
||
|
|
if (FText::checkType(dType) && FText::checkType(pType)) {
|
||
|
|
return nl->SymbolAtom(Classifier::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int toclassifierVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
Stream<Tuple> stream = static_cast<Stream<Tuple> >(args[0].addr);
|
||
|
|
stream.open();
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Classifier* c = static_cast<Classifier*>(result.addr);
|
||
|
|
Tuple* tuple = stream.request();
|
||
|
|
FText *desc, *ptext;
|
||
|
|
map<int, int> final2Pat;
|
||
|
|
Pattern* p = 0;
|
||
|
|
vector<string> texts;
|
||
|
|
vector<Pattern*> patterns;
|
||
|
|
while (tuple) {
|
||
|
|
desc = (FText*)tuple->GetAttribute(0);
|
||
|
|
if (!desc->IsDefined()) {
|
||
|
|
cout << "Undefined description" << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
ptext = (FText*)tuple->GetAttribute(1);
|
||
|
|
if (!ptext->IsDefined()) {
|
||
|
|
cout << "Undefined pattern text" << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
p = Pattern::getPattern(ptext->GetValue(), true); // do not build NFA
|
||
|
|
if (!p) {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
texts.push_back(desc->GetValue());
|
||
|
|
texts.push_back(ptext->GetValue());
|
||
|
|
patterns.push_back(p);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
tuple = stream.request();
|
||
|
|
}
|
||
|
|
stream.close();
|
||
|
|
c->appendCharPos(0);
|
||
|
|
for (unsigned int i = 0; i < texts.size(); i++) {
|
||
|
|
for (unsigned int j = 0; j < texts[i].length(); j++) { //store desc&pattern
|
||
|
|
c->appendChar(texts[i][j]);
|
||
|
|
}
|
||
|
|
c->appendCharPos(c->getCharSize());
|
||
|
|
}
|
||
|
|
vector<map<int, int> > nfa;
|
||
|
|
set<int> finalStates;
|
||
|
|
c->buildMultiNFA(patterns, nfa, finalStates, final2Pat);
|
||
|
|
for (unsigned int i = 0; i < patterns.size(); i++) {
|
||
|
|
delete patterns[i];
|
||
|
|
}
|
||
|
|
c->setPersistentNFA(nfa, finalStates, final2Pat);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct toclassifierInfo : OperatorInfo {
|
||
|
|
toclassifierInfo() {
|
||
|
|
name = "toclassifier";
|
||
|
|
signature = "stream(tuple(description: text, pattern: text)) -> classifier";
|
||
|
|
syntax = "_ toclassifier";
|
||
|
|
meaning = "creates a classifier from a stream(tuple(s: text, t: text))";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~matches~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
This type mapping checks whether the second argument (i.e., the pattern) is
|
||
|
|
constant or not and passes that information to the value mapping.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr matchesTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 2)) {
|
||
|
|
return NList::typeError("Two arguments expected");
|
||
|
|
}
|
||
|
|
if (!nl->HasLength(nl->First(args),2) || !nl->HasLength(nl->Second(args),2)) {
|
||
|
|
return NList::typeError("Two arguments expected for each sublist");
|
||
|
|
}
|
||
|
|
ListExpr mtype = nl->First(nl->First(args));
|
||
|
|
ListExpr ptype = nl->First(nl->Second(args));
|
||
|
|
if ((!MLabel::checkType(mtype) && !MPlace::checkType(mtype) &&
|
||
|
|
!MLabels::checkType(mtype) && !MPlaces::checkType(mtype)) ||
|
||
|
|
(!FText::checkType(ptype) && !PatPersistent::checkType(ptype))) {
|
||
|
|
return NList::typeError("Expecting mlabel(s)/mplace(s) x text/pattern");
|
||
|
|
}
|
||
|
|
string query = nl->ToString(nl->Second(nl->Second(args)));
|
||
|
|
Word res;
|
||
|
|
bool isConst = QueryProcessor::ExecuteQuery(query, res);
|
||
|
|
if (isConst) {
|
||
|
|
if (FText::checkType(nl->First(nl->Second(args)))) {
|
||
|
|
((FText*)res.addr)->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
delete (PatPersistent*)res.addr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
||
|
|
nl->OneElemList(nl->BoolAtom(isConst)),
|
||
|
|
nl->SymbolAtom(CcBool::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int matchesSelect(ListExpr args) {
|
||
|
|
if (MLabel::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args))) ? 4 : 0;
|
||
|
|
}
|
||
|
|
if (MPlace::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args))) ? 5 : 1;
|
||
|
|
}
|
||
|
|
if (MLabels::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args))) ? 6 : 2;
|
||
|
|
}
|
||
|
|
if (MPlaces::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args))) ? 7 : 3;
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class P>
|
||
|
|
int matchesVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
M *traj = static_cast<M*>(args[0].addr);
|
||
|
|
P* pText = static_cast<P*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcBool* b = static_cast<CcBool*>(result.addr);
|
||
|
|
Pattern *p = 0;
|
||
|
|
if (message != CLOSE) {
|
||
|
|
if ((static_cast<CcBool*>(args[2].addr))->GetValue()) { //2nd argument const
|
||
|
|
if (!local.addr) {
|
||
|
|
if (pText->IsDefined() && traj->IsDefined()) {
|
||
|
|
local.addr = Pattern::getPattern(pText->toText(), false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "Undefined pattern text or trajectory." << endl;
|
||
|
|
b->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
p = (Pattern*)local.addr;
|
||
|
|
if (!p) {
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
else if (p->hasAssigns()) {
|
||
|
|
cout << "No assignments allowed for matches" << endl;
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
ExtBool res = p->matches(traj);
|
||
|
|
switch (res) {
|
||
|
|
case ST_FALSE: {
|
||
|
|
b->Set(true, false);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case ST_TRUE: {
|
||
|
|
b->Set(true, true);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
default: {
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else { // second argument non-constant
|
||
|
|
if (pText->IsDefined()) {
|
||
|
|
p = Pattern::getPattern(pText->toText(), false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "Undefined pattern text." << endl;
|
||
|
|
b->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (!p) {
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
else if (p->hasAssigns()) {
|
||
|
|
cout << "No assignments allowed for matches" << endl;
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
ExtBool res = p->matches(traj);
|
||
|
|
switch (res) {
|
||
|
|
case ST_FALSE: {
|
||
|
|
b->Set(true, false);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case ST_TRUE: {
|
||
|
|
b->Set(true, true);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
default: {
|
||
|
|
b->SetDefined(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (p) {
|
||
|
|
delete p;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if (local.addr) {
|
||
|
|
delete (Pattern*)local.addr;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string matchesSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> {mlabel(s)|mplace(s)} x {pattern|text} -> bool </text--->"
|
||
|
|
"<text> M matches P </text--->"
|
||
|
|
"<text> Checks whether the trajectory M matches the pattern P.\n"
|
||
|
|
"<text> query mlabel1 matches '(_ \"Eving\") *' </text--->) )";
|
||
|
|
|
||
|
|
ValueMapping matchesVMs[] = {matchesVM<MLabel, FText>, matchesVM<MPlace, FText>,
|
||
|
|
matchesVM<MLabels, FText>, matchesVM<MPlaces, FText>,
|
||
|
|
matchesVM<MLabel, PatPersistent>, matchesVM<MPlace, PatPersistent>,
|
||
|
|
matchesVM<MLabels, PatPersistent>, matchesVM<MPlaces, PatPersistent>};
|
||
|
|
|
||
|
|
Operator matches("matches", matchesSpec, 8, matchesVMs, matchesSelect,
|
||
|
|
matchesTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createtupleindex~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class PosType, class PosType2>
|
||
|
|
ListExpr createtupleindexTM(ListExpr args) {
|
||
|
|
string err = "Operator expects a stream of tuples where at least one "
|
||
|
|
"attribute is a symbolic trajectory. Optionally, the user can "
|
||
|
|
"specify the name of the main attribute.";
|
||
|
|
if (!nl->HasLength(args, 1) && !nl->HasLength(args, 2)) {
|
||
|
|
return listutils::typeError(err + " ("
|
||
|
|
+ stringutils::int2str(nl->ListLength(args)) + " arguments instead of 1)");
|
||
|
|
}
|
||
|
|
if (!listutils::isTupleStream(nl->First(args))) {
|
||
|
|
return listutils::typeError(err + " (no tuple stream received)");
|
||
|
|
}
|
||
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
string attrName;
|
||
|
|
int pos = -1;
|
||
|
|
if (nl->HasLength(args, 1)) {
|
||
|
|
string symAttrNames[] = {"mlabel", "mlabels", "mplace", "mplaces"};
|
||
|
|
int found = 0;
|
||
|
|
for (int i = 0; i < 4; i++) {
|
||
|
|
found += listutils::findType(attrList, nl->SymbolAtom(symAttrNames[i]),
|
||
|
|
attrName);
|
||
|
|
if (found != 0 && pos == -1) {
|
||
|
|
pos = found;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (found == 0) {
|
||
|
|
return listutils::typeError(err + " (no symbolic attribute found)");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr type;
|
||
|
|
pos = listutils::findAttribute(attrList, attrName, type);
|
||
|
|
if (pos == 0 || !Tools::isSymbolicType(type)) {
|
||
|
|
return listutils::typeError(err + " (" + attrName + " is not the name of "
|
||
|
|
+ "a symbolic attribute)");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(pos - 1)),
|
||
|
|
nl->SymbolAtom(TupleIndex<PosType, PosType2>::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class PosType, class PosType2>
|
||
|
|
int createtupleindexVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Stream<Tuple> stream = static_cast<Stream<Tuple> >(args[0].addr);
|
||
|
|
CcInt *attrno = static_cast<CcInt*>(args[2].addr);
|
||
|
|
TupleIndex<PosType, PosType2> * ti
|
||
|
|
= static_cast<TupleIndex<PosType, PosType2>* >(result.addr);
|
||
|
|
int counter = 0;
|
||
|
|
stream.open();
|
||
|
|
Tuple* tuple = stream.request();
|
||
|
|
if (tuple) {
|
||
|
|
ti->initialize(tuple->GetTupleType(), attrno->GetIntval());
|
||
|
|
}
|
||
|
|
while (tuple) {
|
||
|
|
if (!ti->addTuple(tuple)) {
|
||
|
|
ti->deleteIndexes();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
counter++;
|
||
|
|
if (counter % 1000 == 0) {
|
||
|
|
cout << counter << " tuples processed" << endl;
|
||
|
|
}
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
tuple = stream.request();
|
||
|
|
}
|
||
|
|
stream.close();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createtupleindexInfo : OperatorInfo {
|
||
|
|
createtupleindexInfo() {
|
||
|
|
name = "createtupleindex";
|
||
|
|
signature = "stream(tuple(X)) --> bool";
|
||
|
|
syntax = "_ createtupleindex";
|
||
|
|
meaning = "Creates a multiple index for all moving attributes of the "
|
||
|
|
"tuple stream.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~bulkloadtupleindex~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class PosType, class PosType2>
|
||
|
|
ListExpr bulkloadtupleindexTM(ListExpr args) {
|
||
|
|
string err = (PosType::BasicType() == "unitpos" ? "Operator expects a "
|
||
|
|
"relation and the name of an attribute of a moving type, e.g., mlabel."
|
||
|
|
: "Operator expects a relation");
|
||
|
|
int numOfArgs = (PosType::BasicType() == "unitpos" ? 2 : 1);
|
||
|
|
if (!nl->HasLength(args, numOfArgs)) {
|
||
|
|
return listutils::typeError(err + " (" +
|
||
|
|
stringutils::int2str(nl->ListLength(args)) + " arguments instead of " +
|
||
|
|
stringutils::int2str(numOfArgs) + ")");
|
||
|
|
}
|
||
|
|
if (!listutils::isRelDescription(nl->First(args))) {
|
||
|
|
return listutils::typeError(err + " (no relation received)");
|
||
|
|
}
|
||
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
string attrName;
|
||
|
|
int pos = -1;
|
||
|
|
// if (nl->HasLength(args, 1)) {
|
||
|
|
// string symAttrNames[] = {"mlabel", "mlabels", "mplace", "mplaces"};
|
||
|
|
// int found = 0;
|
||
|
|
// for (int i = 0; i < 4; i++) {
|
||
|
|
// found += listutils::findType(attrList, nl->SymbolAtom(symAttrNames[i]),
|
||
|
|
// attrName);
|
||
|
|
// if (found != 0 && pos == -1) {
|
||
|
|
// pos = found;
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// if (found == 0) {
|
||
|
|
// return listutils::typeError(err + " (no symbolic attribute found)");
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
if (numOfArgs == 2) { // attribute name given
|
||
|
|
attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr type;
|
||
|
|
pos = listutils::findAttribute(attrList, attrName, type);
|
||
|
|
if (pos == 0 || !Tools::isSymbolicType(type)) {
|
||
|
|
return listutils::typeError(err + " (" + attrName + " is not the name of "
|
||
|
|
+ "a symbolic attribute)");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ListExpr result = (numOfArgs == 1 ?
|
||
|
|
nl->SymbolAtom(TupleIndex<PosType, PosType2>::BasicType()) :
|
||
|
|
nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(pos - 1)),
|
||
|
|
nl->SymbolAtom(TupleIndex<PosType, PosType2>::BasicType())));
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class PosType, class PosType2>
|
||
|
|
int bulkloadtupleindexVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Relation *rel = static_cast<Relation*>(args[0].addr);
|
||
|
|
int attrPos = -1;
|
||
|
|
if (PosType::BasicType() == "unitpos") {
|
||
|
|
CcInt* attrno = static_cast<CcInt*>(args[2].addr);
|
||
|
|
attrPos = attrno->GetIntval();
|
||
|
|
}
|
||
|
|
TupleIndex<PosType, PosType2>* ti
|
||
|
|
= static_cast<TupleIndex<PosType, PosType2>*>(result.addr);
|
||
|
|
if (rel->GetNoTuples() == 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
TupleType *tt = rel->GetTupleType();
|
||
|
|
ti->initialize(tt, attrPos);
|
||
|
|
int majorValueNo;
|
||
|
|
vector<pair<int, string> > relevantAttrs =
|
||
|
|
Tools::getRelevantAttrs(tt, attrPos, majorValueNo);
|
||
|
|
Supplier s0 = qp->GetSon(s, 0);
|
||
|
|
ListExpr ttList = nl->Second(qp->GetType(s0));
|
||
|
|
int relevantAttrCount = 0;
|
||
|
|
for (int a = 1; a <= tt->GetNoAttributes(); a++) {
|
||
|
|
if (Tools::isMovingAttr(ttList, a)) {
|
||
|
|
string typeName = relevantAttrs[relevantAttrCount].second;
|
||
|
|
ti->collectSortInsert(rel, a - 1, typeName, qp->GetMemorySize(s));
|
||
|
|
relevantAttrCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string bulkloadtupleindexSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> relation(tuple(X)) x attrname --> tupleindex </text--->"
|
||
|
|
"<text> _ bulkloadtupleindex[attr] </text--->"
|
||
|
|
"<text> Creates a tupleindex for all moving attributes of the \n"
|
||
|
|
"relation, given the name of an attribute. </text--->"
|
||
|
|
"<text> Dotraj bulkloadtupleindex[Trajectory]</text--->) )";
|
||
|
|
|
||
|
|
struct bulkloadtupleindexInfo : OperatorInfo {
|
||
|
|
bulkloadtupleindexInfo() {
|
||
|
|
name = "bulkloadtupleindex";
|
||
|
|
signature = "relation(tuple(X)) x ATTRNAME --> tupleindex";
|
||
|
|
syntax = "_ bulkloadtupleindex[ _ ]";
|
||
|
|
meaning = "Creates a multiple index for all moving attributes of the "
|
||
|
|
"relation, given the name of an attribute (applicable with "
|
||
|
|
"indextmatches).";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
Operator bulkloadtupleindex("bulkloadtupleindex", bulkloadtupleindexSpec,
|
||
|
|
bulkloadtupleindexVM<UnitPos, UnitPos>, Operator::SimpleSelect,
|
||
|
|
bulkloadtupleindexTM<UnitPos, UnitPos>);
|
||
|
|
|
||
|
|
const string bulkloadtupleindex2Spec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> relation(tuple(X)) --> tupleindex2 </text--->"
|
||
|
|
"<text> _ bulkloadtupleindex[attr] </text--->"
|
||
|
|
"<text> Creates a tupleindex2 for all moving attributes of the \n"
|
||
|
|
"relation. </text--->"
|
||
|
|
"<text> Dotraj bulkloadtupleindex2</text--->) )";
|
||
|
|
|
||
|
|
struct bulkloadtupleindex2Info : OperatorInfo {
|
||
|
|
bulkloadtupleindex2Info() {
|
||
|
|
name = "bulkloadtupleindex2";
|
||
|
|
signature = "relation(tuple(X)) --> tupleindex2";
|
||
|
|
syntax = "_ bulkloadtupleindex2";
|
||
|
|
meaning = "Creates a tupleindex2 for all moving attributes of the "
|
||
|
|
"relation (applicable with indextmatches2).";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
Operator bulkloadtupleindex2("bulkloadtupleindex2", bulkloadtupleindex2Spec,
|
||
|
|
bulkloadtupleindexVM<NewInterval, UnitPos>, Operator::SimpleSelect,
|
||
|
|
bulkloadtupleindexTM<NewInterval, UnitPos>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~tmatches~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr tmatchesTM(ListExpr args) {
|
||
|
|
string err = "the expected syntax is: tuple(X) x attrname x (text | pattern)";
|
||
|
|
if (!nl->HasLength(args, 3)) {
|
||
|
|
return listutils::typeError(err + " (wrong number of arguments)");
|
||
|
|
}
|
||
|
|
ListExpr attrs;
|
||
|
|
if (!Tuple::checkType(nl->First(nl->First(args)))) {
|
||
|
|
return listutils::typeError(err + " (first argument is not a tuple)");
|
||
|
|
}
|
||
|
|
attrs = nl->Second(nl->First(nl->First(args)));
|
||
|
|
if (!listutils::isSymbol(nl->First(nl->Second(args))) ||
|
||
|
|
(!FText::checkType(nl->First(nl->Third(args))) &&
|
||
|
|
!PatPersistent::checkType(nl->First(nl->Third(args))))) {
|
||
|
|
return listutils::typeError(err + " (error in 2nd or 3rd argument)");
|
||
|
|
}
|
||
|
|
string name = nl->SymbolValue(nl->First(nl->Second(args)));
|
||
|
|
ListExpr type;
|
||
|
|
int index = listutils::findAttribute(attrs, name, type);
|
||
|
|
if (!index) {
|
||
|
|
return listutils::typeError("Attribute " + name + " not found in tuple.");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(type) && !MLabels::checkType(type) &&
|
||
|
|
!MPlace::checkType(type) && !MPlaces::checkType(type)) {
|
||
|
|
return listutils::typeError("Attribute " + name + " is not a symbolic "
|
||
|
|
"trajectory (MLabel, MLabels, MPlace, MPlaces)");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(index - 1)),
|
||
|
|
nl->SymbolAtom(CcBool::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int tmatchesSelect(ListExpr args) {
|
||
|
|
return FText::checkType(nl->Third(args)) ? 0 : 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class P>
|
||
|
|
int tmatchesVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Tuple *tuple = static_cast<Tuple*>(args[0].addr);
|
||
|
|
CcInt *attrno = static_cast<CcInt*>(args[3].addr);
|
||
|
|
P* pat = static_cast<P*>(args[2].addr);
|
||
|
|
Pattern *p = 0;
|
||
|
|
CcBool* res = static_cast<CcBool*>(result.addr);
|
||
|
|
res->SetDefined(false);
|
||
|
|
if (pat->IsDefined() && attrno->IsDefined()) {
|
||
|
|
Supplier s0 = qp->GetSon(s, 0);
|
||
|
|
ListExpr ttype = qp->GetType(s0);
|
||
|
|
p = Pattern::getPattern(pat->toText(), false, tuple, ttype);
|
||
|
|
if (p) {
|
||
|
|
ExtBool result = p->tmatches(tuple, attrno->GetIntval(), ttype);
|
||
|
|
if (result == ST_TRUE) {
|
||
|
|
res->Set(true, true);
|
||
|
|
}
|
||
|
|
else if (result == ST_FALSE) {
|
||
|
|
res->Set(true, false);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
delete p;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string tmatchesSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> tuple(X) x attrname x (pattern | text) -> bool </text--->"
|
||
|
|
"<text> t matches [attr, p] </text--->"
|
||
|
|
"<text> Checks whether the moving type attributes of the tuple match the\n"
|
||
|
|
"pattern. The given attribute name has to be the name of a symbolic\n"
|
||
|
|
"trajectory attribute. It is treated as a master attribute."
|
||
|
|
"<text>query Part feed filter[. matches [ML, "
|
||
|
|
"'* (_ _ superset{\"BKA\"}) *']] count </text--->) )";
|
||
|
|
|
||
|
|
ValueMapping tmatchesVMs[] = {tmatchesVM<FText>, tmatchesVM<PatPersistent>};
|
||
|
|
|
||
|
|
Operator tmatches("tmatches", tmatchesSpec, 2, tmatchesVMs, tmatchesSelect,
|
||
|
|
tmatchesTM);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~indextmatches~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr indextmatchesTM(ListExpr args) {
|
||
|
|
string err = "the expected syntax is: tupleindex x rel x attrname x "
|
||
|
|
"(text | pattern)";
|
||
|
|
if (!nl->HasLength(args, 4)) {
|
||
|
|
return listutils::typeError(err + " (4 arguments expected)");
|
||
|
|
}
|
||
|
|
if (!TupleIndex<UnitPos, UnitPos>::checkType(nl->First(nl->First(args)))) {
|
||
|
|
return listutils::typeError(err + " (first argument is not a tuple index)");
|
||
|
|
}
|
||
|
|
if (!Relation::checkType(nl->First(nl->Second(args)))) {
|
||
|
|
return listutils::typeError(err + " (second argument is not a relation)");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->First(nl->Third(args))) ||
|
||
|
|
(!FText::checkType(nl->First(nl->Fourth(args))) &&
|
||
|
|
!PatPersistent::checkType(nl->First(nl->Fourth(args))))) {
|
||
|
|
return listutils::typeError(err + " (error in 3rd or 4th argument)");
|
||
|
|
}
|
||
|
|
ListExpr tList = nl->Second(nl->First(nl->Second(args)));
|
||
|
|
ListExpr attrs = nl->Second(tList);
|
||
|
|
string name = nl->SymbolValue(nl->First(nl->Third(args)));
|
||
|
|
ListExpr type;
|
||
|
|
int index = listutils::findAttribute(attrs, name, type);
|
||
|
|
if (!index) {
|
||
|
|
return listutils::typeError("Attribute " + name + " not found in relation");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(type) && !MLabels::checkType(type) &&
|
||
|
|
!MPlace::checkType(type) && !MPlaces::checkType(type)) {
|
||
|
|
return listutils::typeError("Attribute " + name + " is not a symbolic "
|
||
|
|
"trajectory (MLabel, MLabels, MPlace, MPlaces)");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(index - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), tList));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int indextmatchesSelect(ListExpr args) {
|
||
|
|
return FText::checkType(nl->Fourth(args)) ? 0 : 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class P>
|
||
|
|
int indextmatchesVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
TMatchIndexLI *li = (TMatchIndexLI*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
Relation *rel = static_cast<Relation*>(args[1].addr);
|
||
|
|
CcInt *attrno = static_cast<CcInt*>(args[4].addr);
|
||
|
|
TupleIndex<UnitPos, UnitPos> *ti
|
||
|
|
= static_cast<TupleIndex<UnitPos, UnitPos>*>(args[0].addr);
|
||
|
|
FText* pText = static_cast<FText*>(args[3].addr);
|
||
|
|
Pattern *p = 0;
|
||
|
|
if (pText->IsDefined() && attrno->IsDefined() && rel->GetNoTuples() > 0) {
|
||
|
|
Supplier s0 = qp->GetSon(s, 1);
|
||
|
|
ListExpr ttList = nl->Second(qp->GetType(s0));
|
||
|
|
// cout << "ttype is " << nl->ToString(ttList) << endl;
|
||
|
|
Tuple *firstTuple = rel->GetTuple(1, false);
|
||
|
|
TupleType *tt = firstTuple->GetTupleType();
|
||
|
|
p = Pattern::getPattern(pText->GetValue(), false, firstTuple, ttList);
|
||
|
|
if (p) {
|
||
|
|
vector<pair<int, string> > relevantAttrs;
|
||
|
|
int majorValueNo = -1;
|
||
|
|
if (p->isCompatible(tt, attrno->GetIntval(), relevantAttrs,
|
||
|
|
majorValueNo)) {
|
||
|
|
DataType mtype = Tools::getDataType(tt, attrno->GetIntval());
|
||
|
|
li = new TMatchIndexLI(rel, ttList, ti, attrno->GetIntval(), p,
|
||
|
|
majorValueNo, mtype);
|
||
|
|
if (!li->initialize(true)) {
|
||
|
|
delete li;
|
||
|
|
li = 0;
|
||
|
|
local.addr = 0;
|
||
|
|
cout << "initialization failed" << endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
firstTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
local.addr = li;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextTuple() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string indextmatchesSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> tuple(X) x attrname x (pattern | text) -> bool </text--->"
|
||
|
|
"<text> tupleindex rel indextmatches [attr, p] </text--->"
|
||
|
|
"<text> Checks whether the moving type attributes of the relation match the\n"
|
||
|
|
"pattern. The given attribute name has to be the name of a symbolic\n"
|
||
|
|
"trajectory attribute. It is treated as a main attribute."
|
||
|
|
"<text>query Part bulkloadtupleindex[ML] Part indextmatches[ML, "
|
||
|
|
"'* (_ _ superset{\"BKA\"}) *'] count </text--->) )";
|
||
|
|
|
||
|
|
ValueMapping indextmatchesVMs[] = {indextmatchesVM<FText>,
|
||
|
|
indextmatchesVM<PatPersistent>};
|
||
|
|
|
||
|
|
Operator indextmatches("indextmatches", indextmatchesSpec, 2, indextmatchesVMs,
|
||
|
|
indextmatchesSelect, indextmatchesTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~indextmatches2~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr indextmatches2TM(ListExpr args) {
|
||
|
|
string err = "the expected syntax is: tupleindex x rel x (text | pattern)";
|
||
|
|
if (!nl->HasLength(args, 3)) {
|
||
|
|
return listutils::typeError(err + " (3 arguments expected)");
|
||
|
|
}
|
||
|
|
if (!TupleIndex<NewInterval, UnitPos>::checkType(nl->First(nl->First(args)))){
|
||
|
|
return listutils::typeError(err + " (1st argument is not a tupleindex2)");
|
||
|
|
}
|
||
|
|
if (!Relation::checkType(nl->First(nl->Second(args)))) {
|
||
|
|
return listutils::typeError(err + " (2nd argument is not a relation)");
|
||
|
|
}
|
||
|
|
if (!FText::checkType(nl->First(nl->Third(args))) &&
|
||
|
|
!PatPersistent::checkType(nl->Third(args))) {
|
||
|
|
return listutils::typeError(err + " (3rd argument is not a text/pattern)");
|
||
|
|
}
|
||
|
|
ListExpr tList = nl->Second(nl->First(nl->Second(args)));
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), tList);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int indextmatches2Select(ListExpr args) {
|
||
|
|
return FText::checkType(nl->Third(args)) ? 0 : 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class P>
|
||
|
|
int indextmatches2VM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
TMatchIndexLI *li = (TMatchIndexLI*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
Relation *rel = static_cast<Relation*>(args[1].addr);
|
||
|
|
TupleIndex<NewInterval, UnitPos> *ti
|
||
|
|
= static_cast<TupleIndex<NewInterval, UnitPos>*>(args[0].addr);
|
||
|
|
FText* pText = static_cast<FText*>(args[2].addr);
|
||
|
|
Pattern *p = 0;
|
||
|
|
if (pText->IsDefined() && rel->GetNoTuples() > 0) {
|
||
|
|
Supplier s0 = qp->GetSon(s, 1);
|
||
|
|
ListExpr ttList = nl->Second(qp->GetType(s0));
|
||
|
|
// cout << "ttype is " << nl->ToString(ttList) << endl;
|
||
|
|
Tuple *firstTuple = rel->GetTuple(1, false);
|
||
|
|
TupleType *tt = firstTuple->GetTupleType();
|
||
|
|
p = Pattern::getPattern(pText->GetValue(), false, firstTuple, ttList);
|
||
|
|
if (p) {
|
||
|
|
vector<pair<int, string> > relevantAttrs;
|
||
|
|
int majorValueNo;
|
||
|
|
if (p->isCompatible(tt, -1, relevantAttrs, majorValueNo)) {
|
||
|
|
li = new TMatchIndexLI(rel, ttList, ti, p);
|
||
|
|
if (!li->initialize(false)) {
|
||
|
|
delete li;
|
||
|
|
li = 0;
|
||
|
|
local.addr = 0;
|
||
|
|
cout << "initialization failed" << endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
firstTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
local.addr = li;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextTuple() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string indextmatches2Spec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> tuple(X) x attrname x (pattern | text) -> bool </text--->"
|
||
|
|
"<text> tupleindex rel indextmatches2 [p] </text--->"
|
||
|
|
"<text> Checks whether the moving type attributes of the relation match the\n"
|
||
|
|
"pattern. A main attribute is not specified, in contrast to indextmatches."
|
||
|
|
"<text>query Part bulkloadtupleindex[ML] Part indextmatches2["
|
||
|
|
"'* (_ _ superset{\"BKA\"}) *'] count </text--->) )";
|
||
|
|
|
||
|
|
ValueMapping indextmatches2VMs[] = {indextmatches2VM<FText>,
|
||
|
|
indextmatches2VM<PatPersistent>};
|
||
|
|
|
||
|
|
Operator indextmatches2("indextmatches2", indextmatches2Spec, 2,
|
||
|
|
indextmatches2VMs, indextmatches2Select, indextmatches2TM);
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~indexrewrite~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr indexrewriteTM(ListExpr args) {
|
||
|
|
string err = "the expected syntax is: tupleindex x rel x attrname x "
|
||
|
|
"(text | pattern)";
|
||
|
|
if (!nl->HasMinLength(args,1))
|
||
|
|
return listutils::typeError("Operator requires 1 Argument at least!");
|
||
|
|
if (!TupleIndex<UnitPos, UnitPos>::checkType(nl->First(args))) {
|
||
|
|
return listutils::typeError(err + " (first argument is not a tupleindex)");
|
||
|
|
}
|
||
|
|
if (!Relation::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(err + " (second argument is not a relation)");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Third(args)) ||
|
||
|
|
(!FText::checkType(nl->Fourth(args)) &&
|
||
|
|
!PatPersistent::checkType(nl->Fourth(args)))) {
|
||
|
|
return listutils::typeError(err + " (error in 3rd or 4th argument)");
|
||
|
|
}
|
||
|
|
ListExpr attrs = nl->Second(nl->Second(nl->Second(args)));
|
||
|
|
string name = nl->SymbolValue(nl->Third(args));
|
||
|
|
ListExpr type;
|
||
|
|
int index = listutils::findAttribute(attrs, name, type);
|
||
|
|
if (!index) {
|
||
|
|
return listutils::typeError("Attribute " + name + " not found in relation");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(type) && !MLabels::checkType(type) &&
|
||
|
|
!MPlace::checkType(type) && !MPlaces::checkType(type)) {
|
||
|
|
return listutils::typeError("Attribute " + name + " is not a symbolic "
|
||
|
|
"trajectory (MLabel, MLabels, MPlace, MPlaces)");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(index - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), type));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int indexrewriteSelect(ListExpr args) {
|
||
|
|
ListExpr attrs = nl->Second(nl->Second(nl->Second(args)));
|
||
|
|
string name = nl->SymbolValue(nl->Third(args));
|
||
|
|
ListExpr type;
|
||
|
|
listutils::findAttribute(attrs, name, type);
|
||
|
|
if (MLabel::checkType(type)) return 0;
|
||
|
|
if (MLabels::checkType(type)) return 1;
|
||
|
|
if (MPlace::checkType(type)) return 2;
|
||
|
|
if (MPlaces::checkType(type)) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int indexrewriteVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
IndexRewriteLI<M> *li = (IndexRewriteLI<M>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
Relation *rel = static_cast<Relation*>(args[1].addr);
|
||
|
|
CcInt *attrno = static_cast<CcInt*>(args[4].addr);
|
||
|
|
TupleIndex<UnitPos, UnitPos> *ti
|
||
|
|
= static_cast<TupleIndex<UnitPos, UnitPos>*>(args[0].addr);
|
||
|
|
FText* pText = static_cast<FText*>(args[3].addr);
|
||
|
|
Pattern *p = 0;
|
||
|
|
if (pText->IsDefined() && attrno->IsDefined() && rel->GetNoTuples() > 0) {
|
||
|
|
Supplier s0 = qp->GetSon(s, 1);
|
||
|
|
ListExpr ttList = nl->Second(qp->GetType(s0));
|
||
|
|
// cout << "ttype is " << nl->ToString(ttList) << endl;
|
||
|
|
Tuple *firstTuple = rel->GetTuple(1, false);
|
||
|
|
TupleType *tt = firstTuple->GetTupleType();
|
||
|
|
p = Pattern::getPattern(pText->GetValue(), false, firstTuple, ttList);
|
||
|
|
if (p) {
|
||
|
|
vector<pair<int, string> > relevantAttrs;
|
||
|
|
int majorValueNo = -1;
|
||
|
|
if (p->isCompatible(tt, attrno->GetIntval(), relevantAttrs,
|
||
|
|
majorValueNo)) {
|
||
|
|
DataType mtype = Tools::getDataType(tt, attrno->GetIntval());
|
||
|
|
li = new IndexRewriteLI<M>(rel, ttList, ti, attrno->GetIntval(), p,
|
||
|
|
majorValueNo, mtype);
|
||
|
|
if (!li->initialize(true, true)) {
|
||
|
|
delete li;
|
||
|
|
li = 0;
|
||
|
|
local.addr = 0;
|
||
|
|
cout << "initialization failed" << endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "invalid pattern" << endl;
|
||
|
|
}
|
||
|
|
firstTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
local.addr = li;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextResult() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct indexrewriteInfo : OperatorInfo {
|
||
|
|
indexrewriteInfo() {
|
||
|
|
name = "indexrewrite";
|
||
|
|
signature = "tupleindex x rel x attrname x (text | pattern) -> stream(T),"
|
||
|
|
" where T is the type of attrname";
|
||
|
|
syntax = "_ _ indexrewrite[_, _]";
|
||
|
|
meaning = "Rewrites all attribute values according to the pattern.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createunitrtree~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createunitrtreeTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("Exactly 2 arguments expected.");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Second(args))) {
|
||
|
|
return listutils::typeError("Attribute name expected as 2nd argument.");
|
||
|
|
}
|
||
|
|
if (!listutils::isTupleStream(nl->First(args))) {
|
||
|
|
return listutils::typeError("Tuple stream expected as 1st argument.");
|
||
|
|
}
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
ListExpr attrType;
|
||
|
|
int attrIndex = listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (attrIndex <= 0) {
|
||
|
|
return listutils::typeError("Specified attribute name does not occur in the"
|
||
|
|
" tuple stream.");
|
||
|
|
}
|
||
|
|
if (!Tools::isSymbolicType(attrType)) { // TODO: add all moving types
|
||
|
|
return listutils::typeError(nl->ToString(attrType) + " is not a valid "
|
||
|
|
"attribute type.");
|
||
|
|
}
|
||
|
|
ListExpr first;
|
||
|
|
ListExpr rest = attrList;
|
||
|
|
int j(1), tidIndex(0);
|
||
|
|
while (!nl->IsEmpty(rest)) {
|
||
|
|
first = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if (nl->SymbolValue(nl->Second(first)) == TupleIdentifier::BasicType()) {
|
||
|
|
if (tidIndex != 0) {
|
||
|
|
return listutils::typeError("Exactly one tuple identifier attribute "
|
||
|
|
"expected within the tuple stream.");
|
||
|
|
}
|
||
|
|
tidIndex = j;
|
||
|
|
}
|
||
|
|
j++;
|
||
|
|
}
|
||
|
|
if (tidIndex <= 0) {
|
||
|
|
return listutils::typeError("Exactly one tuple identifier attribute "
|
||
|
|
"expected within the tuple stream.");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(attrIndex),
|
||
|
|
nl->IntAtom(tidIndex)),
|
||
|
|
nl->FourElemList(
|
||
|
|
nl->SymbolAtom(R_Tree<1, NewPair<TupleId, int> >::BasicType()),
|
||
|
|
nl->Second(nl->First(args)),
|
||
|
|
attrType,
|
||
|
|
nl->BoolAtom(false)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int createunitrtreeSelect(ListExpr args) {
|
||
|
|
ListExpr tList = nl->First(nl->Rest(nl->First(args)));
|
||
|
|
ListExpr aList = nl->Second(tList);
|
||
|
|
string aName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr aType;
|
||
|
|
listutils::findAttribute(aList, aName, aType);
|
||
|
|
if (MLabel::checkType(aType)) return 0;
|
||
|
|
if (MLabels::checkType(aType)) return 1;
|
||
|
|
if (MPlace::checkType(aType)) return 2;
|
||
|
|
if (MPlaces::checkType(aType)) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int createunitrtreeVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
Word wTuple;
|
||
|
|
R_Tree<1, NewPair<TupleId, int> > *rtree =
|
||
|
|
(R_Tree<1, NewPair<TupleId, int> >*)qp->ResultStorage(s).addr;
|
||
|
|
result.setAddr(rtree);
|
||
|
|
if (!rtree->InitializeBulkLoad()) {
|
||
|
|
cout << "R-tree not initialized for bulk load" << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
int attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
||
|
|
int tidIndex = ((CcInt*)args[3].addr)->GetIntval() - 1;
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, wTuple);
|
||
|
|
while (qp->Received(args[0].addr)) {
|
||
|
|
Tuple *tuple = (Tuple*)wTuple.addr;
|
||
|
|
M *traj = (M*)tuple->GetAttribute(attrIndex);
|
||
|
|
TupleIdentifier *tid = (TupleIdentifier *)tuple->GetAttribute(tidIndex);
|
||
|
|
double start[1], end[1];
|
||
|
|
if (traj->IsDefined() && tid->IsDefined()) {
|
||
|
|
for (int i = 0; i < traj->GetNoComponents(); i++) {
|
||
|
|
SecInterval timeIv(true);
|
||
|
|
traj->GetInterval(i, timeIv);
|
||
|
|
start[0] = timeIv.start.ToDouble();
|
||
|
|
end[0] = timeIv.end.ToDouble();
|
||
|
|
Rectangle<1> doubleIv(true, start, end);
|
||
|
|
if (doubleIv.IsDefined()) {
|
||
|
|
NewPair<TupleId, int> position(tid->GetTid(), i);
|
||
|
|
R_TreeLeafEntry<1, NewPair<TupleId, int> > entry(doubleIv, position);
|
||
|
|
rtree->InsertBulkLoad(entry);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
deleteIfAllowed(tuple);
|
||
|
|
qp->Request(args[0].addr, wTuple);
|
||
|
|
}
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
if (!rtree->FinalizeBulkLoad()) {
|
||
|
|
cout << "bulk load not finalized" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createunitrtreeInfo : OperatorInfo {
|
||
|
|
createunitrtreeInfo() {
|
||
|
|
name = "createunitrtree";
|
||
|
|
signature = "stream(tuple(X)) x IDENT -> rtree";
|
||
|
|
syntax = "_ createunitrtree [ _ ]";
|
||
|
|
meaning = "Creates an rtree from a tuple stream having a moving type "
|
||
|
|
"attribute Each unit in each tuple is indexed separately.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~indexmatches~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr indexmatchesTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting a relation, the name of a mT (T in {label(s)"
|
||
|
|
", place(s)}) attribute of that relation, an invfile, an rtree, and a "
|
||
|
|
"pattern/text";
|
||
|
|
if (nl->HasLength(args, 5)) {
|
||
|
|
if (FText::checkType(nl->Fifth(args)) ||
|
||
|
|
PatPersistent::checkType(nl->Fifth(args))) {
|
||
|
|
if (Relation::checkType(nl->First(args))) {
|
||
|
|
ListExpr tList = nl->First(nl->Rest(nl->First(args)));
|
||
|
|
if (Tuple::checkType(tList) && listutils::isSymbol(nl->Second(args))) {
|
||
|
|
ListExpr aType;
|
||
|
|
ListExpr aList = nl->Second(tList);
|
||
|
|
string aName = nl->SymbolValue(nl->Second(args));
|
||
|
|
int i = listutils::findAttribute(aList, aName, aType);
|
||
|
|
if (i == 0) {
|
||
|
|
return listutils::typeError(aName + " not found");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(aType) && !MPlace::checkType(aType) &&
|
||
|
|
!MLabels::checkType(aType) && !MPlaces::checkType(aType)) {
|
||
|
|
return listutils::typeError
|
||
|
|
("type " + nl->ToString(aType) + " is invalid");
|
||
|
|
}
|
||
|
|
if (InvertedFile::checkType(nl->Third(args)) &&
|
||
|
|
R_Tree<1, TwoLayerLeafInfo>::checkType(nl->Fourth(args))) {
|
||
|
|
if (Tools::isSymbolicType(nl->Third(nl->Fourth(args)))) {
|
||
|
|
return nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(i - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), tList));
|
||
|
|
}
|
||
|
|
return listutils::typeError("invalid rtree type " +
|
||
|
|
nl->ToString(nl->Third(nl->Fourth(args))));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int indexmatchesSelect(ListExpr args) {
|
||
|
|
ListExpr tList = nl->First(nl->Rest(nl->First(args)));
|
||
|
|
ListExpr aList = nl->Second(tList);
|
||
|
|
string aName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr aType;
|
||
|
|
listutils::findAttribute(aList, aName, aType);
|
||
|
|
if (MLabel::checkType(aType)) {
|
||
|
|
return (FText::checkType(nl->Fourth(args)) ? 0 : 4);
|
||
|
|
}
|
||
|
|
if (MLabels::checkType(aType)) {
|
||
|
|
return (FText::checkType(nl->Fourth(args)) ? 1 : 5);
|
||
|
|
}
|
||
|
|
if (MPlace::checkType(aType)) {
|
||
|
|
return (FText::checkType(nl->Fourth(args)) ? 2 : 6);
|
||
|
|
}
|
||
|
|
if (MPlaces::checkType(aType)) {
|
||
|
|
return (FText::checkType(nl->Fourth(args)) ? 3 : 7);
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class P>
|
||
|
|
int indexmatchesVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
IndexMatchesLI *li = (IndexMatchesLI*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
Pattern *p = 0;
|
||
|
|
P *pText = static_cast<P*>(args[4].addr);
|
||
|
|
CcInt *attr = static_cast<CcInt*>(args[5].addr);
|
||
|
|
InvertedFile *inv = static_cast<InvertedFile*>(args[2].addr);
|
||
|
|
R_Tree<1, NewPair<TupleId, int> > *rt =
|
||
|
|
static_cast<R_Tree<1, NewPair<TupleId, int> >*>(args[3].addr);
|
||
|
|
Relation *rel = static_cast<Relation*>(args[0].addr);
|
||
|
|
if (pText->IsDefined() && attr->IsDefined()) {
|
||
|
|
p = Pattern::getPattern(pText->toText(), false);
|
||
|
|
if (p) {
|
||
|
|
if (p->isValid(M::BasicType())) {
|
||
|
|
local.addr = new IndexMatchesLI(rel, inv, rt, attr->GetIntval(), p,
|
||
|
|
Tools::getDataType(M::BasicType()));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "undefined parameter(s)" << endl;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextTuple() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct indexmatchesInfo : OperatorInfo {
|
||
|
|
indexmatchesInfo() {
|
||
|
|
name = "indexmatches";
|
||
|
|
signature = "rel(tuple(X)) x IDENT x invfile x rtree x text -> "
|
||
|
|
"stream(tuple(X))";
|
||
|
|
syntax = "_ indexmatches [ _ , _ , _ , _ ]";
|
||
|
|
meaning = "Filters a relation containing a mlabel attribute, applying a "
|
||
|
|
"twofold index (trie and 1-dim rtree) and passing only those "
|
||
|
|
"trajectories matching the pattern on to the output stream.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~filtermatches~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr filtermatchesTM(ListExpr args) {
|
||
|
|
string err = "the expected syntax is: stream(tuple(X)) x attrname x text"
|
||
|
|
"or stream(tuple(X)) x attrname x pattern";
|
||
|
|
if (!nl->HasLength(args, 3)) {
|
||
|
|
return listutils::typeError(err + " (wrong number of arguments)");
|
||
|
|
}
|
||
|
|
ListExpr stream = nl->First(args);
|
||
|
|
ListExpr anlist = nl->Second(args);
|
||
|
|
if (!Stream<Tuple>::checkType(stream) || !listutils::isSymbol(anlist) ||
|
||
|
|
(!FText::checkType(nl->Third(args)) &&
|
||
|
|
!PatPersistent::checkType(nl->Third(args)))) {
|
||
|
|
return listutils::typeError(err);
|
||
|
|
}
|
||
|
|
string name = nl->SymbolValue(anlist);
|
||
|
|
ListExpr type;
|
||
|
|
int index = listutils::findAttribute(nl->Second(nl->Second(stream)),
|
||
|
|
name, type);
|
||
|
|
if (!index) {
|
||
|
|
return listutils::typeError("attribute " + name + " not found in tuple");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(type) && !MLabels::checkType(type) &&
|
||
|
|
!MPlace::checkType(type) && !MPlaces::checkType(type)) {
|
||
|
|
return listutils::typeError("wrong type " + nl->ToString(type)
|
||
|
|
+ " of attritube " + name);
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(index - 1)), stream);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int filtermatchesSelect(ListExpr args) {
|
||
|
|
ListExpr stream = nl->First(args);
|
||
|
|
ListExpr anlist = nl->Second(args);
|
||
|
|
ListExpr pattern = nl->Third(args);
|
||
|
|
string name = nl->SymbolValue(anlist);
|
||
|
|
ListExpr type;
|
||
|
|
listutils::findAttribute(nl->Second(nl->Second(stream)),
|
||
|
|
name, type);
|
||
|
|
if (MLabel::checkType(type)) return (FText::checkType(pattern) ? 0 : 4);
|
||
|
|
if (MLabels::checkType(type)) return (FText::checkType(pattern) ? 1 : 5);
|
||
|
|
if (MPlace::checkType(type)) return (FText::checkType(pattern) ? 2 : 6);
|
||
|
|
if (MPlaces::checkType(type)) return (FText::checkType(pattern) ? 3 : 7);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping for a Text}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class T>
|
||
|
|
int filtermatchesVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
FilterMatchesLI<M>* li = (FilterMatchesLI<M>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
CcInt* ccint = (CcInt*)args[3].addr;
|
||
|
|
T* pText = (T*)args[2].addr;
|
||
|
|
if (pText->IsDefined() && ccint->IsDefined()) {
|
||
|
|
string text = pText->toText();
|
||
|
|
local.addr = new FilterMatchesLI<M>(args[0], ccint->GetValue(), text);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "undefined argument(s)" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->getNextResult() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct filtermatchesInfo : OperatorInfo {
|
||
|
|
filtermatchesInfo() {
|
||
|
|
name = "filtermatches";
|
||
|
|
signature = "stream(tuple(X)) x IDENT x text -> stream(tuple(X))";
|
||
|
|
syntax = "_ filtermatches [ _ , _ ]";
|
||
|
|
meaning = "Filters a stream containing symbolic trajectories, passing "
|
||
|
|
"exactly the tuples whose trajectories match the pattern on "
|
||
|
|
"to the output stream.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~rewrite~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr rewriteTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting an mT (T in {label(s), place(s)} and a "
|
||
|
|
"pattern/text";
|
||
|
|
if (nl->HasLength(args, 2)) {
|
||
|
|
ListExpr mtype = nl->First(args);
|
||
|
|
if ((MLabel::checkType(mtype) || MLabels::checkType(mtype) ||
|
||
|
|
MPlace::checkType(mtype) || MPlaces::checkType(mtype)) &&
|
||
|
|
(FText::checkType(nl->Second(args)) ||
|
||
|
|
PatPersistent::checkType(nl->Second(args)))) {
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Stream<Attribute>::BasicType()),
|
||
|
|
mtype);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NList::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int rewriteSelect(ListExpr args) {
|
||
|
|
if (MLabel::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args)) ? 4 : 0);
|
||
|
|
}
|
||
|
|
if (MLabels::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args)) ? 5 : 1);
|
||
|
|
}
|
||
|
|
if (MPlace::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args)) ? 6 : 2);
|
||
|
|
}
|
||
|
|
if (MPlaces::checkType(nl->First(args))) {
|
||
|
|
return (PatPersistent::checkType(nl->Second(args)) ? 7 : 3);
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping (for a text)}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M, class T>
|
||
|
|
int rewriteVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
M *source = 0;
|
||
|
|
T* pText = 0;
|
||
|
|
Pattern *p = 0;
|
||
|
|
RewriteLI<M> *rewriteLI = 0;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
source = static_cast<M*>(args[0].addr);
|
||
|
|
pText = static_cast<T*>(args[1].addr);
|
||
|
|
if (!pText->IsDefined()) {
|
||
|
|
cout << "Error: undefined pattern text." << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (!source->IsDefined()) {
|
||
|
|
cout << "Error: undefined mlabel." << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
p = Pattern::getPattern(pText->toText(), false);
|
||
|
|
if (!p) {
|
||
|
|
cout << "Error: pattern not initialized." << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if (!p->isValid(M::BasicType())) {
|
||
|
|
cout << "Pattern not suitable for type " << M::BasicType() << endl;
|
||
|
|
}
|
||
|
|
else if (!p->hasAssigns()) {
|
||
|
|
cout << "No result specified." << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if (p->initAssignOpTrees() && p->initEasyCondOpTrees(false)) {
|
||
|
|
rewriteLI = new RewriteLI<M>(source, p);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
local.addr = rewriteLI;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
if (!local.addr) {
|
||
|
|
result.addr = 0;
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
rewriteLI = ((RewriteLI<M>*)local.addr);
|
||
|
|
result.addr = rewriteLI->getNextResult();
|
||
|
|
return (result.addr ? YIELD : CANCEL);
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (local.addr) {
|
||
|
|
rewriteLI = ((RewriteLI<M>*)local.addr);
|
||
|
|
delete rewriteLI;
|
||
|
|
local.addr=0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct rewriteInfo : OperatorInfo {
|
||
|
|
rewriteInfo() {
|
||
|
|
name = "rewrite";
|
||
|
|
signature = "mT x P -> stream(mT), where T in {label(s), place(s)}, "
|
||
|
|
"P in {pattern, text}";
|
||
|
|
syntax = "rewrite (_, _)";
|
||
|
|
meaning = "Rewrite a symbolic trajectory according to a rewrite rule.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~multirewrite~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr multirewriteTM(ListExpr args) {
|
||
|
|
if (nl->HasLength(args, 3)) {
|
||
|
|
if (!Stream<Tuple>::checkType(nl->First(args))) {
|
||
|
|
return NList::typeError("First argument must be a tuple stream.");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Second(args))) {
|
||
|
|
return NList::typeError("Second argument must be an attribute name.");
|
||
|
|
}
|
||
|
|
if (!Stream<FText>::checkType(nl->Third(args))) {
|
||
|
|
return NList::typeError("Third argument must be a text stream.");
|
||
|
|
}
|
||
|
|
string attrname = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr attrlist = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
ListExpr attrtype;
|
||
|
|
int index = listutils::findAttribute(attrlist, attrname, attrtype);
|
||
|
|
if (!index) {
|
||
|
|
return listutils::typeError("Attribute " + attrname + " not found.");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(attrtype) && !MLabels::checkType(attrtype) &&
|
||
|
|
!MPlace::checkType(attrtype) && !MPlaces::checkType(attrtype)) {
|
||
|
|
return listutils::typeError("Wrong type " + nl->ToString(attrtype)
|
||
|
|
+ " of attritube " + attrname + ".");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(index - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(
|
||
|
|
Stream<Attribute>::BasicType()),
|
||
|
|
attrtype));
|
||
|
|
}
|
||
|
|
return listutils::typeError("Three arguments expected.");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int multirewriteSelect(ListExpr args) {
|
||
|
|
ListExpr stream = nl->First(args);
|
||
|
|
string attrname = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr attrtype;
|
||
|
|
listutils::findAttribute(nl->Second(nl->Second(stream)),attrname, attrtype);
|
||
|
|
if (MLabel::checkType(attrtype)) return 0;
|
||
|
|
if (MLabels::checkType(attrtype)) return 1;
|
||
|
|
if (MPlace::checkType(attrtype)) return 2;
|
||
|
|
if (MPlaces::checkType(attrtype)) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int multirewriteVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
MultiRewriteLI<M> *li = (MultiRewriteLI<M>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
int attrpos = (static_cast<CcInt*>(args[3].addr))->GetIntval();
|
||
|
|
local.addr = new MultiRewriteLI<M>(args[0], args[2], attrpos);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextResult() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct multirewriteInfo : OperatorInfo {
|
||
|
|
multirewriteInfo() {
|
||
|
|
name = "multirewrite";
|
||
|
|
signature = "stream(tuple(..., mT, ...)) x IDENT x stream(text) -> "
|
||
|
|
"stream(mT), where T in {label(s), place(s)}";
|
||
|
|
syntax = "_ rewrite [ _ , _ ]";
|
||
|
|
meaning = "Rewrite a stream of symbolic trajectories.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~classify~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr classifyTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting an mT (T in {label(s), place(s)} and a "
|
||
|
|
"classifier.";
|
||
|
|
if (nl->HasLength(args, 2)) {
|
||
|
|
if (Tools::isSymbolicType(nl->First(args))
|
||
|
|
&& Classifier::checkType(nl->Second(args))) {
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->SymbolAtom(FText::BasicType()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int classifySelect(ListExpr args) {
|
||
|
|
if (MLabel::checkType(nl->First(args))) return 0;
|
||
|
|
if (MLabels::checkType(nl->First(args))) return 1;
|
||
|
|
if (MPlace::checkType(nl->First(args))) return 2;
|
||
|
|
if (MPlaces::checkType(nl->First(args))) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping without index}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int classifyVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
ClassifyLI *li = (ClassifyLI*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
M* source = static_cast<M*>(args[0].addr);
|
||
|
|
if (source) {
|
||
|
|
if (source->IsDefined()) {
|
||
|
|
local.addr = new ClassifyLI(source, args[1]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextResultText() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct classifyInfo : OperatorInfo {
|
||
|
|
classifyInfo() {
|
||
|
|
name = "classify";
|
||
|
|
signature = "mT (T in {label(s), place(s)}) x classifier -> stream(text)";
|
||
|
|
syntax = "classify(_ , _)";
|
||
|
|
meaning = "Classifies a trajectory according to a classifier";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~indexclassify~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr indexclassifyTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting a relation, the name of an mT (T in "
|
||
|
|
"{label(s), place(s)}) attribute, an invfile, an rtree, and a classifier";
|
||
|
|
if (nl->HasLength(args, 5)) {
|
||
|
|
if (Classifier::checkType(nl->Fifth(args))) {
|
||
|
|
if (Relation::checkType(nl->First(args))) {
|
||
|
|
if (Tuple::checkType(nl->First(nl->Rest(nl->First(args))))
|
||
|
|
&& listutils::isSymbol(nl->Second(args))) {
|
||
|
|
ListExpr attrType;
|
||
|
|
ListExpr attrList = nl->Second(nl->First(nl->Rest(nl->First(args))));
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
int i = listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (i == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrName + " not found");
|
||
|
|
}
|
||
|
|
if (!MLabel::checkType(attrType) && !MLabels::checkType(attrType) &&
|
||
|
|
!MPlace::checkType(attrType) && !MPlaces::checkType(attrType)) {
|
||
|
|
return listutils::typeError
|
||
|
|
("Type " + nl->ToString(attrType) + " is invalid");
|
||
|
|
}
|
||
|
|
if (InvertedFile::checkType(nl->Third(args)) &&
|
||
|
|
R_Tree<1, TwoLayerLeafInfo>::checkType(nl->Fourth(args))) {
|
||
|
|
ListExpr outputAttrs = nl->TwoElemList(
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Description"),
|
||
|
|
nl->SymbolAtom(FText::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Trajectory"), attrType));
|
||
|
|
return nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(i - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
outputAttrs)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int indexclassifySelect(ListExpr args) {
|
||
|
|
ListExpr attrList = nl->Second(nl->First(nl->Rest(nl->First(args))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (MLabel::checkType(attrType)) return 0;
|
||
|
|
if (MLabels::checkType(attrType)) return 1;
|
||
|
|
if (MPlace::checkType(attrType)) return 2;
|
||
|
|
if (MPlaces::checkType(attrType)) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int indexclassifyVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
IndexClassifyLI *li = (IndexClassifyLI*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
InvertedFile *inv = static_cast<InvertedFile*>(args[2].addr);
|
||
|
|
R_Tree<1, NewPair<TupleId, UnitPos> > *rt =
|
||
|
|
static_cast<R_Tree<1, NewPair<TupleId, UnitPos> >*>(args[3].addr);
|
||
|
|
CcInt *attr = static_cast<CcInt*>(args[5].addr);
|
||
|
|
Relation *rel = static_cast<Relation*>(args[0].addr);
|
||
|
|
if (!attr->IsDefined()) {
|
||
|
|
cout << "undefined parameter(s)" << endl;
|
||
|
|
local.addr = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
local.addr = new IndexClassifyLI(rel, inv, rt, args[4], attr->GetIntval(),
|
||
|
|
Tools::getDataType(M::BasicType()));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
cout << "REQUEST next tuple" << endl;
|
||
|
|
result.addr = li ? li->nextResultTuple<M>() : 0;
|
||
|
|
cout << "return " << (result.addr ? "TUPLE" : "NULL") << endl;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct indexclassifyInfo : OperatorInfo {
|
||
|
|
indexclassifyInfo() {
|
||
|
|
name = "indexclassify";
|
||
|
|
signature = "rel(tuple(..., mT, ...)) x attrname x invfile x rtree x "
|
||
|
|
"classifier -> stream(tuple(string, mT))";
|
||
|
|
syntax = "_ indexclassify [_ , _ , _ , _]";
|
||
|
|
meaning = "Classifies an indexed relation of trajectories according to a "
|
||
|
|
" classifier";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{operator ~createml~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createmlTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting an integer and a bool.";
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("Two arguments expected.");
|
||
|
|
}
|
||
|
|
if (CcInt::checkType(nl->First(args)) &&
|
||
|
|
CcBool::checkType(nl->Second(args))) {
|
||
|
|
return nl->SymbolAtom(MLabel::BasicType());
|
||
|
|
}
|
||
|
|
return NList::typeError(errMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int createmlVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcInt* ccint = static_cast<CcInt*>(args[0].addr);
|
||
|
|
CcBool* ccbool = static_cast<CcBool*>(args[1].addr);
|
||
|
|
MLabel* ml = static_cast<MLabel*>(result.addr);
|
||
|
|
ml->SetDefined(false);
|
||
|
|
if (!ccint->IsDefined() || !ccbool->IsDefined()) {
|
||
|
|
cout << "undefined value" << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
map<string, set<string> > transitions;
|
||
|
|
if (!Tools::createTransitions(ccbool->GetValue(), transitions)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
vector<string> labels;
|
||
|
|
if (!Tools::createLabelSequence(ccint->GetValue(), 1, ccbool->GetValue(),
|
||
|
|
transitions, labels)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
ml->SetDefined(true);
|
||
|
|
ml->createML(ccint->GetValue(), 0, labels);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createmlInfo : OperatorInfo {
|
||
|
|
createmlInfo() {
|
||
|
|
name = "createml";
|
||
|
|
signature = "int x bool -> mlabel";
|
||
|
|
syntax = "createml(_,_)";
|
||
|
|
meaning = "Creates an MLabel, representing a trip either through "
|
||
|
|
"Dortmund's districts (iff the second parameter is true) or "
|
||
|
|
" Germany's counties. The first parameter determines the size.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createmlrel~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createmlrelTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 4) {
|
||
|
|
return listutils::typeError("Four arguments expected.");
|
||
|
|
}
|
||
|
|
if (nl->IsEqual(nl->First(args), CcInt::BasicType())
|
||
|
|
&& nl->IsEqual(nl->Second(args), CcInt::BasicType())
|
||
|
|
&& nl->IsEqual(nl->Third(args), CcString::BasicType())
|
||
|
|
&& nl->IsEqual(nl->Fourth(args), CcBool::BasicType())) {
|
||
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
||
|
|
}
|
||
|
|
return NList::typeError("Expecting two integers, a string and a bool.");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int createmlrelVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
CcInt* ccint1 = static_cast<CcInt*>(args[0].addr);
|
||
|
|
CcInt* ccint2 = static_cast<CcInt*>(args[1].addr);
|
||
|
|
CcString* ccstring = static_cast<CcString*>(args[2].addr);
|
||
|
|
CcBool* ccbool = static_cast<CcBool*>(args[3].addr);
|
||
|
|
int number, size;
|
||
|
|
string relName, errMsg;
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcBool* res = (CcBool*)result.addr;
|
||
|
|
if (ccstring->IsDefined() && ccint1->IsDefined() && ccint2->IsDefined() &&
|
||
|
|
ccbool->IsDefined()) {
|
||
|
|
SecondoCatalog* sc = SecondoSystem::GetCatalog();
|
||
|
|
relName = ccstring->GetValue();
|
||
|
|
if (!sc->IsValidIdentifier(relName, errMsg, true)) { // check relation name
|
||
|
|
cout << "Invalid relation name \"" << relName << "\"; " << errMsg << endl;
|
||
|
|
res->Set(true, false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (sc->IsObjectName(relName)) {
|
||
|
|
cout << relName << " is an existing DB object" << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (sc->IsSystemObject(relName)) {
|
||
|
|
cout << relName << " is a reserved name" << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
number = ccint1->GetValue();
|
||
|
|
size = ccint2->GetValue();
|
||
|
|
ListExpr typeInfo = nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
nl->TwoElemList(nl->TwoElemList(nl->SymbolAtom("No"),
|
||
|
|
nl->SymbolAtom(CcInt::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Trajectory"),
|
||
|
|
nl->SymbolAtom(MLabel::BasicType()))));
|
||
|
|
ListExpr numTypeInfo = sc->NumericType(typeInfo);
|
||
|
|
TupleType* type = new TupleType(numTypeInfo);
|
||
|
|
Relation* rel = new Relation(type, false);
|
||
|
|
Tuple* tuple;
|
||
|
|
MLabel* ml;
|
||
|
|
srand(time(0));
|
||
|
|
map<string, set<string> > transitions;
|
||
|
|
if (!Tools::createTransitions(ccbool->GetValue(), transitions)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
vector<string> labels;
|
||
|
|
if (!Tools::createLabelSequence(size, number, ccbool->GetValue(),
|
||
|
|
transitions, labels)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
for (int i = 0; i < number; i++) {
|
||
|
|
tuple = new Tuple(type);
|
||
|
|
ml = new MLabel(1);
|
||
|
|
ml->createML(size, i, labels);
|
||
|
|
tuple->PutAttribute(0, new CcInt(true, i));
|
||
|
|
tuple->PutAttribute(1, ml);
|
||
|
|
rel->AppendTuple(tuple);
|
||
|
|
tuple = 0;
|
||
|
|
ml = 0;
|
||
|
|
}
|
||
|
|
Word relWord;
|
||
|
|
relWord.setAddr(rel);
|
||
|
|
sc->InsertObject(relName, "", nl->TwoElemList
|
||
|
|
(nl->SymbolAtom(Relation::BasicType()), typeInfo), relWord, true);
|
||
|
|
res->Set(true, true);
|
||
|
|
type->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "Error: undefined value." << endl;
|
||
|
|
res->Set(true, false);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createmlrelInfo : OperatorInfo {
|
||
|
|
createmlrelInfo() {
|
||
|
|
name = "createmlrel";
|
||
|
|
signature = "int x int x string x bool -> bool";
|
||
|
|
syntax = "createmlrelation(_ , _ , _ , _)";
|
||
|
|
meaning = "Creates a relation containing arbitrary many synthetic moving"
|
||
|
|
"labels of arbitrary size and stores it into the database. If "
|
||
|
|
"the boolean parameter is true, a trip through Dortmund's "
|
||
|
|
"districts is simulated (12 different labels); otherwise the "
|
||
|
|
"trip is based on German counties (439 different labels).";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createtrie~}
|
||
|
|
|
||
|
|
createtrie: rel(tuple(..., mT, ...)) -> invfile, where T in {label(s), place(s)}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createtrieTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 2) {
|
||
|
|
return listutils::typeError("Two arguments expected.");
|
||
|
|
}
|
||
|
|
if (Relation::checkType(nl->First(args))) {
|
||
|
|
if (Tuple::checkType(nl->First(nl->Rest(nl->First(args))))) {
|
||
|
|
ListExpr attrList =
|
||
|
|
nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
int i = listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (i > 0) { // found
|
||
|
|
if (MLabel::checkType(attrType) || MLabels::checkType(attrType) ||
|
||
|
|
MPlace::checkType(attrType) || MPlaces::checkType(attrType)) {
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(i)),
|
||
|
|
nl->SymbolAtom(InvertedFile::BasicType()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError("Argument types must be rel(tuple(..., mT, ...)) "
|
||
|
|
"x attrname, where T in {label(s), place(s)}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int createtrieSelect(ListExpr args) {
|
||
|
|
ListExpr attrList = nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (MLabel::checkType(attrType)) return 0;
|
||
|
|
if (MLabels::checkType(attrType)) return 1;
|
||
|
|
if (MPlace::checkType(attrType)) return 2;
|
||
|
|
if (MPlaces::checkType(attrType)) return 3;
|
||
|
|
return -1; // cannot occur
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int createtrieVM(Word* args, Word& result, int message, Word& local,Supplier s){
|
||
|
|
Relation *rel = (Relation*)(args[0].addr);
|
||
|
|
Tuple *tuple = 0;
|
||
|
|
M *src = 0;
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
InvertedFileT<UnitPos, UnitPos>* inv
|
||
|
|
= (InvertedFileT<UnitPos, UnitPos>*)result.addr;
|
||
|
|
inv->setParams(false, 1, "");
|
||
|
|
size_t maxMem = 0;/*qp->GetMemorySize(s) * 1024 * 1024*/
|
||
|
|
size_t trieCacheSize = maxMem / 20;
|
||
|
|
if (trieCacheSize < 4096) {
|
||
|
|
trieCacheSize = 4096;
|
||
|
|
}
|
||
|
|
size_t invCacheSize;
|
||
|
|
if (trieCacheSize + 4096 > maxMem) {
|
||
|
|
invCacheSize = 4096;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
invCacheSize = maxMem - trieCacheSize;
|
||
|
|
}
|
||
|
|
appendcache::RecordAppendCache* cache = inv->createAppendCache(invCacheSize);
|
||
|
|
TrieNodeCacheType* trieCache = inv->createTrieCache(trieCacheSize);
|
||
|
|
int attrno = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
||
|
|
int64_t dummy;
|
||
|
|
for (int i = 0; i < rel->GetNoTuples(); i++) {
|
||
|
|
tuple = rel->GetTuple(i + 1, false);
|
||
|
|
src = (M*)(tuple->GetAttribute(attrno));
|
||
|
|
TupleIndex<UnitPos, UnitPos>::insertIntoTrie(inv, i + 1, src,
|
||
|
|
Tools::getDataType(tuple->GetTupleType(), attrno), cache, trieCache, dummy);
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
delete trieCache;
|
||
|
|
delete cache;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createtrieInfo : OperatorInfo {
|
||
|
|
createtrieInfo() {
|
||
|
|
name = "createtrie";
|
||
|
|
signature = "rel(tuple(..., mT, ...)) x attrname -> invfile, where T in "
|
||
|
|
"{label(s), place(s)}";
|
||
|
|
syntax = "_ createtrie [ _ ]";
|
||
|
|
meaning = "Builds an index for a relation of numbered symbolic "
|
||
|
|
"trajectories.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~derivegroups~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr derivegroupsTM(ListExpr args) {
|
||
|
|
if (nl->ListLength(args) != 3) {
|
||
|
|
return listutils::typeError("Three arguments expected.");
|
||
|
|
}
|
||
|
|
if (Stream<Tuple>::checkType(nl->First(args))) {
|
||
|
|
if (Tuple::checkType(nl->First(nl->Rest(nl->First(args))))) {
|
||
|
|
ListExpr attrList =
|
||
|
|
nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
int i = listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (i > 0) { // found
|
||
|
|
if (MLabel::checkType(attrType) || MLabels::checkType(attrType) ||
|
||
|
|
MPlace::checkType(attrType) || MPlaces::checkType(attrType)) {
|
||
|
|
if (CcReal::checkType(nl->Third(args))) {
|
||
|
|
ListExpr newAttr = nl->TwoElemList(nl->SymbolAtom("Group"),
|
||
|
|
nl->SymbolAtom(CcInt::BasicType()));
|
||
|
|
ListExpr newAttrList = nl->OneElemList(nl->First(attrList));
|
||
|
|
ListExpr rest = nl->Rest(attrList);
|
||
|
|
ListExpr last = newAttrList;
|
||
|
|
while (rest != nl->Empty()) {
|
||
|
|
last = nl->Append(last, nl->First(rest));
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
}
|
||
|
|
last = nl->Append(last, newAttr);
|
||
|
|
ListExpr output = nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(Stream<Tuple>::BasicType()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()), newAttrList));
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(i - 1)), output);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return listutils::typeError("Argument types must be stream(tuple(..., mT, "
|
||
|
|
"...)) x attrname x real, where T in {label(s), place(s)}");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int derivegroupsSelect(ListExpr args) {
|
||
|
|
ListExpr attrList = nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (MLabel::checkType(attrType)) return 0;
|
||
|
|
if (MLabels::checkType(attrType)) return 1;
|
||
|
|
if (MPlace::checkType(attrType)) return 2;
|
||
|
|
if (MPlaces::checkType(attrType)) return 3;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class M>
|
||
|
|
int derivegroupsVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
DeriveGroupsLI<M>* li = (DeriveGroupsLI<M>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
CcReal *threshold = static_cast<CcReal*>(args[2].addr);
|
||
|
|
CcInt *attrNo = static_cast<CcInt*>(args[3].addr);
|
||
|
|
if (threshold->IsDefined() && attrNo->IsDefined()){
|
||
|
|
local.addr = new DeriveGroupsLI<M>(args[0], threshold->GetValue(),
|
||
|
|
attrNo->GetValue());
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "undefined argument(s)" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->getNextTuple() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct derivegroupsInfo : OperatorInfo {
|
||
|
|
derivegroupsInfo() {
|
||
|
|
name = "derivegroups";
|
||
|
|
signature = "stream(tuple(..., mT, ...)) x attrname x real -> stream(tuple("
|
||
|
|
"..., mT, ..., int)), where T in {label(s), place(s)}";
|
||
|
|
syntax = "_ derivegroups [ _ , _ ]";
|
||
|
|
meaning = "Finds groups of similar symbolic trajectories inside a tuple "
|
||
|
|
"stream. The granularity of the groups is specified by a "
|
||
|
|
"threshold.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createMaxspeedRaster~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// ListExpr createMaxspeedRasterTM(ListExpr args) {
|
||
|
|
// const std::string error_message = "expects the signature sint x nrel(... "
|
||
|
|
// "(WayInfo (arel (tuple ((WayTagKey text) (WayTagValue text)))))) x rtree";
|
||
|
|
// if (!nl->HasLength(args, 3)) {
|
||
|
|
// return listutils::typeError(error_message);
|
||
|
|
// }
|
||
|
|
// if (!raster2::sint::checkType(nl->First(args))) {
|
||
|
|
// return listutils::typeError("First argument must be an sint");
|
||
|
|
// }
|
||
|
|
// if (!RTree2TID::checkType(nl->Third(args))) {
|
||
|
|
// return listutils::typeError("Third argument must be an rtree");
|
||
|
|
// }
|
||
|
|
// if (NestedRelation::checkType(nl->Second(args))) {
|
||
|
|
// if (nl->HasLength(nl->Second(args), 2)) {
|
||
|
|
// if (nl->HasLength(nl->Second(nl->Second(args)), 2)) {
|
||
|
|
// ListExpr nrelAttrs = nl->Second(nl->Second(nl->Second(args)));
|
||
|
|
// ListExpr arelAttrs = nl->Second(nl->Second(nl->Second(nl->Nth(
|
||
|
|
// nl->ListLength(nrelAttrs), nrelAttrs))));
|
||
|
|
// if (nl->ToString(nl->First(nl->First(arelAttrs))) == "WayTagKey"
|
||
|
|
// && nl->ToString(nl->First(nl->Second(arelAttrs))) == "WayTagValue"
|
||
|
|
// && FText::checkType(nl->Second(nl->First(arelAttrs)))
|
||
|
|
// && FText::checkType(nl->Second(nl->Second(arelAttrs)))) {
|
||
|
|
// return nl->SymbolAtom(raster2::sint::BasicType());
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// return listutils::typeError("Second argument must be an nrel(... (WayInfo "
|
||
|
|
// "(arel (tuple ((WayTagKey text) (WayTagValue text))))))");
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// int createMaxspeedRasterVM(Word* args, Word& result, int message,Word& local,
|
||
|
|
// Supplier s) {
|
||
|
|
// result = qp->ResultStorage(s);
|
||
|
|
// raster2::sint *hgt = static_cast<raster2::sint*>(args[0].addr);
|
||
|
|
// NestedRelation *nrel = static_cast<NestedRelation*>(args[1].addr);
|
||
|
|
// RTree2TID *rtree = static_cast<RTree2TID*>(args[2].addr);
|
||
|
|
// MaxspeedRaster mr(hgt, nrel, rtree);
|
||
|
|
// raster2::sint *res = static_cast<raster2::sint*>(result.addr);
|
||
|
|
// res->setGrid(hgt->getGrid());
|
||
|
|
// raster2::sint::storage_type& rs = hgt->getStorage();
|
||
|
|
// for (raster2::sint::iter_type it = rs.begin(),e = rs.end(); it != e; ++it){
|
||
|
|
// raster2::RasterIndex<2> pos = it.getIndex();
|
||
|
|
// int maxspeed = mr.getMaxspeed(pos);
|
||
|
|
// res->set(pos, maxspeed);
|
||
|
|
// }
|
||
|
|
// return 0;
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// struct createMaxspeedRasterInfo : OperatorInfo {
|
||
|
|
// createMaxspeedRasterInfo() {
|
||
|
|
// name = "createMaxspeedRaster";
|
||
|
|
// signature = raster2::sint::BasicType() + " x nrel(... (WayInfo (arel
|
||
|
|
// (tuple((WayTagKey text) (WayTagValue text)))))) x rtree" + "
|
||
|
|
// -> " + raster2::sint::BasicType();
|
||
|
|
// syntax = "createMaxspeedRaster( _ , _ , _ )";
|
||
|
|
// meaning = "Creates an sint raster where every tile holds the maximum"
|
||
|
|
// "speed (kph) permitted on the roads inside the tile.";
|
||
|
|
// }
|
||
|
|
// };
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createTileAreas~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// ListExpr createTileAreasTM(ListExpr args) {
|
||
|
|
// if (!nl->HasLength(args, 1)) {
|
||
|
|
// return listutils::typeError("One argument expected");
|
||
|
|
// }
|
||
|
|
// if (!raster2::sint::checkType(nl->First(args))) {
|
||
|
|
// return listutils::typeError("First argument must be an sint");
|
||
|
|
// }
|
||
|
|
// return nl->SymbolAtom(Tileareas::BasicType());
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// int createTileAreasVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
// Supplier s) {
|
||
|
|
// result = qp->ResultStorage(s);
|
||
|
|
// raster2::sint *hgt = static_cast<raster2::sint*>(args[0].addr);
|
||
|
|
// Tileareas *res = static_cast<Tileareas*>(result.addr);
|
||
|
|
// res->retrieveAreas(hgt);
|
||
|
|
// res->recordRoadCourses(hgt);
|
||
|
|
// return 0;
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// struct createTileAreasInfo : OperatorInfo {
|
||
|
|
// createTileAreasInfo() {
|
||
|
|
// name = "createTileAreas";
|
||
|
|
// signature = raster2::sint::BasicType() + " -> " + Tileareas::BasicType();
|
||
|
|
// syntax = "createTileAreas( _ )";
|
||
|
|
// meaning = "Stores all areas with tiles having the same value and all "
|
||
|
|
// "possible transitions from one area to another.";
|
||
|
|
// }
|
||
|
|
// };
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~restoreTraj~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// ListExpr restoreTrajTM(ListExpr args) {
|
||
|
|
// if (!nl->HasLength(args, 10)) {
|
||
|
|
// return listutils::typeError("Ten arguments expected.");
|
||
|
|
// }
|
||
|
|
// if (!BTree::checkType(nl->Second(args))) {
|
||
|
|
// return listutils::typeError("Second argument must be a btree");
|
||
|
|
// }
|
||
|
|
// if (!RTree2TID::checkType(nl->Third(args))) {
|
||
|
|
// return listutils::typeError("Third argument must be an rtree");
|
||
|
|
// }
|
||
|
|
// if (!raster2::sint::checkType(nl->Fourth(args))) { // elevation raster file
|
||
|
|
// return listutils::typeError("Fourth argument must be an sint");
|
||
|
|
// }
|
||
|
|
// if (!nl->Equal(nl->SymbolAtom(Hash::BasicType()),
|
||
|
|
// nl->First(nl->Fifth(args)))
|
||
|
|
// || !CcInt::checkType(nl->Third(nl->Fifth(args)))) {
|
||
|
|
// return listutils::typeError("Fifth argument must be a hash file");
|
||
|
|
// }
|
||
|
|
// if (!raster2::sint::checkType(nl->Sixth(args))) { // maxspeed raster file
|
||
|
|
// return listutils::typeError("Sixth argument must be an sint");
|
||
|
|
// }
|
||
|
|
// if (!Tileareas::checkType(nl->Seventh(args))) { // tileareas
|
||
|
|
// return listutils::typeError("Seventh argument must be a tileareas");
|
||
|
|
// }
|
||
|
|
// for (int i = 8; i <= 10; i++) {
|
||
|
|
// if (!MLabel::checkType(nl->Nth(i, args))) {
|
||
|
|
// std::stringstream sstr;
|
||
|
|
// sstr << "Argument " << i << " must be an mlabel";
|
||
|
|
// return listutils::typeError(sstr.str());
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// if (Relation::checkType(nl->First(args))) { // extended edges relation
|
||
|
|
// if (Tuple::checkType(nl->First(nl->Rest(nl->First(args))))) {
|
||
|
|
// ListExpr attrList =
|
||
|
|
// nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
// if (nl->ListLength(attrList) != 5) {
|
||
|
|
// return listutils::typeError("Edges relation must have 5 attributes");
|
||
|
|
// }
|
||
|
|
// if (!LongInt::checkType(nl->Second(nl->First(attrList)))) {
|
||
|
|
// return listutils::typeError("Edges: type error in first attribute");
|
||
|
|
// }
|
||
|
|
// if (!FText::checkType(nl->Second(nl->Second(attrList)))) {
|
||
|
|
// return listutils::typeError("Edges: type error in second attribute");
|
||
|
|
// }
|
||
|
|
// if (!SimpleLine::checkType(nl->Second(nl->Third(attrList)))) {
|
||
|
|
// return listutils::typeError("Edges: type error in third attribute");
|
||
|
|
// }
|
||
|
|
// if (!CcString::checkType(nl->Second(nl->Fourth(attrList)))) {
|
||
|
|
// return listutils::typeError("Edges: type error in fourth attribute");
|
||
|
|
// }
|
||
|
|
// if (!CcInt::checkType(nl->Second(nl->Fifth(attrList)))) {
|
||
|
|
// return listutils::typeError("Edges: type error in fifth attribute");
|
||
|
|
// }
|
||
|
|
// return nl->TwoElemList(listutils::basicSymbol<Stream<Rectangle<2> > >
|
||
|
|
// (),
|
||
|
|
// listutils::basicSymbol<Rectangle<2> >());
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// return listutils::typeError("Argument types must be rel(tuple(longint, "
|
||
|
|
// text, "
|
||
|
|
// "sline, string, int)) x btree x rtree x sint x "
|
||
|
|
// "hash x sint x tileareas x mlabel x mlabel x mlabel");
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// int restoreTrajVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
// Supplier s) {
|
||
|
|
// Relation *edgesRel = static_cast<Relation*>(args[0].addr);
|
||
|
|
// BTree *heightBtree = static_cast<BTree*>(args[1].addr);
|
||
|
|
// RTree2TID *segmentsRtree = static_cast<RTree2TID*>(args[2].addr);
|
||
|
|
// raster2::sint *raster = static_cast<raster2::sint*>(args[3].addr);
|
||
|
|
// Hash *rhash = static_cast<Hash*>(args[4].addr);
|
||
|
|
// raster2::sint *maxspeedRaster = static_cast<raster2::sint*>(args[5].addr);
|
||
|
|
// Tileareas *ta = static_cast<Tileareas*>(args[6].addr);
|
||
|
|
// MLabel *direction = static_cast<MLabel*>(args[7].addr);
|
||
|
|
// MLabel *height = static_cast<MLabel*>(args[8].addr);
|
||
|
|
// MLabel *speed = static_cast<MLabel*>(args[9].addr);
|
||
|
|
// RestoreTrajLI *li = static_cast<RestoreTrajLI*>(local.addr);
|
||
|
|
// switch (message) {
|
||
|
|
// case OPEN: {
|
||
|
|
// if (li) {
|
||
|
|
// delete li;
|
||
|
|
// local.addr = 0;
|
||
|
|
// }
|
||
|
|
// li = new RestoreTrajLI(edgesRel, heightBtree, segmentsRtree, raster,
|
||
|
|
// rhash, maxspeedRaster, ta, height, direction, speed);
|
||
|
|
// local.addr = li;
|
||
|
|
// return 0;
|
||
|
|
// }
|
||
|
|
// case REQUEST: {
|
||
|
|
// result.addr = li ? li->nextCandidate() : 0;
|
||
|
|
// return result.addr ? YIELD : CANCEL;
|
||
|
|
// }
|
||
|
|
// case CLOSE: {
|
||
|
|
// if (local.addr) {
|
||
|
|
// li = (RestoreTrajLI*)local.addr;
|
||
|
|
// delete li;
|
||
|
|
// local.addr = 0;
|
||
|
|
// }
|
||
|
|
// return 0;
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// return 0;
|
||
|
|
// }
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
// struct restoreTrajInfo : OperatorInfo {
|
||
|
|
// restoreTrajInfo() {
|
||
|
|
// name = "restoreTraj";
|
||
|
|
// signature = "rel(tuple(longint,text,sline,string, int)) x btree x rtree "
|
||
|
|
// "x sint x hash x sint x mlabel x mlabel x mlabel";
|
||
|
|
// syntax = "restoreTraj( _ , _ , _ , _ , _ , _ , _ , _ , _)";
|
||
|
|
// meaning = "Restores the original trajectory (mpoint) from symbolic "
|
||
|
|
// "direction, height, and speed information as well as a road "
|
||
|
|
// "network with elevation data.";
|
||
|
|
// }
|
||
|
|
// };
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~getPatterns~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr getPatternsTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 6) && !nl->HasLength(args, 7)) {
|
||
|
|
return listutils::typeError("Six or seven arguments expected");
|
||
|
|
}
|
||
|
|
if (!Relation::checkType(nl->First(args))) {
|
||
|
|
return listutils::typeError("1st argument is not a relation");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Second(args))) {
|
||
|
|
return listutils::typeError("2nd argument is not an attribute name");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Third(args))) {
|
||
|
|
return listutils::typeError("3rd argument is not an attribute name");
|
||
|
|
}
|
||
|
|
ListExpr attrs = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
string attrnameTextual = nl->SymbolValue(nl->Second(args));
|
||
|
|
string attrnameSpatial = nl->SymbolValue(nl->Third(args));
|
||
|
|
ListExpr type;
|
||
|
|
int indexTextual = listutils::findAttribute(attrs, attrnameTextual, type);
|
||
|
|
if (indexTextual == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrnameTextual + " not found");
|
||
|
|
}
|
||
|
|
int indexSpatial = listutils::findAttribute(attrs, attrnameSpatial, type);
|
||
|
|
if (indexSpatial == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrnameSpatial + " not found");
|
||
|
|
}
|
||
|
|
if (!CcReal::checkType(nl->Fourth(args))) {
|
||
|
|
return listutils::typeError("4th argument is not a real number");
|
||
|
|
}
|
||
|
|
if (!CcInt::checkType(nl->Fifth(args))) {
|
||
|
|
return listutils::typeError("5th argument is not an integer");
|
||
|
|
}
|
||
|
|
if (!CcInt::checkType(nl->Sixth(args))) {
|
||
|
|
return listutils::typeError("6th argument is not an integer");
|
||
|
|
}
|
||
|
|
if (nl->HasLength(args, 7)) {
|
||
|
|
if (!Geoid::checkType(nl->Seventh(args))) {
|
||
|
|
return listutils::typeError("7th argument is not a geoid");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ListExpr outputAttrs = nl->TwoElemList(
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Pattern"),
|
||
|
|
nl->SymbolAtom(FText::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Support"),
|
||
|
|
nl->SymbolAtom(CcReal::BasicType())));
|
||
|
|
return nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(indexTextual - 1),
|
||
|
|
nl->IntAtom(indexSpatial - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
outputAttrs)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int getPatternsVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
T* li = (T*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
Geoid *geoid = 0;
|
||
|
|
int geoidSpecified = (qp->GetNoSons(s) == 9 ? 1 : 0);
|
||
|
|
Relation *rel = static_cast<Relation*>(args[0].addr);
|
||
|
|
CcReal *suppmin = static_cast<CcReal*>(args[3].addr);
|
||
|
|
CcInt *atomsmin = static_cast<CcInt*>(args[4].addr);
|
||
|
|
CcInt *atomsmax = static_cast<CcInt*>(args[5].addr);
|
||
|
|
if (geoidSpecified == 1) {
|
||
|
|
geoid = static_cast<Geoid*>(args[6].addr);
|
||
|
|
if (!geoid->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CcInt *posTextual = static_cast<CcInt*>(args[6+geoidSpecified].addr);
|
||
|
|
CcInt *posSpatial = static_cast<CcInt*>(args[7+geoidSpecified].addr);
|
||
|
|
if (!suppmin->IsDefined() || !atomsmin->IsDefined()
|
||
|
|
|| !atomsmax->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (suppmin->GetValue() > 0 && suppmin->GetValue() <= 1
|
||
|
|
&& atomsmin->GetValue() > 0 && atomsmax->GetValue() > 0
|
||
|
|
&& atomsmin->GetValue() <= atomsmax->GetValue()) {
|
||
|
|
local.addr = new T(rel,
|
||
|
|
NewPair<int, int>(posTextual->GetValue(), posSpatial->GetValue()),
|
||
|
|
suppmin->GetValue(), atomsmin->GetValue(), atomsmax->GetValue(),
|
||
|
|
geoid, qp->GetMemorySize(s));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "the minimum support has to be in (0,1], and the minimum number"
|
||
|
|
" of atoms must be at least 1" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? GetPatternsLI::getNextResult(li->agg,li->tupleType) :0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct getPatternsInfo : OperatorInfo {
|
||
|
|
getPatternsInfo() {
|
||
|
|
name = "getPatterns";
|
||
|
|
signature = "rel(tuple(X)) x ATTR x ATTR x real x int --> "
|
||
|
|
"stream(tuple(Pattern: text, Support: real))";
|
||
|
|
syntax = "_ getPatterns[ _ , _ , _ , _ , _ ]";
|
||
|
|
meaning = "Computes patterns for spatio-textual attributes of movement "
|
||
|
|
"data (mpoint, mlabel). The numeric parameters represent the "
|
||
|
|
"patterns' minimum support and the minimum and maximum number "
|
||
|
|
"of atoms for each pattern, respectively.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const string getPatternsSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> rel(tuple(X)) x ATTR x ATTR x real x int x int --> \n"
|
||
|
|
"stream(tuple(Pattern: text, Support: real))</text--->"
|
||
|
|
"<text> _ getPatterns[ _ , _ , _ , _ , _ ] </text--->"
|
||
|
|
"<text> Computes patterns for spatio-textual attributes of movement data \n"
|
||
|
|
"(mpoint, mlabel). The numeric parameters represent the patterns' minimum \n"
|
||
|
|
"support and the minimum and maximum number of atoms for each pattern, \n"
|
||
|
|
"respectively.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \""
|
||
|
|
"getPatterns[Trajectory, X, 0.5, 1, 5] count </text--->) )";
|
||
|
|
|
||
|
|
Operator getPatterns("getPatterns", getPatternsSpec,
|
||
|
|
getPatternsVM<GetPatternsLI>, Operator::SimpleSelect, getPatternsTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createfptree~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
Used for FP-tree and Projected Databases
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
ListExpr createMiningStructureTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 4) && !nl->HasLength(args, 5)) {
|
||
|
|
return listutils::typeError("Four or five arguments expected");
|
||
|
|
}
|
||
|
|
if (!Relation::checkType(nl->First(args))) {
|
||
|
|
return listutils::typeError("1st argument is not a relation");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Second(args))) {
|
||
|
|
return listutils::typeError("2nd argument is not an attribute name");
|
||
|
|
}
|
||
|
|
if (!listutils::isSymbol(nl->Third(args))) {
|
||
|
|
return listutils::typeError("3rd argument is not an attribute name");
|
||
|
|
}
|
||
|
|
ListExpr attrs = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
string attrnameTextual = nl->SymbolValue(nl->Second(args));
|
||
|
|
string attrnameSpatial = nl->SymbolValue(nl->Third(args));
|
||
|
|
ListExpr type;
|
||
|
|
int indexTextual = listutils::findAttribute(attrs, attrnameTextual, type);
|
||
|
|
if (indexTextual == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrnameTextual + " not found");
|
||
|
|
}
|
||
|
|
int indexSpatial = listutils::findAttribute(attrs, attrnameSpatial, type);
|
||
|
|
if (indexSpatial == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrnameSpatial + " not found");
|
||
|
|
}
|
||
|
|
if (!CcReal::checkType(nl->Fourth(args))) {
|
||
|
|
return listutils::typeError("4th argument is not a real number");
|
||
|
|
}
|
||
|
|
if (nl->HasLength(args, 5)) {
|
||
|
|
if (!Geoid::checkType(nl->Seventh(args))) {
|
||
|
|
return listutils::typeError("5th argument is not a geoid");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(indexTextual - 1),
|
||
|
|
nl->IntAtom(indexSpatial - 1)),
|
||
|
|
nl->SymbolAtom(T::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int createMiningStructureVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
T *resultPtr = (T*)result.addr;
|
||
|
|
resultPtr->clear();
|
||
|
|
Geoid *geoid = 0;
|
||
|
|
int geoidSpecified = (qp->GetNoSons(s) == 7 ? 1 : 0);
|
||
|
|
Relation *rel = static_cast<Relation*>(args[0].addr);
|
||
|
|
CcReal *suppmin = static_cast<CcReal*>(args[3].addr);
|
||
|
|
if (geoidSpecified == 1) {
|
||
|
|
geoid = static_cast<Geoid*>(args[4].addr);
|
||
|
|
if (!geoid->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CcInt *posTextual = static_cast<CcInt*>(args[4+geoidSpecified].addr);
|
||
|
|
CcInt *posSpatial = static_cast<CcInt*>(args[5+geoidSpecified].addr);
|
||
|
|
if (!suppmin->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (suppmin->GetValue() <= 0 || suppmin->GetValue() > 1) {
|
||
|
|
cout << "the minimum support has to be in (0,1]" << endl;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
RelAgg *agg = new RelAgg();
|
||
|
|
agg->scanRelation(rel, NewPair<int, int>(posTextual->GetValue(),
|
||
|
|
posSpatial->GetValue()), geoid);
|
||
|
|
agg->filter(suppmin->GetValue(), qp->GetMemorySize(s));
|
||
|
|
resultPtr->initialize(suppmin->GetValue(), agg);
|
||
|
|
resultPtr->construct();
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string createfptreeSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> rel(tuple(X)) x ATTR x ATTR x real --> fptree</text--->"
|
||
|
|
"<text> _ createfptree[ _ , _ , _ ] </text--->"
|
||
|
|
"<text> Computes an FP-tree from a relation, two attribute names, and a \n"
|
||
|
|
"real number (minimum support).</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createfptree[Trajectory, X, 0.5] getTypeNL\n"
|
||
|
|
"</text--->) )";
|
||
|
|
|
||
|
|
Operator createfptree("createfptree", createfptreeSpec,
|
||
|
|
createMiningStructureVM<FPTree>, Operator::SimpleSelect,
|
||
|
|
createMiningStructureTM<FPTree>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~minefptree~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
ListExpr mineStructureTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 3)) {
|
||
|
|
return listutils::typeError("Three arguments expected");
|
||
|
|
}
|
||
|
|
if (!T::checkType(nl->First(args))) {
|
||
|
|
return listutils::typeError("1st argument is not a " + T::BasicType());
|
||
|
|
}
|
||
|
|
if (!CcInt::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError("2nd argument is not an integer");
|
||
|
|
}
|
||
|
|
if (!CcInt::checkType(nl->Third(args))) {
|
||
|
|
return listutils::typeError("3rd argument is not an integer");
|
||
|
|
}
|
||
|
|
ListExpr outputAttrs = nl->TwoElemList(
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Pattern"),
|
||
|
|
nl->SymbolAtom(FText::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Support"),
|
||
|
|
nl->SymbolAtom(CcReal::BasicType())));
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()), outputAttrs));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T, class L>
|
||
|
|
int mineStructureVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
L* li = (L*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
T *structure = static_cast<T*>(args[0].addr);
|
||
|
|
CcInt *amin = static_cast<CcInt*>(args[1].addr);
|
||
|
|
CcInt *amax = static_cast<CcInt*>(args[2].addr);
|
||
|
|
if (!amin->IsDefined() || !amax->IsDefined()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (amin->GetValue() > 0 && amax->GetValue() > 0
|
||
|
|
&& amin->GetValue() <= amax->GetValue()) {
|
||
|
|
local.addr = new L(structure, amin->GetValue(), amax->GetValue());
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "condition 0 < minNoAtoms <= maxNoAtoms not fulfilled" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->getNextResult() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string minefptreeSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> fptree x int x int --> stream(tuple(Pattern: text, Support: real\n"
|
||
|
|
"))</text--->"
|
||
|
|
"<text> _ minefptree[ _ , _ ] </text--->"
|
||
|
|
"<text> Retrieves the frequent patterns from an FP-tree.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createfptree[Trajectory, X, 0.5] minefptree[1, 5] count\n"
|
||
|
|
"</text--->) )";
|
||
|
|
|
||
|
|
Operator minefptree("minefptree", minefptreeSpec,
|
||
|
|
mineStructureVM<FPTree, MineFPTreeLI>,
|
||
|
|
Operator::SimpleSelect, mineStructureTM<FPTree>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createprojecteddb~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
See ~createStructureTM~
|
||
|
|
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string createprojecteddbSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> rel x ATTR x ATTR x real ( x geoid) --> projecteddb </text--->"
|
||
|
|
"<text> _ createprojecteddb [ _ , _ , _ , _ ] </text--->"
|
||
|
|
"<text> Computes the auxiliary structure for PrefixSpan.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createprojecteddb[Trajectory, X, 0.5] getTypeNL</text--->) )";
|
||
|
|
|
||
|
|
|
||
|
|
Operator createprojecteddb("createprojecteddb", createprojecteddbSpec,
|
||
|
|
createMiningStructureVM<ProjectedDB>, Operator::SimpleSelect,
|
||
|
|
createMiningStructureTM<ProjectedDB>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~prefixSpan~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
See ~getPatternsTM~
|
||
|
|
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
See ~getPatternsVM
|
||
|
|
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string prefixSpanSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> projecteddb x int x int --> stream(tuple(Pattern: text, \n"
|
||
|
|
"Support: real))</text--->"
|
||
|
|
"<text> _ prefixSpan[ _ , _ ] </text--->"
|
||
|
|
"<text> Retrieves the frequent patterns from a projecteddb.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createprojecteddb[Trajectory, X, 0.5] prefixSpan[1, 2] count</text--->) )";
|
||
|
|
|
||
|
|
Operator prefixSpan("prefixSpan", prefixSpanSpec,
|
||
|
|
mineStructureVM<ProjectedDB, PrefixSpanLI>,
|
||
|
|
Operator::SimpleSelect, mineStructureTM<ProjectedDB>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createverticaldb~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
See ~createStructureTM~
|
||
|
|
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string createverticaldbSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> rel x ATTR x ATTR x real ( x geoid) --> verticaldb </text--->"
|
||
|
|
"<text> _ createverticaldb [ _ , _ , _ , _ ] </text--->"
|
||
|
|
"<text> Computes the auxiliary structure for Spade.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createverticaldb[Trajectory, X, 0.5] getTypeNL</text--->) )";
|
||
|
|
|
||
|
|
|
||
|
|
Operator createverticaldb("createverticaldb", createverticaldbSpec,
|
||
|
|
createMiningStructureVM<VerticalDB>, Operator::SimpleSelect,
|
||
|
|
createMiningStructureTM<VerticalDB>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~spade~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
See ~getPatternsTM~
|
||
|
|
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
See ~getPatternsVM
|
||
|
|
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string spadeSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> verticaldb x int x int --> stream(tuple(Pattern: text, \n"
|
||
|
|
"Support: real))</text--->"
|
||
|
|
"<text> _ spade[ _ , _ ] </text--->"
|
||
|
|
"<text> Retrieves the frequent patterns from a verticaldb.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[X: [const mpoint value undef]] consume \n"
|
||
|
|
"createverticaldb[Trajectory, X, 0.5] spade[1, 2] count</text--->) )";
|
||
|
|
|
||
|
|
Operator spade("spade", spadeSpec, mineStructureVM<VerticalDB, SpadeLI>,
|
||
|
|
Operator::SimpleSelect, mineStructureTM<VerticalDB>);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~getlabels~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr getlabelsTM(ListExpr args) {
|
||
|
|
string err = "Operator expects a symbolic trajectory.";
|
||
|
|
if (!nl->HasLength(args, 1)) {
|
||
|
|
return listutils::typeError(err + " ("
|
||
|
|
+ stringutils::int2str(nl->ListLength(args)) + " arguments instead of 2)");
|
||
|
|
}
|
||
|
|
if (!Tools::isSymbolicType(nl->First(args))) {
|
||
|
|
return listutils::typeError(err + " (wrong type)");
|
||
|
|
}
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Stream<Attribute>::BasicType()),
|
||
|
|
nl->SymbolAtom(FText::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mappings}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int getlabelsVM(Word* args, Word& result, int message, Word& local, Supplier s){
|
||
|
|
GetLabelsLI<T> *li = (GetLabelsLI<T>*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
T* src = static_cast<T*>(args[0].addr);
|
||
|
|
if (!src->IsDefined()) {
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
local.addr = new GetLabelsLI<T>(*src);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->nextResult() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
ValueMapping getlabelsVMs[] = {getlabelsVM<MLabel>, getlabelsVM<MLabels>,
|
||
|
|
getlabelsVM<MPlace>, getlabelsVM<MPlaces>};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string getlabelsSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> stream(tuple(X)) x ATTR -> set(text) </text--->"
|
||
|
|
"<text> getlabels ( _ ) </text--->"
|
||
|
|
"<text> Collects and outputs all labels into the stream.</text--->"
|
||
|
|
"<text> query getlabels(Dotraj feed extract[Trajectory])</text--->) )";
|
||
|
|
|
||
|
|
Operator getlabels("getlabels", getlabelsSpec, 4, getlabelsVMs,
|
||
|
|
distancesymSelect, getlabelsTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createlexicon~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createlexiconTM(ListExpr args) {
|
||
|
|
string err = "Operator expects a stream of tuples and the name of an "
|
||
|
|
"mlabel(s) or mplace(s) attribute.";
|
||
|
|
if (!nl->HasLength(args, 2)) {
|
||
|
|
return listutils::typeError(err + " ("
|
||
|
|
+ stringutils::int2str(nl->ListLength(args)) + " arguments instead of 2)");
|
||
|
|
}
|
||
|
|
if (!listutils::isTupleStream(nl->First(args))) {
|
||
|
|
return listutils::typeError(err + " (no tuple stream received)");
|
||
|
|
}
|
||
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
||
|
|
string attrName;
|
||
|
|
int pos = -1;
|
||
|
|
attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
ListExpr type;
|
||
|
|
pos = listutils::findAttribute(attrList, attrName, type);
|
||
|
|
if (pos == 0 || !Tools::isSymbolicType(type)) {
|
||
|
|
return listutils::typeError(err + " (" + attrName + " is not the name of "
|
||
|
|
+ "a symbolic attribute)");
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(pos - 1)),
|
||
|
|
nl->SymbolAtom(InvertedFile::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int createlexiconVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
Stream<Tuple> stream = static_cast<Stream<Tuple> >(args[0].addr);
|
||
|
|
int attrno = (static_cast<CcInt*>(args[2].addr))->GetValue();
|
||
|
|
InvertedFile *inv = static_cast<InvertedFile*>(result.addr);
|
||
|
|
inv->setParams(false, 1, "");
|
||
|
|
vector<string> labels;
|
||
|
|
multiset<string> allLabels;
|
||
|
|
set<string> justInserted;
|
||
|
|
stream.open();
|
||
|
|
Tuple* tuple = stream.request();
|
||
|
|
int tupleCounter = 0;
|
||
|
|
while (tuple) {
|
||
|
|
tupleCounter++;
|
||
|
|
T *src = (T*)(tuple->GetAttribute(attrno));
|
||
|
|
src->InsertLabels(labels);
|
||
|
|
for (auto it : labels) {
|
||
|
|
if (justInserted.find(it) == justInserted.end()) { // not present yet
|
||
|
|
justInserted.insert(it);
|
||
|
|
allLabels.insert(it);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
labels.clear();
|
||
|
|
justInserted.clear();
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
tuple = stream.request();
|
||
|
|
}
|
||
|
|
stream.close();
|
||
|
|
size_t maxMem = 0;/*qp->GetMemorySize(s) * 1024 * 1024*/
|
||
|
|
size_t trieCacheSize = maxMem / 20;
|
||
|
|
if (trieCacheSize < 4096) {
|
||
|
|
trieCacheSize = 4096;
|
||
|
|
}
|
||
|
|
size_t invCacheSize;
|
||
|
|
if (trieCacheSize + 4096 > maxMem) {
|
||
|
|
invCacheSize = 4096;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
invCacheSize = maxMem - trieCacheSize;
|
||
|
|
}
|
||
|
|
appendcache::RecordAppendCache* cache = inv->createAppendCache(invCacheSize);
|
||
|
|
TrieNodeCacheType* trieCache = inv->createTrieCache(trieCacheSize);
|
||
|
|
string curLabel = *(allLabels.begin());
|
||
|
|
int freq(0), pos(0);
|
||
|
|
for (auto it : allLabels) {
|
||
|
|
if (it == curLabel) {
|
||
|
|
freq++;
|
||
|
|
}
|
||
|
|
else { // next label
|
||
|
|
inv->insertString(pos, curLabel, freq, 0, cache, trieCache);
|
||
|
|
curLabel = it;
|
||
|
|
freq = 1;
|
||
|
|
pos++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
inv->insertString(pos, curLabel, freq, 0, cache, trieCache);
|
||
|
|
inv->insertString(tupleCounter, "zzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0, 0, cache,
|
||
|
|
trieCache);
|
||
|
|
// TODO: find out why final entry cannot be accessed
|
||
|
|
delete trieCache;
|
||
|
|
delete cache;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createlexiconSpec : OperatorInfo {
|
||
|
|
createlexiconSpec() {
|
||
|
|
name = "createlexicon";
|
||
|
|
signature = "stream(tuple(X)) x ATTR --> invfile";
|
||
|
|
syntax = "_ createlexicon [ _ ]";
|
||
|
|
meaning = "Creates a lexicon of all occurring labels, stores their "
|
||
|
|
"position according to lexicographic order and the number of "
|
||
|
|
"tuples they occur in.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
ValueMapping createlexiconVMs[] = {createlexiconVM<MLabel>,
|
||
|
|
createlexiconVM<MLabels>, createlexiconVM<MPlace>, createlexiconVM<MPlaces>};
|
||
|
|
|
||
|
|
Operator createlexicon(createlexiconSpec(), createlexiconVMs,
|
||
|
|
derivegroupsSelect, createlexiconTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~frequencyvector~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr frequencyvectorTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting mT x inv (x bool), T in {label(s),place(s)}";
|
||
|
|
if (!nl->HasLength(args, 2) && !nl->HasLength(args, 3)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
ListExpr arg1 = nl->First(args);
|
||
|
|
if (!MLabel::checkType(arg1) && !MLabels::checkType(arg1) &&
|
||
|
|
!MPlace::checkType(arg1) && !MPlaces::checkType(arg1)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
if (!InvertedFile::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
if (nl->HasLength(args, 3)) {
|
||
|
|
if (!CcBool::checkType(nl->Third(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->TwoElemList(nl->SymbolAtom(Vector::BasicType()),
|
||
|
|
nl->SymbolAtom(CcReal::BasicType()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<class T>
|
||
|
|
int frequencyvectorVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
T* src = static_cast<T*>(args[0].addr);
|
||
|
|
InvertedFile* inv = static_cast<InvertedFile*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
collection::Collection* res =
|
||
|
|
static_cast<collection::Collection*>(result.addr);
|
||
|
|
res->Clear();
|
||
|
|
if (!src->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
bool useIdf = false;
|
||
|
|
if (qp->GetNoSons(s) == 3) {
|
||
|
|
CcBool *ccb = static_cast<CcBool*>(args[2].addr);
|
||
|
|
if (!ccb->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
useIdf = ccb->GetValue();
|
||
|
|
}
|
||
|
|
vector<double> fv(inv->getNoEntries() - 1, 0.0);
|
||
|
|
src->FrequencyVector(*inv, fv, useIdf);
|
||
|
|
for (unsigned int i = 0; i < fv.size(); i++) {
|
||
|
|
CcReal *elem = new CcReal(true, fv[i]);
|
||
|
|
res->Insert(elem, 1);
|
||
|
|
elem->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct frequencyvectorSpec : OperatorInfo {
|
||
|
|
frequencyvectorSpec() {
|
||
|
|
name = "frequencyvector";
|
||
|
|
signature = "mT x invfile (x bool) -> vector(real), where T in {label(s), "
|
||
|
|
"place(s)}";
|
||
|
|
syntax = "frequencyvector(_, _)";
|
||
|
|
meaning = "Computes the frequency vector of the labels of a symbolic "
|
||
|
|
"trajectory, according to the labels stored in the trie. The "
|
||
|
|
"boolean value indicates whether idf (inverted document "
|
||
|
|
"frequency) is applied (false by default).";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
ValueMapping frequencyvectorVMs[] = {frequencyvectorVM<MLabel>,
|
||
|
|
frequencyvectorVM<MLabels>, frequencyvectorVM<MPlace>,
|
||
|
|
frequencyvectorVM<MPlaces>};
|
||
|
|
|
||
|
|
Operator frequencyvector(frequencyvectorSpec(), frequencyvectorVMs,
|
||
|
|
distancesymSelect, frequencyvectorTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~cosinesim~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr cosinesimTM(ListExpr args) {
|
||
|
|
const string errMsg = "Expecting vector(int) x vector(int)";
|
||
|
|
if (!nl->HasLength(args, 2)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
||
|
|
if (!collection::Collection::KindCheck(nl->First(args), errorInfo) ||
|
||
|
|
!collection::Collection::KindCheck(nl->Second(args), errorInfo)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
string ctype1 = nl->SymbolValue(nl->First(nl->First(args)));
|
||
|
|
string ctype2 = nl->SymbolValue(nl->First(nl->Second(args)));
|
||
|
|
if (ctype1 != Vector::BasicType() || ctype2 != Vector::BasicType()) {
|
||
|
|
return listutils::typeError(errMsg + " two vectors required");
|
||
|
|
}
|
||
|
|
string etype1 = nl->SymbolValue(nl->Second(nl->First(args)));
|
||
|
|
string etype2 = nl->SymbolValue(nl->Second(nl->Second(args)));
|
||
|
|
if (etype1 != CcReal::BasicType() || etype2 != CcReal::BasicType()) {
|
||
|
|
return listutils::typeError(errMsg + " real type required");
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int cosinesimVM(Word* args, Word& result, int message, Word& local, Supplier s){
|
||
|
|
collection::Collection* v1 =
|
||
|
|
static_cast<collection::Collection*>(args[0].addr);
|
||
|
|
collection::Collection* v2 =
|
||
|
|
static_cast<collection::Collection*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcReal* res = (CcReal*)result.addr;
|
||
|
|
if (!v1->IsDefined() || !v2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (v1->GetNoComponents() != v2->GetNoComponents()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
res->Set(true, cosineSimilarity(*v1, *v2));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct cosinesimSpec : OperatorInfo {
|
||
|
|
cosinesimSpec() {
|
||
|
|
name = "cosinesim";
|
||
|
|
signature = "vector(real) x vector(real) -> real";
|
||
|
|
syntax = "cosinesim(_, _)";
|
||
|
|
meaning = "Computes the cosine similarity for two frequency vectors.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
Operator cosinesim(cosinesimSpec(), cosinesimVM, cosinesimTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~jaccardsim~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr jaccardsimTM(ListExpr args) {
|
||
|
|
const string errMsg = "vector(int) x vector(int) or mlabel(s) x mlabel(s) or "
|
||
|
|
"mplace(s) x mplace(s) expected";
|
||
|
|
if (!nl->HasLength(args, 2)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
if (MLabel::checkType(nl->First(args))) {
|
||
|
|
if (!MLabel::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (MLabels::checkType(nl->First(args))) {
|
||
|
|
if (!MLabels::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (MPlace::checkType(nl->First(args))) {
|
||
|
|
if (!MPlace::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (MPlaces::checkType(nl->First(args))) {
|
||
|
|
if (!MPlaces::checkType(nl->Second(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
||
|
|
if (!collection::Collection::KindCheck(nl->First(args), errorInfo) ||
|
||
|
|
!collection::Collection::KindCheck(nl->Second(args), errorInfo)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
string ctype1 = nl->SymbolValue(nl->First(nl->First(args)));
|
||
|
|
string ctype2 = nl->SymbolValue(nl->First(nl->Second(args)));
|
||
|
|
if (ctype1 != Vector::BasicType() || ctype2 != Vector::BasicType()) {
|
||
|
|
return listutils::typeError(errMsg + " two vectors required");
|
||
|
|
}
|
||
|
|
string etype1 = nl->SymbolValue(nl->Second(nl->First(args)));
|
||
|
|
string etype2 = nl->SymbolValue(nl->Second(nl->Second(args)));
|
||
|
|
if (etype1 != CcReal::BasicType() || etype2 != CcReal::BasicType()) {
|
||
|
|
return listutils::typeError(errMsg + " real type required");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mappings}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int jaccardsimFVVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
collection::Collection* v1 =
|
||
|
|
static_cast<collection::Collection*>(args[0].addr);
|
||
|
|
collection::Collection* v2 =
|
||
|
|
static_cast<collection::Collection*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcReal* res = (CcReal*)result.addr;
|
||
|
|
if (!v1->IsDefined() || !v2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (v1->GetNoComponents() != v2->GetNoComponents()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
res->Set(true, jaccardSimilarity(*v1, *v2));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class M>
|
||
|
|
int jaccardsimMLVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
M* m1 = static_cast<M*>(args[0].addr);
|
||
|
|
M* m2 = static_cast<M*>(args[1].addr);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
CcReal* res = (CcReal*)result.addr;
|
||
|
|
if (!m1->IsDefined() || !m2->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
set<string> allLabels1, allLabels2;
|
||
|
|
m1->InsertLabels(allLabels1);
|
||
|
|
m2->InsertLabels(allLabels2);
|
||
|
|
res->Set(true, jaccardSimilarity(allLabels1, allLabels2));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
ValueMapping jaccardsimVMs[] = {jaccardsimFVVM, jaccardsimMLVM<MLabel>,
|
||
|
|
jaccardsimMLVM<MLabels>, jaccardsimMLVM<MPlace>, jaccardsimMLVM<MPlaces>};
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Selection Function}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int jaccardsimSelect(ListExpr args) {
|
||
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
||
|
|
if (collection::Collection::KindCheck(nl->First(args), errorInfo)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (MLabel::checkType(nl->First(args))) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (MLabels::checkType(nl->First(args))) {
|
||
|
|
return 2;
|
||
|
|
}
|
||
|
|
if (MPlace::checkType(nl->First(args))) {
|
||
|
|
return 3;
|
||
|
|
}
|
||
|
|
if (MPlaces::checkType(nl->First(args))) {
|
||
|
|
return 4;
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct jaccardsimSpec : OperatorInfo {
|
||
|
|
jaccardsimSpec() {
|
||
|
|
name = "jaccardsim";
|
||
|
|
signature = "(vector(real) x vector(real)) | (mlabel(s) x mlabel(s)) | "
|
||
|
|
"(mplace(s) x mplace(s)) -> real";
|
||
|
|
syntax = "jaccardsim(_, _)";
|
||
|
|
meaning = "Computes the Jaccard similarity for two frequency vectors or "
|
||
|
|
"two mlabels.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
Operator jaccardsim(jaccardsimSpec(), jaccardsimVMs, jaccardsimSelect,
|
||
|
|
jaccardsimTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~createsplsemtraj~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr createsplsemtrajTM(ListExpr args) {
|
||
|
|
const string errMsg = "mpoint x mlabel x real [x geoid] expected";
|
||
|
|
if (!nl->HasLength(args, 3) && !nl->HasLength(args, 4)) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
if (!MPoint::checkType(nl->First(args)) ||
|
||
|
|
!MLabel::checkType(nl->Second(args)) ||
|
||
|
|
!CcReal::checkType(nl->Third(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
if (nl->HasLength(args, 4)) {
|
||
|
|
if (!Geoid::checkType(nl->Fourth(args))) {
|
||
|
|
return listutils::typeError(errMsg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(SplSemTraj::BasicType());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mappings}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int createsplsemtrajVM(Word* args, Word& result, int message, Word& local,
|
||
|
|
Supplier s) {
|
||
|
|
MPoint* mp = static_cast<MPoint*>(args[0].addr);
|
||
|
|
MLabel* ml = static_cast<MLabel*>(args[1].addr);
|
||
|
|
CcReal* tol = static_cast<CcReal*>(args[2].addr);
|
||
|
|
Geoid* geoid = 0;
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
SplSemTraj* res = (SplSemTraj*)result.addr;
|
||
|
|
if (!mp->IsDefined() || !ml->IsDefined() || !tol->IsDefined()) {
|
||
|
|
res->SetDefined(false);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (qp->GetNoSons(s) == 4) {
|
||
|
|
geoid = static_cast<Geoid*>(args[3].addr);
|
||
|
|
}
|
||
|
|
res->convertFromMPointMLabel(*mp, *ml, tol->GetValue(), geoid);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct createsplsemtrajSpec : OperatorInfo {
|
||
|
|
createsplsemtrajSpec() {
|
||
|
|
name = "createsplsemtraj";
|
||
|
|
signature = "mpoint x mlabel -> splsemtraj";
|
||
|
|
syntax = "createsplsemtraj(_, _)";
|
||
|
|
meaning = "Transforms an mpoint with corresponding mlabel into a "
|
||
|
|
"splsemtraj.";
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
Operator createsplsemtraj(createsplsemtrajSpec(), createsplsemtrajVM,
|
||
|
|
createsplsemtrajTM);
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Operator ~splitter~}
|
||
|
|
|
||
|
|
\subsection{Type Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr splitterTM(ListExpr args) {
|
||
|
|
if (!nl->HasLength(args, 6) && !nl->HasLength(args, 7)) {
|
||
|
|
return listutils::typeError("Six or seven arguments expected.");
|
||
|
|
}
|
||
|
|
if (!Stream<Tuple>::checkType(nl->First(args))) {
|
||
|
|
return listutils::typeError("First argument must be a stream.");
|
||
|
|
}
|
||
|
|
if (!Tuple::checkType(nl->First(nl->Rest(nl->First(args))))) {
|
||
|
|
return listutils::typeError("First argument must be a tuple stream.");
|
||
|
|
}
|
||
|
|
if (nl->AtomType(nl->Second(args)) != SymbolType) {
|
||
|
|
return listutils::typeError("Second argument must be an attribute name.");
|
||
|
|
}
|
||
|
|
if (!CcReal::checkType(nl->Third(args))) {
|
||
|
|
return listutils::typeError("Third argument must be a real number.");
|
||
|
|
}
|
||
|
|
if (!Duration::checkType(nl->Fourth(args))) {
|
||
|
|
return listutils::typeError("Fourth argument must be a duration.");
|
||
|
|
}
|
||
|
|
if (!CcInt::checkType(nl->Fifth(args))) {
|
||
|
|
return listutils::typeError("Fifth argument must be an integer.");
|
||
|
|
}
|
||
|
|
if (!CcReal::checkType(nl->Sixth(args))) {
|
||
|
|
return listutils::typeError("Sixth argument must be a real number.");
|
||
|
|
}
|
||
|
|
if (nl->HasLength(args, 7)) {
|
||
|
|
if (!Geoid::checkType(nl->Seventh(args))) {
|
||
|
|
return listutils::typeError("Seventh argument must be a geoid.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ListExpr attrList =
|
||
|
|
nl->First(nl->Rest(nl->First(nl->Rest(nl->First(args)))));
|
||
|
|
ListExpr attrType;
|
||
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
||
|
|
int i = listutils::findAttribute(attrList, attrName, attrType);
|
||
|
|
if (i == 0) {
|
||
|
|
return listutils::typeError("Attribute " + attrName + " not found.");
|
||
|
|
}
|
||
|
|
if (!SplSemTraj::checkType(attrType)) {
|
||
|
|
return listutils::typeError("Wrong attribute type, must be splsemtraj.");
|
||
|
|
}
|
||
|
|
ListExpr outputAttrs = nl->TwoElemList(
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Pattern"),
|
||
|
|
nl->SymbolAtom(FText::BasicType())),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom("Support"),
|
||
|
|
nl->SymbolAtom(CcReal::BasicType())));
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(i - 1)),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
outputAttrs)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Value Mapping}
|
||
|
|
|
||
|
|
*/
|
||
|
|
int splitterVM(Word* args, Word& result, int message, Word& local, Supplier s) {
|
||
|
|
Splitter* li = (Splitter*)local.addr;
|
||
|
|
switch (message) {
|
||
|
|
case OPEN: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
int attrNoPos = (qp->GetNoSons(s) == 8 ? 7 : 6);
|
||
|
|
CcReal *suppmin = static_cast<CcReal*>(args[2].addr);
|
||
|
|
DateTime *mtt = static_cast<DateTime*>(args[3].addr);
|
||
|
|
CcInt* maxNoAtoms = static_cast<CcInt*>(args[4].addr);
|
||
|
|
CcReal *eps = static_cast<CcReal*>(args[5].addr);
|
||
|
|
Geoid *geoid = 0;
|
||
|
|
if (qp->GetNoSons(s) == 8) {
|
||
|
|
geoid = static_cast<Geoid*>(args[6].addr);
|
||
|
|
}
|
||
|
|
CcInt *attrNo = static_cast<CcInt*>(args[attrNoPos].addr);
|
||
|
|
if (suppmin->IsDefined() && mtt->IsDefined() && eps->IsDefined() &&
|
||
|
|
maxNoAtoms->IsDefined()) {
|
||
|
|
if (suppmin->GetValue() <= 0.0 || suppmin->GetValue() > 1.0) {
|
||
|
|
cout << "invalid parameter, suppmin must be in (0,1]." << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (maxNoAtoms->GetValue() < 1) {
|
||
|
|
cout << "invalid parameter, maxNoAtoms must be >= 1." << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (eps->GetValue() < 0.0) {
|
||
|
|
cout << "invalid parameter, eps (tolerance) must >= 0." << endl;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
local.addr = new Splitter(args[0], suppmin->GetValue(), *mtt,
|
||
|
|
maxNoAtoms->GetValue(), eps->GetValue(),
|
||
|
|
geoid, (int)attrNo->GetValue());
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
cout << "undefined argument(s)" << endl;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
case REQUEST: {
|
||
|
|
result.addr = li ? li->next() : 0;
|
||
|
|
return result.addr ? YIELD : CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE: {
|
||
|
|
if (li) {
|
||
|
|
delete li;
|
||
|
|
local.addr = 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
\subsection{Operator Info}
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string splitterSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
||
|
|
"( <text> stream(tuple(X)) x ATTR x real x duration x real [x geoid]-> "
|
||
|
|
"stream(splsemtraj)" "</text--->"
|
||
|
|
"<text> tuplestream splitter[attrname, suppmin, deltaT, eps] </text--->"
|
||
|
|
"<text> Computes all fine-grained pattern according to Splitter algorithm."
|
||
|
|
" The second argument must be the name of an attribute in the tuple "
|
||
|
|
"stream of the type splsemtraj. The remaining parameters represent "
|
||
|
|
"the minimum support, the maximum transition time, and the spatial "
|
||
|
|
"tolerance, i.e., two places with the same label are treated as identical"
|
||
|
|
" if their distance is no more than eps.</text--->"
|
||
|
|
"<text> query Dotraj feed extend[SST: createsplsemtraj([const mpoint value "
|
||
|
|
"(((\"2012-01-01\" \"2012-01-01-00:30\" TRUE FALSE) (7.0 51.0 7.1 51.1)))"
|
||
|
|
"], .Trajectory, )] splitter[SST, 0.5, create_duration(0, 7200000), "
|
||
|
|
"1000.0] count</text--->) )";
|
||
|
|
|
||
|
|
Operator splitter("splitter", splitterSpec, splitterVM, Operator::SimpleSelect,
|
||
|
|
splitterTM);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
\section{Class ~SymbolicTrajectoryAlgebra~}
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
class SymbolicTrajectoryAlgebra : public Algebra {
|
||
|
|
public:
|
||
|
|
SymbolicTrajectoryAlgebra() : Algebra() {
|
||
|
|
|
||
|
|
AddTypeConstructor(&patternTC);
|
||
|
|
AddTypeConstructor(&tupleindexTC);
|
||
|
|
AddTypeConstructor(&tupleindex2TC);
|
||
|
|
AddTypeConstructor(&classifierTC);
|
||
|
|
AddTypeConstructor(&fptreeTC);
|
||
|
|
AddTypeConstructor(&projecteddbTC);
|
||
|
|
AddTypeConstructor(&verticaldbTC);
|
||
|
|
AddTypeConstructor(&splsemtrajTC);
|
||
|
|
splsemtrajTC.AssociateKind(Kind::DATA());
|
||
|
|
|
||
|
|
// AddTypeConstructor(&tileareasTC);
|
||
|
|
|
||
|
|
ValueMapping distanceVMs[] = {distanceVM<Label>, distanceVM<Labels>,
|
||
|
|
distanceVM<Place>, distanceVM<Places>, distanceVM<MLabel>,
|
||
|
|
distanceVM<MLabels>, distanceVM<MPlace>, distanceVM<MPlaces>, 0};
|
||
|
|
AddOperator(distanceInfo(), distanceVMs, distanceSelect, distanceTM);
|
||
|
|
|
||
|
|
ValueMapping distancesymVMs[] = {distancesymVM<MLabel>,
|
||
|
|
distancesymVM<MLabels>, distancesymVM<MPlace>, distancesymVM<MPlaces>, 0};
|
||
|
|
AddOperator(distancesymInfo(), distancesymVMs, distancesymSelect,
|
||
|
|
distancesymTM);
|
||
|
|
|
||
|
|
ValueMapping hybriddistanceVMs[] = {hybriddistanceVM<MLabel, false>,
|
||
|
|
hybriddistanceVM<MPlace, false>, hybriddistanceVM<MLabels, false>,
|
||
|
|
hybriddistanceVM<MLabel, true>, hybriddistanceVM<MPlace, true>,
|
||
|
|
hybriddistanceVM<MLabels, false>, 0};
|
||
|
|
AddOperator(hybriddistanceInfo(), hybriddistanceVMs, hybriddistanceSelect,
|
||
|
|
hybriddistanceTM);
|
||
|
|
|
||
|
|
AddOperator(gethybriddistanceparamsInfo(), gethybriddistanceparamsVM,
|
||
|
|
gethybriddistanceparamsTM);
|
||
|
|
|
||
|
|
AddOperator(&sethybriddistanceparam);
|
||
|
|
sethybriddistanceparam.SetUsesArgsInTypeMapping();
|
||
|
|
|
||
|
|
ValueMapping longestcommonsubsequenceSymbolicVMs[] =
|
||
|
|
{longestcommonsubsequenceSymbolicVM<MLabel, Label>,
|
||
|
|
longestcommonsubsequenceSymbolicVM<MPlace, Place>, 0};
|
||
|
|
AddOperator(longestcommonsubsequenceSymbolicInfo(),
|
||
|
|
longestcommonsubsequenceSymbolicVMs,
|
||
|
|
longestcommonsubsequenceSymbolicSelect,
|
||
|
|
longestcommonsubsequenceSymbolicTM);
|
||
|
|
|
||
|
|
AddOperator(topatternInfo(), topatternVM, topatternTM);
|
||
|
|
|
||
|
|
AddOperator(toclassifierInfo(), toclassifierVM, toclassifierTM);
|
||
|
|
|
||
|
|
AddOperator(&matches);
|
||
|
|
matches.SetUsesArgsInTypeMapping();
|
||
|
|
|
||
|
|
AddOperator(createtupleindexInfo(), createtupleindexVM<UnitPos, UnitPos>,
|
||
|
|
createtupleindexTM<UnitPos, UnitPos>);
|
||
|
|
|
||
|
|
AddOperator(&bulkloadtupleindex);
|
||
|
|
bulkloadtupleindex.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&bulkloadtupleindex2);
|
||
|
|
bulkloadtupleindex2.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&tmatches);
|
||
|
|
tmatches.SetUsesArgsInTypeMapping();
|
||
|
|
|
||
|
|
AddOperator(&indextmatches);
|
||
|
|
indextmatches.SetUsesArgsInTypeMapping();
|
||
|
|
|
||
|
|
AddOperator(&indextmatches2);
|
||
|
|
indextmatches2.SetUsesArgsInTypeMapping();
|
||
|
|
|
||
|
|
ValueMapping indexrewriteVMs[] = {indexrewriteVM<MLabel>,
|
||
|
|
indexrewriteVM<MLabels>, indexrewriteVM<MPlace>, indexrewriteVM<MPlaces>,0};
|
||
|
|
AddOperator(indexrewriteInfo(), indexrewriteVMs, indexrewriteSelect,
|
||
|
|
indexrewriteTM);
|
||
|
|
|
||
|
|
ValueMapping createunitrtreeVMs[] = {createunitrtreeVM<MLabel>,
|
||
|
|
createunitrtreeVM<MLabels>, createunitrtreeVM<MPlace>,
|
||
|
|
createunitrtreeVM<MPlaces>, 0};
|
||
|
|
AddOperator(createunitrtreeInfo(), createunitrtreeVMs, createunitrtreeSelect,
|
||
|
|
createunitrtreeTM);
|
||
|
|
|
||
|
|
// ValueMapping indexmatchesVMs[] = {indexmatchesVM<MLabel, FText>,
|
||
|
|
// indexmatchesVM<MLabels, FText>, indexmatchesVM<MPlace, FText>,
|
||
|
|
// indexmatchesVM<MPlaces, FText>, indexmatchesVM<MLabel, PatPersistent>,
|
||
|
|
// indexmatchesVM<MLabels, PatPersistent>,
|
||
|
|
// indexmatchesVM<MPlace, PatPersistent>,
|
||
|
|
// indexmatchesVM<MPlaces, PatPersistent>, 0};
|
||
|
|
// AddOperator(indexmatchesInfo(), indexmatchesVMs, indexmatchesSelect,
|
||
|
|
// indexmatchesTM);
|
||
|
|
|
||
|
|
ValueMapping filtermatchesVMs[] = {filtermatchesVM<MLabel, FText>,
|
||
|
|
filtermatchesVM<MLabels, FText>, filtermatchesVM<MPlace, FText>,
|
||
|
|
filtermatchesVM<MPlaces, FText>, filtermatchesVM<MLabel, PatPersistent>,
|
||
|
|
filtermatchesVM<MLabels, PatPersistent>,
|
||
|
|
filtermatchesVM<MPlace, PatPersistent>,
|
||
|
|
filtermatchesVM<MPlaces, PatPersistent>, 0};
|
||
|
|
AddOperator(filtermatchesInfo(), filtermatchesVMs, filtermatchesSelect,
|
||
|
|
filtermatchesTM);
|
||
|
|
|
||
|
|
ValueMapping rewriteVMs[] = {rewriteVM<MLabel, FText>,
|
||
|
|
rewriteVM<MLabels, FText>, rewriteVM<MPlace, FText>,
|
||
|
|
rewriteVM<MPlaces, FText>, rewriteVM<MLabel, PatPersistent>,
|
||
|
|
rewriteVM<MLabels, PatPersistent>, rewriteVM<MPlace, PatPersistent>,
|
||
|
|
rewriteVM<MPlaces, PatPersistent>, 0};
|
||
|
|
AddOperator(rewriteInfo(), rewriteVMs, rewriteSelect, rewriteTM);
|
||
|
|
|
||
|
|
ValueMapping multirewriteVMs[] = {multirewriteVM<MLabel>,
|
||
|
|
multirewriteVM<MLabels>, multirewriteVM<MPlace>, multirewriteVM<MPlaces>,0};
|
||
|
|
AddOperator(multirewriteInfo(), multirewriteVMs, multirewriteSelect,
|
||
|
|
multirewriteTM);
|
||
|
|
|
||
|
|
ValueMapping classifyVMs[] = {classifyVM<MLabel>, classifyVM<MLabels>,
|
||
|
|
classifyVM<MPlace>, classifyVM<MPlaces>, 0};
|
||
|
|
AddOperator(classifyInfo(), classifyVMs, classifySelect, classifyTM);
|
||
|
|
|
||
|
|
ValueMapping indexclassifyVMs[] = {indexclassifyVM<MLabel>,
|
||
|
|
indexclassifyVM<MLabels>, indexclassifyVM<MPlace>, indexclassifyVM<MPlaces>,
|
||
|
|
0};
|
||
|
|
AddOperator(indexclassifyInfo(), indexclassifyVMs, indexclassifySelect,
|
||
|
|
indexclassifyTM);
|
||
|
|
|
||
|
|
AddOperator(createmlInfo(), createmlVM, createmlTM);
|
||
|
|
|
||
|
|
AddOperator(createmlrelInfo(), createmlrelVM, createmlrelTM);
|
||
|
|
|
||
|
|
ValueMapping createtrieVMs[] = {createtrieVM<MLabel>, createtrieVM<MLabels>,
|
||
|
|
createtrieVM<MPlace>, createtrieVM<MPlaces>, 0};
|
||
|
|
AddOperator(createtrieInfo(), createtrieVMs, createtrieSelect, createtrieTM);
|
||
|
|
|
||
|
|
// AddOperator(createMaxspeedRasterInfo(), createMaxspeedRasterVM,
|
||
|
|
// createMaxspeedRasterTM);
|
||
|
|
|
||
|
|
// AddOperator(createTileAreasInfo(), createTileAreasVM, createTileAreasTM);
|
||
|
|
|
||
|
|
// AddOperator(restoreTrajInfo(), restoreTrajVM, restoreTrajTM);
|
||
|
|
|
||
|
|
// ValueMapping derivegroupsVMs[] = {derivegroupsVM<MLabel>,
|
||
|
|
// derivegroupsVM<MLabels>, derivegroupsVM<MPlace>,
|
||
|
|
// derivegroupsVM<MPlaces>,0};
|
||
|
|
// AddOperator(derivegroupsInfo(), derivegroupsVMs, derivegroupsSelect,
|
||
|
|
// derivegroupsTM);
|
||
|
|
|
||
|
|
AddOperator(&getPatterns);
|
||
|
|
getPatterns.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&createfptree);
|
||
|
|
createfptree.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&minefptree);
|
||
|
|
minefptree.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&createprojecteddb);
|
||
|
|
createprojecteddb.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&prefixSpan);
|
||
|
|
prefixSpan.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&createverticaldb);
|
||
|
|
createverticaldb.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&spade);
|
||
|
|
spade.SetUsesMemory();
|
||
|
|
|
||
|
|
AddOperator(&getlabels);
|
||
|
|
|
||
|
|
AddOperator(&createlexicon);
|
||
|
|
|
||
|
|
AddOperator(&frequencyvector);
|
||
|
|
|
||
|
|
AddOperator(&cosinesim);
|
||
|
|
AddOperator(&jaccardsim);
|
||
|
|
|
||
|
|
AddOperator(&createsplsemtraj);
|
||
|
|
|
||
|
|
AddOperator(&splitter);
|
||
|
|
|
||
|
|
}
|
||
|
|
~SymbolicTrajectoryAlgebra() {}
|
||
|
|
};
|
||
|
|
|
||
|
|
// SymbolicTrajectoryAlgebra SymbolicTrajectoryAlgebra;
|
||
|
|
|
||
|
|
} // end of namespace ~stj~
|
||
|
|
|
||
|
|
extern "C"
|
||
|
|
Algebra* InitializeSymbolicTrajectoryAlgebra(NestedList *nlRef,
|
||
|
|
QueryProcessor *qpRef) {
|
||
|
|
return new stj::SymbolicTrajectoryAlgebra;
|
||
|
|
}
|