/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.example.table;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import com.rapidminer.example.Attribute;
import com.rapidminer.tools.Ontology;
/**
* This class is used to create and clone attributes. It should be used to
* create attributes instead of directly creating them by using constructors.
* Additionally, it provides some helper methods for attribute creation purposes
* (name creation, block numbers,...).
*
* @author Ingo Mierswa
* Exp $
*/
public class AttributeFactory {
/** The prefix of the name of generated attributes. */
private static final String GENSYM_PREFIX = "gensym";
/**
* The current highest id counters for generated attribute names. The counter will be increased each time an
* attribute name is generated more than once.
*/
private static Map<String,AtomicInteger> nameCounters = new HashMap<String,AtomicInteger>();
static {
resetNameCounters();
}
/** Creates a simple single attribute depending on the given value type. */
public static Attribute createAttribute(String name, int valueType) {
String attributeName = (name != null) ? new String(name) : createName(); // we copy the name if the underlying char array value is larger than needed
if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.DATE_TIME)) {
return new DateAttribute(attributeName, valueType);
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.BINOMINAL)) {
return new BinominalAttribute(attributeName);
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.NOMINAL)) {
return new PolynominalAttribute(attributeName, valueType);
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.NUMERICAL)) {
return new NumericalAttribute(attributeName, valueType);
} else {
throw new RuntimeException("AttributeFactory: cannot create attribute with value type '" + Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(valueType) + "' (" + valueType + ")!");
}
}
/**
* Creates a simple single attribute depending on the given value type. The
* name is randomly created. This attribute can also be used for generators
* to define their desired input attributes for compatibility checks.
*/
public static Attribute createAttribute(int valueType) {
return createAttribute(createName(), valueType);
}
/** Creates a simple attribute depending on the given value type. */
public static Attribute createAttribute(int valueType, int blockType, String constructionDescription) {
Attribute attribute = createAttribute(valueType);
attribute.setBlockType(blockType);
attribute.setConstruction(constructionDescription);
return attribute;
}
/** Creates a simple attribute depending on the given value type. */
public static Attribute createAttribute(String name, int valueType, int blockType) {
Attribute attribute = createAttribute(name, valueType);
attribute.setBlockType(blockType);
return attribute;
}
// ================================================================================
/**
* Simple clone factory method for attributes. Invokes
* {@link #createAttribute(Attribute att, String name)} with name = null.
*/
public static Attribute createAttribute(Attribute attribute) {
return createAttribute(attribute, null);
}
/**
* Simple clone factory method for attributes. Returns the clone of the
* given attribute and sets the function name to the given one if not null.
* In this case the attribute is used as an argument of returned attribute.
* This method might be usefull for example to create a prediction attribute
* with the same properties as the original label attribute.
*/
public static Attribute createAttribute(Attribute attribute, String functionName) {
Attribute result = (Attribute) attribute.clone();
if (functionName == null) {
result.setName(attribute.getName());
} else {
result.setName(functionName + "(" + attribute.getName() + ")");
result.setConstruction(functionName + "(" + attribute.getName() + ")");
}
return result;
}
// ================================================================================
// changes the value type of the given attribute
// ================================================================================
/**
* Changes the value type of the given attribute and returns a new attribute
* with the same properties but the new value type. Since values within examples are
* not altered it is not suggested to use this method to change attributes within an
* exampleset in use. Operators should create a new attribute to ensure parallel executability.
*/
public static Attribute changeValueType(Attribute attribute, int valueType) {
Attribute result = createAttribute(attribute.getName(), valueType);
if (attribute.isNominal() && result.isNominal())
result.setMapping(attribute.getMapping());
result.setTableIndex(attribute.getTableIndex());
return result;
}
// ================================================================================
// helper methods
// ================================================================================
/** Resets the counters for the generated attribute names. */
public static void resetNameCounters() {
nameCounters.clear();
}
/** Creates a new unsused attribute name. */
public static String createName() {
return createName(GENSYM_PREFIX);
}
/** Creates a new unsused attribute name with a given prefix. */
public static String createName(String prefix) {
AtomicInteger counter = nameCounters.get(prefix);
if (counter == null) {
nameCounters.put(prefix, new AtomicInteger(1));
return prefix;
} else {
return prefix + counter.getAndIncrement();
}
}
}