/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . */ /************************************************************* * * * PURPOSE: * * * COMMENTS: * - QtScale is expected to have rounding errors with >1 tiles * - shift, extend, scale release input tiles only at end; this * shouldbe optimized (release immediately after evaluating) * - why is this file called "binary"? all ops have just one MDD! * - QtShift(), QtExtend() deliver for >1 tiles under PG an error * "libpq 'select' did not yield 1 result but 0" * which however does not seem to affect the result. * ************************************************************/ static const char rcsid[] = "@(#)qlparser, QtMintervalSelect, QtShift: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtbinaryfunc.cc,v 1.37 2005/09/03 20:17:55 rasdev Exp $"; #include "mymalloc/mymalloc.h" #include "mymalloc/mymalloc.h" #include "qlparser/qtbinaryfunc.hh" #include "qlparser/qtdata.hh" #include "qlparser/qtintervaldata.hh" #include "qlparser/qtmintervaldata.hh" #include "qlparser/qtatomicdata.hh" #include "qlparser/qtmdd.hh" #include "qlparser/qtpointdata.hh" #include "mddmgr/mddobj.hh" #include "tilemgr/tile.hh" #include "raslib/rmdebug.hh" #include "raslib/dlist.hh" #include #ifndef CPPSTDLIB #include // STL #else #include using namespace std; #endif // --- QtShift -------------------------------------------------- const QtNode::QtNodeType QtShift::nodeType = QT_SHIFT; QtShift::QtShift( QtOperation* mddOp, QtOperation* pointOp ) : QtBinaryOperation( mddOp, pointOp ) { } bool QtShift::isCommutative() const { return false; // NOT commutative } QtData* QtShift::evaluate( QtDataList* inputList ) { RMDBCLASS( "QtShift", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; QtData* operand1 = NULL; QtData* operand2 = NULL; // evaluate sub-nodes to obtain operand values if( getOperands( inputList, operand1, operand2 ) ) { // // This implementation simply creates a new transient MDD object with the new // domain while copying the data. Optimization of this is left for future work. // QtMDD* qtMDDObj = (QtMDD*)operand1; const r_Point& transPoint = ((QtPointData*)operand2)->getPointData(); MDDObj* currentMDDObj = qtMDDObj->getMDDObject(); if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() ) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtShift::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl; parseInfo.setErrorNo(407); throw parseInfo; } // compute new domain r_Minterval destinationDomain( qtMDDObj->getLoadDomain().create_translation( transPoint ) ); // create a transient MDD object for the query result MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), destinationDomain ); // get all tiles vector* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() ); // iterate over source tiles for( vector::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ ) { // get relevant area of source tile r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() ); // compute translated tile domain r_Minterval destinationTileDomain = sourceTileDomain.create_translation( transPoint ); // create a new transient tile, copy the transient data, and insert it into the mdd object // FIXME: how can this work without tile area allocation??? -- PB 2005-jun-19 Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() ); newTransTile->copyTile( destinationTileDomain, *tileIter, sourceTileDomain ); resultMDD->insertTile( newTransTile ); } // create a new QtMDD object as carrier object for the transient MDD object returnValue = new QtMDD( (MDDObj*)resultMDD ); // delete the tile vector, the tiles itself are deleted when the destructor // of the MDD object is called delete tiles; tiles=NULL; // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); } return returnValue; } void QtShift::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtShift Object " << getNodeType() << endl; QtBinaryOperation::printTree( tab, s, mode ); } void QtShift::printAlgebraicExpression( ostream& s ) { s << "shift("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << ","; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } void QtShift::optimizeLoad( QtTrimList* trimList ) { RMDBCLASS( "QtShift", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ ) QtNode::QtTrimList *list1=NULL, *list2=NULL; if( input1 && input2 ) { QtNode::QtTrimList::iterator iter; // // The result of input2 has to be a constant expression. // // shift of trimList is just possible, if no open bounds are available bool openBounds = false; for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ ) openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed()); if( openBounds ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; RMInit::logOut << "Error: QtShift::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl; parseInfo.setErrorNo(409); throw parseInfo; } QtData* operand = input2->evaluate(NULL); if( !operand ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand of shift function must be a constant expression." << endl; parseInfo.setErrorNo(408); throw parseInfo; } if( operand->getDataType() != QT_POINT ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; operand->deleteRef(); RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand must be of type Point." << endl; parseInfo.setErrorNo(406); throw parseInfo; } // get transPoint const r_Point& transPoint = ((QtPointData*)operand)->getPointData(); // shift trim elements by -transPoint for( iter=trimList->begin(); iter!=trimList->end(); iter++ ) { QtTrimElement* elem = *iter; if( elem->dimension <= transPoint.dimension() ) elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] ); } // point is not needed anymore operand->deleteRef(); input1->optimizeLoad( trimList ); } else { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; } } const QtTypeElement& QtShift::checkType( QtTypeTuple* typeTuple ) { RMDBCLASS( "QtShift", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ ) dataStreamType.setDataType( QT_TYPE_UNKNOWN ); // check operand branches if( input1 && input2 ) { // get input types const QtTypeElement& inputType1 = input1->checkType( typeTuple ); const QtTypeElement& inputType2 = input2->checkType( typeTuple ); if( inputType1.getDataType() != QT_MDD ) { RMInit::logOut << "Error: QtShift::checkType() - first operand must be of type MDD." << endl; parseInfo.setErrorNo(405); throw parseInfo; } if( inputType2.getDataType() != QT_POINT ) { RMInit::logOut << "Error: QtShift::checkType() - second operand must be of type Point." << endl; parseInfo.setErrorNo(406); throw parseInfo; } // pass MDD type dataStreamType = inputType1; } else RMInit::logOut << "Error: QtShift::checkType() - operand branch invalid." << endl; return dataStreamType; } // --- QtExtend -------------------------------------------------- const QtNode::QtNodeType QtExtend::nodeType = QT_EXTEND; QtExtend::QtExtend( QtOperation* mddOp, QtOperation* mintervalOp ) : QtBinaryOperation( mddOp, mintervalOp ) { } bool QtExtend::isCommutative() const { return false; // NOT commutative } QtData* QtExtend::evaluate( QtDataList* inputList ) { RMDBCLASS( "QtExtend", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; // operation result QtData* operand1 = NULL; // 1st operand: MDD expression QtData* operand2 = NULL; // 2nd operand: Minterval expression vector completeAreaList; // list of tiles comprising the whole area (possibly with holes); needed for 1-code below if( getOperands( inputList, operand1, operand2 ) ) { // // This implementation simply creates a single new transient MDD object with the new // domain while copying the data. // FIXME: create a tiled object // QtMDD* qtMDDObj = (QtMDD*)operand1; // object to be extended r_Minterval targetDomain = ((QtMintervalData*)operand2)->getMintervalData(); // new domain of extended object MDDObj* currentMDDObj = qtMDDObj->getMDDObject(); // precondition checks (we call the MDD C and the Minterval M): // - dim(C) == dim(M) if( targetDomain.dimension() != qtMDDObj->getLoadDomain().dimension() ) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl; parseInfo.setErrorNo(407); throw parseInfo; } // - M does not contain open bounds (i.e., "*") if( ! targetDomain.is_origin_fixed() || ! targetDomain.is_high_fixed() ) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - target domain must not have open bounds." << endl; parseInfo.setErrorNo(420); throw parseInfo; } // - M.subset( sdom(C) ); can we relieve this? if( ! targetDomain.covers( qtMDDObj->getLoadDomain() ) ) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - new interval does not cover MDD to be extended." << endl; parseInfo.setErrorNo(421); throw parseInfo; } // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - extending MDD with basetype " << currentMDDObj->getMDDBaseType() << " and load domain " << qtMDDObj->getLoadDomain() << " to domain " << targetDomain << endl; // create a transient MDD object for the query result MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain ); // --- 1: put all existing tiles into their place ------------------------ // get all tiles vector* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() ); // iterate over source tiles // Note that source and target MDD have the same coordinate basis for( vector::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ ) { // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - load domain is " << qtMDDObj->getLoadDomain() << endl; // get relevant area of source tile r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() ); Tile* newTransTile = new Tile( sourceTileDomain, currentMDDObj->getCellType() ); // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding source part " << sourceTileDomain << " of tile " << (*tileIter)->getDomain() << endl; newTransTile->copyTile( sourceTileDomain, *tileIter, sourceTileDomain ); resultMDD->insertTile( newTransTile ); // needed for 2-code below // completeAreaList.push_back( newTransTile ); // needed for 1-code below } // --- 2: fill up new space with null values ----------------------------- #if 0 // this 1-code does the same thing as the 2-code, but easier & more efficiently -- PB 2005-jun-24 // INCOMPLETE! // create minimal (1x1) tiles at origin and high end, but only if the source domain isn't there if (targetDomain.get_origin() != qtMDDObj->getLoadDomain().get_origin()) { RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at origin." << endl; -> Tile* originTile = new Tile( origin..origin+1 , currentMDDObj->getCellType() ); extendDomainList.push_back( originTile ); } if (targetDomain.get_high() != qtMDDObj->getLoadDomain().get_high()) { RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at high." << endl; -> Tile* highTile = new Tile( high-1..high, currentMDDObj->getCellType() ); extendDomainList.push_back( highTile ); } // merge all tiles into one & free not-used-any-longer stuff Tile* completeTile = new Tile( extendDomainList ); delete[] extendDomainList; resultMDD->insertTile( completeTile ); delete completeTile; #else // 2-code; unused -- PB 2005-jun-24 // the part below does the trick explicitly, leading to a larger number of result tiles. // establish list of domains vector extendDomainList; // inspect 2*d lower/upper neighbours // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2*d lower/upper neighbours, dimension is " << targetDomain.dimension() << endl; for (r_Dimension d=0; dgetLoadDomain().get_origin()[d]) { // this domain is identical to original MDD except for dim d where it is left of original r_Minterval lowerNeighbour = qtMDDObj->getLoadDomain(); lowerNeighbour[d] = r_Sinterval( targetDomain.get_origin()[d], qtMDDObj->getLoadDomain().get_origin()[d]-1 ); // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding lower neighbour domain " << lowerNeighbour << endl; extendDomainList.push_back( lowerNeighbour ); } // is there any space right of original MDD; ie, has MDD been extended right? if (targetDomain.get_high()[d] > qtMDDObj->getLoadDomain().get_high()[d]) { // this domain is identical to original MDD except for dim d where it is right of original r_Minterval upperNeighbour = qtMDDObj->getLoadDomain(); upperNeighbour[d] =r_Sinterval( qtMDDObj->getLoadDomain().get_high()[d]+1, targetDomain.get_high()[d] ); // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding upper neighbour domain " << upperNeighbour << endl; extendDomainList.push_back( upperNeighbour ); } } // inspect 2^d corner points // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2^d corner neighbours, dimension is " << targetDomain.dimension() << endl; r_Minterval cornerBoxDomain = r_Minterval( targetDomain.dimension() ); QtExtend::extendGetCornerTiles( targetDomain, qtMDDObj->getLoadDomain(), 0, targetDomain.dimension(), cornerBoxDomain, &extendDomainList ); // merge where possible to minimize tile number // ...just an optimization, tbd later // create tiles for all domains found // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - creating " << extendDomainList.size() << " tiles..." << endl; for( vector::iterator domainIter = extendDomainList.begin(); domainIter != extendDomainList.end(); domainIter++ ) { // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): creating tile for domain " << (*domainIter) << endl; Tile* newTransTile = new Tile( *domainIter, currentMDDObj->getCellType() ); resultMDD->insertTile( newTransTile ); } #endif 0 // --- 3: package into MDD object & finalize ----------------------------- // create a new QtMDD object as carrier object for the transient MDD object returnValue = new QtMDD( (MDDObj*)resultMDD ); // delete the tile vector, the tiles itself are deleted when the destructor // of the MDD object is called delete tiles; tiles=NULL; // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); // temporary: dump result tile // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - result tile = " << newTransTile->printStatus() << endl; // newTransTile->printStatus(99,RMInit::logOut); } // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - done." << endl; return returnValue; } #if 1 // needed for 1-code above -- PB 2005-jun-24 /** aux function for QtExtend::evaluate(): build up (recursing the dimension) a list of all spatial domains that sit in the corners between outerDomain and innerDomain; at the recursion bottom the resulting domain is added to the cornerList. **/ void QtExtend::extendGetCornerTiles( r_Minterval outerDomain, r_Minterval innerDomain, const r_Dimension currentDim, const r_Dimension maxDim, r_Minterval currentInterval, vector* cornerList ) { // RMInit::logOut << "QtExtend::extendGetCornerTiles( " << outerDomain << ", " << innerDomain << ", " << currentDim << ", " << maxDim << ", " << currentInterval << ", _ ) start" << endl; // not yet addressed all dimensions in the current coordinate? // note: what about 1D? 0D? if (currentDim < maxDim) { // add domain's lower end, continue building up the minterval // ...but only if the area is nonempty if (outerDomain.get_origin()[currentDim] < innerDomain.get_origin()[currentDim]) { // make local working copy r_Minterval extendedInterval( currentInterval ); // add i-th coordinate to domain, up to (but excluding) innerDomain extendedInterval[currentDim] = r_Sinterval( outerDomain.get_origin()[currentDim], innerDomain.get_origin()[currentDim]-1 ); // inspect next dimension // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for lower end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl; extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList ); } // add domain's upper end, continue building up the minterval if (innerDomain.get_high()[currentDim] < outerDomain.get_high()[currentDim]) { // make local working copy r_Minterval extendedInterval( currentInterval ); // add i-th coordinate to domain, starting from (but excluding) innerDomain extendedInterval[currentDim] = r_Sinterval( innerDomain.get_high()[currentDim]+1, outerDomain.get_high()[currentDim] ); // inspect next dimension // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for upper end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl; extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList ); } } else if (currentDim > maxDim) { // this is an error, see preconditions RMInit::logOut << "QtExtend::extendGetCornerTiles(): error: dimension overflow." << endl; } else // then we've reached currentDim==maxDim { // add this minterval to the tile domain list cornerList->push_back( currentInterval ); // RMInit::logOut << "QtExtend::extendGetCornerTiles(): added " << currentInterval << " to tile domain list." << endl; } // RMInit::logOut << "QtExtend::extendGetCornerTiles() done." << endl; } #endif 1 void QtExtend::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtExtend Object " << getNodeType() << endl; QtBinaryOperation::printTree( tab, s, mode ); } void QtExtend::printAlgebraicExpression( ostream& s ) { s << "extend("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << ","; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } void QtExtend::optimizeLoad( QtTrimList* trimList ) { RMDBCLASS( "QtExtend", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ ) QtNode::QtTrimList *list1=NULL, *list2=NULL; if( input1 && input2 ) { #if 0 // not yet sure what to do -- PB 2005-06-18 QtNode::QtTrimList::iterator iter; // // The result of input2 has to be a constant expression. // // shift of trimList is just possible, if no open bounds are available bool openBounds = false; for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ ) openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed()); if( openBounds ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; RMInit::logOut << "Error: QtExtend::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl; // XXX need new error code parseInfo.setErrorNo(409); throw parseInfo; } QtData* operand = input2->evaluate(NULL); if( !operand ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand of extend function must be a constant expression." << endl; // XXX correct new error code parseInfo.setErrorNo(408); throw parseInfo; } if( operand->getDataType() != QT_MINTERVAL ) { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; operand->deleteRef(); RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand must be of type Minterval." << endl; // XXX correct new error code parseInfo.setErrorNo(406); throw parseInfo; } // get extend target domain const r_Minterval& targetDomain = ((QtPointData*)operand)->getMintervalData(); // shift trim elements by -transPoint // XXX replace with extend() code for( iter=trimList->begin(); iter!=trimList->end(); iter++ ) { QtTrimElement* elem = *iter; if( elem->dimension <= transPoint.dimension() ) elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] ); } // point is not needed anymore operand->deleteRef(); #endif 0 // not yet sure what to do -- PB 2005-06-18 input1->optimizeLoad( trimList ); } else { // release( trimList->begin(), trimList->end() ); for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ ) { delete *iter; *iter=NULL; } delete trimList; trimList=NULL; } } const QtTypeElement& QtExtend::checkType( QtTypeTuple* typeTuple ) { RMDBCLASS( "QtExtend", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ ) dataStreamType.setDataType( QT_TYPE_UNKNOWN ); // check operand branches if( input1 && input2 ) { // get input types const QtTypeElement& inputType1 = input1->checkType( typeTuple ); const QtTypeElement& inputType2 = input2->checkType( typeTuple ); if( inputType1.getDataType() != QT_MDD ) { RMInit::logOut << "Error: QtExtend::checkType() - first operand must be of type MDD." << endl; parseInfo.setErrorNo(405); throw parseInfo; } if( inputType2.getDataType() != QT_MINTERVAL ) { RMInit::logOut << "Error: QtExtend::checkType() - second operand must be of type Minterval." << endl; parseInfo.setErrorNo(422); throw parseInfo; } // pass MDD type dataStreamType = inputType1; } else RMInit::logOut << "Error: QtExtend::checkType() - operand branch invalid." << endl; return dataStreamType; } // --- QtScale -------------------------------------------------- const QtNode::QtNodeType QtScale::nodeType = QT_SCALE; QtScale::QtScale( QtOperation* mddOp, QtOperation* pointOp ) : QtBinaryOperation( mddOp, pointOp ) { } bool QtScale::isCommutative() const { return false; // NOT commutative } #include #include // this define was used during testing, we had a problem inline double FLOOR(double a) { return floor(a); } QtData* QtScale::evaluate( QtDataList* inputList ) { RMDBCLASS( "QtScale", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ ) QtData* returnValue = NULL; QtData* operand1 = NULL; QtData* operand2 = NULL; if(!getOperands( inputList, operand1, operand2 ) ) return returnValue; QtMDD* qtMDDObj = (QtMDD*)operand1; MDDObj* currentMDDObj = qtMDDObj->getMDDObject(); vector scaleVector(0); scaleVector = vector( qtMDDObj->getLoadDomain().dimension() ); r_Minterval sourceDomain = qtMDDObj->getLoadDomain(); r_Minterval targetDomain; r_Point origin1 = sourceDomain.get_origin(); r_Point origin2 = qtMDDObj->getMDDObject()->getCurrentDomain().get_origin(); r_Minterval wishedTargetDomain; r_Point translation; //used for scale with wishedIv bool isWishedTargetSet = false; r_Double sourceRange=0., targetRange=0., f=0., Tl=0., Th=0.; switch( operand2->getDataType() ) { case QT_POINT: { const r_Point& transPoint = ((QtPointData*)operand2)->getPointData(); if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() ) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl; parseInfo.setErrorNo(418); throw parseInfo; } for( int i=0; igetUnsignedValue();; } break; case QT_OCTET: case QT_SHORT: case QT_LONG: { for( int i=0; igetSignedValue();; } break; case QT_DOUBLE: case QT_FLOAT: { RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scaling: " << ((QtAtomicData*)operand2)->getDoubleValue() ) for( int i=0; igetDoubleValue(); } break; case QT_MINTERVAL: { wishedTargetDomain = ((QtMintervalData*)operand2)->getMintervalData(); isWishedTargetSet=true; if( wishedTargetDomain.dimension() != sourceDomain.dimension()) { // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl; parseInfo.setErrorNo(418); throw parseInfo; } for( int i=0; i"<"<: "<"<getDataType()); break; } // ---------------------------------------------------------- #ifdef RMANDEBUG RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale vector : " ) for( int i=0; ideleteRef(); if( operand2 ) operand2->deleteRef(); RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - empty result after scaling." << endl; parseInfo.setErrorNo(419); throw parseInfo; } RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Dummy target domain: " << targetDomain << endl ) if(isWishedTargetSet) { translation = wishedTargetDomain.get_origin() - targetDomain.get_origin(); targetDomain.translate(translation); } // create a transient MDD object for the query result MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain ); //********************** origin1 = r_Point(scaleVector.size()); // all zero!! //********************** // get all tiles vector* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() ); //tile domain before & after r_Minterval sourceTileDomain, destinationTileDomain; // // Algorithm A: Scale each Tile // // iterate over source tiles for( vector::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ ) { // get relevant area of source tile sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() ); // compute scaled tile domain and check if it exists if( (*tileIter)->scaleGetDomain( sourceTileDomain, scaleVector, destinationTileDomain) ) { RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Destination tile domain: " << destinationTileDomain << endl ) // create a new transient tile Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() ); newTransTile->execScaleOp( *tileIter, sourceTileDomain, origin1, scaleVector ); if(isWishedTargetSet) ((r_Minterval&)newTransTile->getDomain()).translate(translation); resultMDD->insertTile( newTransTile ); } } // create a new QtMDD object as carrier object for the transient MDD object returnValue = new QtMDD( (MDDObj*)resultMDD ); // delete the tile vector, the tiles itself are deleted when the destructor // of the MDD object is called delete tiles; tiles=NULL; // delete the old operands if( operand1 ) operand1->deleteRef(); if( operand2 ) operand2->deleteRef(); return returnValue; } void QtScale::printTree( int tab, ostream& s, QtChildType mode ) { s << SPACE_STR(tab).c_str() << "QtScale Object " << getNodeType() << endl; QtBinaryOperation::printTree( tab, s, mode ); } void QtScale::printAlgebraicExpression( ostream& s ) { s << "scale("; if( input1 ) input1->printAlgebraicExpression( s ); else s << ""; s << ","; if( input2 ) input2->printAlgebraicExpression( s ); else s << ""; s << ")"; } void QtScale::optimizeLoad( QtTrimList* trimList ) { RMDBCLASS( "QtScale", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ ) // by default, pass load domain to input1 if( input1 ) input1->optimizeLoad( trimList ); else { delete trimList; trimList=NULL; } } const QtTypeElement& QtScale::checkType( QtTypeTuple* typeTuple ) { RMDBCLASS( "QtScale", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ ) dataStreamType.setDataType( QT_TYPE_UNKNOWN ); // check operand branches if( input1 && input2 ) { // get input types const QtTypeElement& inputType1 = input1->checkType( typeTuple ); const QtTypeElement& inputType2 = input2->checkType( typeTuple ); if( inputType1.getDataType() != QT_MDD ) { RMInit::logOut << "Error: QtScale::checkType() - first operand must be of type MDD." << endl; parseInfo.setErrorNo(416); throw parseInfo; } if( inputType2.getDataType() != QT_POINT && inputType2.getDataType() != QT_MINTERVAL && inputType2.getDataType() != QT_FLOAT && inputType2.getDataType() != QT_DOUBLE && !inputType2.isInteger() ) { RMInit::logOut << "Error: QtScale::checkType() - second operand must be either of type Point, Integer or Float." << endl; parseInfo.setErrorNo(417); throw parseInfo; } // pass MDD type dataStreamType = inputType1; } else RMInit::logOut << "Error: QtScale::checkType() - operand branch invalid." << endl; return dataStreamType; } int QtScale::scaleDomain( const r_Minterval& areaOp, const vector& scaleFactors, r_Minterval &areaScaled ) { RMDBGENTER( 2, RMDebug::module_qlparser, "QtScale", "scaleDomain( D: " << areaOp << ", F: " << scaleFactors << ", D: " << areaScaled << " )" ) try { areaScaled = areaOp.create_scale(scaleFactors); } catch(r_Error) { //error scaling RMInit::logOut << "Error: QtScale::scaleDomain() - exception while determining scale target interval for " << areaOp << " and " << scaleFactors << endl; return 0; } RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaleDomain(...) D: " << areaOp << " mapped to D: " << areaScaled ) return 1; } // origin1 von getLoadDomain // origin2 von getCurrentDomain int QtScale::scaleDomain( const r_Minterval& areaOp, const r_Point& origin1, const r_Point& origin2, const vector& scaleFactors, r_Minterval &areaScaled ) { RMDBGENTER( 2, RMDebug::module_qlparser, "QtScale", "scaleDomain( D: " << areaOp << ", O1: " << origin1 << ", O2: " << origin2 << ", F: " << scaleFactors << " D: " << areaScaled << " )" ) r_Minterval tempIv=areaOp; //reverse_translated with origin1 tempIv.reverse_translate(origin1); //scale it normaly if(!scaleDomain(tempIv, scaleFactors, areaScaled)) return 0; //translate areaScaled to origin2 areaScaled.translate(origin2); RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaledDomain(...) D: " << areaOp << " translated to D: " << areaScaled ) return 1; }