Files
secondo/Algebras/Periodic/RelInterval.cpp

756 lines
15 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
3.2 ~RelInterval~
*/
#include <iostream>
#include <string>
#include "NestedList.h"
#include "PeriodicTypes.h"
#include "PeriodicSupport.h"
#include "StandardTypes.h"
#include "DateTime.h"
extern NestedList* nl;
using namespace datetime;
using namespace std;
namespace periodic{
/*
~Constructor~
The special constructor for the cast function.
[3] O(1)
*/
RelInterval::RelInterval(){
__TRACE__
}
/*
~Constructor~
This constructor creates a defined single instant with length 0.
[3] O(1)
*/
RelInterval::RelInterval(int dummy):
Attribute(true),
length(datetime::durationtype),
state(0)
{
__TRACE__
ChangeLeftClosed(true);
ChangeRightClosed(true);
ChangeCanDelete(false);
}
/*
~A private constructor~
Creates a RelInterval from the given values. Is private because
the values can leads to a invalid state of this RelInterval.
[3] O(1)
*/
RelInterval::RelInterval(const DateTime* length, const bool leftClosed,
const bool rightClosed):
Attribute(true), length(durationtype), state(0){
__TRACE__
DateTime Zero= DateTime(durationtype);
int comp=length->CompareTo(&Zero);
assert(comp>=0);
assert(comp>0 || (leftClosed && rightClosed));
this->ChangeLeftClosed(leftClosed);
this->ChangeRightClosed(rightClosed);
this->length.Equalize(length);
}
/*
~Append~
This function appends D2 to this RelInterval if possible.
When D2 can't appended to this false is returned.
[3] O(1)
*/
bool RelInterval::Append(const RelInterval* R2){
__TRACE__
if(!CanAppended(R2))
return false;
length.Add(&(R2->length));
ChangeRightClosed(R2->IsRightClosed());
return true;
}
/*
~CanAppended~
This function checks whether D2 can appended to this RelInterval.
[3] O(1)
*/
bool RelInterval::CanAppended(const RelInterval* D2)const {
__TRACE__
if(IsRightClosed())
return ! D2->IsLeftClosed();
else
return D2->IsLeftClosed();
}
/*
~Contains~
Checks whether T is contained in this RelInterval
[3] O(1)
*/
bool RelInterval::Contains(const DateTime* T, bool relax /*=false*/)const {
__TRACE__
if(!IsDefined()){
return false;
}
DateTime Zero=DateTime(durationtype);
int compz = T->CompareTo(&Zero);
if(compz<0)
return false;
if(compz==0)
return IsLeftClosed() || relax;
int compe = T->CompareTo(&length);
if(compe<0)
return true;
if(compe==0)
return IsRightClosed() || relax;
return false;
}
/*
~Mul~
This functions extends this relinterval to be factor[mul]oldlength.
[3] O(1)
*/
void RelInterval::Mul(const long factor){
__TRACE__
length.Mul((int)factor);
}
/*
~Clone~
This function creates a new RelInterval with the same value as
the this object.
[3] O(1)
*/
RelInterval* RelInterval::Clone() const{
__TRACE__
RelInterval* Copy = new RelInterval(1);
Copy->Equalize(this);
return Copy;
}
/*
~CompareTo~
This function compares two RelIntervals.
[3] O(1)
*/
int RelInterval::CompareTo(const RelInterval* D2)const {
__TRACE__
if(!IsDefined() && !D2->IsDefined()){
return 0;
}
if(!IsDefined() && D2->IsDefined()){
return -1;
}
if(IsDefined() && !D2->IsDefined()){
return 1;
}
// at this point both involved intervals are defined
if(IsLeftClosed() && !D2->IsLeftClosed()) return -1;
if(!IsLeftClosed() && D2->IsLeftClosed()) return 1;
int tc = length.CompareTo(&(D2->length));
if(tc!=0) return tc;
if(!IsRightClosed() && D2->IsRightClosed()) return -1;
if(IsRightClosed() && !D2->IsRightClosed()) return 1;
return 0;
}
/*
~Compare~
This functions compares an attribute with this relinterval.
[3] O(1)
*/
int RelInterval::Compare(const Attribute* arg) const{
__TRACE__
RelInterval* D2 = (RelInterval*) arg;
return CompareTo(D2);
}
/*
~CopyFrom~
This function take the value for this relinterval from the
given argument.
[3] O(1)
*/
void RelInterval::CopyFrom(const Attribute* arg){
__TRACE__
Equalize((RelInterval*)arg);
}
/*
~HashValue~
[3] O(1)
*/
size_t RelInterval::HashValue() const{
__TRACE__
size_t lhv = length.HashValue();
if(IsLeftClosed()) lhv = lhv +1;
if(IsRightClosed()) lhv = lhv +1;
return lhv;
}
/*
~Sizeof~
[3] O(1)
*/
size_t RelInterval::Sizeof() const{
__TRACE__
return sizeof(*this);
}
/*
~Split~
Splits an interval at the specified position. __delta__ has to be in [0,1].
The return value indicates whether a rest exists.
[3] O(1)
*/
bool RelInterval::Split(const double delta, const bool closeFirst,
RelInterval& Rest){
__TRACE__
if((delta==0) && (!IsLeftClosed() || !closeFirst))
return false;
if((delta==1) && (!IsRightClosed() || closeFirst))
return false;
if(length.IsZero())
return false;
Rest.Equalize(this);
ChangeRightClosed(closeFirst);
Rest.SetLeftClosed(!closeFirst);
length.Split(delta,Rest.length);
return true;
}
/*
~Split~
This function splits an interval at a given point in time.
If the splitting instant is outside the interval, this interval or
Rest will be undefined. The other one will contain this interval.
If the spitting point is inside the interval, this interval will
end at this endpoint and Rest will begin at duration. The return
value is always true.
*/
bool RelInterval::Split(const DateTime duration, const bool closeFirst,
RelInterval& Rest){
// at this point all cases with unbounded intervals are processed
// duration left of this interval
if(duration.LessThanZero()){
// the complete interval is picked up by Rest
Rest.Equalize(this);
this->ChangeDefined(false);
return true;
}
// duration left of this interval
if(duration.IsZero() && (!closeFirst || ! IsLeftClosed())){
Rest.Equalize(this);
this->ChangeDefined(false);
return true;
}
// duration right on this interval
if(duration>length){
// Rest will not be defined
Rest.ChangeDefined(false);
return true;
}
// duration right on this interval
if(duration==length && (!IsRightClosed() || closeFirst)){
// Rest will not be defined
Rest.ChangeDefined(false);
return true;
}
// the splitting instance is inside this interval
Rest.length = this->length - duration;
Rest.ChangeRightClosed(this->IsRightClosed());
Rest.ChangeLeftClosed(!closeFirst);
this->length = duration;
this->ChangeRightClosed(closeFirst);
return true;
}
/*
~Equalize~
The ~Equalize~ function changes the value of this RelInterval to
the value of D2.
[3] O(1)
*/
void RelInterval::Equalize(const RelInterval* D2){
__TRACE__
::Attribute::operator=(*D2);
length.Equalize(&(D2->length));
state = D2->state;
}
/*
~GetLength~
This function returns a clone of the contained time value.
Note that this function
creates a new DateTime instance. The caller of this function has to make
free the memory occupied by this instance after using it.
[3] O(1)
*/
DateTime* RelInterval::GetLength() const {
__TRACE__
DateTime* res = new DateTime(durationtype);
res->Equalize(&length);
return res;
}
void RelInterval::GetLength(DateTime& result)const{
result.Equalize(&length);
}
/*
~StoreLength~
This function stored the length of this interval in the argument of this
function. The advantage of this function in contrast to the GetLength
function is that no memory is allocated by this function.
*/
void RelInterval::StoreLength(DateTime& result) const{
__TRACE__
result.Equalize(&length);
}
/*
~ToListExpr~
This function computes the list representation of this RelInterval value.
[3] O(1)
*/
ListExpr RelInterval::ToListExpr(const bool typeincluded)const{
__TRACE__
ListExpr time;
time = length.ToListExpr(false);
if(typeincluded)
return ::nl->TwoElemList(::nl->SymbolAtom("rinterval"),
::nl->ThreeElemList(
::nl->BoolAtom(IsLeftClosed()),
::nl->BoolAtom(IsRightClosed()),
time));
else
return ::nl->ThreeElemList(
::nl->BoolAtom(IsLeftClosed()),
::nl->BoolAtom(IsRightClosed()),
time);
}
ListExpr RelInterval::ToListExpr(const ListExpr typeInfo)const{
return ToListExpr(false);
}
/*
~IsLeftClosed~
This function returns true if the left endpoint of this interval is
contained in it.
[3] O(1)
*/
bool RelInterval::IsLeftClosed()const{
__TRACE__
return GetLeftClosed();
}
/*
~IsRightClosed~
This function will return true iff the interval is right closed.
[3] O(1)
*/
bool RelInterval::IsRightClosed()const{
__TRACE__
return GetRightClosed();
}
/*
~ReadFrom~
This function read the value from the argument. If the argument list don't
contains a valid RelInterval, false will be returned and the value of this
remains unchanged. In the other case the value is taken from this parameter
and true is returned.
[3] O(1)
*/
bool RelInterval::ReadFrom(const ListExpr LE, const bool typeincluded){
__TRACE__
ListExpr V;
if(typeincluded){
if(::nl->ListLength(LE)!=2){
if(DEBUG_MODE)
cerr << __POS__ << ": wrong length for typed interval" << endl;
return false;
}
if(!::nl->IsEqual(::nl->First(LE),"rinterval")){
if(DEBUG_MODE){
cerr << __POS__ << ": wrong type for interval" << endl;
cerr << "expected : rinterval , received :";
::nl->WriteListExpr(::nl->First(LE));
}
return false;
}
V = ::nl->Second(LE);
} else
V = LE;
if(::nl->ListLength(V)!=3){
if(DEBUG_MODE)
cerr << __POS__ << ": wrong length for interval" << endl;
return false;
}
if(::nl->AtomType(::nl->First(V))!=BoolType){
if(DEBUG_MODE)
cerr << __POS__ << ": wrong type in interval" << endl;
return false;
}
if(::nl->AtomType(::nl->Second(V))!=BoolType){
if(DEBUG_MODE)
cerr << __POS__ << ": wrong type in interval" << endl;
return false;
}
DateTime time(durationtype);
if(!(time.ReadFrom(::nl->Third(V),false))){
if(DEBUG_MODE)
cerr << __POS__ << ": error in reading length of interval" << endl;
return false;
}
bool LC = ::nl->BoolValue(::nl->First(V));
bool RC = ::nl->BoolValue(::nl->Second(V));
// a single instant has to be both left- and rightclosed
if( (time.IsZero()) && (!LC || !RC)){
if(DEBUG_MODE)
cerr << __POS__ << ": invalid values in interval" << endl;
return false;
}
ChangeLeftClosed(LC);
ChangeRightClosed(RC);
length.Equalize(&time);
return true;
}
/*
~Set~
This function sets this RelINterval to be finite with determined length.
If the arguments don't represent a valid RelINterval value, the return value
will be false and this instance remains unchanged. In the other case true
is returned and the value of this is taken from the arguments.
[3] O(1)
*/
bool RelInterval::Set(const DateTime* length, const bool leftClosed,
const bool rightClosed){
__TRACE__
if((length->IsZero()) && (!leftClosed || !rightClosed)) return false;
this->ChangeDefined(true);
this->ChangeLeftClosed(leftClosed);
this->ChangeRightClosed(rightClosed);
this->length.Equalize(length);
return true;
}
/*
~SetLeftClosed~
This function sets the closure of this interval at its left end.
*/
void RelInterval::SetLeftClosed(bool LC){
this->ChangeLeftClosed(LC);
}
/*
~SetRightClosed~
This function works like the function ~SetLeftClosed~ but for the
right end of this interval.
*/
void RelInterval::SetRightClosed(bool RC){
this->ChangeRightClosed(RC);
}
/*
~SetClosure~
This functions is a summarization of the ~SetLeftClosed~ and the
~SetRightClosed~ function. The effect will be the same like calling
this two functions.
*/
void RelInterval::SetClosure(bool LC,bool RC){
this->ChangeLeftClosed(LC);
this->ChangeRightClosed(RC);
}
/*
~SetLength~
This function is used to set the length of this RelINterval.
If the given parameter collides with internal settings, false
is returned.
[3] O(1)
*/
bool RelInterval::SetLength(const DateTime* T){
__TRACE__
if(T->IsZero() && (!IsLeftClosed() || !IsRightClosed())) return false;
length.Equalize(T);
return true;
}
/*
~ToString~
This function returns a string representation of this RelInterval.
[3] O(1)
*/
string RelInterval::ToString()const{
__TRACE__
if(!IsDefined()){
return "_undefined_";
}
ostringstream tmp;
tmp << (IsLeftClosed()?"[":"]");
tmp << " 0.0 , ";
tmp << length.ToString();
tmp << (IsRightClosed()?"]":"[");
return tmp.str();
}
/*
~Where~
This function returns at which procentual part of this interval T is located.
The result will be a value in $[0,1]$. In all errors cases the value -1
is returned.
[3] O(1)
*/
double RelInterval::Where(const DateTime* T)const{
__TRACE__
if(length.CompareTo(T)<0)
return -1;
if(T->LessThanZero()) return -1;
unsigned long ms1 = 86400000L*T->GetDay()+T->GetAllMilliSeconds();
unsigned long ms2 = 86400000L*length.GetDay()+length.GetAllMilliSeconds();
return (double)ms1/(double)ms2;
}
/*
~Plus~
This function adds the argument to this interval.
The 'weld point' is included to the new interval regardless
to the closure properties of the source intervals. The closure on the
left of this interval will not be changed and the closure on the
right is taken from the argument.
*/
bool RelInterval::Plus(const RelInterval* I){
ChangeRightClosed(I->IsRightClosed());
length.Add(&(I->length));
return true;
}
/*
~Copy Constructor~
*/
RelInterval::RelInterval(const RelInterval& source):
Attribute(source.IsDefined()),
length(source.length),
state(source.state) {
Equalize(&source);
}
/*
~Destructor~
Because an relative interval has only primitive members,
the destructor makes nothing.
*/
RelInterval::~RelInterval(){}
/*
~Assignment operator~
*/
RelInterval & RelInterval::operator=(const RelInterval& source){
Equalize(&source);
return *this;
}
/*
~Attribute Supporting functions~
The next functions support some operations for using this type
as an attribute within a relation.
*/
void RelInterval::Destroy(){
ChangeCanDelete(true);
}
int RelInterval::NumOfFLOBs() const{
return 0;
}
Flob* RelInterval::GetFLOB(const int i){
assert(false);
}
bool RelInterval::Adjacent(const Attribute*)const{
return false;
}
/*
~Changing flags ~
*/
void RelInterval::ChangeLeftClosed(const bool value){
if(value){
state = (state | 1);
}else{
state = (state & ~1);
}
}
void RelInterval::ChangeRightClosed(const bool value){
if(value){
state = state | 2;
}else{
state = state & ~2;
}
}
void RelInterval::ChangeDefined(const bool value){
if(value){
state = state | 4;
}else{
state = state & ~4;
}
}
void RelInterval::ChangeCanDelete(const bool value){
if(value){
state = state | 8;
}else{
state = state & ~8;
}
}
bool RelInterval::GetLeftClosed() const{
return (state & 1 )>0;
};
bool RelInterval::GetRightClosed() const{
return (state & 2) >0;
}
bool RelInterval::GetDefined() const{
return (state & 4) > 0;
}
bool RelInterval::GetCanDelete() const{
return (state & 8) > 0;
}
ostream& operator<< (ostream& os, const RelInterval I){
__TRACE__
os << I.ToString();
return os;
}
} // end of namespace periodic