org.prom5.analysis.decisionmining.DecisionMiningLogTrace.java Source code

Java tutorial

Introduction

Here is the source code for org.prom5.analysis.decisionmining.DecisionMiningLogTrace.java

Source

/**
 *    This program 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.
 *
 *    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 General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *    Copyright (c) 2003-2006 TU/e Eindhoven
 *    by Eindhoven University of Technology
 *    Department of Information Systems
 *    http://is.tm.tue.nl
 *
 ************************************************************************/

package org.prom5.analysis.decisionmining;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.prom5.analysis.decisionmining.DecisionPointContext.AttributeSelectionScope;
import org.prom5.analysis.petrinet.cpnexport.CpnUtils;
import org.prom5.framework.log.AuditTrailEntry;
import org.prom5.framework.log.LogEvent;
import org.prom5.framework.log.ProcessInstance;
import org.prom5.framework.ui.Message;

import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;

/**
 * Records additional information related to the decision points
 * of the connected process model for one Process instance
 * (i.e., records which alternative paths have been taken in this trace).
 *
 * @author arozinat
 */
public class DecisionMiningLogTrace {

    /**
     * The process instance that is represented by this log trace.
     */
    private ProcessInstance myInstance;

    /**
     * Contains the amount of times each branch of each decision point has
     * been taken (can be more than one in the presence of loops).
     */
    private HashMap myDecisions;

    /**
     * Create a diagnostic log trace by copying the ordinary process instance.
     * @param pi the template process instance used to create the diagnostic log trace
     */
    public DecisionMiningLogTrace(ProcessInstance pi) {
        myInstance = pi;
    }

    /**
     * Retrieves the process instance represented by this log trace.
     * @return the belonging process instance from the log
     */
    public ProcessInstance getProcessInstance() {
        return myInstance;
    }

    /**
     * Initializes the diagnostic entry for each branch of each decision point
     * with <code>0</code>.
     * @param decisionPoints the list of decision points for which the taken
     * branches will be recorded
     */
    public void initDiagnosticDataStructures(List<DecisionPoint> decisionPoints) {
        myDecisions = new HashMap();
        Iterator allDecisionPoints = decisionPoints.iterator();
        while (allDecisionPoints.hasNext()) {
            DecisionPoint current = (DecisionPoint) allDecisionPoints.next();
            Iterator currentBranches = current.getTargetConcept().iterator();
            while (currentBranches.hasNext()) {
                DecisionCategory branch = (DecisionCategory) currentBranches.next();
                // put only global ID string
                myDecisions.put(branch.getID(), new Integer(0));
            }
        }
    }

    /**
     * Increment the corresponding entry by the specified value.
     * @param branchName the name of the decision branch to be updated
     * @param value the value to be added to the current value
     * @throws Exception in the case that the specified entry is missing
     */
    public void addDecisionOccurrences(String branchName, Integer value) throws Exception {
        // check existence of entry
        if (myDecisions.containsKey(branchName)) {
            // retrieve the corrensponding Item from token counter
            int currentAmount = ((Integer) myDecisions.get(branchName)).intValue();
            int incrementValue = value.intValue();
            // create updated item
            Integer newAmount = new Integer(currentAmount + incrementValue);
            // modify the corresponding entry
            myDecisions.put(branchName, newAmount);
        } else {
            throw new Exception("addDecisionOccurrences could not find an entry\nat process instance: "
                    + myInstance.getName() + "\nfor decision branch: " + branchName + ".");
        }
    }

    /**
     * The increment of the corresponding missingTokens entry is assumed to be 1.
     * @param branchName the name of the decision branch to be updated
     */
    public void incrementDecisionOccurrences(String branchName) throws Exception {
        addDecisionOccurrences(branchName, new Integer(1));
    }

    /**
     * Returns the name of this process instance.
     */
    public String toString() {
        return myInstance.getName();
    }

    /**
     * Creates a learning instance that can be used by a weka data mining algorithm.
     * Note that loop semantics are not yet taken into account, therefore each trace
     * is exactly represented by one learning instance.
     * @param dataset the enclosing data set
     * @param attInfoSize the number of attributes (including the class attribute) specified by the instance
     * @return the learning instance representing this log trace
     */
    public Instance makeInstance(Instances dataset, int attInfoSize, DecisionCategory branch,
            DecisionMiningLogReader log, DecisionPointContext context) {
        Instance instance = new Instance(attInfoSize);

        // provide global attribute values
        Map<String, String> piData = myInstance.getAttributes();
        evaluateDataForInstance(piData, instance, dataset);

        // provide ATE attribute values
        Iterator<AuditTrailEntry> ates = myInstance.getAuditTrailEntryList().iterator();
        while (ates.hasNext()) {
            AuditTrailEntry ate = ates.next();
            Map<String, String> ateData = ate.getAttributes();
            evaluateDataForInstance(ateData, instance, dataset);

            // Which logEvent happened?
            LogEvent le = log.findLogEvent(ate);
            // check whether trace should be further traversed 
            // (or whether learning instance should be build from current state)
            if (branch.contains(le) && ((context.getAttributeSelectionScope() == AttributeSelectionScope.ALL_BEFORE)
                    || (context.getAttributeSelectionScope() == AttributeSelectionScope.JUST_BEFORE))) {
                // stop with data attributes up to current state of trace
                break;
            }
        }
        // make enclosing dataset known to this instance
        instance.setDataset(dataset);
        return instance;
    }

    /**
     * Helper method for reading the mapp of data attributes (key,value) pairs, 
     * and adding them to the current learning instance.
     * @param data the map of data attribues
     * @param instance the current learning instance
     * @param dataset the current learning problem (contains attribute info)
     */
    private void evaluateDataForInstance(Map<String, String> data, Instance instance, Instances dataset) {
        Iterator<Entry<String, String>> dataIterator = data.entrySet().iterator();
        while (dataIterator.hasNext()) {
            Entry<String, String> currentDataEntry = dataIterator.next();
            String attName = currentDataEntry.getKey();
            String attValue = currentDataEntry.getValue();

            // replace white spaces and special characters by underscores both in name and value
            attName = CpnUtils.replaceSpecialCharacters(attName);
            attValue = CpnUtils.replaceSpecialCharacters(attValue);

            // check whether current attribute is contained in relevant attributes
            Attribute wekaAtt = dataset.attribute(attName);
            if (wekaAtt != null) {
                if (wekaAtt.isNominal() == true) {
                    // corresponding string can be directly provided
                    instance.setValue(wekaAtt, attValue);
                } else if (wekaAtt.isNumeric() == true) {
                    // value must be converted into double first
                    try {
                        double doubleAttValue = (new Double(attValue)).doubleValue();
                        instance.setValue(wekaAtt, doubleAttValue);
                    } catch (NumberFormatException ex) {
                        // the attribute did not contain a parsable number
                        Message.add("attribute " + attName + " appears not to be a numeric attribute!", 2);
                    }
                }
            }
        }
    }
}