Files
secondo/Algebras/Periodic/MovingRealUnit.cpp

365 lines
8.3 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
3.12 ~MovingRealUnit~
*/
#include <iostream>
#include <string>
#include "NestedList.h"
#include "PeriodicSupport.h"
#include "PeriodicTypes.h"
#include "DateTime.h"
extern NestedList* nl;
using namespace std;
using namespace datetime;
namespace periodic{
/*
~constructor~
This constructor does nothing.
*/
MovingRealUnit::MovingRealUnit(){}
/*
~constructor~
This constructor creates a MovingRealUnit with the given values for the
interval and for the map.
*/
MovingRealUnit::MovingRealUnit(MRealMap map, RelInterval interval){
Set(map,interval);
}
/*
~constructor~
This constructor creates a MovingRealUnit representing the constant value
zero. The length of the interval will also be zero.
*/
MovingRealUnit::MovingRealUnit(int dummy):interval(dummy),map(dummy){
}
/*
~Copy Constructor~
*/
MovingRealUnit::MovingRealUnit(const MovingRealUnit& source){
Equalize(&source);
}
/*
~Destrucor~
*/
MovingRealUnit::~MovingRealUnit(){}
/*
~Assignment Operator~
*/
MovingRealUnit& MovingRealUnit::operator=(const MovingRealUnit& source){
Equalize(&source);
return *this;
}
/*
~Set function~
This functions sets the values of the internal variables to defined values.
*/
void MovingRealUnit::Set(MRealMap map, RelInterval interval){
this->map.Equalize(&map);
this->interval.Equalize(&interval);
defined=true;
}
/*
~Min~ and ~Max~
Returns the minimum value and the maximum value respectively.
The unit has be be defined.
*/
double MovingRealUnit::min() const{
assert(defined);
DateTime* length = interval.GetLength();
DateTime* start = new DateTime(durationtype);
double v1;
At(start,v1);
double v2;
At(length,v2);
double v3 = v1;
DateTime pos = map.ExtremumAt();
if(pos.IsDefined()){
if(!pos.LessThanZero() && ( pos < (*length))){
At(&pos,v3);
}
}
delete length;
delete start;
return ::max(v1,::max(v2,v3));
}
double MovingRealUnit::max() const{
assert(defined);
DateTime* length = interval.GetLength();
DateTime* start = new DateTime(durationtype);
double v1;
At(start,v1);
double v2;
At(length,v2);
double v3 = v1;
DateTime pos = map.ExtremumAt();
if(pos.IsDefined()){
if(!pos.LessThanZero() && ( pos < (*length))){
At(&pos,v3);
}
}
delete length;
delete start;
return ::min(v1,::min(v2,v3));
}
/*
~GetFrom Function~
When this function is called, the value of this unit is computed to
change from value __start__ to value __end__ whithin __interval__
in a linear way. If __start__ and __end__ differs, the length of the
interval must be greater than zero. For equal value also length zero
is allowed. If the interval does not fullfills this conditions, the
value of this unit remains unchanged. The return value indicates
the success of the call of this function.
*/
bool MovingRealUnit::GetFrom(double start,
double end,
RelInterval interval){
// check the preconditions
DateTime length(durationtype);
interval.StoreLength(length);
if(length.LessThanZero())
return false;
if(length.IsZero()){
if(start!=end)
return false;
if(!interval.IsRightClosed() || !interval.IsLeftClosed())
return false;
}
// special case, no change while interval
if(start==end){
map.Set(0,0,start,false);
this->interval.Equalize(&interval);
defined = true;
return true;
}
double b = (end-start) / (length.ToDouble());
map.Set(0,b,start,false);
defined = true;
this->interval.Equalize(&interval);
return true;
}
/*
~At~
This function computes the value of this unit for a given instant.
This unit must be defined at this instant. This should be checked
by calling the ~IsDefinedAt~ function before.
*/
void MovingRealUnit::At(const DateTime* duration,double& res) const {
assert(interval.Contains(duration,true));
assert(defined);
assert(map.IsDefinedAt(duration));
res = map.At(duration);
}
/*
~IsDefinedAt~
This function cvhecks whether this unit is defined at the given point in time.
*/
bool MovingRealUnit::IsDefinedAt(const DateTime* duration) const{
return interval.Contains(duration) &&
defined &&
map.IsDefinedAt(duration);
}
/*
~ToListExpr~
This function computes the representation of this unit in nested list format.
*/
ListExpr MovingRealUnit::ToListExpr()const{
if(!defined)
return ::nl->TwoElemList(::nl->SymbolAtom("linear"),
::nl->TwoElemList(
interval.ToListExpr(false),
::nl->SymbolAtom("undefined")));
return ::nl->TwoElemList(::nl->SymbolAtom("linear"),
::nl->TwoElemList(
interval.ToListExpr(false),
map.ToListExpr()));
}
/*
~ReadFrom~
If the argument contains a valid representation of a moving real unit,
the value of this unit is changed to the value from the argument. Otherwise,
this unit remains unchanged.
*/
bool MovingRealUnit::ReadFrom(ListExpr le){
if(::nl->ListLength(le)!=2)
return false;
if(::nl->AtomType(::nl->First(le))!=SymbolType)
return false;
if(::nl->SymbolValue(::nl->First(le))!="linear")
return false;
ListExpr v = ::nl->Second(le);
if(::nl->ListLength(v)!=2)
return false;
RelInterval tmpinterval;
if(!tmpinterval.ReadFrom(::nl->First(v),false))
return false;
if(!map.ReadFrom(::nl->Second(v)))
return false;
interval.Equalize(&tmpinterval);
defined=true;
return true;
}
/*
~CanSummarized~
This function checkes whether two moving real units can summarized. This means, the
intervals are adjacent and the coefficients are choosen that the functions are equal.
*/
bool MovingRealUnit::CanSummarized(const MovingRealUnit* MRU) const{
if(!interval.CanAppended(&(MRU->interval)))
return false;
DateTime * DT = interval.GetLength();
double d = DT->ToDouble();
delete DT;
DT = NULL;
return map.EqualsTo(MRU->map,d);
}
/*
~Initial~
This function returns the value of this unit at the start of its interval.
*/
bool MovingRealUnit::Initial(double& res)const{
if(!map.IsDefinedAt(0.0)){
return false;
} else {
res = (map.At(0.0));
return true;
}
}
/*
~Final~
This function returns the value of this unit at the end of its interval.
*/
bool MovingRealUnit::Final(double& res)const{
DateTime* end = interval.GetLength();
if(!map.IsDefinedAt(end))
return false;
else
res = (map.At(end));
delete end;
end = NULL;
return true;
}
/*
~Split~
This function splits this unit into 2 ones. The splitting point is
given by the argument __duration__. The left part will be the
__this__ objects, the right part will be stored in the argument __right__.
The affiliation of the splitting point is ruled by the parameter __toLeft__.
The function will return __true__ if this unit can splittet, i.e. the
splitting point is contained in this unit. In the other case, this unit
left as it is, the __right__ parameter is set to be undefined, and the
return value will be __false__.
*/
bool MovingRealUnit::Split(const DateTime duration,
const bool toLeft,
MovingRealUnit& unit){
// case duration not contained
if(!interval.Contains(&duration)){
unit.defined=false;
return false;
}
// case left will be empty
if(duration.IsZero() && !toLeft){
unit.defined=false;
return false;
}
// all ok, split this unit
if(!interval.Split(duration,toLeft,unit.interval)){
unit.defined=true;
return false;
}
unit.defined=true;
double d = duration.ToDouble();
unit.map.Set(map.a,map.b-2*d, d*d-d*map.b+map.c,map.root);
return true;
}
/*
~SetDefined~
Using this function, we can set the defined flag for this instance.
Use carefully this function with an value of true. The internal stored
values are nmot checked to hold meaningful values, just the flag is
changed.
*/
void MovingRealUnit::SetDefined(const bool defined){
this->defined=defined;
}
void MovingRealUnit::Equalize(const MovingRealUnit* source){
interval.Equalize(&(source->interval));
map.Equalize(&(source->map));
defined = source->defined;
}
} // end of namespace periodic