/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of 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 ---- //paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}] //[TOC] [\tableofcontents] Started July 2014, Fabio Vald\'{e}s */ #include "Tools.h" using namespace std; using namespace datetime; using namespace temporalalgebra; namespace stj { /* \section{Implementation of class ~Tools~} \subsection{Function ~intersect~} */ void Tools::intersect(const vector >& tidsets, set& result) { result.clear(); if (tidsets.empty()) { return; } vector::iterator> it; for (unsigned int i = 0; i < tidsets.size(); i++) { // initialize iterators // cout << "size of set " << i << " is " << tidsets[i].size() << endl; set::iterator iter = tidsets[i].begin(); it.push_back(iter); if (iter == tidsets[i].end()) { // empty set return; } } while (true) { unsigned int min(UINT_MAX), max(0); for (unsigned int i = 0; i < tidsets.size(); i++) { if (*(it[i]) < min) { min = *(it[i]); } if (*(it[i]) > max) { max = *(it[i]); } } if (min == max) { result.insert(min); for (unsigned int i = 0; i < tidsets.size(); i++) { it[i]++; if (it[i] == tidsets[i].end()) { return; } } } else { // min < max for (unsigned int i = 0; i < tidsets.size(); i++) { while (*it[i] < max) { it[i]++; if (it[i] == tidsets[i].end()) { return; } } } } } } void Tools::intersectPairs(vector > >& posVec, set >*& result) { result->clear(); if (posVec.empty()) { return; } if (posVec.size() == 1) { result = &(posVec[0]); return; } vector >::iterator> it; for (unsigned int i = 0; i < posVec.size(); i++) { // initialize iterators // cout << "size of set " << i << " is " << posVec[i].size() << endl; set >::iterator iter = posVec[i].begin(); it.push_back(iter); if (iter == posVec[i].end()) { // empty set return; } } while (true) { pair min = make_pair(UINT_MAX, INT_MAX); pair max = make_pair(0, INT_MIN); for (unsigned int i = 0; i < posVec.size(); i++) { if (*(it[i]) < min) { min = *(it[i]); } if (*(it[i]) > max) { max = *(it[i]); } } if (min == max) { result->insert(min); for (unsigned int i = 0; i < posVec.size(); i++) { it[i]++; if (it[i] == posVec[i].end()) { return; } } } else { // min < max for (unsigned int i = 0; i < posVec.size(); i++) { while (*it[i] < max) { it[i]++; if (it[i] == posVec[i].end()) { return; } } } } } } void Tools::uniteLast(unsigned int size, vector >& tidsets) { if (tidsets.size() < size) { return; } for (unsigned int i = tidsets.size() - size + 1; i < tidsets.size(); i++) { tidsets[tidsets.size() - size].insert(tidsets[i].begin(), tidsets[i].end()); } for (unsigned int i = 1; i < size; i++) { tidsets.pop_back(); } } void Tools::uniteLastPairs(unsigned int size, vector > >& posVec) { if (posVec.size() < size) { return; } for (unsigned int i = posVec.size() - size + 1; i < posVec.size(); i++) { posVec[posVec.size() - size].insert(posVec[i].begin(), posVec[i].end()); } for (unsigned int i = 1; i < size; i++) { posVec.pop_back(); } } void Tools::filterPairs(set >* pairs, const set& pos, set >*& result) { if (pos.empty() || pairs->empty()) { result = pairs; return; } set >::iterator ip = pairs->begin(); set::iterator it = pos.begin(); set >::iterator ir = result->begin(); while ((ip != pairs->end()) && (it != pos.end())) { if (ip->first == *it) { ir = result->insert(ir, *ip); ip++; it++; } else if (ip->first < *it) { ip++; } else { it++; } } if (it == pos.end()) { while (ip != pairs->end()) { ir = result->insert(ir, *ip); ip++; } } } string Tools::int2String(int i) { stringstream result; result << i; return result.str(); } int Tools::str2Int(string const &text) { int result; stringstream ss(text); if((ss >> result).fail()) result = 0; return result; } void Tools::deleteSpaces(string &text) { size_t pos = 0; while ((pos = text.find(' ', pos)) != string::npos) text.erase(pos, 1); } /* \subsection{Function ~convert~} Converts a string into a char[*]. */ char* Tools::convert(string arg) { return strdup(arg.c_str()); } /* \subsection{Function ~eraseQM~} Deletes enclosing quotation marks from a string. */ void Tools::eraseQM(string& arg) { if (arg.at(0) == '"') { arg = arg.substr(1, arg.length() - 2); } } void Tools::addQM(string& arg) { if (arg.at(0) != '"') { arg.insert(0, "\""); arg.append("\""); } } void Tools::simplifyRegEx(string ®Ex) { for (unsigned int i = 0; i < regEx.length(); i++) { switch (regEx[i]) { case '*': { regEx[i] = '?'; break; } case '+': { regEx.erase(i, 1); break; } default: { break; } } } } /* function ~setToString~ */ string Tools::setToString(const set& input) { set::iterator i; stringstream result; if (input.size() == 1) { result << *(input.begin()); } else if (input.size() > 1) { result << "{"; for (i = input.begin(); i != input.end(); i++) { if (i != input.begin()) { result << ", "; } result << *i; } result << "}"; } return result.str(); } /* function ~createSetMatrix~ Creates and returns a twodimensional array that is used to store the matching positions. */ set** Tools::createSetMatrix(unsigned int dim1,unsigned int dim2){ set** result = new set*[dim1]; for (unsigned int i = 0; i < dim1; i++) { result[i] = new set[dim2]; } return result; }; /* function ~deleteSetMatrix~ Deletes a twodimensional array. */ void Tools::deleteSetMatrix(set** &victim, unsigned int dim1) { if (victim) { for (unsigned int i = 0; i < dim1; i++) { if (victim[i]) { delete[] victim[i]; } } delete[] victim; victim = 0; } } /* function ~prefixCount~ Returns the number of strings from which ~str~ is a prefix. This is needed in MLabel::buildIndex. */ int Tools::prefixCount(string str, set strings) { set::iterator it; int result = 0; for (it = strings.begin(); it != strings.end(); it++) { if ((it->substr(0, str.length()) == str) && (*it != str)) { result++; } } return result; } void Tools::splitPattern(string& input, vector& result) { result.clear(); if (input.empty()) { return; } size_t pos = input.find('{'); if (pos == 0) { // ({2012, 2013}, ...) result.push_back(input.substr(0, input.find('}') + 1)); if (input.find('{', 1) != string::npos) { // ({2012, 2013}, {a, b, c}) result.push_back(input.substr(input.find('{', 1))); } else { // ({2012, 2013} a) result.push_back(input.substr(input.find('}') + 1)); } } else if (pos == string::npos) { // no curly brackets if (input.find(' ') == string::npos) { // * or + result.push_back(input); } else { // (2012 a) result.push_back(input.substr(0, input.find(' '))); result.push_back(input.substr(input.find(' '))); } } else { // (2012 {a, b, c}) result.push_back(input.substr(0, input.find(' '))); result.push_back(input.substr(input.find(' '))); } } /* function ~extractVar~ Takes an assignment string like ~time:=Z.time~ and returns the variable string. */ string Tools::extractVar(const string& input) { int posEq = input.find('='); int posDot = input.find('.'); return input.substr(posEq + 1, posDot - posEq - 1); } int Tools::getKey(const string& type, Tuple *tuple /* = 0 */, ListExpr tupleType /* = 0 */) { if (type.empty()) { cout << "Error: empty string after variable" << endl; return -1; } if (type == "label") return 0; if (type == "place") return 1; if (type == "time") return 2; if (type == "start") return 3; if (type == "end") return 4; if (type == "leftclosed") return 5; if (type == "rightclosed") return 6; if (type == "card") return 7; if (type == "labels") return 8; if (type == "places") return 9; if (tuple) { if (tupleType == 0) { cout << "Error: no tuple type found" << endl; return -1; } if (nl->ListLength(tupleType) != 2) { cout << "Error: list length must be 2" << endl; return -1; } if (!IsTupleDescription(nl->Second(tupleType))) { cout << "Error: list is not a tuple description" << endl; return -1; } ListExpr aType; int pos = FindAttribute(nl->Second(tupleType), type, aType); if (pos == 0) { cout << "Attribute " << type << " not found" << endl; return -1; } return pos + 99; } else { cout << "Error: type " << type << " is invalid without tuple" << endl; } return -1; // should not occur } string Tools::getDataType(const int key) { switch (key) { case -2: return MBool::BasicType(); case -1: return CcBool::BasicType(); case 0: return Label::BasicType(); case 1: return Place::BasicType(); case 2: return SecInterval::BasicType(); case 3: case 4: return Instant::BasicType(); case 5: case 6: return CcBool::BasicType(); case 7: return CcInt::BasicType(); case 8: return Labels::BasicType(); case 9: return Places::BasicType(); default: return "error"; } } DataType Tools::getDataType(const string& type) { if (type == "mlabel") return MLABEL; if (type == "mlabels") return MLABELS; if (type == "mplace") return MPLACE; return MPLACES; } DataType Tools::getDataType(TupleType *ttype, const int attrno) { SecondoCatalog* sc = SecondoSystem::GetCatalog(); AttributeType attrType = ttype->GetAttributeType(attrno); string typeName = sc->GetTypeName(attrType.algId, attrType.typeId); return getDataType(typeName); } string Tools::getTypeName(TupleType *ttype, const int attrno) { SecondoCatalog* sc = SecondoSystem::GetCatalog(); AttributeType attrType = ttype->GetAttributeType(attrno); return sc->GetTypeName(attrType.algId, attrType.typeId); } int Tools::getNoComponents(Relation *rel, const TupleId tid, const string &type, const int attrno) { Tuple *tuple = rel->GetTuple(tid, true); if (type == "mreal") { ((MReal*)tuple->GetAttribute(attrno))->GetNoComponents(); } else if (type == "mint") { ((MInt*)tuple->GetAttribute(attrno))->GetNoComponents(); } else if (type == "mpoint") { ((MPoint*)tuple->GetAttribute(attrno))->GetNoComponents(); } else if (type == "mregion") { ((MRegion*)tuple->GetAttribute(attrno))->GetNoComponents(); } else if (type == "mbool") { ((MBool*)tuple->GetAttribute(attrno))->GetNoComponents(); } tuple->DeleteIfAllowed(); return -1; } bool Tools::isSymbolicType(ListExpr type) { return ((nl->ToString(type) == "mlabel") || (nl->ToString(type) == "mlabels") || (nl->ToString(type) == "mplace") || (nl->ToString(type) == "mplaces")); } string Tools::getWeekdayStr(const int weekday) { if (weekday < 0 || weekday > 6) { return string(); } std::string weekdays[7] = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}; return weekdays[weekday]; } string Tools::getMonthStr(const int month) { if (month < 0 || month > 11) { return string(); } static std::string months[12] = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"}; return months[month]; } string Tools::getDaytimeStr(const int daytime) { if (daytime < 0 || daytime > 3) { return string(); } static std::string daytimes[4] = {"morning", "afternoon", "evening", "night"}; return daytimes[daytime]; } /* function ~extendDate~ Takes a datetime string and extends it to the format YYYY-MM-DD-HH:MM:SS.MMM, the variable ~start~ decides on the values. */ string Tools::extendDate(string input, const bool start) { string result, mask; int month, daysInMonth, year; if (start) { mask.assign("-01-01-00:00:00"); } else { mask.assign("-12-31-23:59:59.999"); } if (input[input.size() - 1] == '-') { // handle case 2011-04-02- input.resize(input.size() - 1); } result.assign(input); size_t pos = 1; if ((pos = input.find('-', pos)) == string::npos) { result.append(mask.substr(0)); return result; } pos++; if ((pos = input.find('-', pos)) == string::npos) { if (!start) { stringstream yearStream(input.substr(0, input.find('-'))); stringstream monthStream(input.substr(input.find('-') + 1)); stringstream dayStream; if ((monthStream >> month).fail()) { cout << "month stringstream error" << endl; return input + mask.substr(3); } else { switch (month){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: daysInMonth = 31; break; case 4: case 6: case 9: case 11: daysInMonth = 30; break; case 2: if ((yearStream >> year).fail()) { cout << "year stringstream error" << endl; return input + mask.substr(3); } else { if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) { daysInMonth = 29; } else { daysInMonth = 28; } } break; default: // should not occur cout << "month " << month << " does not exist" << endl; return input + mask.substr(3); } } dayStream << "-" << daysInMonth; result.append(dayStream.str()); result.append(mask.substr(6)); return result; } } pos = input.find('-') + 1; if ((pos = input.find('-', pos)) == string::npos) { result.append(mask.substr(3)); return result; } pos++; if ((pos = input.find('-', pos)) == string::npos) { result.append(mask.substr(6)); return result; } pos++; if ((pos = input.find(':', pos)) == string::npos) { result.append(mask.substr(9)); return result; } pos++; if ((pos = input.find(':', pos)) == string::npos) { result.append(mask.substr(12)); return result; } pos++; if ((pos = input.find('.', pos)) == string::npos) { result.append(mask.substr(15)); return result; } return input; } /* function ~checkSemanticDate~ Checks whether ~text~ is a valid semantic date string or a valid database object of type ~Periods~ and contains the time interval defined by ~uIv~. If the parameter ~resultNeeded~ is ~false~, the function will only check the validity of ~text~. */ bool Tools::checkSemanticDate(const string &text, const SecInterval &uIv, const bool eval) { Instant uStart = uIv.start; Instant uEnd = uIv.end; bool isSemanticDate = false; for (int i = 0; i < 12; i++) { if (!text.compare(getMonthStr(i))) { isSemanticDate = true; } else if (i < 7) { if (!text.compare(getWeekdayStr(i))) { isSemanticDate = true; } else if (i < 4) { if (!text.compare(getDaytimeStr(i))) { isSemanticDate = true; } } } } if (isSemanticDate && !eval) { return true; } else if (isSemanticDate && eval) { if ((uStart.GetYear() == uEnd.GetYear()) // year and month of start and end && (uStart.GetMonth() == uEnd.GetMonth())) { //must coincode for match for (int i = 0; i < 12; i++) { // handle months if (!text.compare(getMonthStr(i))) { return (i == uStart.GetMonth() - 1); } } // for weekdays and daytimes, start and end day have to coincide if (uStart.GetGregDay() == uEnd.GetGregDay()) { for (int i = 0; i < 7; i++) { // handle weekdays if (!text.compare(getWeekdayStr(i))) { return (i == uStart.GetWeekday()); } } for (int i = 0; i < 4; i++) { // handle daytimes if (!text.compare(getDaytimeStr(i))) { switch (i) { case 0: return (uStart.GetHour() >= 0) && (uEnd.GetHour() <= 11); case 1: return (uStart.GetHour() >= 12) && (uEnd.GetHour() <= 16); case 2: return (uStart.GetHour() >= 17) && (uEnd.GetHour() <= 20); case 3: return (uStart.GetHour() >= 21) && (uEnd.GetHour() <= 23); default: // cannot occur cout << "daytime error" << endl; return false; } } } } } // different months => match impossible } else { SecondoCatalog* sc = SecondoSystem::GetCatalog(); const int errPos = 0; ListExpr errInfo; bool ok; if (Periods::checkType(sc->GetObjectTypeExpr(text)) || SecInterval::checkType(sc->GetObjectTypeExpr(text))) { Word pWord = sc->InObject(sc->GetObjectTypeExpr(text), sc->GetObjectValue(text), errPos, errInfo, ok); if (!ok) { cout << "Error: InObject failed." << endl; return false; } else { if (Periods::checkType(sc->GetObjectTypeExpr(text))) { Periods* period = static_cast(pWord.addr); return (eval ? period->Contains(uIv) : true); } else { SecInterval* interval = static_cast(pWord.addr); return (eval ? interval->Contains(uIv) : true); } } } cout << text << " is not a periods / interval object." << endl; return false; } return false; } /* function ~checkDaytime~ Checks whether the daytime interval resulting from text (e.g., 0:00[~]8:00) contains the one from the unit label. */ bool Tools::checkDaytime(const string& text, const SecInterval& uIv) { if ((uIv.start.GetYear() == uIv.end.GetYear()) && (uIv.start.GetMonth() == uIv.end.GetMonth()) && (uIv.start.GetGregDay() == uIv.end.GetGregDay())) { string startString, endString; stringstream startStream; startStream << uIv.start.GetYear() << "-" << uIv.start.GetMonth() << "-" << uIv.start.GetGregDay() << "-"; startString.assign(startStream.str()); endString.assign(startString); startString.append(text.substr(0, text.find('~'))); endString.append(text.substr(text.find('~') + 1)); Instant pStart(instanttype); Instant pEnd(instanttype); if (!pStart.ReadFrom(extendDate(startString, true))) { cout << "error: ReadFrom " << extendDate(startString, true) << endl; return false; } if (!pEnd.ReadFrom(extendDate(endString, false))) { cout << "error: ReadFrom " << extendDate(endString, false) << endl; return false; } SecInterval pInterval(pStart, pEnd, true, true); return pInterval.Contains(uIv); } // no match possible in case of different days return false; } int Tools::getDaytime(const int hour) { if (hour < 0 || hour > 23) { return INT_MIN; } if (hour <= 11) { return 0; } if (hour <= 16) { return 1; } if (hour <= 20) { return 2; } return 3; } /* \subsection{Function ~isInterval~} */ bool Tools::isInterval(const string& str) { if (str.empty()) { return false; } if ((str[0] > 96) && (str[0] < 123)) { // 1st case: semantic date/time return false; } if (isDaytime(str)) { return false; } return true; } /* \subsection{Function ~isDaytime~} */ bool Tools::isDaytime(const string& str) { if ((str.find('-') == string::npos) // 2nd case: 19:09~22:00 && ((str.find(':') < str.find('~')) // on each side of [~], || (str[0] == '~')) // there has to be either xx:yy or nothing && ((str.find(':', str.find('~')) != string::npos) || str[str.size() - 1] == '~' || str.find('~') == string::npos)) { return true; } return false; } /* \subsection{Function ~semanticToTimePer~} */ void Tools::semanticToTimePer(const string& spec, const NewPair limits, Periods& result) { Periods tempResult(true); Instant leftLimit(limits.first), rightLimit(limits.second); Instant startTemp(instanttype), endTemp(instanttype); Interval limitsIv(leftLimit, rightLimit, true, true); // cout << "limits from multi-index are " << leftLimit << ", " << rightLimit // << endl; bool found = false; for (int i = 0; i < 7 && !found; i++) { if (spec == getWeekdayStr(i)) { found = true; int firstDay; if (i >= leftLimit.GetWeekday()) { firstDay = leftLimit.GetDay() + i - leftLimit.GetWeekday(); } else { firstDay = leftLimit.GetDay() + 7 - (leftLimit.GetWeekday() - i); } for (int d = firstDay; d <= rightLimit.GetDay(); d = d + 7) { Instant startTmp(d, 0, instanttype), endTmp(d, 86399999, instanttype); Interval ivTemp(startTmp, endTmp, true, true); tempResult.MergeAdd(ivTemp); } } } for (int i = 0; i < 12 && !found; i++) { if (spec == getMonthStr(i)) { found = true; for (int y = leftLimit.GetYear(); y <= rightLimit.GetYear(); y++) { startTemp.Set(y, i + 1, 1, 0, 0, 0, 0); endTemp.Set(y, i + 1, 31, 23, 59, 59, 999); if (endTemp.GetGregDay() < 31) { endTemp.Set(y, i + 1, 31 - endTemp.GetGregDay(), 23, 59, 59, 999); } Interval ivTemp(startTemp, endTemp, true, true); tempResult.MergeAdd(ivTemp); } } } for (int i = 0; i < 4 && !found; i++) { if (spec == getDaytimeStr(i)) { int startHours[5] = {0, 12, 17, 20, 24}; found = true; for (int d = leftLimit.GetDay(); d <= rightLimit.GetDay(); d++) { Instant startTmp(d, 0, instanttype), endTmp(d, 0, instanttype); startTmp.Set(startTmp.GetYear(), startTmp.GetMonth(), startTmp.GetGregDay(), startHours[i], 0, 0, 0); endTmp.Set(endTmp.GetYear(), endTmp.GetMonth(), endTmp.GetGregDay(), startHours[i + 1] - 1, 59, 59, 999); Interval ivTemp(startTmp, endTmp, true, true); tempResult.MergeAdd(ivTemp); } } } if (!found) { result.SetDefined(false); } else { tempResult.Intersection(limitsIv, result); // cout << "sTTP result: " << result << endl; } } /* \subsection{Function ~specToPeriods~} */ void Tools::specToPeriods(const string& spec, const NewPair limits, Periods& result) { // cout << "start sTP with |" << spec << "|" << endl; result.Clear(); Instant first(limits.first), last(limits.second); if (spec.empty()) { result.SetDefined(false); } else if (isInterval(spec)) { result.SetDefined(true); SecInterval iv(first, last, true, true); stringToInterval(spec, iv); result.Add(iv); } else if (isDaytime(spec)) { result.SetDefined(true); stringToDaytimePer(spec, limits, result); } else { semanticToTimePer(spec, limits, result); } } /* \subsection{Function ~stringToInterval~} */ void Tools::stringToInterval(const string& str, SecInterval& result) { if (!isInterval(str)) { result.SetDefined(false); return; } Instant pStart(instanttype); Instant pEnd(instanttype); if (str[0] == '~') { // 3rd case: ~2012-05-12 pStart.ToMinimum(); pEnd.ReadFrom(extendDate(str.substr(1), false)); } else if (str[str.size() - 1] == '~') { // 4th case: 2011-04-02-19:09~ pStart.ReadFrom(extendDate(str.substr(0, str.size() - 1), true)); pEnd.ToMaximum(); } else if (str.find('~') == string::npos) { // 5th case: no [~] found pStart.ReadFrom(extendDate(str, true)); pEnd.ReadFrom(extendDate(str, false)); } else { // sixth case: 2012-05-12-20:00~2012-05-12-22:00 pStart.ReadFrom(extendDate(str.substr(0, str.find('~')), true)); pEnd.ReadFrom(extendDate(str.substr(str.find('~') + 1), false)); } result.Set(pStart, pEnd, true, true); } /* \subsection{Function ~setDaytime~} */ void Tools::setDaytime(const string& str, const bool isStart, Instant& result) { // cout << "setDaytime(" << str << ", " << isStart << ")" << endl; string src(str); size_t pos = 0; int hour(-1), minute(-1), second(-1), millisecond(-1); pos = src.find(":"); if (pos != string::npos) { istringstream istr(src.substr(0, pos)); istr >> hour; // cout << "found hour. " << hour << endl; src = src.substr(pos + 1); pos = src.find(':'); if (pos != string::npos) { istr.clear(); istringstream istr(src.substr(0, pos)); istr >> minute; // cout << "found minute. " << minute << endl; src = src.substr(pos + 1); pos = src.find('.'); if (pos != string::npos) { // all values given, 19:09:09.009 istr.clear(); istringstream istr(src.substr(0, pos)); istr >> second; // cout << "found second. " << second << endl; istringstream iistr(src.substr(pos + 1)); iistr >> millisecond; // cout << "found millisecond " << millisecond << endl; } else { // no millisecond, 19:09:09 istr.clear(); istringstream istr(src.substr(0, src.find('~'))); istr >> second; // cout << "found second " << second << endl; millisecond = (isStart ? 0 : 999); } } else { // no second, 19:09 istringstream istr(src.substr(0, src.find('~'))); istr >> minute; // cout << "found minute " << minute << endl; second = (isStart ? 0 : 59); millisecond = (isStart ? 0 : 999); } } else { istringstream istr(src.substr(0, src.find('~'))); istr >> hour; // cout << "found hour " << hour << endl; minute = (isStart ? 0 : 59); second = (isStart ? 0 : 59); millisecond = (isStart ? 0 : 999); } result.Set(result.GetYear(), result.GetMonth(), result.GetGregDay(), hour, minute, second, millisecond); // cout << "result of setDaytime: " << result << endl; } /* \subsection{Function ~stringToDaytmePer~} */ void Tools::stringToDaytimePer(const string& str, const NewPair limits, Periods& result) { Instant leftLimit(limits.first), rightLimit(limits.second); Interval limitsIv(leftLimit, rightLimit, true, true); Instant leftDummy(leftLimit), rightDummy(rightLimit); leftDummy.Set(leftLimit.GetYear(), leftLimit.GetMonth(), leftLimit.GetGregDay(), 0, 0, 0, 0); rightDummy.Set(rightLimit.GetYear(), rightLimit.GetMonth(), rightLimit.GetGregDay(), 23, 59, 59, 999); size_t pos = str.find('~'); if (pos == 0) { // ~19:09; left limit remains unchanged setDaytime(str.substr(1), false, rightDummy); } else if (pos == string::npos) { // 19:09 setDaytime(str, true, leftDummy); setDaytime(str, false, rightDummy); } else if (pos == str.length() - 1) { // 19:09~ ; right limit remains unchanged setDaytime(str.substr(0, pos), true, leftDummy); } else { // 19:09~20:15 setDaytime(str.substr(0, pos), true, leftDummy); setDaytime(str.substr(pos + 1), false, rightDummy); } int startDay = std::floor(leftDummy.ToDouble()); int endDay = std::floor(rightDummy.ToDouble()); double startDaytime = leftDummy.ToDouble() - std::floor(leftDummy.ToDouble()); double endDaytime = rightDummy.ToDouble() - std::floor(rightDummy.ToDouble()); Periods tempResult(true); for (int i = startDay; i <= endDay; i++) { Instant startTemp(startDaytime + i); Instant endTemp(endDaytime + i); Interval iv(startTemp, endTemp, true, true); tempResult.MergeAdd(iv); } tempResult.Intersection(limitsIv, result); } /* \subsection{Function ~orderCheckInsert~} */ bool Tools::orderCheckInsert(Range *range, const Interval &iv) { set, ivCmp> ivSet; Interval ivTemp; for (int i = 0; i < range->GetNoComponents(); i++) { range->Get(i, ivTemp); ivSet.insert(ivTemp); } ivSet.insert(iv); // intervals are ordered in ivSet range->Clear(); for (set, ivCmp>::iterator it = ivSet.begin(); it != ivSet.end(); it++) { range->MergeAdd(*it); } return range->IsValid(); } /* \subsection{Function ~parseInterval~} */ bool Tools::parseInterval(const string& input, bool &isEmpty, int &pos, int &endpos, Word &value) { double left(0.0), right(0.0); bool lc(true), rc(true); endpos = input.find(' ', pos); stringstream leftss(input.substr(pos + 1, endpos)); leftss >> left; if (input[pos] == '<') { // interval pos = input.find_first_not_of(' ', endpos); endpos = input.find(' ', pos); stringstream rightss(input.substr(pos, endpos - 1)); rightss >> right; if (right < left) { cout << "invalid interval" << endl; return false; } if (input.find('>', pos) > input.find(' ', pos)) { // if (input[pos] != 't' && input[pos] != 'f') { cout << "\"t\" or \"f\" expected for interval, instead of \"" << input[pos] << "\"" << endl; return false; } lc = (input[pos] == 't'); pos = input.find_first_not_of(' ', pos + 1); rc = (input[pos] == 't'); pos = input.find('>', pos) + 1; } endpos = input.find(' ', pos); pos = input.find_first_not_of(' ', endpos); } else { // single value right = left; pos = input.find_first_not_of(' ', endpos); } CcReal ccleft(left); CcReal ccright(right); Interval iv(ccleft, ccright, lc, rc); if (isEmpty) { value.addr = new Range(true); ((Range*)value.addr)->Add(iv); isEmpty = false; } else { if (!Tools::orderCheckInsert((Range*)value.addr, iv)) { cout << "error: interval " << input << " cannot be inserted" << endl; return false; } } // cout << "interval " << (lc ? "[" : "(") << left << ", " << right // << (rc ? "]" : ")") << " inserted" << endl; endpos = pos - 1; pos = input.find_first_not_of(' ', pos); return true; } /* \subsection{Function ~isSetRel~} */ bool Tools::isSetRel(const string& input, int &pos, int &endpos, SetRel &setrel) { if (input.substr(pos, 8) == "disjoint") { setrel = DISJOINT; } else if (input.substr(pos, 8) == "superset") { setrel = SUPERSET; } else if (input.substr(pos, 5) == "equal") { setrel = EQUAL; } else if (input.substr(pos, 9) == "intersect") { setrel = INTERSECT; } if (setrel != STANDARD) { pos = input.find_first_of('{', pos); return true; } else { return false; } } /* \subsection{Function ~parseBoolorObj~} */ bool Tools::parseBoolorObj(const string& input, bool &isEmpty, int &pos, int &endpos, Word &value, std::string& type) { if (!stringutils::isLetter(input[pos])) { return false; } endpos = input.find_first_of(" ,)}", pos) - 1; if (input.substr(pos, 4) == "TRUE") { if (isEmpty) { value.addr = new CcBool(true, true); } else { ((CcBool*)value.addr)->Set(true, true); } type = CcBool::BasicType(); } else if (input.substr(pos, 5) == "FALSE") { if (isEmpty) { value.addr = new CcBool(true, false); } // no else required; false remains false; true remains true type = CcBool::BasicType(); } else { SecondoCatalog* sc = SecondoSystem::GetCatalog(); string name = input.substr(pos, endpos - pos + 1); if (!sc->IsObjectName(name)) { cout << name << " is not an object name" << endl; return false; } Word valuePart; bool defined; if (!sc->GetObject(name, valuePart, defined)) { cout << "object " << name << " could not be read" << endl; return false; } type = nl->ToString(sc->GetObjectTypeExpr(name)); if (type == "rect") { type = "region"; if (isEmpty) { value.addr = new Region(*((Rectangle<2>*)valuePart.addr)); ((Rectangle<2>*)valuePart.addr)->DeleteIfAllowed(); } else { Region rect(*((Rectangle<2>*)valuePart.addr)); ((Rectangle<2>*)valuePart.addr)->DeleteIfAllowed(); Region res(true); ((Region*)value.addr)->Union(rect, res); ((Region*)value.addr)->DeleteIfAllowed(); ((Region*)value.addr)->CopyFrom(&res); // ((Region*)value.addr)->Print(cout); cout << endl; } } else if (type == "region") { if (isEmpty) { value.addr = valuePart.addr; } else { Region res(true); ((Region*)value.addr)->Union(*((Region*)valuePart.addr), res); ((Region*)valuePart.addr)->DeleteIfAllowed(); ((Region*)value.addr)->CopyFrom(&res); } } else if (type == "line") { Region res(true); if (isEmpty) { Region emptyReg(true); emptyReg.Union(*((Line*)valuePart.addr), res); ((Line*)valuePart.addr)->DeleteIfAllowed(); value.addr = new Region(res); } else { ((Region*)value.addr)->Union(*((Line*)valuePart.addr), res); } } else if (type == "label") { if (isEmpty) { value.addr = new Labels(true); ((Labels*)value.addr)->Append(*((Label*)valuePart.addr)); ((Label*)valuePart.addr)->DeleteIfAllowed(); } else { ((Labels*)value.addr)->Append(*((Label*)valuePart.addr)); ((Label*)valuePart.addr)->DeleteIfAllowed(); } } else if (type == "labels") { if (isEmpty) { value.addr = valuePart.addr; } else { set labels; ((Labels*)valuePart.addr)->GetValues(labels); ((Labels*)value.addr)->Append(labels); } } else if (type == "place") { // TODO. } else if (type == "places") { // TODO. } else if (type == "interval") { if (isEmpty) { value.addr = new Range(true); ((Range*)value.addr)->Add((*(Interval*)valuePart.addr)); delete (Interval*)valuePart.addr; } else { orderCheckInsert((Range*)value.addr, *((Interval*)valuePart.addr)); delete (Interval*)valuePart.addr; } } else if (type == "bool") { if (isEmpty) { value.addr = valuePart.addr; } else { ((CcBool*)value.addr)->Set(true, ((CcBool*)value.addr)->GetValue() || ((CcBool*)valuePart.addr)->GetValue()); ((CcBool*)valuePart.addr)->DeleteIfAllowed(); } } else { cout << "type " << type << " is invalid" << endl; return false; } } pos = input.find_first_not_of(' ', endpos + 1); isEmpty = false; return true; } /* \subsection{Function ~checkAttrType~} */ bool Tools::checkAttrType(const string& typeName, const Word &value) { if (value.addr == 0) { return true; } else { if (typeName == "mlabel" || typeName == "mlabels") { return ((Labels*)value.addr)->IsDefined(); } else if (typeName == "mplace" || typeName == "mplaces") { return ((Places*)value.addr)->IsDefined(); } else if (typeName == "mpoint" || typeName == "mregion") { return ((Region*)value.addr)->IsDefined(); } else if (typeName == "mbool") { return ((CcBool*)value.addr)->IsDefined(); } else if (typeName == "mint" || typeName == "mreal") { return ((Range*)value.addr)->IsDefined(); } } cout << "invalid type " << typeName << endl; return false; } /* \subsection{Function ~isRelevantAttr~} */ bool Tools::isRelevantAttr(const string& name) { set relevantAttrTypes; relevantAttrTypes.insert("mbool"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mint"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mlabel"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mlabels"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mplace"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mplace"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mpoint"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mreal"); relevantAttrTypes.insert(relevantAttrTypes.end(), "mregion"); return relevantAttrTypes.find(name) != relevantAttrTypes.end(); } /* \subsection{Function ~isMovingAttr~} */ bool Tools::isMovingAttr(const ListExpr ttype, const int attrno) { if (!nl->HasLength(ttype, 2)) { return false; } if (attrno < 1 || attrno > nl->ListLength(nl->Second(ttype))) { return false; } if (!nl->HasLength(nl->Nth(attrno, nl->Second(ttype)), 2)) { return false; } return isRelevantAttr(nl->ToString(nl->Second(nl->Nth(attrno, nl->Second(ttype))))); } /* \subsection{Function ~getRelevantAttrs~} */ vector > Tools::getRelevantAttrs(TupleType *ttype, const int majorAttrNo, int& majorValueNo) { vector > result; SecondoCatalog* sc = SecondoSystem::GetCatalog(); for (int i = 0; i < ttype->GetNoAttributes(); i++) { AttributeType attrType = ttype->GetAttributeType(i); string typeName = sc->GetTypeName(attrType.algId, attrType.typeId); if (i == majorAttrNo) { majorValueNo = result.size(); } if (isRelevantAttr(typeName)) { result.push_back(make_pair(i, typeName)); } } return result; } /* \subsection{Function ~deleteValue~} */ void Tools::deleteValue(Word &value, const string &type) { if (value.addr == 0) { return; } if (type == "mlabel" || type == "mlabels") { ((Labels*)value.addr)->DeleteIfAllowed(); } else if (type == "mplace" || type == "mplaces") { ((Places*)value.addr)->DeleteIfAllowed(); } else if (type == "mpoint" || type == "mregion") { ((Region*)value.addr)->DeleteIfAllowed(); } else if (type == "mbool") { ((CcBool*)value.addr)->DeleteIfAllowed(); } else if (type == "mint" || type == "mreal") { ((Range*)value.addr)->DeleteIfAllowed(); } else { // cannot occur cout << "cannot delete invalid type " << type << endl; } } /* \subsection{Function ~timesMatch~} Checks whether the time interval ~uIv~ is completely enclosed by each of the intervals specified in ~ivs~. If ~ivs~ is empty, the result is ~true~. */ bool Tools::timesMatch(const Interval& iv, const set& ivs) { if (ivs.empty()) { return true; } bool elementOk(false); SecInterval pIv(true); for (set::iterator j = ivs.begin(); j != ivs.end(); j++) { if (((*j)[0] > 96) && ((*j)[0] < 123)) { // 1st case: semantic date/time elementOk = checkSemanticDate(*j, iv, true); } else if (((*j).find('-') == string::npos) // 2nd case: 19:09~22:00 && (((*j).find(':') < (*j).find('~')) // on each side of [~], || ((*j)[0] == '~')) // there has to be either xx:yy or nothing && (((*j).find(':', (*j).find('~')) != string::npos) || (*j)[(*j).size() - 1] == '~')) { elementOk = checkDaytime(*j, iv); } else { stringToInterval(*j, pIv); elementOk = pIv.Contains(iv); } if (!elementOk) { // all intervals have to match return false; } } return true; } /* \subsection{Function ~processQueryStr~} Invoked by ~initOpTrees~ and others. */ pair Tools::processQueryStr(string query, int type) { pair result; result.first = 0; result.second = 0; SecParser parser; string qParsed; ListExpr qList, rType; bool correct(false), evaluable(false), defined(false), isFunction(false); if (parser.Text2List(query, qParsed)) { cout << "Text2List(" << query << ") failed" << endl; return result; } if (!nl->ReadFromString(qParsed, qList)) { cout << "ReadFromString(" << qParsed << ") failed" << endl; return result; } result.first = new QueryProcessor(nl, am); try { result.first->Construct(nl->Second(qList), correct, evaluable, defined, isFunction, result.second, rType); } catch (...) { delete result.first; result.first = 0; result.second = 0; } if (!correct || !evaluable || !defined) { cout << "correct: " << (correct ? "TRUE" : "FALSE") << endl << "evaluable: " << (evaluable ? "TRUE" : "FALSE") << endl << "defined: " << (correct ? "TRUE" : "FALSE") << endl; delete result.first; result.first = 0; result.second = 0; return result; } if (nl->ToString(rType) != getDataType(type)) { if (nl->ToString(rType) != getDataType(-2)) { cout << "incorrect result type: " << nl->ToString(rType) << "; should be " << getDataType(type) << " or " << getDataType(-2) << endl; delete result.first; result.first = 0; result.second = 0; } } return result; } /* \subsection{Function ~evaluate~} The string ~input~ is evaluated by Secondo. The result is returned as a Word. */ // Word evaluate(string input) { // SecParser qParser; // string query, queryStr; // ListExpr queryList; // Word queryResult; // input.insert(0, "query "); // if (!qParser.Text2List(input, queryStr)) { // if (nl->ReadFromString(queryStr, queryList)) { // if (!nl->IsEmpty(nl->Rest(queryList))) { // query = nl->ToString(nl->First(nl->Rest(queryList))); // if (qp->ExecuteQuery(query, queryResult)) { // return queryResult; // } // } // } // } // return queryResult; // } bool Tools::createTransitions(const bool dortmund, map >& transitions) { if (dortmund) { map >::iterator im; set::iterator it; transitions["Aplerbeck"].insert("Hörde"); transitions["Aplerbeck"].insert("Innenstadt-Ost"); transitions["Aplerbeck"].insert("Brackel"); transitions["Brackel"].insert("Innenstadt-Nord"); transitions["Brackel"].insert("Innenstadt-Ost"); transitions["Brackel"].insert("Scharnhorst"); transitions["Eving"].insert("Huckarde"); transitions["Eving"].insert("Innenstadt-Nord"); transitions["Eving"].insert("Mengede"); transitions["Eving"].insert("Scharnhorst"); transitions["Hörde"].insert("Hombruch"); transitions["Hörde"].insert("Innenstadt-Ost"); transitions["Hombruch"].insert("Innenstadt-Ost"); transitions["Hombruch"].insert("Innenstadt-West"); transitions["Hombruch"].insert("Lütgendortmund"); transitions["Huckarde"].insert("Innenstadt-Nord"); transitions["Huckarde"].insert("Innenstadt-West"); transitions["Huckarde"].insert("Lütgendortmund"); transitions["Huckarde"].insert("Mengede"); transitions["Innenstadt-Nord"].insert("Innenstadt-Ost"); transitions["Innenstadt-Nord"].insert("Innenstadt-West"); transitions["Innenstadt-Nord"].insert("Scharnhorst"); transitions["Innenstadt-Ost"].insert("Innenstadt-West"); transitions["Innenstadt-West"].insert("Lütgendortmund"); for (im = transitions.begin(); im != transitions.end(); im++) { for (it = im->second.begin(); it != im->second.end(); it++) { transitions[*it].insert(im->first); // add symmetric transitions } transitions[im->first].insert(im->first); // remaining in the same area } } else { Word kreis, kreisrtree; bool defined; SecondoCatalog* sc = SecondoSystem::GetCatalog(); if (!sc->GetObject("Kreis", kreis, defined)) { cout << "Error: GetObject Kreis failed" << endl; return false; } if (!defined) { cout << "Error: object Kreis undefined" << endl; return false; } if (!sc->GetObject("Kreisrtree", kreisrtree, defined)) { cout << "Error: GetObject Kreisrtree failed" << endl; return false; } if (!defined) { cout << "Error: object Kreisrtree undefined" << endl; return false; } Relation *rel = (Relation*)(kreis.addr); R_Tree<2, TupleId> *rtree = (R_Tree<2, TupleId>*)(kreisrtree.addr); RelationIterator *it1 = new RelationIterator(*rel); Tuple *tuple1 = it1->GetNextTuple(); R_TreeLeafEntry<2, TupleId> leaf; Tuple *tuple2 = 0; while (tuple1) { string name1 = ((CcString*)(tuple1->GetAttribute(0)))->GetValue(); Region *r1 = (Region*)(tuple1->GetAttribute(4)); Rectangle<2> bbox = r1->BoundingBox(); if (rtree->First(bbox, leaf)) { tuple2 = rel->GetTuple(leaf.info, true); string name2 = ((CcString*)(tuple2->GetAttribute(0)))->GetValue(); transitions[name1.substr(3)].insert(name2.substr(3)); tuple2->DeleteIfAllowed(); while (rtree->Next(leaf)) { tuple2 = rel->GetTuple(leaf.info, true); string name2 = ((CcString*)(tuple2->GetAttribute(0)))->GetValue(); transitions[name1.substr(3)].insert(name2.substr(3)); tuple2->DeleteIfAllowed(); } } tuple1->DeleteIfAllowed(); tuple1 = it1->GetNextTuple(); } delete it1; delete rtree; delete rel; } return true; } /* \subsection{Function ~createLabelSequence~} Creates a vector of string containing either districts of Dortmund or German counties in a random but sensible order. */ bool Tools::createLabelSequence(const int size, const int number, const bool dortmund, map >& transitions, vector& result) { time_t t; time(&t); srand((unsigned int)t); map >::iterator im; set::iterator it; for (int i = 0; i < number; i++) { im = transitions.begin(); int choice = rand() % transitions.size(); advance(im, choice); string name = im->first; result.push_back(name); for (int j = 1; j < size; j++) { it = transitions[name].begin(); choice = rand() % transitions[name].size(); advance(it, choice); name = *it; result.push_back(name); } } return result.size() == (unsigned int)(size * number); } void Tools::printNfa(vector > &nfa, set &finalStates) { map::iterator it; for (unsigned int i = 0; i < nfa.size(); i++) { cout << (finalStates.count(i) ? " * " : " ") << "state " << i << ": "; for (it = nfa[i].begin(); it != nfa[i].end(); it++) { cout << "---" << it->first << "---> " << it->second << " "; } cout << endl << endl; } } void Tools::makeNFApersistent(vector > &nfa,set &finalStates, DbArray &trans, DbArray &s2p, map &state2Pat) { NFAtransition tr; map::iterator im; for (unsigned int i = 0; i < nfa.size(); i++) { tr.oldState = i; for (im = nfa[i].begin(); im != nfa[i].end(); im++) { tr.trigger = im->first; tr.newState = im->second; trans.Append(tr); } s2p.Append(state2Pat[i]); } } void Tools::createNFAfromPersistent(DbArray &trans, DbArray &s2p, vector > &nfa, set &finalStates) { nfa.clear(); finalStates.clear(); map emptymap; NFAtransition tr; for (int i = 0; i < trans.Size(); i++) { trans.Get(i, tr); while (tr.oldState >= (int)nfa.size()) { nfa.push_back(emptymap); } nfa[tr.oldState][tr.trigger] = tr.newState; } int pat = INT_MAX; for (int i = 1; i < s2p.Size(); i++) { s2p.Get(i, pat); if ((pat != INT_MAX) && (pat >= 0)) { finalStates.insert(i); } } } DistanceFunSym Tools::getDistanceFunSym(std::string funName) { std::transform(funName.begin(), funName.end(), funName.begin(), (int (*)(int))::tolower); if (funName == "equallabels") { return EQUALLABELS; } else if (funName == "prefix") { return PREFIX; } else if (funName == "suffix") { return SUFFIX; } else if (funName == "prefixsuffix") { return PREFIXSUFFIX; } else { return ERROR; } } bool Tools::getGeoFromORel(const std::string& relName, const unsigned int ref, const bool bbox, Word& geo, std::string& type) { if (ref == 0) { geo.addr = new Rectangle<2>(true); ((Rectangle<2>*)(geo.addr))->SetDefined(false); return true; } SecondoCatalog* sc = SecondoSystem::GetCatalog(); Word orelPtr; bool defined; if (!sc->GetObject(relName, orelPtr, defined)) { cout << "Error: cannot find relation 'Places'" << endl; return false; } if (!defined) { cout << "Error: relation 'Places' is undefined" << endl; return false; } OrderedRelation *orel = static_cast(orelPtr.addr); vector attributes(1); vector attrTypes(1); attrTypes[0] = SmiKey::Integer; attributes[0] = new CcInt(true, ref); CompositeKey fromKey(attributes, attrTypes, false); CompositeKey toKey(attributes, attrTypes, true); OrderedRelationIterator *rit = (OrderedRelationIterator*)orel->MakeRangeScan(fromKey, toKey); Tuple *pt = rit->GetNextTuple(); if (bbox) { geo.addr = pt->GetAttribute(5); type = Rectangle<2>::BasicType(); } else { if (pt->GetAttribute(1)->IsDefined()) { geo.addr = pt->GetAttribute(1)->Copy(); // point type = Point::BasicType(); } else if (pt->GetAttribute(2)->IsDefined()) { geo.addr = pt->GetAttribute(2)->Copy(); // line type = Line::BasicType(); } else if (pt->GetAttribute(3)->IsDefined()) { geo.addr = pt->GetAttribute(3)->Copy(); // region type = Region::BasicType(); } else { geo.addr = 0; cout << "Error: no defined geometry for reference " << ref << endl; } } ((CcInt*)attributes[0])->DeleteIfAllowed(); // pt->DeleteIfAllowed(); return (geo.addr != 0); } bool Tools::getRectFromOrel(const std::string& relName, const unsigned int ref, Rectangle<2>& box) { Word geo; std::string type; if (!getGeoFromORel(relName, ref, true, geo, type)) { return false; } box.CopyFrom((Rectangle<2>*)(geo.addr)); return true; } }