/* * 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.operator.meta; import java.util.List; import com.rapidminer.example.ExampleSet; import com.rapidminer.operator.IOContainer; import com.rapidminer.operator.OperatorDescription; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.performance.PerformanceVector; import com.rapidminer.operator.ports.InputPort; import com.rapidminer.parameter.ParameterType; import com.rapidminer.parameter.ParameterTypeBoolean; import com.rapidminer.parameter.ParameterTypeCategory; import com.rapidminer.parameter.ParameterTypeDouble; import com.rapidminer.parameter.ParameterTypeInt; import com.rapidminer.parameter.conditions.BooleanParameterCondition; /** * Performs its inner operators until all given criteria are met or a timeout * occurs. * * @author Stefan Rueping */ public class RepeatUntilOperatorChain extends AbstractIteratingOperatorChain { /** The parameter name for "Minimal number of attributes in first example set" */ public static final String PARAMETER_MIN_ATTRIBUTES = "min_attributes"; /** The parameter name for "Maximal number of attributes in first example set" */ public static final String PARAMETER_MAX_ATTRIBUTES = "max_attributes"; /** The parameter name for "Minimal number of examples in first example set" */ public static final String PARAMETER_MIN_EXAMPLES = "min_examples"; /** The parameter name for "Maximal number of examples in first example set" */ public static final String PARAMETER_MAX_EXAMPLES = "max_examples"; /** The parameter name for "Minimal main criterion in first performance vector" */ public static final String PARAMETER_MIN_CRITERION = "min_criterion"; /** The parameter name for "Maximal main criterion in first performance vector" */ public static final String PARAMETER_MAX_CRITERION = "max_criterion"; /** The parameter name for "Maximum number of iterations" */ public static final String PARAMETER_MAX_ITERATIONS = "max_iterations"; public static final String PARAMETER_LIMIT_TIME = "limit_time"; /** The parameter name for "Timeout in minutes (-1 = no timeout)" */ public static final String PARAMETER_TIMEOUT = "timeout"; /** The parameter name for "Stop when performance of inner chain behaves like this." */ public static final String PARAMETER_PERFORMANCE_CHANGE = "performance_change"; /** The parameter name for "Evaluate condition before inner chain is applied (true) or after?" */ public static final String PARAMETER_CONDITION_BEFORE = "condition_before"; public static final String[] COMPARISONS = { "none", "decreasing", "non-increasing" }; public static final int NONE = 0; public static final int DECREASING = 1; public static final int NONINCREASING = 2; private long stoptime; private double fitness; private final InputPort performanceConditionInput = getSubprocess(0).getInnerSinks().createPort("performance", PerformanceVector.class); private final InputPort exampleSetConditionInput = getSubprocess(0).getInnerSinks().createPort("example set", ExampleSet.class); public RepeatUntilOperatorChain(OperatorDescription description) { super(description); } @Override public void doWork() throws OperatorException { stoptime = Long.MAX_VALUE; if (getParameterAsBoolean(PARAMETER_LIMIT_TIME)) stoptime = System.currentTimeMillis() + 60L * 1000 * getParameterAsInt(PARAMETER_TIMEOUT); fitness = Double.NEGATIVE_INFINITY; super.doWork(); } /** Evaluates whether the stopping condition is met * @throws OperatorException */ private boolean evaluateCondition(IOContainer input) throws OperatorException { if ((getIteration() == 0) && (!getParameterAsBoolean(PARAMETER_CONDITION_BEFORE))) { return false; } int maxit = getParameterAsInt(PARAMETER_MAX_ITERATIONS); if (getIteration() >= maxit) { getLogger().fine("Maximum number of iterations met."); return true; }; if (java.lang.System.currentTimeMillis() > stoptime) { getLogger().fine("Runtime exceeded."); return true; }; // NOTE: This is not optional PerformanceVector performanceVector = performanceConditionInput.getData(); int changeType = getParameterAsInt(PARAMETER_PERFORMANCE_CHANGE); if (changeType != NONE) { if (getIteration() > 0) { double currentFitness = performanceVector.getMainCriterion().getFitness(); if ((changeType == DECREASING) && (currentFitness < fitness)) { return true; } else if ((changeType == NONINCREASING) && (currentFitness <= fitness)) { return true; } fitness = currentFitness; } } double maxCrit = getParameterAsDouble(PARAMETER_MAX_CRITERION); double minCrit = getParameterAsDouble(PARAMETER_MIN_CRITERION); if ((maxCrit < Double.POSITIVE_INFINITY) || (minCrit > Double.NEGATIVE_INFINITY)) { double crit = performanceVector.getMainCriterion().getAverage(); if ((crit > maxCrit) || (crit < minCrit)) return false; } ExampleSet exampleSet = exampleSetConditionInput.getData(); int maxAtts = getParameterAsInt(PARAMETER_MAX_ATTRIBUTES); int minAtts = getParameterAsInt(PARAMETER_MIN_ATTRIBUTES); if ((maxAtts < Integer.MAX_VALUE) || (minAtts > 0)) { int nrAtts = exampleSet.getAttributes().size(); if ((nrAtts > maxAtts) || (nrAtts < minAtts)) return false; } int maxEx = getParameterAsInt(PARAMETER_MAX_EXAMPLES); int minEx = getParameterAsInt(PARAMETER_MIN_EXAMPLES); if ((maxEx < Integer.MAX_VALUE) || (minEx > 0)) { int nrEx = exampleSet.size(); if ((nrEx > maxEx) || (nrEx < minEx)) return false; } getLogger().fine("All criteria met."); return true; } @Override boolean shouldStop(IOContainer iterationResults) throws OperatorException { return evaluateCondition(iterationResults); } @Override public List<ParameterType> getParameterTypes() { List<ParameterType> types = super.getParameterTypes(); ParameterType type = new ParameterTypeInt(PARAMETER_MIN_ATTRIBUTES, "Minimal number of attributes in first example set", 0, Integer.MAX_VALUE, 0); type.setExpert(false); types.add(type); type = new ParameterTypeInt(PARAMETER_MAX_ATTRIBUTES, "Maximal number of attributes in first example set", 0, Integer.MAX_VALUE, 0); type.setExpert(false); types.add(type); type = new ParameterTypeInt(PARAMETER_MIN_EXAMPLES, "Minimal number of examples in first example set", 0, Integer.MAX_VALUE, 0); type.setExpert(false); types.add(type); type = new ParameterTypeInt(PARAMETER_MAX_EXAMPLES, "Maximal number of examples in first example set", 0, Integer.MAX_VALUE, Integer.MAX_VALUE); type.setExpert(false); types.add(type); type = new ParameterTypeDouble(PARAMETER_MIN_CRITERION, "Minimal main criterion in first performance vector", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY); type.setExpert(false); types.add(type); type = new ParameterTypeDouble(PARAMETER_MAX_CRITERION, "Maximal main criterion in first performance vector", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); type.setExpert(false); types.add(type); type = new ParameterTypeInt(PARAMETER_MAX_ITERATIONS, "Maximum number of iterations", 0, Integer.MAX_VALUE, Integer.MAX_VALUE); type.setExpert(true); types.add(type); type = new ParameterTypeBoolean(PARAMETER_LIMIT_TIME, "If checked, the loop will be aborted at last after a specified time.", false); types.add(type); type = new ParameterTypeInt(PARAMETER_TIMEOUT, "Timeout in minutes", 1, Integer.MAX_VALUE, 1); type.registerDependencyCondition(new BooleanParameterCondition(this, PARAMETER_LIMIT_TIME, true, true)); type.setExpert(true); types.add(type); type = new ParameterTypeCategory(PARAMETER_PERFORMANCE_CHANGE, "Stop when performance of inner chain behaves like this. 'none' means to ignore any performance changes.", COMPARISONS, NONE); type.setExpert(false); types.add(type); type = new ParameterTypeBoolean(PARAMETER_CONDITION_BEFORE, "Evaluate condition before inner chain is applied (true) or after?", true); type.setExpert(true); types.add(type); return types; } }