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

4512 lines
130 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
[1] Source File of the 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 <limits>
#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<Instant>& p1, Interval<Instant>& 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<Instant>& p1, Interval<Instant>& p2,
int simple)
{
Instant a=p1.start, A=p1.end, b=p2.start, B=p2.end;
switch(simple)
{
case aabb:
return(a<A && a<b && a<B && A<b && A<B && b<B);
break;
case bbaa:
return(b<B && b<a && b<A && B<a && B<A && a<A);
break;
case aa_bb:
return(a<A && a<b && a<B && A==b && A<B && b<B);
break;
case bb_aa:
return(b<B && b<a && b<A && B==a && B<A && a<A);
break;
case abab:
return(a<b && a<A && a<B && b<A && b<B && A<B);
break;
case baba:
return(b<a && b<B && b<A && A<b && a<A && B<A);
break;
case baab:
return(b<a && b<A && b<B && a<A && a<B && A<B);
break;
case abba:
return(a<b && a<B && a<A && b<B && b<A && B<A);
break;
case a_bab:
return(a==b && a<A && a<B && b<A && b<B && A<B);
break;
case a_bba:
return(a==b && a<B && a<A && b<B && b<A && B<A);
break;
case baa_b:
return(b<a && b<A && b<B && a<A && a<B && A==B);
break;
case aba_b:
return(a<b && a<A && a<B && b<A && b<B && A==B);
break;
case a_ba_b:
return(a==b && a<A && a<B && b<A && b<B && A==B);
break;
case a_abb:
return(a==A && a<b && a<B && A<b && A<B && b<B);
break;
case a_a_bb:
return(a==A && a==b && a<B && A==b && A<B && b<B);
break;
case ba_ab:
return(b<a && b<A && b<B && a==A && a<B && A<B);
break;
case bb_a_a:
return(b<B && b<a && b<A && B==a && B==A && a==A);
break;
case bba_a:
return(b<B && b<a && b<A && B<a && B<A && a==A);
break;
case b_baa:
return(b==B && b<a && b<A && B<a && B<A && a<A);
break;
case b_b_aa:
return(b==B && b==a && b<A && B==a && B<A && a<A);
break;
case ab_ba:
return(a<b && a<B && a<A && b==B && b<A && B<A);
break;
case aa_b_b:
return(a<A && a<b && a<B && A==b && A==B && b==B);
break;
case aab_b:
return(a<A && a<b && a<B && A<b && A<B && b==B);
break;
case a_ab_b:
return(a==A && a<b && a<B && A<b && A<B && b==B);
break;
case a_a_b_b:
return(a==A && a==b && a==B && A==b && A==B && b==B);
break;
case b_ba_a:
return(b==B && b<a && b<A && B<a && B<A && a==A);
break;
default:
assert(0); //invalid simple relationships
}
return false;
}
/*
~STVector::Clear~\\
Clears all entries in an ~stvector~ instnace.
*/
void STVector::Clear()
{
this->count= 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<STVector*>( 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<STVector*>( 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<STVector*>( 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<STVector*>( w.addr );
w.addr = 0;
}
Word STVector::Clone( const ListExpr typeInfo, const Word& w )
{
STVector* vec = static_cast<STVector*>( 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<Instant>& in,
Interval<CcReal>& 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<instant> into an interval<real>. 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<Instant>& in,
Interval<CcReal>& 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<CcReal>& in,
Interval<Instant>& 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<Interval<Instant> >& vec)
{
UBool unit(0);
vec.clear();
if(!mb->IsDefined() || mb->IsEmpty() || !mb->IsValid()) return 0;
for(int i=0; i<mb->GetNoComponents(); 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<Interval<Instant> > 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<<loopCnt<<", ";
Counter::getRef(counterPrefix + int2Str(loopCnt), true)++;
qp->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<Interval<Instant> >& domain )
{
vector<Interval<Instant> > sa(count);
if(SA.size() == 0)
{
for(int i=0; i<count; i++)
sa[i].CopyFrom(nullInterval);
for(unsigned int i=0; i<domain.size(); i++)
{
sa[index]= domain[i];
SA.push_back(sa);
}
return 0;
}
unsigned int SASize= SA.size();
for(unsigned int i=0; i<SASize; i++)
{
sa= SA[0];
for(unsigned int j=0; j< domain.size(); j++)
{
sa[index]= domain[j];
if(IsSupported(sa,index))
SA.push_back(sa);
}
SA.erase(SA.begin());
}
return 0;
}
/*
~CSP::IsSupported~\\
This function searches the ConstraintGraph for the constraints that
involve the given variable and check their fulfillment. It is modified to check
only the constraints related to the newly evaluated variable instead of
re-checking all the constraints.
*/
bool CSP::IsSupported(vector<Interval<Instant> > sa, int index)
{
bool debugme= false;
bool supported=false;
if(debugme)
{
cerr<<endl<<assignedVars.size()<<endl;
for(unsigned int u=0; u<assignedVars.size(); u++)
cerr<< assignedVars[u];
}
for(unsigned int i=0; i<assignedVars.size()-1; i++)
{
for(unsigned int j=i; j<assignedVars.size(); j++)
{
if(debugme)
cerr<<endl<<"Checking constraints ("<<assignedVars[i] <<
", "<< assignedVars[j] <<") and ("<< assignedVars[j] <<
", "<< assignedVars[i] << ")";
if(assignedVars[i]== index || assignedVars[j] == index )
{
if(ConstraintGraph[assignedVars[i]][assignedVars[j]].size() != 0)
{
supported= CheckConstraint(sa[assignedVars[i]],
sa[assignedVars[j]],
ConstraintGraph[assignedVars[i]][assignedVars[j]]);
if(!supported) return false;
}
if(ConstraintGraph[assignedVars[j]][assignedVars[i]].size() != 0)
{
supported= CheckConstraint(sa[assignedVars[j]],
sa[assignedVars[i]],
ConstraintGraph[assignedVars[j]][assignedVars[i]]);
if(!supported) return false;
}
}
}
}
return supported;
}
/*
~CSP::CheckConstraint~\\
A predicate that checks a temporal constraint, represented as an ~stvector~
instance, on two time intervals.
*/
bool CSP::CheckConstraint(Interval<Instant>& p1, Interval<Instant>& p2,
vector<Supplier> 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])<<endl;
cout.flush();
}
qp->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<int> vars(0);
vector<double> numconstraints(0);
double cnt=0;
int index=-1;
for(unsigned int i=0;i<Agenda.size();i++)
{
if(!UsedAgendaVars[i])
{
vars.push_back(i);
cnt=0;
for(unsigned int r=0; r< ConstraintGraph.size(); r++)
{
for(unsigned int c=0; c< ConstraintGraph[r].size(); c++)
{
if( r == i && ConstraintGraph[r][c].size() != 0)
{
cnt+= ConstraintGraph[r][c].size() * 0.5;
for(unsigned int v=0; v< assignedVars.size(); v++)
{
if(c == (unsigned int)assignedVars[v])
cnt+=0.5 * ConstraintGraph[r][c].size();
}
}
if( c == i && ConstraintGraph[r][c].size() != 0)
{
cnt+=0.5 * ConstraintGraph[r][c].size();
for(unsigned int v=0; v< assignedVars.size(); v++)
{
if(r == (unsigned int)assignedVars[v])
cnt+=0.5 * ConstraintGraph[r][c].size();
}
}
}
}
numconstraints.push_back(cnt);
}
}
double max=-1;
for(unsigned int i=0; i<numconstraints.size(); i++)
{
if(numconstraints[i]>max){ max=numconstraints[i]; index=vars[i];}
}
if(debugme)
{
for(unsigned int i=0; i<numconstraints.size(); i++)
cout<< "\nConnectivity of variable " <<vars[i] <<" = "
<< numconstraints[i];
cout<<endl<< "Picking variable "<< index<<endl;
cout.flush();
}
if(index== -1) return -1;
assignedVars.push_back(index);
return index;
}
/*
~CSP::AddVariable~\\
Inserts one variable into the CSP, and reserves place for it in the
ConstraintGraph.
*/
int CSP::AddVariable(string alias, Supplier handle)
{
Agenda.push_back(handle);
UsedAgendaVars.push_back(false);
VarAliasMap[alias]=count;
count++;
ConstraintGraph.resize(count);
for(int i=0; i<count; i++)
ConstraintGraph[i].resize(count);
return 0;
}
/*
~CSP::AddConstraint~\\
Inserts one binary constraint into the CSP.
*/
int CSP::AddConstraint(string alias1, string alias2, Supplier handle)
{
int index1=-1, index2=-1;
try{
index1= VarAliasMap[alias1];
index2= VarAliasMap[alias2];
if(index1==index2)
throw;
}
catch(...)
{
return -1;
}
ConstraintGraph[index1][index2].push_back(handle);
return 0;
}
/*
~CSP::MoveNext~\\
Iterates over the supported assignments. This function is used, for example, in
the ~stpatternex~ operator in order to iterate over the SA, and find solutions
to the second part of the predicate.
*/
bool CSP::MoveNext()
{
if(iterator < (signed int)SA.size()-1)
iterator++;
else
return false;
return true;
}
/*
~CSP::GetSA~\\
Yields an SA entry.
*/
bool CSP::GetSA(unsigned int saIndex, unsigned int varIndex, Periods& res)
{
res.Clear();
if(saIndex >= 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<string, int>::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<string, int>::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; j<SA[i].size(); j++)
{
cout<<SA[i][j].start.millisecondsToNull()<< "\t "<<
SA[i][j].end.millisecondsToNull()<<" | ";
}
cout<<endl;
}
cout.flush();
}
/*
~CSP::Clear~\\
Clears this CSP instance, and prepare it for the next operator call.
*/
int CSP::Clear()
{
closureRes= notPA;
SA.clear();
Agenda.clear();
UsedAgendaVars.clear();
ConstraintGraph.clear();
VarAliasMap.clear();
assignedVars.clear();
count=0;
iterator=-1;
return 0;
}
/*
~CSP::ResetTuple~\\
Partially clears this CSP instance, and prepare it for matching a new tuple
against the pattern. The Agenda, and the ConstraintGraph are kept. Other members
related to the evaluation are reset.
*/
int CSP::ResetTuple()
{
SA.clear();
UsedAgendaVars.assign(Agenda.size(), false);
assignedVars.clear();
iterator=-1;
return 0;
}
/*
\section{Auxiliary functions}
This section defines some helper functions that are used within operators or
other class members.
~RandomDelay~\\
Apply different random delays to the units of the given mpoint. The resulting
mpoint will have the same trajectory but different unit speeds form the input
mpoint.
*/
void RandomDelay(const MPoint* actual, const Instant* threshold, MPoint& res)
{
bool debugme= false;
MPoint delayed(actual->GetNoComponents());
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<Tuple>::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<string>& aliases)
{
for(set<string>::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<string>& aliases)
{
ListExpr typeList;
for(set<string>::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<string>& 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<string>& 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<string>& 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<string> IntervalVars)
{
bool debugme= false;
if(debugme)
{
string cList= nl->ToString(ConstraintList);
cerr<<endl<<cList<<endl;
for(vector<string>::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<string, int> alias2IAIndex;
ListExpr ConstraintListRest = nl->Second(ConstraintList);
ListExpr STConstraint;
ListExpr IARelListRest;
STVector IAVector(0);
string alias, IARel;
set<pair<int, int> > relatedPairs;
int i=-1, j;
for(vector<string>::iterator
it=IntervalVars.begin(); it< IntervalVars.end(); ++it)
assert(alias2IAIndex.insert(pair<string, int>(*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<CcInt*>(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<<endl;
raw= qp->GetSon(TRTable, i);
for(int j=0; j< PAReasonerN ; ++j)
{
son= qp->GetSon(raw, j);
qp->Request(son, value);
Table[tblIndex++]= static_cast<CcInt*>(value.addr)->GetIntval();
if(debugme)
cerr<<static_cast<CcInt*>(value.addr)->GetIntval()<<",";
}
}
paReasoner->ImportFromArray(Table);
delete[] Table;
}
else
{
son= qp->GetSon(TRTable, 1);
qp->Request(son, value);
res= static_cast<ClosureResult>(
static_cast<CcInt*>(value.addr)->GetIntval());
}
return res;
}
/*
~CreateMaximalPeriods~\\
*/
Periods* CreateMaximalPeriods()
{
Instant i1(instanttype); i1.ToMinimum();
Instant i2(instanttype); i2.ToMaximum();
Interval<Instant> 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;i<noconn; i++)
{
simple= ((CcString*)args[i].addr)->GetValue();
if(! res->Add(simple))
return 1;
}
return 0;
}
const string CreateSTVectorSpec =
"( ( "
" \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( "
" <text>(list of string) -> stvector</text--->"
" <text>vec( _ )</text--->"
" <text>Creates a vector temporal relations, to be used within the "
" spatiotemporal pattern query operators (e.g., stpattern, reportpattern)."
" </text--->"
" <text>let meanwhile = vec(\"abab\",\"abba\",\"aba.b\");</text--->"
") )";
Operator createstvector (
"vec", //name
CreateSTVectorSpec, //specification
CreateSTVectorVM, //value mapping
Operator::SimpleSelect, //trivial selection function
CreateSTVectorTM //type mapping
);
/*
\subsection{The stpattern and stpatternex Operators}
*/
template<bool extended>
ListExpr STPatternTM(ListExpr args)
{
bool debugme= false;
string opName= extended? "stpatternex": "stpattern";
string argstr;
if(debugme)
{
cout<<endl<< nl->ToString(args)<<endl;
cout.flush();
}
nl->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<string> predAliases1, predAliases2;
ExtractPredAliasesFromPredList(NamedPredList, predAliases1);
ExtractPredAliasesFromConstraintList(ConstraintList, predAliases2);
if(debugme)
{
set<string>::iterator it1= predAliases1.begin(), it2= predAliases2.begin();
cerr<<endl;
while(it1 != predAliases1.end())
cerr<<*it1++<< '\t';
cerr<<endl;
while(it2 != predAliases2.end())
cerr<<*it2++<< '\t';
}
if((predAliases1.size() != predAliases2.size()) ||
!std::equal(predAliases1.begin(), predAliases1.end(), predAliases2.begin()))
{
ErrorReporter::ReportError("Operator "+ opName +": unknown alises 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 result = nl->SymbolAtom(CcBool::BasicType());
if(debugme)
{
cout<<endl<<endl<<"Operator "+ opName +" accepted the input";
cout.flush();
}
return result;
}
template<bool extended>
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<Tuple*>(w.addr);
cerr<<endl<<"Id: "<<
static_cast<CcInt*>(tuple->GetAttribute(0))->GetValue();
cerr<<", Line: "<<
static_cast<CcInt*>(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\" ) "
"( "
" <text>tuple(x) X namedFunlist X constraintList -> bool</text--->"
" <text>_ stpattern[ namedFunlist; constraintList ]</text--->"
" <text>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."
" </text--->"
" <text> "
" 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;"
"</text--->"
") )";
const string STPatternExSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
" <text>tuple(x) X namedFunlist X constraintList X bool -> bool</text--->"
" <text>_ stpatternex[ namedFunlist; constraintList; bool ]</text--->"
" <text>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.</text--->"
" <text>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</text--->"
") )";
Operator stpattern (
"stpattern", //name
STPatternSpec, //specification
STPatternVM<false>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternTM<false> //type mapping
);
Operator stpatternex (
"stpatternex", //name
STPatternExSpec, //specification
STPatternVM<true>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternTM<true> //type mapping
);
/*
\subsection{The stpatternextend and stpatternexextend Operators}
*/
template<bool extended, bool enableTemporalReasoner, bool extendstream>
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<<endl<< nl->ToString(args)<<endl;
cout.flush();
}
nl->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<string> 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<string> 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<string>::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<Tuple>::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<<endl<<endl<<"Operator "+ opName + " accepted the input";
cout<<endl<< nl->ToString(result);
cout.flush();
//return nl->SymbolAtom(Symbols::TYPEERROR());
}
return result;
}
template<bool extended>
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\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList -> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternextend[ namedFunlist; constraintList ]</text--->"
"<text>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.</text--->"
"<text>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 "
"</text--->"
") )";
const string STPatternExExtendSpec =
"( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList X bool-> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))</text--->"
"<text>_ stpatternexextend[ namedFunlist; constraintList; bool]</text--->"
"<text>The operator extends the input stream with the first supported "
" assignment. Tuples that doesn't fulfill "
" the pattern are extended with undef values.</text--->"
"<text>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"
"</text--->"
") )";
Operator stpatternextend (
"stpatternextend", //name
STPatternExtendSpec, //specification
STPatternExtendVM<false>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<false, false, false> //type mapping
);
Operator stpatternexextend (
"stpatternexextend", //name
STPatternExExtendSpec, //specification
STPatternExtendVM<true>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<true, false, false> //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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
Tuple *newTuple = new Tuple( localInfo->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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
bool Part2=false;
ArgVectorPointer funargs= qp->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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
Tuple *newTuple = new Tuple( localInfo->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\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList -> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternextendstream[ namedFunlist; constraintList ]</text--->"
"<text>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."
"</text--->"
"<text>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 "
"</text--->"
") )";
const string STPatternExExtendStreamSpec =
"( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList X bool-> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternexextendstream[ namedFunlist; constraintList; bool]"
"</text--->"
"<text>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."
"</text--->"
"<text>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 "
"</text--->"
") )";
Operator stpatternextendstream (
"stpatternextendstream", //name
STPatternExtendStreamSpec, //specification
STPatternExtendStreamVM, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<false, false, true> //type mapping
);
Operator stpatternexextendstream (
"stpatternexextendstream", //name
STPatternExExtendStreamSpec, //specification
STPatternExExtendStreamVM, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<true, false, true> //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<<endl<< nl->ToString(args)<<endl;
cout.flush();
}
if(!nl->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<<endl<<endl<<"Operator stconstraint accepted the input";
cout.flush();
}
return result;
}
int STConstraintVM
(Word* args, Word& result, int message, Word& local, Supplier s)
{
assert(0); //this function should never be invoked.
return 0;
}
const string STConstraintSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>string X string X stvector -> bool</text--->"
"<text>_ stconstraint( string, string, vec(_))</text--->"
"<text>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."
"</text--->"
" <text> "
" 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;"
"</text--->"
") )";
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<<endl<< nl->ToString(args) <<endl;
cout<< nl->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 <bool leftbound> int StartEndVM
(Word* args, Word& result, int message, Word& local, Supplier s)
{
bool debugme= false;
Interval<Instant> interval;
Word input;
string lbl;
//qp->Request(args[0].addr, input);
lbl= ((CcString*)args[0].addr)->GetValue();
if(debugme)
{
cout<<endl<<"Executing ";
if(leftbound) cout<<"start("; else cout<<"end("; cout<< lbl<<")";
cout.flush();
}
Instant res(0,0,instanttype);
bool found=false;
if(leftbound)
found=csp.GetStart(lbl, res);
else
found=csp.GetEnd(lbl, res);
if(debugme)
{
cout<<endl<<"Value is "; if(!found) cout<<"Not found";
res.Print(cout);
cout.flush();
}
result = qp->ResultStorage( s );
((Instant*)result.addr)->CopyFrom(&res);
return 0;
}
const string StartEndSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>string -> instant</text--->"
"<text>start( _ )/ end(_)</text--->"
"<text>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.</text--->"
" <text>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</text--->"
") )";
Operator start (
"start", //name
StartEndSpec, //specification
StartEndVM<true>, //value mapping
Operator::SimpleSelect, //trivial selection function
StartEndTM //type mapping
);
Operator end (
"end", //name
StartEndSpec, //specification
StartEndVM<false>, //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<<nl->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<<nl->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<Instant> 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++<n)
{
rnd=rand()%50000; //deciding the duration of a unit
while(rnd<2)
rnd=rand()%50000;
intr.end.Set(intr.start.GetYear(), intr.start.GetMonth(),
intr.start.GetGregDay(), intr.start.GetHour(),intr.start.GetMinute(),
intr.start.GetSecond(),intr.start.GetMillisecond()+rnd);
unit.constValue.Set(true, bval);
unit.timeInterval= intr;
result.Add(unit);
intr.start= intr.end;
bval=!bval;
}
if(debugme)
result.Print(cout);
}
int
RandomMBoolVM(Word* args, Word& result, int message, Word& local, Supplier s)
{
result = qp->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<MPoint*>( args[0].addr );
Instant *threshold = static_cast<Instant*>(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\" ) "
"( <text> instant -> mbool</text--->"
"<text>randommbool( _ )</text--->"
"<text>Creates a random mbool value. The operator is used for testing"
"purposes.</text--->"
"<text>let mb1 = randommbool(now())</text--->"
") )";
const string PassMBoolSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" ) "
"( <text>mbool -> mbool</text--->"
"<text>passmbool( _ )</text--->"
"<text>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.</text--->"
"<text>let mb2= passmbool(mb1)</text--->"
") )";
const string RandomDelaySpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" ) "
"( <text>mpoint x duration -> mpoint</text--->"
"<text>randomdelay(schedule, delay_threshold)</text--->"
"<text>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.</text--->"
"<text>query randomdelay(train7)</text--->"
") )";
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<<endl<< nl->ToString(args)<<endl;
cout.flush();
}
nl->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<string> predAliases1Unsorted;
set<string> 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<<endl<<endl<<"Operator "+ opName +" accepted the input";
nl->WriteToString(argstr, result);
cout<<endl<<"Output is:"<<argstr;
cout.flush();
}
return result;
}
int ComputeClosureVM(
Word* args, Word& result, int message, Word& local, Supplier s)
{
Supplier TRTable= args[3].addr;
Word value;
PointAlgebraReasoner* paReasoner= 0;
ClosureResult closureRes= ImportPAReasonerFromArgs(TRTable, paReasoner);
result = qp->ResultStorage( s );
((CcInt*)result.addr)->Set(true, closureRes);
return 0;
}
const string ComputeClosureSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" ) ( <text>tuple(x) X periods X namedFunlist X "
"constraintList -> int</text--->"
"<text>_ computeclosure[ namedFunlist; constraintList ]</text--->"
"<text>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)."
"</text--->"
"<text>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"
"</text--->) )";
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<MBool*>( args[0].addr );
CcBool *ndefval = static_cast<CcBool*>( 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<MPoint*>( args[0].addr );
Instant *threshold = static_cast<Instant*>(args[1].addr );
double dx = static_cast<CcReal*>(args[2].addr )->GetRealval();
double dy = static_cast<CcReal*>(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\" ) "
"( <text>mpoint x duration x real x real-> mpoint</text--->"
"<text>randomdelay(schedule, delay_threshold, dx, dy)</text--->"
"<text>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."
"</text---> <text>query randomdelay(train7)</text--->"
") )";
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<bool extended>
ListExpr STPattern2TM(ListExpr args)
{
bool debugme= false;
string opName= (extended)? "stpatternex2": "stpattern2";
string argstr;
if(debugme)
{
cout<<endl<< nl->ToString(args)<<endl;
cout.flush();
}
nl->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<string> predAliases1Unsorted;
set<string> 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<<endl<<endl<<"Operator "+ opName +" accepted the input";
nl->WriteToString(argstr, result);
cout<<endl<<"Output is:"<<argstr;
cout.flush();
}
return result;
}
template<bool extended>
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<Tuple*>(w.addr);
cerr<<endl<<"Id: "<<
static_cast<CcInt*>(tuple->GetAttribute(0))->GetValue();
cerr<<", Line: "<<
static_cast<CcInt*>(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<Tuple*>(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\" ) ( <text>tuple(x) X namedFunlist X "
"constraintList -> bool</text--->"
"<text>_ stpattern2[ namedFunlist; constraintList ]</text--->"
"<text>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'."
"</text--->"
"<text>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 </text--->"
") )";
const string STPatternEx2Spec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>tuple(x) X namedFunlist X constraintList X bool -> bool</text--->"
"<text>_ stpatternex2[ namedFunlist; constraintList; bool ]</text--->"
"<text>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'. "
"</text--->"
"<text>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 </text--->"
") )";
Operator stpattern2 (
"stpattern2", //name
STPattern2Spec, //specification
STPattern2VM<false>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPattern2TM<false> //type mapping
);
Operator stpatternex2 (
"stpatternex2", //name
STPatternEx2Spec, //specification
STPattern2VM<true>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPattern2TM<true> //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<bool extended>
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<STPatternExtendLocalInfo*>(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<STPatternExtendLocalInfo*>(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\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList -> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternextend2[ namedFunlist; constraintList ]</text--->"
"<text>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.</text--->"
"<text>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"
"</text--->"
") )";
const string STPatternExExtend2Spec =
"( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList X bool-> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternexextend2[ namedFunlist; constraintList; bool]</text--->"
"<text>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."
"</text--->"
"<text>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 "
" </text--->"
") )";
Operator stpatternextend2 (
"stpatternextend2", //name
STPatternExtend2Spec, //specification
STPatternExtend2VM<false>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<false, true, false> //type mapping
);
Operator stpatternexextend2 (
"stpatternexextend2", //name
STPatternExExtend2Spec, //specification
STPatternExtend2VM<true>, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<true, true, false> //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<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
{
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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
Tuple *newTuple = new Tuple( localInfo->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<STPExtendStreamInfo*>(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<STPExtendStreamInfo*>(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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
bool Part2=false;
ArgVectorPointer funargs= qp->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 "<<csp.iterator + 1 << "/"<<csp.SA.size();
Tuple *newTuple = new Tuple( localInfo->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<STPExtendStreamInfo*>(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\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList ->"
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternextendstream2[ namedFunlist; constraintList ]</text--->"
"<text>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.</text--->"
"<text>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 "
"</text--->"
") )";
const string STPatternExExtendStream2Spec =
"( (\"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( "
"<text>stream(tuple(x)) X namedFunlist X constraintList X bool-> "
" stream(tuple(x,alias1:Periods,...,alias1:Periods))"
"</text--->"
"<text>_ stpatternexextendstream2[ namedFunlist; constraintList; bool]"
"</text--->"
"<text>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.</text--->"
"<text>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 "
"</text--->"
") )";
Operator stpatternextendstream2 (
"stpatternextendstream2", //name
STPatternExtendStream2Spec, //specification
STPatternExtendStream2VM, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<false, true, true> //type mapping
);
Operator stpatternexextendstream2 (
"stpatternexextendstream2", //name
STPatternExExtendStream2Spec, //specification
STPatternExExtendStream2VM, //value mapping
Operator::SimpleSelect, //trivial selection function
STPatternExtendTM<true, true, true> //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<<endl<<i<< ": "<< relsVector[i];
}
return true;
}
/*
~STVector::Simple2PARelations~\\
The Simple2PARelations function converts an IA simple relation (i.e., one term)
into a set of PA relations. It works similar to Vectore2PARelations, yet it is
able to convert one term only.
*/
bool STVector::Simple2PARelations(int simple, int rels[12])
{
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};
for(int i= 0; i<12; ++i)
rels[i]= unknown;
switch(simple)
{
case aabb:
{
rels[aA]= lss; rels[ab]= lss; rels[aB]= lss;
rels[ba]= grt; rels[bA]= grt; rels[bB]= lss;
rels[Ab]= lss; rels[AB]= lss; rels[Ba]= grt;
rels[BA]= grt; rels[Bb]= grt; rels[Aa]= grt;
}break;
case bbaa:
{
rels[aA]= lss; rels[ab]= grt; rels[aB]= grt;
rels[ba]= lss; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= grt; rels[Ba]= lss;
rels[BA]= lss; rels[Bb]= grt; rels[Aa]= grt;
}break;
case aa_bb:
{
rels[aA]= lss; rels[ab]= lss; rels[aB]= lss;
rels[ba]= grt; rels[bA]= eql; rels[bB]= lss;
rels[Ab]= eql; rels[AB]= lss; rels[Ba]= grt;
rels[BA]= grt; rels[Bb]= grt; rels[Aa]= grt;
}break;
case bb_aa:
{
rels[aA]= lss; rels[ab]= grt; rels[aB]= eql;
rels[ba]= lss; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= grt; rels[Ba]= eql;
rels[BA]= lss; rels[Bb]= grt; rels[Aa]= grt;
}break;
case abab:
{
rels[aA]= lss; rels[ab]= lss; rels[aB]= lss;
rels[ba]= grt; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= lss; rels[Ba]= grt;
rels[BA]= grt; rels[Bb]= grt; rels[Aa]= grt;
}break;
case baba:
{
rels[aA]= lss; rels[ab]= grt; rels[aB]= lss;
rels[ba]= lss; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= grt; rels[Ba]= grt;
rels[BA]= lss; rels[Bb]= grt; rels[Aa]= grt;
}break;
case baab:
{
rels[aA]= lss; rels[ab]= grt; rels[aB]= lss;
rels[ba]= lss; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= lss; rels[Ba]= grt;
rels[BA]= grt; rels[Bb]= grt; rels[Aa]= grt;
}break;
case abba:
{
rels[aA]= lss; rels[ab]= lss; rels[aB]= lss;
rels[ba]= grt; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= grt; rels[Ba]= grt;
rels[BA]= lss; rels[Bb]= grt; rels[Aa]= grt;
}break;
case a_bab:
{
rels[aA]= lss; rels[ab]= eql; rels[aB]= lss;
rels[ba]= eql; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= lss; rels[Ba]= grt;
rels[BA]= grt; rels[Bb]= grt; rels[Aa]= grt;
}break;
case a_bba:
{
rels[aA]= lss; rels[ab]= eql; rels[aB]= lss;
rels[ba]= eql; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= grt; rels[Ba]= grt;
rels[BA]= lss; rels[Bb]= grt; rels[Aa]= grt;
}break;
case baa_b:
{
rels[aA]= lss; rels[ab]= grt; rels[aB]= lss;
rels[ba]= lss; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= eql; rels[Ba]= grt;
rels[BA]= eql; rels[Bb]= grt; rels[Aa]= grt;
}break;
case aba_b:
{
rels[aA]= lss; rels[ab]= lss; rels[aB]= lss;
rels[ba]= grt; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= eql; rels[Ba]= grt;
rels[BA]= eql; rels[Bb]= grt; rels[Aa]= grt;
}break;
case a_ba_b:
{
rels[aA]= lss; rels[ab]= eql; rels[aB]= lss;
rels[ba]= eql; rels[bA]= lss; rels[bB]= lss;
rels[Ab]= grt; rels[AB]= eql; rels[Ba]= grt;
rels[BA]= eql; rels[Bb]= grt; rels[Aa]= grt;
}break;
case a_abb:
case a_a_bb:
case ba_ab:
case bb_a_a:
case bba_a:
case b_baa:
case b_b_aa:
case ab_ba:
case aa_b_b:
case aab_b:
case a_ab_b:
case a_a_b_b:
case b_ba_a:
return false;
break;
default:
assert(0); //illegal simple temporal connector
}
return true;
}
/*
~CSP::SetConsistentPeriods~\\
The SetConsistentPeriods is a helper function, used by the CSP::Solve as a part
of the temporal reasoning.
*/
void CSP::SetConsistentPeriods(
int varIndex, Periods* periodsArg, PointAlgebraReasoner* paReasoner)
{
Periods* consistentPeriods= periodsArg;
consistentPeriods->Clear();
Instant tMIN(instanttype), tMAX(instanttype);
tMIN.ToMinimum(); tMAX.ToMaximum();
unsigned int SASize= SA.size();
if(SASize == 0)
{
Interval<Instant> I(tMIN, tMAX, false, false);
consistentPeriods->Add(I);
return;
}
vector<Interval<Instant> > sa(count);
vector<PARelation> PARels;
vector<int> PAVarIndexes(0), lowerBoundIndexes(0), upperBoundIndexes(0);
vector<Instant> lowerBounds(0), upperBounds(0);
DateTime epsilon(0,1010, durationtype);
int curPAVarIndex, IAVar;
Instant lowerBound, upperBound;
Interval<Instant> bounds(tMIN, tMAX, false, false);
Range<Instant> unionp(0);
for(vector<int>::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; j<PAVarIndexes.size(); ++j)
{
if(PARels[PAVarIndexes[j]] == grt || PARels[PAVarIndexes[j]] == geq ||
PARels[PAVarIndexes[j]] == eql )
lowerBoundIndexes.push_back(PAVarIndexes[j]);
}
PARels= paReasoner->GetRelations(varEndIndex);
for(unsigned int j= 0; j<PAVarIndexes.size(); ++j)
{
if(PARels[PAVarIndexes[j]] == lss || PARels[PAVarIndexes[j]] == leq ||
PARels[PAVarIndexes[j]] == eql )
upperBoundIndexes.push_back(PAVarIndexes[j]);
}
if(lowerBoundIndexes.empty() && upperBoundIndexes.empty())
{
Interval<Instant> I(tMIN, tMAX, false, false);
consistentPeriods->Add(I);
return;
}
for(unsigned int i=0; i<SASize; i++)
{
sa= SA[i];
bounds.start.ToMinimum(); bounds.end.ToMaximum();
if(!lowerBoundIndexes.empty())
{
//find the maximum lower bound
for(unsigned int j=0; j<lowerBoundIndexes.size(); ++j)
{
curPAVarIndex = lowerBoundIndexes[j];
lowerBound= (curPAVarIndex % 2)?
sa[(curPAVarIndex / 2)].end:
sa[(curPAVarIndex / 2)].start;
if(bounds.start < lowerBound) bounds.start.CopyFrom(&lowerBound);
}
}
if(!upperBoundIndexes.empty())
{
//find the minimum upper bound
for(unsigned int j=0; j<upperBoundIndexes.size(); ++j)
{
curPAVarIndex = upperBoundIndexes[j];
upperBound= (curPAVarIndex % 2)?
sa[(curPAVarIndex / 2)].end:
sa[(curPAVarIndex / 2)].start;
if(bounds.end > 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<Interval<Instant> > 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<<loopCnt<<", ";
Counter::getRef(counterPrefix + int2Str(loopCnt), true)++;
if(GetClosureResult() == consistent )
SetConsistentPeriods(varIndex, periodsArg, paReasoner);
if(debugme && 0)
{
if(!IsMaximumPeriods(*periodsArg))
{
periodsArg->Print(cerr);
for(int i= 0; i<periodsArg->GetNoComponents(); ++i)
{
Interval<Instant> intr;
periodsArg->Get(i, intr);
cerr<<endl<<intr.start.millisecondsToNull()<< "\t"<<
intr.end.millisecondsToNull();
}
}
}
qp->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<domain.size(); ++i)
{
cerr<<endl;
domain[i].Print(cerr);
}
}
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::SetClosureResult~\\
*/
void CSP::SetClosureResult(ClosureResult _res)
{
closureRes= _res;
}
/*
~SP::GetClosureResult~\\
*/
ClosureResult CSP::GetClosureResult()
{
return closureRes;
}
/*
\section{The Algebra Definition}
*/
class STPatternAlgebra : public Algebra
{
public:
STPatternAlgebra() : Algebra()
{
AddTypeConstructor( &stvectorTC );
/*
~SetRequestsArguments~ annotates the operator as being lazy, in the sense that
the query processor will not evaluate its arguments before calling it. The
operator is responsible in its value map to evaluate its arguments.
*/
stpattern.SetRequestsArguments();
stpattern2.SetRequestsArguments();
stpatternex.SetRequestsArguments();
stpatternex2.SetRequestsArguments();
stpatternextend.SetRequestsArguments();
stpatternextend2.SetRequestsArguments();
stpatternexextend.SetRequestsArguments();
stpatternexextend2.SetRequestsArguments();
stpatternextendstream.SetRequestsArguments();
stpatternextendstream2.SetRequestsArguments();
stpatternexextendstream.SetRequestsArguments();
stpatternexextendstream2.SetRequestsArguments();
/*
~SetUsesArgsInTypeMapping~ forces the query processor to pass the values of the
literal operator arguments to the typemap. That is, if one of the operator
arguments is a string literal, the typemap receives a list (string value).
*/
stpattern.SetUsesArgsInTypeMapping();
stpattern2.SetUsesArgsInTypeMapping();
stpatternex.SetUsesArgsInTypeMapping();
stpatternex2.SetUsesArgsInTypeMapping();
stpatternextend.SetUsesArgsInTypeMapping();
stpatternextend2.SetUsesArgsInTypeMapping();
stpatternexextend.SetUsesArgsInTypeMapping();
stpatternexextend2.SetUsesArgsInTypeMapping();
stpatternextendstream.SetUsesArgsInTypeMapping();
stpatternextendstream2.SetUsesArgsInTypeMapping();
stpatternexextendstream.SetUsesArgsInTypeMapping();
stpatternexextendstream2.SetUsesArgsInTypeMapping();
computeClosure.SetUsesArgsInTypeMapping();
AddOperator(&STP::createstvector);
AddOperator(&STP::stpattern);
AddOperator(&STP::stpattern2);
AddOperator(&STP::stconstraint);
AddOperator(&STP::stpatternex);
AddOperator(&STP::stpatternex2);
AddOperator(&STP::stpatternextend);
AddOperator(&STP::stpatternextend2);
AddOperator(&STP::stpatternexextend);
AddOperator(&STP::stpatternexextend2);
AddOperator(&STP::stpatternextendstream);
AddOperator(&STP::stpatternextendstream2);
AddOperator(&STP::stpatternexextendstream);
AddOperator(&STP::stpatternexextendstream2);
AddOperator(&STP::start);
AddOperator(&STP::end);
AddOperator(&randommbool);
AddOperator(&passmbool);
AddOperator(&randomdelay);
AddOperator(&computeClosure);
AddOperator(&randomshiftdelay);
}
~STPatternAlgebra() {};
};
};
/*
\section{Initialization}
*/
extern "C"
Algebra*
InitializeSTPatternAlgebra( NestedList* nlRef,
QueryProcessor* qpRef )
{
// The C++ scope-operator :: must be used to qualify the full name
return new STP::STPatternAlgebra;
}