/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.indexStructures;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
import xxl.core.indexStructures.Descriptor;
import xxl.core.io.converters.DoubleConverter;
import xxl.core.io.converters.IntegerConverter;
import xxl.core.io.converters.MeasuredConverter;
import xxl.core.util.Interval1D;
/** This class provides several static methods which are useful for
* for preparing tests of indexstructures.
*/
public class Tests {
/** The name of the working directory.
*/
public static final String WORK_DIR_NAME="d:\\Benutzer\\tests.old";
/** It makes the program wait for an input from the user.
*/
public static void waitForUser() {
try {
System.out.print("Please, press a key to continue!");
//while(System.in.read()!=13);
System.in.read();
System.in.skip(System.in.available());
} catch (IOException e) {
e.printStackTrace();
}
}
/** Creates random <tt>nr</tt> keys from <tt>[low, high[</tt>
* and stores thme into the file with the given file
* name. In the file each key lies in a separate line.
*
* @param fileName the name of the file into which the created keys have to be stored
* @param nr the number of the keys which have to be created
* @param low the minimal bound of key range
* @param high the maximal bound of the key range
* @throws IOException
*/
public static void createKeys(String fileName, int nr, int low, int high) throws IOException {
List keys= new LinkedList();
for(int i=low; i<high; i++) keys.add(new Integer(i));
Random r= new Random();
while(keys.size()>nr) {
int i=r.nextInt(keys.size());
keys.remove(i);
}
for(int i=0; i<2*nr; i++) {
int k= r.nextInt(keys.size());
int l= r.nextInt(keys.size()-1);
Integer Kk= (Integer)keys.remove(k);
Integer Kl= (Integer)keys.remove(l);
keys.add(l, Kk);
keys.add(k, Kl);
}
OutputStream output= new BufferedOutputStream(new FileOutputStream(fileName));
PrintStream out=new PrintStream(output);
for(int i=0; i<keys.size(); i++) out.println(keys.get(i));
output.flush();
output.close();
}
/** For each interval [k, l[ of <tt>[low, low+jump[, [low+jump, low+2jump[, ..., [low+(n-1)jump, low+n*jump[,</tt> where n
* is the greatest integer so that <tt>n*jump</tt> is smaller than high, creates randomly keys by calling the
* the method {@link #createKeys(String fileName, int nr, int k, int l)}. The <tt>fileName</tt> is
* <tt>WORK_DIR_NAME+"/Keys"+k+"_"+l+".test"</tt> and <tt>nr</tt> equals <tt>2*(l-k)/3</tt>.
*
* @param low the minimal bound of key range
* @param high the maximal bound of the key range
* @param jump the length of the intervals
* @throws IOException
*/
public static void createKeys(int low, int high, int jump) throws IOException {
int nr=2*jump/3;
for(int i=low; i<high; i+=jump) {
String fileName= WORK_DIR_NAME+"/Keys"+i+"_"+(i+jump)+".test";
createKeys(fileName, nr, i, i+jump);
}
}
/** It is equivalent to:
* <pre><code>
createKeys(0, high, 1000);
</code></pre>
*
* @param high the maximal bound of the key range
* @throws IOException
*/
public static void createKeys(int high) throws IOException {
createKeys(0, high, 1000);
}
/** Merges the contents of all given files randomly and add simultaneously
* an "incom" component for each key (personal number) (see {@link Tests.Employee}).
* The result is written into the file with the given file name
* <tt>fileName</tt>.
*
* @param keysFiles files containig the keys
* @param fileName the name of the result file
* @throws IOException
*/
public static void makeInsertTestFile(String[] keysFiles, String fileName) throws IOException {
Random r1= new Random();
Random r2= new Random();
BufferedReader[] br=new BufferedReader[keysFiles.length];
for(int i=0; i<br.length; i++) br[i]=new BufferedReader(new FileReader(keysFiles[i]));
OutputStream output= new BufferedOutputStream(new FileOutputStream(fileName));
PrintStream out=new PrintStream(output);
while(true) {
int f=r1.nextInt(br.length);
int f1=f;
boolean begin=true;
String s=null;
while(s==null && (begin || f1!=f)) {
s=br[f1].readLine();
f1=(f1+1)%br.length;
begin=false;
}
if(s==null) break;
int persNr= Integer.parseInt(s);
double incom= r2.nextDouble();
incom=(int)(1000000*incom)/100;
out.println(persNr+" "+incom);
}
output.flush();
output.close();
for(int i=0; i<br.length; i++) br[i].close();
}
/** Gives the names of the files which were created at last by calling the method
* {@link Tests#createKeys(int low, int high, int jump)}.
*
* @param low the minimal bound of key range
* @param high the maximal bound of the key range
* @param jump the length of the intervals
* @return an <tt>Array</tt> containig the file names
*/
public static String[] getKeysFiles(int low, int high, int jump) {
String[] keysFiles= new String[(high-low)/jump];
int i=0;
for(int l=low; l<high; l+=jump) keysFiles[i++]= WORK_DIR_NAME+"/Keys"+l+"_"+(l+jump)+".test";
return keysFiles;
}
/** Is equivalent to:
* <pre><code>
getKeysFiles(0, high, 1000);
</code></pre>
* @param high the maximal bound of the key range
* @return an <tt>Array</tt> containig the file names
*/
public static String[] getKeysFiles(int high) {
return getKeysFiles(0, high, 1000);
}
public static void main(String[] args) throws IOException {
if(args.length!=1) {
System.out.println("A method to create test data for index structure tests.");
System.out.println("Usage: Tests high");
System.out.println("high= the upper bound of the keys, which are to create.");
}
createKeys(Integer.parseInt(args[0]));
System.out.println("End");
}
/**
* A class to represent the data objects which are stored in an index structure.
* An <tt>Employee</tt> has a unique personal number and incom.
*/
public static class Employee implements Comparable {
private static byte[] data = new byte[0];
public static void setDataSize(int size) {
data = new byte[size];
}
public static int getDataSize() {
return data.length;
}
/** This <tt>Function</tt> is used to extract the key component (persNr) of the data object.
*/
public static final Function getKey = new AbstractFunction() {
public Object invoke(Object data) {
return new Integer(((Employee)data).getPersNr());
}
};
/** A default <tt>Converter</tt> to serialize the data objects.
*/
public static final MeasuredConverter DEFAULT_CONVERTER = new MeasuredConverter() {
public Object read(DataInput input, Object object) throws IOException {
int nr = IntegerConverter.DEFAULT_INSTANCE.readInt(input);
double incom = DoubleConverter.DEFAULT_INSTANCE.readDouble(input);
input.readFully(Employee.data);
return new Employee(nr,incom);
}
public void write(DataOutput output, Object object) throws IOException {
Employee data = (Employee) object;
IntegerConverter.DEFAULT_INSTANCE.writeInt(output, data.persNr);
DoubleConverter.DEFAULT_INSTANCE.writeDouble(output,data.incom);
output.write(Employee.data);
}
public int getMaxObjectSize() {
return IntegerConverter.SIZE + DoubleConverter.SIZE + Employee.data.length;
}
};
public static Function<Employee,Descriptor> getDescriptor = new AbstractFunction<Employee,Descriptor> () {
public Descriptor invoke (Employee employee) {
return new Interval1D(employee.getPersNr());
}
public Descriptor invoke (Employee from, Employee to) {
return new Interval1D(from.getPersNr(), to.getPersNr());
}
};
/*
public static int getMaxObjectSize() {
return IntegerConverter.SIZE + DoubleConverter.SIZE;
}
public static int getMaxKeySize() {
return IntegerConverter.SIZE;
}
*/
/**
* A <tt>Converter</tt> to serialize the keys of the data objects.
*/
public static final MeasuredConverter KEY_CONVERTER= new MeasuredConverter() {
public Object read(DataInput input, Object object) throws IOException {
return IntegerConverter.DEFAULT_INSTANCE.read(input, null);
}
public void write(DataOutput output, Object object) throws IOException {
IntegerConverter.DEFAULT_INSTANCE.write(output, (Integer)object);
}
public int getMaxObjectSize() {
return IntegerConverter.SIZE;
}
};
/** A unique personal number (key).
*/
private int persNr;
/** The income of the employee.
*/
private double incom;
/** Creates a new Employee.
*
* @param nr the peronal number of the employee
* @param incom the incom of the employee
*/
protected Employee(int nr, double incom) {
this.incom=incom;
persNr=nr;
}
/** Gives the personal number of this <tt>Employee</tt>.
*
* @return the personal number of this <tt>Employee</tt>
*/
public int getPersNr() {
return persNr;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return persNr;
}
/** Checks whether two <tt>Employees</tt> are the same,
* i.e. they have the same personal number.
*
* @param data the second <tt>Employee</tt>
* @return <tt>true</tt> if the employees have the same personal number,
* <tt>false</tt> otherwise
*/
public boolean equals(Object data) {
return persNr==((Employee)data).persNr;
}
public int compareTo(Object obj) {
return ((Integer)this.persNr).compareTo((Integer)((Employee)obj).persNr);
}
/** Converts this <tt>Employee</tt> to a String to display it.
*
* @return the String display of this <tt>Employee</tt>
*/
public String toString() {
return "\""+persNr+", "+incom+"\"";
}
}
}