Skip to content

Commit

Permalink
Merge pull request #169 from csanadtelbisz/telbisz_por (DPOR)
Browse files Browse the repository at this point in the history
DPOR (Dynamic Partial Order Reduction)
  • Loading branch information
csanadtelbisz authored Jul 4, 2022
2 parents 8224ad1 + 5dae508 commit de5fef9
Show file tree
Hide file tree
Showing 9 changed files with 504 additions and 56 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ buildscript {

allprojects {
group = "hu.bme.mit.inf.theta"
version = "4.0.0"
version = "4.1.0"

apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts"))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/*
* Copyright 2022 Budapest University of Technology and Economics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package hu.bme.mit.theta.analysis.algorithm;

import hu.bme.mit.theta.analysis.Action;
import hu.bme.mit.theta.analysis.LTS;
import hu.bme.mit.theta.analysis.State;
import hu.bme.mit.theta.core.decl.Decl;
import hu.bme.mit.theta.core.type.Type;

import java.util.*;
import java.util.function.Predicate;

/**
* LTS with a POR (Partial Order Reduction) algorithm applied as a filter when returning enabled actions.
*
* @param <S> the type of the state
* @param <A> the type of the action (transition in the state space)
* @param <T> the type of the transition in the original formalism
*/
public abstract class PorLts<S extends State, A extends Action, T> implements LTS<S, A> {

/* CACHE COLLECTIONS */

/**
* Shared objects (~global variables) used by a transition.
*/
private final HashMap<T, Set<? extends Decl<? extends Type>>> usedSharedObjects = new HashMap<>();

/**
* Shared objects (~global variables) that are used by the key transition or by transitions reachable from the
* current state via a given transition.
*/
private final HashMap<T, Set<? extends Decl<? extends Type>>> influencedSharedObjects = new HashMap<>();

/**
* Backward transitions in the transition system (a transition of a loop).
*/
protected final Set<T> backwardTransitions = new HashSet<>();


/**
* Returns the enabled actions in the ARG from the given state filtered with a POR algorithm.
*
* @param state the state whose enabled actions we would like to know
* @return the enabled actions
*/
@Override
public Collection<A> getEnabledActionsFor(S state) {
// Collecting enabled actions
Collection<A> allEnabledActions = getAllEnabledActionsFor(state);

// Calculating the persistent set starting from every (or some of the) enabled transition; the minimal persistent set is stored
Collection<A> minimalPersistentSet = new HashSet<>();
Collection<A> persistentSetFirstActions = getPersistentSetFirstActions(allEnabledActions);
for (A firstAction : persistentSetFirstActions) {
Collection<A> persistentSet = calculatePersistentSet(allEnabledActions, firstAction);
if (minimalPersistentSet.size() == 0 || persistentSet.size() < minimalPersistentSet.size()) {
minimalPersistentSet = persistentSet;
}
}

return minimalPersistentSet;
}

/**
* Calculates a persistent set of enabled actions starting from a particular action.
*
* @param enabledActions the enabled actions in the present state
* @param firstAction the action who will be added to the persistent set as the first action
* @return the persistent set of enabled actions
*/
protected Collection<A> calculatePersistentSet(Collection<A> enabledActions, A firstAction) {
if (isBackwardAction(firstAction)) {
return new HashSet<>(enabledActions);
}

Set<A> persistentSet = new HashSet<>();
Set<A> otherActions = new HashSet<>(enabledActions); // actions not in the persistent set
persistentSet.add(firstAction);
otherActions.remove(firstAction);

boolean addedNewAction = true;
while (addedNewAction) {
addedNewAction = false;
Set<A> actionsToRemove = new HashSet<>();
for (A action : otherActions) {
// for every action that is not in the persistent set it is checked whether it should be added to the persistent set
// (because it is dependent with an action already in the persistent set)
if (persistentSet.stream().anyMatch(persistentSetAction -> areDependents(persistentSetAction, action))) {
if (isBackwardAction(action)) {
return new HashSet<>(enabledActions); // see POR algorithm for the reason of removing backward transitions
}

persistentSet.add(action);
actionsToRemove.add(action);
addedNewAction = true;
}
}
actionsToRemove.forEach(otherActions::remove);
}

return persistentSet;
}

/**
* Returns all the enabled actions in a state.
*
* @param state the state whose enabled actions are to be returned
* @return the enabled actions in the state
*/
protected abstract Collection<A> getAllEnabledActionsFor(S state);

/**
* Returns the actions from where persistent sets will be calculated (a subset of the given enabled actions).
* The default implementation returns all enabled actions.
*
* @param allEnabledActions all the enabled actions in the present state
* @return the actions from where persistent sets will be calculated
*/
protected Collection<A> getPersistentSetFirstActions(Collection<A> allEnabledActions) {
return allEnabledActions;
}

/**
* Determines whether an action is dependent with another one (based on the notions introduced for the POR
* algorithm) already in the persistent set.
*
* @param persistentSetAction the action in the persistent set
* @param action the other action (not in the persistent set)
* @return true, if the two actions are dependent in the context of persistent sets
*/
protected boolean areDependents(A persistentSetAction, A action) {
return canEnOrDisableEachOther(persistentSetAction, action) ||
getInfluencedSharedObjects(getTransitionOf(action)).stream().anyMatch(varDecl ->
getCachedUsedSharedObjects(getTransitionOf(persistentSetAction)).contains(varDecl));
}

/**
* Determines whether two actions can enable or disable each other (if true, the two actions are dependent).
*
* @param action1 action 1
* @param action2 action 2
* @return true, if the two actions can enable or disable each other
*/
protected abstract boolean canEnOrDisableEachOther(A action1, A action2);

/**
* Determines whether the given action is a backward action.
*
* @param action the action to be classified as backward action or non-backward action
* @return true, if the action is a backward action
*/
protected boolean isBackwardAction(A action) {
return backwardTransitions.contains(getTransitionOf(action));
}

/**
* Get the original transition of an action (from which the action has been created).
*
* @param action whose original transition is to be returned
* @return the original transition
*/
protected abstract T getTransitionOf(A action);

/**
* Returns the successive transitions of a transition (transitions whose source is the target of the given
* parameter).
*
* @param transition whose successive transitions is to be returned
* @return the successive transitions of the transition given as the parameter
*/
protected abstract Set<T> getSuccessiveTransitions(T transition);


/**
* Returns the shared objects (~global variables) that an action uses (it is present in one of its labels).
*
* @param transition whose shared objects are to be returned
* @return the set of used shared objects
*/
protected abstract Set<? extends Decl<? extends Type>> getDirectlyUsedSharedObjects(T transition);

/**
* Returns the shared objects (~global variables) that an action uses.
*
* @param transition whose shared objects are to be returned
* @return the set of directly or indirectly used shared objects
*/
protected Set<? extends Decl<? extends Type>> getUsedSharedObjects(T transition) {
return getDirectlyUsedSharedObjects(transition);
}

/**
* Same as {@link PorLts#getUsedSharedObjects(T transition)} with an additional cache layer.
*
* @param transition whose shared objects are to be returned
* @return the set of directly or indirectly used shared objects
*/
private Set<? extends Decl<? extends Type>> getCachedUsedSharedObjects(T transition) {
if (!usedSharedObjects.containsKey(transition)) {
Set<? extends Decl<? extends Type>> vars = getUsedSharedObjects(transition);
usedSharedObjects.put(transition, vars);
}
return usedSharedObjects.get(transition);
}

/**
* Returns the shared objects (~global variables) used by the given transition or by transitions that are reachable
* via the given transition ("influenced shared objects").
*
* @param transition whose successor transitions' shared objects are to be returned.
* @return the set of influenced shared objects
*/
protected Set<? extends Decl<? extends Type>> getInfluencedSharedObjects(T transition) {
if (!influencedSharedObjects.containsKey(transition)) {
influencedSharedObjects.put(transition, getSharedObjectsWithBFS(transition, t -> true));
}
return influencedSharedObjects.get(transition);
}

/**
* Returns shared objects (~global variables) encountered in a search starting from a given transition.
*
* @param startTransition the start point (transition) of the search
* @param visitTransition the predicate that tells whether a transition has to be explored
* @return the set of encountered shared objects
*/
protected Set<? extends Decl<? extends Type>> getSharedObjectsWithBFS(T startTransition, Predicate<T> visitTransition) {
Set<Decl<? extends Type>> vars = new HashSet<>();
List<T> exploredTransitions = new ArrayList<>();
List<T> transitionsToExplore = new ArrayList<>();
transitionsToExplore.add(startTransition);

while (!transitionsToExplore.isEmpty()) {
T exploring = transitionsToExplore.remove(0);
vars.addAll(getDirectlyUsedSharedObjects(exploring));
Set<T> successiveTransitions = getSuccessiveTransitions(exploring);

for (var newTransition : successiveTransitions) {
if (!exploredTransitions.contains(newTransition) && visitTransition.test(newTransition)) {
transitionsToExplore.add(newTransition);
}
}
exploredTransitions.add(exploring);
}
return vars;
}

/**
* Collects backward transitions of the transition system.
*/
protected abstract void collectBackwardTransitions();
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@
import hu.bme.mit.theta.xcfa.analysis.common.autoexpl.XcfaGlobalStaticAutoExpl;
import hu.bme.mit.theta.xcfa.analysis.common.autoexpl.XcfaNewAtomsAutoExpl;
import hu.bme.mit.theta.xcfa.analysis.common.autoexpl.XcfaNewOperandsAutoExpl;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.XcfaInitFunc;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.XcfaLts;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.XcfaOrd;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.XcfaPrecRefiner;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.XcfaTransFunc;
import hu.bme.mit.theta.xcfa.analysis.impl.interleavings.*;
import hu.bme.mit.theta.xcfa.analysis.impl.singlethread.XcfaDistToErrComparator;
import hu.bme.mit.theta.xcfa.analysis.impl.singlethread.XcfaSTInitFunc;
import hu.bme.mit.theta.xcfa.analysis.impl.singlethread.XcfaSTLts;
Expand Down Expand Up @@ -101,7 +97,7 @@ public enum Refinement {
public enum Algorithm {
SINGLETHREAD {
@Override
public LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts() {
public LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts(XCFA xcfa) {
return new XcfaSTLts();
}

Expand Down Expand Up @@ -134,7 +130,7 @@ public <S extends ExprState, P extends Prec, A extends StmtAction> Analysis<Xcfa

INTERLEAVINGS {
@Override
public LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts() {
public LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts(XCFA xcfa) {
return new XcfaLts();
}

Expand Down Expand Up @@ -162,9 +158,41 @@ public <S extends ExprState> PartialOrd<XcfaState<S>> getPartialOrder(final Part
public <S extends ExprState, P extends Prec, A extends StmtAction> Analysis<XcfaState<S>, A, XcfaPrec<P>> getAnalysis(final List<XcfaLocation> initLocs, final Analysis<S, A, P> analysis) {
return XcfaAnalysis.create(initLocs, getPartialOrder(analysis.getPartialOrd()), getInitFunc(initLocs, analysis.getInitFunc()), getTransFunc(analysis.getTransFunc()));
}
},

INTERLEAVINGS_POR {
@Override
public LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts(XCFA xcfa) {
return new XcfaPorLts(xcfa);
}

@Override
public <S extends ExprState, P extends Prec> InitFunc<XcfaState<S>, XcfaPrec<P>> getInitFunc(List<XcfaLocation> initLocs, InitFunc<S, P> initFunc) {
return INTERLEAVINGS.getInitFunc(initLocs, initFunc);
}

@Override
public <S extends ExprState, A extends StmtAction, P extends Prec> TransFunc<XcfaState<S>, A, XcfaPrec<P>> getTransFunc(TransFunc<S, A, P> transFunc) {
return INTERLEAVINGS.getTransFunc(transFunc);
}

@Override
public <P extends Prec, R extends Refutation> PrecRefiner<XcfaState<ExprState>, ? extends StmtAction, XcfaPrec<P>, R> getPrecRefiner(RefutationToPrec<P, R> refToPrec) {
return INTERLEAVINGS.getPrecRefiner(refToPrec);
}

@Override
public <S extends ExprState> PartialOrd<XcfaState<S>> getPartialOrder(PartialOrd<S> partialOrd) {
return INTERLEAVINGS.getPartialOrder(partialOrd);
}

@Override
public <S extends ExprState, P extends Prec, A extends StmtAction> Analysis<? extends XcfaState<? extends S>, ? extends A, ? extends XcfaPrec<P>> getAnalysis(List<XcfaLocation> initLoc, Analysis<S, A, P> analysis) {
return INTERLEAVINGS.getAnalysis(initLoc, analysis);
}
};

public abstract LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts();
public abstract LTS<? extends XcfaState<?>, ? extends XcfaAction> getLts(XCFA xcfa);

public abstract <S extends ExprState, P extends Prec> InitFunc<XcfaState<S>, XcfaPrec<P>> getInitFunc(final List<XcfaLocation> initLocs, final InitFunc<S, P> initFunc);

Expand Down Expand Up @@ -299,7 +327,7 @@ public XcfaConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) {
}

public XcfaConfig<? extends State, ? extends Action, ? extends Prec> build(final XCFA xcfa) {
final LTS lts = algorithm.getLts();
final LTS lts = algorithm.getLts(xcfa);
final Abstractor abstractor;
final Refiner refiner;
final XcfaPrec prec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,25 @@

public class XcfaAction extends hu.bme.mit.theta.xcfa.analysis.common.XcfaAction {
private final Integer process;
private final XcfaEdge edge;
private final List<XcfaLabel> labels;
private final XcfaLocation source;
private final XcfaLocation target;

protected XcfaAction(final Integer process, final XcfaLocation source, final XcfaLocation target, final List<XcfaLabel> labels) {
protected XcfaAction(final Integer process, final XcfaEdge edge, final List<XcfaLabel> labels) {
this.process = checkNotNull(process);
this.source = checkNotNull(source);
this.target = checkNotNull(target);
this.edge = checkNotNull(edge);
this.source = checkNotNull(edge.getSource());
this.target = checkNotNull(edge.getTarget());
this.labels = checkNotNull(labels);
}

public static XcfaAction create(final Integer process, final XcfaEdge edge) {
return new XcfaAction(process, edge.getSource(), edge.getTarget(), edge.getLabels());
return new XcfaAction(process, edge, edge.getLabels());
}

public XcfaEdge getEdge() {
return edge;
}

public XcfaLocation getSource() {
Expand Down Expand Up @@ -75,6 +81,6 @@ public Integer getProcess() {
}

public XcfaAction withLabels(final List<XcfaLabel> stmts) {
return new XcfaAction(process, source, target, stmts);
return new XcfaAction(process, edge, stmts);
}
}
Loading

0 comments on commit de5fef9

Please sign in to comment.