/* 3.16 ~PMSimple~ */ #ifndef PMSIMPLE_H #define PMSIMPLE_H #include #include #include "NestedList.h" #include "PeriodicSupport.h" #include "PeriodicTypes.h" #include "StandardTypes.h" #include "DateTime.h" extern NestedList* nl; namespace periodic{ /* ~Constructor~ */ template PMSimple::PMSimple(){} template PMSimple::PMSimple(int dummy): Attribute(false), linearMoves(1), compositeMoves(1), compositeSubMoves(1), periodicMoves(1), canDelete(false), interval(1), startTime(datetime::instanttype){ __TRACE__ } template PMSimple::PMSimple(const PMSimple& source): Attribute(source.IsDefined()){ Equalize(&source); } /* ~Destructor~ */ template PMSimple::~PMSimple() { __TRACE__ if(canDelete){ linearMoves.Destroy(); compositeMoves.Destroy(); compositeSubMoves.Destroy(); periodicMoves.Destroy(); } } /* ~Assignment operator~ */ template PMSimple PMSimple::operator=(const PMSimple& source){ Equalize(&source); return *this; } /* ~Destroy~ If this function is called, the destructor can destroy the FLOB objects. [3] O(1) */ template void PMSimple::Destroy(){ __TRACE__ canDelete = true; } /* ~Equalize~ This function takes the value for this PMSimple from another instance __B__. [3] O(L), where L is the number of contained linear moves */ template void PMSimple::Equalize(const PMSimple* B2){ __TRACE__ linearMoves.copyFrom(B2->linearMoves); compositeMoves.copyFrom(B2->compositeMoves); compositeSubMoves.copyFrom(B2->compositeSubMoves); periodicMoves.copyFrom(B2->periodicMoves); SetDefined(B2->IsDefined()); interval.Equalize(&(B2->interval)); startTime.Equalize(&(B2->startTime)); submove.Equalize(&(B2->submove)); } /* ~NumOfFLOBs~ Returns four because four DbArrays are managed. [3] O(1) */ template int PMSimple::NumOfFLOBs() const{ __TRACE__ return 4; } /* ~GetFLOB~ This function returns the FLOB at the specified index. If the index is out of range, the system will going down. The flobs are: * 0: the units * 1: the composite moves * 2: the composite submoves * 3: the periodic moves [3] O(1) */ template Flob* PMSimple::GetFLOB(const int i){ __TRACE__ assert(i>=0 && i int PMSimple::Compare(const Attribute* arg) const{ __TRACE__ cout << "PMSImple::Compare not implemented yet " << std::endl; return -1; } /* ~Adjacent~ Returns false because it's not clear when two moving constants should be adjacent. [3] O(1) */ template bool PMSimple::Adjacent(const Attribute*)const{ __TRACE__ return false; } /* ~Clone~ This functions creates a new periodic moving constant with the same value like the calling instance and returns it. [3] O(L), where L is the number of contained linear moves */ template PMSimple* PMSimple::Clone() const{ __TRACE__ PMSimple* res = new PMSimple(1); res->Equalize(this); return res; } /* ~SizeOf~ Returns the size of the class PMSimple. [3] O(1) */ template size_t PMSimple::Sizeof()const{ __TRACE__ return sizeof(PMSimple); } /* ~HashValue~ This functions computes a HashValue for this PMSimple from the sizes of the contained FLOBs. [3] O(1) */ template size_t PMSimple::HashValue() const{ __TRACE__ return (size_t) (interval.HashValue()+linearMoves.Size()+ compositeMoves.Size()+ periodicMoves.Size()+ compositeSubMoves.Size()); } /* ~CopyFrom~ By calling this function the value of this instance will be equalized with this one of the attribute. The attribute must be of Type PMSimple. If __arg__ is of another type, the result is not determined and can lead to a crash of [secondo]. [3] O(L), where L is the number of contained linear moves */ template void PMSimple::CopyFrom(const Attribute* arg){ __TRACE__ Equalize((PMSimple*) arg); } /* ~ToListExpr~ This function converts a periodic moving constant into its nested list representation. [3] O(L), where L is the number of contained linear moves */ template ListExpr PMSimple::ToListExpr(const ListExpr typeInfo)const { __TRACE__ ListExpr timelist = startTime.ToListExpr(false); ListExpr SubMoveList = GetSubMoveList(submove); return ::nl->TwoElemList(timelist,SubMoveList); } /* ~ReadFrom~ Takes the value of this simple periodic moving object from a nested list. The result informs about the success of this call. If the List don't represent a valid periodic moving object, this instance will be undefined. This behavior differns to other ~readFrom~ functions to avoid some expensive tests before creating the actual object. [3] O(L), where L is the number of contained linear moves */ template bool PMSimple::ReadFrom(const ListExpr value, const ListExpr typeInfo){ __TRACE__ /* The list is scanned twice. In the first scan we compute only the needed size of the contained arrays. The reason is, that we want to avoid frequently ~Resize~ on the arrays. */ if(::nl->ListLength(value)!=2){ if(DEBUG_MODE){ std::cerr << __POS__ << ": wrong listlength ("; std::cerr << (::nl->ListLength(value)) << ")" << std::endl; } SetDefined(false); return false; } if(!ResizeArrays(value)){ if(DEBUG_MODE){ std::cerr << __POS__ << ": resize array failed" << std::endl; } SetDefined(false); return false; } if(!startTime.ReadFrom(::nl->First(value),false)){ if(DEBUG_MODE){ std::cerr << __POS__ << "reading of the start time failed" << std::endl; std::cerr << "The list is " << std::endl; ::nl->WriteListExpr(::nl->First(value)); } SetDefined(false); return false; } // now we have to append the included submove ListExpr SML = ::nl->Second(value); if(::nl->ListLength(SML)!=2){ if(DEBUG_MODE){ std::cerr << __POS__ << ": wrong list length for submove" << std::endl; } SetDefined(false); return false; } ListExpr SMT = ::nl->First(SML); int LMIndex = 0; int CMIndex = 0; int SMIndex = 0; int PMIndex = 0; if(::nl->IsEqual(SMT,"linear")){ submove.arrayNumber = LINEAR; submove.arrayIndex = 0; if(!AddLinearMove(::nl->Second(SML),LMIndex,CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << " Error in reading linear move" << std::endl; } SetDefined(false); return false; } SetDefined(true); Unit LM; linearMoves.Get(0,LM); interval.Equalize(&(LM.interval)); CorrectDurationSums(); return true; } if(::nl->IsEqual(SMT,"composite")){ submove.arrayNumber=COMPOSITE; submove.arrayIndex = 0; if(!AddCompositeMove(::nl->Second(SML),LMIndex, CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << "error in reading composite move" << std::endl; } SetDefined(false); return false; } SetDefined(true); CompositeMove CM; compositeMoves.Get(0,CM); interval.Equalize(&(CM.interval)); CorrectDurationSums(); return true; } if(::nl->IsEqual(SMT,"period")){ submove.arrayNumber = PERIOD; submove.arrayIndex = 0; if(!AddPeriodMove(::nl->Second(SML),LMIndex,CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << " error in reading periodic move" << std::endl; } SetDefined(false); return false; } SetDefined(true); PeriodicMove PM; periodicMoves.Get(0,PM); interval.Equalize(&(PM.interval)); CorrectDurationSums(); return true; } if(DEBUG_MODE){ std::cerr << __POS__ << "unknown subtype" << std::endl; ::nl->WriteListExpr(SMT); } return false; } /* ~IsEmpty~ This function yields __true__ if this periodic moving constant don't contain any unit. */ template bool PMSimple::IsEmpty()const{ return linearMoves.Size()==0; } /* ~At~ This function returns a pointer to a new created instance of type T. If this periodic moving constant is not defined at this timepoint, the result will be 0. The caller of this function has to delete the returned value of this function if the result is not null. [3] O(L), where L is the number of contained linear moves */ template void PMSimple::At(const datetime::DateTime* instant,T& res)const{ __TRACE__ datetime::DateTime* duration = new datetime::DateTime(*instant); duration->Minus(&startTime); // now it is a duration if(interval.Contains(duration)){ // in the other case, we have nothing to do // because the result is initialized with "undefined" SubMove sm(submove); CompositeMove CM; PeriodicMove PM; RelInterval RI; while(sm.arrayNumber!=LINEAR){ if(sm.arrayNumber==COMPOSITE){ // in this stage of implementation a linear search is // executed. i have to make it better in the future int i = sm.arrayIndex; compositeMoves.Get(i,CM); int cur = CM.minIndex; int max = CM.maxIndex; bool found=false; while( (cur<=max) && ! found){ CSubMove csm; compositeSubMoves.Get(cur,csm); // get the submove if(csm.arrayNumber==LINEAR){ Unit LM; linearMoves.Get(csm.arrayIndex,LM); RI = LM.interval; } else if(csm.arrayNumber==PERIOD){ periodicMoves.Get(csm.arrayIndex,PM); RI = PM.interval; } else { //another submoves are not allowed assert(false); } if(RI.Contains(duration)) // be happy found=true; else{ // search again datetime::DateTime* L = RI.GetLength(); duration->Minus(L); delete L; L = NULL; cur++; } } assert(found); //otherwise we have an error in computation } else if(sm.arrayNumber==PERIOD){ int index = sm.arrayIndex; periodicMoves.Get(index,PM); // this is a very slow implementation // i have to speed up it in the future sm = PM.submove; RelInterval RI; if(sm.arrayNumber==LINEAR){ Unit LM; linearMoves.Get(sm.arrayIndex,LM); RI = LM.interval; } else if(sm.arrayNumber==COMPOSITE){ compositeMoves.Get(sm.arrayIndex,CM); RI = CM.interval; } else { //another submoves are not allowed assert(false); } while(!RI.Contains(duration)){ datetime::DateTime* L = RI.GetLength(); duration->Minus(L); delete L; L = NULL; } } else{ // this case should never occurs assert(false); } } Unit LM; linearMoves.Get(sm.arrayIndex,LM); if(LM.IsDefinedAt(duration)){ LM.At(duration,res); } } delete duration; duration = NULL; } /* ~Initial~ This function computes the first defined value of this moving constant. */ template bool PMSimple::Initial(T& result) const{ __TRACE__ if(!IsDefined() || IsEmpty()){ return false; } Unit lm; linearMoves.Get(0,lm); return lm.Initial(result); } /* ~Final~ The ~Final~ function returns the last defined value of this periodic moving object. If none exists, NULL is returned. */ template bool PMSimple::Final(T& res)const{ __TRACE__ if(!IsDefined()){ return false; } if(IsEmpty()){ return false; } Unit lm = GetLastUnit(); return lm.Final(res); } /* ~Translation~ Moves this simple time within the time. */ template void PMSimple::Translate(const datetime::DateTime& duration){ startTime += duration; } template void PMSimple::Translate(const datetime::DateTime* duration, PMSimple& res)const{ res.Equalize(this); res.startTime += *duration; } /* ~Minimize~ When this function is called, consecutive units with the same value are summarized into single units. */ template void PMSimple::Minimize(){ if(MinimizationRequired()){ DbArray newLinearMoves(1); DbArray newCompositeMoves(1); DbArray newCompositeSubMoves(1); DbArray newPeriodicMoves(1); Unit Summarization; bool CompleteSummarized; SubMove SM3 = MinimizeRec(submove,newLinearMoves,newCompositeMoves, newCompositeSubMoves, newPeriodicMoves,Summarization,CompleteSummarized); if(CompleteSummarized){ // the whole movement can be represented in a single linear move compositeMoves.clean(); compositeSubMoves.clean(); periodicMoves.clean(); linearMoves.clean(); linearMoves.Append(Summarization); submove.arrayNumber = LINEAR; submove.arrayIndex = 0; } else{ submove = SM3; // copy the new created objects into the local dbarrays linearMoves.copyFrom(newLinearMoves); compositeMoves.copyFrom(newCompositeMoves); compositeSubMoves.copyFrom(newCompositeSubMoves); periodicMoves.copyFrom(newPeriodicMoves); } } CorrectDurationSums(); } /* ~Statistical Information~ The following functions can be used in debugging for get some additional information about the inner structure of this instant. */ template int PMSimple::NumberOfLinearMoves(){ return linearMoves.Size(); } template int PMSimple::NumberOfCompositeMoves(){ return compositeMoves.Size(); } template int PMSimple::NumberOfCompositeSubMoves(){ return compositeSubMoves.Size(); } template int PMSimple::NumberOfPeriodicMoves(){ return periodicMoves.Size(); } /* ~Split~ Calling this function splits this moving object at the given instant. The splitpoint is given by an instant as well as a flag describing whether this instant should be contained in the 'left' part. The results are stored into the corresponding arguments. When the instant is outside the definition time of this moving object, oe part will contain a copy of this, the other part will be undefined. */ template void PMSimple::Split(const datetime::DateTime instant, const bool toLeft, PMSimple& leftPart, PMSimple& rightPart){ SubMove SMLeft,SMRight; SMLeft.arrayNumber = -1; SMRight.arrayNumber = -1; datetime::DateTime stCopy = startTime; splitRec(instant, toLeft,leftPart,rightPart,submove,stCopy,SMLeft,SMRight); // set the values of the root record of the left part if(SMLeft.arrayNumber<0){ // leftpart is empty leftPart.defined=false; } else{ // leftpart is non-empty leftPart.defined = true; leftPart.startTime = startTime; leftPart.GetInterval(SMLeft,leftPart.interval); } // set the values of the root record of the right part if(SMRight.arrayNumber<0){ rightPart.defined=false; }else{ rightPart.defined=true; rightPart.startTime = instant; rightPart.GetInterval(SMRight,rightPart.interval); } std::cerr << "Missing correction for splitted infinite periodic moves !!!" << std::endl; } /* ~SpliRec~ This function splits the given submove of this periodic moving objects into two part. The leftPart will be extended by the part of this submove before the given instant. The remainder of this submove will stored into rightPart. The new added submove of leftPart and rightPart is returned in the arguments SMLeft and SMRight respectively. The argument toLeft controls whereto put in the object at the given instant (closure properties). The starttime is changed to be after the processed submove. If the submove is not defined before the given instant, leftPart is not changed and SMLeft will hold an negative number for the arrayNumber indicating an invalid value. When submove is'nt defined after this instant, the same holds for rightPart and SMRight. */ template void PMSimple::splitRec(const datetime::DateTime instant, const bool toLeft, PMSimple& leftPart, PMSimple& rightPart, SubMove submove, datetime::DateTime& startTime, SubMove& SMLeft, SubMove& SMRight){ if(submove.arrayNumber==LINEAR){ // here we process a single unit. this case is easy to handle because a // unit have to provide a split function Unit LML; linearMoves.Get(submove.arrayIndex,LML); Unit LMR; datetime::DateTime Dur = instant - startTime; startTime = startTime + (*LML.interval.GetLength()); bool saveLeft,saveRight; if(LML.GetDefined()){ LML.Split(Dur,toLeft,LMR); saveLeft = LML.GetDefined(); saveRight = LMR.GetDefined(); } else{ // original is undefined LML.interval.Split(Dur,toLeft,LMR.interval); LMR.SetDefined(false); saveLeft = LML.interval.IsDefined(); saveRight = LMR.interval.IsDefined(); } if(saveLeft){ SMLeft.arrayNumber=LINEAR; SMLeft.arrayIndex = leftPart.linearMoves.Size(); leftPart.linearMoves.Append(LML); }else{ SMLeft.arrayNumber = -1; } // do the same thing with the right part if(saveRight){ SMRight.arrayNumber=LINEAR; SMRight.arrayIndex=rightPart.linearMoves.Size(); rightPart.linearMoves.Append(LML); } else{ SMRight.arrayNumber = -1; } return; // linear moves processed } if(submove.arrayNumber==COMPOSITE){ // we store the submoves of this composite moves into an vector // to ensure a single block representing this submove CompositeMove CM; compositeMoves.Get(submove.arrayIndex,CM); std::vector submovesLeft(CM.maxIndex-CM.minIndex+1); std::vector submovesRight(CM.maxIndex-CM.minIndex+1); CSubMove SM; for(int i=CM.minIndex;i<=CM.maxIndex;i++){ compositeSubMoves.Get(i,SM); // get the submove // call recursive splitRec(instant,toLeft,leftPart,rightPart,SM,startTime,SMLeft,SMRight); // collect valid submoves CSubMove CSMLeft; CSMLeft.arrayNumber = SMLeft.arrayNumber; CSMLeft.arrayIndex = SMLeft.arrayIndex; CSubMove CSMRight; CSMRight.arrayNumber = SMRight.arrayNumber; CSMRight.arrayIndex = SMRight.arrayIndex; if(SMLeft.arrayNumber>=0) submovesLeft.push_back(CSMLeft); if(SMRight.arrayNumber>=0) submovesRight.push_back(CSMRight); } // process the left part int size = submovesLeft.size(); if(size==0){ SMLeft.arrayNumber = -1; } else if (size>1){ // in case size==1 is nothing to do CompositeMove CMLeft; CMLeft.minIndex = leftPart.compositeSubMoves.Size(); for(int i=0;i1){ CompositeMove CMRight; CMRight.minIndex = rightPart.compositeSubMoves.Size(); for(int i=0;i void PMSimple::SplitLeft(const datetime::DateTime& instant, const bool toLeft, PMSimple* result){ SubMove LastMove; datetime::DateTime startTimecopy(datetime::instanttype); startTimecopy.Equalize(&startTime); if(!SplitLeftRec(instant,toLeft,*result,submove,startTimecopy,LastMove)) result->SetDefined(false); else{ result->startTime = startTime; datetime::DateTime len = instant-startTime; result->interval.Set(&len,interval.IsLeftClosed(),toLeft); result->submove = LastMove; } } template bool PMSimple::SplitLeftRec(const datetime::DateTime& instant, const bool toLeft, PMSimple& result,const SubMove& submove, datetime::DateTime& startTime,SubMove& lastSubmove){ /* First, we handle the a single unit. */ if(submove.arrayNumber==LINEAR){ if(startTime > instant) // is right of the instant return false; Unit u; linearMoves.Get(submove.arrayIndex,u); RelInterval interval; interval.Equalize(&u.interval); datetime::DateTime dur = instant-startTime; if(!u.interval.Contains(&dur)){ return false; } Unit rightUnit; u.Split(dur,toLeft,rightUnit); result.linearMoves.Append(u); datetime::DateTime len(datetime::durationtype); interval.StoreLength(len); startTime = startTime + len; lastSubmove.arrayNumber=LINEAR; lastSubmove.arrayIndex = result.linearMoves.Size()-1; return true; } /* Second, handling of composite moves */ if(submove.arrayNumber == COMPOSITE){ CompositeMove CM; compositeMoves.Get(submove.arrayIndex,CM); datetime::DateTime dur = instant-startTime; if(!CM.interval.Contains(&dur)) return false; CSubMove SM; std::vector mySubmoves(CM.maxIndex-CM.minIndex); bool done = false; for(int i =CM.minIndex;i<=CM.maxIndex && !done;i++){ compositeSubMoves.Get(i,SM); if(SplitLeftRec(instant,toLeft,result,SM,startTime,lastSubmove)){ mySubmoves.push_back(lastSubmove); } else { // after this move can't follow any further moves done=true; } } if(mySubmoves.size()<2){ // ok, this submoves is end in smoke return true; }else{ // we have to build a composite move from the remaining submoves datetime::DateTime length(datetime::durationtype); datetime::DateTime nextLength(datetime::durationtype); int size = mySubmoves.size(); RelInterval interval; CM.minIndex = result.compositeSubMoves.Size(); for(int i=0;i void PMSimple::Intersection( const datetime::DateTime minTime, const bool minIncluded, const datetime::DateTime maxTime, const bool maxIncluded, PMSimple* res){ PMSimple TMPPM1; PMSimple TMPPM2; Split(minTime,!minIncluded,TMPPM2,TMPPM1); //TMPPM1.Split(maxTime,maxIncluded,TMPPM1,*result); TMPPM1.SplitLeft(maxTime,maxIncluded,res); } /* ~CopyValuesFrom~ By calling this function, the value of this pmsimple is set to the given values. There is no check whether the values are valid. Use this function very carefully. A possible application of this function is to take the tree from another periodic moving object. */ template void PMSimple::CopyValuesFrom( DbArray& linearMoves, DbArray& compositeMoves, DbArray& compositeSubMoves, DbArray& periodicMoves, bool defined, RelInterval interval, datetime::DateTime startTime, SubMove submove){ // first, clear all contained arraysa this->linearMoves.copyFrom(linearMoves); this->compositeMoves.copyFrom(compositeMoves); this->compositeSubMoves.copyFrom(compositeSubMoves); this->periodicMoves.copyFrom(periodicMoves); SetDefined(defined); this->interval.Equalize(&interval); this->startTime.Equalize(&startTime); this->submove=submove; } /* ~TakeValuesFrom~ This function works similar to the ~CopyValuesFrom~ function. The difference is, that the values are assigned to the internal variables. These variables are cleaned before. *Note*: There is no check for the integrity of the given data. */ template void PMSimple::TakeValuesFrom( DbArray& linearMoves, DbArray& compositeMoves, DbArray& compositeSubMoves, DbArray& periodicMoves, bool defined, RelInterval interval, datetime::DateTime startTime, SubMove submove){ this->linearMoves.Clear(); this->linearMoves.Destroy(); this->compositeMoves.clean(); this->compositeMoves.Destroy(); this->compositeSubMoves.clean(); this->compositeSubMoves.Destroy(); this->periodicMoves.clean(); this->periodicMoves.Destroy(); this->linearMoves = linearMoves; this->compositeMoves = compositeMoves; this->compositeSubMoves = compositeSubMoves; this->periodicMoves = periodicMoves; this->defined = defined; this->interval = interval; this->startTimes = startTime; this->submove = submove; } /* ~SetStartTime~ This function can be used for moving this PMsimple in time. */ template void PMSimple::SetStartTime(datetime::DateTime newStart){ startTime.Equalize(&newStart); } /* ~Functions returning pointers to the members~ Each of the next functions returns a pointer for a member. This way bypasses the protected declaration of the members because this function enables the possibility to manipulate the members direcly without control of the PMSimple class. This may be not good for encapsulating the code but the only way to have an efficient implementation for that. The caller of this functions must be very very carefully to ensure that all the manipulated members results in a consistent instance of type PMSimple. A possible application of this function is to make a copy of the tree structure of another periodic moving object. */ template DbArray* PMSimple::GetLinearMoves(){ return &linearMoves; } template DbArray* PMSimple::GetCompositeMoves(){ return &compositeMoves; } template DbArray* PMSimple::GetCompositeSubMoves(){ return &compositeSubMoves; } template DbArray* PMSimple::GetPeriodicMoves(){ return &periodicMoves; } template RelInterval* PMSimple::GetInterval(){ return &interval; } template SubMove* PMSimple::GetSubmove(){ return &submove; } /* ~GetLength~ This function returns the lenght of the interval of the given submove. */ template void PMSimple::GetLength(SubMove sm, datetime::DateTime& result){ switch(sm.arrayNumber){ case LINEAR: { Unit U; linearMoves.Get(sm.arrayIndex,U); U.interval.StoreLength(result); } break; case COMPOSITE: { CompositeMove CM; compositeMoves.Get(sm.arrayIndex,CM); CM.interval.StoreLength(result); }break; case PERIOD: { PeriodicMove PM; periodicMoves.Get(sm.arrayIndex,PM); PM.interval.StoreLength(result); } break; default: assert(false); // unknown move type } } /* ~GetLeftClosed~ This function returns the state of the LeftClosed flag of the interval of the given submove. */ template bool PMSimple::GetLeftClosed(SubMove sm){ switch(sm.arrayNumber){ case LINEAR: { Unit U; linearMoves.Get(sm.arrayIndex,U); return U.interval.IsLeftClosed(); } case COMPOSITE: { CompositeMove CM; return CM.interval.IsLeftClosed(); } case PERIOD: { PeriodicMove PM; return PM.interval.IsLeftClosed(); } default: assert(false); // unknown move type } } /* ~GetRightClosed~ This function returns the state of the RightClosed flag of the interval of the given submove. */ template bool PMSimple::GetRightClosed(SubMove sm){ switch(sm.arrayNumber){ case LINEAR: { Unit U; linearMoves.Get(sm.arrayIndex,U); return U.interval.IsRightClosed(); } case COMPOSITE: { CompositeMove CM; return CM.interval.IsRightClosed(); } case PERIOD: { PeriodicMove PM; return PM.interval.IsRightClosed(); } default: assert(false); // unknown move type } } /* ~GetInterval~ This function returns the returns the interval of the given submove independly of the type of the submove. */ template void PMSimple::GetInterval(SubMove sm,RelInterval& interval){ switch(sm.arrayNumber){ case LINEAR: { Unit U; linearMoves.Get(sm.arrayIndex,U); interval.Equalize(&U.interval); } break; case COMPOSITE: { CompositeMove CM; compositeMoves.Get(sm.arrayIndex,CM); interval.Equalize(&CM.interval); }break; case PERIOD: { PeriodicMove PM; periodicMoves.Get(sm.arrayIndex,PM); interval.Equalize(&PM.interval); }break; default: assert(false); // unknown move type } } /* ~GetSubMoveList~ This function returns the list representation for the submove in the argument. [3] O(L), where L is the number of contained linear moves */ template ListExpr PMSimple::GetSubMoveList(const SubMove SM) const{ __TRACE__ ListExpr SubMoveList; int SubMoveType = SM.arrayNumber; int index = SM.arrayIndex; if(SubMoveType==LINEAR) SubMoveList = GetLinearMoveList(index); else if(SubMoveType==COMPOSITE) SubMoveList = GetCompositeMoveList(index); else if(SubMoveType==PERIOD) SubMoveList = GetPeriodicMoveList(index); else{ std::cerr << __POS__ << " Error in creating ListExpr" << std::endl; SubMoveList = ::nl->TheEmptyList(); } return SubMoveList; } /* ~GetLinearMoveList~ This functions takes the linear move at the specified index and returns its nested list representation. [3] O(1) */ template ListExpr PMSimple::GetLinearMoveList(const int index)const{ __TRACE__ Unit LM; linearMoves.Get(index,LM); return LM.ToListExpr(); } /* ~GetPeriodicMoveList~ Creates a nested list for the periodic move at the specified index. [3] O(L), where L is the number of contained linear moves */ template ListExpr PMSimple::GetPeriodicMoveList(const int index)const{ __TRACE__ PeriodicMove PM; periodicMoves.Get(index,PM); ListExpr periodtype = ::nl->SymbolAtom("period"); ListExpr RepList = ::nl->IntAtom(PM.repeatations); ListExpr SML = GetSubMoveList(PM.submove); ListExpr RC = ::nl->BoolAtom(interval.IsRightClosed()); ListExpr LC = ::nl->BoolAtom(interval.IsLeftClosed()); return ::nl->TwoElemList(periodtype,::nl->FourElemList(RepList,LC,RC,SML)); } /* ~GetCompositeMoveList~ Returns the CompositeMove at the specified index in its nested list representation. [3] O(L), where L is the number of contained linear moves */ template ListExpr PMSimple::GetCompositeMoveList(const int index)const{ __TRACE__ CompositeMove CM; compositeMoves.Get(index,CM); ListExpr CType = ::nl->SymbolAtom("composite"); int minIndex = CM.minIndex; int maxIndex = CM.maxIndex; ListExpr SubMovesList; if(maxIndexTheEmptyList(); } else{ // construct the List of submoves CSubMove SM; compositeSubMoves.Get(minIndex,SM); SubMovesList = ::nl->OneElemList(GetSubMoveList(SM)); ListExpr Last = SubMovesList; for(int i=minIndex+1;i<=maxIndex;i++){ compositeSubMoves.Get(i,SM); Last = ::nl->Append(Last,GetSubMoveList(SM)); } } return ::nl->TwoElemList(CType,SubMovesList); } /* ~ResizeArrays~ This functions resizes all array to be able to insert the moves contained in the argument list.This function should be called before this instance is read from a nested list to avoid frequently resize of the contained DB-Arrays. The return value of this function is an indicator for the correctness of the structure of this list. If the result is __false__, the list don't represent a valid periodic moving object. But a return value of __true__ don't guarantees a correct list representation. [3] O(L), where L is the number of contained linear moves */ template bool PMSimple::ResizeArrays(const ListExpr value){ __TRACE__ // first all entries in the arrays are removed linearMoves.clean(); compositeMoves.clean(); compositeSubMoves.clean(); periodicMoves.clean(); int LMSize = 0; int CMSize = 0; int SMSize = 0; int PMSize = 0; if(!AddSubMovesSize(::nl->Second(value),LMSize,CMSize,SMSize,PMSize)) return false; // set the arrays to the needed size if(LMSize>0) linearMoves.resize(LMSize); if(CMSize>0) compositeMoves.resize(CMSize); if(SMSize>0) compositeSubMoves.resize(SMSize); if(PMSize>0) periodicMoves.resize(PMSize); return true; } /* ~AddSubMovesSize~ Adds the number of in value contained submoves to the appropriate size. If the result is__false__, the list is not a correct representation of a periodic moving object. If it is __true__ the content of the list can be wrong but the structure is correct. [3] O(L), where L is the number of contained linear moves */ template bool PMSimple::AddSubMovesSize(const ListExpr value, int &LMSize,int &CMSize, int &SMSize,int &PMSize){ __TRACE__ // all moves have the length 2 if(::nl->ListLength(value)!=2) return false; ListExpr type = ::nl->First(value); if(::nl->AtomType(type)!=SymbolType) return false; // in a linear move we have only to increment the size of LM if(::nl->IsEqual(type,"linear")){ LMSize = LMSize +1; return true; } if(::nl->IsEqual(type,"composite")){ CMSize = CMSize+1; // the composite move itself ListExpr rest = ::nl->Second(value); SMSize = SMSize+::nl->ListLength(rest); // the contained submoves while(!::nl->IsEmpty(rest)){ if(!AddSubMovesSize(::nl->First(rest),LMSize,CMSize,SMSize,PMSize)) return false; rest = ::nl->Rest(rest); } return true; } if(::nl->IsEqual(type,"period")){ PMSize = PMSize+1; int len = ::nl->ListLength(value); ListExpr PMove; if(len==2) PMove = ::nl->Second(value); else if(len==4) PMove = ::nl->Fourth(value); else // incorrect listlength return false; return AddSubMovesSize(::nl->Second(PMove), LMSize,CMSize,SMSize,PMSize); } // a unknown type description return false; } /* ~AddLinearMove~ This function adds the LinearMove given in value to this PMSimple. If the list represents a valid Unit, this unit is append to to appropriate dbarray and the argument __LMIndex__ is increased. If the list is incorrect, this periodic moving object is not changed and the result will be __false__. [3] O(1) */ template bool PMSimple::AddLinearMove(const ListExpr value,int &LMIndex, int &CMIndex, int &SMIndex, int &PMIndex){ __TRACE__ Unit LM = Unit(0); if(!LM.ReadFrom(value)) return false; linearMoves.Put(LMIndex,LM); LMIndex++; return true; } /* ~AddCompositeMove~ This function creates a CompositeMove from value and adds it (and all contained submoves) to this PMSimple. The return value corresponds to the correctness of the list for this composite move. The arguments are increased by the number of contained submoves in this composite move. *Note*: This function can change this periodic moving object even when the list is not correct. In the case of a result of __false__, the state of this object is not defined and the defined flag should be set to false. [3] O(L), where L is the number of contained linear moves */ template bool PMSimple::AddCompositeMove(const ListExpr value, int &LMIndex, int &CMIndex, int &SMIndex, int &PMIndex){ __TRACE__ // a composite move has to contains at least two submoves int len = ::nl->ListLength(value); if(len<2){ if(DEBUG_MODE){ std::cerr << __POS__ << " less than 2 submoves (" << len << ")" << std::endl; } return false; } CompositeMove CM=CompositeMove(1); int CMPos=CMIndex; int SMPos=SMIndex; // ensure that no submove used the positions for this composite move CMIndex++; CM.minIndex=SMIndex; CM.maxIndex=SMIndex+len-1; SMIndex= SMIndex+len; // Append the contained Submoves ListExpr rest = value; ListExpr SML,TL,VL; bool isFirst = true; while(!::nl->IsEmpty(rest)){ SML = ::nl->First(rest); rest = ::nl->Rest(rest); if(::nl->ListLength(SML)!=2){ // all submoves have the // format (type value) if(DEBUG_MODE){ std::cerr << __POS__ << " submove has wrong length ("; std::cerr << ::nl->ListLength(SML) << ")" << std::endl; } return false; } TL = ::nl->First(SML); VL = ::nl->Second(SML); if(::nl->IsEqual(TL,"linear")){ // process a linear submove int LMPos = LMIndex; if(!AddLinearMove(VL,LMIndex,CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << " can't add a linear move " << std::endl; } return false; } Unit LM; linearMoves.Get(LMPos,LM); // Append the interval of LM to CM if(isFirst){ isFirst=false; CM.interval.Equalize(&(LM.interval)); }else{ if(!CM.interval.Append(&(LM.interval))){ if(DEBUG_MODE){ std::cerr << __POS__ << " can't append interval " << std::endl; std::cerr << "The original interval is"; std::cerr << CM.interval.ToString() << std::endl; std::cerr << "The interval to append is"; std::cerr << LM.interval.ToString() << std::endl; } return false; } } // put the submove in the array CSubMove SM; SM.arrayNumber = LINEAR; SM.arrayIndex = LMPos; compositeSubMoves.Put(SMPos,SM); SMPos++; } else if(::nl->IsEqual(TL,"period")){ // process a periodic submove int PMPos = PMIndex; if(!AddPeriodMove(VL,LMIndex,CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << "can't add period move " << std::endl; } return false; } PeriodicMove PM; periodicMoves.Get(PMPos,PM); if(isFirst){ isFirst=false; CM.interval.Equalize(&(PM.interval)); }else{ if(!CM.interval.Append(&(PM.interval))){ if(DEBUG_MODE){ std::cerr << __POS__ << " can't append interval" << std::endl; } return false; } } CSubMove SM; SM.arrayNumber = PERIOD; SM.arrayIndex = PMPos; compositeSubMoves.Put(SMPos,SM); SMPos++; } else{ // not of type linear or period if(DEBUG_MODE){ std::cerr << __POS__ << " submove not of type "; std::cerr << "linear od period" << std::endl; } return false; } } // put the compositeMove itself compositeMoves.Put(CMPos,CM); return true; } /* ~AddPeriodMove~ Adds the period move described in value to this PMSimple. *Note*: This function can change this objects even wehn the list does not represent a valid period move. If the result is __false__ the __defined__ flag of this move should be set to false. [3] O(L), where L is the number of contained linear moves */ template bool PMSimple::AddPeriodMove(const ListExpr value, int &LMIndex, int &CMIndex, int &SMIndex, int &PMIndex){ __TRACE__ int len = ::nl->ListLength(value); if((len!=2) && (len!=4)){ // (repeatations ) if(DEBUG_MODE) std::cerr << __POS__ << ": wrong listlength" << std::endl; return false; } if(::nl->AtomType(::nl->First(value))!=IntType){ if(DEBUG_MODE){ std::cerr << __POS__ << ": wrong type for repeatations" << std::endl; } return false; } int rep = ::nl->IntValue(::nl->First(value)); // rep must be greater than 1 if(rep<=1 ){ if(DEBUG_MODE){ std::cerr << __POS__ << " wrong number of repeatations" << std::endl; } return false; } ListExpr SML; if(len==2){ SML = ::nl->Second(value); } else { // len == 4 SML = ::nl->Fourth(value); } if(::nl->ListLength(SML)!=2){ if(DEBUG_MODE){ std::cerr << __POS__ << ": wrong length for submove" << std::endl; } return false; } PeriodicMove PM=PeriodicMove(1); PM.repeatations = rep; int IncludePos = PMIndex; // store the positiuon PMIndex++; ListExpr SMT = ::nl->First(SML); // take the submove type if(::nl->IsEqual(SMT,"linear")){ int LMPos = LMIndex; if(!AddLinearMove(::nl->Second(SML),LMIndex,CMIndex,SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << ": can't add linear submove" << std::endl; } return false; } PM.submove.arrayNumber = LINEAR; PM.submove.arrayIndex = LMPos; Unit LM; linearMoves.Get(LMPos,LM); RelInterval SMI = LM.interval; PM.interval.Equalize(&SMI); PM.interval.Mul(rep); if(len==4){ ListExpr LC = ::nl->Second(value); ListExpr RC = ::nl->Third(value); if((::nl->AtomType(LC)!=BoolType) || (::nl->AtomType(RC)!=BoolType)) return false; PM.interval.SetLeftClosed(::nl->BoolValue(LC)); PM.interval.SetRightClosed(::nl->BoolValue(RC)); } periodicMoves.Put(IncludePos,PM); return true; }else if(::nl->IsEqual(SMT,"composite")){ int CMPos = CMIndex; if(!AddCompositeMove(::nl->Second(SML),LMIndex,CMIndex, SMIndex,PMIndex)){ if(DEBUG_MODE){ std::cerr << __POS__ << ": can't add composite submove" << std::endl; } return false; } PM.submove.arrayNumber = COMPOSITE; PM.submove.arrayIndex = CMPos; CompositeMove CM; compositeMoves.Get(CMPos,CM); RelInterval SMI = CM.interval; PM.interval.Equalize(&SMI); PM.interval.Mul(rep); if(len==4){ ListExpr LC = ::nl->Second(value); ListExpr RC = ::nl->Third(value); if((::nl->AtomType(LC)!=BoolType) || (::nl->AtomType(RC)!=BoolType)) return false; PM.interval.SetLeftClosed(::nl->BoolValue(LC)); PM.interval.SetRightClosed(::nl->BoolValue(RC)); } periodicMoves.Put(IncludePos,PM); return true; } return false; // invalid type } /* ~GetLastUnit~ This function returns the temporal last unit of this periodic moving point. It is realized by going down the repetition tree up to a unit. */ template Unit PMSimple::GetLastUnit()const{ __TRACE__ const SubMove* s = &submove; while(s->arrayNumber!=LINEAR){ if(s->arrayNumber==PERIOD){ PeriodicMove PM; periodicMoves.Get(s->arrayIndex,PM); s = &PM.submove; } else if(s->arrayNumber==COMPOSITE){ CompositeMove CSM; compositeMoves.Get(s->arrayIndex,CSM); CSubMove csm; compositeSubMoves.Get(CSM.maxIndex,csm); SubMove sm; sm.arrayNumber = csm.arrayNumber; sm.arrayIndex = csm.arrayIndex; s = &sm; } else{ assert(false); // unknown arraynumber } } Unit res; linearMoves.Get(s->arrayIndex,res); return res; } /* ~MinimizationRequired~ This function checks, whether an call of ~Minimize~ will change the tree. Particularly, it checks whether two consecutive units can be summarized to a single one. */ template bool PMSimple::MinimizationRequired(){ __TRACE__ Unit LM; Unit LM2; CompositeMove CM; PeriodicMove PM; const SubMove* SM=0; // check periodic moves int size = periodicMoves.Size(); for(int i=0;iarrayIndex==LINEAR){ linearMoves.Get(SM->arrayIndex,LM); if(LM.interval.CanAppended(&LM.interval)) return true; } } CSubMove CSM; CSubMove CSM2; // check composite moves size = compositeMoves.Size(); for(int i=0;i SubMove PMSimple::MinimizeRec(SubMove SM, DbArray& newLinearMoves, DbArray& newCompositeMoves, DbArray& newCompositeSubMoves, DbArray& newPeriodicMoves, Unit& Summarization, bool& CompleteSummarized){ if(SM.arrayNumber==LINEAR){ linearMoves.Get(SM.arrayIndex,Summarization); CompleteSummarized=true; return SM; } if(SM.arrayNumber==PERIOD){ PeriodicMove PM2; periodicMoves.Get(SM.arrayIndex,PM2); SubMove SM2 = MinimizeRec(PM2.submove, newLinearMoves,newCompositeMoves, newCompositeSubMoves,newPeriodicMoves, Summarization, CompleteSummarized); if(!CompleteSummarized){ PM2.submove = SM2; int Pos = newPeriodicMoves.Size(); newPeriodicMoves.Append(PM2); SM2.arrayNumber=PERIOD; SM2.arrayIndex= Pos; CompleteSummarized = false; return SM2; }else{ // the result is a single linear move if(!Summarization.interval.CanAppended( &Summarization.interval)){ // a little gap int LinPos = newLinearMoves.Size(); newLinearMoves.Append(Summarization); PM2.submove.arrayNumber=LINEAR; PM2.submove.arrayIndex=LinPos; // store this periodic move int PerPos = newPeriodicMoves.Size(); newPeriodicMoves.Append(PM2); SM2.arrayNumber=PERIOD; SM2.arrayIndex=PerPos; CompleteSummarized=false; return SM2; }else{ // we don't need longer this periodic move Summarization.interval.Mul(PM2.repeatations); return SM2; } } } if(SM.arrayNumber==COMPOSITE){ CompositeMove CM; compositeMoves.Get(SM.arrayIndex,CM); Unit LM(0); bool LMdefined = false; std::vector MySubMoves; for(int i=CM.minIndex;i<=CM.maxIndex;i++){ CSubMove Current; compositeSubMoves.Get(i,Current); SubMove SM2 = MinimizeRec(Current, newLinearMoves,newCompositeMoves, newCompositeSubMoves,newPeriodicMoves, Summarization, CompleteSummarized); if(!CompleteSummarized){ // store summarized submove if present if(LMdefined){ int LinPos = newLinearMoves.Size(); newLinearMoves.Append(LM); LMdefined=false; CSubMove SM3; SM3.arrayNumber=LINEAR; SM3.arrayIndex=LinPos; MySubMoves.push_back(SM3); } CSubMove SM3; SM3.arrayIndex = SM2.arrayIndex; SM3.arrayNumber= SM2.arrayNumber; MySubMoves.push_back(SM3); }else{ // submove complete summarized if(!LMdefined){ // first summarized LinearMove; LM = Summarization; LMdefined=true; }else{ if(LM.CanSummarized(&Summarization)){ // append the new summarization to LM LM.interval.Append(&Summarization.interval); } else{ // the new summarization cannot appendend to LM // store LM int LinPos = newLinearMoves.Size(); newLinearMoves.Append(LM); CSubMove SM3; SM3.arrayNumber=LINEAR; SM3.arrayIndex=LinPos; MySubMoves.push_back(SM3); LM = Summarization; } } } } // all submoves processed; if(MySubMoves.size()==0){ // all its collected into LM CompleteSummarized=true; Summarization = LM; return SM; // unimportant in this case }else{ if(LMdefined){ // store the last summarization int LinPos = newLinearMoves.Size(); newLinearMoves.Append(LM); CSubMove SM3; SM3.arrayNumber = LINEAR; SM3.arrayIndex = LinPos; MySubMoves.push_back(SM3); } CM.minIndex = newCompositeSubMoves.Size(); CM.maxIndex = CM.minIndex + MySubMoves.size()-1; // store the submoves for(unsigned int k=0;k void PMSimple::CorrectDurationSums(){ if(IsEmpty() || !IsDefined()){ // nothing to do return; } int cmsize = compositeMoves.Size(); RelInterval currentInterval; datetime::DateTime currentLength(datetime::durationtype); datetime::DateTime duration(datetime::durationtype); CompositeMove CM; // process all compositeMoves. for(int i=0;i