package org.jbpt.pm.quality; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import org.apache.commons.math3.util.Pair; import org.deckfour.xes.model.XLog; import org.jbpt.petri.NetSystem; import org.jbpt.petri.mc.LoLA2ModelChecker; import org.jbpt.pm.utils.Utils; import dk.brics.automaton.Automaton; import gnu.trove.map.TObjectShortMap; import gnu.trove.map.custom_hash.TObjectShortCustomHashMap; import gnu.trove.strategy.HashingStrategy; /** * Abstract Quality Measure Class * * @author Artem Polyvyanyy * * @author Anna Kalenkova */ public abstract class AbstractQualityMeasure { protected Collection<QualityMeasureLimitation> limitations = new ArrayList<QualityMeasureLimitation>(); private Boolean limitationsHold = null; private Set<String> violetedLimitations = new HashSet<String>(); protected Object relevantTraces = null; protected Object retrievedTraces = null; private Long measureComputationTime = null; private Pair<Double, Double> measureValue = null; private HashMap<QualityMeasureLimitation,Long> timesOfLimitationChecks = new HashMap<QualityMeasureLimitation,Long>(); private HashMap<QualityMeasureLimitation,Boolean> resultsOfLimitationChecks = new HashMap<QualityMeasureLimitation,Boolean>(); public AbstractQualityMeasure(Object relevantTraces, Object retrievedTraces) { this.relevantTraces = relevantTraces; this.retrievedTraces = retrievedTraces; this.initializeLimitations(); } // initialize limitations of this method protected abstract void initializeLimitations(); public Collection<QualityMeasureLimitation> getLimitations() { return Collections.unmodifiableCollection(this.limitations); } /** * Check if the given models satisfy limitations of this measure. * * @return true if the limitations are satisfied by the model; false otherwise. */ public boolean checkLimitations() { long start = 0; for (QualityMeasureLimitation limitation : this.limitations) { switch (limitation) { case RETRIEVED_BOUNDED: start = System.currentTimeMillis(); boolean limitationHolds = this.checkBounded(this.retrievedTraces); if (!limitationHolds) { violetedLimitations.add(limitation.getDescription()); } this.resultsOfLimitationChecks.put(QualityMeasureLimitation.RETRIEVED_BOUNDED, new Boolean(limitationHolds)); this.timesOfLimitationChecks.put(QualityMeasureLimitation.RETRIEVED_BOUNDED, new Long(System.currentTimeMillis() - start)); break; case RELEVANT_BOUNDED: start = System.currentTimeMillis(); limitationHolds = this.checkBounded(this.relevantTraces); if (!limitationHolds) { violetedLimitations.add(limitation.getDescription()); } this.resultsOfLimitationChecks.put(QualityMeasureLimitation.RELEVANT_BOUNDED, new Boolean(limitationHolds)); this.timesOfLimitationChecks.put(QualityMeasureLimitation.RELEVANT_BOUNDED, new Long(System.currentTimeMillis() - start)); break; } } boolean hold = true; for (Boolean b : this.resultsOfLimitationChecks.values()) { hold &= b.booleanValue(); } if (hold) this.limitationsHold = Boolean.TRUE; else this.limitationsHold = Boolean.FALSE; return hold; } private boolean checkBounded(Object model) { if (model instanceof NetSystem) { NetSystem sys = (NetSystem) model; sys.loadNaturalMarking(); LoLA2ModelChecker lola = new LoLA2ModelChecker("./lola2/win/lola"); boolean result = lola.isBounded(sys); return result; } return true; } /** * Compute value of this measure. * * @return Value of this measure for the given models of relevant and retrieved traces. * @throws Exception if limitations of this measure are not satisfied by the given models. */ public Pair<Double, Double> computeMeasure() throws Exception { if (limitationsHold==null) this.checkLimitations(); if (limitationsHold==null || !limitationsHold.booleanValue()) { throw new Exception(String.format("Limitation(s): %s of %s measure are not fulfilled", violetedLimitations, this.getClass().getName())); } HashingStrategy<String> strategy = new HashingStrategy<String>() { public int computeHashCode(String object) { return object.hashCode(); } public boolean equals(String o1, String o2) { return o1.equals(o2); } }; TObjectShortMap<String> activity2short = new TObjectShortCustomHashMap<String>(strategy, 10, 0.5f, (short) -1); System.out.println(String.format("Constructing automaton RET that encodes the retrieved model.")); long start = System.currentTimeMillis(); if (retrievedTraces instanceof NetSystem) { retrievedTraces = Utils.constructAutomatonFromNetSystem((NetSystem) retrievedTraces, activity2short); } else if (retrievedTraces instanceof XLog){ retrievedTraces = Utils.constructAutomatonFromLog((XLog) retrievedTraces, activity2short); } long finish = System.currentTimeMillis(); System.out.println(String.format("Automaton RET constructed in %s ms.", (finish-start))); System.out.println(String.format("Automaton RET has %s states and %s transitions.", ((Automaton)retrievedTraces).getNumberOfStates(), Utils.numberOfTransitions((Automaton)retrievedTraces))); System.out.println(String.format("Constructing automaton REL that encodes the relevant model.")); start = System.currentTimeMillis(); if (relevantTraces instanceof NetSystem) { relevantTraces = Utils.constructAutomatonFromNetSystem((NetSystem) relevantTraces, activity2short); } else if (relevantTraces instanceof XLog){ relevantTraces = Utils.constructAutomatonFromLog((XLog) relevantTraces, activity2short); } finish = System.currentTimeMillis(); System.out.println(String.format("Automaton REL constructed in %s ms.", (finish-start))); System.out.println(String.format("Automaton REL has %s states and %s transitions.", ((Automaton)relevantTraces).getNumberOfStates(), Utils.numberOfTransitions((Automaton)relevantTraces))); start = System.nanoTime(); this.measureValue = this.computeMeasureValue(); this.measureComputationTime = System.nanoTime()-start; return this.measureValue; } /** * Get measure computation time (in nanoseconds). * * @return Time spent computing the measure; null if the measure was not computed. */ public Long getMeasureComputationTime() { return measureComputationTime; } public Long getLimitationCheckTime(QualityMeasureLimitation limitation) { return this.timesOfLimitationChecks.get(limitation); } public Boolean getLimitationCheckResult(QualityMeasureLimitation limitation) { return this.resultsOfLimitationChecks.get(limitation); } /** * Get value of this measure. * * @return Value of this measure; null if the measure was not computed. */ public Pair<Double, Double> getMeasureValue() { return measureValue; } // compute measure value protected abstract Pair<Double, Double> computeMeasureValue(); }