blob: f329fbffef721f44f08622762f83c8e2f783f5e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2013 University of Utah School of Computing
* 50 S Central Campus Dr. 3190 Salt Lake City, UT 84112
* http://www.cs.utah.edu/formal_verification/
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alan Humphrey - Initial API and implementation
* Christopher Derrick - Initial API and implementation
* Prof. Ganesh Gopalakrishnan - Project Advisor
*******************************************************************************/
package org.eclipse.ptp.internal.gem.util;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ptp.internal.gem.GemPlugin;
import org.eclipse.ptp.internal.gem.preferences.PreferenceConstants;
/**
* This class represents all information for each MPI call (transition) in every
* interleaving explored. This is the central source of information used by all
* components within GEM.
*/
public class Transitions {
private final ArrayList<ArrayList<Envelope>> transitionList;
private final ArrayList<HashMap<String, Envelope>> errorCalls;
private HashMap<Integer, String> irrelevantBarriers;
private HashMap<Integer, Envelope> resourceLeaks;
private HashMap<Integer, String> typeMismatches;
private ArrayList<Integer> deadlockInterleavings;
private int numRanks;
public int currentInterleaving;
public int currentTransitionIndex;
private int deadlockIndex;
private boolean deadlock;
private boolean assertionViolation;
private boolean resourceLeak;
private boolean fib;
/**
* Constructor
*
* @param logFile
* The Resource representing the log file to parse.
* @throws ParseException
*/
public Transitions(IFile logFile) throws ParseException {
this.transitionList = new ArrayList<ArrayList<Envelope>>();
this.errorCalls = new ArrayList<HashMap<String, Envelope>>();
this.irrelevantBarriers = null;
this.resourceLeaks = null;
this.typeMismatches = null;
// Add null as padding so we can be one-based later
this.errorCalls.add(null);
this.numRanks = -1;
this.deadlock = false;
this.assertionViolation = false;
this.resourceLeak = false;
parseLogFile(logFile);
}
/**
* Moves to the deadlock interleaving, or if there are multiple
* interleavings, it cycles through all.
*
* @param none
* @return boolean True if the operation was successful, false otherwise.
*/
synchronized public boolean deadlockInterleaving() {
if (!this.deadlock) {
return false;
}
this.currentInterleaving = this.deadlockInterleavings.get(this.deadlockIndex) - 1;
this.currentTransitionIndex = -1;
// This is to cycle through the deadlock interleavings
this.deadlockIndex++;
this.deadlockIndex = this.deadlockIndex % this.deadlockInterleavings.size();
return true;
}
/**
* Returns a list of all envelopes involved in the collective call held in
* the Envelope that is passed in.
*
* @param env
* The Envelope holding the collective call.
* @return ArrayList<Envelope> A list of all Envelopes involved with that
* call.
*/
// TODO This is not currently being used
public ArrayList<Envelope> getCollectiveTransitions(Envelope env) {
if (env.getIssueIndex() < 0) {
return null;
}
return env.getCommunicator_matches();
}
/**
* Returns the interleaving current being displayed.
*
* @param none
* @return int The current interleaving.
*/
public int getCurrentInterleaving() {
return this.currentInterleaving + 1;
}
/**
* Returns the Envelope involved with the current transition.
*
* @param none
* @return Envelope The current Envelope in the current interleaving.
*/
synchronized public Envelope getCurrentTransition() {
if (this.currentInterleaving < 0
|| this.currentInterleaving >= this.transitionList.size()
|| this.currentTransitionIndex < 0
|| this.currentTransitionIndex >= this.transitionList.get(this.currentInterleaving).size()) {
return null;
}
return this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex);
}
/**
* Returns the index of the current transition.
*
* @param none
* @return int The current transition index.
*/
public int getCurrentTransitionIndex() {
return this.currentTransitionIndex;
}
/**
* Returns the list of deadlock interleavings.
*
* @param none
* @return ArrayList<Integer> The list of deadlock interleavings.
*/
public ArrayList<Integer> getDeadlockInterleavings() {
return this.deadlockInterleavings;
}
/**
* Returns the list of HashMaps containing Envelopes involved in the error.
* There may be multiple maps due to multiple errors in separate
* interleavings.
*
* @param none
* @return ArrayList<HashMap<String, Envelope>> The list of HashMaps
* containing Envelopes involved in program errors.
*/
public ArrayList<HashMap<String, Envelope>> getErrorCalls() {
return this.errorCalls;
}
/**
* Walks the appropriate list to the first transition for the specified rank
* in the current interleaving.
*
* @param rank
* The rank for which to find the first.
* @return Envelope The first Envelope in the current interleaving for the
* specified rank.
*/
synchronized public Envelope getFirstTransition(int rank) {
boolean valid = true;
if (rank < 0 || rank > this.numRanks) {
valid = false;
}
final int size = this.transitionList.get(this.currentInterleaving).size();
for (int i = 0; i < size; i++) {
final Envelope env = this.transitionList.get(this.currentInterleaving).get(i);
if (!valid || env.getRank() == rank) {
this.currentTransitionIndex = i;
return env;
}
}
return null;
}
/**
* Returns an ArrayList of all envelopes in the interleaving that is passed
* in.
*
* @param interleaving
* An integer representing the desired interleaving (1-based).
* @return ArrayList<Envelope> The ArrayList of all envelopes in the
* specified interleaving.
*/
public ArrayList<Envelope> getInterleavingEnvelopes(int interleaving) {
if (interleaving < 1 || interleaving > getTotalInterleavings()) {
return null;
}
return this.transitionList.get(interleaving - 1); // 0-based
}
/**
* Returns the list of the interleavings listing the calls pertaining to
* Irrelevant barriers.
*
* @param none
* @return HashMap<Integer, String> The unique set of irrelevant barriers.
*/
public HashMap<Integer, String> getIrrelevantBarriers() {
return this.irrelevantBarriers;
}
/**
* Walks the appropriate list to the last transition for the specified rank
* in the current interleaving.
*
* @param rank
* The rank to find the last transition for.
* @return Envelope The last Envelope in the current interleaving for the
* specified rank.
*/
synchronized public Envelope getLastTransition(int rank) {
boolean valid = true;
if (rank < 0 || rank > this.numRanks) {
valid = false;
}
final int size = this.transitionList.get(this.currentInterleaving).size() - 1;
for (int i = size; i >= 0; i--) {
final Envelope env = this.transitionList.get(this.currentInterleaving).get(i);
if (!valid || env.getRank() == rank) {
this.currentTransitionIndex = i;
return env;
}
}
return null;
}
/**
* Returns the envelope that matches with the envelope passed in.
*
* @param env
* The Envelope whose match we are requesting.
* @return Envelope The Envelope that matches, or null if there is no match.
*/
public Envelope getMatchingTransition(Envelope env) {
if (env.getIssueIndex() < 0) {
return null;
}
return env.getMatch_envelope();
}
/**
* Finds the next transition for the specified rank in the current
* interleaving.
*
* @param rank
* The rank of the next Envelope to find.
* @return Envelope The next Envelope in the current interleaving for the
* specified rank.
*/
synchronized public Envelope getNextTransition(int rank) {
if (this.currentTransitionIndex + 1 >= this.transitionList.get(this.currentInterleaving).size()) {
return null;
}
// If the rank is invalid, treat it as any rank can advance.
if (rank < 0 || rank >= this.numRanks) {
this.currentTransitionIndex++;
return this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex);
}
final int end = this.transitionList.get(this.currentInterleaving).size();
for (int i = this.currentTransitionIndex + 1; i < end; i++) {
final Envelope e = this.transitionList.get(this.currentInterleaving).get(i);
if (e.getRank() == rank) {
this.currentTransitionIndex = i;
return e;
}
}
return null;
}
/**
* Returns the number of ranks used.
*
* @param none
* @return int The number of ranks used.
*/
public int getNumRanks() {
return this.numRanks;
}
/**
* Finds the previous transition for the specified rank in the current
* interleaving.
*
* @param rank
* The rank to find the previous transition for.
* @return Envelope The previous Envelope in the current interleaving for
* the specified rank.
*/
synchronized public Envelope getPreviousTransition(int rank) {
if (this.currentTransitionIndex <= 0) {
return null;
}
// If the rank is invalid, treat it as if any rank can be changed.
if (rank < 0 || rank >= this.numRanks) {
this.currentTransitionIndex--;
return this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex);
}
for (int i = this.currentTransitionIndex - 1; i >= 0; i--) {
final Envelope env = this.transitionList.get(this.currentInterleaving).get(i);
if (env.getRank() == rank) {
this.currentTransitionIndex = i;
return env;
}
}
return null;
}
/**
* Observes the current envelope and discovers which ranks are involved with
* it at this moment.
*
* @param total
* The integer array containing all ranks involved.
* @return String The String representing the ranks of those involved with
* the current call.
*/
public String getRanksInvolved(int totalRanksInvolved[]) {
final Envelope currentEnvelope = this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex);
final int rank = currentEnvelope.getRank();
String result = Integer.toString(rank);
final int currentLineNumber = currentEnvelope.getLinenumber();
// We can safely assume that we are currently on the 1st iteration
int i = this.currentTransitionIndex;
final int size = this.transitionList.get(this.currentInterleaving).size();
int numRanksInvloved = 1;
// start at next envelope
for (i++; i < size; i++) {
final Envelope env = this.transitionList.get(this.currentInterleaving).get(i);
if (currentLineNumber == env.getLinenumber()) {
numRanksInvloved++;
result += "," + env.getRank(); //$NON-NLS-1$
} else {
break;
}
}
totalRanksInvolved[0] = numRanksInvloved;
return result;
}
/**
* Returns and HashMap of Envelopes that holds each envelope that contains
* a resource leak.
*
* @param none
* @return HashMap<Integer, Envelope> The set of resource leaks.
*/
public HashMap<Integer, Envelope> getResourceLeaks() {
return this.resourceLeaks;
}
/**
* Returns the number of interleavings found for this source file.
*
* @param none
* @return int The total number of interleavings.
*/
public int getTotalInterleavings() {
return this.transitionList.size();
}
/**
* Returns an ArrayList of ArrayLists of Envelopes. Each ArrayList
* corresponds to a particular interleaving, and holds envelopes
* representing individual MPI call transitions.
*
* @param none
* @return ArrayList<ArrayList<Envelope>> List representing each MPI Call in
* each possible interleaving.
*/
public ArrayList<ArrayList<Envelope>> getTransitionList() {
return this.transitionList;
}
/**
* Returns the list of the interleavings listing the calls pertaining to MPI
* type mismatches.
*
* @param none
* @return HashMap<Integer, String>The unique set of MPI type mismatches.
*/
public HashMap<Integer, String> getTypeMismatches() {
return this.typeMismatches;
}
/**
* Returns a boolean representing whether or not there is an assertion.
* violation.
*
* @param none
* @return boolean True if there was an assertion violation, false
* otherwise.
*/
public boolean hasAssertion() {
return this.assertionViolation;
}
/**
* Returns a boolean representing whether or not there is a deadlock.
*
* @param none
* @return boolean True if there was a deadlock, false otherwise.
*/
public boolean hasDeadlock() {
return this.deadlock;
}
/**
* Returns whether or not the transition list contains an error.
*
* @param none
* @return boolean True for an error, false otherwise.
*/
public boolean hasError() {
if (this.assertionViolation || this.deadlock) {
return true;
}
final Iterator<HashMap<String, Envelope>> itr = this.errorCalls.iterator();
while (itr.hasNext()) {
final HashMap<String, Envelope> currentHash = itr.next();
if (currentHash != null && !currentHash.isEmpty()) {
return true;
}
}
return false;
}
/**
* Returns whether or not a functionally irrelevant barrier was detected.
*
* @param none
* @return boolean True if a functionally irrelevant barrier was detected, false otherwise.
*/
public boolean hasFIB() {
return this.fib;
}
/**
* Returns a boolean representing whether or not there is a next
* interleaving from the currentInterleaving.
*
* @param none
* @return boolean True if there is a next interleaving, false otherwise.
*/
synchronized public boolean hasNextInterleaving() {
return this.currentInterleaving + 1 < this.transitionList.size();
}
/**
* Returns true if there is a next transition, false otherwise.
*
* @param none
* @return boolean True if the current interleaving has a next transition,
* false otherwise.
*/
synchronized public boolean hasNextTransition() {
return this.currentTransitionIndex + 1 < this.transitionList.get(
this.currentInterleaving).size();
}
/**
* Returns a boolean representing whether or not there is a previous
* interleaving from the currentInterleaving.
*
* @param none
* @return boolean True if there is a previous interleaving, false
* otherwise.
*/
synchronized public boolean hasPreviousInterleaving() {
return this.currentInterleaving != 0;
}
/**
* Returns true if there is a previous transition, false otherwise.
*
* @param none
* @return boolean True if the current interleaving has a previous
* transition, false otherwise.
*/
// TODO This is not currently being used
public boolean hasPreviousTransition() {
return this.currentTransitionIndex > 0;
}
/**
* Returns a boolean representing whether or not a resource leak was detected.
*
* @param none
* @return boolean True if a resource leak was detected, false otherwise.
*/
public boolean hasResourceLeak() {
return this.resourceLeak;
}
/**
* Returns true if there is a next non-repetitive transition, false
* otherwise.
*
* @param none
* @return boolean True if the current interleaving has a valid next
* transition, false otherwise.
*/
synchronized public boolean hasValidNextTransition(int rank) {
if (this.currentTransitionIndex == -1) {
try {
this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex + 1);
return true;
} catch (final Exception e) {
return false;
}
}
int tempIndex = this.currentTransitionIndex;
while (tempIndex < this.transitionList.get(this.currentInterleaving).size()) {
final int line1 = this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex).getLinenumber();
final int line2 = this.transitionList.get(this.currentInterleaving).get(tempIndex).getLinenumber();
if (line1 == line2) {
tempIndex++;
continue;
} else if (rank == -1 || this.transitionList.get(this.currentInterleaving).get(tempIndex).getRank() == rank) {
return true;
}
tempIndex++;
}
return false;
}
/**
* Returns true if there is a non-repetitive previous transition, false
* otherwise.
*
* @param none
* @return boolean True if the current interleaving has a valid previous
* transition, false otherwise.
*/
public boolean hasValidPreviousTransition(int rank) {
int tempIndex = this.currentTransitionIndex - 1;
while (tempIndex >= 0) {
final int line1 = this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex).getLinenumber();
final int line2 = this.transitionList.get(this.currentInterleaving).get(tempIndex).getLinenumber();
final boolean collective = this.transitionList.get(this.currentInterleaving).get(this.currentTransitionIndex)
.isCollective();
if (line1 == line2 && rank == -1 && collective) {
tempIndex--;
continue;
} else if (rank == -1 || this.transitionList.get(this.currentInterleaving).get(tempIndex).getRank() == rank) {
return true;
}
tempIndex--;
}
return false;
}
/*
* This is where the bulk of the p2p and collective matching gets done.
*/
private void parseLogFile(IFile logFile) {
final HashMap<String, Envelope> p2pMatches = new HashMap<String, Envelope>();
final HashMap<String, ArrayList<Envelope>> collectiveMatches = new HashMap<String, ArrayList<Envelope>>();
final HashMap<Integer, Integer> issueOrders = new HashMap<Integer, Integer>();
final ArrayList<HashMap<String, Integer>> collectiveCount = new ArrayList<HashMap<String, Integer>>();
Scanner scanner = null;
String line = null;
int interleaving = -1;
boolean fileReadSuccess = false;
try {
scanner = new Scanner(logFile.getContents());
// Check for empty log file
if (!scanner.hasNextLine()) {
return;
}
line = scanner.nextLine();
try {
this.numRanks = Integer.parseInt(line);
fileReadSuccess = true;
} catch (final NumberFormatException e) {
GemUtilities.logExceptionDetail(e);
}
if (fileReadSuccess) {
for (int i = 0; i < this.numRanks; i++) {
collectiveCount.add(new HashMap<String, Integer>());
}
}
while (scanner.hasNext()) {
// If the analysis has been aborted then stop parsing
if (GemUtilities.isAborted()) {
return;
}
// Check if we're processing warnings at the end of the log file
if (!line.startsWith("[")) { //$NON-NLS-1$
line = scanner.nextLine();
}
// identify the deadlock interleavings
if (line.endsWith("DEADLOCK")) { //$NON-NLS-1$
if (this.deadlockInterleavings == null) {
this.deadlock = true;
this.deadlockInterleavings = new ArrayList<Integer>();
this.deadlockIndex = 0;
}
final StringTokenizer st = new StringTokenizer(line);
this.deadlockInterleavings.add(Integer.parseInt(st.nextToken()));
continue;
}
// If this line indicates FIB, process all of them
if (line.equalsIgnoreCase("[FIB]")) { //$NON-NLS-1$
this.fib = true;
this.irrelevantBarriers = new HashMap<Integer, String>();
line = scanner.nextLine();
// Marks end of FIB list
while (!line.equals("") && !line.startsWith("[")) { //$NON-NLS-1$ //$NON-NLS-2$
final StringTokenizer st = new StringTokenizer(line);
st.nextToken();
final int lineNumber = Integer.parseInt(st.nextToken());
this.irrelevantBarriers.put(lineNumber, line);
// See if this is the end of the log file.
if (!scanner.hasNextLine()) {
break;
}
line = scanner.nextLine();
}
continue;
}
// If this line indicates TYPE MISMATCH, process all of them
if (line.equalsIgnoreCase("[TYPEMISMATCH]")) { //$NON-NLS-1$
this.typeMismatches = new HashMap<Integer, String>();
line = scanner.nextLine();
// Marks end of FIB list
while (!line.equals("") && !line.startsWith("[")) { //$NON-NLS-1$ //$NON-NLS-2$
final StringTokenizer st = new StringTokenizer(line);
st.nextToken();
final int lineNumber = Integer.parseInt(st.nextToken());
this.typeMismatches.put(lineNumber, line);
// See if this is the end of the log file.
if (!scanner.hasNextLine()) {
break;
}
line = scanner.nextLine();
}
continue;
}
final Envelope env = Envelope.parse(line);
if (env == null) {
throw new ParseException(line, interleaving);
// continue;
} else if (env.isAssertion()) {
this.assertionViolation = true;
env.setInterleaving((interleaving < 0) ? 1 : interleaving);
} else if (env.getFunctionName() == "MPI_assert") { //$NON-NLS-1$
if (scanner.hasNext()) {
scanner.nextLine();
}
} else if (env.isLeak()) {
if (this.resourceLeaks == null) {
this.resourceLeak = true;
this.resourceLeaks = new HashMap<Integer, Envelope>();
}
this.resourceLeaks.put(env.getLinenumber(), env);
}
// Advance to the next interleaving if needed. Also need to
// clear all the data structures.
if (env.getInterleaving() != interleaving) {
// add a transition list for the interleaving
this.transitionList.add(new ArrayList<Envelope>());
interleaving = env.getInterleaving();
this.errorCalls.add(interleaving, null);
for (int j = 0; j < this.numRanks; j++) {
collectiveCount.get(j).clear();
}
p2pMatches.clear();
collectiveMatches.clear();
}
/*
* Check for calls that were not issued and add them to the
* interleaving's HashMap in the error list. However, leaks
* should not be added!
*/
if (env.getIssueIndex() == -1 && !env.isLeak()) {
if (this.errorCalls.get(interleaving) == null) {
this.errorCalls.add(interleaving, new HashMap<String, Envelope>());
}
final String key = env.getFunctionName() + env.getFilePath() + env.getLinenumber();
this.errorCalls.get(interleaving).put(key, env);
}
/*
* If we have already seen the issue orders, set to -1, meaning
* not issued.
*/
if (issueOrders.containsKey(env.getIssueIndex())) {
env.setIssueIndex(-1);
} else {
issueOrders.put(env.getIssueIndex(), 0);
}
/*
* See if there is a P2P match - the HashMap contains the
* Envelope's interleaving, rank, and index. If there is a
* match, then store it in the envelope. This is so we don't
* have to search through everything later when we need the
* match.
*/
if (env.getMatch_index() >= 0 && env.getMatch_rank() >= 0) {
final String p2pMatchString = env.getInterleaving() + "_" + env.getMatch_rank() + "_" + env.getMatch_index(); //$NON-NLS-1$ //$NON-NLS-2$
if (p2pMatches.containsKey(p2pMatchString)) {
final Envelope match = p2pMatches.get(p2pMatchString);
env.pairWithEnvelope(match);
if (env.getFunctionName() != "MPI_Probe" && env.getFunctionName() != "MPI_Iprobe") { //$NON-NLS-1$ //$NON-NLS-2$
p2pMatches.remove(p2pMatchString);
}
} else {
p2pMatches.put(env.getInterleaving() + "_" + env.getRank() + "_" + env.getIndex(), env); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/*
* Next, see if there is a collective match. Also, don't want to
* match for communicators of size one, since there will be
* nothing to add.
*/
if (env.isCommunicator_set() && env.getCommunicator_ranks().size() > 1
&& env.getCommunicator_ranks_string() != null) {
int count;
String collective = env.getFunctionName() + " " + env.isCommunicator_set(); //$NON-NLS-1$
if (collectiveCount.get(env.getRank()).containsKey(collective)) {
count = collectiveCount.get(env.getRank()).get(collective);
} else {
count = 0;
}
collectiveCount.get(env.getRank()).put(collective, count + 1);
// Now see if there are others with the same collective.
collective = env.getFunctionName() + " " + count + " " + env.getCommunicator_ranks_string(); //$NON-NLS-1$ //$NON-NLS-2$
if (collectiveMatches.containsKey(collective)) {
final ArrayList<Envelope> matches = collectiveMatches.get(collective);
for (final Envelope e : matches) {
env.addCollectiveMatch(e);
}
matches.add(env);
// See if we have all of the matches, and if so, remove.
if (matches.size() == env.getCommunicator_ranks()
.size()) {
collectiveMatches.remove(collective);
}
} else {
final ArrayList<Envelope> matches = new ArrayList<Envelope>();
matches.add(env);
collectiveMatches.put(collective, matches);
}
}
// Add to the list, but if this is a resource leak DO NOT
if (!env.isLeak()) {
this.transitionList.get(this.transitionList.size() - 1).add(env);
}
}
// If no transitions found in the interleaving, add at least one.
if (this.transitionList.size() == 0) {
this.transitionList.add(new ArrayList<Envelope>());
}
// Sort the transitions if the preference is enabled.
final String str = GemPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.GEM_PREF_STEP_ORDER);
final int size = this.transitionList.size();
if (str.equals("issueOrder")) { //$NON-NLS-1$
// Sort by internal issue order
for (int k = 0; k < size; k++) {
Collections.sort(this.transitionList.get(k), new InternalIssueOrderSorter());
}
} else {
// Sort by program order
for (int l = 0; l < size; l++) {
Collections.sort(this.transitionList.get(l), new ProgramOrderSorter());
}
}
this.currentInterleaving = 0;
this.currentTransitionIndex = -1;
} catch (final CoreException ce) {
GemUtilities.logExceptionDetail(ce);
} catch (final ParseException pe) {
GemUtilities.logExceptionDetail(pe);
} finally {
if (scanner != null) {
scanner.close();
}
}
}
/**
* Sets the envelope involved with the current transition to the one
* specified.
*
* @param none
* @return Envelope Null if it didn't make sense to place the specified
* Envelope, the Envelope otherwise.
*/
// TODO This is not currently being used
synchronized public Envelope setCurrentTransition(Envelope env) {
if (env == null) {
return null;
}
if (env.getInterleaving() - 1 < 0 || env.getInterleaving() - 1 >= this.transitionList.size()) {
return null;
}
for (int i = 0; i < this.transitionList.get(env.getInterleaving() - 1).size(); i++) {
if (this.transitionList.get(env.getInterleaving() - 1).get(i) == env) {
this.currentInterleaving = env.getInterleaving() - 1;
this.currentTransitionIndex = i;
return env;
}
}
return null;
}
/**
* Moves to the next interleaving.
*
* @param none
* @return boolean True if the operation was successful, false otherwise.
*/
synchronized public boolean setNextInterleaving() {
if (this.currentInterleaving + 1 >= this.transitionList.size()) {
return false;
}
this.currentInterleaving++;
this.currentTransitionIndex = -1;
return true;
}
/**
* Moves to the previous interleaving.
*
* @param none
* @return boolean True if the operation was successful, false otherwise.
*/
synchronized public boolean setPreviousInterleaving() {
if (this.currentInterleaving == 0) {
return false;
}
this.currentInterleaving--;
this.currentTransitionIndex = -1;
return true;
}
}