lascer.WekaClassifier.java Source code

Java tutorial

Introduction

Here is the source code for lascer.WekaClassifier.java

Source

/*
 * Dateiname      : WekaClassifier.java
 * Letzte nderung: 02. Juni 2009
 * Autoren        : Dietmar Lippold
 * Copyright (C)  : Dietmar Lippold, 2007
 *
 * This file is part of Lascer (http://lascer.berlios.de/).
 *
 * Lascer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Lascer 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Lascer; if not, see <http://www.gnu.org/licenses/>.
 */

package lascer;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.Vector;
import java.util.Enumeration;
import java.io.StringReader;

import weka.core.OptionHandler;
import weka.core.Option;
import weka.core.Instance;
import weka.core.Instances;
import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;

import de.unistuttgart.commandline.ParameterParser;

import lascer.problemdaten.AttributSammlung;
import lascer.problemdaten.Beispiel;
import lascer.problemdaten.Beispieldaten;
import lascer.problemdaten.ArffDateiEinlesen;
import lascer.konzepte.Konzept;
import lascer.konzepte.KonzeptErzeugungFacade;
import lascer.konzepte.einzelne.Disjunktion;
import lascer.konzepte.einzelne.Konjunktion;

/**
 * Classifier for Weka by using Lascer.<P>
 *
 * ATTENTION: When using the standard package of weka, all integer attributes
 * are handled as real attributes.
 *
 * @author  Dietmar Lippold
 */
public class WekaClassifier extends Classifier implements OptionHandler {

    /**
     * Die Revision der Software.
     */
    public static final String REVISION = "1.0.*";

    /**
     * Der Parser fr die Kommandozeilen-Parameter.
     */
    private ParameterParser parser;

    /**
     * Der Datensatz, zu dem der Klassifizierer der positiven Beispiele
     * erzeugt wurde.
     */
    private Beispieldaten posDatensatz = null;

    /**
     * Der Datensatz, zu dem der Klassifizierer der negativen Beispiele
     * erzeugt wurde.
     */
    private Beispieldaten negDatensatz = null;

    /**
     * Eine Liste der Attribute des Datensatzes vom Typ
     * <CODE>weka.coreExtended.Attribute</CODE>.
     */
    private LinkedList attributListe = null;

    /**
     * Die zu den positiven Beispielen erzeugte Formel.
     */
    private Konzept posFormel = null;

    /**
     * Die zu den negativen Beispielen erzeugte Formel.
     */
    private Konzept negFormel = null;

    /**
     * Die Nummer der Klasse <EM>true</EM> im <CODE>Instances</CODE>-Objekt
     * von Weka. Wird in Methode <CODE>buildClassifier</CODE> gesetzt.
     */
    private double wekaClassTrue = -1;

    /**
     * Die Nummer der Klasse <EM>false</EM> im <CODE>Instances</CODE>-Objekt
     * von Weka. Wird in Methode <CODE>buildClassifier</CODE> gesetzt.
     */
    private double wekaClassFalse = -1;

    /**
     * Gibt an, ob der debug-Modus gesetzt ist.
     */
    private boolean debugMode = false;

    /**
     * Creates a new instance.
     */
    public WekaClassifier() {
        de.unistuttgart.commandline.Option formelnArtOption;
        de.unistuttgart.commandline.Option formelnKlasseOption;
        de.unistuttgart.commandline.Option lokalGrenzwertOption;
        de.unistuttgart.commandline.Option loggingSwitch;
        int paramCheck;

        // Parser erzeugen und Option zum Debugging aufnehmen.
        parser = Steuerung.parser();

        formelnArtOption = new de.unistuttgart.commandline.Option("formelArt");
        paramCheck = de.unistuttgart.commandline.Option.ONE_PARAMETER_CHECK;
        formelnArtOption.setParameterNumberCheck(paramCheck);
        formelnArtOption.setParamDescription("[dis|kon|beste]");
        formelnArtOption.setFullDescription("Gibt die Art der Formel an, die" + " fr die Klassifikation erzeugt"
                + " und verwendet werden soll." + " (default: " + Konstanten.WEKA_FORMEL_ART + ")");
        parser.addOption(formelnArtOption);

        formelnKlasseOption = new de.unistuttgart.commandline.Option("formelKlasse");
        paramCheck = de.unistuttgart.commandline.Option.ONE_PARAMETER_CHECK;
        formelnKlasseOption.setParameterNumberCheck(paramCheck);
        formelnKlasseOption.setParamDescription("[pos|neg|beste|beide]");
        formelnKlasseOption.setFullDescription("Gibt die Klasse der Formel an," + " die fr die Klassifikation"
                + " erzeugt und verwendet werden" + " soll. (default: " + Konstanten.WEKA_FORMEL_KLASSE + ")");
        parser.addOption(formelnKlasseOption);

        lokalGrenzwertOption = new de.unistuttgart.commandline.Option("lokalGrenzwert");
        paramCheck = de.unistuttgart.commandline.Option.ONE_PARAMETER_CHECK;
        lokalGrenzwertOption.setParameterNumberCheck(paramCheck);
        lokalGrenzwertOption.setParamDescription("float");
        lokalGrenzwertOption.setFullDescription("Der Grenzwert, bis zu dem eine" + " Klasifikation lokal anhand"
                + " des Testbeispiels erfolgt." + " (default: " + Konstanten.LOKAL_GRENZWERT + ")");
        parser.addOption(lokalGrenzwertOption);

        loggingSwitch = new de.unistuttgart.commandline.Option("logging");
        paramCheck = de.unistuttgart.commandline.Option.ZERO_PARAMETERS_CHECK;
        loggingSwitch.setParameterNumberCheck(paramCheck);
        loggingSwitch.setFullDescription("Gibt bei der Erzeugung des" + " Klassifikatiors detailierte"
                + " Informationen auf der Konsole" + " aus.");
        parser.addOption(loggingSwitch);

        // Die Parameter fr den Parser initialisieren.
        parser.setComandline(new String[0]);
    }

    /**
     * Returns the revision string.
     *
     * @return  the revision.
     */
    public String getRevision() {
        return REVISION;
    }

    /**
     * Set debugging mode.
     *
     * @param debug  <CODE>true</CODE> if debug output shall be printed,
     *               otherwise <CODE>false</CODE>.
     */
    public void setDebug(boolean debug) {
        debugMode = debug;
    }

    /**
     * Get whether debugging is turned on.
     *
     * @return  <CODE>true</CODE> if debugging output is on, otherwise
     *          <CODE>false</CODE>.
     */
    public boolean getDebug() {
        return debugMode;
    }

    /**
     * Returns an enumeration of all the available options.
     *
     * @return  an enumeration of all available options.
     */
    public Enumeration listOptions() {
        de.unistuttgart.commandline.Option parserOption;
        Vector optionVector;
        Iterator optionIter;
        Option wekaOption;
        String optionSynopsis;
        String paramDescription;

        optionVector = new Vector();

        optionIter = parser.getOptionList().iterator();
        while (optionIter.hasNext()) {
            parserOption = (de.unistuttgart.commandline.Option) optionIter.next();
            optionSynopsis = parserOption.getPrefix() + parserOption.getKey();
            paramDescription = parserOption.getParamDescription();
            if (!paramDescription.equals("")) {
                optionSynopsis += " <" + paramDescription + ">";
            }
            wekaOption = new Option("\t" + parserOption.getFullDescription(), parserOption.getKey(),
                    parserOption.maxParameterNumber(), optionSynopsis);
            optionVector.addElement(wekaOption);
        }

        return optionVector.elements();
    }

    /**
     * Sets the OptionHandler's options using the given list. All options
     * will be set (or reset) during this call (i.e. incremental setting
     * of options is not possible). Replaces options with empty strings.
     *
     * @param options  the list of options as an array of strings.
     *
     * @exception Exception  if an option is not supported.
     */
    public void setOptions(String[] options) throws Exception {
        String[] lascerOptions;
        int lascerOptionAnz;
        int lascerOptionNr;

        // Zhlen, wie viele Optionen tatschlich vorhanden sind.
        lascerOptionAnz = 0;
        for (int i = 0; i < options.length; i++) {
            if (!options[i].equals("")) {
                lascerOptionAnz++;
            }
        }

        // Die tatschlich vorhandenen Optionen kopieren.
        lascerOptions = new String[lascerOptionAnz];
        lascerOptionNr = 0;
        for (int i = 0; i < options.length; i++) {
            if (!options[i].equals("")) {
                lascerOptions[lascerOptionNr] = options[i];
                lascerOptionNr++;
            }
        }

        parser.setComandline(lascerOptions);

        // Alle Optionen durch einen leeren String ersetzen.
        for (int i = 0; i < options.length; i++) {
            options[i] = "";
        }
    }

    /**
     * Gets the current option settings for the OptionHandler.
     *
     * @return the list of current option settings as an array of strings
     */
    public String[] getOptions() {
        de.unistuttgart.commandline.Option parserOption;
        ArrayList options;
        Iterator optionIter;
        Iterator paramIter;
        StringBuffer optionString;

        try {
            Steuerung.parseArguments(parser);
        } catch (Exception e) {
            throw (new RuntimeException(e));
        }

        options = new ArrayList();

        optionIter = parser.getOptionList().iterator();
        while (optionIter.hasNext()) {
            parserOption = (de.unistuttgart.commandline.Option) optionIter.next();

            if (parserOption.isEnabled()) {
                optionString = new StringBuffer();
                optionString.append(parserOption.getPrefix() + parserOption.getKey());

                paramIter = parserOption.getParameterList().iterator();
                while (paramIter.hasNext()) {
                    optionString.append(" " + paramIter.next());
                }

                options.add(optionString.toString());
            }
        }

        return ((String[]) options.toArray(new String[0]));
    }

    /**
     * Returns a new generated formula.
     *
     * @param erzeugungsDatensatz  The data, for which the formula shall be
     *                             generated.
     * @param praedErzParameter    The parameter for the generation of the
     *                             predicates.
     * @param konzErzParameter     The parameter for the generation of the
     *                             concepts.
     * @param formelArt            The type of concept, which shall be
     *                             generated.
     *
     * @return  The generated formula.
     */
    private Konzept generatedFormula(Beispieldaten erzeugungsDatensatz, PraedErzParameter praedErzParameter,
            KonzErzParameter konzErzParameter, String formelArt) {
        KonzeptErzeugungFacade konzeptErzeugung;
        ArrayList praedErzeuger;

        // Erzeugung der Prdikat-Erzeuger.
        praedErzeuger = Steuerung.praedikatErzeuger(erzeugungsDatensatz, praedErzParameter);

        // Erzeugung des Konzept-Erzeugers.
        konzeptErzeugung = new KonzeptErzeugungFacade(erzeugungsDatensatz, konzErzParameter);

        // Erzeugung der Formel.
        if (formelArt.equals("dis")) {
            konzeptErzeugung.erzeugeKorrKonzepte(praedErzeuger);
            return konzeptErzeugung.besteKorrFormel();
        } else if (formelArt.equals("kon")) {
            konzeptErzeugung.erzeugeVollKonzepte(praedErzeuger);
            return konzeptErzeugung.besteVollFormel();
        } else {
            // Es soll die beste Formel geliefert werden.
            konzeptErzeugung.erzeugeKonzepte(praedErzeuger);
            return konzeptErzeugung.besteFormel();
        }
    }

    /**
     * Generates the classifier.
     *
     * @param data  the data to be used.
     *
     * @exception Exception  if the classifier can't built successfully.
     */
    public void buildClassifier(Instances data) throws Exception {
        weka.coreExtended.Instances extendedInstances;
        weka.coreExtended.BasicInstance extInst;
        weka.coreExtended.BasicAttribute classAttribut;
        de.unistuttgart.commandline.Option formelnArtOption;
        de.unistuttgart.commandline.Option formelnKlasseOption;
        de.unistuttgart.commandline.Option loggingSwitch;
        Instance readInst;
        Beispieldaten invDatensatz;
        StringReader stringReader;
        Enumeration instEnum;
        Enumeration attribEnum;
        PraedErzParameter praedErzParameter = null;
        KonzErzParameter konzErzParameter = null;
        Pruning pruning;
        String formelArt;
        String formelKlasse;
        String optionWert;
        float posPruneAnt, negPruneAnt;
        int instNumber;
        boolean unbekannteWertBsp;

        Steuerung.parseArguments(parser);

        formelArt = Konstanten.WEKA_FORMEL_ART;
        formelnArtOption = parser.getOption("formelArt");
        if (parser.isEnabled(formelnArtOption)) {
            optionWert = parser.getParameter(formelnArtOption);
            if (!optionWert.equals("dis") && !optionWert.equals("kon") && !optionWert.equals("beste")) {

                System.err.println("Wert der Option formelArt unzulssig");
                System.err.println("Zulssig: " + formelnArtOption.toString());
                throw (new RuntimeException("Wert von Option unzulssig."));
            }
            formelArt = optionWert;
        }

        formelKlasse = Konstanten.WEKA_FORMEL_KLASSE;
        formelnKlasseOption = parser.getOption("formelKlasse");
        if (parser.isEnabled(formelnKlasseOption)) {
            optionWert = parser.getParameter(formelnKlasseOption);
            if (!optionWert.equals("pos") && !optionWert.equals("neg") && !optionWert.equals("beste")
                    && !optionWert.equals("beide")) {

                System.err.println("Wert der Option formelKlasse unzulssig");
                System.err.println("Zulssig: " + formelnKlasseOption.toString());
                throw (new RuntimeException("Wert von Option unzulssig."));
            }
            formelKlasse = optionWert;
        }

        loggingSwitch = parser.getOption("logging");
        if (debugMode || parser.isEnabled(loggingSwitch)) {
            Steuerung.setLogLevel(Konstanten.LOGGING_LEVEL);
        }

        // Ermittlung der Parameter.
        unbekannteWertBsp = Steuerung.unbekannteWertBeispiele(parser);
        posPruneAnt = Steuerung.posPruneAnteil(parser);
        negPruneAnt = Steuerung.negPruneAnteil(parser);
        praedErzParameter = Steuerung.praedErzParameter(parser);
        konzErzParameter = Steuerung.konzErzParameter(parser);

        // Einlesen der Daten und Erzeugung des Instanzen-Objekts.
        instNumber = data.numInstances();
        stringReader = new StringReader(data.toString());
        extendedInstances = new weka.coreExtended.Instances(stringReader, instNumber);
        instEnum = data.enumerateInstances();
        while (instEnum.hasMoreElements()) {
            readInst = (Instance) instEnum.nextElement();
            extInst = new weka.coreExtended.BasicInstance(readInst.weight(), readInst.toDoubleArray());
            extendedInstances.addBasicInstance(extInst);
        }

        // Erzeugung der Datenstze.
        posDatensatz = ArffDateiEinlesen.beispieldaten(extendedInstances, unbekannteWertBsp);
        negDatensatz = posDatensatz.kopie(true);

        // Erzeugung der Liste der Attribute.
        attributListe = new LinkedList();
        attribEnum = extendedInstances.enumerateBasicAttributes();
        while (attribEnum.hasMoreElements()) {
            attributListe.add(attribEnum.nextElement());
        }

        // Ermittlung der Werte der Klassifikation.
        classAttribut = extendedInstances.basicClassAttribute();
        wekaClassTrue = classAttribut.indexOfValue("true");
        wekaClassFalse = classAttribut.indexOfValue("false");

        // Die Formel zur Klasse der positiven Beispiele erzeugen.
        if (formelKlasse.equals("pos") || formelKlasse.equals("beste") || formelKlasse.equals("beide")) {

            posFormel = generatedFormula(posDatensatz, praedErzParameter, konzErzParameter, formelArt);
        }

        // Die Formel zur Klasse der negativen Beispiele erzeugen.
        if (formelKlasse.equals("neg") || formelKlasse.equals("beste") || formelKlasse.equals("beide")) {

            negFormel = generatedFormula(negDatensatz, praedErzParameter, konzErzParameter, formelArt);
        }

        if (formelKlasse.equals("beste")) {
            // Die schlechtere Formel lschen.
            if (negFormel.istBesser(posFormel)) {
                posFormel = null;
            } else {
                negFormel = null;
            }
        }

        if ((posPruneAnt > 0) || (negPruneAnt > 0)) {
            pruning = new Pruning();

            if (posFormel != null) {
                posDatensatz = pruning.reduzierteDaten(posDatensatz, posFormel, posPruneAnt, negPruneAnt);
                posFormel = generatedFormula(posDatensatz, praedErzParameter, konzErzParameter, formelArt);
            }

            if (negFormel != null) {
                negDatensatz = pruning.reduzierteDaten(negDatensatz, negFormel, negPruneAnt, posPruneAnt);
                negFormel = generatedFormula(negDatensatz, praedErzParameter, konzErzParameter, formelArt);
            }
        }
    }

    /**
     * Returns a new generated formula after adding the test example to a copy
     * of the data set.
     *
     * @param erzeugungsDatensatz  The data, for which the formula shall be
     *                             generated.
     * @param praedErzParameter    The parameter for the generation of the
     *                             predicates.
     * @param konzErzParameter     The parameter for the generation of the
     *                             concepts.
     * @param vorhandeneFormel     The always generated formula.
     * @param testbeispiel         The example which shall be added to a copy
     *                             of the data set.
     * @param posTestBeispiel      <CODE>true</CODE>, if the test example
     *                             shall be added as a positive example.
     *
     * @return  The generated formula.
     */
    private Konzept generatedAddFormula(Beispieldaten erzeugungsDatensatz, PraedErzParameter praedErzParameter,
            KonzErzParameter konzErzParameter, Konzept vorhandeneFormel, Beispiel testbeispiel,
            boolean posTestBeispiel) {
        Beispieldaten datensatzKopie;
        String formelArt;

        // Die Art der erzeugten Formel ermitteln.
        if (vorhandeneFormel instanceof Disjunktion) {
            formelArt = "dis";
        } else if (vorhandeneFormel instanceof Konjunktion) {
            formelArt = "kon";
        } else {
            throw new RuntimeException("Art der Formel unbekannt: " + vorhandeneFormel);
        }

        datensatzKopie = erzeugungsDatensatz.kopie(false);
        datensatzKopie.beispielAufnehmen(testbeispiel, posTestBeispiel);

        return generatedFormula(datensatzKopie, praedErzParameter, konzErzParameter, formelArt);
    }

    /**
     * Returns a new generated concept after adding the test example to a copy
     * of the data set.
     *
     * @param erzeugungsDatensatz  The data, for which the concept shall be
     *                             generated.
     * @param praedErzParameter    The parameter for the generation of the
     *                             predicates.
     * @param konzErzParameter     The parameter for the generation of the
     *                             concepts.
     * @param vorhandeneFormel     The always generated formula.
     * @param testbeispiel         The example which shall be added to a copy
     *                             of the data set.
     * @param posTestBeispiel      <CODE>true</CODE>, if the test example
     *                             shall be added as a positive example.
     *
     * @return  The generated concept.
     */
    private Konzept generatedAddConcept(Beispieldaten erzeugungsDatensatz, PraedErzParameter praedErzParameter,
            KonzErzParameter konzErzParameter, Konzept vorhandeneFormel, Beispiel testbeispiel,
            boolean posTestBeispiel) {
        KonzeptErzeugungFacade konzeptErzeugung;
        Beispieldaten datensatzKopie;
        ArrayList praedErzeuger;
        int beispielNr;

        // Testbeispiel in Kopie vom Datensatz aufnehmen.
        datensatzKopie = erzeugungsDatensatz.kopie(false);
        datensatzKopie.beispielAufnehmen(testbeispiel, posTestBeispiel);

        // Erzeugung der Prdikat-Erzeuger.
        praedErzeuger = Steuerung.praedikatErzeuger(datensatzKopie, praedErzParameter);

        // Erzeugung des Konzept-Erzeugers.
        konzeptErzeugung = new KonzeptErzeugungFacade(datensatzKopie, konzErzParameter);

        if (vorhandeneFormel instanceof Disjunktion) {
            if (posTestBeispiel) {
                beispielNr = datensatzKopie.posBspAnz() - 1;
                return konzeptErzeugung.effizientKorrKonzept(praedErzeuger, beispielNr);
            } else {
                return konzeptErzeugung.effizientKorrKonzept(praedErzeuger, -1);
            }
        } else if (vorhandeneFormel instanceof Konjunktion) {
            if (posTestBeispiel) {
                return konzeptErzeugung.effizientVollKonzept(praedErzeuger, -1);
            } else {
                beispielNr = datensatzKopie.negBspAnz() - 1;
                return konzeptErzeugung.effizientVollKonzept(praedErzeuger, beispielNr);
            }
        } else {
            throw new RuntimeException("Art der Formel unbekannt: " + vorhandeneFormel);
        }
    }

    /**
     * Classifies a given example.
     *
     * @param datensatz            The data, for which the concept shall be
     *                             generated.
     * @param praedErzParameter    The parameter for the generation of the
     *                             predicates.
     * @param konzErzParameter     The parameter for the generation of the
     *                             concepts.
     * @param vorhandFormel        The always generated formula.
     * @param testbeispiel         The example to be classified.
     * @param lokalGrenzwert       The value for the difference of the
     *                             complexities of the two formulas, upto that
     *                             a local classification will be done.
     * @param trueClassValue       The value to return, when the example is
     *                             positive classified.
     * @param falseClassValue      The value to return, when the example is
     *                             negative classified.
     *
     * @return  the classification of the example.
     */
    private double relativeCassification(Beispieldaten datensatz, PraedErzParameter praedErzParameter,
            KonzErzParameter konzErzParameter, Konzept vorhandFormel, Beispiel testbeispiel, float lokalGrenzwert,
            double trueClassValue, double falseClassValue) {
        Konzept formelTrue, formelFalse;
        Konzept konzeptTrue, konzeptFalse;
        float fehlAnzTrue, fehlAnzFalse;
        float komplexTrue, komplexFalse, komplexDiff;
        float bewertTrue, bewertFalse;

        // Eine Formel fr die Beispiele des Datensatzes inklusive des
        // Testbeispiels erzeugen.
        if (vorhandFormel.trifftZu(testbeispiel)) {
            formelTrue = vorhandFormel;
            formelFalse = generatedAddFormula(datensatz, praedErzParameter, konzErzParameter, vorhandFormel,
                    testbeispiel, false);
        } else {
            formelFalse = vorhandFormel;
            formelTrue = generatedAddFormula(datensatz, praedErzParameter, konzErzParameter, vorhandFormel,
                    testbeispiel, true);
        }

        // Die Fehleranzahl der Formeln ermitteln.
        fehlAnzTrue = formelTrue.posFalschAnz() + formelTrue.negFalschAnz();
        fehlAnzFalse = formelFalse.posFalschAnz() + formelFalse.negFalschAnz();

        // Die Komplexitt der Formeln ermitteln.
        komplexTrue = formelTrue.komplexitaet();
        komplexFalse = formelFalse.komplexitaet();
        komplexDiff = komplexTrue - komplexFalse;

        if (fehlAnzTrue < fehlAnzFalse) {
            return trueClassValue;
        } else if (fehlAnzTrue > fehlAnzFalse) {
            return falseClassValue;
        } else {
            if (Math.abs(komplexDiff) >= lokalGrenzwert) {
                // Klassifikation entsprechend der Komplexitt.
                if (komplexTrue < komplexFalse) {
                    return trueClassValue;
                } else {
                    return falseClassValue;
                }
            } else {
                // Lokale Klassifikation.

                konzeptTrue = generatedAddConcept(datensatz, praedErzParameter, konzErzParameter, vorhandFormel,
                        testbeispiel, true);
                konzeptFalse = generatedAddConcept(datensatz, praedErzParameter, konzErzParameter, vorhandFormel,
                        testbeispiel, false);

                // Die Bewertungen der Konzepte ermitteln.
                bewertTrue = KonzeptErzeugungFacade.konzeptEffizienz(konzeptTrue);
                bewertFalse = KonzeptErzeugungFacade.konzeptEffizienz(konzeptFalse);

                if (bewertTrue >= bewertFalse) {
                    return trueClassValue;
                } else {
                    return falseClassValue;
                }
            }
        }
    }

    /**
     * Classifies a given instance.
     *
     * @param inst  the instance to be classified.
     *
     * @return  the classification of the instance.
     */
    public double classifyInstance(Instance inst) {
        weka.coreExtended.Instance extendedInstance;
        de.unistuttgart.commandline.Option lokalGrenzwertOption;
        AttributSammlung attributSammlung;
        PraedErzParameter praedErzParameter = null;
        KonzErzParameter konzErzParameter = null;
        Konzept posFormelTrue, posFormelFalse;
        Konzept negFormelTrue, negFormelFalse;
        Konzept posKonzeptTrue, posKonzeptFalse;
        Konzept negKonzeptTrue, negKonzeptFalse;
        Beispiel testbeispiel;
        float fehlAnzPosTrue, fehlAnzPosFalse, fehlAnzPosDiff;
        float fehlAnzNegTrue, fehlAnzNegFalse, fehlAnzNegDiff;
        float komplexPosTrue, komplexPosFalse, komplexPosDiff;
        float komplexNegTrue, komplexNegFalse, komplexNegDiff;
        float bewertPosTrue, bewertPosFalse, bewertPosDiff;
        float bewertNegTrue, bewertNegFalse, bewertNegDiff;
        float lokalGrenzwert;

        extendedInstance = new weka.coreExtended.BasicInstance(inst.weight(), inst.toDoubleArray());
        attributSammlung = posDatensatz.attributSammlung();
        testbeispiel = ArffDateiEinlesen.instanzBeispiel(extendedInstance, attributListe, attributSammlung);

        lokalGrenzwert = Konstanten.LOKAL_GRENZWERT;
        lokalGrenzwertOption = parser.getOption("lokalGrenzwert");
        if (parser.isEnabled(lokalGrenzwertOption)) {
            lokalGrenzwert = parser.getParameterAsFloat(lokalGrenzwertOption);
        }

        if ((posFormel != null) && (negFormel != null) || (lokalGrenzwert > 0)) {
            // Ermittlung der Parameter.
            praedErzParameter = Steuerung.praedErzParameter(parser);
            konzErzParameter = Steuerung.konzErzParameter(parser);
        }

        if ((posFormel == null) && (negFormel == null)) {

            throw (new RuntimeException("Keine Formel vorhanden."));

        } else if (negFormel == null) {
            // Es ist nur eine Formel fr die positiven Beispiele vorhanden.

            if (lokalGrenzwert == 0) {
                // Die Klassifikation erfolgt nur mittels der vorhandenen
                // Formel.
                if (posFormel.trifftZu(testbeispiel)) {
                    return wekaClassTrue;
                } else {
                    return wekaClassFalse;
                }
            } else {
                // Die Klassifikation erfolgt nach Erzeugung von Formeln und
                // gegebenenfalls Konzepten nach Hinzunahme des Testbeispiels
                // zum Datensatz.
                return relativeCassification(posDatensatz, praedErzParameter, konzErzParameter, posFormel,
                        testbeispiel, lokalGrenzwert, wekaClassTrue, wekaClassFalse);
            }

        } else if (posFormel == null) {
            // Es ist nur eine Formel fr die negativen Beispiele vorhanden.

            if (lokalGrenzwert == 0) {
                // Die Klassifikation erfolgt nur mittels der vorhandenen
                // Formel.
                if (negFormel.trifftZu(testbeispiel)) {
                    return wekaClassFalse;
                } else {
                    return wekaClassTrue;
                }
            } else {
                // Die Klassifikation erfolgt nach Erzeugung von Formeln und
                // gegebenenfalls Konzepten nach Hinzunahme des Testbeispiels
                // zum Datensatz.
                return relativeCassification(negDatensatz, praedErzParameter, konzErzParameter, negFormel,
                        testbeispiel, lokalGrenzwert, wekaClassFalse, wekaClassTrue);
            }

        } else {
            // Es ist sowohl eine Formel fr die positiven wie fr negativen
            // Beispiele vorhanden. Es findet daher eine Klassifikation
            // entsprechend der relativen Vernderung der Komplexitt der
            // Formeln bei Bercksichtigung des zu klassifizierenden Beispiels
            // statt.

            // Eine Formel fr die positiven Beispiele inklusive des
            // Testbeispiels erzeugen.
            if (posFormel.trifftZu(testbeispiel)) {
                posFormelTrue = posFormel;
                posFormelFalse = generatedAddFormula(posDatensatz, praedErzParameter, konzErzParameter, posFormel,
                        testbeispiel, false);
            } else {
                posFormelFalse = posFormel;
                posFormelTrue = generatedAddFormula(posDatensatz, praedErzParameter, konzErzParameter, posFormel,
                        testbeispiel, true);
            }

            // Eine Formel fr die negativen Beispiele inklusive des
            // Testbeispiels erzeugen.
            if (negFormel.trifftZu(testbeispiel)) {
                negFormelTrue = negFormel;
                negFormelFalse = generatedAddFormula(negDatensatz, praedErzParameter, konzErzParameter, negFormel,
                        testbeispiel, false);
            } else {
                negFormelFalse = negFormel;
                negFormelTrue = generatedAddFormula(negDatensatz, praedErzParameter, konzErzParameter, negFormel,
                        testbeispiel, true);
            }

            // Die Fehleranzahl der Formeln ermitteln.
            fehlAnzPosTrue = (posFormelTrue.posFalschAnz() + posFormelTrue.negFalschAnz());
            fehlAnzPosFalse = (posFormelFalse.posFalschAnz() + posFormelFalse.negFalschAnz());
            fehlAnzNegTrue = (negFormelTrue.posFalschAnz() + negFormelTrue.negFalschAnz());
            fehlAnzNegFalse = (negFormelFalse.posFalschAnz() + negFormelFalse.negFalschAnz());
            fehlAnzPosDiff = fehlAnzPosTrue - fehlAnzPosFalse;
            fehlAnzNegDiff = fehlAnzNegTrue - fehlAnzNegFalse;

            // Die Komplexitt der Formeln ermitteln.
            komplexPosTrue = posFormelTrue.komplexitaet();
            komplexPosFalse = posFormelFalse.komplexitaet();
            komplexNegTrue = negFormelTrue.komplexitaet();
            komplexNegFalse = negFormelFalse.komplexitaet();
            komplexPosDiff = komplexPosTrue - komplexPosFalse;
            komplexNegDiff = komplexNegTrue - komplexNegFalse;

            // Vergleich der Vernderungen der Formeln.
            if ((fehlAnzPosDiff < 0) && (fehlAnzNegDiff > 0)) {

                return wekaClassTrue;

            } else if ((fehlAnzPosDiff > 0) && (fehlAnzNegDiff < 0)) {

                return wekaClassFalse;

            } else if (Math.abs(fehlAnzPosDiff) > Math.abs(fehlAnzNegDiff)) {

                // fehlAnzPosDiff ist nicht Null.
                if (fehlAnzPosDiff < 0) {
                    return wekaClassTrue;
                } else {
                    return wekaClassFalse;
                }

            } else if (Math.abs(fehlAnzPosDiff) < Math.abs(fehlAnzNegDiff)) {

                // fehlAnzNegDiff ist nicht Null.
                if (fehlAnzNegDiff > 0) {
                    return wekaClassTrue;
                } else {
                    return wekaClassFalse;
                }

            } else {
                // Die Vernderung der Fehleranzahl bezglich der Klassse des
                // Testbeispiels ist fr beide Formeln aller Beispiel der
                // jeweiligen Klasse gleich.

                if ((Math.abs(komplexPosDiff - komplexNegDiff) >= 2 * lokalGrenzwert)
                        && (komplexPosDiff != komplexNegDiff)) {

                    // Klassifikation nach den Komplexitten.
                    if (Math.abs(komplexPosDiff) > Math.abs(komplexNegDiff)) {

                        // komplexPosDiff ist nicht Null.
                        if (komplexPosDiff < 0) {
                            return wekaClassTrue;
                        } else {
                            return wekaClassFalse;
                        }

                    } else {

                        // komplexNegDiff ist betragsmig grer als
                        // komplexPosDiff und nicht Null.
                        if (komplexNegDiff > 0) {
                            return wekaClassTrue;
                        } else {
                            return wekaClassFalse;
                        }

                    }

                } else if (lokalGrenzwert > 0) {
                    // Eine lokale Klassifikation vornehmen.

                    // Erzeugung der effizientesten Konzepte nach Hinzunahme
                    // des Testbeispiels.
                    posKonzeptTrue = generatedAddConcept(posDatensatz, praedErzParameter, konzErzParameter,
                            posFormel, testbeispiel, true);
                    posKonzeptFalse = generatedAddConcept(posDatensatz, praedErzParameter, konzErzParameter,
                            posFormel, testbeispiel, false);
                    negKonzeptTrue = generatedAddConcept(negDatensatz, praedErzParameter, konzErzParameter,
                            negFormel, testbeispiel, true);
                    negKonzeptFalse = generatedAddConcept(negDatensatz, praedErzParameter, konzErzParameter,
                            negFormel, testbeispiel, false);

                    // Die Bewertungen der Konzepte ermitteln.
                    bewertPosTrue = KonzeptErzeugungFacade.konzeptEffizienz(posKonzeptTrue);
                    bewertPosFalse = KonzeptErzeugungFacade.konzeptEffizienz(posKonzeptFalse);
                    bewertNegTrue = KonzeptErzeugungFacade.konzeptEffizienz(negKonzeptTrue);
                    bewertNegFalse = KonzeptErzeugungFacade.konzeptEffizienz(negKonzeptFalse);
                    bewertPosDiff = bewertPosTrue - bewertPosFalse;
                    bewertNegDiff = bewertNegTrue - bewertNegFalse;

                    if (Math.abs(bewertPosDiff) >= Math.abs(bewertNegDiff)) {
                        if (bewertPosDiff >= 0) {
                            return wekaClassTrue;
                        } else {
                            return wekaClassFalse;
                        }
                    } else {
                        if (bewertNegDiff < 0) {
                            return wekaClassTrue;
                        } else {
                            return wekaClassFalse;
                        }
                    }

                } else {
                    // Die Vernderung der Komplexitt bezglich der Klassse
                    // des Testbeispiels ist fr beide Formeln aller Beispiel
                    // der jeweiligen Klasse gleich und eine lokale
                    // Klassifikation soll nicht erfolgen. Daher nach der
                    // Anzahl der Beispiele der Klassen klassifizieren.

                    if (posDatensatz.posBspAnz() >= posDatensatz.negBspAnz()) {
                        return wekaClassTrue;
                    } else {
                        return wekaClassFalse;
                    }
                }
            }
        }
    }

    /**
     * Returns a description of the classifier.
     *
     * @return  a description of the classifier as a string.
     */
    public String toString() {

        if ((posFormel != null) && (negFormel != null)) {
            return ("{pos: " + posFormel.toString() + "; neg: " + negFormel.toString() + "}");
        } else if (posFormel != null) {
            return "pos: " + posFormel.toString();
        } else if (negFormel != null) {
            return "neg: " + negFormel.toString();
        } else {
            return "";
        }
    }

    /**
     * Evaluates the classifier.
     *
     * @param args  an array with the options for the evaluation.
     */
    public static void main(String[] args) {

        try {
            System.out.println(Evaluation.evaluateModel(new WekaClassifier(), args));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}