/* ---- 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 Spatiotemporal Pattern Algebra Started June, 2009 Mahmoud Sakr [TOC] \section{Overview} This source file contains the necessary implementations for evaluating the spatiotemporal pattern (STP) predicates [Mahmoud Attia Sakr, Ralf Hartmut G\"{u}ting: Spatiotemporal pattern queries, Geoinformatica (2011) 15:497-540]. It contains the implementations of the following: \begin{itemize} \item The \emph{stvector} type for representing a temporal relationship between two time intervals. There are 26 such simple relatioships accounting for Allen's 13 operator, and variants of them that allow each of the two intervals to degenerate into a time instant. The \emph{stvector} type is a bit vector (represented by a single integer) containing one bit for each of these 26 simple relationships. An object of type \emph{stvector} represents a temporal relationship, which is the disjunction of all the simple relationships whose corresponding bits are set to 1. \item The \emph{CSP} class (stands for Constraint Satisfaction Problem). This class implements our algorithm for solving the CSP associated with the STP predicate. \item The algebra operators. See the most recent list of operators at the end of this file. \item In 2011, the implementation of the temporal reasoning was added by Mahmoud Sakr. For more details about this technique, please refer to the PhD thesis of Mahmoud Sakr, Chapter 6 Temporal Reasoning. \end{itemize} \section{Defines and includes} */ #include "STPatternAlgebra.h" #include #include "Symbols.h" #include "Stream.h" using namespace temporalalgebra; using namespace std; using namespace datetime; namespace STP{ /* \section{Classes} \subsection{Class STVector} ~StrSimpleConnectors~\\ A string array that enumerates the 26 simple interval relationships. Each of these entries describes a relationship between two intervals. The traditional way that used to be adopted in the literature is to assign names for such relationships (e.g., before, after, etc like the Allen's operators. Here we alternatively propose a language instead of names. This is because in our case 26 such relationships are possible, which makes it difficult for a user to memorize the names. In the entries below, the letters $aa$ denote the begin and end time instants of the first interval. Similarly $bb$ are the begin and end of the second interval. The order of the letters describes the temporal relationship, that is, a sequence $ab$ means $a < b$. The dot symbol denotes the equality constraint, hence, the sequence $a.b$ means $a = b$, and $a.a$ means that the start and the ends of the first interval are the same (i.e., the interval degenerates into a time instant). For example, the relationship \emph{aa.bb} between the intervals $i_1, i_2$ denotes the order: ($(i_1.t_1 < i_1.t_2) \wedge (i_1.t_2 = i_2.t_1) \wedge (i_2.t_1 < i_2.t_2)$). */ string StrSimpleConnectors[]= {"aabb" , "bbaa" , "aa.bb" , "bb.aa" , "abab" , "baba" , "baab" , "abba" , "a.bab" , "a.bba" , "baa.b" , "aba.b" , "a.ba.b" , "a.abb" , "a.a.bb" , "ba.ab" , "bb.a.a" , "bba.a" , "b.baa" , "b.b.aa" , "ab.ba" , "aa.b.b" , "aab.b" , "a.ab.b" , "a.a.b.b" , "b.ba.a" }; /* ~STVector::Count~\\ A utility for counting the number of simple relationships inside an ~stvector~ instance. */ int STVector::Count(int vec) { int c=0; if(vec & aabb) c++ ; if(vec & bbaa) c++ ; if(vec & aa_bb) c++ ; if(vec & bb_aa) c++ ; if(vec & abab) c++ ; if(vec & baba) c++ ; if(vec & baab) c++ ; if(vec & abba) c++ ; if(vec & a_bab) c++ ; if(vec & a_bba) c++ ; if(vec & baa_b) c++ ; if(vec & aba_b) c++ ; if(vec & a_ba_b) c++ ; if(vec & a_abb) c++ ; if(vec & a_a_bb) c++ ; if(vec & ba_ab) c++ ; if(vec & bb_a_a) c++ ; if(vec & bba_a) c++ ; if(vec & b_baa) c++ ; if(vec & b_b_aa) c++ ; if(vec & ab_ba) c++ ; if(vec & aa_b_b) c++ ; if(vec & aab_b) c++ ; if(vec & a_ab_b) c++ ; if(vec & a_a_b_b) c++ ; if(vec & b_ba_a) c++ ; return c; } /* ~STVector::Str2Simple~\\ A utility that gets a string representing one of the 26 simple relationships, and returns the bit vector corresponding to this simple relationship. */ inline int STVector::Str2Simple(string s) { if(s=="aabb") return 1 ; if(s=="bbaa") return 2 ; if(s=="aa.bb")return 4; if(s=="ab.ab")return 4; if(s=="bb.aa")return 8; if(s=="ba.ba")return 8; if(s=="abab") return 16; if(s=="baba") return 32; if(s=="baab") return 64; if(s=="abba") return 128; if(s=="a.bab")return 256; if(s=="b.aab")return 256; if(s=="a.bba")return 512; if(s=="b.aba")return 512; if(s=="baa.b")return 1024; if(s=="bab.a")return 1024; if(s=="aba.b")return 2048; if(s=="abb.a")return 2048; if(s=="a.ba.b") return 4096; if(s=="a.bb.a") return 4096; if(s=="b.aa.b") return 4096; if(s=="b.ab.a") return 4096; if(s=="a.abb") return 8192 ; if(s=="a.a.bb") return 16384; if(s=="a.b.ab") return 16384; if(s=="b.a.ab") return 16384 ; if(s=="ba.ab") return 32768 ; if(s=="bb.a.a") return 65536; if(s=="ba.b.a") return 65536; if(s=="ba.a.b") return 65536 ; if(s=="bba.a") return 131072 ; if(s=="b.baa") return 262144 ; if(s=="b.b.aa") return 524288; if(s=="b.a.ba") return 524288; if(s=="a.b.ba") return 524288 ; if(s=="ab.ba") return 1048576 ; if(s=="aa.b.b") return 2097152; if(s=="ab.a.b") return 2097152; if(s=="ab.b.a") return 2097152 ; if(s=="aab.b") return 4194304 ; if(s=="a.ab.b") return 8388608 ; if(s=="a.a.b.b")return 16777216; if(s=="a.b.a.b")return 16777216; if(s=="a.b.b.a")return 16777216; if(s=="b.b.a.a")return 16777216; if(s=="b.a.b.a")return 16777216; if(s=="b.a.a.b")return 16777216; if(s=="b.ba.a") return 33554432; return -1; } /* ~STVector::Vector2List~\\ A utility that converts an ~stvector~ into a nested list of symbols. This is used in the out function of the ~stvector~ type to provide a nice display of the vector content. */ inline ListExpr STVector::Vector2List() { ListExpr list; ListExpr last; int simple=1; int i=0; bool first=true; while(i<26 && first) { if(v & simple) { list= nl->OneElemList(nl->SymbolAtom(StrSimpleConnectors[i])); last=list; first=false; } simple*=2; i++; } for(; i<26; i++) { if(v & simple) last= nl->Append(last, nl->SymbolAtom(StrSimpleConnectors[i])); simple*=2; } return list; } /* ~STVector::Add~\\ Inserts a simple relationship into an ~stvector~ instance. The relationship is given as a string. If the relationship is already there in the vector, nothing changes. */ bool STVector::Add(string simple) { int vec= Str2Simple(simple); if(vec==-1) return false; v = v|vec; return true; } /* ~STVector::Add~\\ Inserts a simple relationship into an ~stvector~ instance. The relationship is given as an integer (i.e., the bit vector of the given relationship). If the relationship is already there in the vector, nothing changes. */ bool STVector::Add(int simple) { if(simple <= b_ba_a && Count(simple)==1) { v = v|simple; return true; } return false; } /* ~STVector::ApplyVector~\\ Checks whether the relationship specified in this ~stvector~ instance holds for the two intervals ~p1, p2~. The function yields true if any of the simple relationships inside the vector holds for the given two intervals. */ bool STVector::ApplyVector(Interval& p1, Interval& p2) { int simple=1; bool supported=false; for(int i=0; i<26; i++) { if(v & simple) { supported = ApplySimple(p1, p2, simple); if(supported) return true; } simple*=2; } return false; } /* ~STVector::ApplySimple~\\ Checks whether the given simple relationship holds for the two intervals ~p1, p2~. */ bool STVector::ApplySimple(Interval& p1, Interval& p2, int simple) { Instant a=p1.start, A=p1.end, b=p2.start, B=p2.end; switch(simple) { case aabb: return(acount= 0; this->v= 0; } /* SECONDO framework support functions. These functions are required by SECONDO to be able to deal with the ~stvector~ type. In, Out, Create, Delete, Open, Save, Close, Clone, SizeOfObj, Property, and KindCheck. */ Word STVector::In( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ) { correct = false; Word result = SetWord(Address(0)); const string errMsg = "STVector::In: Expecting a simple temporal" " connector!"; STVector* res=new STVector(0); NList list(instance), first; while(! list.isEmpty()) { first= list.first(); if(! res->Add(first.str())) { correct=false; cmsg.inFunError(errMsg); return result; } list.rest(); } result.addr= res; return result; } ListExpr STVector::Out( ListExpr typeInfo, Word value ) { STVector* vec = static_cast( value.addr ); return vec->Vector2List(); } Word STVector::Create( const ListExpr typeInfo ) { return (SetWord( new STVector( 0))); } void STVector::Delete( const ListExpr typeInfo, Word& w ) { delete static_cast( w.addr ); w.addr = 0; } bool STVector::Open( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ) { size_t size = sizeof(int); int vec; bool ok = valueRecord.Read( &vec, size, offset ); offset += size; if(!ok){ return false; } value.addr = new STVector(vec); return ok; } bool STVector::Save( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ) { STVector* vec = static_cast( value.addr ); size_t size = sizeof(int); bool ok = true; ok = ok && valueRecord.Write( &vec->v, size, offset ); offset += size; return ok; } void STVector::Close( const ListExpr typeInfo, Word& w ) { delete static_cast( w.addr ); w.addr = 0; } Word STVector::Clone( const ListExpr typeInfo, const Word& w ) { STVector* vec = static_cast( w.addr ); return SetWord( new STVector(*vec) ); } int STVector::SizeOfObj() { return sizeof(STVector); } ListExpr STVector::Property() { return (nl->TwoElemList( nl->FiveElemList(nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List"), nl->StringAtom("Remarks")), nl->FiveElemList(nl->StringAtom("-> SIMPLE"), nl->StringAtom("stvector"), nl->StringAtom("(s1 s2 ...)"), nl->StringAtom("(1 128 32)"), nl->StringAtom("")))); } bool STVector::KindCheck( ListExpr type, ListExpr& errorInfo ) { return (nl->IsEqual( type, "stvector" )); } void IntervalInstant2IntervalCcReal(const Interval& in, Interval& out) { out.start.Set(in.start.IsDefined(), in.start.ToDouble()); out.end.Set(in.end.IsDefined(), in.end.ToDouble()); } /* \subsection{Class CSP} ~csp~\\ A global variable holding the csp during the evaluation of the STP operator. */ CSP csp; /* ~Constructor and destructor~\\ */ CSP::CSP(): closureRes(notPA), count(0),iterator(-1), nullInterval(Instant((int64_t)0),Instant((int64_t)0), true,true) {} CSP::~CSP() { } /* ~CSP::IntervalInstant2IntervalCcReal~\\ A utility to convert an interval into an interval. This is used to speed up the computations, because comparing reals is faster than comparing instants. In 2011 Thomas Behr added another mechanism to deal with instants as int64. Comparing instants is not anymore slow. Since then, this algebra was modified, and the ~CSP::IntervalInstant2IntervalCcReal~ utility, and its inverse ~CSP::IntervalCcReal2IntervalInstant~ are not anymore used. */ void CSP::IntervalInstant2IntervalCcReal(const Interval& in, Interval& out) { out.start.Set(in.start.IsDefined(), in.start.ToDouble()); out.end.Set(in.end.IsDefined(), in.end.ToDouble()); out.lc= in.lc; out.rc= in.rc; } void CSP::IntervalCcReal2IntervalInstant(const Interval& in, Interval& out) { out.start.ReadFrom(in.start.GetRealval()); out.end.ReadFrom(in.end.GetRealval()); out.lc= in.lc; out.rc= in.rc; } /* ~CSP::MBool2Vec~\\ This function is used within the ~extend~ function. It gets an mbool instance and yields the list of time intervals during which this mbool instance is true. It is equivalent to deftime(mb at TRUE). */ int CSP::MBool2Vec(const MBool* mb, vector >& vec) { UBool unit(0); vec.clear(); if(!mb->IsDefined() || mb->IsEmpty() || !mb->IsValid()) return 0; for(int i=0; iGetNoComponents(); i++) { mb->Get(i, unit); if( ((CcBool)unit.constValue).GetValue()) vec.push_back(unit.timeInterval); } return 0; } /* ~CSP::Solve~\\ This is the main interface to the CSP class. When called it iteratively tries to find a solution to the CSP. If such a solution is found it yields true. Our proposed algorithm for solving the CSP tries to solve the sub-CSP of $k-1$ variables ($\mathit{CSP_{k-1}}$) first and then to extend it to $\mathit{CSP_k}$. Therefore, an early stop is possible if a solution to the $\mathit{CSP_{k-1}}$ cannot be found. Which means that, in case no solution is found, the evaluation will be stopped as soon as this is realized, without the unnecessary evaluation of the remaining time-dependent predicates. This ~CSP::Solve~ function uses three data structures, which are made globally accessible for all its helper functions: the $\mathit{SA}$ list (for Supported Assignments), the \emph{Agenda} and the \emph{ConstraintGraph}. The Agenda keeps a list of variables that are not yet consumed by the algorithm. One variable from the Agenda is consumed in every iteration. Consuming a variable is equivalent to computing its domain (i.e., evaluating the corresponding time-dependent predicate). Every supported assignment in the $\mathit{SA}$ list is a solution for the sub-CSP consisting of the variables that have been consumed so far. In iteration $k$ there are $k-1$ previously consumed variables and one newly consumed variable ($X_k$ with domain $D_k$). Every entry in $\mathit{SA}$ at this iteration is a solution for the $\mathit{CSP_{k-1}}$. To extend the $\mathit{SA}$, the Cartesian product of $\mathit{SA}$ and $D_k$ is computed. Then only the entries that constitute a solution for $\mathit{CSP_{k}}$ are kept in $\mathit{SA}$. $\mathit{CSP_{k}}$ is constructed using the consumed variables and their corresponding constraints in the constraint graph. */ bool CSP::Solve() { bool debugme=false; int varIndex; Word Value; vector > domain(0); int loopCnt=0; Counter::getRef("TemporalReasoningOn", false)= 0; string counterPrefix= "CSP::Solve::Iteration"; if(debugme) cerr<<"Iterations "; while( (varIndex= PickVariable()) != -1) { ++loopCnt; if(debugme) cerr<Request(Agenda[varIndex], Value); //Agenda[varIndex]=0; UsedAgendaVars[varIndex]= true; MBool2Vec((MBool*)Value.addr, domain); if(domain.size()==0) {SA.clear(); return false;} if(Extend(varIndex, domain)!= 0) return false; if(SA.size()==0) return false; if(debugme&&0) Print(); } return true; } /* ~CSP::Extend~\\ A helper function called by the previous ~CSP::Solve~. Mainly it distinguishes between two cases: \begin{itemize} \item If the variable given is the first agenda variable to be consumed, the SA is initialized. \item Else, the function creates and checks (on the fly) the Cartesian product of SA and the domain of the variable. \end{itemize} */ int CSP::Extend(int index, vector >& domain ) { vector > sa(count); if(SA.size() == 0) { for(int i=0; i > sa, int index) { bool debugme= false; bool supported=false; if(debugme) { cerr<& p1, Interval& p2, vector constraint) { bool debugme=false; Word Value; bool satisfied=false; for(unsigned int i=0;i< constraint.size(); i++) { if(debugme) { cout<< "\nChecking constraint "<< qp->GetType(constraint[i])<Request(constraint[i],Value); STVector* vec= (STVector*) Value.addr; satisfied= vec->ApplyVector(p1, p2); if(!satisfied) return false; } return true; } /* ~CSP::PickVariable~\\ The function PickVariable picks Agenda variables according to their connectivity rank. \begin{alltt} For every variable v \{ For every constraint c(v,x) \{ if x in Agenda rank+=0.5 if x is not in the Agenda rank+=1 \} \} \end{alltt} */ int CSP::PickVariable() { bool debugme=false; vector vars(0); vector numconstraints(0); double cnt=0; int index=-1; for(unsigned int i=0;imax){ max=numconstraints[i]; index=vars[i];} } if(debugme) { for(unsigned int i=0; i= SA.size() || varIndex >= SA[0].size()) return false; res.Add(SA[saIndex][varIndex]); return true; } /* ~CSP::AppendSolutionToTuple~\\ A utility that is used within the stpattern??extend? operators to append the fulfillment periods of the time-dependent predicates to an input tuple that matches the pattern. */ bool CSP::AppendSolutionToTuple(int saIndex, Tuple* oldTup, Tuple* resTup) { if(!this->SA.empty()) { Periods attrVal(0); for (unsigned int i=0; i < this->Agenda.size();i++) { csp.GetSA(saIndex, i, attrVal); resTup->PutAttribute(oldTup->GetNoAttributes()+i, attrVal.Clone()); } } else { Periods undefRes(0); undefRes.SetDefined(false); for (unsigned int i=0; i < this->Agenda.size();i++) { resTup->PutAttribute(oldTup->GetNoAttributes()+i, undefRes.Clone()); } } return true; } /* ~CSP::AppendUnDefsToTuple~\\ A utility that is used within the stpattern??extend? operators to append the undefined periods to an input tuple that does not match the pattern. */ bool CSP::AppendUnDefsToTuple(Tuple* oldTup, Tuple* resTup) { Periods undefRes(0); undefRes.SetDefined(false); for (unsigned int i=0; i < this->Agenda.size();i++) { resTup->PutAttribute(oldTup->GetNoAttributes()+i, undefRes.Clone()); } return true; } /* ~CSP::GetStart~\\ Used in the second part of the extended STP predicate. It accesses the current SA entry (specified by the SA iterator), and yields the starting time instant of the fulfillment interval of the given time-dependent predicate. */ bool CSP::GetStart(string alias, Instant& result) { map::iterator it; it=VarAliasMap.find(alias); if(it== VarAliasMap.end()) return false; int index=(*it).second; result.CopyFrom(& SA[iterator][index].start); return true; } /* ~CSP::GetEnd~\\ Used in the second part of the extended STP predicate. It accesses the current SA entry (specified by the SA iterator), and yields the final time instant of the fulfillment interval of the given time-dependent predicate. */ bool CSP::GetEnd(string alias, Instant& result) { map::iterator it; it=VarAliasMap.find(alias); if(it== VarAliasMap.end()) return false; int index=(*it).second; result.CopyFrom(& SA[iterator][index].end); return true; } /* ~CSP::Print~\\ A debug utility. It prints the content of the CSP to the stderr. */ void CSP::Print() { cout<< "\n==========================\nSA.size() = "<< SA.size()<< endl; for(unsigned int i=0; i< SA.size(); i++) { for(unsigned int j=0; jGetNoComponents()); UPoint first(0), next(0); UPoint *shifted,*temp, *cur; int rmillisec=0, rday=0; actual->Get( 0, first ); cur=new UPoint(first); for( int i = 1; i < actual->GetNoComponents(); i++ ) { actual->Get( i, next ); rmillisec= rand()% threshold->GetAllMilliSeconds(); rday=0; if(threshold->GetDay()> 0) rday = rand()% threshold->GetDay(); DateTime delta(rday,rmillisec,durationtype) ; shifted= new UPoint(*cur); delete cur; temp= new UPoint(next); if(rmillisec > rand()%24000 ) { if((shifted->timeInterval.end + delta) < next.timeInterval.end ) { shifted->timeInterval.end += delta ; temp->timeInterval.start= shifted->timeInterval.end; } } else { if((shifted->timeInterval.end - delta) >shifted->timeInterval.start) { shifted->timeInterval.end -= delta ; temp->timeInterval.start= shifted->timeInterval.end; } } cur=temp; if(debugme) { cout.flush(); cout<<"\n original "; cur->Print(cout); cout<<"\n shifted " ; shifted->Print(cout); cout.flush(); } delayed.Add(*shifted); delete shifted; } delayed.Add(*temp); delete temp; res.CopyFrom(&delayed); if(debugme) { res.Print(cout); cout.flush(); } return; } /* ~IsSimplePredicateList~\\ A typemap helper function. It accepts the signature ((Alias: mbool), ...). */ bool IsSimplePredicateList(ListExpr args, bool WithUserArgs=false) { if(nl->IsAtom(args)) return false; ListExpr NamedPredListRest = WithUserArgs? nl->First(args): args; ListExpr NamedPred; while( !nl->IsEmpty(NamedPredListRest) ) { NamedPred = nl->First(NamedPredListRest); NamedPredListRest = nl->Rest(NamedPredListRest); if(!(nl->ListLength(NamedPred) == 2 && nl->IsAtom(nl->First(NamedPred))&& nl->IsAtom(nl->Second(NamedPred))&& nl->SymbolValue(nl->Second(NamedPred))== MBool::BasicType())) return false; } return true; } /* ~IsMapTuplePredicateList~\\ A typemap helper function. It accepts the signature (Alias: map(tuple) -> mbool), ...). */ bool IsMapTuplePredicateList(ListExpr args, bool WithUserArgs=false) { if(nl->IsAtom(args)) return false; ListExpr NamedPredListRest = WithUserArgs? nl->First(args): args; ListExpr NamedPred, Map; while( !nl->IsEmpty(NamedPredListRest) ) { NamedPred = nl->First(NamedPredListRest); NamedPredListRest = nl->Rest(NamedPredListRest); Map= nl->Second(NamedPred); if(nl->ListLength(NamedPred) != 2 || !nl->IsAtom(nl->First(NamedPred)) || !listutils::isMap<1>(Map)|| !nl->IsEqual(nl->Nth(nl->ListLength(Map), Map), MBool::BasicType())) return false; if(!nl->IsEqual(nl->First(nl->Second(Map)), Tuple::BasicType())) return false; } return true; } /* ~IsMapTuplePredicateList~\\ A typemap helper function. It accepts the signature (Alias: map(tuple, periods) -> mbool), ...). */ bool IsMapTuplePeriodsPredicateList(ListExpr args, bool WithUserArgs=false) { if(nl->IsAtom(args)) return false; ListExpr NamedPredListRest = WithUserArgs? nl->First(args): args; ListExpr NamedPred, Map; while( !nl->IsEmpty(NamedPredListRest) ) { NamedPred = nl->First(NamedPredListRest); NamedPredListRest = nl->Rest(NamedPredListRest); Map= nl->Second(NamedPred); if(nl->ListLength(NamedPred) != 2 || !nl->IsAtom(nl->First(NamedPred)) || !listutils::isMap<2>(Map)|| !nl->IsEqual(nl->Nth(nl->ListLength(Map), Map), MBool::BasicType())) return false; if(!nl->IsEqual(nl->First(nl->Second(Map)), Tuple::BasicType()) || !nl->IsEqual(nl->Third(Map), Periods::BasicType()) ) return false; } return true; } /* ~IsConstraintList~\\ A typemap helper function. It accepts the signature (bool, ...). */ bool IsConstraintList(ListExpr args, bool WithUserArgs=false) { if(nl->IsAtom(args)) return false; ListExpr ConstraintListRest = WithUserArgs? nl->First(args): args; ListExpr STConstraint; while( !nl->IsEmpty(ConstraintListRest) ) { STConstraint = nl->First(ConstraintListRest); ConstraintListRest = nl->Rest(ConstraintListRest); if(!((nl->IsAtom(STConstraint)&& nl->SymbolValue(STConstraint)== CcBool::BasicType()))) return false; } return true; } /* ~IsTupleExpr~\\ A typemap helper function. It accepts the signature (tuple (attrs)). */ bool IsTupleExpr(ListExpr args, bool WithUserArgs=false) { ListExpr tuple; if(WithUserArgs){ if(nl->IsAtom(args) || nl->IsEmpty(args)){ return false; } tuple = nl->First(args); } else { tuple = args; } return Tuple::checkType(tuple); } /* ~IsTupleStream~\\ A typemap helper function. It accepts the signature (stream streamElems). */ bool IsTupleStream(ListExpr args, bool WithUserArgs=false) { ListExpr stream; if(WithUserArgs){ if(nl->IsAtom(args) || nl->IsEmpty(args)){ return false; } stream = nl->First(args); } else { stream = args; } return Stream::checkType(stream); } /* ~IsBoolExpr~\\ A typemap helper function. It accepts the signature bool. */ bool IsBoolExpr(ListExpr args, bool WithUserArgs=false) { ListExpr boolExpr = WithUserArgs? nl->First(args): args; return (nl->IsAtom(boolExpr) && nl->IsEqual(boolExpr, CcBool::BasicType())); } /* ~IsBoolMap~\\ A typemap helper function. It accepts the signature (map (-) bool). */ bool IsBoolMap(ListExpr args, bool WithUserArgs=false) { ListExpr boolExpr = WithUserArgs? nl->First(args): args; if(nl->IsAtom(args)) return false; ListExpr Map = nl->First(boolExpr), MapReturn= nl->Nth(nl->ListLength(boolExpr), boolExpr); if(nl->ListLength(boolExpr) < 3 || !nl->IsEqual(Map, Symbols::MAP()) || !nl->IsEqual(MapReturn, CcBool::BasicType())) return false; return true; } /* ~IsPeriodsExpr~\\ A typemap helper function. It accepts the signature periods. */ bool IsPeriodsExpr(ListExpr args, bool WithUserArgs=false) { ListExpr periodsExpr = WithUserArgs? nl->First(args): args; return (nl->IsAtom(periodsExpr) && nl->IsEqual(periodsExpr, Periods::BasicType())); } /* ~IsAliasInCatalog~\\ A typemap helper function. It checks whether an alias that is given to a time-dependent predicate collides with a known DB object name in the SECONDO catalog. */ bool IsAliasInCatalog(set& aliases) { for(set::iterator it= aliases.begin(); it!= aliases.end(); ++it) if(SecondoSystem::GetCatalog()->IsTypeName(*it)) return true; return false; } /* ~IsAliasInAttributeNames~\\ A typemap helper function. It checks whether an alias that is given to a time-dependent predicate collides with an attribute in the input tuple. */ bool IsAliasInAttributeNames(ListExpr AttrList,set& aliases) { ListExpr typeList; for(set::iterator it= aliases.begin(); it!= aliases.end(); ++it) if(FindAttribute(AttrList, *it, typeList) != 0) return true; return false; } /* ~ExtractPredAliasesFromPredList~\\ A typemap helper function. It return a set of strings containing all the aliases of the time-dependent predicates in the STP operator. */ void ExtractPredAliasesFromPredList(ListExpr args, set& aliases) { ListExpr NamedPredListRest = nl->First(args); ListExpr NamedPred; string alias; aliases.clear(); while( !nl->IsEmpty(NamedPredListRest) ) { NamedPred = nl->First(NamedPredListRest); NamedPredListRest = nl->Rest(NamedPredListRest); alias= nl->ToString(nl->First(NamedPred)); aliases.insert(alias); } } /* ~ExtractPredAliasesFromPredList~\\ A typemap helper function. It return a vector of strings containing all the aliases of the time-dependent predicates in the STP operator, in the same order they appear. */ void ExtractPredAliasesFromPredList(ListExpr args, vector& aliases) { ListExpr NamedPredListRest = nl->First(args); ListExpr NamedPred; string alias; aliases.clear(); while( !nl->IsEmpty(NamedPredListRest) ) { NamedPred = nl->First(NamedPredListRest); NamedPredListRest = nl->Rest(NamedPredListRest); alias= nl->ToString(nl->First(NamedPred)); aliases.push_back(alias); } } /* ~ExtractPredAliasesFromConstraintList~\\ A typemap helper function. It return a set of strings containing all the aliases that are mentioned in the list of tempotral constraints. */ void ExtractPredAliasesFromConstraintList(ListExpr args, set& aliases) { ListExpr ConstraintListRest = nl->Second(args); ListExpr STConstraint; string alias; aliases.clear(); while( !nl->IsEmpty(ConstraintListRest) ) { STConstraint = nl->First(ConstraintListRest); ConstraintListRest = nl->Rest(ConstraintListRest); alias= nl->StringValue(nl->Second(STConstraint)); aliases.insert(alias); alias= nl->StringValue(nl->Third(STConstraint)); aliases.insert(alias); } } /* ~CSPAddPredicates~\\ A helper function that fills the csp with the time-dependent predicates in the user query. */ void CSPAddPredicates(Supplier& namedpredlist) { Supplier namedpred,alias, pred; string aliasstr; int noofpreds= qp->GetNoSons(namedpredlist); for(int i=0; i< noofpreds; i++) { namedpred= qp->GetSupplierSon(namedpredlist, i); alias= qp->GetSupplierSon(namedpred, 0); pred = qp->GetSupplierSon(namedpred, 1); aliasstr= nl->ToString(qp->GetType(alias)); csp.AddVariable(aliasstr,pred); } } /* ~CSPAddConstraints~\\ A helper function that fills the csp with the temporal constraints in the user query. */ void CSPAddConstraints(Supplier& constraintlist) { Supplier constraint, alias1, alias2, stvector; Word Value; string alias1str, alias2str; int noofconstraints= qp->GetNoSons(constraintlist); for(int i=0; i< noofconstraints; i++) { constraint = qp->GetSupplierSon(constraintlist, i); alias1= qp->GetSupplierSon(constraint, 0); alias2= qp->GetSupplierSon(constraint, 1); stvector= qp->GetSupplierSon(constraint, 2); qp->Request(alias1, Value); alias1str= ((CcString*) Value.addr)->GetValue(); qp->Request(alias2, Value); alias2str= ((CcString*) Value.addr)->GetValue(); csp.AddConstraint(alias1str,alias2str, stvector); } } /* ~CSPSetPredsArgs~\\ A helper function that fills the argument vector of all the time-dependent predicates with the current tuple from the input tuple stream. */ bool CSPSetPredsArgs(Supplier predList, Tuple* tup) { ArgVectorPointer funargs; Supplier namedpred,pred; int noofpreds= qp->GetNoSons(predList); for(int i=0; i< noofpreds; i++) { namedpred= qp->GetSupplierSon(predList, i); //alias= qp->GetSupplierSon(namedpred, 0); pred = qp->GetSupplierSon(namedpred, 1); funargs = qp->Argument(pred); ((*funargs)[0]).setAddr(tup); } return true; } /* ~ComputeClosure~\\ Computes the closure within the Type Map */ ListExpr ComputeClosure(ListExpr ConstraintList, vector IntervalVars) { bool debugme= false; if(debugme) { string cList= nl->ToString(ConstraintList); cerr<::iterator it= IntervalVars.begin(); it!= IntervalVars.end(); ++it) cerr<<*it<<'\t'; } enum relIndex{ aA=0, ab=1, aB=2, ba=3, bA=4, bB=5, Ab=6, AB=7, Ba=8, BA=9, Aa=10, Bb=11}; //defined in TemporalReasoner.h //enum PARelation{lss=0, leq=1, grt=2, geq=3, eql=4, neq=5, uni=6, inc=7}; PARelation PARels[12]; int aIndex, AIndex, bIndex, BIndex; unsigned int numIntervals= 2 * IntervalVars.size(); PointAlgebraReasoner PAReasoner(numIntervals); map alias2IAIndex; ListExpr ConstraintListRest = nl->Second(ConstraintList); ListExpr STConstraint; ListExpr IARelListRest; STVector IAVector(0); string alias, IARel; set > relatedPairs; int i=-1, j; for(vector::iterator it=IntervalVars.begin(); it< IntervalVars.end(); ++it) assert(alias2IAIndex.insert(pair(*it, ++i)).second); while( !nl->IsEmpty(ConstraintListRest) ) { STConstraint = nl->First(ConstraintListRest); ConstraintListRest = nl->Rest(ConstraintListRest); alias= nl->StringValue(nl->Second(STConstraint)); i= alias2IAIndex[alias]; alias= nl->StringValue(nl->Third(STConstraint)); j= alias2IAIndex[alias]; if((! relatedPairs.insert(make_pair(i,j)).second) || (! relatedPairs.insert(make_pair(j,i)).second)) return nl->TwoElemList(nl->IntAtom(0), nl->IntAtom(notPA)); IAVector.Clear(); IARelListRest= nl->Fourth(STConstraint); //(vec "aabb" "abab" ...) IARelListRest= nl->Rest(IARelListRest); //("aabb" "abab" ...) while( !nl->IsEmpty(IARelListRest) ) { IARel= nl->StringValue(nl->First(IARelListRest)); IARelListRest= nl->Rest(IARelListRest); IAVector.Add(IARel); } if(! IAVector.Vector2PARelations((int*)PARels)) return nl->TwoElemList(nl->IntAtom(0), nl->IntAtom(notPA)); aIndex= i*2; AIndex= (i*2)+1; bIndex= j*2; BIndex= (j*2)+1; for(int k=0; k<12; ++k) { if(PARels[k] == unknown) continue; switch(k) { case aA: PAReasoner.Add(aIndex, AIndex, PARels[k]); break; case ab: PAReasoner.Add(aIndex, bIndex, PARels[k]); break; case aB: PAReasoner.Add(aIndex, BIndex, PARels[k]); break; case ba: PAReasoner.Add(bIndex, aIndex, PARels[k]); break; case bA: PAReasoner.Add(bIndex, AIndex, PARels[k]); break; case bB: PAReasoner.Add(bIndex, BIndex, PARels[k]); break; case Ab: PAReasoner.Add(AIndex, bIndex, PARels[k]); break; case AB: PAReasoner.Add(AIndex, BIndex, PARels[k]); break; case Ba: PAReasoner.Add(BIndex, aIndex, PARels[k]); break; case BA: PAReasoner.Add(BIndex, AIndex, PARels[k]); break; case Aa: PAReasoner.Add(AIndex, aIndex, PARels[k]); break; case Bb: PAReasoner.Add(BIndex, bIndex, PARels[k]); break; default: assert(0); } } } if(debugme) PAReasoner.Print(cerr); bool isConsistent= PAReasoner.Close(); if(!isConsistent) return nl->TwoElemList(nl->IntAtom(0), nl->IntAtom(inconsistent)); if(debugme) PAReasoner.Print(cerr); return PAReasoner.ExportToNestedList(); } /* ~ImportPAReasonerFromArgs~\\ This function is used to import the PointAlgebraReasoner in the value mapping. */ ClosureResult ImportPAReasonerFromArgs( Supplier TRTable, PointAlgebraReasoner*& paReasoner) { Word value; bool debugme=false; if(debugme) qp->ListOfTree(TRTable, cerr); Supplier son= qp->GetSon(TRTable, 0), raw; qp->Request(son, value); int PAReasonerN= static_cast(value.addr)->GetValue(); int tblIndex=0; ClosureResult res= consistent; if(PAReasonerN != 0) { paReasoner= new PointAlgebraReasoner(PAReasonerN); int *Table= new int[PAReasonerN * PAReasonerN + 1]; Table[tblIndex++]= PAReasonerN; for(int i=1; i<= PAReasonerN; ++i) { if(debugme) cerr<GetSon(TRTable, i); for(int j=0; j< PAReasonerN ; ++j) { son= qp->GetSon(raw, j); qp->Request(son, value); Table[tblIndex++]= static_cast(value.addr)->GetIntval(); if(debugme) cerr<(value.addr)->GetIntval()<<","; } } paReasoner->ImportFromArray(Table); delete[] Table; } else { son= qp->GetSon(TRTable, 1); qp->Request(son, value); res= static_cast( static_cast(value.addr)->GetIntval()); } return res; } /* ~CreateMaximalPeriods~\\ */ Periods* CreateMaximalPeriods() { Instant i1(instanttype); i1.ToMinimum(); Instant i2(instanttype); i2.ToMaximum(); Interval I(i1, i2, true, true); Periods* periods= new Periods(0); periods->Add(I); return periods; } /* ~CSPSetPredsArgs~\\ */ bool CSPSetPredsArgs(Supplier predList, Tuple* tup, Periods* periods) { ArgVectorPointer funargs; Supplier namedpred,pred; int noofpreds= qp->GetNoSons(predList); for(int i=0; i< noofpreds; i++) { namedpred= qp->GetSupplierSon(predList, i); //alias= qp->GetSupplierSon(namedpred, 0); pred = qp->GetSupplierSon(namedpred, 1); funargs = qp->Argument(pred); ((*funargs)[0]).setAddr(tup); ((*funargs)[1]).setAddr(periods); } return true; } /* \section{Algebra Types and Operators} */ /* \subsection{The stvector Type} */ TypeConstructor stvectorTC( "stvector", // name of the type in SECONDO STVector::Property, // property function describing signature STVector::Out, STVector::In, // Out and In functions 0, 0, // SaveToList, RestoreFromList functions STVector::Create, STVector::Delete, // object creation and deletion STVector::Open, STVector::Save, // object open, save STVector::Close, STVector::Clone, // close, and clone 0, // cast function STVector::SizeOfObj, // sizeof function STVector::KindCheck ); // kind checking function /* \subsection{The createstvector Operator} */ ListExpr CreateSTVectorTM(ListExpr args) { // bool debugme= false; string argstr; ListExpr rest= args, first; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); nl->WriteToString(argstr, first); if(!nl->IsAtom(first) || nl->SymbolValue(first)!= CcString::BasicType()) { ErrorReporter::ReportError( "Operator v: expects a list of strings but got '" + argstr + "'.\n"); return nl->SymbolAtom(Symbols::TYPEERROR()); } } return nl->SymbolAtom(STVector::BasicType()); } int CreateSTVectorVM (Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); int noconn= qp->GetNoSons(s); string simple; STVector* res= (STVector*) result.addr; for(int i=0;iGetValue(); if(! res->Add(simple)) return 1; } return 0; } const string CreateSTVectorSpec = "( ( " " \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( " " (list of string) -> stvector" " vec( _ )" " Creates a vector temporal relations, to be used within the " " spatiotemporal pattern query operators (e.g., stpattern, reportpattern)." " " " let meanwhile = vec(\"abab\",\"abba\",\"aba.b\");" ") )"; Operator createstvector ( "vec", //name CreateSTVectorSpec, //specification CreateSTVectorVM, //value mapping Operator::SimpleSelect, //trivial selection function CreateSTVectorTM //type mapping ); /* \subsection{The stpattern and stpatternex Operators} */ template ListExpr STPatternTM(ListExpr args) { bool debugme= false; string opName= extended? "stpatternex": "stpattern"; string argstr; if(debugme) { cout<ToString(args)<WriteToString(argstr, args); if((!extended && nl->ListLength(args) != 3) || (extended && nl->ListLength(args) != 4)) { ErrorReporter::ReportError("Operator "+ opName +": expects " + int2string(3 + extended) + "arguments\nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr tupleExpr = nl->First(args), NamedPredList = nl->Second(args), ConstraintList = nl->Third(args); nl->WriteToString(argstr, tupleExpr); if(!IsTupleExpr(tupleExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects " "argument a list with structure (tuple ((a1 t1)...(an tn))).\n" "But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, NamedPredList); if(! IsSimplePredicateList(NamedPredList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "aliased predicates. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, ConstraintList); if(!IsConstraintList(ConstraintList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "temporal connectors. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } set predAliases1, predAliases2; ExtractPredAliasesFromPredList(NamedPredList, predAliases1); ExtractPredAliasesFromConstraintList(ConstraintList, predAliases2); if(debugme) { set::iterator it1= predAliases1.begin(), it2= predAliases2.begin(); cerr<SymbolAtom(Symbols::TYPEERROR()); } if(extended) { ListExpr boolExpr= nl->Fourth(args); nl->WriteToString(argstr, boolExpr); if(!IsBoolExpr(boolExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a boolean " "expression. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } } ListExpr result = nl->SymbolAtom(CcBool::BasicType()); if(debugme) { cout< int STPatternVM(Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme= false; Word Value; Supplier namedpredlist, constraintlist, filter; result = qp->ResultStorage( s ); namedpredlist = args[1].addr; constraintlist= args[2].addr; if(debugme) { Word w; qp->Request(args[0].addr, w); Tuple* tuple= static_cast(w.addr); cerr<(tuple->GetAttribute(0))->GetValue(); cerr<<", Line: "<< static_cast(tuple->GetAttribute(1))->GetValue(); } csp.Clear(); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); bool hasSolution= false; hasSolution=csp.Solve(); ((CcBool*)result.addr)->Set(true, hasSolution); if(!hasSolution || !extended) return 0; //if extended filter= args[3].addr; bool Part2=false; while(!Part2 && csp.MoveNext()) { qp->Request(filter, Value); Part2= ((CcBool*)Value.addr)->GetValue(); } ((CcBool*)result.addr)->Set(true,Part2); return 0; } const string STPatternSpec = "( ( " " \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " " tuple(x) X namedFunlist X constraintList -> bool" " _ stpattern[ namedFunlist; constraintList ]" " The operator implements the Spatiotemporal Pattern Predicate. The " " namedFunList parameter is a comma separated list in the form alias: " " time-dependent predicate, ... . The constraintList is a comma separated " " list in the form stconstraint(_,_,_), ... . The stpattern predicate " " yields true iff the input tuple fulfills all the time-dependent " " predicates (namedFunList) in the exact temporal order specified by " " (constraintList). Please refer to Mahmoud Sakr, Ralf Hartmut G\"{u}ting: '" " Spatiotemporal pattern queries', Geoinformatica (2011) 15:497-540." " " " " " query Trains feed " " filter[. stpattern[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ]] " " count;" "" ") )"; const string STPatternExSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " " tuple(x) X namedFunlist X constraintList X bool -> bool" " _ stpatternex[ namedFunlist; constraintList; bool ]" " This operator implements the Extended Spatiotemporal Pattern " " Predicate. The original predicate (the stpattern operator) asserts that " " all the time-dependent predicates (namedFunList) are fulfilled in the " " exact temporal order specified in (constraintList). This stpatternex " " predicate additionally allows for a bool condition expressed on the parts" " of the trajecotry that match the pattern. One can use this parameter " " for example to assert that the second time-dependent predicate starts to " " be true no more than 5 minutes after the first time-dependent predicate " " ends to be true. For more information, please refer to Mahmoud Sakr, " " Ralf Hartmut G\"{u}ting: ' Spatiotemporal pattern queries', " " Geoinformatica (2011) 15:497-540." " query Trains feed " " filter[. stpatternex[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\"))" " ; (end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)]]]" " count" ") )"; Operator stpattern ( "stpattern", //name STPatternSpec, //specification STPatternVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternTM //type mapping ); Operator stpatternex ( "stpatternex", //name STPatternExSpec, //specification STPatternVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternTM //type mapping ); /* \subsection{The stpatternextend and stpatternexextend Operators} */ template ListExpr STPatternExtendTM(ListExpr args) { bool debugme= false; string opName; if(extended && enableTemporalReasoner && extendstream) opName= "stpatternexextendstream2"; else if(!extended && enableTemporalReasoner && extendstream) opName= "stpatternextendstream2"; else if(extended && !enableTemporalReasoner && extendstream) opName= "stpatternexextendstream"; else if(extended && enableTemporalReasoner && !extendstream) opName= "stpatternexextend2"; else if(!extended && !enableTemporalReasoner && extendstream) opName= "stpatternextendstream"; else if(!extended && enableTemporalReasoner && !extendstream) opName= "stpatternextend2"; else if(extended && !enableTemporalReasoner && !extendstream) opName= "stpatternexextend"; else if(!extended && !enableTemporalReasoner && !extendstream) opName= "stpatternextend"; string argstr; if(debugme) { cout<ToString(args)<WriteToString(argstr, args); if((!extended && nl->ListLength(args) != 3) || (extended && nl->ListLength(args) != 4)) { ErrorReporter::ReportError("Operator "+ opName +": expects " + int2string(3 + extended) + "arguments\nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr StreamExpr = nl->First(args), //stream(tuple(x)) NamedPredList = nl->Second(args), //named predicate list ConstraintList = nl->Third(args); //STConstraint list nl->WriteToString(argstr, StreamExpr); if(!IsTupleStream(StreamExpr, true)) { ErrorReporter::ReportError("Operator "+ opName+ ": expects " "a list with structure (stream(tuple ((a1 t1)...(an tn)))).\n" "But got '" + argstr + "'."); return nl->TypeError(); }; nl->WriteToString(argstr, NamedPredList); if((enableTemporalReasoner && !IsMapTuplePeriodsPredicateList(NamedPredList, true))|| (!enableTemporalReasoner && !IsMapTuplePredicateList(NamedPredList, true))) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "aliased predicates. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, ConstraintList); if(!IsConstraintList(ConstraintList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "temporal connectors. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } set predAliases1, predAliases2; ListExpr TupleExpr = nl->Second(nl->First(StreamExpr)); //tuple(x) ListExpr AttrList = nl->Second(TupleExpr); ExtractPredAliasesFromPredList(NamedPredList, predAliases1); ExtractPredAliasesFromConstraintList(ConstraintList, predAliases2); if(IsAliasInAttributeNames(AttrList, predAliases1)) { ErrorReporter::ReportError("Operator "+ opName +": alias" " is already an attribute name in the input stream"); return nl->TypeError(); } if(IsAliasInCatalog(predAliases1)) { ErrorReporter::ReportError("Operator "+ opName +": alias" " is a known DB type"); return nl->TypeError(); } if((predAliases1.size() != predAliases2.size()) || !std::equal(predAliases1.begin(), predAliases1.end(), predAliases2.begin())) { ErrorReporter::ReportError("Operator "+ opName +": unknown aliases in " "temporal constraints."); return nl->SymbolAtom(Symbols::TYPEERROR()); } vector aliases; ExtractPredAliasesFromPredList(NamedPredList, aliases); ListExpr resAttrlist= nl->OneElemList(nl->TwoElemList( nl->First(nl->First(AttrList)), nl->Second(nl->First(AttrList)))), last= resAttrlist; int n= 1; while(n < nl->ListLength(AttrList)) last= nl->Append(last, nl->Nth(++n, AttrList)); for(vector::iterator it= aliases.begin(); it!=aliases.end(); ++it) last= nl->Append(last, nl->TwoElemList(nl->SymbolAtom(*it), nl->SymbolAtom(Periods::BasicType()))); if(extended) { ListExpr boolExpr= nl->Fourth(args); nl->WriteToString(argstr, boolExpr); if(!IsBoolMap(boolExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a boolean " "expression. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } } ListExpr result, resStream= nl->TwoElemList(nl->SymbolAtom(Stream::BasicType()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),resAttrlist)); if(enableTemporalReasoner) { ListExpr PAReasoner= ComputeClosure(ConstraintList, aliases); result = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(PAReasoner), resStream); } else result= resStream; if(debugme) { cout<ToString(result); cout.flush(); //return nl->SymbolAtom(Symbols::TYPEERROR()); } return result; } template int STPatternExtendVM( Word* args, Word& result, int message, Word& local, Supplier s) { //bool debugme=false; Word t, value; Tuple* tup; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; qp->Open(stream); csp.Clear(); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; }break; case REQUEST : { Supplier stream, namedpredlist, filter; resultTupleType = (TupleType *)local.addr; stream= args[0].addr; qp->Request(stream ,t); if (qp->Received(stream)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); ++i ) newTuple->CopyAttribute( i, tup, i ); csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, tup); bool hasSolution= csp.Solve(); if(!hasSolution || !extended) { csp.AppendSolutionToTuple(0, tup, newTuple); tup->DeleteIfAllowed(); result.setAddr(newTuple); return YIELD; } //IF !extended filter= args[3].addr; bool Part2=false; ArgVectorPointer funargs= qp->Argument(filter); ((*funargs)[0]).setAddr(tup); while(!Part2 && csp.MoveNext()) { qp->Request(filter, value); Part2= ((CcBool*)value.addr)->GetValue(); } if(Part2) csp.AppendSolutionToTuple(csp.iterator, tup, newTuple); else csp.AppendUnDefsToTuple(tup, newTuple); tup->DeleteIfAllowed(); result.setAddr(newTuple); return YIELD; } else return CANCEL; }break; case CLOSE : { if(local.addr) { ((TupleType *)local.addr)->DeleteIfAllowed(); local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert(0); } return 0; } const string STPatternExtendSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList -> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternextend[ namedFunlist; constraintList ]" "The stpatternextend is the (non-predicate) version of the stpattern " " operator. The namedFunList parameter is a comma " " separated list in the form alias: time-dependent predicate, ... . The " " constraintList is a comma separated list in the form stconstraint(_,_,_)," " ... . The stpattern predicate yields true iff the input tuple fulfills " " all the time-dependent predicates (namedFunList) in the exact temporal " " order specified by (constraintList). Unlike the stpattern predicate, the " " stpatternextend extends the input stream with the first supported " " assignment. Tuples that doesn't fulfill the pattern are extended with " " undef values." "query Trains feed " " stpatternextend[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ] " " filter[ isdefined(.IsClose) ] count " "" ") )"; const string STPatternExExtendSpec = "( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList X bool-> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "_ stpatternexextend[ namedFunlist; constraintList; bool]" "The operator extends the input stream with the first supported " " assignment. Tuples that doesn't fulfill " " the pattern are extended with undef values." "query Trains feed " " stpatternexextend[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\"))" " ; (end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)]] " " filter[ isdefined(.IsClose) ] count" "" ") )"; Operator stpatternextend ( "stpatternextend", //name STPatternExtendSpec, //specification STPatternExtendVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); Operator stpatternexextend ( "stpatternexextend", //name STPatternExExtendSpec, //specification STPatternExtendVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); /* \subsection{The stpatternextendstream and stpatternexextendstream Operators} The typemap is defined before as ~STPatternExtendTM~ */ struct STPExtendStreamInfo { TupleType *resultTupleType; Tuple* tup; PointAlgebraReasoner* paReasoner; }; int STPatternExtendStreamVM( Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme= false; Word t, value; STPExtendStreamInfo *localInfo; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; qp->Open(stream); csp.Clear(); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); localInfo= new STPExtendStreamInfo(); resultType = GetTupleResultType( s ); localInfo->resultTupleType = new TupleType( nl->Second( resultType ) ); localInfo->tup=0; local.setAddr( localInfo ); return 0; }break; case REQUEST : { Supplier stream, namedpredlist; localInfo= (STPExtendStreamInfo*) local.addr; stream= args[0].addr; bool hasMoreSol= csp.MoveNext(); while(csp.SA.empty()|| !hasMoreSol) { if(localInfo->tup != 0) { localInfo->tup->DeleteIfAllowed(); localInfo->tup= 0; } qp->Request(stream ,t); if (qp->Received(stream)) localInfo->tup = (Tuple*)t.addr; else return CANCEL; csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, localInfo->tup); if(csp.Solve()) { hasMoreSol= csp.MoveNext(); if(debugme) cerr<< csp.SA.size() << " + "; } } if(debugme && 0) cerr<< "\nsa "<resultTupleType ); for( int i = 0; i < localInfo->tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, localInfo->tup, i ); csp.AppendSolutionToTuple(csp.iterator, localInfo->tup, newTuple); result.setAddr(newTuple); return YIELD; }break; case CLOSE : { if(local.addr != 0) { ((STPExtendStreamInfo*)local.addr)->resultTupleType->DeleteIfAllowed(); delete (STPExtendStreamInfo*)local.addr; local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert( 0); } return 0; } int STPatternExExtendStreamVM( Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme=false; Word t, Value; STPExtendStreamInfo *localInfo; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; qp->Open(stream); csp.Clear(); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); resultType = GetTupleResultType( s ); localInfo= new STPExtendStreamInfo(); localInfo->resultTupleType = new TupleType( nl->Second( resultType ) ); localInfo->tup= 0; local.setAddr(localInfo ); return 0; }break; case REQUEST : { Supplier stream, namedpredlist, filter; filter= args[3].addr; localInfo = (STPExtendStreamInfo *)local.addr; stream= args[0].addr; while(true) { bool hasMoreSol= csp.MoveNext(); while(csp.SA.empty() || !hasMoreSol) { if(localInfo->tup != 0) { localInfo->tup->DeleteIfAllowed(); localInfo->tup= 0; } qp->Request(stream ,t); if (qp->Received(stream)) localInfo->tup = (Tuple*)t.addr; else return CANCEL; csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, localInfo->tup); if(csp.Solve()) { hasMoreSol= csp.MoveNext(); if(debugme) cerr<< csp.SA.size() << " + "; } } if(debugme) cerr<< "\nsa "<Argument(filter); ((*funargs)[0]).setAddr(localInfo->tup); qp->Request(filter, Value); Part2= ((CcBool*)Value.addr)->GetValue(); while(!Part2 && csp.MoveNext()) { qp->Request(filter, Value); Part2= ((CcBool*)Value.addr)->GetValue(); } if(Part2) { if(debugme) cerr<< "\nsa "<resultTupleType ); for( int i = 0; i < localInfo->tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, localInfo->tup, i ); csp.AppendSolutionToTuple(csp.iterator, localInfo->tup, newTuple); result.setAddr(newTuple); return YIELD; } } }break; case CLOSE : { if(local.addr != 0) { ((STPExtendStreamInfo*)local.addr)->resultTupleType->DeleteIfAllowed(); delete (STPExtendStreamInfo*)local.addr; local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert( 0); } return 0; } const string STPatternExtendStreamSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList -> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternextendstream[ namedFunlist; constraintList ]" "The operator extends each tuple in the input stream with all the " " supported assignments (i.e. periods that fulfill the pattern). " " Tuples that don't fulfill the pattern don't appear in the results." "" "query Trains feed " " stpatternextendstream[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ] " " filter[isdefined(.IsClose)] count " "" ") )"; const string STPatternExExtendStreamSpec = "( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList X bool-> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternexextendstream[ namedFunlist; constraintList; bool]" "" "The operator extends each tuple in the input stream with all the " " supported assignemts (i.e., periods that fulfill the pattern). Tuples that" " doesn't fulfill the pattern don't appear in the results." "" "query Trains feed " " stpatternexextendstream[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\"))" " ; (end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)] ] " " filter[ isdefined(.IsClose) ] count " "" ") )"; Operator stpatternextendstream ( "stpatternextendstream", //name STPatternExtendStreamSpec, //specification STPatternExtendStreamVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); Operator stpatternexextendstream ( "stpatternexextendstream", //name STPatternExExtendStreamSpec, //specification STPatternExExtendStreamVM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); /* \subsection{The stconstraint faked Operator} This valuemap of this operator is not called by query processor. It is evaluated inside the value maps of the STP query operators (i.e., inside the ~Solve~ function). */ ListExpr STConstraintTM(ListExpr args) { bool debugme= false; string argstr; if(debugme) { cout<ToString(args)<HasLength(args,3)){ return listutils::typeError("3 arguments expected"); } ListExpr alias1 = nl->First(args), //tuple(x) alias2 = nl->Second(args), //named predicate list temporalconnector = nl->Third(args);//STConstraint list nl->WriteToString(argstr, alias1); if(!nl->IsAtom(alias1) || nl->SymbolValue(alias1)!= CcString::BasicType()) { ErrorReporter::ReportError( "Operator stconstraint: expects a predicate label as first " "argument.\n But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, alias2); if(!nl->IsAtom(alias2) || nl->SymbolValue(alias2)!= CcString::BasicType()) { ErrorReporter::ReportError( "Operator stconstraint: expects a predicate label as second " "argument.\n But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, temporalconnector); if(!nl->IsAtom(temporalconnector) || nl->SymbolValue(temporalconnector) != STVector::BasicType()) { ErrorReporter::ReportError( "Operator stconstraint: expects a temporal connector as third " "argument.\n But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr result = nl->SymbolAtom(CcBool::BasicType()); if(debugme) { cout<string X string X stvector -> bool" "_ stconstraint( string, string, vec(_))" "This operator is faked. It can be used only within the stpattern and " " stpatternex operators. It is used to express a temporal constraint. " " The operator doesn't have a value mapping function because it " " is evaluated within the stpattern. It should never be called elsewhere." "" " " " query Trains feed " " filter[. stpattern[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ]] " " count;" "" ") )"; Operator stconstraint ( "stconstraint", //name STConstraintSpec, //specification STConstraintVM, //value mapping Operator::SimpleSelect, //trivial selection function STConstraintTM //type mapping ); /* \subsection{The start and end Operators} */ ListExpr StartEndTM(ListExpr args) { bool debugme=false; string argstr; if(debugme) { cout<ToString(args) <ListLength(args) << ".."<< nl->IsAtom(nl->First(args))<< ".."<< nl->SymbolValue(nl->First(args)); cout.flush(); } nl->WriteToString(argstr, args); if(nl->ListLength(args) != 1 || !nl->IsAtom(nl->First(args)) || nl->SymbolValue(nl->First(args))!= CcString::BasicType()) { ErrorReporter::ReportError("Operator start/end expects a string symbol " "but got." + argstr); return nl->SymbolAtom(Symbols::TYPEERROR()); } return nl->SymbolAtom(Instant::BasicType()); } template int StartEndVM (Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme= false; Interval interval; Word input; string lbl; //qp->Request(args[0].addr, input); lbl= ((CcString*)args[0].addr)->GetValue(); if(debugme) { cout<ResultStorage( s ); ((Instant*)result.addr)->CopyFrom(&res); return 0; } const string StartEndSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "string -> instant" "start( _ )/ end(_)" "These are faked operators. They can only be used within an extended " " spatiotemporal pattern predicate or operator. They return the start and " " end time instants for a predicate in the SA list. These operators should " " never be called alone." " query Trains feed " " filter[. stpatternex[" " InSnow: .Trip inside msnow, " " IsClose: distance(.Trip, mehringdamm) < 10.0, " " IsFast: speed(.Trip) > 8.0 " " ; stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\"))" " ; (end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)]]]" " count" ") )"; Operator start ( "start", //name StartEndSpec, //specification StartEndVM, //value mapping Operator::SimpleSelect, //trivial selection function StartEndTM //type mapping ); Operator end ( "end", //name StartEndSpec, //specification StartEndVM, //value mapping Operator::SimpleSelect, //trivial selection function StartEndTM //type mapping ); /* \subsection{The randommbool, passmbool, and randomdelay Operators} The randommbool operator is used for experimental evaluation. We use it to generate the random mbool values that are used in the first experiment in the technical report. */ ListExpr RandomMBoolTM(ListExpr args) { //cout<ToString(args); if(nl->ListLength(args) != 1 || !nl->IsAtom(nl->First(args)) || nl->SymbolValue(nl->First(args))!= Instant::BasicType()) { ErrorReporter::ReportError("Operator randommbool expects one parameter."); return nl->SymbolAtom(Symbols::TYPEERROR()); }; return nl->SymbolAtom(MBool::BasicType()); } /* The passmbool operator is used for experimental evaluation. We use it to mimic time-dependent predicates in the first experiment in the technical report. */ ListExpr PassMBoolTM(ListExpr args) { //cout<ToString(args); if(nl->ListLength(args) != 1 || !nl->IsAtom(nl->First(args)) || nl->SymbolValue(nl->First(args))!= MBool::BasicType()) { ErrorReporter::ReportError("Operator passmbool expects one parameter."); return nl->SymbolAtom(Symbols::TYPEERROR()); } return nl->SymbolAtom(MBool::BasicType()); } /* The randomdelay operator is used to enrich the examples. It adds random time delays to the moving point within a given delay threshold */ ListExpr RandomDelayTM( ListExpr typeList ) { if(!(nl->ListLength(typeList) == 2 && nl->IsAtom(nl->First(typeList)) && (nl->SymbolValue(nl->First(typeList))== MPoint::BasicType()) && nl->IsAtom(nl->Second(typeList)) && (nl->SymbolValue(nl->Second(typeList))== Duration::BasicType()))) { ErrorReporter::ReportError( "randomdelay operator expects (" + MPoint::BasicType() + " " + Duration::BasicType() + ") but got " + nl->ToString(typeList)); return nl->SymbolAtom(Symbols::TYPEERROR()); } return (nl->SymbolAtom(MPoint::BasicType())); } void CreateRandomMBool(Instant starttime, MBool& result) { bool debugme=false,bval=false; result.Clear(); int rnd,i=0,n; UBool unit(true); Interval intr(starttime, starttime, true, false); rnd=rand()%20; //deciding the number of units in the mbool value n=++rnd; bval= ((rand()%2)==1); //deciding the bool value of the first unit while(i++ResultStorage(s); MBool* res = (MBool*) result.addr; DateTime* tstart = (DateTime*) args[0].addr; CreateRandomMBool(*tstart,*res); return 0; } int PassMBoolVM(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MBool* res = (MBool*) result.addr; MBool* inp = (MBool*) args[0].addr; res->CopyFrom(inp); return 0; } int RandomDelayVM(ArgVector args, Word& result, int msg, Word& local, Supplier s ) { MPoint *pActual = static_cast( args[0].addr ); Instant *threshold = static_cast(args[1].addr ); MPoint* shifted = (MPoint*) qp->ResultStorage(s).addr; if(pActual->GetNoComponents()<2 || !pActual->IsDefined()) shifted->CopyFrom(pActual); else { RandomDelay(pActual, threshold, *shifted); } result= SetWord(shifted); //This looks redundant but it is really necessary. After 2 hours of //debugging, it seems that the "result" word is not correctly set //by the query processor to point to the results. return 0; } const string RandomMBoolSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( instant -> mbool" "randommbool( _ )" "Creates a random mbool value. The operator is used for testing" "purposes." "let mb1 = randommbool(now())" ") )"; const string PassMBoolSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( mbool -> mbool" "passmbool( _ )" "Mimics a time-dependent predicate. The operator takes the name" "of an mbool dbobject and return the object itself. The operator is " "used for testing purposes." "let mb2= passmbool(mb1)" ") )"; const string RandomDelaySpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( mpoint x duration -> mpoint" "randomdelay(schedule, delay_threshold)" "Given an mpoint and a duration value, the operator randomly shift " "the start and end instants of every unit in the mpoint. This gives the " "effect of having positive and negative delays in the movement. The " "random shift value is bound by the given threshold." "query randomdelay(train7)" ") )"; Operator randommbool ( "randommbool", // name RandomMBoolSpec, // specification RandomMBoolVM, // value mapping Operator::SimpleSelect, // trivial selection function RandomMBoolTM // type mapping ); Operator passmbool ( "passmbool", // name PassMBoolSpec, // specification PassMBoolVM, // value mapping Operator::SimpleSelect, // trivial selection function PassMBoolTM // type mapping ); Operator randomdelay ( "randomdelay", // name RandomDelaySpec, // specification RandomDelayVM, // value mapping Operator::SimpleSelect, // trivial selection function RandomDelayTM // type mapping ); /* \section{Temporal Reasoning} This part was added to the algebra in 2011. The technique is descriped in Chapter 6 of the PhD thesis of Mahmoud Sakr. Mainly we introduce a copy of each of the STP operators defined above, where this copy has the same name with an appended "2" at the end. For example the temporal reasoning version of stpattern is called stpattern2. The goal of temporal reasoning is to use the temporal information that the ~Solve~ function collects from the temporal constraints and the during the evaluation of the CSP, in order to restrict the trajectories after every iteration. This should improve the run-time of the operators. */ /* \subsection{The computeclosure Operator} */ ListExpr ComputeClosureTM(ListExpr args) { bool debugme= false; string opName= "computeclosure"; string argstr; if(debugme) { cout<ToString(args)<WriteToString(argstr, args); if( nl->ListLength(args) != 3) { ErrorReporter::ReportError("Operator "+ opName +": expects " + int2string(3 ) + "arguments\nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr tupleExpr = nl->First(args), NamedPredList = nl->Second(args), ConstraintList = nl->Third(args); nl->WriteToString(argstr, tupleExpr); if(!IsTupleExpr(tupleExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects " "argument a list with structure (tuple ((a1 t1)...(an tn))).\n" "But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, NamedPredList); if(!IsMapTuplePeriodsPredicateList(NamedPredList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "aliased predicates, each of which has the syntax " "(tuple, periods)->bool. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, ConstraintList); if(!IsConstraintList(ConstraintList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "temporal connectors. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } vector predAliases1Unsorted; set predAliases1, predAliases2; ExtractPredAliasesFromPredList(NamedPredList, predAliases1Unsorted); ExtractPredAliasesFromConstraintList(ConstraintList, predAliases2); predAliases1.insert(predAliases1Unsorted.begin(), predAliases1Unsorted.end()); if((predAliases1.size() != predAliases2.size()) || !std::equal(predAliases1.begin(), predAliases1.end(), predAliases2.begin())) { ErrorReporter::ReportError("Operator "+ opName +": unknown aliases in " "temporal constraints."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr PAReasoner= ComputeClosure(ConstraintList, predAliases1Unsorted); ListExpr result = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(PAReasoner), nl->SymbolAtom(CcInt::BasicType())); if(debugme) { cout<WriteToString(argstr, result); cout<ResultStorage( s ); ((CcInt*)result.addr)->Set(true, closureRes); return 0; } const string ComputeClosureSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) ( tuple(x) X periods X namedFunlist X " "constraintList -> int" "_ computeclosure[ namedFunlist; constraintList ]" "The operator is gets the same set of arguments of stpattern2 " "Predicate. It constructs the point algebra constraint network for the given " "arguments, and tries to compute its closure. The result is: 0 if the network" " is inconsistent, 1 if it is consistent, 2 if it is not representable by the" "point algebra (i.e., does not belong to the continuous endpoint algebra)." "" "query Trains feed " "filter[. computeclosure[" "insnow: fun(t1: STREAMELEM, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " "isclose: fun(t2: STREAMELEM, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm)<10.0, " "isfast: fun(t3: STREAMELEM, p3: periods) " " speed( attr(t3, Trip) atperiods p3) >8.0 ; " "stconstraint(\"insnow\",\"isclose\",vec(\"aabb\")), " "stconstraint(\"isclose\",\"isfast\",vec(\"bbaa\"))] = 1 ] count" ") )"; void RandomShiftDelay( const MPoint* actual, const Instant* threshold, double dx, double dy, MPoint& res) { bool debugme= false; MPoint delayed(actual->GetNoComponents()); UPoint first(0), next(0); UPoint *shifted,*temp, *cur; int xshift=0, yshift=0; int64_t rmillisec=0; actual->Get( 0, first ); cur=new UPoint(first); for( int i = 1; i < actual->GetNoComponents(); i++ ) { actual->Get( i, next ); if(threshold->millisecondsToNull() > 0) rmillisec= rand()% threshold->GetAllMilliSeconds(); DateTime delta(durationtype, rmillisec) ; xshift= rand() % ((int)dx +1); yshift= rand() % ((int)dy +1); shifted= new UPoint(*cur); delete cur; temp= new UPoint(next); if(rmillisec > rand()%24000 ) { if((shifted->timeInterval.end + delta) < next.timeInterval.end ) { shifted->timeInterval.end += delta ; temp->timeInterval.start= shifted->timeInterval.end; shifted->p1.Set(shifted->p1.GetX()+xshift, shifted->p1.GetY()+yshift); temp->p0.Set(shifted->p1.GetX(), shifted->p1.GetY()); } } else { if((shifted->timeInterval.end - delta) >shifted->timeInterval.start) { shifted->timeInterval.end -= delta ; temp->timeInterval.start= shifted->timeInterval.end; shifted->p1.Set(shifted->p1.GetX()-xshift, shifted->p1.GetY()-yshift); temp->p0.Set(shifted->p1.GetX(), shifted->p1.GetY()); } } cur=temp; if(debugme) { cout.flush(); cout<<"\n original "; cur->Print(cout); cout<<"\n shifted " ; shifted->Print(cout); cout.flush(); } delayed.Add(*shifted); delete shifted; } delayed.Add(*temp); delete temp; res.CopyFrom(&delayed); if(debugme) { res.Print(cout); cout.flush(); } return; } /* Value mapping function for the operator ~ndefunit~ */ void NDefUnit(MBool* arg, CcBool* nval, MBool* res) { bool debugme=false; res->Clear(); res->StartBulkLoad(); UBool uarg; UBool uBool(nval->GetBoolval()), uBool2(nval->GetBoolval()); uBool.constValue= *nval; if(!arg->IsDefined()||arg->GetNoComponents() == 0) { res->SetDefined(false); return; } arg->Get(0, uarg); //uarg.Print(cout); uBool2.CopyFrom(&uarg); res->MergeAdd(uBool2); //res->Print(cout); uBool.timeInterval.lc = !uarg.timeInterval.rc; uBool.timeInterval.start = uarg.timeInterval.end; for( int i = 1; i < arg->GetNoComponents(); i++) { arg->Get(i, uarg); uBool.timeInterval.rc = !uarg.timeInterval.lc; uBool.timeInterval.end = uarg.timeInterval.start; if(uBool.timeInterval.start < uBool.timeInterval.end || (uBool.timeInterval.start == uBool.timeInterval.end && uBool.timeInterval.lc && uBool.timeInterval.rc)) { res->MergeAdd(uBool); //res->Print(cout); } uBool2.CopyFrom(&uarg); res->MergeAdd(uBool2); //res->Print(cout); uBool.timeInterval.lc = !uarg.timeInterval.rc; uBool.timeInterval.start = uarg.timeInterval.end; } res->EndBulkLoad(false); if(debugme) { cout<<"NDefUnit is called"; cout<<"\nInput1:"; arg->Print(cout); cout<<"\nInput2:"; nval->Print(cout); cout<<"\nOutput:"; res->Print(cout); cout.flush(); } } int NDefUnitVM( ArgVector args, Word& result, int msg, Word& local, Supplier s ) { bool debugme=false; MBool *arg = static_cast( args[0].addr ); CcBool *ndefval = static_cast( args[1].addr ); MBool* tmp=new MBool(0); result= qp->ResultStorage(s); MBool* res= (MBool*) result.addr; NDefUnit(arg, ndefval, res); //res->CopyFrom(tmp); tmp->Destroy(); delete tmp; if(debugme) { cout.flush(); res->Print(cout); cout.flush(); } return 0; } ListExpr RandomShiftDelayTM( ListExpr args ) { if(!nl->HasLength(args,4)){ return listutils::typeError("4 arguments expected"); } if( !MPoint::checkType(nl->First(args)) || !Duration::checkType(nl->Second(args)) || !CcReal::checkType(nl->Third(args)) || !CcReal::checkType(nl->Fourth(args))){ return listutils::typeError("mpoint x duration x real x real expected"); } return (nl->SymbolAtom("mpoint")); } int RandomShiftDelayVM(ArgVector args, Word& result, int msg, Word& local, Supplier s ) { MPoint *pActual = static_cast( args[0].addr ); Instant *threshold = static_cast(args[1].addr ); double dx = static_cast(args[2].addr )->GetRealval(); double dy = static_cast(args[3].addr )->GetRealval(); MPoint* shifted = (MPoint*) qp->ResultStorage(s).addr; if(pActual->GetNoComponents()<2 || !pActual->IsDefined()) shifted->CopyFrom(pActual); else { RandomShiftDelay(pActual, threshold, dx, dy, *shifted); } result= SetWord(shifted); //This looks redundant but it is really necessary. After 2 hours of //debugging, it seems that the "result" word is not correctly set //by the query processor to point to the results. return 0; } const string RandomShiftDelaySpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( mpoint x duration x real x real-> mpoint" "randomdelay(schedule, delay_threshold, dx, dy)" "Given an mpoint and a duration value, the operator randomly shift the" "start and end intstants of every unit in the mpoint. This gives the " "effect of having positive and negative delays and spatial shifts in the " "movement. The random shift values are bound by the given threshold." " query randomdelay(train7)" ") )"; Operator computeClosure ( "computeclosure", //name ComputeClosureSpec, //specification ComputeClosureVM, //value mapping Operator::SimpleSelect, //trivial selection function ComputeClosureTM //type mapping ); Operator randomshiftdelay ( "randomshiftdelay", // name RandomShiftDelaySpec, // specification RandomShiftDelayVM, // value mapping Operator::SimpleSelect, // trivial selection function RandomShiftDelayTM // type mapping ); /* \subsection{The stpattern2 and stpatternex2 Operators} */ template ListExpr STPattern2TM(ListExpr args) { bool debugme= false; string opName= (extended)? "stpatternex2": "stpattern2"; string argstr; if(debugme) { cout<ToString(args)<WriteToString(argstr, args); if((!extended && nl->ListLength(args) != 3) || (extended && nl->ListLength(args) != 4)) { ErrorReporter::ReportError("Operator "+ opName +": expects " + int2string(3 + extended) + "arguments\nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } ListExpr tupleExpr = nl->First(args), NamedPredList = nl->Second(args), ConstraintList = nl->Third(args); nl->WriteToString(argstr, tupleExpr); if(!IsTupleExpr(tupleExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects " "argument a list with structure (tuple ((a1 t1)...(an tn))).\n" "But got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, NamedPredList); if(!IsMapTuplePeriodsPredicateList(NamedPredList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "aliased predicates, each of which has the syntax " "(tuple, periods)->bool. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } nl->WriteToString(argstr, ConstraintList); if(!IsConstraintList(ConstraintList, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a list of " "temporal connectors. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } vector predAliases1Unsorted; set predAliases1, predAliases2; ExtractPredAliasesFromPredList(NamedPredList, predAliases1Unsorted); ExtractPredAliasesFromConstraintList(ConstraintList, predAliases2); predAliases1.insert(predAliases1Unsorted.begin(), predAliases1Unsorted.end()); if((predAliases1.size() != predAliases2.size()) || !std::equal(predAliases1.begin(), predAliases1.end(), predAliases2.begin())) { ErrorReporter::ReportError("Operator "+ opName +": unknown aliases in " "temporal constraints."); return nl->SymbolAtom(Symbols::TYPEERROR()); } if(extended) { ListExpr boolExpr= nl->Fourth(args); nl->WriteToString(argstr, boolExpr); if(!IsBoolExpr(boolExpr, true)) { ErrorReporter::ReportError("Operator "+ opName +": expects a boolean " "expression. \nBut got '" + argstr + "'."); return nl->SymbolAtom(Symbols::TYPEERROR()); } } ListExpr PAReasoner= ComputeClosure(ConstraintList, predAliases1Unsorted); ListExpr result = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(PAReasoner), nl->SymbolAtom(CcBool::BasicType())); if(debugme) { cout<WriteToString(argstr, result); cout< int STPattern2VM(Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme= false; if(debugme) { Word w; qp->Request(args[0].addr, w); Tuple* tuple= static_cast(w.addr); cerr<(tuple->GetAttribute(0))->GetValue(); cerr<<", Line: "<< static_cast(tuple->GetAttribute(1))->GetValue(); } Supplier namedpredlist, constraintlist, filter, TRTable; result = qp->ResultStorage( s ); Word w; qp->Request(args[0].addr, w); Tuple* tup= static_cast(w.addr); namedpredlist = args[1].addr; constraintlist= args[2].addr; if(extended) { filter= args[3].addr; TRTable= args[4].addr; } else TRTable= args[3].addr; Word value; PointAlgebraReasoner* paReasoner= 0; ClosureResult closureRes= ImportPAReasonerFromArgs(TRTable, paReasoner); csp.Clear(); csp.SetClosureResult(closureRes); if(closureRes == inconsistent) { ((CcBool*)result.addr)->Set(true, false); return 0; } CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); bool hasSolution= false; Periods* periods= CreateMaximalPeriods(); CSPSetPredsArgs(namedpredlist, tup, periods); hasSolution=csp.Solve(periods, paReasoner); delete periods; delete paReasoner; ((CcBool*)result.addr)->Set(true, hasSolution); if(!hasSolution || !extended) return 0; bool Part2=false; while(!Part2 && csp.MoveNext()) { qp->Request(filter, value); Part2= ((CcBool*)value.addr)->GetValue(); } ((CcBool*)result.addr)->Set(true,Part2); return 0; } const string STPattern2Spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) ( tuple(x) X namedFunlist X " "constraintList -> bool" "_ stpattern2[ namedFunlist; constraintList ]" "The operator is an optimized version of the stpattern Predicate " "(Please refer to the stpattern operator). It reasons over the temporal " "constraints and allows the user to restrict the trajectories based on the " "reasoning results. The goal is to reduce the number of trajectory units " "processed by the time-dependent predicates, and thus reduce the run-time. " "For more information, please refer to the PhD thesis of Mahmoud Sakr " "'Spatiotemporal Pattern Queries'|'Chapter 6 Temporal Reasoning'." "" "query Trains feed " " filter[. stpattern2[" " InSnow: fun(t1: STREAMELEM, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsCclose: fun(t2: STREAMELEM, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0, " " IsFast: fun(t3: STREAMELEM, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) " " ]] " " count " ") )"; const string STPatternEx2Spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "tuple(x) X namedFunlist X constraintList X bool -> bool" "_ stpatternex2[ namedFunlist; constraintList; bool ]" "The operator is an optimized version of the stpatternex Predicate. " " It reasons over the temporal constraints and allows the user to restrict " " the trajectories based on the reasoning results. The goal is to reduce " " the number of trajectory units processed by the time-dependent " " predicates, and thus reduce the run-time. For more information, please " " refer to the PhD thesis of Mahmoud Sakr 'Spatiotemporal Pattern " " Queries'|'Chapter 6 Temporal Reasoning'. " "" "query Trains feed " " filter[. stpatternex2[" " InSnow: fun(t1: STREAMELEM, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsClose: fun(t2: STREAMELEM, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0, " " IsFast: fun(t3: STREAMELEM, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) " " ;(end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)] ]]" " count " ") )"; Operator stpattern2 ( "stpattern2", //name STPattern2Spec, //specification STPattern2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPattern2TM //type mapping ); Operator stpatternex2 ( "stpatternex2", //name STPatternEx2Spec, //specification STPattern2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPattern2TM //type mapping ); /* \subsection{The stpatternextend2 and stpatternexextend2 Operators} The typemap is defined before as ~STPatternExtendTM~ */ struct STPatternExtendLocalInfo { public: STPatternExtendLocalInfo(): resultTupleType(0), paReasoner(0){} TupleType* resultTupleType; PointAlgebraReasoner* paReasoner; }; template int STPatternExtend2VM( Word* args, Word& result, int message, Word& local, Supplier s) { //bool debugme=false; Word t, value; Tuple* tup; STPatternExtendLocalInfo *localInfo; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist, TRTable; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; if(extended) { //filter= args[3].addr; TRTable= args[4].addr; } else TRTable= args[3].addr; Word value; localInfo= new STPatternExtendLocalInfo(); resultType = GetTupleResultType( s ); localInfo->resultTupleType = new TupleType( nl->Second( resultType ) ); ClosureResult closureRes= ImportPAReasonerFromArgs(TRTable, localInfo->paReasoner); csp.Clear(); csp.SetClosureResult(closureRes); qp->Open(stream); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); local.setAddr(localInfo); return 0; }break; case REQUEST : { if(csp.GetClosureResult() == inconsistent) return CANCEL; Periods* periods= CreateMaximalPeriods(); Supplier stream, namedpredlist, filter; localInfo= static_cast(local.addr); stream= args[0].addr; qp->Request(stream ,t); if (qp->Received(stream)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( localInfo->resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, tup, i ); csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, tup, periods); bool hasSolution= csp.Solve(periods, localInfo->paReasoner); if(!hasSolution || !extended) { csp.AppendSolutionToTuple(0, tup, newTuple); tup->DeleteIfAllowed(); result.setAddr(newTuple); delete periods; return YIELD; } //IF extended bool Part2=false; filter= args[3].addr; ArgVectorPointer funargs= qp->Argument(filter); ((*funargs)[0]).setAddr(tup); while(!Part2 && csp.MoveNext()) { qp->Request(filter, value); Part2= ((CcBool*)value.addr)->GetValue(); } if(Part2) csp.AppendSolutionToTuple(csp.iterator, tup, newTuple); else csp.AppendUnDefsToTuple(tup, newTuple); tup->DeleteIfAllowed(); result.setAddr(newTuple); delete periods; return YIELD; } else { delete periods; return CANCEL; } }break; case CLOSE : { if(local.addr != 0) { localInfo= static_cast(local.addr); if(localInfo->resultTupleType != 0) localInfo->resultTupleType->DeleteIfAllowed(); if(localInfo->paReasoner != 0) delete localInfo->paReasoner; delete localInfo; local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert( 0); } return 0; } const string STPatternExtend2Spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList -> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternextend2[ namedFunlist; constraintList ]" "The operator extends the input stream with the first supported " " assignment. Tuples that doesn't fulfill the pattern are extended with " " undef values. It is an optimized version of the stpatternextend operator." " It reasons over the temporal constraints and allows the user to " " restrict the trajectories based on the reasoning results." "query Trains feed " " stpatternextend2[" " InSnow: fun(t1: TUPLE, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsClose: fun(t2: TUPLE, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0, " " IsFast: fun(t3: TUPLE, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ] " " filter[isdefined(.IsClose)] count" "" ") )"; const string STPatternExExtend2Spec = "( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList X bool-> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternexextend2[ namedFunlist; constraintList; bool]" "The operator extends the input stream with the first supported " " assignment. Tuples that doesn't fulfill the pattern are extended with " " undef values. This operator is an optimized version of the " " stpatternexextend operator. It reasons over the temporal constraints and " " allows the user to restrict the trajectories based on the reasoning " " results." "" "query Trains feed " " stpatternexextend2[" " InSnow: fun(t1: TUPLE, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsClose: fun(t2: TUPLE, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0," " IsFast: fun(t3: TUPLE, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) " " ;(end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)] ] " " filter[ isdefined(.IsClose) ] count " " " ") )"; Operator stpatternextend2 ( "stpatternextend2", //name STPatternExtend2Spec, //specification STPatternExtend2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); Operator stpatternexextend2 ( "stpatternexextend2", //name STPatternExExtend2Spec, //specification STPatternExtend2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); /* \subsection{The stpatternextendstream2 and stpatternexextendstream2 Operators} The typemap is defined before as ~STPatternExtendTM~ */ int STPatternExtendStream2VM( Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme= false; Word t, value; STPExtendStreamInfo *localInfo; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist, TRTable; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; TRTable= args[3].addr; localInfo= new STPExtendStreamInfo(); resultType = GetTupleResultType( s ); localInfo->resultTupleType = new TupleType( nl->Second( resultType ) ); localInfo->tup=0; ClosureResult closureRes= ImportPAReasonerFromArgs(TRTable, localInfo->paReasoner); csp.Clear(); csp.SetClosureResult(closureRes); qp->Open(stream); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); local.setAddr( localInfo ); return 0; }break; case REQUEST : { if(csp.GetClosureResult() == inconsistent) return CANCEL; Periods* periods= CreateMaximalPeriods(); Supplier stream, namedpredlist; localInfo= static_cast(local.addr); stream= args[0].addr; bool hasMoreSol= csp.MoveNext(); while(csp.SA.empty()|| !hasMoreSol) { if(localInfo->tup != 0) { localInfo->tup->DeleteIfAllowed(); localInfo->tup= 0; } qp->Request(stream ,t); if (qp->Received(stream)) localInfo->tup = (Tuple*)t.addr; else { delete periods; return CANCEL; } csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, localInfo->tup, periods); if(csp.Solve(periods, localInfo->paReasoner)) { hasMoreSol= csp.MoveNext(); if(debugme) cerr<< csp.SA.size() << " + "; } } if(debugme && 0) cerr<< "\nsa "<resultTupleType ); for( int i = 0; i < localInfo->tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, localInfo->tup, i ); csp.AppendSolutionToTuple(csp.iterator, localInfo->tup, newTuple); result.setAddr(newTuple); delete periods; return YIELD; }break; case CLOSE : { if(local.addr != 0) { localInfo= static_cast(local.addr); if(localInfo->resultTupleType != 0) localInfo->resultTupleType->DeleteIfAllowed(); if(localInfo->paReasoner != 0) delete localInfo->paReasoner; delete localInfo; local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert( 0); } return 0; } int STPatternExExtendStream2VM( Word* args, Word& result, int message, Word& local, Supplier s) { bool debugme=false; Word t, Value; STPExtendStreamInfo *localInfo; ListExpr resultType; switch (message) { case OPEN : { Supplier stream, namedpredlist, constraintlist, TRTable; stream = args[0].addr; namedpredlist = args[1].addr; constraintlist= args[2].addr; TRTable= args[4].addr; localInfo= new STPExtendStreamInfo(); resultType = GetTupleResultType( s ); localInfo->resultTupleType = new TupleType( nl->Second( resultType ) ); localInfo->tup= 0; ClosureResult closureRes= ImportPAReasonerFromArgs(TRTable, localInfo->paReasoner); csp.Clear(); csp.SetClosureResult(closureRes); qp->Open(stream); CSPAddPredicates(namedpredlist); CSPAddConstraints(constraintlist); local.setAddr(localInfo ); return 0; }break; case REQUEST : { if(csp.GetClosureResult() == inconsistent) return CANCEL; Periods* periods= CreateMaximalPeriods(); Supplier stream, namedpredlist, filter; localInfo= static_cast(local.addr); filter= args[3].addr; stream= args[0].addr; while(true) { bool hasMoreSol= csp.MoveNext(); while(csp.SA.empty() || !hasMoreSol) { if(localInfo->tup != 0) { localInfo->tup->DeleteIfAllowed(); localInfo->tup= 0; } qp->Request(stream ,t); if (qp->Received(stream)) localInfo->tup = (Tuple*)t.addr; else { delete periods; return CANCEL; } csp.ResetTuple(); namedpredlist = args[1].addr; CSPSetPredsArgs(namedpredlist, localInfo->tup, periods); if(csp.Solve(periods, localInfo->paReasoner)) { hasMoreSol= csp.MoveNext(); if(debugme) cerr<< csp.SA.size() << " + "; } } if(debugme) cerr<< "\nsa "<Argument(filter); ((*funargs)[0]).setAddr(localInfo->tup); qp->Request(filter, Value); Part2= ((CcBool*)Value.addr)->GetValue(); while(!Part2 && csp.MoveNext()) { qp->Request(filter, Value); Part2= ((CcBool*)Value.addr)->GetValue(); } if(Part2) { if(debugme) cerr<< "\nsa "<resultTupleType ); for( int i = 0; i < localInfo->tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, localInfo->tup, i ); csp.AppendSolutionToTuple(csp.iterator, localInfo->tup, newTuple); result.setAddr(newTuple); delete periods; return YIELD; } } }break; case CLOSE : { if(local.addr != 0) { localInfo= static_cast(local.addr); if(localInfo->resultTupleType != 0) localInfo->resultTupleType->DeleteIfAllowed(); if(localInfo->paReasoner != 0) delete localInfo->paReasoner; delete localInfo; local.setAddr(0); } qp->Close(args[0].addr); csp.Clear(); }break; default: assert( 0); } return 0; } const string STPatternExtendStream2Spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList ->" " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternextendstream2[ namedFunlist; constraintList ]" "The operator extends each tuple in the input stream with all the " " supported assignments (i.e. periods that fulfill the pattern). " " Tuples that doesn't fulfill the pattern don't appear in the results. " " This operator is an optimized version of the stpatternextendstream " " operator. It reasons over " " the temporal constraints and allows the user to restrict the trajectories" " based on the reasoning results." "query Trains feed " " stpatternextendstream2[" " InSnow: fun(t1: TUPLE, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsClose: fun(t2: TUPLE, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0, " " IsFast: fun(t3: TUPLE, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) ] " " filter[ isdefined(.IsClose) ] count " "" ") )"; const string STPatternExExtendStream2Spec = "( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( " "stream(tuple(x)) X namedFunlist X constraintList X bool-> " " stream(tuple(x,alias1:Periods,...,alias1:Periods))" "" "_ stpatternexextendstream2[ namedFunlist; constraintList; bool]" "" "The operator extends each tuple in the input stream with all the " " supported assignments (i.e. periods that fulfill the pattern). Tuples that " " doesn't fulfill the pattern don't appear in the results. This operator is " " an optimized version of the stpatternexextendstream operator. It reasons " " over the temporal constraints and allows the user to restrict the " " trajectories based on the reasoning results." "query Trains feed " " stpatternexextendstream2[" " InSnow: fun(t1: TUPLE, p1: periods) " " (attr(t1, Trip) atperiods p1) inside msnow, " " IsClose: fun(t2: TUPLE, p2: periods) " " distance(attr(t2, Trip) atperiods p2, mehringdamm) < 10.0, " " IsFast: fun(t3: TUPLE, p3: periods) " " speed( attr(t3, Trip) atperiods p3) > 8.0 " " ;stconstraint(\"InSnow\",\"IsClose\",vec(\"aabb\")), " " stconstraint(\"IsClose\",\"IsFast\",vec(\"bbaa\")) " " ;(end(\"IsClose\") - start(\"InSnow\")) < [const duration value (1 0)] ]" " filter[ isdefined(.IsClose) ] count " "" ") )"; Operator stpatternextendstream2 ( "stpatternextendstream2", //name STPatternExtendStream2Spec, //specification STPatternExtendStream2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); Operator stpatternexextendstream2 ( "stpatternexextendstream2", //name STPatternExExtendStream2Spec, //specification STPatternExExtendStream2VM, //value mapping Operator::SimpleSelect, //trivial selection function STPatternExtendTM //type mapping ); /* \subsection{Auxiliary temporal reasoning functions} */ /* ~STVector::Vector2PARelations~\\ The Vector2PARelations function converts the IA relation represented in the vector into a set of PA relations among the end points of the two intervals. The function returns false if the conversion is not possible (i.e., the IA relation does not belong to the continuous point algebra. That is, it cannot be represented as point relations unless the != relation is used). The output PA relations are reported in the rels argument. It has 10 places for the relations aA ab aB ba bA bB Ab AB Ba BA Aa Bb in order. Each array elem has the value 0 (relation not specified), or 1-7 (<, =, >, <=, >=, !=, ?). As indicated above, if an elem in rels has the value 6 (!=), the function yields false. */ bool STVector::Vector2PARelations(int rels[12]) { bool debugme= false; enum relIndex{ aA=0, ab=1, aB=2, ba=3, bA=4, bB=5, Ab=6, AB=7, Ba=8, BA=9, Aa=10, Bb=11}; /* defined in TemporalReasoner.h enum PARelation{ lss=0, leq=1, grt=2, geq=3, eql=4, neq=5, uni=6, inc=7, unknown=8}; */ PARelation orTable[][9]= {{lss,leq,neq,uni,leq,neq,uni,inc,lss}, {leq,leq,uni,uni,leq,uni,uni,inc,leq}, {neq,uni,grt,geq,geq,neq,uni,inc,grt}, {uni,uni,geq,geq,geq,uni,uni,inc,geq}, {leq,leq,geq,geq,eql,uni,uni,inc,eql}, {neq,uni,neq,uni,uni,neq,uni,inc,neq}, {uni,uni,uni,uni,uni,uni,uni,inc,uni}, {inc,inc,inc,inc,inc,inc,inc,inc,inc}, {lss,leq,grt,geq,eql,neq,uni,inc,unknown} }; int simple=1; PARelation relsSimple[12], relsVector[12], relSimple, relVector, relNew; for(int i= 0; i<12; ++i) relsVector[i]= unknown; for(int i=0; i<26; i++) { if(v & simple) { if(! Simple2PARelations(simple, (int*)relsSimple)) return false; for(int i= 0; i<12; ++i) { relSimple= relsSimple[i]; relVector= relsVector[i]; relNew= orTable[relSimple][relVector]; relsVector[i]= relNew; } } simple*=2; } for(int i= 0; i<12; ++i) { if(relsVector[i]== neq) return false; rels[i]= relsVector[i]; if(debugme) cerr<Clear(); Instant tMIN(instanttype), tMAX(instanttype); tMIN.ToMinimum(); tMAX.ToMaximum(); unsigned int SASize= SA.size(); if(SASize == 0) { Interval I(tMIN, tMAX, false, false); consistentPeriods->Add(I); return; } vector > sa(count); vector PARels; vector PAVarIndexes(0), lowerBoundIndexes(0), upperBoundIndexes(0); vector lowerBounds(0), upperBounds(0); DateTime epsilon(0,1010, durationtype); int curPAVarIndex, IAVar; Instant lowerBound, upperBound; Interval bounds(tMIN, tMAX, false, false); Range unionp(0); for(vector::iterator it= assignedVars.begin(); it!=assignedVars.end(); ++it) { IAVar= *it; if(IAVar == varIndex) continue; PAVarIndexes.push_back(IAVar * 2); PAVarIndexes.push_back((IAVar * 2) + 1 ); } int varStartIndex= varIndex*2, varEndIndex= (varIndex*2) +1; PARels= paReasoner->GetRelations(varStartIndex); for(unsigned int j= 0; jGetRelations(varEndIndex); for(unsigned int j= 0; j I(tMIN, tMAX, false, false); consistentPeriods->Add(I); return; } for(unsigned int i=0; i upperBound) bounds.end.CopyFrom(&upperBound); } } //expand the bounds with epslon if(!bounds.start.IsMinimum()) bounds.start-= epsilon; if(!bounds.end.IsMaximum()) bounds.end+= epsilon; //union the bounds with the consistentPeriods if(bounds.IsValid()) { consistentPeriods->Union(bounds , unionp); consistentPeriods->CopyFrom(&unionp); } } } /* ~CSP::Solve~\\ The second variant of the CSP::Solve function. This variant performs temporal reasoning to compute the supported assignments efficiently. */ bool CSP::Solve(Periods* periodsArg, PointAlgebraReasoner* paReasoner) { bool debugme=false; int varIndex; Word Value; vector > domain(0); int loopCnt=0; string counterPrefix= "CSP::SolveTR::Iteration"; Counter::getRef("TemporalReasoningOn", false)= 1; if(debugme) cerr<<"TR Iterations "; while( (varIndex= PickVariable()) != -1) { ++loopCnt; if(debugme) cerr<Print(cerr); for(int i= 0; iGetNoComponents(); ++i) { Interval intr; periodsArg->Get(i, intr); cerr<Request(Agenda[varIndex], Value); UsedAgendaVars[varIndex]= true; if(debugme && 0) ((MBool*)Value.addr)->Print(cerr); MBool2Vec((MBool*)Value.addr, domain); if(debugme && 0) { for(unsigned int i=0; i