/*
* 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 .
/
/**
* SOURCE: test_ix.cc
*
* MODULE: test for RasDaMan tiles indexes
*
* PURPOSE:
* Compares RPTreeIx's to DirIx's
*
* COMMENTS:
* none
*
*/
#include "mymalloc/mymalloc.h"
#include
#include
#include
#include "o2lib_CC.hxx" // declaration of O2-collection-classes
#include // O2 Engine
#include // O2 error from O2 Engine
#include "dbmddobjix.hh"
#include "basetype.hh"
#include "chartype.hh"
#include "raslib/minterval.hh"
#include "raslib/sinterval.hh"
#include "cachetamgr/perstile.hh"
#include "tools/timer.hh"
#include "indexmgr/persdirix.hh"
#include "indexmgr/pershierix.hh"
#include "indexmgr/rptreeix.hh"
#include "indexmgr/dirix.hh"
#include "raslib/rmdebug.hh"
#include
// This test program must use a different base because it
// doesn't use catalogif and adminif. It is not a complete RasDaBase.
static char O2BenchDBName[] = "TestIxBase";
static char O2BenchSchemaName[] = "TestSMSchema";
extern char* myExecArgv0 = "";
unsigned maximumFill = 10;
#include "raslib/rminit.hh"
RMINITGLOBALS('C')
static void ClearDB( d_Database &DB );
// indexType 1 : R+ tree, 2: DirIx
static void testPopulateIx( int indexType,
const vector< r_Minterval >& tilesDoms );
// static void createTilesArr( Tile** tiles, float alignFactor, int numberTiles );
void testCompareIxs( );
void calculateGrid( const r_Minterval& baseTile,
const r_Minterval& gridDesc,
long& numberParts,
vector*& grid ); //r_Minterval*& grid );
static void testCompareIxs( char* index, char* index1,
MultiDimIx* ix, MultiDimIx* ix1,
r_Minterval* searchInts, int numInts);
float calculateAlignFactor( const vector& partition);
int isDisjunctive( const vector& parts );
void createTilesDomains( ofstream& outPopFile,
ofstream& outBMFile,
float alignFactor,
vector< r_Minterval >*& tgIntsVec,
int numberTiles,
unsigned dim );
int randomInsertion;
/*************************************************************
* Function name.: int main( int argc, char** argv)
*
* Arguments.....:
* argc: number of arguments given to program
* argv: array of char* with arguments
* Return value..: exit status
* Description...: none
************************************************************/
int
main( int argc, char** argv)
{
// variables representing O2 database, ta and session
d_Session session;
d_Database database;
d_Transaction ta;
if( argc < 4 ) {
cout << "Usage: test_ix [-r]" << endl;
return -1;
}
unsigned dim;
unsigned numberTiles;
float af;
dim = atoi( argv[1]);
numberTiles = atoi( argv[2]);
af = atof( argv[3] );
if ( dim < 2 || dim > 8 )
{
cout << " Error : dimensionality outside supported limits !" << endl;
return -1;
}
if ( numberTiles > 100000 || numberTiles < 50 )
{
cout << " Error : number of tiles outside supported limits !" << endl;
return -1;
}
if ( af < 0.05 || af > 1 )
{
cout << " Error : alignment fator outside supported limits !" << endl;
return -1;
}
if ( argc == 5 && strcmp(argv[4], "-r") == 0 )
randomInsertion = 1;
else
randomInsertion = 0;
cout << "Dimensionality " << dim << endl;
cout << "Number of Tiles " << numberTiles << endl;
cout << "Alignment factor " << af << endl;
cout << "RandomInsertion ";
if ( randomInsertion )
cout << " yes " << endl;
else
cout << " no " << endl;
/*
// initialize the O2 session
cout << "Initializing O2 session..." << endl;
session.set_default_env();
if (session.begin(argc, argv)){
cerr << "Something wrong to start o2" << endl;
exit(1);
}
// connect to the database
cout << "Connecting to database " << O2BenchDBName
<< "..." << endl;
try{
database.open( O2BenchDBName ); // doesn't work with O2 V.5
}
catch( ...)
{
cout << "Could not open database. Exiting "<< endl;
session.end();
return -1;
}
// create root collection
cout << "Checking root collection..." << endl;
ta.begin();
Handle collHandle = 0;
collHandle = o2_get_root((char*)"HierIndexContainer");
if (!collHandle)
{
cout << "Collection doesn't exist yet, creating collection ... "<< endl;
// if root name isn't used yet, create new root name for MDD collection
// I don't know if this is needed. It works without it.
o2_unref_handle( collHandle );
database.create_persistent_root( "HierIndexContainer",
"d_List>",
OL_CONSTANT);
}
else
{
cout << "Collection exists already, does nothing. "<< endl;
// if it exists already, doesn't do anything
// I don't know if this is needed. It works without it.
o2_unref_handle(collHandle);
}
*/
/*
int exists = 1;
try{
d_List< DBMDDObjIxId > indexList("HierIndexContainer");
}
catch( ...)
{
cout << "Persistent root does't exist" << endl;
exists =0;
}
if ( !exists )
database.create_persistent_root( "HierIndexContainer",
"d_List>",
OL_CONSTANT);
*/
// ta.commit();
vector< r_Minterval >* tgIntsVec;
char namePopFile[100];
char nameBMFile[100];
int afint = af*100;
if ( randomInsertion )
{
sprintf( namePopFile, "ix%dd%dn%dafrndpop.txt", dim, numberTiles, afint);
sprintf( nameBMFile, "ix%dd%dn%dafrnd.bm", dim, numberTiles, afint);
}
else
{
sprintf( namePopFile, "ix%dd%dn%dafpop.txt", dim, numberTiles, afint);
sprintf( nameBMFile, "ix%dd%dn%daf.bm", dim, numberTiles, afint);
}
cout << "namePopFile " << namePopFile << endl;
cout << "nameBMFile " << nameBMFile << endl;
ofstream ixStreamPopResults(namePopFile);
ofstream ixStreamBMResults(nameBMFile);
// system("/usr/bin/date
if ( !ixStreamPopResults || !ixStreamBMResults )
{
cout <<"Error: one file could not be openened" << endl;
return -1;
}
cout << "Dim " << dim << endl;
cout << "NTiles wanted " << numberTiles << endl;
cout << "AlignFactor wanted " << af << endl;
// numberTiles = 80 * i;
createTilesDomains( ixStreamPopResults, ixStreamBMResults, af, tgIntsVec, numberTiles, dim );
numberTiles = tgIntsVec->size( ); // integer arithmetic error
/*
cout << "Populating Index 1..." << endl;
ta.begin( );
testPopulateIx( 1, *tgIntsVec );
ta.commit( );
cout << "Populating Index 2..." << endl;
ta.begin( );
testPopulateIx( 2, *tgIntsVec );
ta.commit( );
delete tgIntsVec;
cout <<"Testing two indexes ..."<< endl;
ta.begin( );
testCompareIxs( );
ta.commit( );
cout << endl;
cout << "Ending O2 session..." << endl;
database.close();
session.end();
*/
ixStreamPopResults.close( );
ixStreamBMResults.close( );
return 0;
}
/*************************************************************************
*
*
************************************************************************/
void
testPopulateIx( int indexType, const vector< r_Minterval >& tilesDomains )
{
CharType anyType;
char* anyCells;
const int numberTiles = tilesDomains.size( );
const int dim = tilesDomains[1].dimension( );
cout << "....testPopulateIx"<< endl;
d_List< DBMDDObjIxId > indexList("HierIndexContainer");
PersDirIx* ix = new PersDirIx( dim, &anyType );
MultiDimIx< Tile >* rix;
cout << "Ix of type ";
switch( indexType )
{
case 1:
cout << "RPlusTree ";
rix = new RPlusTreeIx( ix, maximumFill );
break;
case 2:
cout << "DirIx ";
rix = new DirIx< PersDirIx, Tile >( ix );
break;
// to be extended
default:
cout <<"Error "<printStatus( );
Tile* tiles[100000];
for( int i = 0; i < tilesDomains.size( ); i++ )
{
anyCells = (char*)mymalloc(tilesDomains[i].cell_count() * anyType.getSize());
tiles[i] =
new PersTile( tilesDomains[i], (const BaseType*) &anyType, anyCells);
}
cout << endl;
for( i = 0; i < numberTiles ; i++ )
{
cout << endl << "Insert new tile " << i << " " << tiles[i]->getDomain( )<< endl;
rix->insertObject( tiles[i] );
// rix->printStatus( );
// cout << endl;
}
cout << endl << "Finished, index contents: " << endl;
rix->printStatus( );
cout << endl;
indexList.insert_element_last( ( (PersIx*) (rix->getIxDS( )) )->getDBMDDObjIxId( ) );
for( i = 0; i < numberTiles ; i++ )
delete tiles[i];
delete rix;
}
/*************************************************************************
*
*
************************************************************************/
void
calculateGrid( const r_Minterval& baseTile,
const r_Minterval& gridDesc,
long& numberParts,
vector< r_Minterval>*& grid ) // grid r_Minterval*& grid)
{
cout << "calculateGrid( " << baseTile << ", "<< gridDesc << ") "<< endl;
numberParts = gridDesc.cell_count( );
grid = new vector(numberParts); //new r_Minterval[numberParts];
r_Point ix( baseTile.dimension( ));
r_Point ext = baseTile.get_extent( );
for ( int i= 0; i < numberParts ; i++ )
{
ix = gridDesc.cell_point( i )* ext;
(*grid)[i] = baseTile.create_translation( ix );
// grid[i] = r_Minterval( baseTile.create_translation( ix ) );
}
}
/*************************************************************************
*
*
************************************************************************/
void
createTilesDomains( ofstream& outPopFile, // file for test_populate
ofstream& outBMFile, // file for benchmark
float alignFactor,
vector< r_Minterval >*& tgIntsVec,
int numberTiles,
unsigned dim )
{
if( alignFactor > 1 || alignFactor == 0 )
{
cout <<"Error: invalid alignment factor." << endl;
exit(0);
}
cout << "Alignment factor wanted " << alignFactor << endl;
cout << "Number of tiles, dim " << numberTiles << ", "<< dim << endl;
// number of partitions of the total grid
double ntgdouble = numberTiles/alignFactor;
// cout <<"Number of tiles in total grid (double)== " << ntgdouble << endl;
long ntg = ntgdouble;
cout <<"Number of tiles in total grid (long)== " << ntg << endl;
// r_Minterval* tgInts;
float f = float (1/ float(dim) );
long n = pow( ntg, f);
cout <<"Number of tiles in d-1 first directions (n) == " << n << endl;
r_Minterval tile(dim);
const unsigned tileLength = 5;
r_Minterval totalGrid( dim );
for (int i = 0; i < dim -1; i++ )
{
tile[i].set_interval( r_Range( 0 ), tileLength-1 );
totalGrid[i].set_interval( r_Range( 0 ), n-1 );
}
long n1 = pow(n,dim-1);
n1 = ntg/n1;
cout << "Number of tiles in direction d (n1) == " << n1 << endl;
tile[dim-1].set_interval( r_Range( 0 ), tileLength-1 );
totalGrid[dim-1].set_interval( r_Range( 0 ), n1-1 );
long ntg1;
calculateGrid( tile, totalGrid, ntg1, tgIntsVec );
if ( ntg1 < numberTiles )
{
cout <<"Error: number of partitions in total grid less than numberTiles";
cout <<"Exiting the program (integer arithmetic)"<< endl;
// exit(0);
}
if ( ntg1 != ntg )
{
cout << "Warning: number of partitions in total grid is not as expected " << endl;
cout << "Alignment factor won't be as expected (integer arithmetic)"<< endl;
}
cout << endl;
//tgIntsVec = new vector< r_Minterval >( tgInts, tgInts+ntg1 );
// delete tgInts; // ????
cout << "Number of tiles in total grid " << ntg1 << endl;
/*
for( i =0; i < tgIntsVec->size( ); i++ )
cout << "Interval "<< i << (*tgIntsVec)[i] <size( ) );
// merge randomly
int notFinished = 1;
int contr = 1;
for( int ri = 0; contr && cont ; ri++)
{
notFinished = 1;
int init = rand( ) % tgIntsVec->size( );
for( int j = init; notFinished ; )
{
// cout <<"i,j"<< i <<","<< j<erase( tgIntsVec->begin( ) + r );
if ( i % 100 == 0 )
{
if ( r < j )
cout << (*tgIntsVec)[j-1] <size( );
if ( j == init )
notFinished = 0;
}
// cout << " r == " << r << ", j == " << j << " , notFinished == " << notFinished << endl;
// cout << " ri == " << ri << " , tgIntsVec->size( ) " << tgIntsVec->size( ) << endl;
r = (r+1) % tgIntsVec->size( );
if ( found )
contr = 0; // already found
else
{
if ( ri >= tgIntsVec->size( ) )
cont = 0; // no more merges possible
else
r = (r+1) % tgIntsVec->size( );
}
}
}
cout << "======================================================="<< endl;
cout << "Results : "<< endl;
cout << " Alignement Factor wanted :" << alignFactor << endl;
cout << " Number of Resulting Tiles " << tgIntsVec->size( ) << endl;
cout << " Resulting Tiles " << endl;
unsigned ntilesObta = tgIntsVec->size( );
cout << "NTiles obtained " << ntilesObta << endl;
float faObta = float ( tgIntsVec->size( ))/ntg1;
cout <<" Alignment factor obtained "<< faObta << endl;
/*
* Benchmark file format:
* Dim \t ntiles \t af \t random \t h \t occ
*/
outBMFile << dim << "\t";
outBMFile << ntilesObta << "\t";
outBMFile << faObta << "\t";
if ( randomInsertion )
outBMFile <<"1\t";
else
outBMFile << "0\t";
// Visual_Tiling_2D visTil( dom, "TilesImage");
/*
* Pop file format:
* Database: BmarkIxBase
*
* MDDColl: Ix2D_1000N_5AF_Set; Char2DSet
*
* MDDObj: [ 0:*, 0:*] ; Char2D
*
* HowToStore:
* IndexType: R+TreeIx
*/
char collName[100];
char collTypeName[100];
char mddTypeName[100];
int faInt = faObta*100;
if ( randomInsertion )
sprintf( collName, "Ix%dD_%dN_%dAF_RND_Set", dim, ntilesObta, faInt);
else
sprintf( collName, "Ix%dD_%dN_%dAF_Set", dim, ntilesObta, faInt);
r_Minterval dom( dim );
for ( int d = 0; d < dim; d++ )
dom[d].set_interval((r_Range)0,'*');
sprintf( collTypeName, "Char%dDSet", dim);
sprintf( mddTypeName, "Char%dD", dim );
outPopFile << "Database: BmarkIxBase " << endl << endl;
outPopFile << "MDDColl: " << collName << "; " << collTypeName << endl<< endl;
outPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
outPopFile << "HowToStore:" << endl;
outPopFile << "IndexType: R+TreeIx " << endl << endl;
if ( randomInsertion )
{
unsigned vecSz = tgIntsVec->size( );
vector< r_Minterval >* tgIntsVec2;
tgIntsVec2 = new vector(vecSz);
unsigned tix = i;
for( i = 0; i < vecSz; i++ )
{
tix = rand( ) % tgIntsVec->size( );
outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[tix] << "; 0x0000" << endl;
(*tgIntsVec2)[i] = (*tgIntsVec)[tix];
tgIntsVec->erase( tgIntsVec->begin( ) + tix );
}
vector< r_Minterval >* tmpIntsVec;
tmpIntsVec = tgIntsVec;
tgIntsVec = tgIntsVec2;
delete tmpIntsVec;
}
else
{
for( i = 0; i < tgIntsVec->size( ); i++ )
{
outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[i] << "; 0x0000" << endl;
}
}
/* For debugging purposes:
if( !isDisjunctive( *tgIntsVec ))
{
cout <<"Error: Nondisjunctive partition, exiting program "<< endl;
exit( 0);
}
else cout <<" Disjunctive partition OK " << endl;
*/
if( tgIntsVec->size( ) != numberTiles )
{
cout <<"Error: tgIntsVec->size( ) != numberTiles "<< endl;
// exit( 0);
}
// calculateAlignFactor( tgIntsVec );
}
/*************************************************************************
*
*
************************************************************************/
/*
void
createTilesArr( Tile** tiles,
float alignFactor,
vector< r_Minterval >* tgIntsVec )
{
ULongType anyType;
char* anyCells;
for( i = 0; i < tgIntsVec->size( ); i++ )
{
anyCells = (char*)malloc(tilesDomains[i].cell_count() * anyType.getSize());
tiles[i] =
new PersTile( (*tgIntsVec)[i], (const BaseType*) &anyType, anyCells);
}
}
*/
/*************************************************************************
*
*
************************************************************************/
float
calculateAlignFactor( const vector& part )
{
float fa;
// for ( int i = 0; i < part.size( ); i++ ) ;
return fa;
}
/*************************************************************************
*
*
************************************************************************/
int isDisjunctive( const vector& parts )
{
for( int i = 0; i < parts.size( ); i++ )
{
r_Minterval inter = parts[i];
for( int j = i+1; j < parts.size( ); j++ )
{
if( inter.intersects_with( parts[j] ))
return 0;
}
}
return 1;
}
/*************************************************************
* Function name.:
* void
* testCompareIxs( char* index, char* index1, )
*
* Arguments.....:
* index : name of first index
* index1: name of second index
*
************************************************************/
void
testCompareIxs( )
{
DBMDDObjIxId accessedIndex;
CharType anyType;
// char anyCell[4];
cout << "....testCompareIxs"< indexList("HierIndexContainer");
// used for iterating
d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
MultiDimIx< Tile >* ix = 0;
MultiDimIx< Tile >* ix1 = 0;
PersIx* dix;
PersIx* dix1;
for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
{
accessedIndex = indexIt.get_element();
cout << " --"<printStatus();
if (accessedIndex->isRoot( ) && accessedIndex->isLeaf( ) )
{
// to avoid mem leaks in repeated executions of this test program
if ( ix1 ) delete ix1;
cout << endl << "Creating DirIx ... ";
dix1 = new PersDirIx( accessedIndex, (const BaseType*) &anyType );
ix1 = new DirIx< PersDirIx, Tile >( (PersDirIx*)dix1 );
}
else
{
// to avoid mem leaks in repeated executions of this test program
if ( ix ) delete ix;
cout << endl << "Creating R+-tree ... ";
dix = new PersHierIx( accessedIndex, (const BaseType*) &anyType );
ix = new RPlusTreeIx( dix,maximumFill );
}
cout << endl;
}
cout <<"OK"<* ix, MultiDimIx* ix1,
r_Minterval* searchInts, int numInts)
{
cout << "....testCompareIxs"<< endl;
//ULongType anyType;
// char anyCell[4];
cout << "Comparison of Index " << index << endl;
cout << "with Index1 " << index1 << endl;
for( int i = 0; i < numInts; i++ )
{
Timer time; Timer time1;
RMTimer* rtime = new RMTimer( index, "intersect" );
RMTimer* rtime1 = new RMTimer( index1, "intersect" );
cout << "Intersect with "<< searchInts[i] << endl;
// Index
time.start( ); rtime->start( );
vector< Tile* >* rqResult = ix->intersect( searchInts[i] );
int num, num1;
rtime->stop( ); time.stop( );
if ( rqResult )
{
num = rqResult->size( );
cout << index << endl << " No. of tiles, time , time/noTiles = "
<< rqResult->size( ) << " , "<< time << " , ";
if ( rqResult->size( ) ) cout << time.ellapsed_sec( )/rqResult->size( ) << endl;
}
else
{
cout << "No tiles intersected "<< endl;
num = 0;
}
delete rtime;
// Index 1
time1.start( ); rtime1->start( );
vector< Tile* >* rqResult1 = ix1->intersect( searchInts[i] );
rtime1->stop( ); time1.stop( );
if ( rqResult1 )
{
num1 = rqResult1->size( );
cout << index1 << endl << " No. of tiles, time1, time1/noTiles = "
<< rqResult1->size( ) << " , "<< time1 << " , ";
if ( rqResult1->size( ) ) cout << time1.ellapsed_sec( )/rqResult1->size( ) << endl;
}
else
{
cout << "No tiles intersected "<< endl;
num1 = 0;
}
delete rtime1;
if ( num != num1 )
cout << "Error !!!!" << endl;
// Index
cout << "Result " << index << endl;
if ( rqResult )
{
for( int j = 0; j < rqResult->size( ); j++)
{
cout << ( *rqResult )[j]->getDomain( ) << endl;
delete (*rqResult)[j];
}
delete rqResult;
}
// Index1
cout << "Result " << index1 << endl;
if ( rqResult1 )
{
for( int j = 0; j < rqResult1->size( ); j++)
{
cout << ( *rqResult1 )[j]->getDomain( ) << endl;
delete (*rqResult1)[j];
}
delete rqResult1;
}
cout << endl;
}
}