/* * 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.operator.ExecutionUnit; import com.rapidminer.operator.OperatorChain; import com.rapidminer.operator.OperatorDescription; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.UserError; import com.rapidminer.operator.ports.InputPorts; import com.rapidminer.operator.ports.MultiInputPortPairExtender; import com.rapidminer.operator.ports.MultiOutputPortPairExtender; import com.rapidminer.operator.ports.OutputPorts; import com.rapidminer.operator.ports.metadata.MDTransformationRule; import com.rapidminer.parameter.ParameterType; import com.rapidminer.parameter.ParameterTypeInt; /** This operator can be used to employ a single inner operator or operator chain. * Which operator should be used can be defined by the parameter "select_which". * Together with one of the parameter optimizing or iterating operators this operator * can be used to dynamically change the process setup which might be useful in order to * test different layouts, e.g. the gain by using different preprocessing steps or chains * or the quality of a certain learner. * * @author Ingo Mierswa */ public class OperatorSelector extends OperatorChain { /** The parameter name for "Indicates if the operator which inner operator should be used". */ public static final String PARAMETER_SELECT_WHICH = "select_which"; private final MultiOutputPortPairExtender inputExtender = new MultiOutputPortPairExtender("input", getInputPorts(), new OutputPorts[] { getSubprocess(0).getInnerSources(), getSubprocess(1).getInnerSources() }); private final MultiInputPortPairExtender outputExtender = new MultiInputPortPairExtender("output", getOutputPorts(), new InputPorts[] { getSubprocess(0).getInnerSinks(), getSubprocess(1).getInnerSinks() }); public OperatorSelector(OperatorDescription description) { super(description, "Selection 1", "Selection 2"); inputExtender.start(); outputExtender.start(); getTransformer().addRule(inputExtender.makePassThroughRule()); getTransformer().addRule(new MDTransformationRule() { @Override public void transformMD() { int operatorIndex = -1; try { operatorIndex = getParameterAsInt(PARAMETER_SELECT_WHICH) - 1; for (int i = 0; i < getNumberOfSubprocesses(); i++) { if (i != operatorIndex) { // skip selected and transform last, so it overrides everything getSubprocess(i).transformMetaData(); } } if ((operatorIndex >= 0) && (operatorIndex < getNumberOfSubprocesses())) { getSubprocess(operatorIndex).transformMetaData(); } } catch (Exception e) { } } }); getTransformer().addRule(outputExtender.makePassThroughRule()); } @Override public boolean areSubprocessesExtendable() { return true; } @Override protected ExecutionUnit createSubprocess(int index) { return new ExecutionUnit(this, "Selection"); } @Override public ExecutionUnit addSubprocess(int index) { ExecutionUnit newProcess = super.addSubprocess(index); inputExtender.addMultiPorts(newProcess.getInnerSources(), index); outputExtender.addMultiPorts(newProcess.getInnerSinks(), index); normalizeSubprocessNames(); return newProcess; } @Override public ExecutionUnit removeSubprocess(int index) { ExecutionUnit oldProcess = super.removeSubprocess(index); inputExtender.removeMultiPorts(index); outputExtender.removeMultiPorts(index); normalizeSubprocessNames(); return oldProcess; } private void normalizeSubprocessNames() { for (int i = 0; i < getNumberOfSubprocesses(); i++) { getSubprocess(i).setName("Selection " + (i+1)); } } @Override public void doWork() throws OperatorException { int operatorIndex = getParameterAsInt(PARAMETER_SELECT_WHICH); if ((operatorIndex < 1) || (operatorIndex > getNumberOfSubprocesses())) { throw new UserError(this, 207, new Object[] { operatorIndex, PARAMETER_SELECT_WHICH, "must be between 1 and the number of inner operators."} ); } inputExtender.passDataThrough(); getSubprocess(operatorIndex - 1).execute(); outputExtender.passDataThrough(operatorIndex - 1); } @Override public List<ParameterType> getParameterTypes() { List<ParameterType> types = super.getParameterTypes(); ParameterType type = new ParameterTypeInt(PARAMETER_SELECT_WHICH, "Indicates which inner operator should be currently employed by this operator on the input objects.", 1, Integer.MAX_VALUE, 1); type.setExpert(false); types.add(type); return types; } }