Files
2026-01-23 17:03:45 +08:00

661 lines
15 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004-2009, University in Hagen, Faculty of Mathematics
and 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
----
1 MReals.h
*/
#pragma once
#include "AlmostEqual.h"
#include "MFsObjects.h"
#include "IReals.h"
namespace ColumnMovingAlgebra
{
/*
1.1 Forward Declaration of ~RealUnit~
~RealUnit~ represents a moving real unit
*/
class RealUnit;
/*
1.1 Declaration of ~MReals~
~MReals~ represents a moving real
*/
typedef MFsObjects<RealUnit> MReals;
/*
1.2 Declaration of class ~RealUnit~
*/
class RealUnit
{
public:
typedef double Value;
typedef IReals Instants;
typedef CcReal Attr;
typedef temporalalgebra::RReal RAttr;
typedef temporalalgebra::MReal MAttr;
/*
constructors
*/
RealUnit() = default;
RealUnit(temporalalgebra::MReal mreal, int unit);
RealUnit(Interval interval, double a, double b, double c, bool r);
/*
~interval~ returns the definition interval of this unit
*/
Interval interval() const;
/*
~minimum~ returns the minimum value of the mapping function during the
definition interval
*/
Value minimum() const;
/*
~maximum~ returns the maximum value of the mapping function during the
definition interval
*/
Value maximum() const;
/*
~appendTo~ adds this unit to a moving object in the temporal algebra
*/
void appendTo(temporalalgebra::MReal & mreal);
/*
~compareValue~ compares this unit
*/
int compareValue(const RealUnit & realUnit);
/*
~atInstant~ returns an intime for ~instant~
*/
temporalalgebra::IReal atInstant(Instant instant);
/*
~restrictToInterval~ restricts the unit to ~unitInterval~
*/
RealUnit restrictToInterval(Interval interval);
/*
~passes~ returns true, iff this this unit has the same value
*/
bool passes(CcReal ccReal);
/*
or iff the value is in the specified range
*/
bool passes(temporalalgebra::RReal rReal);
/*
~at~ adds this unit to ~result~ iff it has the same value as specified
*/
void at(CcReal ccReal, MReals & result);
/*
of iff its value is in the specified range
*/
void at(temporalalgebra::RReal rReal, MReals & result);
/*
~undefinedAttr~ returns an undefined attribute
*/
static CcReal undefinedAttr();
/*
~compare~
returns -1 if ~value~ smaller ~attr~,
returns 0 if ~value~ equal ~attr~,
returns 1 if ~value~ greater ~attr~
*/
static int compare(Value value, Attr attr);
/*
~random~ returns a unit with the specified interval and a random value
*/
static RealUnit random(Interval interval);
private:
/*
~mInterval~ represents the definition interval of this unit
*/
Interval m_Interval;
/*
iff ~mR~ is true, the mapping function f(t) of this unit is
~mA~ t t + ~mB~ t + ~mC~.
Otherwise the mapping function of this unit is
sqrt(~mA~ t t + ~mB~ t + ~mC~).
~mMinimum~ and ~mMaximum~ represent the minimum and maximum
of the mapping function on the definition interval of this unit.
as minimum and maximum value might be on the boundaries of the
definition interval and the definition interval is not necessarily left and
right closed, we also need ~mMinIncluded~ and ~mMaxIncluded~ to determine,
whether the mapping function ever has the value ~mMinimum~ and ~mMaximum~
on the definition interval or only converges
*/
double m_A, m_B, m_C, m_Minimum, m_Maximum;
bool m_R, m_MinIncluded, m_MaxIncluded;
/*
~calculateExtrema~
sets the values ~mMinimum~, ~mMaximum~, ~mMinIncluded~ and ~mMaxIncluded~
*/
void calculateExtrema();
/*
~timeToDouble~ converts ~t~ to double
*/
double timeToDouble(int64_t t);
/*
~doubleToTime~ converts ~x~ to time value
*/
int64_t doubleToTime(double x);
/*
~solveLinear~ solves a linear mapping function
*/
void solveLinear(double y, int64_t & t);
/*
~solveQuadratic~ solves a quadratic mapping function. returns the
number of found solutions.
*/
int solveQuadratic(double y, int64_t & t0, int64_t & t1);
};
/*
1.2 Implementation of class ~RealUnit~
constructors
*/
inline RealUnit::RealUnit(temporalalgebra::MReal mreal, int unit)
{
temporalalgebra::UReal u;
mreal.Get(unit, u);
m_Interval = u.timeInterval;
m_A = u.a;
m_B = u.b;
m_C = u.c;
m_R = u.r;
calculateExtrema();
}
inline RealUnit::RealUnit(Interval interval, double a,
double b, double c, bool r) :
m_Interval(interval),
m_A(a),
m_B(b),
m_C(c),
m_R(r)
{
calculateExtrema();
}
/*
~minimum~ returns the minimum value of the mapping function during the
definition interval
*/
inline RealUnit::Value RealUnit::minimum() const
{
return m_Minimum;
}
/*
~maximum~ returns the maximum value of the mapping function during the
definition interval
*/
inline RealUnit::Value RealUnit::maximum() const
{
return m_Maximum;
}
/*
~interval~ returns the definition interval of this unit
*/
inline Interval RealUnit::interval() const
{
return m_Interval;
}
/*
~appendTo~ adds this unit to a moving object in the temporal algebra
*/
inline void RealUnit::appendTo(
temporalalgebra::MReal & mreal)
{
mreal.Add(temporalalgebra::UReal(m_Interval.convert(), m_A, m_B, m_C, m_R));
}
/*
~compareValue~ compares this unit
*/
inline int RealUnit::compareValue(const RealUnit & realUnit)
{
double dDiff;
dDiff = m_A - realUnit.m_A;
if (dDiff != 0.0)
return dDiff < 0.0 ? -1 : 1;
dDiff = m_B - realUnit.m_B;
if (dDiff != 0.0)
return dDiff < 0.0 ? -1 : 1;
dDiff = m_C - realUnit.m_C;
if (dDiff != 0.0)
return dDiff < 0.0 ? -1 : 1;
if (m_R != realUnit.m_R)
return m_R ? -1 : 1;
return 0;
}
/*
~atInstant~ returns an intime for ~instant~
*/
inline temporalalgebra::IReal RealUnit::atInstant(Instant instant)
{
double x = timeToDouble(instant.millisecondsToNull());
double result = m_A * x * x + m_B * x + m_C;
if (m_R) {
if (result >= 0.0) {
result = sqrt(result);
} else {
check(AlmostEqual(result, 0.0), "result is imaginary number");
result = 0.0;
}
}
return temporalalgebra::IReal(instant, CcReal(true, result));
}
/*
~restrictToInterval~ restricts the unit to ~unitInterval~
*/
inline RealUnit RealUnit::restrictToInterval(Interval newInterval)
{
double x = timeToDouble(newInterval.s);
double uc = m_A * x * x + m_B * x + m_C;
if (newInterval.s == newInterval.e) {
return RealUnit(newInterval, 0.0, 0.0, uc, m_R);
} else {
double ub = 2 * m_A * x + m_B;
return RealUnit(newInterval, m_A, ub, uc, m_R);
}
}
/*
~passes~ returns true, iff this this unit has the same value
*/
inline bool RealUnit::passes(CcReal ccReal)
{
double y = ccReal.GetValue();
if (y < m_Minimum || (y == m_Minimum && !m_MinIncluded))
return false;
if (y > m_Maximum || (y == m_Maximum && !m_MaxIncluded))
return false;
return true;
}
/*
or iff the value is in the specified range
*/
inline bool RealUnit::passes(temporalalgebra::RReal rReal)
{
for (int index = 0; index < rReal.GetNoComponents(); index++) {
temporalalgebra::Interval<CcReal> ri;
rReal.Get(index, ri);
double ys = ri.end.GetValue(), ye = ri.start.GetValue();
bool fis = ri.rc, fie = ri.lc;
if (ys < m_Minimum || (ys == m_Minimum && (!m_MinIncluded || !fis)))
continue;
if (ye > m_Maximum || (ye == m_Maximum && (!m_MaxIncluded || !fie)))
continue;
return true;
}
return false;
}
/*
~at~ adds this unit to ~result~ iff it has the same value as specified
*/
inline void RealUnit::at(CcReal ccReal, MReals & result)
{
if (passes(ccReal)) {
std::list<Interval> intersections;
double y = ccReal.GetValue();
if (AlmostEqual(m_A, 0.0)) {
if (AlmostEqual(m_B, 0.0)) {
result.addUnit(*this);
return;
}
int64_t t;
solveLinear(y, t);
intersections.push_back(Interval(t, t, true, true));
} else {
int64_t t0, t1;
int count = solveQuadratic(y, t0, t1);
if (count >= 1)
intersections.push_back(Interval(t0, t0, true, true));
if (count >= 2)
intersections.push_back(Interval(t1, t1, true, true));
}
for (auto & i : intersections)
if (i.intersects(m_Interval)) {
RealUnit u(i, 0.0, 0.0, y, false);
result.addUnit(u);
}
}
}
/*
of iff its value is in the specified range
*/
inline void RealUnit::at(temporalalgebra::RReal rReal, MReals & result)
{
temporalalgebra::Interval<CcReal> ri;
struct IntervalCompare {
bool operator() (const Interval &a, const Interval &b) const {
return a.s < b.s;
}
};
std::set<Interval, IntervalCompare> intersections;
if (AlmostEqual(m_A, 0.0)) {
if (AlmostEqual(m_B, 0.0)) {
for (int index = 0; index < rReal.GetNoComponents(); index++) {
rReal.Get(index, ri);
double ys = ri.start.GetValue(), ye = ri.end.GetValue();
if ( ye >= m_Minimum &&
(ye != m_Minimum || (m_MinIncluded && ri.rc)) &&
ys <= m_Maximum &&
(ys != m_Maximum || (m_MaxIncluded && ri.lc)))
{
result.addUnit(*this);
return;
}
}
return;
}
for (int index = 0; index < rReal.GetNoComponents(); index++) {
rReal.Get(index, ri);
double ys = ri.start.GetValue(), ye = ri.end.GetValue();
int64_t t0, t1;
solveLinear(ys, t0);
solveLinear(ye, t1);
if (t0 < t1)
intersections.insert(Interval(t0, t1, ri.lc, ri.rc));
else
intersections.insert(Interval(t1, t0, ri.rc, ri.lc));
}
} else {
for (int index = 0; index < rReal.GetNoComponents(); index++) {
rReal.Get(index, ri);
double ys = ri.start.GetValue(), ye = ri.end.GetValue();
int64_t t00=0, t01=0, t10=0, t11=0;
int count0 = solveQuadratic(ys, t00, t01);
int count1 = solveQuadratic(ye, t10, t11);
bool i0 = ri.lc, i1 = ri.rc;
if (count1 > count0) {
std::swap(count0, count1);
std::swap(t00, t10);
std::swap(t01, t11);
std::swap(i0, i1);
}
if (count0 == 2) {
if (count1 == 2) {
if (t00 > t10) {
std::swap(t00, t10);
std::swap(t01, t11);
std::swap(i0, i1);
}
intersections.insert(Interval(t00, t10, i0, i1));
intersections.insert(Interval(t11, t01, i1, i0));
} else if (count1 == 1) {
if (i1) {
intersections.insert(Interval(t00, t01, i0, i0));
} else {
intersections.insert(Interval(t00, t10, i0, false));
intersections.insert(Interval(t10, t01, false, i0));
}
} else {
intersections.insert(Interval(t00, t01, i0 || i1, i0 || i1));
}
} else if (count0 == 1) {
intersections.insert(Interval(t00, t00, i0 || i1, i0 || i1));
}
}
}
for (auto i : intersections)
if (i.intersects(m_Interval)) {
RealUnit u = restrictToInterval(i.intersection(m_Interval));
result.addUnit(u);
}
}
/*
~calculateExtrema~
sets the values ~mMinimum~, ~mMaximum~, ~mMinIncluded~ and ~mMaxIncluded~
*/
inline void RealUnit::calculateExtrema()
{
m_Minimum = m_Maximum = m_C;
m_MinIncluded = m_MaxIncluded = m_Interval.lc;
double xEnd = timeToDouble(m_Interval.e);
double y = m_A * xEnd * xEnd + m_B * xEnd + m_C;
if (y < m_Minimum || (y == m_Minimum && !m_MinIncluded)) {
m_Minimum = y;
m_MinIncluded = m_Interval.rc;
}
if (y > m_Maximum || (y == m_Maximum && !m_MaxIncluded)) {
m_Maximum = y;
m_MaxIncluded = m_Interval.rc;
}
if (!AlmostEqual(m_A, 0.0)) {
double x = -m_B / (2.0 * m_A);
if (0.0 < x && x < xEnd) {
double y = m_A * x * x + m_B * x + m_C;
if (y < m_Minimum || (y == m_Minimum && !m_MinIncluded)) {
m_Minimum = y;
m_MinIncluded = true;
}
if (y > m_Maximum || (y == m_Maximum && !m_MaxIncluded)) {
m_Maximum = y;
m_MaxIncluded = true;
}
}
}
if (m_R) {
if (m_Minimum >= 0.0) {
m_Minimum = sqrt(m_Minimum);
} else {
check(AlmostEqual(m_Minimum, 0.0), "minimum is imaginary number");
m_Minimum = 0.0;
}
if (m_Maximum >= 0.0) {
m_Maximum = sqrt(m_Maximum);
} else {
check(AlmostEqual(m_Maximum, 0.0), "maximum is imaginary number");
m_Maximum = 0.0;
}
}
}
/*
~timeToDouble~ converts ~t~ to double
*/
inline double RealUnit::timeToDouble(int64_t t)
{
return static_cast<double>(t - m_Interval.s) /
static_cast<double>(MILLISECONDS);
}
/*
~doubleToTime~ converts ~x~ to time value
*/
inline int64_t RealUnit::doubleToTime(double x)
{
return static_cast<int64_t>(x * static_cast<double>(MILLISECONDS)) +
m_Interval.s;
}
/*
~solveLinear~ solves a linear mapping function
*/
inline void RealUnit::solveLinear(double y, int64_t & t)
{
if (m_R)
y *= y;
t = doubleToTime((y - m_C) / m_B);
}
/*
~solveQuadratic~ solves a quadratic mapping function. returns the
number of found solutions.
*/
inline int RealUnit::solveQuadratic(double y, int64_t & t0, int64_t & t1)
{
if (m_R)
y *= y;
double root = m_B * m_B - 4 * m_A * (m_C - y);
if (root < 0.0)
return 0;
root = sqrt(root);
t0 = doubleToTime((-m_B - root) / (2 * m_A));
if (root == 0.0)
return 1;
t1 = doubleToTime((-m_B + root) / (2 * m_A));
return t0 != t1 ? 2 : 1;
}
/*
~undefinedAttr~ returns an undefined attribute
*/
inline CcReal RealUnit::undefinedAttr()
{
CcReal r(1.0);
r.SetDefined(false);
return r;
}
/*
~compare~
returns -1 if ~value~ smaller ~attr~,
returns 0 if ~value~ equal ~attr~,
returns 1 if ~value~ greater ~attr~
*/
inline int RealUnit::compare(Value value, Attr attr)
{
double b = attr.GetValue();
return value < b ? -1 : (value == b ? 0 : 1);
}
/*
~random~ returns a unit with the specified interval and a random value
*/
inline RealUnit RealUnit::random(Interval interval)
{
return RealUnit(interval, static_cast<double>(rand()) / RAND_MAX,
static_cast<double>(rand()) / RAND_MAX,
static_cast<double>(rand()) / RAND_MAX,
(rand() % 2) == 1);
}
}