diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..617341e --- /dev/null +++ b/License.txt @@ -0,0 +1 @@ +This software is public domain software (PDS). diff --git a/Ndrr1D.cpp b/Ndrr1D.cpp new file mode 100644 index 0000000..66e8691 --- /dev/null +++ b/Ndrr1D.cpp @@ -0,0 +1,1750 @@ +///////////////////////////////////////////////////////////////////////////// +// Ndrr1D.cpp --- The one-dimensional Numeric Domains/Ranges Resolver +// See file "ReadMe.txt" and "License.txt". +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +namespace Ndrr1D +{ + +//////////////////////////////////////////////////////////////////////////// +// public functions + +bool IsPositiveNumber(const DRR1D_VALUE& value) +{ + return value > 0; +} + +bool IsNegativeNumber(const DRR1D_VALUE& value) +{ + return value < 0; +} + +bool IsNaturalNumber(const DRR1D_VALUE& value) +{ + #ifdef DRR1D_USES_PMPNUMBER + return value >= 0 && (value % 1).is_zero(); + #else + return value >= 0 && std::fmod(value, 1) == 0; + #endif +} + +bool IsRegularNumber(const DRR1D_VALUE& value) +{ + #ifdef DRR1D_USES_PMPNUMBER + return (value % 1).is_zero(); + #else + return std::fmod(value, 1) == 0; + #endif +} + +bool IsEvenNumber(const DRR1D_VALUE& value) +{ + #ifdef DRR1D_USES_PMPNUMBER + return (value % 2).is_zero(); + #else + return std::fmod(value, 2) == 0; + #endif +} + +bool IsOddNumber(const DRR1D_VALUE& value) +{ + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v = value % 2; + return v == 1 || v == -1; + #else + DRR1D_VALUE v = std::fmod(value, 2); + return v == 1 || v == -1; + #endif +} + +bool IsPrimeNumber(const DRR1D_VALUE& value) +{ + if (value < 2) + return false; + + if (value == 2) + return true; + + #ifdef DRR1D_USES_PMPNUMBER + if ((value % 2).is_zero()) + return false; + + for (DRR1D_VALUE i = 3; i < value; i += 2) + { + if ((value % i).is_zero()) + return false; + } + #else + if (std::fmod(value, 2) == 0) + return false; + + for (int i = 3; i < value; i += 2) + { + if (std::fmod(value, i) == 0) + return false; + } + #endif + + return true; +} + +DRR1D_VALUE GauseModFloor(const DRR1D_VALUE& d, const DRR1D_VALUE& mod) +{ + #ifdef DRR1D_USES_PMPNUMBER + if (d >= 0) + return pmp::floor(d / mod) * mod; + else + return -pmp::ceil(-d / mod) * mod; + #else + if (d >= 0) + return std::floor(d / mod) * mod; + else + return -std::ceil(-d / mod) * mod; + #endif +} + +DRR1D_VALUE GauseModCeil(const DRR1D_VALUE& d, const DRR1D_VALUE& mod) +{ + #ifdef DRR1D_USES_PMPNUMBER + if (d >= 0) + return pmp::ceil(d / mod) * mod; + else + return -pmp::floor(-d / mod) * mod; + #else + if (d >= 0) + return std::ceil(d / mod) * mod; + else + return -std::floor(-d / mod) * mod; + #endif +} + +//////////////////////////////////////////////////////////////////////////// +// Range + +/*static*/ Range *Range::Intersect(const Range *r1, const Range *r2) +{ + if (r1->empty() || r2->empty()) + return NULL; + + bool has_min = false; + DRR1D_VALUE *pnLBound = NULL; + if (r1->m_pnLBound && r2->m_pnLBound) + { + if (*r1->m_pnLBound < *r2->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r2->m_pnLBound); + has_min = r2->m_has_min; + } + else if (*r1->m_pnLBound > *r2->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r1->m_pnLBound); + has_min = r1->m_has_min; + } + else + { + pnLBound = new DRR1D_VALUE(*r1->m_pnLBound); + has_min = r1->m_has_min && r2->m_has_min; + } + } + else if (r1->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r1->m_pnLBound); + has_min = r1->m_has_min; + } + else if (r2->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r2->m_pnLBound); + has_min = r2->m_has_min; + } + + bool has_max = false; + DRR1D_VALUE *pnUBound = NULL; + if (r1->m_pnUBound && r2->m_pnUBound) + { + if (*r1->m_pnUBound < *r2->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r1->m_pnUBound); + has_max = r1->m_has_max; + } + else if (*r1->m_pnUBound > *r2->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r2->m_pnUBound); + has_max = r2->m_has_max; + } + else + { + pnUBound = new DRR1D_VALUE(*r2->m_pnUBound); + has_max = r1->m_has_max && r2->m_has_max; + } + } + else if (r1->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r1->m_pnUBound); + has_max = r1->m_has_max; + } + else if (r2->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r2->m_pnUBound); + has_max = r2->m_has_max; + } + + Range *r = new Range; + r->m_has_min = has_min; + r->m_has_max = has_max; + r->m_pnLBound = pnLBound; + r->m_pnUBound = pnUBound; + if (r->empty()) + { + delete r; + r = NULL; + } + return r; +} + +bool Range::Includes(const Range& range) const +{ + if (range.empty()) + return true; + + if (m_pnLBound && range.m_pnLBound) + { + if (*m_pnLBound > *range.m_pnLBound) + return false; + if (*m_pnLBound == *range.m_pnLBound && m_has_min < range.m_has_min) + return false; + } + else if (m_pnLBound) + { + return false; + } + + if (m_pnUBound && range.m_pnUBound) + { + if (*m_pnUBound < *range.m_pnUBound) + return false; + if (*m_pnUBound == *range.m_pnUBound && m_has_max < range.m_has_max) + return false; + } + else if (m_pnUBound) + { + return false; + } + + return true; +} + +bool Range::Contains(DRR1D_VALUE value) const +{ + if (m_pnLBound) + { + if (*m_pnLBound > value) + return false; + if (*m_pnLBound == value && !m_has_min) + return false; + } + if (m_pnUBound) + { + if (*m_pnUBound < value) + return false; + if (*m_pnUBound == value && !m_has_max) + return false; + } + return true; +} + +bool Range::empty() const +{ + if (m_pnLBound && m_pnUBound) + { + if (*m_pnLBound > *m_pnUBound) + return true; + if (*m_pnLBound == *m_pnUBound && (!m_has_min || !m_has_max)) + return true; + } + return false; +} + +void Range::clear() +{ + delete m_pnLBound; + m_pnLBound = new DRR1D_VALUE(1); + delete m_pnUBound; + m_pnUBound = new DRR1D_VALUE(0); +} + +void Range::Intersect(const Range& r) +{ + Range *range = Range::Intersect(this, &r); + if (range) + { + *this = *range; + delete range; + } + else + clear(); +} + +//////////////////////////////////////////////////////////////////////////// +// Ranges + +/*static*/ Ranges *Ranges::Optimize(const Ranges *ranges) +{ + Ranges *pRanges = new Ranges(*ranges); + + // remove empty ranges +retry1: + std::size_t siz = pRanges->size(); + for (std::size_t i = 0; i < siz; ++i) + { + if ((*pRanges)[i]->empty()) + { + pRanges->erase(pRanges->begin() + i); + goto retry1; + } + } + +retry2: + siz = pRanges->size(); + for (std::size_t i = 0; i < siz - 1; ++i) + { + for (std::size_t j = i + 1; j < siz; ++j) + { + Range *range = Range::Intersect((*pRanges)[i].get(), (*pRanges)[j].get()); + if (range) + { + delete range; + + bool has_min = false, has_max = false;; + DRR1D_VALUE *pnLBound = NULL, *pnUBound = NULL; + + shared_ptr r1 = (*pRanges)[i]; + shared_ptr r2 = (*pRanges)[j]; + if (r1->m_pnLBound && r2->m_pnLBound) + { + if (*r1->m_pnLBound < *r2->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r1->m_pnLBound); + has_min = r1->m_has_min; + } + else if (*r1->m_pnLBound > *r2->m_pnLBound) + { + pnLBound = new DRR1D_VALUE(*r2->m_pnLBound); + has_min = r2->m_has_min; + } + else + { + pnLBound = new DRR1D_VALUE(*r2->m_pnLBound); + has_min = r1->m_has_min || r2->m_has_min; + } + } + if (r1->m_pnUBound && r2->m_pnUBound) + { + if (*r1->m_pnUBound < *r2->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r2->m_pnUBound); + has_max = r2->m_has_max; + } + else if (*r1->m_pnUBound > *r2->m_pnUBound) + { + pnUBound = new DRR1D_VALUE(*r1->m_pnUBound); + has_max = r1->m_has_max; + } + else + { + pnUBound = new DRR1D_VALUE(*r2->m_pnUBound); + has_max = r1->m_has_max || r2->m_has_max; + } + } + + Range *r = new Range; + r->m_has_min = has_min; + r->m_has_max = has_max; + r->m_pnLBound = pnLBound; + r->m_pnUBound = pnUBound; + (*pRanges)[i] = shared_ptr(r); + pRanges->erase(pRanges->begin() + j); + goto retry2; + } + else if ( + (*pRanges)[i]->m_pnUBound && + (*pRanges)[j]->m_pnLBound && + *(*pRanges)[i]->m_pnUBound == *(*pRanges)[j]->m_pnLBound && + ((*pRanges)[i]->m_has_max || (*pRanges)[j]->m_has_min)) + { + Range *r = new Range; + r->m_has_min = (*pRanges)[i]->m_has_min; + r->m_has_max = (*pRanges)[j]->m_has_max; + if ((*pRanges)[i]->m_pnLBound) + r->m_pnLBound = new DRR1D_VALUE(*(*pRanges)[i]->m_pnLBound); + if ((*pRanges)[j]->m_pnUBound) + r->m_pnUBound = new DRR1D_VALUE(*(*pRanges)[j]->m_pnUBound); + (*pRanges)[i] = shared_ptr(r); + pRanges->erase(pRanges->begin() + j); + goto retry2; + } + else if ( + (*pRanges)[j]->m_pnUBound && + (*pRanges)[i]->m_pnLBound && + *(*pRanges)[j]->m_pnUBound == *(*pRanges)[i]->m_pnLBound && + ((*pRanges)[j]->m_has_max || (*pRanges)[i]->m_has_min)) + { + Range *r = new Range; + r->m_has_min = (*pRanges)[j]->m_has_min; + r->m_has_max = (*pRanges)[i]->m_has_max; + if ((*pRanges)[j]->m_pnLBound) + r->m_pnLBound = new DRR1D_VALUE(*(*pRanges)[j]->m_pnLBound); + if ((*pRanges)[i]->m_pnUBound) + r->m_pnUBound = new DRR1D_VALUE(*(*pRanges)[i]->m_pnUBound); + (*pRanges)[i] = shared_ptr(r); + pRanges->erase(pRanges->begin() + j); + goto retry2; + } + } + } + + // check existence of the whole range + for (std::size_t i = 0; i < siz; ++i) + { + if ((*pRanges)[i]->m_pnLBound == NULL && + (*pRanges)[i]->m_pnUBound == NULL) + { + Range *r = Range::Whole(); + pRanges->clear(); + pRanges->push_back(shared_ptr(r)); + break; + } + } + + return pRanges; +} + +/*static*/ Ranges *Ranges::Intersect(const Ranges *ranges, const Range *range) +{ + Ranges *pRanges = new Ranges(); + std::size_t i, siz = ranges->size(); + for (i = 0; i < siz; ++i) + { + Range *r = Range::Intersect((*ranges)[i].get(), range); + if (r) + pRanges->push_back(shared_ptr(r)); + } + return pRanges; +} + +/*static*/ Ranges *Ranges::Intersect(const Ranges *r1, const Ranges *r2) +{ + Ranges *pRanges = new Ranges(); + std::size_t i, siz1 = r1->size(); + for (i = 0; i < siz1; ++i) + { + Ranges *r = Ranges::Intersect(r2, ((*r1)[i]).get()); + if (r->size()) + pRanges->insert(pRanges->end(), r->begin(), r->end()); + delete r; + } + return pRanges; +} + +bool Ranges::Includes(const Ranges& ranges) const +{ + std::size_t i, j, siz1 = size(), siz2 = ranges.size(); + for (j = 0; j < siz2; ++j) + { + bool flag = false; + for (i = 0; i < siz1; ++i) + { + if ((*this)[i]->Includes(*ranges[j].get())) + { + flag = true; + break; + } + } + if (!flag) + return false; + } + return true; +} + +bool Ranges::Contains(DRR1D_VALUE value) const +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if ((*this)[i]->Contains(value)) + return true; + } + return false; +} + +void Ranges::Optimize() +{ + Ranges *ranges = Ranges::Optimize(this); + *this = *ranges; + delete ranges; +} + +/*static*/ Ranges *Ranges::Union(const Ranges *r1, const Ranges *r2) +{ + Ranges *r = new Ranges(*r1); + r->insert(r->end(), r2->begin(), r2->end()); + Ranges *ranges = Ranges::Optimize(r); + delete r; + return ranges; +} + +/*static*/ Ranges *Ranges::Whole() +{ + Ranges *ranges = new Ranges; + Range *r = Range::Whole(); + ranges->push_back(shared_ptr(r)); + return ranges; +} + +void Ranges::Union(const Ranges& ranges) +{ + Ranges *r = Ranges::Union(this, &ranges); + *this = *r; + delete r; +} + +void Ranges::Intersect(const Range& range) +{ + Ranges *ranges = Ranges::Intersect(this, &range); + *this = *ranges; + delete ranges; +} + +void Ranges::Intersect(const Ranges& ranges) +{ + Ranges *r = Ranges::Intersect(this, &ranges); + *this = *r; + delete r; +} + +bool Ranges::empty() const +{ + if (size() == 0) + return true; + + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if (!((*this)[i])->empty()) + return false; + } + return true; +} + +DRR1D_VALUE *Ranges::GetLBound(bool& has_min) const +{ + std::size_t i, siz = size(); + has_min = false; + if (siz == 0) + return NULL; + for (i = 0; i < siz; ++i) + { + if (((*this)[i])->m_pnLBound == NULL) + return NULL; + } + DRR1D_VALUE *value = ((*this)[0])->m_pnLBound; + has_min = ((*this)[0])->m_has_min; + for (i = 1; i < siz; ++i) + { + if (*value > *((*this)[i])->m_pnLBound) + { + value = ((*this)[i])->m_pnLBound; + has_min = ((*this)[i])->m_has_min; + } + else if (*value == *((*this)[i])->m_pnLBound) + { + if (((*this)[i])->m_has_min) + has_min = true; + } + } + return value; +} + +DRR1D_VALUE *Ranges::GetUBound(bool& has_max) const +{ + std::size_t i, siz = size(); + has_max = false; + if (siz == 0) + { + return NULL; + } + for (i = 0; i < siz; ++i) + { + if (((*this)[i])->m_pnUBound == NULL) + { + return NULL; + } + } + DRR1D_VALUE *value = ((*this)[0])->m_pnUBound; + has_max = ((*this)[0])->m_has_max; + for (i = 1; i < siz; ++i) + { + if (*value < *((*this)[i])->m_pnUBound) + { + value = ((*this)[i])->m_pnUBound; + has_max = ((*this)[i])->m_has_max; + } + else if (*value == *((*this)[i])->m_pnUBound) + { + if (((*this)[i])->m_has_max) + has_max = true; + } + } + return value; +} + +//////////////////////////////////////////////////////////////////////////// +// Domain + +bool Domain::Contains(const DRR1D_VALUE& value) const +{ + if (!m_ranges->Contains(value)) + return false; + + std::size_t i, siz = m_afnContains.size(); + for (i = 0; i < siz; ++i) + { + if (!(*m_afnContains[i])(value)) + return false; + } + return true; +} + +bool Domain::Includes(Domain::Type type) const +{ + switch (m_dom_type) + { + case Domain::EMPTY: + return false; + + case Domain::SEISUU: + switch (type) + { + case Domain::SEISUU: + case Domain::GUUSUU: + case Domain::KISUU: + case Domain::SOSUU: + return true; + + case Domain::JISSUU: + return false; + + default: + assert(0); + } + break; + + case Domain::GUUSUU: + switch (type) + { + case Domain::SEISUU: + case Domain::KISUU: + case Domain::JISSUU: + case Domain::SOSUU: + return false; + + case Domain::GUUSUU: + return true; + + default: + assert(0); + } + break; + + case Domain::KISUU: + switch (type) + { + case Domain::SEISUU: + case Domain::GUUSUU: + case Domain::JISSUU: + case Domain::SOSUU: + return false; + + case Domain::KISUU: + return true; + + default: + assert(0); + } + break; + + case Domain::JISSUU: + return true; + + case Domain::SOSUU: + switch (type) + { + case Domain::SEISUU: + case Domain::GUUSUU: + case Domain::KISUU: + case Domain::JISSUU: + return false; + + case Domain::SOSUU: + return true; + + default: + assert(0); + } + break; + + default: + assert(0); + } + return false; +} + +bool Domain::Includes(const Domain& domain) const +{ + if (domain.m_dom_type == Domain::EMPTY) + return true; + + if (!m_ranges->Includes(*domain.m_ranges.get())) + return false; + + return Includes(domain.m_dom_type); +} + +bool Domain::empty() const +{ + return m_dom_type == Domain::EMPTY || m_ranges->empty(); +} + +void Domain::RestrictTo(Domain::Type type) +{ + switch (type) + { + case Domain::EMPTY: + m_dom_type = type; + break; + + case Domain::SEISUU: + if (m_dom_type == Domain::JISSUU) + m_dom_type = type; + break; + + case Domain::GUUSUU: + switch (m_dom_type) + { + case Domain::EMPTY: + case Domain::GUUSUU: + break; + + case Domain::SEISUU: + case Domain::JISSUU: + m_dom_type = type; + break; + + case Domain::KISUU: + m_dom_type = Domain::EMPTY; + break; + + case Domain::SOSUU: + { + Range *r = new Range; + r->m_has_min = r->m_has_max = true; + r->m_pnLBound = new DRR1D_VALUE(2); + r->m_pnUBound = new DRR1D_VALUE(2); + Intersect(*r); + delete r; + } + break; + + default: + assert(0); + } + break; + + case Domain::KISUU: + switch (m_dom_type) + { + case Domain::EMPTY: + case Domain::KISUU: + break; + + case Domain::SEISUU: + case Domain::JISSUU: + m_dom_type = type; + break; + + case Domain::GUUSUU: + m_dom_type = Domain::EMPTY; + break; + + case Domain::SOSUU: + { + Range *r = new Range; + r->m_has_min = true; + r->m_has_max = false; + r->m_pnLBound = new DRR1D_VALUE(3); + r->m_pnUBound = NULL; + Intersect(*r); + delete r; + } + break; + + default: + assert(0); + } + break; + + case Domain::JISSUU: + break; + + case Domain::SOSUU: + switch (m_dom_type) + { + case Domain::EMPTY: + break; + + case Domain::GUUSUU: + m_dom_type = type; + { + Range *r = new Range; + r->m_has_min = r->m_has_max = true; + r->m_pnLBound = new DRR1D_VALUE(2); + r->m_pnUBound = new DRR1D_VALUE(2); + Intersect(*r); + delete r; + } + break; + + case Domain::KISUU: + m_dom_type = type; + { + Range *r = new Range; + r->m_has_min = true; + r->m_has_max = false; + r->m_pnLBound = new DRR1D_VALUE(3); + r->m_pnUBound = NULL; + Intersect(*r); + delete r; + } + break; + + case Domain::SEISUU: + case Domain::JISSUU: + m_dom_type = type; + break; + + default: + assert(0); + } + break; + + default: + assert(0); + } +} + +void Domain::clear() +{ + m_dom_type = Domain::EMPTY; + m_ranges.get()->clear(); + m_afnContains.clear(); +} + +void Domain::Intersect(const Domain& d) +{ + Domain *domain = Domain::Intersect(this, &d); + if (domain) + { + *this = *domain; + delete domain; + } + else + clear(); +} + +void Domain::Intersect(const Range& r) +{ + std::size_t i, siz = m_ranges->size(); + for (i = 0; i < siz; ++i) + { + m_ranges.get()->Intersect(r); + } +} + +/*static*/ Domain *Domain::Whole() +{ + Domain *d = new Domain; + Ranges *r = Ranges::Whole(); + d->m_ranges = shared_ptr(r); + return d; +} + +/*static*/ Domain *Domain::Intersect(const Domain *d1, const Domain *d2) +{ + Domain *d = new Domain(*d1); + d->RestrictTo(d2->m_dom_type); + if (d->m_dom_type == Domain::EMPTY) + { + delete d; + return NULL; + } + d->m_ranges->Intersect(*d2->m_ranges.get()); + if (d->m_ranges->empty()) + { + delete d; + return NULL; + } + d->m_afnContains.insert(d->m_afnContains.end(), + d2->m_afnContains.begin(), d2->m_afnContains.end()); + return d; +} + +DRR1D_VALUE *Domain::GetLBound(bool& has_min) const +{ + has_min = false; + if (empty()) + return NULL; + + return m_ranges->GetLBound(has_min); +} + +DRR1D_VALUE *Domain::GetUBound(bool& has_max) const +{ + has_max = false; + if (empty()) + return NULL; + + return m_ranges->GetUBound(has_max); +} + +bool Domain::GetValues(std::vector& values) const +{ + values.clear(); + if (empty()) + return true; + + bool has_min, has_max; + DRR1D_VALUE *pnLBound = GetLBound(has_min); + DRR1D_VALUE *pnUBound = GetUBound(has_max); + if (pnLBound == NULL || pnUBound == NULL) + { + return false; + } + + if (m_dom_type == Domain::JISSUU) + { + if (*pnLBound == *pnUBound && has_min && has_max) + { + values.push_back(*pnLBound); + return true; + } + return false; + } + if (m_dom_type == Domain::GUUSUU) + { + DRR1D_VALUE m0, m1; + + #ifdef DRR1D_USES_PMPNUMBER + if ((*pnLBound % 2).is_zero()) + m0.assign(pnLBound->to_i()); + else + m0.assign(GauseModCeil(*pnLBound, 2)); + if ((*pnUBound % 2).is_zero()) + m1.assign(pnUBound->to_i()); + else + m1 = DRR1D_VALUE(pnUBound->to_i()) - 1; + #else + if (std::fmod(*pnLBound, 2) == 0) + m0 = (int)*pnLBound; + else + m0 = (int)*pnLBound + 1; + if (std::fmod(*pnUBound, 2) == 0) + m1 = (int)*pnUBound; + else + m1 = (int)*pnUBound - 1; + #endif + + if (*pnLBound > *pnUBound) + return true; + if (*pnLBound == *pnUBound) + { + if (Contains(*pnLBound)) + values.push_back(*pnLBound); + return true; + } + for (DRR1D_VALUE i = m0; i <= m1; ++i) + { + if (Contains(i)) + values.push_back(i); + } + return true; + } + if (m_dom_type == Domain::KISUU) + { + DRR1D_VALUE m0, m1; + + #ifdef DRR1D_USES_PMPNUMBER + if ((*pnLBound % 2).is_zero()) + m0 = DRR1D_VALUE(pnLBound->to_i()) + 1; + else + m0.assign(pnLBound->to_i()); + if ((*pnUBound % 2).is_zero()) + m1 = DRR1D_VALUE(pnUBound->to_i()) - 1; + else + m1.assign(pnUBound->to_i()); + #else + if (std::fmod(*pnLBound, 2) == 0) + m0 = (int)*pnLBound + 1; + else + m0 = (int)*pnLBound; + if (std::fmod(*pnUBound, 2) == 0) + m1 = (int)*pnUBound - 1; + else + m1 = (int)*pnUBound; + #endif + if (*pnLBound > *pnUBound) + return true; + if (*pnLBound == *pnUBound) + { + if (Contains(*pnLBound)) + values.push_back(*pnLBound); + return true; + } + for (DRR1D_VALUE i = m0; i <= m1; i += 2) + { + if (Contains(i)) + values.push_back(i); + } + return true; + } + if (m_dom_type == Domain::SOSUU) + { + DRR1D_VALUE m0, m1; + #ifdef DRR1D_USES_PMPNUMBER + m0.assign(pnLBound->to_i()); + m1 = DRR1D_VALUE(pnUBound->to_i()) + 1; + #else + m0 = (int)*pnLBound; + m1 = (int)*pnUBound + 1; + #endif + if (*pnLBound > *pnUBound) + return true; + if (*pnLBound == *pnUBound) + { + if (Contains(*pnLBound)) + values.push_back(*pnLBound); + return true; + } + for (DRR1D_VALUE i = m0; i <= m1; ++i) + { + if (Contains(i)) + values.push_back(i); + } + return true; + } + if (m_dom_type == Domain::SEISUU) + { + DRR1D_VALUE m0, m1; + #ifdef DRR1D_USES_PMPNUMBER + m0.assign(pnLBound->to_i()); + m1 = DRR1D_VALUE(pnUBound->to_i()) + 1; + #else + m0 = (int)*pnLBound; + m1 = (int)*pnUBound + 1; + #endif + if (*pnLBound > *pnUBound) + return true; + if (*pnLBound == *pnUBound) + { + if (Contains(*pnLBound)) + values.push_back(*pnLBound); + return true; + } + for (DRR1D_VALUE i = m0; i <= m1; ++i) + { + if (Contains(i)) + values.push_back(i); + } + return true; + } + return false; +} + +void Domain::FixNarrower() +{ + switch (m_dom_type) + { + case Domain::EMPTY: + case Domain::JISSUU: + return; + + default: + break; + } + + std::size_t i, siz = m_ranges->size(); + for (i = 0; i < siz; ++i) + { + Range& r = *(*m_ranges.get())[i].get(); + switch (m_dom_type) + { + case Domain::SEISUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::ceil(v1); + #else + DRR1D_VALUE v2 = std::ceil(v1); + #endif + // v1 == 2, v2 == 2, has_min == true + // result: 2, true + // v1 == 2, v2 == 2, has_min == false + // result: 3, true + // v1 == 1.5, v2 == 2, has_min == true + // result: 2, false + // v1 == 1.5, v2 == 2, has_min == false + // result: 2, false + *r.m_pnLBound = v2; + if (v1 == v2) + { + if (!r.m_has_min) + { + (*r.m_pnLBound) += 1; + r.m_has_min = true; + } + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::floor(v1); + #else + DRR1D_VALUE v2 = std::floor(v1); + #endif + *r.m_pnUBound = v2; + if (v1 == v2) + { + if (!r.m_has_max) + { + (*r.m_pnUBound) -= 1; + r.m_has_max = true; + } + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::GUUSUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + DRR1D_VALUE v2 = GauseModCeil(v1, 2); + *r.m_pnLBound = v2; + if (v1 == v2) + { + if (!r.m_has_min) + { + (*r.m_pnLBound) += 2; + r.m_has_min = true; + } + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + DRR1D_VALUE v2 = GauseModFloor(v1, 2); + *r.m_pnUBound = v2; + if (v1 == v2) + { + if (!r.m_has_max) + { + (*r.m_pnUBound) -= 2; + r.m_has_max = true; + } + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::KISUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + DRR1D_VALUE v2 = GauseModCeil(v1 + 1, 2) - 1; + *r.m_pnLBound = v2; + if (v1 == v2) + { + if (!r.m_has_min) + { + (*r.m_pnLBound) += 2; + r.m_has_min = true; + } + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + DRR1D_VALUE v2 = GauseModFloor(v1 - 1, 2) + 1; + *r.m_pnUBound = v2; + if (v1 == v2) + { + if (!r.m_has_max) + { + (*r.m_pnUBound) -= 2; + r.m_has_max = true; + } + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::SOSUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::ceil(v1); + #else + DRR1D_VALUE v2 = std::ceil(v1); + #endif + if (v2 < 2) + { + break; + } + while (!IsPrimeNumber(v2)) + { + v2 += 1; + } + *r.m_pnLBound = v2; + if (v1 == v2) + { + if (!r.m_has_min) + { + do + { + v2 += 1; + } while (!IsPrimeNumber(v2)); + *r.m_pnLBound = v2; + } + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::floor(v1); + #else + DRR1D_VALUE v2 = std::floor(v1); + #endif + while (v2 >= 2 && !IsPrimeNumber(v2)) + { + v2 -= 1; + } + if (v2 < 2) + { + r.empty(); + break; + } + *r.m_pnUBound = v2; + if (v1 == v2) + { + if (!r.m_has_max) + { + do + { + v2 -= 1; + } while (v2 >= 2 && !IsPrimeNumber(v2)); + *r.m_pnUBound = v2; + r.m_has_max = true; + } + } + else + { + r.m_has_max = false; + } + } + break; + + default: + assert(0); + } + } +} + +void Domain::FixWider() +{ + switch (m_dom_type) + { + case Domain::EMPTY: + case Domain::JISSUU: + return; + + default: + break; + } + + std::size_t i, siz = m_ranges->size(); + for (i = 0; i < siz; ++i) + { + Range& r = *(*m_ranges.get())[i].get(); + switch (m_dom_type) + { + case Domain::SEISUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::floor(v1); + #else + DRR1D_VALUE v2 = std::floor(v1); + #endif + *r.m_pnLBound = v2; + if (v1 == v2 && r.m_has_min) + { + r.m_has_min = false; + (*r.m_pnLBound) -= 1; + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::ceil(v1); + #else + DRR1D_VALUE v2 = std::ceil(v1); + #endif + *r.m_pnUBound = v2; + if (v1 == v2 && r.m_has_max) + { + r.m_has_max = false; + (*r.m_pnUBound) += 1; + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::GUUSUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + DRR1D_VALUE v2 = GauseModFloor(v1, 2); + *r.m_pnLBound = v2; + if (v1 == v2 && r.m_has_min) + { + r.m_has_min = false; + (*r.m_pnLBound) -= 2; + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + DRR1D_VALUE v2 = GauseModCeil(v1, 2); + *r.m_pnUBound = v2; + if (v1 == v2 && r.m_has_max) + { + r.m_has_max = false; + (*r.m_pnUBound) += 2; + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::KISUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + DRR1D_VALUE v2 = GauseModFloor(v1 + 1, 2) - 1; + *r.m_pnLBound = v2; + if (v1 == v2 && r.m_has_min) + { + r.m_has_min = false; + (*r.m_pnLBound) -= 2; + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + DRR1D_VALUE v2 = GauseModCeil(v1 - 1, 2) + 1; + *r.m_pnUBound = v2; + if (v1 == v2 && r.m_has_max) + { + r.m_has_max = false; + (*r.m_pnUBound) += 2; + } + else + { + r.m_has_max = false; + } + } + break; + + case Domain::SOSUU: + if (r.m_pnLBound) + { + DRR1D_VALUE v1 = *r.m_pnLBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::floor(v1); + #else + DRR1D_VALUE v2 = std::floor(v1); + #endif + while (v2 > 2 && !IsPrimeNumber(v2)) + { + v2 -= 1; + } + if (v2 < 2) + break; + *r.m_pnLBound = v2; + if (v1 == v2 && r.m_has_min) + { + do + { + v2 -= 1; + } + while (v2 > 2 && !IsPrimeNumber(v2)); + r.m_has_min = false; + (*r.m_pnLBound) = v2; + } + else + { + r.m_has_min = false; + } + } + if (r.m_pnUBound) + { + DRR1D_VALUE v1 = *r.m_pnUBound; + #ifdef DRR1D_USES_PMPNUMBER + DRR1D_VALUE v2 = pmp::ceil(v1); + #else + DRR1D_VALUE v2 = std::ceil(v1); + #endif + while (!IsPrimeNumber(v2)) + { + v2 += 1; + } + *r.m_pnUBound = v2; + if (v1 == v2 && r.m_has_max) + { + r.m_has_max = false; + do + { + v2 += 1; + } while (!IsPrimeNumber(v2)); + (*r.m_pnUBound) = v2; + } + else + { + r.m_has_max = false; + } + } + break; + + default: + assert(0); + } + } +} + +void Domain::Optimize() +{ + m_ranges.get()->Optimize(); +} + +//////////////////////////////////////////////////////////////////////////// +// Domains + +bool Domains::empty() const +{ + if (size() == 0) + return true; + + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if (!(*this)[0]->empty()) + return false; + } + return true; +} + +bool Domains::Includes(const Domain& domain) const +{ + if (domain.empty()) + return true; + + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if ((*this)[i]->Includes(domain)) + return true; + if (domain.m_dom_type == Domain::SEISUU) + { + Domain d1(domain), d2(domain); + d1.RestrictTo(Domain::GUUSUU); + d2.RestrictTo(Domain::KISUU); + if (!d1.empty() && !d2.empty() && + Includes(d1) && Includes(d2)) + return true; + } + } + return false; +} + +bool Domains::Includes(const Domains& domains) const +{ + std::size_t j, siz2 = domains.size(); + for (j = 0; j < siz2; ++j) + { + bool flag = false; + if (Includes(*domains[j].get())) + { + flag = true; + break; + } + if (!flag) + return false; + } + return true; +} + +bool Domains::Contains(DRR1D_VALUE value) const +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if ((*this)[i]->Contains(value)) + return true; + } + return false; +} + +void Domains::Intersect(const Range& range) +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + (*this)[i].get()->Intersect(range); + } +} + +void Domains::Intersect(const Domain& domain) +{ + Domains *d = Domains::Intersect(this, &domain); + *this = *d; + delete d; +} + +void Domains::Intersect(const Domains& domains) +{ + Domains *d = Domains::Intersect(this, &domains); + *this = *d; + delete d; +} + +void Domains::Union(const Domain& domain) +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + if ((*this)[i]->Includes(domain)) + return; + } + for (i = 0; i < siz; ++i) + { + if ((*this)[i]->m_dom_type == domain.m_dom_type) + { + (*this)[i].get()->m_ranges->Union(*domain.m_ranges.get()); + FixWider(); + return; + } + } + push_back(shared_ptr(new Domain(domain))); + FixWider(); +} + +void Domains::Union(const Domains& domains) +{ + std::size_t i, siz = domains.size(); + for (i = 0; i < siz; ++i) + { + Union(*domains[i].get()); + } + FixWider(); +} + +/*static*/ Domains *Domains::Intersect(const Domains *domains, const Domain *domain) +{ + Domains *pDomains = new Domains(); + std::size_t i, siz = domains->size(); + for (i = 0; i < siz; ++i) + { + Domain *d = Domain::Intersect((*domains)[i].get(), domain); + if (d) + { + pDomains->Union(*d); + delete d; + } + } + return pDomains; +} + +/*static*/ Domains *Domains::Intersect(const Domains *d1, const Domains *d2) +{ + Domains *pDomains = new Domains(); + std::size_t i, siz1 = d1->size(); + for (i = 0; i < siz1; ++i) + { + Domains *d = Domains::Intersect(d2, ((*d1)[i]).get()); + if (d->size()) + pDomains->insert(pDomains->end(), d->begin(), d->end()); + delete d; + } + return pDomains; +} + +/*static*/ Domains *Domains::Whole() +{ + Domains *domains = new Domains; + Domain *domain = Domain::Whole(); + domains->push_back(shared_ptr(domain)); + return domains; +} + +bool Domains::GetValues(std::vector& values) const +{ + values.clear(); + + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + std::vector vec; + if (((*this)[i])->GetValues(vec)) + { + values.insert(values.end(), vec.begin(), vec.end()); + } + else + { + return false; + } + } + std::sort(values.begin(), values.end()); + std::unique(values.begin(), values.end()); + return true; +} + +void Domains::FixNarrower() +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + ((*this)[i]).get()->FixNarrower(); + } +} + +void Domains::FixWider() +{ + std::size_t i, siz = size(); + for (i = 0; i < siz; ++i) + { + ((*this)[i]).get()->FixWider(); + ((*this)[i]).get()->Optimize(); + } + + bool flag = false; + for (i = 0; i < siz; ++i) + { + Domain& domain1 = *((*this)[i]).get(); + if (domain1.m_dom_type == Domain::SEISUU) + { + for (std::size_t j = 0; j < siz; ++j) + { + if (j == i) + continue; + Domain& domain2 = *((*this)[j]).get(); + if (domain2.m_dom_type == Domain::KISUU || + domain2.m_dom_type == Domain::GUUSUU || + domain2.m_dom_type == Domain::SOSUU) + { + domain2.m_ranges.get()->Union(*domain1.m_ranges.get()); + flag = true; + } + } + } + else if (domain1.m_dom_type == Domain::JISSUU) + { + for (std::size_t j = 0; j < siz; ++j) + { + if (j == i) + continue; + Domain& domain2 = *((*this)[j]).get(); + if (domain2.m_dom_type == Domain::KISUU || + domain2.m_dom_type == Domain::GUUSUU || + domain2.m_dom_type == Domain::SOSUU || + domain2.m_dom_type == Domain::SEISUU) + { + domain2.m_ranges.get()->Union(*domain1.m_ranges.get()); + flag = true; + } + } + } + } + + if (flag) + { + for (i = 0; i < siz; ++i) + { + ((*this)[i]).get()->FixWider(); + ((*this)[i]).get()->Optimize(); + } + } +} + +//////////////////////////////////////////////////////////////////////////// + +} // namespace Ndrr1D + +//////////////////////////////////////////////////////////////////////////// diff --git a/Ndrr1D.hpp b/Ndrr1D.hpp new file mode 100644 index 0000000..404c98b --- /dev/null +++ b/Ndrr1D.hpp @@ -0,0 +1,346 @@ +///////////////////////////////////////////////////////////////////////////// +// Ndrr1D.hpp --- The one-dimensional Numeric Domains/Ranges Resolver +// See file "ReadMe.txt" and "License.txt". +///////////////////////////////////////////////////////////////////////////// + +#ifndef __NDRR1D__ +#define __NDRR1D__ + +#ifndef __cplusplus + #error You lose. +#endif + +#include // for std::cout, std::endl, std::size_t +#include // for std::vector + +#ifndef shared_ptr + #if (__cplusplus >= 201103L) + #include + using std::shared_ptr; + using std::static_pointer_cast; + using std::dynamic_pointer_cast; + + using std::make_shared; + #else + // boost::shared_ptr + #include + using boost::shared_ptr; + using boost::static_pointer_cast; + using boost::dynamic_pointer_cast; + + // boost::make_shared + #include + using boost::make_shared; + #endif + #define shared_ptr shared_ptr +#endif // ndef shared_ptr + +//////////////////////////////////////////////////////////////////////////// + +namespace Ndrr1D +{ + // + // DRR1D_VALUE + // + #ifndef DRR1D_VALUE + #ifdef PMPNUMBER_HPP_ + #define DRR1D_VALUE pmp::Number + #ifndef DRR1D_USES_PMPNUMBER + #define DRR1D_USES_PMPNUMBER + #endif + #else + #define DRR1D_VALUE double + #endif + #endif + + bool IsPositiveNumber(const DRR1D_VALUE& value); + bool IsNegativeNumber(const DRR1D_VALUE& value); + bool IsNaturalNumber(const DRR1D_VALUE& value); + bool IsRegularNumber(const DRR1D_VALUE& value); + bool IsEvenNumber(const DRR1D_VALUE& value); + bool IsOddNumber(const DRR1D_VALUE& value); + bool IsPrimeNumber(const DRR1D_VALUE& value); + DRR1D_VALUE GauseModFloor(const DRR1D_VALUE& d, const DRR1D_VALUE& mod); + DRR1D_VALUE GauseModCeil(const DRR1D_VALUE& d, const DRR1D_VALUE& mod); + + // + // Ndrr1D::Range + // + struct Range + { + bool m_has_min; + bool m_has_max; + DRR1D_VALUE * m_pnLBound; + DRR1D_VALUE * m_pnUBound; + + Range() : + m_has_min(false), m_has_max(false), + m_pnLBound(NULL), m_pnUBound(NULL) + { + } + + Range(bool has_min, bool has_max, DRR1D_VALUE *pnLBound, DRR1D_VALUE *pnUBound) : + m_has_min(has_min), m_has_max(has_max), + m_pnLBound(pnLBound ? new DRR1D_VALUE(*pnLBound) : NULL), + m_pnUBound(pnUBound ? new DRR1D_VALUE(*pnUBound) : NULL) + { + } + + Range(const DRR1D_VALUE& value) : + m_has_min(true), m_has_max(true), + m_pnLBound(new DRR1D_VALUE(value)), m_pnUBound(new DRR1D_VALUE(value)) + { + } + + ~Range() + { + delete m_pnLBound; + delete m_pnUBound; + } + + Range(const Range& r) : + m_has_min(r.m_has_min), + m_has_max(r.m_has_max), + m_pnLBound(new DRR1D_VALUE(*r.m_pnLBound)), + m_pnUBound(new DRR1D_VALUE(*r.m_pnUBound)) + { + } + + Range& operator=(const Range& r) + { + m_has_min = r.m_has_min; + delete m_pnLBound; + m_pnLBound = new DRR1D_VALUE(*r.m_pnLBound); + m_has_max = r.m_has_max; + delete m_pnUBound; + m_pnUBound = new DRR1D_VALUE(*r.m_pnUBound); + return *this; + } + + bool empty() const; + void clear(); + bool Includes(const Range& range) const; + bool Contains(DRR1D_VALUE value) const; + void Intersect(const Range& r); + + DRR1D_VALUE *GetLBound(bool& has_min) const + { + has_min = m_has_min; + return m_pnLBound; + } + + DRR1D_VALUE *GetUBound(bool& has_max) const + { + has_max = m_has_max; + return m_pnUBound; + } + + static Range *Whole() + { + return new Range; + } + + protected: + static Range *Intersect(const Range *r1, const Range *r2); + friend struct Ranges; + friend struct Domain; + friend struct Domains; + }; + + // + // Ndrr1D::Ranges + // + struct Ranges : std::vector > + { + Ranges() { } + + Ranges(const Ranges& ranges) : std::vector >(ranges) + { } + + Ranges& operator=(const Ranges& ranges) + { + this->assign(ranges.begin(), ranges.end()); + return *this; + } + + bool empty() const; + bool Includes(const Ranges& ranges) const; + bool Contains(DRR1D_VALUE value) const; + void Intersect(const Range& range); + void Intersect(const Ranges& ranges); + void Union(const Ranges& ranges); + void Optimize(); + + DRR1D_VALUE *GetLBound(bool& has_min) const; + DRR1D_VALUE *GetUBound(bool& has_max) const; + static Ranges *Whole(); + + protected: + static Ranges *Optimize(const Ranges *ranges); + static Ranges *Intersect(const Ranges *ranges, const Range *range); + static Ranges *Intersect(const Ranges *r1, const Ranges *r2); + static Ranges *Union(const Ranges *r1, const Ranges *r2); + friend struct Range; + friend struct Domain; + friend struct Domains; + }; + + // + // Ndrr1D::FN_CONTAINS + // + typedef bool (*FN_CONTAINS)(const DRR1D_VALUE& value); + + // + // Ndrr1D::Domain + // + struct Domain + { + enum Type { EMPTY, SEISUU, GUUSUU, KISUU, JISSUU, SOSUU }; + Type m_dom_type; + shared_ptr m_ranges; + std::vector m_afnContains; + + Domain() : m_dom_type(JISSUU) { } + + Domain(const Domain& d) : + m_dom_type(d.m_dom_type), + m_ranges(d.m_ranges), + m_afnContains(d.m_afnContains) + { + } + + Domain& operator=(const Domain& d) + { + m_dom_type = d.m_dom_type; + m_ranges = d.m_ranges; + m_afnContains = d.m_afnContains; + return *this; + } + + bool empty() const; + void clear(); + bool Includes(Domain::Type type) const; + bool Includes(const Domain& domain) const; + bool Contains(const DRR1D_VALUE& value) const; + void RestrictTo(Domain::Type type); + void Intersect(const Range& r); + void Intersect(const Domain& d); + void Optimize(); + DRR1D_VALUE *GetLBound(bool& has_min) const; + DRR1D_VALUE *GetUBound(bool& has_max) const; + bool GetValues(std::vector& values) const; + void FixWider(); + void FixNarrower(); + static Domain *Whole(); + + protected: + static Domain *Intersect(const Domain *d1, const Domain *d2); + friend struct Range; + friend struct Ranges; + friend struct Domains; + }; + + // + // Ndrr1D::Domains + // + struct Domains : std::vector > + { + Domains() { } + + Domains(const Domains& domains) : std::vector >(domains) + { } + + Domains& operator=(const Domains& domains) + { + this->assign(domains.begin(), domains.end()); + return *this; + } + + bool empty() const; + + // NOTE: You have to call domain.FixNarrower and this->FixWider before + // Domains::Includes(const Domain&) call. + bool Includes(const Domain& domain) const; + + // NOTE: You have to call domains.FixNarrower and this->FixWider before + // Domains::Includes(const Domains&) call. + bool Includes(const Domains& domains) const; + + bool Contains(DRR1D_VALUE value) const; + void Intersect(const Range& range); + void Intersect(const Domain& domain); + void Intersect(const Domains& domains); + void Union(const Domain& domain); + void Union(const Domains& domains); + bool GetValues(std::vector& values) const; + static Domains *Whole(); + void FixWider(); + void FixNarrower(); + + protected: + static Domains *Intersect(const Domains *domains, const Domain *domain); + static Domains *Intersect(const Domains *d1, const Domains *d2); + static Domains *Union(const Domains *d1, const Domains *d2); + friend struct Range; + friend struct Ranges; + friend struct Domain; + }; +} // namespace Ndrr1D + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const Ndrr1D::Range& r) +{ + os << "["; + if (r.m_pnLBound) + { + if (r.m_has_min) os << "(Closed)"; + else os << "(Open)"; + os << "lower: " << *r.m_pnLBound << " "; + } + if (r.m_pnUBound) + { + if (r.m_has_max) os << "(Closed)"; + else os << "(Open)"; + os << "upper: " << *r.m_pnUBound; + } + os << "]"; + return os; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const Ndrr1D::Ranges& r) +{ + os << "["; + for (std::size_t i = 0; i < r.size(); ++i) + { + os << *(r[i].get()); + } + os << "]"; + return os; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const Ndrr1D::Domain& d) +{ + os << "[" << d.m_dom_type << ": " << + (*d.m_ranges.get()) << "]"; + return os; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const Ndrr1D::Domains& d) +{ + os << "[domains: "; + for (std::size_t i = 0; i < d.size(); ++i) + { + os << *(d[i].get()); + } + os << "]"; + return os; +} + +#endif // ndef __NDRR1D__ diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..bfc7706 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,2 @@ +This is The one-dimensional Numeric Domains/Ranges Resolver +(Ndrr1D) by Katayama Hirofumi MZ.