/**
* Copyright (c) 2006-2009, NEPOMUK Consortium
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the NEPOMUK Consortium nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**/
package processing.folkrank;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** The FactReaderPreprocessor reads the facts from the FactReader and
* returns a FolkRankData object. For more information on how this is done
* have a look at the {@link #process()} method.
*
* @author rja
*/
public class FactReaderFactPreprocessor implements FactPreprocessor {
private FolkRankData facts = null;
private FactReader reader;
private String[][] stringPrefItems = null;
private int[][] intPrefItems = null;
private boolean storeInverseMapping = false;
/** Initialize the preprocessor with a reader.
*
* @param reader - the reader which supplies the preprocessor with facts.
*/
public FactReaderFactPreprocessor (final FactReader reader) {
this.reader = reader;
}
public FactReaderFactPreprocessor (final FactReader reader, boolean storeInverseMapping) {
this.reader = reader;
this.storeInverseMapping = storeInverseMapping;
}
/** Process the data the reader returns. This is done by doing the following
* steps:
* <ul>
* <li>initalize a map to map strings to integers for every mode</li>
* <li>initalize a list to store the facts as integers</li>
* <li>iterate over the fact list from the reader and
* <ul>
* <li>add a mapping (string to integer) to the map, if neccessary</li>
* <li>add the fact to integer fact list</li>
* </ul>
* </li>
* <li>copy integer fact list into an array</li>
* <li>generate inverse mapping (integer to tring)</li>
* </ul>
*
* @see org.semanticdesktop.nepomuk.comp.folkpeer.folkrank.process.FactPreprocessor#process()
*/
public void process() {
try {
int noOfDimensions = reader.getNoOfDimensions();
/*
* Initialize the map for the string->integer mapping.
* This map stores for each dimension, which integer an item gets
* assigned.
*/
@SuppressWarnings("unchecked")
final Map<String, Integer> [] mapping = new HashMap[noOfDimensions];
for (int dim = 0; dim < mapping.length; dim++) {
mapping[dim] = new HashMap<String, Integer>();
}
/*
* Initialize integer fact list. This list is used to temporarily
* store the fact list in memory before copying it into an array.
*
* The reason for doing this is, that the number of facts is unknown
* and it may not be possible to read the same facts twice by using
* reset() from the fact reader.
*
*/
List<int[]> factList = new LinkedList<int []>();
/*
* Initialize mapping counters (save current integer for each
* dimension).
*/
int noOfItemsPerDimension[] = new int[noOfDimensions];
Arrays.fill(noOfItemsPerDimension, 0);
/*
* generate mapping and integer fact list
*/
while (reader.hasNext()) {
/*
* for every fact
*/
final String[] stringFact = reader.getFact();
int[] intFact = new int[noOfDimensions];
for (int dim = 0; dim < stringFact.length; dim++) {
/*
* get item for this dimension
*/
final String item = stringFact[dim];
/*
* map new item
*/
if (!mapping[dim].containsKey(item)) {
mapping[dim].put(item, noOfItemsPerDimension[dim]);
noOfItemsPerDimension[dim]++;
}
/*
* save new item in fact
*/
intFact[dim] = mapping[dim].get(item);
}
/*
* store fact
*/
factList.add(intFact);
}
reader.close();
/*
* copy fact list into array
*/
int noOfFacts = factList.size();
facts = new FolkRankData (noOfFacts, noOfItemsPerDimension);
for (int factId = 0; factId < noOfFacts; factId++) {
facts.setFact(factId, factList.remove(0));
}
factList.clear();
/*
* map preference items strings to integers
*/
if (stringPrefItems != null) {
intPrefItems = new int[stringPrefItems.length][];
for (int dim = 0; dim < stringPrefItems.length; dim++) {
intPrefItems[dim] = new int[stringPrefItems[dim].length];
for (int item = 0; item < stringPrefItems[dim].length; item++) {
intPrefItems[dim][item] = mapping[dim].get(stringPrefItems[dim][item]);
}
}
}
/*
* invert mapping and put it into array
*/
for (int dim = 0; dim < mapping.length; dim++) {
final Iterator<String> it = mapping[dim].keySet().iterator();
while (it.hasNext()) {
String key = it.next();
facts.addMapping(dim, mapping[dim].get(key), key);
// delete mapping, if neccessary
if (!storeInverseMapping) it.remove();
}
/*
* store mapping, if neccessary
*/
if (storeInverseMapping) {
facts.addInverseMapping(dim, mapping[dim]);
} else {
mapping[dim].clear();
}
}
} catch (FactReadingException e) {
/*
* TODO: implement proper exception handling
*/
e.printStackTrace();
}
}
/** Returns the filled data for the FolkRank.
* @see org.semanticdesktop.nepomuk.comp.folkpeer.folkrank.process.FactPreprocessor#getFolkRankData()
*/
public FolkRankData getFolkRankData() {
return facts;
}
/** Sets the preference items in string representation such that a
* subsequent call to {@link #process()} will map them to integers.
* @see org.semanticdesktop.nepomuk.comp.folkpeer.folkrank.process.FactPreprocessor#setPrefItems(java.lang.String[][])
*/
public void setPrefItems(String[][] prefItems) {
this.stringPrefItems = prefItems;
}
/** Returns the integer representation of the preference items.
* @see org.semanticdesktop.nepomuk.comp.folkpeer.folkrank.process.FactPreprocessor#getPrefItems()
*/
public int[][] getPrefItems() {
return intPrefItems;
}
}