getTrajectories() {
+ return trajectories;
+ }
+
+ public Object getStateCode() {
+ return stateId;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java
new file mode 100644
index 00000000..d1a41065
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/SolutionTrajectory.java
@@ -0,0 +1,338 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.viatra.dse.base.DseIdPoolHelper;
+import org.eclipse.viatra.dse.designspace.api.IBacktrackListener;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
+import org.eclipse.viatra.dse.util.EMFHelper;
+import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher;
+import org.eclipse.viatra.query.runtime.emf.EMFScope;
+import org.eclipse.viatra.query.runtime.matchers.ViatraQueryRuntimeException;
+import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+/**
+ * A SolutionTrajectory represents a trajectory (i.e. sequence of transformation
+ * rule applications), which can transform the initial model to a desired state.
+ * An instance of this class holds the the actual rule sequence and the
+ * corresponding activation codes. Furthermore it can be used to perform the
+ * transformation on a given model (if possible).
+ *
+ * It is also possible to undo the transformation if initialized with an editing
+ * domain.
+ *
+ * The instance of this class can be reused for different models.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class SolutionTrajectory {
+
+ private final List activationCodes;
+ private final List> transformationRules;
+ private final IStateCoderFactory stateCoderFactory;
+ private Fitness fitness;
+ private Solution solution;
+
+ private ViatraQueryEngine engine;
+ private Notifier model;
+ private EditingDomain editingDomain;
+ private IStateCoder stateCoder;
+ private IBacktrackListener listener;
+
+ private int currentIndex;
+
+ public SolutionTrajectory(final List activationCodes,
+ final List> transformationRules, final IStateCoderFactory stateCoderFactory,
+ final IBacktrackListener backtrackListener) {
+ Objects.requireNonNull(transformationRules, "Parameter transformationRules cannot be null!");
+ Objects.requireNonNull(stateCoderFactory, "Parameter stateCoderFactory cannot be null!");
+ Objects.requireNonNull(activationCodes, "Parameter activations cannot be null!");
+ Preconditions.checkState(transformationRules.size() == activationCodes.size(),
+ "The two List parameters must be the same in size.");
+
+ this.activationCodes = activationCodes;
+ this.transformationRules = transformationRules;
+ this.stateCoderFactory = stateCoderFactory;
+ this.listener = backtrackListener;
+ currentIndex = 0;
+ }
+
+ /**
+ * Initialize this SolutionTrajectory for transforming the model along the
+ * trajectory.
+ *
+ * @param model The model.
+ * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
+ */
+ public void setModel(Notifier model) {
+ editingDomain = null;
+ EMFScope scope = new EMFScope(model);
+ this.engine = ViatraQueryEngine.on(scope);
+ this.model = model;
+ stateCoder = stateCoderFactory.createStateCoder();
+ stateCoder.init(model);
+ currentIndex = 0;
+ DseIdPoolHelper.INSTANCE.disposeByThread();
+ DseIdPoolHelper.INSTANCE.registerRules(rule -> {
+ int id = 0;
+ for (BatchTransformationRule, ?> r : transformationRules.subList(0, currentIndex)) {
+ if (r.equals(rule)) {
+ id++;
+ }
+ }
+ return id;
+ }, new HashSet>(transformationRules));
+ }
+
+ /**
+ * Initialize this SolutionTrajectory for transforming the given model along the
+ * trajectory.
+ *
+ * The transformation will be reversible by creating an {@link EditingDomain} on
+ * the model.
+ *
+ * @param modelRoot The root of the model.
+ * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
+ */
+ public void setModelWithEditingDomain(Notifier modelRoot) {
+ setModel(modelRoot);
+ editingDomain = EMFHelper.createEditingDomain(model);
+ }
+
+ /**
+ * Transforms the given model along the trajectory.
+ *
+ * @param modelRoot The root of the model.
+ * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
+ */
+ public void doTransformation(Notifier modelRoot) {
+ setModel(modelRoot);
+ doTransformation();
+ }
+
+ /**
+ * Transforms the given model along the trajectory.
+ *
+ * The transformation will be reversible by creating an {@link EditingDomain} on
+ * the model.
+ *
+ * @param modelRoot The root of the model.
+ * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
+ */
+ public void doTransformationUndoable(Notifier modelRoot) {
+ setModelWithEditingDomain(modelRoot);
+ doTransformation();
+ }
+
+ /**
+ * Transforms the given model along the trajectory. To initialize the model call
+ * the {@link SolutionTrajectory#setModel(Notifier)} method.
+ *
+ * @throws Exception If the activation to fire is not found.
+ * Possible problems: wrong model, bad state
+ * serializer.
+ * @throws ViatraQueryRuntimeException If the VIATRA Query fails to initialize.
+ */
+ public void doTransformation() {
+ while (doNextTransformation())
+ ;
+ }
+
+ /**
+ * Transforms the given model by one step to the solution (makes one step in the
+ * trajectory). To initialize the model call the
+ * {@link SolutionTrajectory#setModel(Notifier)} method.
+ *
+ * @throws ViatraQueryRuntimeException
+ */
+ public boolean doNextTransformation() {
+ if (currentIndex >= activationCodes.size()) {
+ return false;
+ } else {
+ doNextTransformation(currentIndex);
+ currentIndex++;
+ return true;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doNextTransformation(int index) {
+ Objects.requireNonNull(model, "The model cannot be null! Use the setModel method.");
+
+ // cast for the ".process(match)" method.
+ BatchTransformationRule, ?> tr = transformationRules.get(index);
+ Object activationCode = activationCodes.get(index);
+
+ ViatraQueryMatcher> matcher = tr.getPrecondition().getMatcher(engine);
+
+ boolean isActivationFound = false;
+ for (final IPatternMatch match : matcher.getAllMatches()) {
+ Object matchHash = stateCoder.createActivationCode(match);
+ if (matchHash.equals(activationCode)) {
+ @SuppressWarnings("rawtypes")
+ final Consumer action = tr.getAction();
+
+ if (editingDomain == null) {
+ action.accept(match);
+ } else {
+ ChangeCommand cc = new ChangeCommand(model) {
+ @Override
+ protected void doExecute() {
+ action.accept(match);
+ }
+ };
+ long start = System.nanoTime();
+ editingDomain.getCommandStack().execute(cc);
+ listener.forwardWorked(System.nanoTime() - start);
+ }
+
+ isActivationFound = true;
+ break;
+ }
+ }
+ if (!isActivationFound) {
+ throw new UncheckedExecutionException(
+ "Activation was not found for transformation! Possible cause: wrong model, bad state coder. index: "
+ + index + " Activation code: " + activationCode,
+ null);
+ }
+ }
+
+ /**
+ * Call this method to undo the last transformation.
+ *
+ * @return True, if it was successful.
+ */
+ public boolean undoLastTransformation() {
+ Objects.requireNonNull(editingDomain, "To be able to undo the transformation initialize with editing domain.");
+ long start = System.nanoTime();
+ boolean result;
+
+ if (currentIndex > 0) {
+ try {
+ ((AdvancedViatraQueryEngine) engine).delayUpdatePropagation(() -> {
+ editingDomain.getCommandStack().undo();
+ return null;
+ });
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ currentIndex--;
+ result = true;
+ }
+ result = false;
+ listener.backtrackWorked(System.nanoTime() - start);
+ return result;
+ }
+
+ /**
+ * Call this method to undo the transformation.
+ */
+ public void undoTransformation() {
+ while (undoLastTransformation())
+ ;
+ }
+
+ public List getActivationCodes() {
+ return activationCodes;
+ }
+
+ public List> getTransformationRules() {
+ return transformationRules;
+ }
+
+ public IStateCoderFactory getStateCoderFactory() {
+ return stateCoderFactory;
+ }
+
+ public ViatraQueryEngine getEngine() {
+ return engine;
+ }
+
+ public Notifier getModel() {
+ return model;
+ }
+
+ public IStateCoder getStateCoder() {
+ return stateCoder;
+ }
+
+ public int getCurrentIndex() {
+ return currentIndex;
+ }
+
+ public int getTrajectoryLength() {
+ return activationCodes.size();
+ }
+
+ public Fitness getFitness() {
+ return fitness;
+ }
+
+ public void setFitness(Fitness fitness) {
+ this.fitness = fitness;
+ }
+
+ public String toPrettyString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Fitness: ");
+ sb.append(fitness.toString());
+ sb.append(" | Trajectory (");
+ sb.append(activationCodes.size());
+ sb.append("): ");
+ for (Object object : activationCodes) {
+ sb.append(object.toString());
+ sb.append(" | ");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return activationCodes.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof SolutionTrajectory) {
+ SolutionTrajectory that = (SolutionTrajectory) obj;
+ return activationCodes.equals(that.activationCodes);
+ }
+ return false;
+ }
+
+ public Solution getSolution() {
+ return solution;
+ }
+
+ public void setSolution(Solution solution) {
+ this.solution = solution;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java
new file mode 100644
index 00000000..ed7a90da
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/Strategies.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api;
+
+import org.eclipse.viatra.dse.api.strategy.impl.BestFirstStrategy;
+import org.eclipse.viatra.dse.api.strategy.impl.BreadthFirstStrategy;
+import org.eclipse.viatra.dse.api.strategy.impl.DepthFirstStrategy;
+import org.eclipse.viatra.dse.api.strategy.impl.FixedPriorityStrategy;
+import org.eclipse.viatra.dse.api.strategy.impl.HillClimbingStrategy;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+
+/**
+ * Helper class for instantiating strategies. To implement a new strategy use the {@link IStrategy} interface.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public final class Strategies {
+
+ private Strategies() {
+ }
+
+ /**
+ * Creates a depth-first search exploration strategy without a depth limit.
+ *
+ * @return The strategy.
+ * @see DepthFirstStrategy
+ */
+ public static DepthFirstStrategy createDfsStrategy() {
+ return new DepthFirstStrategy();
+ }
+
+ /**
+ * Creates a depth-first search exploration strategy with a depth limit. A negative depth limit means no
+ * depth limit, zero means that it will check the initial state.
+ *
+ * @param depthLimit
+ * @return The strategy.
+ * @see DepthFirstStrategy
+ */
+ public static DepthFirstStrategy createDfsStrategy(int depthLimit) {
+ return new DepthFirstStrategy(depthLimit);
+ }
+
+ /**
+ * Creates a fixed priority exploration strategy without a depth limit. It is a depth-first search exploration
+ * strategy but from a current state it only explores the activations with the highest priority. Priorities can be
+ * defined on the strategy itself.
+ *
+ * @return The strategy.
+ * @see FixedPriorityStrategy
+ */
+ public static FixedPriorityStrategy createFixedPriorityStrategy() {
+ return createFixedPriorityStrategy(-1);
+ }
+
+ /**
+ * Creates a fixed priority exploration strategy with a depth limit, where a zero or negative depth limit means no
+ * depth limit. It is a depth-first search exploration strategy but from a current state it only explores the
+ * activations with the highest priority. Priorities can be defined on the strategy itself.
+ *
+ * @param depthLimit
+ * @return The strategy.
+ * @see FixedPriorityStrategy
+ */
+ public static FixedPriorityStrategy createFixedPriorityStrategy(int depthLimit) {
+ return new FixedPriorityStrategy().withDepthLimit(depthLimit);
+ }
+
+ /**
+ * Creates a breadth-first search exploration strategy without a depth limit.
+ *
+ * @return The strategy.
+ * @see BreadthFirstStrategy
+ */
+ public static BreadthFirstStrategy createBfsStrategy() {
+ return new BreadthFirstStrategy();
+ }
+
+ /**
+ * Creates a breadth-first search exploration strategy with a depth limit. A zero or negative depth limit means no
+ * depth limit.
+ *
+ * @param depthLimit
+ * @return The strategy.
+ * @see BreadthFirstStrategy
+ */
+ public static BreadthFirstStrategy createBfsStrategy(int depthLimit) {
+ return new BreadthFirstStrategy(depthLimit);
+ }
+
+ /**
+ * Creates a hill climbing exploration strategy. By default, it explores all neighborhood states and chooses the
+ * best one to continue with until all neighborhood states are dominated by the current state. Other options are
+ * available on the strategy.
+ *
+ * @return The strategy.
+ * @see HillClimbingStrategy
+ */
+ public static HillClimbingStrategy creatHillClimbingStrategy() {
+ return new HillClimbingStrategy();
+ }
+
+ /**
+ * See {@link BestFirstStrategy}.
+ */
+ public static BestFirstStrategy createBestFirstStrategy() {
+ return new BestFirstStrategy();
+ }
+
+ /**
+ * See {@link BestFirstStrategy}.
+ */
+ public static BestFirstStrategy createBestFirstStrategy(int depthLimit) {
+ return new BestFirstStrategy(depthLimit);
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java
new file mode 100644
index 00000000..fe5604a1
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BestFirstStrategy.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.PriorityQueue;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+
+/**
+ * This exploration strategy eventually explorers the whole design space but goes in the most promising directions
+ * first, based on the {@link Fitness}.
+ *
+ * There are a few parameter to tune such as
+ *
+ * maximum depth
+ * continue the exploration from a state that satisfies the hard objectives (the default that it will
+ * backtrack),
+ * whether to continue the exploration from the newly explored state if it is at least equally good than the
+ * previous one or only if it is better (default is "at least equally good").
+ *
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class BestFirstStrategy implements IStrategy {
+
+ private ThreadContext context;
+ private SolutionStore solutionStore;
+
+ private int maxDepth;
+ private boolean isInterrupted = false;
+ private boolean backTrackIfSolution = true;
+ private boolean onlyBetterFirst = false;
+
+ private PriorityQueue trajectoiresToExplore;
+ private Logger logger = Logger.getLogger(IStrategy.class);
+
+ private static class TrajectoryWithFitness {
+
+ public Object[] trajectory;
+ public Fitness fitness;
+
+ public TrajectoryWithFitness(Object[] trajectory, Fitness fitness) {
+ super();
+ this.trajectory = trajectory;
+ this.fitness = fitness;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(trajectory) + fitness.toString();
+ }
+
+ }
+
+ /**
+ * Creates a new best-first search algorithm without depth limit.
+ */
+ public BestFirstStrategy() {
+ this(-1);
+ }
+
+ /**
+ * Creates a new best-first search algorithm with depth limit.
+ *
+ * @param maxDepth
+ * A negative maxDepth
means no depth limit, zero means the checking of the initial state.
+ */
+ public BestFirstStrategy(int maxDepth) {
+ if (maxDepth < 0) {
+ this.maxDepth = Integer.MAX_VALUE;
+ } else {
+ this.maxDepth = maxDepth;
+ }
+ }
+
+ public BestFirstStrategy continueIfHardObjectivesFulfilled() {
+ backTrackIfSolution = false;
+ return this;
+ }
+
+ public BestFirstStrategy goOnOnlyIfFitnessIsBetter() {
+ onlyBetterFirst = true;
+ return this;
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+ this.solutionStore = context.getGlobalContext().getSolutionStore();
+ final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper();
+
+ trajectoiresToExplore = new PriorityQueue(11,
+ (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness));
+ }
+
+ @Override
+ public void explore() {
+ final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper();
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ logger.info("Global contraint is not satisifed in the first state. Terminate.");
+ return;
+ }
+
+ final Fitness firstFittness = context.calculateFitness();
+ if (firstFittness.isSatisifiesHardObjectives()) {
+ context.newSolution();
+ logger.info("First state is a solution. Terminate.");
+ return;
+ }
+
+ if (maxDepth == 0) {
+ return;
+ }
+
+ final Object[] firstTrajectory = context.getTrajectory().toArray(new Object[0]);
+ TrajectoryWithFitness currentTrajectoryWithFittness = new TrajectoryWithFitness(firstTrajectory, firstFittness);
+ trajectoiresToExplore.add(currentTrajectoryWithFittness);
+
+ mainLoop: while (!isInterrupted) {
+
+ if (currentTrajectoryWithFittness == null) {
+ if (trajectoiresToExplore.isEmpty()) {
+ logger.debug("State space is fully traversed.");
+ return;
+ } else {
+ currentTrajectoryWithFittness = trajectoiresToExplore.element();
+ if (logger.isDebugEnabled()) {
+ logger.debug("New trajectory is chosen: " + currentTrajectoryWithFittness);
+ }
+ context.getDesignSpaceManager().executeTrajectoryWithMinimalBacktrackWithoutStateCoding(currentTrajectoryWithFittness.trajectory);
+ }
+ }
+
+ Collection activationIds = context.getUntraversedActivationIds();
+ Iterator iterator = activationIds.iterator();
+
+ while (!isInterrupted && iterator.hasNext()) {
+ final Object nextActivation = iterator.next();
+ if (!iterator.hasNext()) {
+ logger.debug("Last untraversed activation of the state.");
+ trajectoiresToExplore.remove(currentTrajectoryWithFittness);
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Executing new activation: " + nextActivation);
+ }
+ context.executeAcitvationId(nextActivation);
+ if (context.isCurrentStateAlreadyTraversed()) {
+ logger.info("The new state is already visited.");
+ context.backtrack();
+ } else if (!context.checkGlobalConstraints()) {
+ logger.debug("Global contraint is not satisifed.");
+ context.backtrack();
+ } else {
+ final Fitness nextFitness = context.calculateFitness();
+ if (nextFitness.isSatisifiesHardObjectives()) {
+ solutionStore.newSolution(context);
+ logger.debug("Found a solution.");
+ if (backTrackIfSolution) {
+ context.backtrack();
+ continue;
+ }
+ }
+ if (context.getDepth() >= maxDepth) {
+ logger.debug("Reached max depth.");
+ context.backtrack();
+ continue;
+ }
+
+ TrajectoryWithFitness nextTrajectoryWithFittness = new TrajectoryWithFitness(
+ context.getTrajectory().toArray(), nextFitness);
+ trajectoiresToExplore.add(nextTrajectoryWithFittness);
+
+ int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFittness.fitness,
+ nextTrajectoryWithFittness.fitness);
+ if (compare < 0) {
+ logger.debug("Better fitness, moving on: " + nextFitness);
+ currentTrajectoryWithFittness = nextTrajectoryWithFittness;
+ continue mainLoop;
+ } else if (compare == 0) {
+ if (onlyBetterFirst) {
+ logger.debug("Equally good fitness, backtrack: " + nextFitness);
+ context.backtrack();
+ continue;
+ } else {
+ logger.debug("Equally good fitness, moving on: " + nextFitness);
+ currentTrajectoryWithFittness = nextTrajectoryWithFittness;
+ continue mainLoop;
+ }
+ } else {
+ logger.debug("Worse fitness.");
+ currentTrajectoryWithFittness = null;
+ continue mainLoop;
+ }
+ }
+ }
+
+ logger.debug("State is fully traversed.");
+ trajectoiresToExplore.remove(currentTrajectoryWithFittness);
+ currentTrajectoryWithFittness = null;
+
+ }
+ logger.info("Interrupted.");
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted = true;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java
new file mode 100644
index 00000000..6b7d9817
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/BreadthFirstStrategy.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.GlobalContext;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+
+/**
+ * A breadth-first search algorithm implementation, that
+ *
+ * can work with multiple threads,
+ * indeterministic,
+ * saves all states (trajectories) as solutions that fulfill all the hard objectives,
+ * can have a depth limit,
+ * will backtrack when a model satisfies the hard objectives (after saving it as a solution) and will not explore
+ * beyond that state.
+ *
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class BreadthFirstStrategy implements IStrategy {
+
+ private static final class BfsSharedObject {
+ private final ConcurrentLinkedQueue trajectoryQueue1 = new ConcurrentLinkedQueue<>();
+ private final ConcurrentLinkedQueue trajectoryQueue2 = new ConcurrentLinkedQueue<>();
+
+ private final AtomicBoolean pushToQueue1 = new AtomicBoolean(false);
+ private final AtomicBoolean designSpaceTraversed = new AtomicBoolean(false);
+
+ public final CyclicBarrier barrier;
+
+ public BfsSharedObject(int numberOfThreads) {
+ barrier = new CyclicBarrier(numberOfThreads, () -> {
+ boolean oldValue = pushToQueue1.get();
+ pushToQueue1.set(!oldValue);
+ if (trajectoryQueue1.isEmpty() && trajectoryQueue2.isEmpty()) {
+ designSpaceTraversed.set(true);
+ }
+ });
+ }
+
+ public Object[] poll() {
+ if (pushToQueue1.get()) {
+ return trajectoryQueue2.poll();
+ } else {
+ return trajectoryQueue1.poll();
+ }
+ }
+
+ public void push(Object[] trajectory) {
+ if (pushToQueue1.get()) {
+ trajectoryQueue1.add(trajectory);
+ } else {
+ trajectoryQueue2.add(trajectory);
+ }
+ }
+
+ public boolean isDesignSpaceTraversed() {
+ return designSpaceTraversed.get();
+ }
+ }
+
+ private int maxDepth = 0;
+ private BfsSharedObject shared;
+ private boolean isInterrupted = false;
+ private ThreadContext context;
+ private Logger logger = Logger.getLogger(IStrategy.class);
+ private SolutionStore solutionStore;
+ private boolean isFirstThread = false;
+
+ /**
+ * Creates a new breadth-first search algorithm without depth limit.
+ */
+ public BreadthFirstStrategy() {
+ this.maxDepth = Integer.MAX_VALUE;
+ }
+
+ /**
+ * Creates a new breadth-first search algorithm with depth limit.
+ *
+ * @param maxDepth
+ * A negative maxDepth
means no depth limit, zero means the checking of the initial state.
+ */
+ public BreadthFirstStrategy(int maxDepth) {
+ if (maxDepth < 0) {
+ this.maxDepth = Integer.MAX_VALUE;
+ } else {
+ this.maxDepth = maxDepth;
+ }
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+ this.solutionStore = context.getGlobalContext().getSolutionStore();
+
+ GlobalContext globalContext = context.getGlobalContext();
+ if (globalContext.getSharedObject() == null) {
+ isFirstThread = true;
+ shared = new BfsSharedObject(globalContext.getThreadPool().getMaximumPoolSize());
+ globalContext.setSharedObject(shared);
+ logger.info("Breadth-first exploration strategy is inited.");
+ } else {
+ shared = (BfsSharedObject) globalContext.getSharedObject();
+ }
+ }
+
+ @Override
+ public void explore() {
+
+ if (isFirstThread) {
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ logger.info("Global contraint is not satisifed in the first state. Terminate.");
+ return;
+ }
+
+ Fitness fitness = context.calculateFitness();
+ if (fitness.isSatisifiesHardObjectives()) {
+ context.newSolution();
+ logger.info("First state is a solution. Terminate.");
+ return;
+ }
+
+ Object[] currentTrajectory = context.getTrajectory().toArray(new Object[0]);
+
+ shared.push(currentTrajectory);
+
+ startThreads();
+ } else {
+ try {
+ shared.barrier.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ }
+ }
+
+ mainLoop: while (!isInterrupted && !shared.isDesignSpaceTraversed()) {
+
+ Object[] next = shared.poll();
+ while (next == null) {
+ try {
+ logger.debug("Reached barrier.");
+ shared.barrier.await();
+ } catch (InterruptedException | BrokenBarrierException e1) {
+ }
+ if (isInterrupted || shared.isDesignSpaceTraversed()) {
+ break mainLoop;
+ }
+ next = shared.poll();
+ }
+
+ context.backtrackUntilRoot();
+
+ context.executeTrajectory(next);
+
+ Collection activationIds = context.getCurrentActivationIds();
+ int i = activationIds.size() - 1;
+
+ while (!isInterrupted && i >= 0) {
+
+ Iterator iterator = activationIds.iterator();
+ int index = i--;
+ while (iterator.hasNext() && index > 0) {
+ index--;
+ iterator.next();
+ }
+ Object activationIdToTry = iterator.next();
+
+ context.executeAcitvationId(activationIdToTry);
+
+ if (context.isCurrentStateAlreadyTraversed()) {
+ logger.info("The new state is already visited.");
+ } else if (!context.checkGlobalConstraints()) {
+ logger.debug("Global contraint is not satisifed.");
+ } else if (context.calculateFitness().isSatisifiesHardObjectives()) {
+ solutionStore.newSolution(context);
+ logger.debug("Found a solution.");
+ } else if (context.getDepth() >= maxDepth) {
+ logger.debug("Reached max depth.");
+ } else {
+ Object[] currentTrajectory = context.getTrajectory().toArray(new Object[0]);
+ shared.push(currentTrajectory);
+ }
+
+ context.backtrack();
+ }
+
+ }
+ }
+
+ private void startThreads() {
+ context.startAllThreads(() -> new BreadthFirstStrategy(maxDepth));
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted = true;
+ shared.barrier.reset();
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java
new file mode 100644
index 00000000..22a4a683
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/DepthFirstStrategy.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+
+/**
+ * A depth-first search algorithm implementation, that
+ *
+ * can work with multiple threads,
+ * randomly traverses the search space,
+ * saves all states (trajectories) as solutions that fulfill all the hard objectives,
+ * can have a depth limit,
+ * will backtrack when a model satisfies the hard objectives (after saving it as a solution), which can be modified
+ * by calling {@link #continueIfHardObjectivesFulfilled()}
+ *
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class DepthFirstStrategy implements IStrategy {
+
+ private int maxDepth;
+ private AtomicBoolean isInterrupted = new AtomicBoolean(false);
+ private ThreadContext context;
+
+ private Logger logger = Logger.getLogger(IStrategy.class);
+
+ private Random random = new Random();
+ private boolean backTrackIfSolution = true;
+
+ /**
+ * Creates a new depth-first search algorithm without depth limit.
+ */
+ public DepthFirstStrategy() {
+ this.maxDepth = Integer.MAX_VALUE;
+ }
+
+ /**
+ * Creates a new depth-first search algorithm with depth limit.
+ *
+ * @param maxDepth
+ * A negative maxDepth
means no depth limit, zero means the checking of the initial state.
+ */
+ public DepthFirstStrategy(int maxDepth) {
+ if (maxDepth < 0) {
+ this.maxDepth = Integer.MAX_VALUE;
+ } else {
+ this.maxDepth = maxDepth;
+ }
+ }
+
+ /**
+ * If called, the algorithm will not backtrack after the hard objectives are fulfilled, instead it goes deeper in
+ * the search space.
+ */
+ public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
+ backTrackIfSolution = false;
+ return this;
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+
+ if (context.getSharedObject() == null) {
+ context.setSharedObject(new Object());
+ logger.info("Depth-first exploration strategy is initied.");
+ startThreads();
+ }
+
+ }
+
+ private void startThreads() {
+ context.startAllThreads(() -> new DepthFirstStrategy(maxDepth));
+ }
+
+ @Override
+ public void explore() {
+
+ mainloop: do {
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Global contraint is not satisifed and cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Global contraint is not satisifed, backtrack.");
+ continue;
+ }
+ }
+
+ Fitness fitness = context.calculateFitness();
+ if (fitness.isSatisifiesHardObjectives()) {
+ context.newSolution();
+ if (backTrackIfSolution) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Found a solution but cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Found a solution, backtrack.");
+ continue;
+ }
+ }
+ }
+
+ if (context.getDepth() >= maxDepth) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Reached max depth but cannot bactrack.");
+ break;
+ } else {
+ logger.debug("Reached max depth, bactrack.");
+ continue;
+ }
+ }
+
+ if (isInterrupted.get()) {
+ logger.info("Interrupted, stop exploration.");
+ break;
+ }
+
+ Object activationId = null;
+ Collection activationIds;
+
+ do {
+ activationIds = context.getUntraversedActivationIds();
+ if (activationIds.isEmpty()) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("No more transitions from current state and cannot backtrack.");
+ break mainloop;
+ } else {
+ logger.debug("No more transitions from current state, backtrack.");
+ continue;
+ }
+ }
+ } while (activationIds.isEmpty());
+
+ int index = random.nextInt(activationIds.size());
+
+ Iterator iterator = activationIds.iterator();
+ while (index-- > 0) {
+ iterator.next();
+ }
+ activationId = iterator.next();
+
+ context.executeAcitvationId(activationId);
+
+ boolean loopInTrajectory = context.isCurrentStateInTrajectory();
+ if (loopInTrajectory) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ throw new DSEException("The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
+ } else {
+ logger.info("The new state is already visited in the trajectory, backtrack.");
+ }
+ }
+
+ } while (true);
+
+ logger.info("Terminated.");
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted.set(true);
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java
new file mode 100644
index 00000000..4ccda4ce
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/FixedPriorityStrategy.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Works as {@link DepthFirstStrategy} but:
+ *
+ * works only with single thread,
+ * in a given state, it only traverses the activations with locally the highest priority.
+ *
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class FixedPriorityStrategy implements IStrategy {
+
+ private int maxDepth = Integer.MAX_VALUE;
+ private AtomicBoolean isInterrupted = new AtomicBoolean(false);
+ private ThreadContext context;
+
+ private Logger logger = Logger.getLogger(IStrategy.class);
+ private Map, Integer> priorities = new HashMap, Integer>();
+
+ private Random random = new Random();
+ private Map> bestPriorityInState = new HashMap<>();
+
+ /**
+ * Adds a depth limit to the strategy.
+ *
+ * @param depthLimit
+ * The depth limit.
+ * @return The actual instance to enable a builder pattern like usage.
+ */
+ public FixedPriorityStrategy withDepthLimit(int maxDepth) {
+ if (maxDepth < 0) {
+ this.maxDepth = Integer.MAX_VALUE;
+ } else {
+ this.maxDepth = maxDepth;
+ }
+ return this;
+ }
+
+ /**
+ * Assigns a priority to a rule. Unassigned rule will have a priority of 0.
+ *
+ * @param rule
+ * The transformation rule.
+ * @param priority
+ * The priority of the rule. Higher is better.
+ * @return The actual instance to enable a builder pattern like usage.
+ */
+ public FixedPriorityStrategy withRulePriority(BatchTransformationRule, ?> rule, int priority) {
+ priorities.put(rule, priority);
+ return this;
+ }
+
+ public Map, Integer> getPriorities() {
+ return priorities;
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+
+ logger.info("Fixed priority exploration strategy is initied.");
+ }
+
+ @Override
+ public void explore() {
+
+ mainloop: do {
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Global contraint is not satisifed and cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Global contraint is not satisifed, backtrack.");
+ continue;
+ }
+ }
+
+ Fitness fitness = context.calculateFitness();
+ if (fitness.isSatisifiesHardObjectives()) {
+ context.newSolution();
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Found a solution but cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Found a solution, backtrack.");
+ continue;
+ }
+ }
+
+ if (context.getDepth() >= maxDepth) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Reached max depth but cannot bactrack.");
+ break;
+ } else {
+ logger.debug("Reached max depth, bactrack.");
+ continue;
+ }
+ }
+
+ if (isInterrupted.get()) {
+ logger.info("Interrupted, stop exploration.");
+ break;
+ }
+
+ List transitions;
+
+ do {
+
+ transitions = bestPriorityInState.get(context.getCurrentStateId());
+
+ if (transitions == null) {
+ Integer bestPriority = getBestPriority(context.getCurrentActivationIds());
+ transitions = Lists.newArrayList();
+ for (Object iTransition : context.getCurrentActivationIds()) {
+ Integer integer = priorities.get(context.getRuleByActivationId(iTransition));
+ if (integer == null) {
+ integer = Integer.valueOf(0);
+ }
+ if (integer.equals(bestPriority)) {
+ transitions.add(iTransition);
+ }
+ }
+ bestPriorityInState.put(context.getCurrentStateId(), transitions);
+ }
+
+ if (transitions.isEmpty()) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("No more transitions from current state and cannot backtrack.");
+ break mainloop;
+ } else {
+ logger.debug("No more transitions from current state, backtrack.");
+ continue;
+ }
+ }
+ } while (transitions.isEmpty());
+
+ int index = random.nextInt(transitions.size());
+ Object transition = transitions.remove(index);
+
+ context.executeAcitvationId(transition);
+
+ boolean loopInTrajectory = context.isCurrentStateInTrajectory();
+ if (loopInTrajectory) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ throw new DSEException(
+ "The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
+ } else {
+ logger.info("The new state is already visited in the trajectory, backtrack.");
+ }
+ }
+
+ } while (true);
+
+ logger.info("Terminated.");
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted.set(true);
+ }
+
+ private Integer getBestPriority(Collection extends Object> transitions) {
+ Integer bestPriority = Integer.MIN_VALUE;
+ for (Object iTransition : transitions) {
+ Integer priority = priorities.get(context.getRuleByActivationId(iTransition));
+ if (priority == null) {
+ priority = Integer.valueOf(0);
+ }
+ if (priority > bestPriority) {
+ bestPriority = priority;
+ }
+ }
+ return bestPriority;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java
new file mode 100644
index 00000000..0ccb0668
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/HillClimbingStrategy.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
+import org.eclipse.viatra.dse.objectives.TrajectoryFitness;
+
+public class HillClimbingStrategy implements IStrategy {
+
+ private AtomicBoolean isInterrupted = new AtomicBoolean(false);
+ private ThreadContext context;
+
+ private Logger logger = Logger.getLogger(IStrategy.class);
+
+ private Random random = new Random();
+ private double percentOfOpenedStates;
+ private ObjectiveComparatorHelper objectiveComparatorHelper;
+
+ public HillClimbingStrategy() {
+ this(2);
+ }
+
+ public HillClimbingStrategy(double percentOfOpenedStates) {
+ this.percentOfOpenedStates = percentOfOpenedStates;
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+ objectiveComparatorHelper = context.getObjectiveComparatorHelper();
+ logger.info("Hill climbing exploration strategy is initied.");
+ }
+
+ @Override
+ public void explore() {
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Global contraint is not satisifed and cannot backtrack.");
+ return;
+ }
+ }
+
+ mainloop: do {
+
+ Fitness previousFitness = context.calculateFitness();
+
+ logger.debug("Current depth: " + context.getDepth() + " Fitness: " + previousFitness);
+
+ Collection transitionsFromCurrentState = context.getCurrentActivationIds();
+
+ while (transitionsFromCurrentState.isEmpty()) {
+ logger.debug("No transitions from current state: considered as a solution.");
+ saveSolutionAndBacktrack();
+ continue mainloop;
+ }
+
+ ArrayList transitionsToTry = new ArrayList<>(transitionsFromCurrentState.size());
+ for (Object transition : transitionsFromCurrentState) {
+ transitionsToTry.add(transition);
+ }
+ double numberOfTransitionsToTry = transitionsToTry.size() * percentOfOpenedStates;
+
+ for (; numberOfTransitionsToTry > 0 && !transitionsToTry.isEmpty(); numberOfTransitionsToTry--) {
+ int index = random.nextInt(transitionsToTry.size());
+ Object transition = transitionsToTry.remove(index);
+
+ context.executeAcitvationId(transition);
+
+ if (!context.checkGlobalConstraints()) {
+ logger.debug("Global contraint is not satisifed, backtrack.");
+ context.backtrack();
+ continue;
+ }
+ if (context.isCurrentStateInTrajectory()) {
+ logger.debug("Current state is in trajectory, backtrack.");
+ context.backtrack();
+ continue;
+ }
+
+ Fitness fitness = context.calculateFitness();
+ objectiveComparatorHelper.addTrajectoryFitness(
+ new TrajectoryFitness(context.getTrajectoryInfo().getLastActivationId(), fitness));
+ context.backtrack();
+ }
+
+ if (objectiveComparatorHelper.getTrajectoryFitnesses().isEmpty()) {
+ logger.debug("No viable transitions from current state: considered as a solution.");
+ saveSolutionAndBacktrack();
+ continue;
+ }
+
+ TrajectoryFitness randomBestFitness = objectiveComparatorHelper.getRandomBest();
+ objectiveComparatorHelper.clearTrajectoryFitnesses();
+
+ int compare = objectiveComparatorHelper.compare(previousFitness, randomBestFitness.fitness);
+
+ if (compare > 0) {
+ saveSolutionAndBacktrack();
+ continue;
+ } else {
+ previousFitness = randomBestFitness.fitness;
+ Object transition = randomBestFitness.trajectory[randomBestFitness.trajectory.length - 1];
+ context.executeAcitvationId(transition);
+ }
+
+ } while (!isInterrupted.get());
+
+ logger.info("Terminated.");
+ }
+
+ private void saveSolutionAndBacktrack() {
+ context.calculateFitness();
+ context.newSolution();
+ logger.debug("Found solution: " + context.getTrajectoryInfo().toString());
+ logger.debug("Backtrack for more solutions, if needed.");
+ context.backtrackUntilRoot();
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted.set(true);
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java
new file mode 100644
index 00000000..af8fb8cc
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/impl/RandomSearchStrategy.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.impl;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.GlobalContext;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+import org.eclipse.viatra.dse.objectives.Fitness;
+
+public class RandomSearchStrategy implements IStrategy {
+
+ private static class SharedData {
+ public final AtomicInteger triesLeft;
+ public final int minDepth;
+ public final int maxDepth;
+
+ public SharedData(int minDepth, int maxDepth, int numberOfTries) {
+ this.minDepth = minDepth;
+ this.maxDepth = maxDepth;
+ this.triesLeft = new AtomicInteger(numberOfTries);
+ }
+ }
+
+ private int maxDepth = -1;
+ private Random rnd = new Random();
+ private SharedData shared;
+ private TrajectoryInfo trajectoryInfo;
+ int nth;
+ private ThreadContext context;
+ private AtomicBoolean isInterrupted = new AtomicBoolean(false);
+ private Logger logger = Logger.getLogger(IStrategy.class);
+
+ public RandomSearchStrategy(int minDepth, int maxDepth, int numberOfTries) {
+ shared = new SharedData(minDepth, maxDepth, numberOfTries);
+ }
+
+ private RandomSearchStrategy() {
+ }
+
+ @Override
+ public void initStrategy(ThreadContext context) {
+ this.context = context;
+ trajectoryInfo = context.getTrajectoryInfo();
+ GlobalContext gc = context.getGlobalContext();
+
+ Object sharedObject = gc.getSharedObject();
+ if (sharedObject == null) {
+ gc.setSharedObject(shared);
+ logger.info("Random exploration strategy is initied.");
+ startThreads();
+ } else {
+ shared = (SharedData) sharedObject;
+ }
+
+ maxDepth = rnd.nextInt(shared.maxDepth - shared.minDepth) + shared.minDepth;
+
+ }
+
+ @Override
+ public void explore() {
+
+ do {
+
+ boolean globalConstraintsAreSatisfied = context.checkGlobalConstraints();
+ if (!globalConstraintsAreSatisfied) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Global contraint is not satisifed and cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Global contraint is not satisifed, backtrack.");
+ continue;
+ }
+ }
+
+ Fitness fitness = context.calculateFitness();
+ if (fitness.isSatisifiesHardObjectives()) {
+ context.newSolution();
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ logger.info("Found a solution but cannot backtrack.");
+ break;
+ } else {
+ logger.debug("Found a solution, backtrack.");
+ continue;
+ }
+ }
+
+ if (trajectoryInfo.getDepth() < maxDepth) {
+
+ Collection transitions = context.getCurrentActivationIds();
+ int index = rnd.nextInt(transitions.size());
+ Object transition = getByIndex(transitions, index);
+ context.executeAcitvationId(transition);
+
+ } else {
+
+ nth = shared.triesLeft.getAndDecrement();
+ logger.debug(nth + " tries left");
+ if (nth > 0) {
+
+ context.backtrackUntilRoot();
+ maxDepth = rnd.nextInt(shared.maxDepth - shared.minDepth) + shared.minDepth;
+
+ } else {
+ break;
+ }
+ }
+
+ boolean loopInTrajectory = context.isCurrentStateInTrajectory();
+ if (loopInTrajectory) {
+ boolean isSuccessfulUndo = context.backtrack();
+ if (!isSuccessfulUndo) {
+ throw new DSEException(
+ "The new state is present in the trajectoy but cannot bactkrack. Should never happen!");
+ } else {
+ logger.info("The new state is already visited in the trajectory, backtrack.");
+ }
+ }
+
+ } while (isInterrupted.get());
+
+ logger.info("Terminated.");
+ }
+
+ @Override
+ public void interruptStrategy() {
+ isInterrupted.set(true);
+ }
+
+ private void startThreads() {
+ context.startAllThreads(RandomSearchStrategy::new);
+ }
+
+ private static Object getByIndex(Collection availableTransitions, int index) {
+ int i = 0;
+ Iterator iterator = availableTransitions.iterator();
+ while (iterator.hasNext()) {
+ Object transition = iterator.next();
+ if (i == index) {
+ return transition;
+ } else {
+ ++i;
+ }
+ }
+ throw new IndexOutOfBoundsException("size: " + availableTransitions.size() + ", index: " + index);
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java
new file mode 100644
index 00000000..8c164396
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategy.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.interfaces;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+
+/**
+ * This high level interface is responsible for defining basic operations of an exploration strategy.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface IStrategy {
+
+ /**
+ * Initializes the strategy with a specific {@link ThreadContext}.
+ *
+ * @param context
+ * The context.
+ */
+ void initStrategy(ThreadContext context);
+
+ /**
+ * This method explores the design space as the implementation specifies. It will be called only once, hence the
+ * exploration loop is run by the implementation. The termination condition is also specified by the implementation
+ * and when it returns the exploration thread will be disposed.
+ */
+ void explore();
+
+ /**
+ * The implementation of this interface should be ready to be interrupted. If this method is called, the
+ * {@link IStrategy#explore()} method should return ASAP.
+ *
+ * This method is also called by the {@link SolutionStore} class if enough solutions are found.
+ */
+ void interruptStrategy();
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java
new file mode 100644
index 00000000..b3352d13
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/api/strategy/interfaces/IStrategyFactory.java
@@ -0,0 +1,13 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.api.strategy.interfaces;
+
+public interface IStrategyFactory {
+ IStrategy createStrategy();
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java
new file mode 100644
index 00000000..d3990c23
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ActivationCodesConflictSet.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.transformation.evm.api.Activation;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictSet;
+
+public class ActivationCodesConflictSet implements ChangeableConflictSet {
+
+ private static class ActivationCodesMultiBiMap {
+ public Map, Object> activationsToCodes = new HashMap<>();
+ public Map>> codesToActivations = new HashMap<>();
+
+ public void addActivation(Activation> activation, Object activationCode) {
+ activationsToCodes.put(activation, activationCode);
+ codesToActivations.computeIfAbsent(activationCode, k -> new HashSet<>()).add(activation);
+ }
+
+ public void removeActivaion(Activation> activation) {
+ Object activationCode = activationsToCodes.remove(activation);
+ Set> activations = codesToActivations.get(activationCode);
+ if (activations != null) {
+ activations.remove(activation);
+ }
+ }
+
+ public void clear() {
+ activationsToCodes.clear();
+ codesToActivations.clear();
+ }
+ }
+
+ protected ActivationCodesMultiBiMap activationCodes;
+ protected IStateCoder stateCoder;
+
+ protected Set> newActivations = new HashSet<>();
+ protected Set> removedActivations = new HashSet<>();
+// private Logger logger = Logger.getLogger(getClass());
+
+ private boolean isIncremental = false;
+ private ConflictSet nextActivationsConflictSet;
+
+ public void setIncremental(boolean isIncremental) {
+ this.isIncremental = isIncremental;
+ }
+
+ public ActivationCodesConflictSet(ConflictSet nextActivationsConflictSet, IStateCoder stateCoder) {
+ Objects.requireNonNull(nextActivationsConflictSet);
+ this.nextActivationsConflictSet = nextActivationsConflictSet;
+ this.stateCoder = stateCoder;
+ activationCodes = new ActivationCodesMultiBiMap();
+ }
+
+ private Object createActivationCode(Activation> activation) {
+ return stateCoder.createActivationCode((IPatternMatch) activation.getAtom());
+ }
+
+ @Override
+ public boolean removeActivation(Activation> activation) {
+ if (isIncremental) {
+//*
+ removedActivations.add(activation);
+ newActivations.remove(activation);
+/*/
+ if(!removedActivations.add(activation)) {
+ logger.debug("Abnormal: already marked to remove: " + activation);
+ } else {
+ logger.debug("marked to remove: " + activation);
+ }
+ if(newActivations.remove(activation)) {
+ logger.debug("Abnormal: removed from new activations: " + activation);
+ }
+//*/
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addActivation(Activation> activation) {
+ if (isIncremental) {
+//*
+ newActivations.add(activation);
+ removedActivations.remove(activation);
+ /*/
+ if (activation.isEnabled()) {
+ if (!newActivations.add(activation)) {
+ logger.debug("Abnormal: already added as new: " + activation);
+ } else {
+ logger.debug("activation added: " + activation);
+ }
+ }
+ if(removedActivations.remove(activation)) {
+ logger.debug("Abnormal: was already marked to remove: " + activation);
+ }
+//*/
+ }
+ return false;
+ }
+
+ public Object getActivationId(Activation> activation) {
+ return activationCodes.activationsToCodes.get(activation);
+ }
+
+ public Activation> getActivation(Object activationId) {
+ Set> activationsSet = activationCodes.codesToActivations.get(activationId);
+ if (activationsSet == null || activationsSet.isEmpty()) {
+ return null;
+ } else {
+ return activationsSet.iterator().next();
+ }
+ }
+
+ public void updateActivationCodes() {
+// logger.debug("Updating activation codes.");
+
+ if (isIncremental) {
+ for (Activation> activation : removedActivations) {
+ activationCodes.removeActivaion(activation);
+// logger.debug("removed activation: " + activationId);
+ }
+
+ for (Activation> activation : newActivations) {
+ if (activation.getState().isInactive()) {
+ continue;
+ }
+ Object activationCode = createActivationCode(activation);
+ activationCodes.addActivation(activation, activationCode);
+// logger.debug("new activation: " + activationId);
+// Activation> similarActivation = activationIds.inverse().get(activationId);
+// if (similarActivation != null) {
+// logger.debug("Activation " + toStringAct(activation) + " is already present with id: " + activationId);
+// if (similarActivation.isEnabled()) {
+// logger.warn("Duplicate activation code: " + activationId);
+// } else {
+// logger.debug("Force put: " + activationId);
+// }
+// continue;
+// }
+// activationIds.put(activation, activationId);
+ }
+ removedActivations.clear();
+ newActivations.clear();
+ } else {
+ activationCodes.clear();
+ for (Activation> activation : nextActivationsConflictSet.getNextActivations()) {
+ Object activationCode = createActivationCode(activation);
+ activationCodes.addActivation(activation, activationCode);
+ }
+ }
+
+
+ }
+
+ protected void reinitWithActivations(ConflictSet nextActivationsConflictSet) {
+ this.nextActivationsConflictSet = nextActivationsConflictSet;
+ activationCodes.clear();
+ for (Activation> activation : nextActivationsConflictSet.getNextActivations()) {
+ Object activationCode = createActivationCode(activation);
+ activationCodes.addActivation(activation, activationCode);
+ }
+ }
+
+ @Override
+ public Activation> getNextActivation() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set> getNextActivations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set> getConflictingActivations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ConflictResolver getConflictResolver() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Object activationCode : activationCodes.activationsToCodes.values()) {
+ sb.append(activationCode);
+ sb.append(" | ");
+ }
+ return sb.toString();
+ }
+
+ public Collection getCurrentActivationCodes() {
+ return activationCodes.activationsToCodes.values();
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java
new file mode 100644
index 00000000..4c6b4097
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DesignSpaceManager.java
@@ -0,0 +1,563 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.designspace.api.IBacktrackListener;
+import org.eclipse.viatra.dse.designspace.api.IDesignSpace;
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+import org.eclipse.viatra.dse.objectives.ActivationFitnessProcessor;
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.dse.visualizer.IExploreEventHandler;
+import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.transformation.evm.api.Activation;
+import org.eclipse.viatra.transformation.evm.api.Context;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+public class DesignSpaceManager implements IBacktrackListener {
+
+ private final IStateCoder stateCoder;
+ private final EditingDomain domain;
+ private Notifier model;
+
+ private IDesignSpace designSpace;
+
+ private final TrajectoryInfo trajectory;
+
+ // the occurence vector callback
+ private List handlers;
+
+ // Dummy context for evm
+ private final Context evmContext = Context.create();
+
+ private Logger logger = Logger.getLogger(this.getClass());
+
+ private boolean isNewState = false;
+ private Map, ActivationFitnessProcessor> activationFitnessProcessors;
+ private Map, String> activationFitnessProcessorNames;
+ private ThreadContext context;
+
+ private ActivationCodesConflictSet activationCodes;
+ private ChangeableConflictSet conflictSet;
+
+ private AdvancedViatraQueryEngine engine;
+
+ private Random random = new Random();
+
+ private long forwardTime = 0;
+ private long backtrackingTime = 0;
+
+ public DesignSpaceManager(ThreadContext context) {
+
+ this.context = context;
+ model = context.getModel();
+ designSpace = context.getGlobalContext().getDesignSpace();
+ domain = context.getEditingDomain();
+
+ conflictSet = context.getConflictResolver().getLastCreatedConflictSet();
+
+ stateCoder = context.getStateCoder();
+ Object initialStateId = stateCoder.createStateCode();
+ designSpace.addState(null, null, initialStateId);
+
+ activationCodes = context.getActivationCodesConflictSet();
+
+ engine = (AdvancedViatraQueryEngine) context.getQueryEngine();
+
+ this.trajectory = new TrajectoryInfo(initialStateId);
+
+ logger.debug("DesignSpaceManager initialized with initial model: " + initialStateId);
+ }
+
+ public void fireActivation(final Object transition) {
+ if (fireActivationSilent(transition)) {
+ return;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(
+ "A retrieved Transition SHOULD have a matching Activation. Possible causes: the state serializer is faulty; the algorithm choosed a wrong Transition.");
+ sb.append("\nSought transition: ");
+ sb.append(transition);
+ Object currentStateId = getCurrentState();
+ sb.append("\nCurrent known state: ");
+ sb.append(currentStateId);
+ Object actualStateId = stateCoder.createStateCode();
+ sb.append("\nActual state: ");
+ sb.append((actualStateId.equals(currentStateId) ? "same as current" : actualStateId));
+ sb.append("\n");
+ sb.append(trajectory);
+ sb.append("\nAvailable transitions:");
+ for (Activation> act : conflictSet.getNextActivations()) {
+ IPatternMatch match = (IPatternMatch) act.getAtom();
+ Object code = generateMatchCode(match);
+ sb.append("\n\t");
+ sb.append(code);
+ }
+
+ throw new DSEException(sb.toString());
+ }
+
+ public boolean tryFireActivation(final Object transition) {
+ return fireActivationSilent(transition);
+ }
+
+ private boolean fireActivationSilent(final Object transition) {
+ final Activation> activation = getActivationById(transition);
+
+ if (activation == null) {
+ return false;
+ }
+
+ BatchTransformationRule, ?> rule = getRuleByActivation(activation);
+
+ Map measureCosts = new HashMap();
+ if (activationFitnessProcessors != null && activationFitnessProcessors.containsKey(rule)) {
+ IPatternMatch match = (IPatternMatch) activation.getAtom();
+ ActivationFitnessProcessor processor = activationFitnessProcessors.get(rule);
+ double fitness = processor.process(match);
+ measureCosts.put(activationFitnessProcessorNames.get(rule), fitness);
+ }
+
+ ChangeCommand rc = new ChangeCommand(model) {
+ @Override
+ protected void doExecute() {
+ activation.fire(evmContext);
+ }
+ };
+
+ Object previousState = trajectory.getCurrentStateId();
+
+ long start = System.nanoTime();
+ domain.getCommandStack().execute(rc);
+ forwardTime += System.nanoTime() - start;
+
+ Object newStateId = stateCoder.createStateCode();
+ updateActivationCodes();
+
+ if (designSpace != null) {
+ isNewState = !designSpace.isTraversed(newStateId);
+ designSpace.addState(previousState, transition, newStateId);
+ }
+
+ trajectory.addStep(transition, rule, newStateId, measureCosts);
+
+ if (handlers != null) {
+ for (IExploreEventHandler iExploreEventHandler : handlers) {
+ iExploreEventHandler.transitionFired(transition);
+ }
+ }
+
+ logger.debug("Executed activation: " + transition);/*
+ * + " from state: " + previousState + " to " + newStateId);
+ */
+
+ return true;
+ }
+
+ public boolean executeRandomActivationId() {
+ Collection transitions = getTransitionsFromCurrentState();
+ int size = transitions.size();
+ if (size == 0) {
+ return false;
+ }
+
+ int index = random.nextInt(size);
+ Iterator iterator = transitions.iterator();
+ for (int i = 0; i < index; ++i) {
+ iterator.next();
+ }
+ Object transition = iterator.next();
+
+ fireActivation(transition);
+ return true;
+ }
+
+ public int executeTrajectory(Object[] trajectoryToExecute) {
+ return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, false, true);
+ }
+
+ public int executeTrajectory(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex) {
+ return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, false, true);
+ }
+
+ public int executeTrajectoryByTrying(Object[] trajectoryToExecute) {
+ return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, true, true);
+ }
+
+ public int executeTrajectoryByTrying(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex) {
+ return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, true, true);
+ }
+
+ public int executeTrajectoryWithoutStateCoding(Object[] trajectoryToExecute) {
+ return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, false, false);
+ }
+
+ public int executeTrajectoryWithoutStateCoding(Object[] trajectoryToExecute, int fromIncludedIndex,
+ int toExcludedIndex) {
+ return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, false, false);
+ }
+
+ public int executeTrajectoryByTryingWithoutStateCoding(Object[] trajectoryToExecute) {
+ return executeTrajectory(trajectoryToExecute, 0, trajectoryToExecute.length, true, false);
+ }
+
+ public int executeTrajectoryByTryingWithoutStateCoding(Object[] trajectoryToExecute, int fromIncludedIndex,
+ int toExcludedIndex) {
+ return executeTrajectory(trajectoryToExecute, fromIncludedIndex, toExcludedIndex, true, false);
+ }
+
+ private int executeTrajectory(Object[] trajectoryToExecute, int fromIncludedIndex, int toExcludedIndex,
+ boolean tryAllActivations, boolean createStateCode) {
+ logger.debug("Executing trajectory.");
+ int unsuccesfulIndex = -1;
+ if (tryAllActivations) {
+ unsuccesfulIndex = 0;
+ }
+ for (int i = fromIncludedIndex; i < toExcludedIndex; i++) {
+ Object activationId = trajectoryToExecute[i];
+ final Activation> activation = getActivationById(activationId);
+
+ if (activation == null) {
+ logger.debug("Couldn't execute activation: " + activationId);
+ if (tryAllActivations) {
+ unsuccesfulIndex++;
+ continue;
+ } else {
+ unsuccesfulIndex = i;
+ logger.debug("Trajectory execution stopped at index " + i + "/" + trajectoryToExecute.length);
+ break;
+ }
+ }
+
+ BatchTransformationRule, ?> rule = getRuleByActivation(activation);
+
+ Map measureCosts = new HashMap();
+ if (activationFitnessProcessors != null && activationFitnessProcessors.containsKey(rule)) {
+ IPatternMatch match = (IPatternMatch) activation.getAtom();
+ ActivationFitnessProcessor processor = activationFitnessProcessors.get(rule);
+ double fitness = processor.process(match);
+ measureCosts.put(activationFitnessProcessorNames.get(rule), fitness);
+ }
+
+ ChangeCommand rc = new ChangeCommand(model) {
+ @Override
+ protected void doExecute() {
+ activation.fire(evmContext);
+ }
+ };
+
+ long start = System.nanoTime();
+ domain.getCommandStack().execute(rc);
+ forwardTime += System.nanoTime() - start;
+
+ Object newStateId = null;
+ if (createStateCode) {
+ newStateId = stateCoder.createStateCode();
+ }
+ updateActivationCodes();
+
+ trajectory.addStep(activationId, rule, newStateId, measureCosts);
+
+ logger.debug("Activation executed: " + activationId);
+ }
+ if (!createStateCode) {
+ trajectory.modifyLastStateCode(stateCoder.createStateCode());
+ }
+ logger.debug("Trajectory execution finished.");
+ return unsuccesfulIndex;
+
+ }
+
+ public Object getTransitionByActivation(Activation> activation) {
+ return activationCodes.getActivationId(activation);
+ }
+
+ public Activation> getActivationById(Object activationId) {
+ return activationCodes.getActivation(activationId);
+ }
+
+ public BatchTransformationRule, ?> getRuleByActivation(Activation> activation) {
+ return context.getGlobalContext().getSpecificationRuleMap().get(activation.getInstance().getSpecification());
+ }
+
+ public BatchTransformationRule, ?> getRuleByActivationId(Object activationId) {
+ return getRuleByActivation(getActivationById(activationId));
+ }
+
+ /**
+ * Returns true if the given state is not owned by this crawler.
+ *
+ **/
+ public boolean isNewModelStateAlreadyTraversed() {
+ return !isNewState;
+ }
+
+ public List getTrajectoryFromRoot() {
+ return trajectory.getTrajectory();
+ }
+
+ public Collection getTransitionsFromCurrentState() {
+ return activationCodes.getCurrentActivationCodes();
+ }
+
+ public Collection getUntraversedTransitionsFromCurrentState() {
+ if (designSpace == null) {
+ throw new DSEException("Unsupported without a design space");
+ }
+ Object currentState = trajectory.getCurrentStateId();
+ Collection traversedIds = designSpace.getActivationIds(currentState);
+
+ List untraversedTransitions = new ArrayList<>();
+ for (Object activationId : activationCodes.getCurrentActivationCodes()) {
+ if (!traversedIds.contains(activationId)) {
+ untraversedTransitions.add(activationId);
+ }
+ }
+
+ return untraversedTransitions;
+ }
+
+ public boolean undoLastTransformation() {
+
+ if (!trajectory.canStepBack()) {
+ return false;
+ }
+
+ long start = System.nanoTime();
+ try {
+ engine.delayUpdatePropagation(() -> {
+ domain.getCommandStack().undo();
+ return null;
+ });
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ updateActivationCodes();
+
+ Object lastActivationId = trajectory.getLastActivationId();
+
+ trajectory.backtrack();
+
+ if (handlers != null) {
+ for (IExploreEventHandler iExploreEventHandler : handlers) {
+ iExploreEventHandler.undo(lastActivationId);
+ }
+ }
+
+ logger.debug("Backtrack.");
+ backtrackingTime += System.nanoTime() - start;
+
+ return true;
+ }
+
+ public void backtrackXTimes(int steps) {
+ long start = System.nanoTime();
+ try {
+ engine.delayUpdatePropagation(() -> {
+ for (int i = steps; i > 0; i--) {
+ domain.getCommandStack().undo();
+ trajectory.backtrack();
+ }
+ return null;
+ });
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ backtrackingTime += System.nanoTime() - start;
+ updateActivationCodes();
+ logger.debug("Backtracked " + steps + " times.");
+ }
+
+ public int backtrackUntilLastCommonActivation(Object[] newTrajectory) {
+ long start = System.nanoTime();
+ Iterator currentTrajectoryIterator = trajectory.getTrajectory().iterator();
+ if (!currentTrajectoryIterator.hasNext()) {
+ return 0;
+ }
+ int indexOfLastCommonActivation = 0;
+ for (Object activationCode : newTrajectory) {
+ if (currentTrajectoryIterator.hasNext()) {
+ Object activationCodeFromCurrent = currentTrajectoryIterator.next();
+ if (activationCodeFromCurrent.equals(activationCode)) {
+ indexOfLastCommonActivation++;
+ } else {
+ break;
+ }
+ } else {
+ // current trajectory is smaller
+ break;
+ }
+ }
+ int numberOfBacktracks = trajectory.getDepth() - indexOfLastCommonActivation;
+ if (numberOfBacktracks > 0) {
+ try {
+ engine.delayUpdatePropagation(() -> {
+ for (int i = numberOfBacktracks; i > 0; i--) {
+ domain.getCommandStack().undo();
+ trajectory.backtrack();
+ }
+ return null;
+ });
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ backtrackingTime += System.nanoTime() - start;
+ updateActivationCodes();
+ logger.debug("Backtracked " + numberOfBacktracks + " times.");
+ return indexOfLastCommonActivation;
+ }
+
+ public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory) {
+ executeTrajectoryWithMinimalBacktrack(trajectory, trajectory.length);
+ }
+
+ public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex) {
+ int fromIndex = backtrackUntilLastCommonActivation(trajectory);
+ executeTrajectory(trajectory, fromIndex, toExcludedIndex, false, true);
+ }
+
+ public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory) {
+ executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory, trajectory.length);
+ }
+
+ public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex) {
+ int fromIndex = backtrackUntilLastCommonActivation(trajectory);
+ executeTrajectory(trajectory, fromIndex, toExcludedIndex, false, false);
+ Object stateCode = stateCoder.createStateCode();
+ this.trajectory.modifyLastStateCode(stateCode);
+ }
+
+ public void undoUntilRoot() {
+ long start = System.nanoTime();
+ try {
+ engine.delayUpdatePropagation(() -> {
+ while (trajectory.canStepBack()) {
+ domain.getCommandStack().undo();
+ trajectory.backtrack();
+ }
+ return null;
+ });
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ backtrackingTime += System.nanoTime() - start;
+ updateActivationCodes();
+ logger.debug("Backtracked to root.");
+ }
+
+ private Object generateMatchCode(IPatternMatch match) {
+ return stateCoder.createActivationCode(match);
+ }
+
+ public Object getCurrentState() {
+ return trajectory.getCurrentStateId();
+ }
+
+ public SolutionTrajectory createSolutionTrajectroy() {
+ return trajectory.createSolutionTrajectory(context.getGlobalContext().getStateCoderFactory(), this);
+ }
+
+ public TrajectoryInfo getTrajectoryInfo() {
+ return trajectory;
+ }
+
+ public void setDesignSpace(IDesignSpace designSpace) {
+ this.designSpace = designSpace;
+ }
+
+ public IDesignSpace getDesignSpace() {
+ return designSpace;
+ }
+
+ public void registerExploreEventHandler(IExploreEventHandler handler) {
+ if (handler == null) {
+ return;
+ }
+ if (handlers == null) {
+ handlers = new ArrayList();
+ }
+ handlers.add(handler);
+ }
+
+ public void deregisterExploreEventHandler(IExploreEventHandler handler) {
+ if (handler == null) {
+ return;
+ }
+ if (handlers != null) {
+ handlers.remove(handler);
+ }
+ }
+
+ public void registerActivationCostProcessor(String name, BatchTransformationRule, ?> rule,
+ ActivationFitnessProcessor activationFitnessProcessor) {
+ if (activationFitnessProcessors == null || activationFitnessProcessorNames == null) {
+ activationFitnessProcessors = new HashMap, ActivationFitnessProcessor>();
+ activationFitnessProcessorNames = new HashMap, String>();
+ }
+ activationFitnessProcessors.put(rule, activationFitnessProcessor);
+ activationFitnessProcessorNames.put(rule, name);
+ }
+
+ public boolean isCurentStateInTrajectory() {
+ Object currentStateId = trajectory.getCurrentStateId();
+ List stateTrajectory = trajectory.getStateTrajectory();
+ int size = stateTrajectory.size();
+ for (int i = 0; i < size - 1; i++) {
+ Object stateId = stateTrajectory.get(i);
+ if (currentStateId.equals(stateId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public IStateCoder getStateCoder() {
+ return stateCoder;
+ }
+
+ private void updateActivationCodes() {
+ activationCodes.updateActivationCodes();
+ }
+
+ public long getForwardTime() {
+ return forwardTime;
+ }
+
+ public long getBacktrackingTime() {
+ return backtrackingTime;
+ }
+
+ @Override
+ public void forwardWorked(long nanos) {
+ forwardTime += nanos;
+ }
+
+ @Override
+ public void backtrackWorked(long nanos) {
+ backtrackingTime += nanos;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java
new file mode 100644
index 00000000..35504b56
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictResolver.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+
+public class DseConflictResolver implements ConflictResolver {
+
+ private ConflictResolver activationOrderingconflictResolver;
+ private IStateCoder stateCoder;
+ private DseConflictSet lastCreatedConflictSet;
+
+ public DseConflictResolver(ConflictResolver activationOrderingConflictResolver, IStateCoder stateCoder) {
+ this.activationOrderingconflictResolver = activationOrderingConflictResolver;
+ this.stateCoder = stateCoder;
+ }
+
+ @Override
+ public ChangeableConflictSet createConflictSet() {
+ lastCreatedConflictSet = new DseConflictSet(this, activationOrderingconflictResolver, stateCoder);
+ return lastCreatedConflictSet;
+ }
+
+ public DseConflictSet getLastCreatedConflictSet() {
+ return lastCreatedConflictSet;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java
new file mode 100644
index 00000000..cba595f4
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseConflictSet.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.Set;
+
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.transformation.evm.api.Activation;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+
+public class DseConflictSet implements ChangeableConflictSet {
+
+ private ActivationCodesConflictSet activationCodesConflictSet;
+ private ChangeableConflictSet activationOrderingConflictSet;
+ private ChangeableConflictSet prevActivationOrderingConflictSet;
+ private ConflictResolver resolver;
+
+ public DseConflictSet(ConflictResolver resolver, ConflictResolver activationOrderingConflictResolver,
+ IStateCoder stateCoder) {
+ this.resolver = resolver;
+ activationOrderingConflictSet = activationOrderingConflictResolver.createConflictSet();
+ activationCodesConflictSet = new ActivationCodesConflictSet(activationOrderingConflictSet, stateCoder);
+ }
+
+ @Override
+ public Activation> getNextActivation() {
+ return activationOrderingConflictSet.getNextActivation();
+ }
+
+ @Override
+ public Set> getNextActivations() {
+ return activationOrderingConflictSet.getNextActivations();
+ }
+
+ @Override
+ public Set> getConflictingActivations() {
+ return activationOrderingConflictSet.getConflictingActivations();
+ }
+
+ @Override
+ public ConflictResolver getConflictResolver() {
+ return resolver;
+ }
+
+ @Override
+ public boolean addActivation(Activation> activation) {
+ activationCodesConflictSet.addActivation(activation);
+ return activationOrderingConflictSet.addActivation(activation);
+ }
+
+ @Override
+ public boolean removeActivation(Activation> activation) {
+ activationCodesConflictSet.removeActivation(activation);
+ return activationOrderingConflictSet.removeActivation(activation);
+ }
+
+ public ActivationCodesConflictSet getActivationCodesConflictSet() {
+ return activationCodesConflictSet;
+ }
+
+ public void changeActivationOrderingConflictSet(ChangeableConflictSet newActivationOrderingConflictSet) {
+ for (Activation> activation : activationOrderingConflictSet.getConflictingActivations()) {
+ newActivationOrderingConflictSet.addActivation(activation);
+ }
+ activationCodesConflictSet.reinitWithActivations(newActivationOrderingConflictSet);
+ ChangeableConflictSet tmp = activationOrderingConflictSet;
+ activationOrderingConflictSet = newActivationOrderingConflictSet;
+ prevActivationOrderingConflictSet = tmp;
+ }
+
+ public void changeActivationOrderingConflictSetBack() {
+ ChangeableConflictSet newActivationOrderingConflictSet =
+ prevActivationOrderingConflictSet.getConflictResolver().createConflictSet();
+ changeActivationOrderingConflictSet(newActivationOrderingConflictSet);
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java
new file mode 100644
index 00000000..838c1d1b
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseEvmRuleBase.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import org.eclipse.viatra.transformation.evm.api.Agenda;
+import org.eclipse.viatra.transformation.evm.api.RuleBase;
+import org.eclipse.viatra.transformation.evm.api.event.EventRealm;
+
+public class DseEvmRuleBase extends RuleBase {
+
+ public DseEvmRuleBase(EventRealm eventRealm, Agenda agenda) {
+ super(eventRealm, agenda);
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java
new file mode 100644
index 00000000..f6fee7be
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/DseIdPoolHelper.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+public enum DseIdPoolHelper {
+
+ INSTANCE;
+
+ public static interface IGetRuleExecutions {
+ int getRuleExecutions(BatchTransformationRule, ?> rule);
+ }
+
+ public static class IdProvider {
+
+ private final BatchTransformationRule, ?> rule;
+ private IGetRuleExecutions getRuleExecutions;
+
+ public IdProvider(IGetRuleExecutions getRuleExecutions, BatchTransformationRule, ?> rule) {
+ this.getRuleExecutions = getRuleExecutions;
+ this.rule = rule;
+ }
+
+ public int getId() {
+ return getRuleExecutions.getRuleExecutions(rule);
+ }
+
+ }
+
+ private ConcurrentHashMap, IdProvider>> idProviders = new ConcurrentHashMap<>();
+
+ public int getId(BatchTransformationRule, ?> rule) {
+ Thread currentThread = Thread.currentThread();
+ HashMap, IdProvider> ruleMap = idProviders.get(currentThread);
+ if (ruleMap == null) {
+ throw new DSEException("There is no registered id provider");
+ }
+ IdProvider idProvider = ruleMap.get(rule);
+ return idProvider.getId();
+ }
+
+ public void registerRules(IGetRuleExecutions getRuleExecutions, Collection> rules) {
+ Thread currentThread = Thread.currentThread();
+ HashMap, IdProvider> ruleMap = new HashMap<>();
+ for (BatchTransformationRule, ?> rule : rules) {
+ IdProvider idProvider = new IdProvider(getRuleExecutions, rule);
+ ruleMap.put(rule, idProvider);
+ }
+ idProviders.put(currentThread, ruleMap);
+ }
+
+ public void disposeByThread() {
+ Thread currentThread = Thread.currentThread();
+ idProviders.remove(currentThread);
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java
new file mode 100644
index 00000000..f2231e5c
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ExplorerThread.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.transformation.evm.api.RuleEngine;
+
+/**
+ * This class implements the {@link Runnable} interface, to able to run an exploration strategy in a separate thread. It
+ * is also responsible to initialize the exploration, start the exploration (call the {@link IStrategy#explore()}
+ * method), catch any exception during exploration and to shutdown the thread correctly.
+ *
+ * @author Földenyi Miklos & Nagy Andras Szabolcs
+ *
+ */
+public class ExplorerThread implements Runnable {
+
+ private final ThreadContext threadContext;
+
+ private IStrategy strategy;
+
+ public ExplorerThread(final ThreadContext context) {
+ this.threadContext = context;
+ strategy = threadContext.getStrategy();
+ }
+
+ /**
+ * Signals the {@link IStrategy} instance that execution should be stopped. By contract, the strategy is to
+ * stop execution at the next stage of execution where stopping and exiting is appropriate.
+ */
+ public void stopRunning() {
+ strategy.interruptStrategy();
+ }
+
+ /**
+ * Starts the design space exploration. Returns only when the {@link IStrategy#explore()} method returns.
+ */
+ public void run() {
+ GlobalContext globalContext = threadContext.getGlobalContext();
+ try {
+
+ threadContext.init();
+
+ strategy.initStrategy(threadContext);
+
+ strategy.explore();
+
+ threadContext.backtrackUntilRoot();
+
+ } catch (Throwable e) {
+ Logger.getLogger(IStrategy.class).error("Thread stopped unexpectedly!", e);
+ globalContext.registerException(e);
+ } finally {
+ globalContext.strategyFinished(this);
+ dispose();
+ }
+ }
+
+ /**
+ * Disposes of this strategy. Recursively calls dispose on the underlying {@link RuleEngine} and
+ * {@link ViatraQueryEngine}. Calling this is only required if the design space exploration was launched in thread, as
+ * the underlying engines get collected on the stop of the running {@link Thread}.
+ */
+ public void dispose() {
+ threadContext.getRuleEngine().dispose();
+ DseIdPoolHelper.INSTANCE.disposeByThread();
+ }
+
+ /**
+ * Returns the associated {@link ThreadContext} that houses all the thread specific data about the exploration
+ * process, and is also the gateway to the {@link GlobalContext} which stores data relevant to the design space
+ * exploration process as a whole.
+ *
+ * @return the relevant {@link ThreadContext}.
+ */
+ public ThreadContext getThreadContext() {
+ return threadContext;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java
new file mode 100644
index 00000000..7325ead3
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/GlobalContext.java
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory;
+import org.eclipse.viatra.dse.designspace.api.IDesignSpace;
+import org.eclipse.viatra.dse.multithreading.DSEThreadPool;
+import org.eclipse.viatra.dse.objectives.IGlobalConstraint;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.dse.objectives.LeveledObjectivesHelper;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
+import org.eclipse.viatra.dse.util.EMFHelper;
+import org.eclipse.viatra.dse.visualizer.IDesignSpaceVisualizer;
+import org.eclipse.viatra.transformation.evm.api.RuleSpecification;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+import org.eclipse.viatra.transformation.evm.specific.ConflictResolvers;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Creates new contexts for strategies. It is needed because of the multithreading.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class GlobalContext {
+
+ // **** fields and methods for multi threading *****//
+ // *************************************************//
+
+ public enum ExplorationProcessState {
+ NOT_STARTED,
+ RUNNING,
+ STOPPING,
+ COMPLETED
+ }
+
+ private ConcurrentLinkedQueue exceptions = new ConcurrentLinkedQueue();
+
+ private volatile ExplorationProcessState state = ExplorationProcessState.NOT_STARTED;
+ private final Set runningThreads = new HashSet();
+ private DSEThreadPool threadPool = new DSEThreadPool();
+ private int numberOfStartedThreads = 0;
+ private IDesignSpace designSpace;
+
+ private AtomicBoolean firstThreadContextInited = new AtomicBoolean(false);
+ private AtomicBoolean firstThreadContextIniting = new AtomicBoolean(false);
+
+ private Map, BatchTransformationRule,?>> specificationRuleMap;
+
+ private Object terminationSnycObject = new Object();
+
+ private Logger logger = Logger.getLogger(IStrategy.class);
+
+ private boolean isAlreadyInited;
+
+ public void waitForTermination() {
+ synchronized (terminationSnycObject) {
+ while (!isDone()) {
+ try {
+ terminationSnycObject.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Starts a new thread to explore the design space.
+ *
+ * @param originalThreadContext The context of the thread which starts the new thread.
+ * @param model The model to start from.
+ * @param cloneModel It should be true in most cases.
+ * @param strategy The strategy, the thread will use.
+ * @return The {@link ExplorerThread}
+ */
+ private synchronized ExplorerThread tryStartNewThread(ThreadContext originalThreadContext, Notifier model,
+ IStrategy strategy) {
+
+ if(!isAlreadyInited) {
+ isAlreadyInited = true;
+ init();
+ }
+
+ if (state != ExplorationProcessState.COMPLETED && state != ExplorationProcessState.STOPPING
+ && threadPool.canStartNewThread()) {
+
+ ThreadContext newThreadContext = new ThreadContext(this, strategy, model);
+
+ // TODO : clone undo list? slave strategy can't go further back...
+ ExplorerThread explorerThread = new ExplorerThread(newThreadContext);
+ newThreadContext.setExplorerThread(explorerThread);
+
+ boolean isSuccessful = threadPool.tryStartNewStrategy(explorerThread);
+
+ if (isSuccessful) {
+ runningThreads.add(explorerThread);
+
+ state = ExplorationProcessState.RUNNING;
+ ++numberOfStartedThreads;
+
+ logger.info("New thread started, active threads: " + runningThreads.size());
+
+ return explorerThread;
+ }
+ }
+ return null;
+ }
+
+ public synchronized ExplorerThread tryStartNewThread(ThreadContext originalThreadContext, IStrategy strategy) {
+ return tryStartNewThread(originalThreadContext, EMFHelper.clone(originalThreadContext.getModel()), strategy);
+ }
+
+ public synchronized ExplorerThread tryStartNewThreadWithoutModelClone(ThreadContext originalThreadContext,
+ IStrategy strategy) {
+ return tryStartNewThread(originalThreadContext, originalThreadContext.getModel(), strategy);
+ }
+
+ public synchronized ExplorerThread startFirstThread(IStrategy strategy, Notifier model) {
+ Preconditions.checkState(!isAlreadyInited, "First thread is already started.");
+ return tryStartNewThread(null, EMFHelper.clone(model), strategy);
+ }
+
+ public synchronized ExplorerThread startFirstThreadWithoutModelClone(IStrategy strategy, Notifier model) {
+ Preconditions.checkState(!isAlreadyInited, "First thread is already started.");
+ return tryStartNewThread(null, model, strategy);
+ }
+
+ public synchronized void startAllThreads(ThreadContext originalThreadContext, IStrategyFactory strategyFactory) {
+ while (canStartNewThread()) {
+ tryStartNewThread(originalThreadContext, strategyFactory.createStrategy());
+ }
+ }
+
+ /**
+ * Starts a new thread to explore the design space.
+ *
+ * @param strategyBase
+ * The {@link Strategy}.
+ * @param tedToClone
+ * The model to clone. Hint: context.getTed()
+ */
+
+ public synchronized void strategyFinished(ExplorerThread strategy) {
+ runningThreads.remove(strategy);
+
+ logger.info("Thread finished, active threads: " + runningThreads.size());
+
+ // is the first part necessary?
+ if (runningThreads.isEmpty()) {
+ state = ExplorationProcessState.COMPLETED;
+ threadPool.shutdown();
+
+ // if the main thread (which started the exploration)
+ // is waiting for the solution, than wake it up
+ synchronized (terminationSnycObject) {
+ terminationSnycObject.notify();
+ logger.info("Exploration terminated.");
+ }
+
+ }
+ }
+
+ public synchronized boolean isDone() {
+ return state == ExplorationProcessState.COMPLETED && runningThreads.isEmpty();
+ }
+
+ public synchronized boolean isNotStarted() {
+ return state == ExplorationProcessState.NOT_STARTED;
+ }
+
+ public boolean canStartNewThread() {
+ return (state == ExplorationProcessState.NOT_STARTED || state == ExplorationProcessState.RUNNING)
+ && threadPool.canStartNewThread();
+ }
+
+ public synchronized void stopAllThreads() {
+ if (state == ExplorationProcessState.RUNNING) {
+ state = ExplorationProcessState.STOPPING;
+ logger.info("Stopping all threads.");
+ for (ExplorerThread strategy : runningThreads) {
+ strategy.stopRunning();
+ }
+ }
+ }
+
+ public void registerException(Throwable e) {
+ exceptions.add(e);
+ }
+
+ // ******* fields and methods for exploration *******//
+ // **************************************************//
+
+ private List objectives = new ArrayList();
+ private IObjective[][] leveledObjectives;
+ private List globalConstraints = new ArrayList();
+ private Set> transformations = new HashSet>();
+ private IStateCoderFactory stateCoderFactory;
+ private SolutionStore solutionStore = new SolutionStore(1);
+ private Object sharedObject;
+ private List visualizers;
+
+ private ConflictResolver conflictResolver = ConflictResolvers.createArbitraryResolver();
+
+ private void init() {
+ leveledObjectives = new LeveledObjectivesHelper(objectives).initLeveledObjectives();
+
+ specificationRuleMap = new HashMap<>();
+ for (BatchTransformationRule,?> rule : transformations) {
+ specificationRuleMap.put(rule.getRuleSpecification(), rule);
+ }
+ }
+
+ public List getVisualizers() {
+ return ImmutableList.copyOf(visualizers);
+ }
+
+ public void registerDesignSpaceVisualizer(IDesignSpaceVisualizer visualizer) {
+ if (visualizer == null) {
+ return;
+ }
+ if (visualizers == null) {
+ visualizers = new ArrayList();
+ }
+ visualizers.add(visualizer);
+ }
+
+ public void deregisterDesignSpaceVisualizer(IDesignSpaceVisualizer visualizer) {
+ if (visualizer == null) {
+ return;
+ }
+ if (visualizers != null) {
+ visualizers.remove(visualizer);
+ }
+ }
+
+ public boolean isDesignSpaceVisualizerRegistered(IDesignSpaceVisualizer visualizer) {
+ if (visualizers != null) {
+ return visualizers.contains(visualizer);
+ }
+ return false;
+ }
+
+ public void initVisualizersForThread(ThreadContext threadContext) {
+ if (visualizers != null && !visualizers.isEmpty()) {
+ for (IDesignSpaceVisualizer visualizer : visualizers) {
+ visualizer.init(threadContext);
+ threadContext.getDesignSpaceManager().registerExploreEventHandler(visualizer);
+ }
+ }
+ }
+
+ public boolean isExceptionHappendInOtherThread() {
+ return !exceptions.isEmpty();
+ }
+
+ public Collection getExceptions() {
+ return exceptions;
+ }
+
+ public IStateCoderFactory getStateCoderFactory() {
+ return stateCoderFactory;
+ }
+
+ public void setStateCoderFactory(IStateCoderFactory stateCoderFactory) {
+ this.stateCoderFactory = stateCoderFactory;
+ }
+
+ public Set> getTransformations() {
+ return transformations;
+ }
+
+ public void setTransformations(Set> transformations) {
+ this.transformations = transformations;
+ }
+
+ public DSEThreadPool getThreadPool() {
+ return threadPool;
+ }
+
+ public IDesignSpace getDesignSpace() {
+ return designSpace;
+ }
+
+ public void setDesignSpace(IDesignSpace designSpace) {
+ this.designSpace = designSpace;
+ }
+
+ public int getNumberOfStartedThreads() {
+ return numberOfStartedThreads;
+ }
+
+ public Object getSharedObject() {
+ return sharedObject;
+ }
+
+ public void setSharedObject(Object sharedObject) {
+ this.sharedObject = sharedObject;
+ }
+
+ public ExplorationProcessState getState() {
+ return state;
+ }
+
+ public List getObjectives() {
+ return objectives;
+ }
+
+ public void setObjectives(List objectives) {
+ this.objectives = objectives;
+ }
+
+ public List getGlobalConstraints() {
+ return globalConstraints;
+ }
+
+ public void setGlobalConstraints(List globalConstraints) {
+ this.globalConstraints = globalConstraints;
+ }
+
+ AtomicBoolean getFirstThreadContextInited() {
+ return firstThreadContextInited;
+ }
+
+ AtomicBoolean getFirstThreadContextIniting() {
+ return firstThreadContextIniting;
+ }
+
+ public IObjective[][] getLeveledObjectives() {
+ return leveledObjectives;
+ }
+
+ public void setSolutionStore(SolutionStore solutionStore) {
+ this.solutionStore = solutionStore;
+ }
+
+ public SolutionStore getSolutionStore() {
+ return solutionStore;
+ }
+
+ public Map, BatchTransformationRule, ?>> getSpecificationRuleMap() {
+ return specificationRuleMap;
+ }
+
+ public void setConflictResolver(ConflictResolver conflictResolver) {
+ this.conflictResolver = conflictResolver;
+ }
+
+ public ConflictResolver getConflictResolver() {
+ return conflictResolver;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java
new file mode 100644
index 00000000..d630964f
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/IDseStrategyContext.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory;
+import org.eclipse.viatra.dse.designspace.api.IDesignSpace;
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.objectives.IGlobalConstraint;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.transformation.evm.api.Activation;
+import org.eclipse.viatra.transformation.evm.api.RuleEngine;
+import org.eclipse.viatra.transformation.evm.api.RuleSpecification;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+/**
+ * This interface is only to overview the required methods for exploration strategies. It is not used explicitly.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface IDseStrategyContext {
+
+ void init();
+
+ Notifier getModel();
+ EditingDomain getEditingDomain();
+ ViatraQueryEngine getQueryEngine();
+ RuleEngine getRuleEngine();
+ IStrategy getStrategy();
+ ExplorerThread getExplorerThread();
+ List getObjectives();
+ IObjective[][] getLeveledObjectives();
+ List getGlobalConstraints();
+
+ SolutionStore getSolutionStore();
+ void newSolution();
+// TODO void newSolution(TrajectoryFitness trajectoryFitness);
+
+
+ ObjectiveComparatorHelper getObjectiveComparatorHelper();
+
+ GlobalContext getGlobalContext();
+ Set> getRules();
+ BatchTransformationRule, ?> getRuleByRuleSpecification(RuleSpecification> ruleSpecification);
+ ExplorerThread tryStartNewThread(IStrategy strategy); /*IDseStrategyContext originalContext*/
+ ExplorerThread tryStartNewThreadWithoutModelClone(IStrategy strategy);
+ void startAllThreads(IStrategyFactory strategyFactory);
+ Object getSharedObject();
+ void setSharedObject(Object sharedObject);
+
+
+ DesignSpaceManager getDesignSpaceManager();
+ IStateCoder getStateCoder();
+ IDesignSpace getDesignSpace();
+ TrajectoryInfo getTrajectoryInfo();
+ List getTrajectory();
+ List getTrajectoryCopied();
+ int getDepth();
+ Object getCurrentStateId();
+
+ Object getTransitionByActivation(Activation> activation);
+ Activation> getActivationById(Object activationId);
+ BatchTransformationRule, ?> getRuleByActivation(Activation> activation);
+ BatchTransformationRule, ?> getRuleByActivationId(Object activationId);
+
+ Collection getCurrentActivationIds();
+ Collection getUntraversedActivationIds();
+// TODO Object getArbitraryActivationId();
+// TODO Object getArbitraryUntraversedActivationId();
+
+ void executeAcitvationId(Object activationId);
+ boolean tryExecuteAcitvationId(Object activationId);
+ boolean executeRandomActivationId();
+ void executeTrajectory(Object[] activationIds);
+ void executeTrajectory(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex);
+ int executeTrajectoryByTrying(Object[] activationIds);
+ int executeTrajectoryByTrying(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex);
+ int executeTrajectoryWithoutStateCoding(Object[] activationIds);
+ int executeTrajectoryWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex);
+ int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds);
+ int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex);
+ void executeTrajectoryWithMinimalBacktrack(Object[] trajectory);
+ void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex);
+ void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory);
+ void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex);
+
+ boolean backtrack();
+ // TODO int backtrack(int times);
+ void backtrackUntilLastCommonActivation(Object[] trajectory);
+ void backtrackUntilRoot();
+
+ Fitness calculateFitness();
+ Fitness getLastFitness();
+ boolean checkGlobalConstraints();
+ boolean isCurrentStateAlreadyTraversed();
+ // this needs states stored:
+ boolean isCurrentStateInTrajectory();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java
new file mode 100644
index 00000000..8c0a715a
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/SingletonSetConflictResolver.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import org.eclipse.viatra.transformation.evm.api.RuleEngine;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+
+/**
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class SingletonSetConflictResolver implements ConflictResolver {
+
+ protected ChangeableConflictSet conflictSet;
+ protected ConflictResolver conflictResolver;
+ protected ConflictResolver prevConflictResolver;
+ protected RuleEngine ruleEngine;
+
+ public SingletonSetConflictResolver(ConflictResolver conflictResolver) {
+ this.conflictResolver = conflictResolver;
+ conflictSet = conflictResolver.createConflictSet();
+ }
+
+ @Override
+ public ChangeableConflictSet createConflictSet() {
+ return conflictSet;
+ }
+
+ public void changeConflictResolver(ConflictResolver conflictResolver) {
+ ConflictResolver tmp = this.conflictResolver;
+ this.conflictResolver = conflictResolver;
+ prevConflictResolver = tmp;
+ conflictSet = conflictResolver.createConflictSet();
+ ruleEngine.setConflictResolver(this);
+ }
+
+ public void changeConflictResolverBack() {
+ changeConflictResolver(prevConflictResolver);
+ }
+
+ public void setRuleEngine(RuleEngine ruleEngine) {
+ this.ruleEngine = ruleEngine;
+ ruleEngine.setConflictResolver(this);
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java
new file mode 100644
index 00000000..b62442ce
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/base/ThreadContext.java
@@ -0,0 +1,542 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.base;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategyFactory;
+import org.eclipse.viatra.dse.designspace.api.IDesignSpace;
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.objectives.IGlobalConstraint;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore;
+import org.eclipse.viatra.dse.statecode.IStateCoder;
+import org.eclipse.viatra.dse.util.EMFHelper;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.emf.EMFScope;
+import org.eclipse.viatra.query.runtime.exception.ViatraQueryException;
+import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
+import org.eclipse.viatra.transformation.evm.api.Activation;
+import org.eclipse.viatra.transformation.evm.api.RuleEngine;
+import org.eclipse.viatra.transformation.evm.api.RuleSpecification;
+import org.eclipse.viatra.transformation.evm.api.event.EventFilter;
+import org.eclipse.viatra.transformation.evm.api.resolver.ChangeableConflictSet;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictResolver;
+import org.eclipse.viatra.transformation.evm.api.resolver.ConflictSet;
+import org.eclipse.viatra.transformation.evm.specific.RuleEngines;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+/**
+ * This class holds all the information that is related to a single processing thread of the DesignSpaceExploration
+ * process. For any attributes related to the Design Space Exploration process as a whole, see {@link GlobalContext}.
+ *
+ * @author Miklos Foldenyi
+ *
+ */
+public class ThreadContext implements IDseStrategyContext{
+
+ private final GlobalContext globalContext;
+ private final IStrategy strategy;
+ private ExplorerThread explorerThread;
+ private RuleEngine ruleEngine;
+ private ViatraQueryEngine queryEngine;
+ private EditingDomain domain;
+ private Notifier model;
+ private DesignSpaceManager designSpaceManager;
+ private List objectives;
+ private List globalConstraints;
+ private Fitness lastFitness;
+ private ObjectiveComparatorHelper objectiveComparatorHelper;
+ private IStateCoder stateCoder;
+ private DseConflictResolver dseConflictResolver;
+ private DseConflictSet dseConflictSet;
+ private ActivationCodesConflictSet activationCodesConflictSet;
+
+ /**
+ * This value is true after the {@link ThreadContext} has been initialized in it's own thread.
+ */
+ private AtomicBoolean inited = new AtomicBoolean(false);
+
+ private boolean isFirstThread = false;
+ private IObjective[][] leveledObjectives;
+
+ private static class GetRuleExecutionsImpl implements DseIdPoolHelper.IGetRuleExecutions {
+
+ private List> executedRules;
+
+ public GetRuleExecutionsImpl(List> executedRulesView) {
+ this.executedRules = executedRulesView;
+ }
+
+ @Override
+ public int getRuleExecutions(BatchTransformationRule, ?> rule) {
+ int nextId = 0;
+ for (BatchTransformationRule, ?> r : executedRules) {
+ if (r.equals(rule)) {
+ nextId ++;
+ }
+ }
+ return nextId;
+ }
+
+ }
+
+ public DseConflictResolver getConflictResolver() {
+ return dseConflictResolver;
+ }
+
+ public ConflictSet getConflictSet() {
+ return dseConflictSet;
+ }
+
+ /**
+ * Creates a {@link ThreadContext} and sets it up to be initialized on the given {@link TransactionalEditingDomain}
+ *
+ * @param globalContext
+ * @param strategyBase
+ * @param domain
+ * @param trajectoryInfoToClone
+ * @param parentGuidance
+ */
+ public ThreadContext(final GlobalContext globalContext, IStrategy strategy, Notifier model) {
+ Preconditions.checkArgument(model != null, "Cannot initialize ThreadContext on a null model.");
+ this.globalContext = globalContext;
+ this.strategy = strategy;
+ this.model = model;
+ }
+
+ /**
+ * Initializes the {@link ThreadContext} by initializing the underlying {@link ViatraQueryEngine} and
+ * {@link RuleEngine}. {@link Guidance} initialization is also happening within this method.
+ *
+ * @throws DSEException
+ */
+ public void init() {
+
+ AtomicBoolean isFirst = globalContext.getFirstThreadContextIniting();
+ AtomicBoolean isFirstReady = globalContext.getFirstThreadContextInited();
+ if (!isFirstReady.get()) {
+ if (!isFirst.compareAndSet(false, true)) {
+ try {
+ do {
+ Thread.sleep(5);
+ } while (!isFirstReady.get());
+ } catch (InterruptedException e) {
+ }
+ } else {
+ isFirstThread = true;
+ }
+ }
+ // prohibit re-initialization
+ Preconditions.checkArgument(!inited.getAndSet(true), "This Thread context has been initialized already!");
+
+ try {
+ // initialize query engine
+ final EMFScope scope = new EMFScope(model);
+ queryEngine = ViatraQueryEngine.on(scope);
+
+
+ stateCoder = getGlobalContext().getStateCoderFactory().createStateCoder();
+ stateCoder.init(model);
+ stateCoder.createStateCode();
+
+ ConflictResolver activationOrderingCconflictResolver = globalContext.getConflictResolver();
+ dseConflictResolver = new DseConflictResolver(activationOrderingCconflictResolver, stateCoder);
+
+ ruleEngine = RuleEngines.createViatraQueryRuleEngine(queryEngine);
+ ruleEngine.setConflictResolver(dseConflictResolver);
+ for (BatchTransformationRule, ?> tr : globalContext.getTransformations()) {
+ ruleEngine.addRule(tr.getRuleSpecification(), (EventFilter) tr.getFilter());
+ }
+ dseConflictSet = dseConflictResolver.getLastCreatedConflictSet();
+ activationCodesConflictSet = dseConflictSet.getActivationCodesConflictSet();
+ activationCodesConflictSet.updateActivationCodes();
+
+
+ } catch (ViatraQueryException e) {
+ throw new DSEException("Failed to create unmanaged ViatraQueryEngine on the model.", e);
+ }
+
+ if (isFirstThread) {
+
+ objectives = globalContext.getObjectives();
+ leveledObjectives = globalContext.getLeveledObjectives();
+ globalConstraints = globalContext.getGlobalConstraints();
+
+ } else {
+ objectives = new ArrayList();
+
+ IObjective[][] leveledObjectivesToCopy = globalContext.getLeveledObjectives();
+ leveledObjectives = new IObjective[leveledObjectivesToCopy.length][];
+ for (int i = 0; i < leveledObjectivesToCopy.length; i++) {
+ leveledObjectives[i] = new IObjective[leveledObjectivesToCopy[i].length];
+ for (int j = 0; j < leveledObjectivesToCopy[i].length; j++) {
+ leveledObjectives[i][j] = leveledObjectivesToCopy[i][j].createNew();
+ objectives.add(leveledObjectives[i][j]);
+ }
+ }
+
+ globalConstraints = new ArrayList();
+ for (IGlobalConstraint globalConstraint : globalContext.getGlobalConstraints()) {
+ globalConstraints.add(globalConstraint.createNew());
+ }
+
+ }
+ // create the thread specific DesignSpaceManager
+ this.domain = EMFHelper.createEditingDomain(model);
+ designSpaceManager = new DesignSpaceManager(this);
+
+ boolean isThereHardObjective = false;
+ for (IObjective objective : objectives) {
+ objective.init(this);
+ if (objective.isHardObjective()) {
+ isThereHardObjective = true;
+ }
+ }
+ if (!isThereHardObjective) {
+ Logger.getLogger(IStrategy.class).warn(
+ "No hard objective is specified: all reachable state is a solution. Use a dummy hard objective to be explicit.");
+ }
+
+ for (IGlobalConstraint globalConstraint : globalConstraints) {
+ globalConstraint.init(this);
+ }
+
+ DseIdPoolHelper.INSTANCE.registerRules(new GetRuleExecutionsImpl(getDesignSpaceManager().getTrajectoryInfo().getRules()), getRules());
+
+ globalContext.initVisualizersForThread(this);
+
+ if (isFirstThread) {
+ isFirstReady.set(true);
+ }
+
+ }
+
+ public Fitness calculateFitness() {
+ Fitness result = new Fitness();
+
+ boolean satisifiesHardObjectives = true;
+
+ for (IObjective objective : objectives) {
+ Double fitness = objective.getFitness(this);
+ result.put(objective.getName(), fitness);
+ if (objective.isHardObjective() && !objective.satisifiesHardObjective(fitness)) {
+ satisifiesHardObjectives = false;
+ }
+ }
+
+ result.setSatisifiesHardObjectives(satisifiesHardObjectives);
+
+ lastFitness = result;
+
+ return result;
+ }
+
+ public boolean checkGlobalConstraints() {
+ for (IGlobalConstraint globalConstraint : globalContext.getGlobalConstraints()) {
+ if (!globalConstraint.checkGlobalConstraint(this)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public RuleEngine getRuleEngine() {
+ return ruleEngine;
+ }
+
+ public GlobalContext getGlobalContext() {
+ return globalContext;
+ }
+
+ public DesignSpaceManager getDesignSpaceManager() {
+ return designSpaceManager;
+ }
+
+ public EditingDomain getEditingDomain() {
+ return domain;
+ }
+
+ public Notifier getModel() {
+ return model;
+ }
+
+ public ViatraQueryEngine getQueryEngine() {
+ return queryEngine;
+ }
+
+ public IStrategy getStrategy() {
+ return strategy;
+ }
+
+ public ExplorerThread getExplorerThread() {
+ return explorerThread;
+ }
+
+ public void setExplorerThread(ExplorerThread explorerThread) {
+ this.explorerThread = explorerThread;
+ }
+
+ public Fitness getLastFitness() {
+ return lastFitness;
+ }
+
+ public ObjectiveComparatorHelper getObjectiveComparatorHelper() {
+ if (objectiveComparatorHelper == null) {
+ objectiveComparatorHelper = new ObjectiveComparatorHelper(leveledObjectives);
+ }
+ return objectiveComparatorHelper;
+ }
+
+ public IObjective[][] getLeveledObjectives() {
+ return leveledObjectives;
+ }
+
+ public List getObjectives() {
+ return objectives;
+ }
+
+ public List getGlobalConstraints() {
+ return globalConstraints;
+ }
+
+ @Override
+ public SolutionStore getSolutionStore() {
+ return globalContext.getSolutionStore();
+ }
+
+ @Override
+ public void newSolution() {
+ globalContext.getSolutionStore().newSolution(this);
+ }
+
+ @Override
+ public Object getSharedObject() {
+ return globalContext.getSharedObject();
+ }
+
+ @Override
+ public void setSharedObject(Object sharedObject) {
+ globalContext.setSharedObject(sharedObject);
+ }
+
+ @Override
+ public Set> getRules() {
+ return globalContext.getTransformations();
+ }
+
+ @Override
+ public BatchTransformationRule, ?> getRuleByRuleSpecification(RuleSpecification> ruleSpecification) {
+ return globalContext.getSpecificationRuleMap().get(ruleSpecification);
+ }
+
+ @Override
+ public ExplorerThread tryStartNewThread(IStrategy strategy) {
+ return globalContext.tryStartNewThread(this, strategy);
+ }
+
+ @Override
+ public ExplorerThread tryStartNewThreadWithoutModelClone(IStrategy strategy) {
+ return globalContext.tryStartNewThreadWithoutModelClone(this, strategy);
+ }
+
+ @Override
+ public void startAllThreads(IStrategyFactory strategyFactory) {
+ globalContext.startAllThreads(this, strategyFactory);
+ }
+
+ @Override
+ public IStateCoder getStateCoder() {
+ return stateCoder;
+ }
+
+ @Override
+ public IDesignSpace getDesignSpace() {
+ return globalContext.getDesignSpace();
+ }
+
+ @Override
+ public TrajectoryInfo getTrajectoryInfo() {
+ return designSpaceManager.getTrajectoryInfo();
+ }
+
+ @Override
+ public List getTrajectory() {
+ return designSpaceManager.getTrajectoryInfo().getTrajectory();
+ }
+
+ @Override
+ public List getTrajectoryCopied() {
+ return new ArrayList(getTrajectory());
+ }
+
+ @Override
+ public int getDepth() {
+ return designSpaceManager.getTrajectoryInfo().getDepth();
+ }
+
+ @Override
+ public Object getCurrentStateId() {
+ return designSpaceManager.getTrajectoryInfo().getCurrentStateId();
+ }
+
+ @Override
+ public Object getTransitionByActivation(Activation> activation) {
+ return designSpaceManager.getTransitionByActivation(activation);
+ }
+
+ @Override
+ public Activation> getActivationById(Object activationId) {
+ return designSpaceManager.getActivationById(activationId);
+ }
+
+ @Override
+ public BatchTransformationRule, ?> getRuleByActivation(Activation> activation) {
+ return designSpaceManager.getRuleByActivation(activation);
+ }
+
+ @Override
+ public BatchTransformationRule, ?> getRuleByActivationId(Object activationId) {
+ return designSpaceManager.getRuleByActivationId(activationId);
+ }
+
+ @Override
+ public Collection getCurrentActivationIds() {
+ return designSpaceManager.getTransitionsFromCurrentState();
+ }
+
+ @Override
+ public Collection getUntraversedActivationIds() {
+ return designSpaceManager.getUntraversedTransitionsFromCurrentState();
+ }
+
+ @Override
+ public void executeAcitvationId(Object activationId) {
+ designSpaceManager.fireActivation(activationId);
+ }
+
+ @Override
+ public boolean tryExecuteAcitvationId(Object activationId) {
+ return designSpaceManager.tryFireActivation(activationId);
+ }
+
+ @Override
+ public boolean executeRandomActivationId() {
+ return designSpaceManager.executeRandomActivationId();
+ }
+
+ @Override
+ public void executeTrajectory(Object[] activationIds) {
+ designSpaceManager.executeTrajectory(activationIds);
+ }
+
+ @Override
+ public void executeTrajectory(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) {
+ designSpaceManager.executeTrajectory(activationIds, fromIncludedIndex, toExcludedIndex);
+ }
+
+ @Override
+ public int executeTrajectoryByTrying(Object[] activationIds) {
+ return designSpaceManager.executeTrajectoryByTrying(activationIds);
+ }
+
+ @Override
+ public int executeTrajectoryByTrying(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) {
+ return designSpaceManager.executeTrajectoryByTrying(activationIds, fromIncludedIndex, toExcludedIndex);
+ }
+
+ @Override
+ public int executeTrajectoryWithoutStateCoding(Object[] activationIds) {
+ return designSpaceManager.executeTrajectoryWithoutStateCoding(activationIds);
+ }
+
+ @Override
+ public int executeTrajectoryWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) {
+ return designSpaceManager.executeTrajectoryWithoutStateCoding(activationIds, fromIncludedIndex, toExcludedIndex);
+ }
+
+ @Override
+ public int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds) {
+ return designSpaceManager.executeTrajectoryByTryingWithoutStateCoding(activationIds);
+ }
+
+ @Override
+ public int executeTrajectoryByTryingWithoutStateCoding(Object[] activationIds, int fromIncludedIndex, int toExcludedIndex) {
+ return designSpaceManager.executeTrajectoryByTryingWithoutStateCoding(activationIds, fromIncludedIndex, toExcludedIndex);
+ }
+
+ @Override
+ public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory) {
+ designSpaceManager.executeTrajectoryWithMinimalBacktrack(trajectory);
+ }
+
+ @Override
+ public void executeTrajectoryWithMinimalBacktrack(Object[] trajectory, int toExcludedIndex) {
+ designSpaceManager.executeTrajectoryWithMinimalBacktrack(trajectory, toExcludedIndex);
+ }
+
+ @Override
+ public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory) {
+ designSpaceManager.executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory);
+ }
+
+ @Override
+ public void executeTrajectoryWithMinimalBacktrackWithoutStateCoding(Object[] trajectory, int toExcludedIndex) {
+ designSpaceManager.executeTrajectoryWithMinimalBacktrackWithoutStateCoding(trajectory, toExcludedIndex);
+ }
+
+ @Override
+ public boolean backtrack() {
+ return designSpaceManager.undoLastTransformation();
+ }
+
+ @Override
+ public void backtrackUntilLastCommonActivation(Object[] trajectory) {
+ designSpaceManager.backtrackUntilLastCommonActivation(trajectory);
+ }
+
+ @Override
+ public void backtrackUntilRoot() {
+ designSpaceManager.undoUntilRoot();
+ }
+
+ @Override
+ public boolean isCurrentStateAlreadyTraversed() {
+ return designSpaceManager.isNewModelStateAlreadyTraversed();
+ }
+
+ @Override
+ public boolean isCurrentStateInTrajectory() {
+ return designSpaceManager.isCurentStateInTrajectory();
+ }
+
+ public ActivationCodesConflictSet getActivationCodesConflictSet() {
+ return activationCodesConflictSet;
+ }
+
+ public void changeActivationOrdering(ChangeableConflictSet activationOrderingConflictSet) {
+ this.dseConflictSet.changeActivationOrderingConflictSet(activationOrderingConflictSet);
+ }
+
+ public void changeActivationOrderingBack() {
+ this.dseConflictSet.changeActivationOrderingConflictSetBack();
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java
new file mode 100644
index 00000000..bc0f08d4
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/DesignSpace.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.designspace.api;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+public class DesignSpace implements IDesignSpace {
+
+ Set statesView;
+
+ Set rootStates;
+ Set rootStatesView;
+
+ Map> statesAndActivations;
+
+ Random random = new Random();
+
+ public DesignSpace() {
+ rootStates = new HashSet<>();
+ rootStatesView = Collections.unmodifiableSet(rootStates);
+
+ statesAndActivations = new HashMap<>();
+ statesView = statesAndActivations.keySet();
+ }
+
+ @Override
+ public synchronized Collection getStates() {
+ return statesView;
+ }
+
+ @Override
+ public synchronized Collection getRoots() {
+ return rootStatesView;
+ }
+
+ @Override
+ public synchronized void addState(Object sourceStateId, Object firedActivationId, Object newStateId) {
+
+ List activationIds = statesAndActivations.get(newStateId);
+
+ if (activationIds == null) {
+ activationIds = new ArrayList();
+ statesAndActivations.put(newStateId, activationIds);
+
+ if (sourceStateId == null) {
+ rootStates.add(newStateId);
+ return;
+ }
+ }
+
+ activationIds = statesAndActivations.get(sourceStateId);
+
+ if (activationIds == null) {
+ activationIds = new ArrayList();
+ activationIds.add(firedActivationId);
+ statesAndActivations.put(sourceStateId, activationIds);
+ } else {
+ activationIds.add(firedActivationId);
+ }
+ }
+
+ public synchronized boolean isTraversed(Object stateId) {
+ return statesAndActivations.containsKey(stateId);
+ }
+
+ @Override
+ public synchronized Collection getActivationIds(Object stateId) {
+ return statesAndActivations.get(stateId);
+ }
+
+ @Override
+ public synchronized Object getRandomActivationId(Object stateId) {
+ List activations = statesAndActivations.get(stateId);
+ int index = random.nextInt(activations.size());
+ return activations.get(index);
+ }
+
+ @Override
+ public synchronized long getNumberOfStates() {
+ return statesAndActivations.size();
+ }
+
+ @Override
+ public synchronized long getNumberOfTransitions() {
+ int numberOfTransitions = 0;
+ for (List activations : statesAndActivations.values()) {
+ numberOfTransitions += activations.size();
+ }
+ return numberOfTransitions;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java
new file mode 100644
index 00000000..5c688276
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IBacktrackListener.java
@@ -0,0 +1,7 @@
+package org.eclipse.viatra.dse.designspace.api;
+
+public interface IBacktrackListener {
+ void forwardWorked(long nanos);
+
+ void backtrackWorked(long nanos);
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java
new file mode 100644
index 00000000..a1d64bbf
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/IDesignSpace.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.designspace.api;
+
+import java.util.Collection;
+
+public interface IDesignSpace {
+
+ Collection getStates();
+ Collection getRoots();
+ void addState(Object sourceStateId, Object firedActivationId, Object newStateId);
+
+ boolean isTraversed(Object stateId);
+
+ Collection getActivationIds(Object stateId);
+ Object getRandomActivationId(Object stateId);
+
+ long getNumberOfStates();
+ long getNumberOfTransitions();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java
new file mode 100644
index 00000000..acd88416
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/designspace/api/TrajectoryInfo.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.designspace.api;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.base.DesignSpaceManager;
+import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+public class TrajectoryInfo {
+
+ private final List trajectory;
+ private final List trajectoryView;
+ private final List> rules;
+ private final List> rulesView;
+ private final List stateIds;
+ private final List stateIdsView;
+ private final List> measuredCosts;
+
+ public TrajectoryInfo(Object initialStateId) {
+ Objects.requireNonNull(initialStateId);
+
+ stateIds = new ArrayList<>();
+ stateIds.add(initialStateId);
+
+ trajectory = new ArrayList<>();
+ rules = new ArrayList<>();
+ measuredCosts = new ArrayList<>();
+
+ trajectoryView = Collections.unmodifiableList(trajectory);
+ stateIdsView = Collections.unmodifiableList(stateIds);
+ rulesView = Collections.unmodifiableList(rules);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @since 0.17
+ */
+ public TrajectoryInfo(TrajectoryInfo other) {
+ this(other.stateIds, other.trajectory, other.rules, other.measuredCosts);
+ }
+
+ protected TrajectoryInfo(List stateIds, List trajectory, List> rules, List> measuredCosts) {
+
+ this.stateIds = new ArrayList<>(stateIds);
+ this.trajectory = new ArrayList<>(trajectory);
+ this.rules = new ArrayList<>(rules);
+ trajectoryView = Collections.unmodifiableList(trajectory);
+ stateIdsView = Collections.unmodifiableList(stateIds);
+ rulesView = Collections.unmodifiableList(rules);
+ this.measuredCosts = new ArrayList<>(measuredCosts);
+ }
+
+ public void addStep(Object activationId, BatchTransformationRule, ?> rule, Object newStateId, Map measuredCosts) {
+ stateIds.add(newStateId);
+ trajectory.add(activationId);
+ rules.add(rule);
+ this.measuredCosts.add(measuredCosts);
+ }
+
+ public void backtrack() {
+ int size = trajectory.size();
+
+ if (size == 0) {
+ throw new DSEException("Cannot step back any further!");
+ }
+
+ trajectory.remove(size - 1);
+ rules.remove(size - 1);
+ stateIds.remove(size);
+ measuredCosts.remove(size - 1);
+ }
+
+ public Object getInitialStateId() {
+ return stateIds.get(0);
+ }
+
+ public Object getCurrentStateId() {
+ return stateIds.get(stateIds.size() - 1);
+ }
+
+ public Object getLastActivationId() {
+ return trajectory.get(trajectory.size() - 1);
+ }
+
+ public List getTrajectory() {
+ return trajectoryView;
+ }
+
+ public List getStateTrajectory() {
+ return stateIdsView;
+ }
+
+ public List> getRules() {
+ return rulesView;
+ }
+
+ public int getDepth() {
+ return trajectory.size();
+ }
+
+ public List> getMeasuredCosts() {
+ return measuredCosts;
+ }
+
+ public SolutionTrajectory createSolutionTrajectory(final IStateCoderFactory stateCoderFactory, final IBacktrackListener listener) {
+
+ List activationIds = new ArrayList<>(trajectory);
+ List> copiedRules = new ArrayList<>(rules);
+
+ return new SolutionTrajectory(activationIds, copiedRules, stateCoderFactory, listener);
+ }
+
+ public boolean canStepBack() {
+ return !trajectory.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Trajectory:\n");
+ for (Object activationId : trajectory) {
+ sb.append(activationId);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * This method is only used by the {@link DesignSpaceManager}.
+ * @param stateCode
+ * @return false if the initial state code is the last one, otherwise true.
+ */
+ public boolean modifyLastStateCode(Object stateCode) {
+ if (stateIds.size() == 1) {
+ return false;
+ }
+ stateIds.set(stateIds.size() - 1, stateCode);
+ return true;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java
new file mode 100644
index 00000000..17e96a75
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/multithreading/DSEThreadPool.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.multithreading;
+
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.DesignSpaceExplorer;
+import org.eclipse.viatra.dse.base.ExplorerThread;
+
+/**
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class DSEThreadPool extends ThreadPoolExecutor {
+
+ private static final long THREAD_KEEP_ALIVE_IN_SECONDS = 60;
+
+ public DSEThreadPool() {
+ // Based on the Executors.newCachedThreadPool()
+ super(0, getProcNumber(), THREAD_KEEP_ALIVE_IN_SECONDS, TimeUnit.SECONDS, new SynchronousQueue());
+ }
+
+ // helper for constructor
+ private static int getProcNumber() {
+ return Runtime.getRuntime().availableProcessors();
+ }
+
+ public boolean tryStartNewStrategy(ExplorerThread strategy) {
+
+ if (!canStartNewThread()) {
+ return false;
+ }
+
+ try {
+ submit(strategy);
+ } catch (RejectedExecutionException e) {
+ Logger.getLogger(DesignSpaceExplorer.class).info("Couldn't start new thread.", e);
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean canStartNewThread() {
+ return getMaximumPoolSize() > getActiveCount();
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java
new file mode 100644
index 00000000..c06d2916
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ActivationFitnessProcessor.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+
+public interface ActivationFitnessProcessor {
+ public double process(IPatternMatch match);
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java
new file mode 100644
index 00000000..b1bd9349
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Comparators.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.Comparator;
+
+/**
+ * This helper class holds comparators for objective implementations.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class Comparators {
+
+ private Comparators() { /*Utility class constructor*/ }
+
+ public static final Comparator HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2);
+
+ public static final Comparator LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1);
+
+ private static final Double ZERO = Double.valueOf(0);
+
+ public static final Comparator DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2));
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java
new file mode 100644
index 00000000..8beef3bd
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/Fitness.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.HashMap;
+
+public class Fitness extends HashMap{
+
+ private boolean satisifiesHardObjectives;
+
+ public boolean isSatisifiesHardObjectives() {
+ return satisifiesHardObjectives;
+ }
+
+ public void setSatisifiesHardObjectives(boolean satisifiesHardObjectives) {
+ this.satisifiesHardObjectives = satisifiesHardObjectives;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " hardObjectives=" + satisifiesHardObjectives;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java
new file mode 100644
index 00000000..2f7f0347
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IGlobalConstraint.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+
+/**
+ *
+ * Implementation of this interface represents a global constraint of the DSE problem, which can halt an exploration
+ * continuing from a state which dissatisfies the global constraint.
+ *
+ * Certain global constraints can have inner state for the validation. In this case a new instance is necessary for
+ * every new thread, and the {@code createNew} method should not return the same instance more than once.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface IGlobalConstraint {
+
+ /**
+ * Returns the name of the global constraint.
+ *
+ * @return The name of the global constraint.
+ */
+ String getName();
+
+ /**
+ * Checks whether the current state satisfies the global constraint.
+ *
+ * @param context
+ * The {@link ThreadContext} which contains the necessary information.
+ * @return True if the state is valid and exploration can be continued from the actual state.
+ */
+ boolean checkGlobalConstraint(ThreadContext context);
+
+ /**
+ * Initializes the global constraint. It is called exactly once for every thread starts.
+ *
+ * @param context
+ * The {@link ThreadContext}.
+ */
+ void init(ThreadContext context);
+
+ /**
+ * Returns an instance of the {@link IGlobalConstraint}. If it returns the same instance, all the methods has to be
+ * thread save as they are called concurrently.
+ *
+ * @return An instance of the global constraint.
+ */
+ IGlobalConstraint createNew();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java
new file mode 100644
index 00000000..849dd4e8
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/IObjective.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.Comparator;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+
+/**
+ *
+ * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution
+ * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated
+ * value.
+ *
+ * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard
+ * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution.
+ *
+ * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary
+ * for every new thread, and the {@code createNew} method should not return the same instance more than once.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface IObjective {
+
+ /**
+ * Returns the name of the objective.
+ *
+ * @return The name of the objective.
+ */
+ String getName();
+
+ /**
+ * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to
+ * minimize or maximize (or minimize or maximize a delta from a given number).
+ *
+ * @param comparator The comparator.
+ */
+ void setComparator(Comparator comparator);
+
+ /**
+ * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is
+ * to minimize or maximize (or minimize or maximize a delta from a given number).
+ *
+ * @return The comparator.
+ */
+ Comparator getComparator();
+
+ /**
+ * Calculates the value of the objective on a given solution (trajectory).
+ *
+ * @param context
+ * The {@link ThreadContext}
+ * @return The objective value in double.
+ */
+ Double getFitness(ThreadContext context);
+
+ /**
+ * Initializes the objective. It is called exactly once for every thread starts.
+ *
+ * @param context
+ * The {@link ThreadContext}.
+ */
+ void init(ThreadContext context);
+
+ /**
+ * Returns an instance of the {@link IObjective}. If it returns the same instance, all the methods has to be thread
+ * save as they are called concurrently.
+ *
+ * @return An instance of the objective.
+ */
+ IObjective createNew();
+
+ /**
+ * Returns true if the objective is a hard objective. In such a case the method
+ * {@link IObjective#satisifiesHardObjective(Double)} is called.
+ *
+ * @return True if the objective is a hard objective.
+ * @see IObjective#satisifiesHardObjective(Double)
+ * @see IObjective
+ */
+ boolean isHardObjective();
+
+ /**
+ * Determines if the given fitness value satisfies the hard objective.
+ *
+ * @param fitness
+ * The fitness value of a solution.
+ * @return True if it satisfies the hard objective or it is a soft constraint.
+ * @see IObjective
+ */
+ boolean satisifiesHardObjective(Double fitness);
+
+ /**
+ * Set the level of the objective.
+ */
+ void setLevel(int level);
+
+ /**
+ * Gets the level of the objective.
+ */
+ int getLevel();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java
new file mode 100644
index 00000000..2d81629b
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/LeveledObjectivesHelper.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+public class LeveledObjectivesHelper {
+
+ private List objectives = new ArrayList();
+ private IObjective[][] leveledObjectives;
+
+ public LeveledObjectivesHelper(List objectives) {
+ this.objectives = objectives;
+ }
+
+ public IObjective[][] initLeveledObjectives() {
+ if (objectives.isEmpty()) {
+ leveledObjectives = new IObjective[0][0];
+ return leveledObjectives;
+ }
+
+ int level = objectives.get(0).getLevel();
+ boolean oneLevelOnly = true;
+ for (IObjective objective : objectives) {
+ if (objective.getLevel() != level) {
+ oneLevelOnly = false;
+ break;
+ }
+ }
+
+ if (oneLevelOnly) {
+ leveledObjectives = new IObjective[1][objectives.size()];
+ for (int i = 0; i < objectives.size(); i++) {
+ leveledObjectives[0][i] = objectives.get(i);
+ }
+ return leveledObjectives;
+ }
+
+ IObjective[] objectivesArray = getSortedByLevelObjectives(objectives);
+
+ int numberOfLevels = getNumberOfObjectiveLevels(objectivesArray);
+
+ leveledObjectives = new IObjective[numberOfLevels][];
+
+ fillLeveledObjectives(objectivesArray);
+
+ return leveledObjectives;
+ }
+
+ private void fillLeveledObjectives(IObjective[] objectivesArray) {
+ int actLevel = objectivesArray[0].getLevel();
+ int levelIndex = 0;
+ int lastIndex = 0;
+ int corrigationForLastLevel = 0;
+ boolean oneObjectiveAtLastLevel = false;
+ for (int i = 0; i < objectivesArray.length; i++) {
+ if (i == objectivesArray.length - 1) {
+ corrigationForLastLevel = 1;
+ if (objectivesArray[i - 1].getLevel() != objectivesArray[i].getLevel()) {
+ oneObjectiveAtLastLevel = true;
+ corrigationForLastLevel = 0;
+ }
+ }
+ if (objectivesArray[i].getLevel() != actLevel || corrigationForLastLevel == 1 || oneObjectiveAtLastLevel) {
+ leveledObjectives[levelIndex] = new IObjective[i - lastIndex + corrigationForLastLevel];
+ for (int j = lastIndex; j < i + corrigationForLastLevel; j++) {
+ leveledObjectives[levelIndex][j - lastIndex] = objectivesArray[j];
+ }
+ if (oneObjectiveAtLastLevel) {
+ leveledObjectives[levelIndex + 1] = new IObjective[1];
+ leveledObjectives[levelIndex + 1][0] = objectivesArray[i];
+ }
+ actLevel = objectivesArray[i].getLevel();
+ levelIndex++;
+ lastIndex = i;
+ }
+ }
+ }
+
+ private int getNumberOfObjectiveLevels(IObjective[] objectivesArray) {
+
+ int actLevel = objectivesArray[0].getLevel();
+ int numberOfLevels = 1;
+
+ for (int i = 1; i < objectivesArray.length; i++) {
+ if (objectivesArray[i].getLevel() != actLevel) {
+ numberOfLevels++;
+ actLevel = objectivesArray[i].getLevel();
+ }
+ }
+
+ return numberOfLevels;
+ }
+
+ private IObjective[] getSortedByLevelObjectives(List objectives) {
+ IObjective[] objectivesArray = objectives.toArray(new IObjective[objectives.size()]);
+ Arrays.sort(objectivesArray, Comparator.comparingInt(IObjective::getLevel));
+ return objectivesArray;
+ }
+
+ public IObjective[][] getLeveledObjectives() {
+ return leveledObjectives;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java
new file mode 100644
index 00000000..39139bb0
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/ObjectiveComparatorHelper.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
+
+/**
+ * This class is responsible to compare and sort fitness values. {@link TrajectoryFitness} instances can be added to an
+ * instance of this class, that it can sort them.
+ *
+ * @author András Szabolcs Nagy
+ */
+public class ObjectiveComparatorHelper {
+
+ private IObjective[][] leveledObjectives;
+ private List trajectoryFitnesses = new ArrayList();
+ private Random random = new Random();
+ private boolean computeCrowdingDistance = false;
+
+ public ObjectiveComparatorHelper(IObjective[][] leveledObjectives) {
+ this.leveledObjectives = leveledObjectives;
+ }
+
+ public void setComputeCrowdingDistance(boolean computeCrowdingDistance) {
+ this.computeCrowdingDistance = computeCrowdingDistance;
+ }
+
+ /**
+ * Compares two fitnesses based on hierarchical dominance. Returns -1 if the second parameter {@code o2} is a better
+ * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates
+ * {@code o2}) and returns 0 if they are non-dominating each other.
+ */
+ public int compare(Fitness o1, Fitness o2) {
+
+ levelsLoop: for (int i = 0; i < leveledObjectives.length; i++) {
+
+ boolean o1HasBetterFitness = false;
+ boolean o2HasBetterFitness = false;
+
+ for (IObjective objective : leveledObjectives[i]) {
+ String objectiveName = objective.getName();
+ int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName));
+
+ if (sgn < 0) {
+ o2HasBetterFitness = true;
+ }
+ if (sgn > 0) {
+ o1HasBetterFitness = true;
+ }
+ if (o1HasBetterFitness && o2HasBetterFitness) {
+ continue levelsLoop;
+ }
+ }
+ if (o2HasBetterFitness && !o1HasBetterFitness) {
+ return -1;
+ } else if (!o2HasBetterFitness && o1HasBetterFitness) {
+ return 1;
+ }
+ }
+
+ return 0;
+
+ }
+
+ /**
+ * Adds a {@link TrajectoryFitness} to an inner list to compare later.
+ *
+ * @param trajectoryFitness
+ */
+ public void addTrajectoryFitness(TrajectoryFitness trajectoryFitness) {
+ trajectoryFitnesses.add(trajectoryFitness);
+ }
+
+ /**
+ * Clears the inner {@link TrajectoryFitness} list.
+ */
+ public void clearTrajectoryFitnesses() {
+ trajectoryFitnesses.clear();
+ }
+
+ /**
+ * Returns the inner {@link TrajectoryFitness} list.
+ */
+ public List getTrajectoryFitnesses() {
+ return trajectoryFitnesses;
+ }
+
+ /**
+ * Returns a random {@link TrajectoryFitness} from the pareto front.
+ */
+ public TrajectoryFitness getRandomBest() {
+ List paretoFront = getParetoFront();
+ int randomIndex = random.nextInt(paretoFront.size());
+ return paretoFront.get(randomIndex);
+ }
+
+ /**
+ * Returns the pareto front of the previously added {@link TrajectoryFitness}.
+ */
+ public List getParetoFront() {
+ return getFronts().get(0);
+ }
+
+ /**
+ * Returns the previously added {@link TrajectoryFitness} instances in fronts.
+ */
+ public List extends List> getFronts() {
+ Preconditions.checkArgument(!trajectoryFitnesses.isEmpty(), "No trajectory fitnesses were added.");
+ List> fronts = new ArrayList>();
+
+ Map> dominatedInstances = new HashMap>();
+ Map dominatingInstances = new HashMap();
+
+ // calculate dominations
+ for (TrajectoryFitness TrajectoryFitnessP : trajectoryFitnesses) {
+ dominatedInstances.put(TrajectoryFitnessP, new ArrayList());
+ dominatingInstances.put(TrajectoryFitnessP, 0);
+
+ for (TrajectoryFitness TrajectoryFitnessQ : trajectoryFitnesses) {
+ int dominates = compare(TrajectoryFitnessP.fitness, TrajectoryFitnessQ.fitness);
+ if (dominates > 0) {
+ dominatedInstances.get(TrajectoryFitnessP).add(TrajectoryFitnessQ);
+ } else if (dominates < 0) {
+ dominatingInstances.put(TrajectoryFitnessP, dominatingInstances.get(TrajectoryFitnessP) + 1);
+ }
+ }
+
+ if (dominatingInstances.get(TrajectoryFitnessP) == 0) {
+ // p belongs to the first front
+ TrajectoryFitnessP.rank = 1;
+ if (fronts.isEmpty()) {
+ ArrayList firstDominationFront = new ArrayList();
+ firstDominationFront.add(TrajectoryFitnessP);
+ fronts.add(firstDominationFront);
+ } else {
+ List firstDominationFront = fronts.get(0);
+ firstDominationFront.add(TrajectoryFitnessP);
+ }
+ }
+ }
+
+ // create fronts
+ int i = 1;
+ while (fronts.size() == i) {
+ ArrayList nextDominationFront = new ArrayList();
+ for (TrajectoryFitness TrajectoryFitnessP : fronts.get(i - 1)) {
+ for (TrajectoryFitness TrajectoryFitnessQ : dominatedInstances.get(TrajectoryFitnessP)) {
+ dominatingInstances.put(TrajectoryFitnessQ, dominatingInstances.get(TrajectoryFitnessQ) - 1);
+ if (dominatingInstances.get(TrajectoryFitnessQ) == 0) {
+ TrajectoryFitnessQ.rank = i + 1;
+ nextDominationFront.add(TrajectoryFitnessQ);
+ }
+ }
+ }
+ i++;
+ if (!nextDominationFront.isEmpty()) {
+ if (computeCrowdingDistance) {
+ crowdingDistanceAssignment(nextDominationFront, leveledObjectives);
+ }
+ fronts.add(nextDominationFront);
+ }
+ }
+
+ return fronts;
+ }
+
+ /**
+ * Executes the crowding distance assignment for the specified front.
+ *
+ * @param front
+ */
+ public static void crowdingDistanceAssignment(List front, IObjective[][] leveledObjectives) {
+
+ for (TrajectoryFitness InstanceData : front) {
+ // initialize crowding distance
+ InstanceData.crowdingDistance = 0;
+ }
+
+ for (final IObjective[] objectives : leveledObjectives) {
+ for (final IObjective objective : objectives) {
+
+ final String m = objective.getName();
+ TrajectoryFitness[] sortedFront = front.toArray(new TrajectoryFitness[0]);
+ // sort using m-th objective value
+ Arrays.sort(sortedFront, (o1, o2) -> objective.getComparator().compare(o1.fitness.get(m), o2.fitness.get(m)));
+ // so that boundary points are always selected
+ sortedFront[0].crowdingDistance = Double.POSITIVE_INFINITY;
+ sortedFront[sortedFront.length - 1].crowdingDistance = Double.POSITIVE_INFINITY;
+ // If minimal and maximal fitness value for this objective are
+ // equal, then do not change crowding distance
+ if (sortedFront[0].fitness.get(m) != sortedFront[sortedFront.length - 1].fitness.get(m)) {
+ for (int i = 1; i < sortedFront.length - 1; i++) {
+ double newCrowdingDistance = sortedFront[i].crowdingDistance;
+ newCrowdingDistance += (sortedFront[i + 1].fitness.get(m) - sortedFront[i - 1].fitness.get(m))
+ / (sortedFront[sortedFront.length - 1].fitness.get(m) - sortedFront[0].fitness.get(m));
+
+ sortedFront[i].crowdingDistance = newCrowdingDistance;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java
new file mode 100644
index 00000000..f783afac
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/TrajectoryFitness.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+
+/**
+ * This class represents a trajectory and its fitness.
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class TrajectoryFitness {
+
+ public Object[] trajectory;
+ public Fitness fitness;
+
+ public int rank;
+ public double crowdingDistance;
+
+ private int hash;
+
+ public int survive;
+
+ /**
+ * Creates a {@link TrajectoryFitness} with the full trajectory.
+ * @param trajectory The trajectory.
+ * @param fitness The fitness.
+ */
+ public TrajectoryFitness(Object[] trajectory, Fitness fitness) {
+ this.fitness = fitness;
+ this.trajectory = trajectory;
+ }
+
+ /**
+ * Creates a {@link TrajectoryFitness} with the full trajectory.
+ * @param trajectoryInfo The trajectory.
+ * @param fitness The fitness.
+ */
+ public TrajectoryFitness(TrajectoryInfo trajectoryInfo, Fitness fitness) {
+ this.fitness = fitness;
+ List fullTraj = trajectoryInfo.getTrajectory();
+ trajectory = fullTraj.toArray(new Object[fullTraj.size()]);
+ }
+
+ /**
+ * Creates a {@link TrajectoryFitness} with the given activation id}
+ * @param transition The transition.
+ * @param fitness The fitness.
+ */
+ public TrajectoryFitness(Object transition, Fitness fitness) {
+ this.fitness = fitness;
+ trajectory = new Object[] {transition};
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TrajectoryFitness) {
+ return Arrays.equals(trajectory, ((TrajectoryFitness) obj).trajectory);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hash == 0 && trajectory.length > 0) {
+ hash = Arrays.hashCode(trajectory);
+ }
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(trajectory) + fitness.toString();
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java
new file mode 100644
index 00000000..9898a3b5
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/AlwaysSatisfiedDummyHardObjective.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+
+/**
+ * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class AlwaysSatisfiedDummyHardObjective extends BaseObjective {
+
+ private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
+
+ public AlwaysSatisfiedDummyHardObjective() {
+ super(DEFAULT_NAME);
+ }
+
+ public AlwaysSatisfiedDummyHardObjective(String name) {
+ super(name);
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+ return 0d;
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return true;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+ return true;
+ }
+
+ @Override
+ public IObjective createNew() {
+ return this;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java
new file mode 100644
index 00000000..0a1de875
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/BaseObjective.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Comparators;
+import org.eclipse.viatra.dse.objectives.IObjective;
+
+/**
+ * This abstract class implements the basic functionality of an objective ({@link IObjective} namely its name,
+ * comparator, level and fitness hard constraint.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public abstract class BaseObjective implements IObjective {
+
+ protected final String name;
+ protected Comparator comparator = Comparators.HIGHER_IS_BETTER;
+ protected int level = 0;
+
+ protected double fitnessConstraint;
+ protected boolean isThereFitnessConstraint = false;
+ protected Comparator fitnessConstraintComparator;
+
+ public BaseObjective(String name) {
+ Objects.requireNonNull(name, "Name of the objective cannot be null.");
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void setComparator(Comparator comparator) {
+ this.comparator = comparator;
+ }
+
+ @Override
+ public Comparator getComparator() {
+ return comparator;
+ }
+
+ @Override
+ public void setLevel(int level) {
+ this.level = level;
+ }
+
+ @Override
+ public int getLevel() {
+ return level;
+ }
+
+ public BaseObjective withLevel(int level) {
+ setLevel(level);
+ return this;
+ }
+
+ public BaseObjective withComparator(Comparator comparator) {
+ setComparator(comparator);
+ return this;
+ }
+
+ /**
+ * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
+ * current state as a solution.
+ *
+ * @param fitnessConstraint
+ * Solutions should be better than this value.
+ * @param fitnessConstraintComparator
+ * {@link Comparator} to determine if the current state is better than the given value.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public BaseObjective withHardConstraintOnFitness(double fitnessConstraint,
+ Comparator fitnessConstraintComparator) {
+ this.fitnessConstraint = fitnessConstraint;
+ this.fitnessConstraintComparator = fitnessConstraintComparator;
+ this.isThereFitnessConstraint = true;
+ return this;
+ }
+
+ /**
+ * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
+ * current state as a solution. The provided comparator will be used.
+ *
+ * @param fitnessConstraint
+ * Solutions should be better than this value.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) {
+ return withHardConstraintOnFitness(fitnessConstraint, null);
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ if (fitnessConstraintComparator == null) {
+ fitnessConstraintComparator = comparator;
+ }
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return isThereFitnessConstraint;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+ if (isThereFitnessConstraint) {
+ int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint);
+ if (compare < 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof BaseObjective) {
+ BaseObjective baseObjective = (BaseObjective) obj;
+ return name.equals(baseObjective.getName());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java
new file mode 100644
index 00000000..cc48d22e
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/CompositeObjective.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
+
+/**
+ * This objective collects a list of other objectives. It returns the weighted sum of the objectives.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class CompositeObjective extends BaseObjective {
+
+ public static final String DEFAULT_NAME = "CompositeObjective";
+ protected List objectives;
+ protected List weights;
+ protected boolean hardObjective;
+
+ public CompositeObjective(String name, List objectives, List weights) {
+ super(name);
+ Objects.requireNonNull(objectives, "The list of objectives cannot be null.");
+ Objects.requireNonNull(weights, "The list of weights cannot be null.");
+ Preconditions.checkState(objectives.size() == weights.size(), "The size of the objectives and weights must match.");
+ this.objectives = objectives;
+ this.weights = weights;
+ }
+
+ public CompositeObjective(List objectives, List weights) {
+ this(DEFAULT_NAME, objectives, weights);
+ }
+
+ public CompositeObjective(String name) {
+ this(name, new ArrayList(), new ArrayList());
+ }
+
+ public CompositeObjective() {
+ this(DEFAULT_NAME, new ArrayList(), new ArrayList());
+ }
+
+ /**
+ * Adds a new objective.
+ *
+ * @param objective
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public CompositeObjective withObjective(IObjective objective) {
+ objectives.add(objective);
+ weights.add(1d);
+ return this;
+ }
+
+ /**
+ * Adds a new objective.
+ *
+ * @param objective
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public CompositeObjective withObjective(IObjective objective, double weight) {
+ objectives.add(objective);
+ weights.add(weight);
+ return this;
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+
+ double result = 0;
+
+ for (int i = 0; i < objectives.size(); i++) {
+ IObjective objective = objectives.get(i);
+ Double weight = weights.get(i);
+ result += objective.getFitness(context) * weight;
+ }
+ return result;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ super.init(context);
+ hardObjective = false;
+ for (IObjective objective : objectives) {
+ objective.init(context);
+ if (objective.isHardObjective()) {
+ hardObjective = true;
+ }
+ }
+ }
+
+ @Override
+ public IObjective createNew() {
+
+ List newObjectives = new ArrayList();
+
+ for (IObjective objective : objectives) {
+ newObjectives.add(objective.createNew());
+ }
+
+ CompositeObjective objective = new CompositeObjective(name, newObjectives, weights);
+ if (isThereFitnessConstraint) {
+ objective.withHardConstraintOnFitness(fitnessConstraint, fitnessConstraintComparator);
+ }
+
+ return objective.withComparator(comparator).withLevel(level);
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return hardObjective;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+
+ boolean hardObjectiveSatisfied = true;
+
+ for (IObjective objective : objectives) {
+ hardObjectiveSatisfied = objective.satisifiesHardObjective(fitness) ? hardObjectiveSatisfied : false;
+ }
+
+ hardObjectiveSatisfied = super.satisifiesHardObjective(fitness) ? hardObjectiveSatisfied : false;
+
+ return hardObjectiveSatisfied;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java
new file mode 100644
index 00000000..77d416f5
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ConstraintsObjective.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher;
+import org.eclipse.viatra.query.runtime.exception.ViatraQueryException;
+
+/**
+ * This objective serves as soft and as hard objective at the same time by defining two lists of VIATRA Query
+ * specifications.
+ *
+ * As a soft objective, it collects a list of VIATRA Query specifications, which have predefined weights. Then the
+ * fitness value of an arbitrary solution is calculated in the following way:
+ *
+ * fitness = sum( pattern[i].countMatches() * weight[i] )
+ *
+ * As a hard objective it collects a separate list of VIATRA Query specifications. If every one of them has a match the
+ * hard constraint is considered to be fulfilled.
+ *
+ * @author Andras Szabolcs Nagy
+ * @see IObjective
+ *
+ */
+public class ConstraintsObjective extends BaseObjective {
+
+ public static final String DEFAULT_NAME = "ConstraintsObjective";
+
+ public static class QueryConstraint {
+ public final String name;
+ public final IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> query;
+ public final Double weight;
+ public final ModelQueryType type;
+
+ public QueryConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> query, Double weight,
+ ModelQueryType type) {
+ this.name = name;
+ this.query = query;
+ this.weight = weight;
+ this.type = type;
+ }
+
+ public QueryConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> query, Double weight) {
+ this(name, query, weight, ModelQueryType.MUST_HAVE_MATCH);
+ }
+
+ public QueryConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> query, ModelQueryType type) {
+ this(name, query, 0d, type);
+ }
+ }
+
+ protected List softConstraints;
+ protected List hardConstraints;
+
+ protected List> softMatchers;
+ protected List> hardMatchers;
+ protected List softMatches;
+ protected List hardMatches;
+
+ public ConstraintsObjective(String name, List softConstraints,
+ List hardConstraints) {
+ super(name);
+ Objects.requireNonNull(softConstraints, "The list of soft constraints cannot be null.");
+ Objects.requireNonNull(hardConstraints, "The list of hard constraints cannot be null.");
+
+ this.softConstraints = softConstraints;
+ this.hardConstraints = hardConstraints;
+ }
+
+ public ConstraintsObjective(String name, List hardConstraints) {
+ this(name, new ArrayList(), hardConstraints);
+ }
+
+ public ConstraintsObjective(List hardConstraints) {
+ this(DEFAULT_NAME, new ArrayList(), hardConstraints);
+ }
+
+ public ConstraintsObjective(String name) {
+ this(name, new ArrayList(), new ArrayList());
+ }
+
+ public ConstraintsObjective() {
+ this(DEFAULT_NAME, new ArrayList(), new ArrayList());
+ }
+
+ /**
+ * Adds a new soft constraint.
+ *
+ * @param name
+ * A name for the soft constraint.
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @param weight
+ * The weight of the pattern.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withSoftConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> softConstraint, double weight) {
+ softConstraints.add(new QueryConstraint(name, softConstraint, weight));
+ return this;
+ }
+
+ /**
+ * Adds a new soft constraint with the name of the query specification's fully qualified name.
+ *
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @param weight
+ * The weight of the pattern.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withSoftConstraint(
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> softConstraint, double weight) {
+ return withSoftConstraint(softConstraint.getFullyQualifiedName(), softConstraint, weight);
+ }
+
+ /**
+ * Adds a new hard constraint.
+ *
+ * @param name
+ * A name for the hard constraint.
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @param type
+ * {@link ModelQueryType}, which determines whether the constraint should have at least one match or none
+ * at all.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withHardConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> hardConstraint,
+ ModelQueryType type) {
+ hardConstraints.add(new QueryConstraint(name, hardConstraint, type));
+ return this;
+ }
+
+ /**
+ * Adds a new hard constraint with the default {@link ModelQueryType#MUST_HAVE_MATCH}.
+ *
+ * @param name
+ * A name for the hard constraint.
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withHardConstraint(String name,
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> hardConstraint) {
+ hardConstraints.add(new QueryConstraint(name, hardConstraint, ModelQueryType.MUST_HAVE_MATCH));
+ return this;
+ }
+
+ /**
+ * Adds a new hard constraint with the name of the query specification's fully qualified name and the default
+ * {@link ModelQueryType#MUST_HAVE_MATCH}.
+ *
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withHardConstraint(
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> hardConstraint) {
+ return withHardConstraint(hardConstraint.getFullyQualifiedName(), hardConstraint,
+ ModelQueryType.MUST_HAVE_MATCH);
+ }
+
+ /**
+ * Adds a new hard constraint with the name of the query specification's fully qualified name.
+ *
+ * @param softConstraint
+ * A VIATRA Query pattern specification.
+ * @param type
+ * {@link ModelQueryType}, which determines whether the constraint should have at least one match or none
+ * at all.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ConstraintsObjective withHardConstraint(
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> hardConstraint,
+ ModelQueryType type) {
+ return withHardConstraint(hardConstraint.getFullyQualifiedName(), hardConstraint, type);
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+
+ if (softConstraints.isEmpty()) {
+ return 0d;
+ }
+
+ double result = 0;
+
+ for (int i = 0; i < softConstraints.size(); i++) {
+ int countMatches = softMatchers.get(i).countMatches();
+ result += countMatches * softConstraints.get(i).weight;
+ softMatches.set(i, Integer.valueOf(countMatches));
+ }
+
+ return result;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+
+ super.init(context);
+
+ softMatches = new ArrayList(softConstraints.size());
+ softMatchers = new ArrayList>(softConstraints.size());
+ hardMatches = new ArrayList(hardConstraints.size());
+ hardMatchers = new ArrayList>(hardConstraints.size());
+ for (int i = 0; i < softConstraints.size(); i++) {
+ softMatches.add(0);
+ }
+ for (int i = 0; i < hardConstraints.size(); i++) {
+ hardMatches.add(0);
+ }
+
+ try {
+ ViatraQueryEngine queryEngine = context.getQueryEngine();
+
+ for (QueryConstraint qc : softConstraints) {
+ softMatchers.add(qc.query.getMatcher(queryEngine));
+ }
+
+ for (QueryConstraint qc : hardConstraints) {
+ hardMatchers.add(qc.query.getMatcher(queryEngine));
+ }
+
+ } catch (ViatraQueryException e) {
+ throw new DSEException("Couldn't initialize the VIATRA Query matcher, see inner exception", e);
+ }
+ }
+
+ @Override
+ public IObjective createNew() {
+ new ArrayList(softConstraints.size());
+ ConstraintsObjective result = new ConstraintsObjective(name, softConstraints, hardConstraints);
+ if (isThereFitnessConstraint) {
+ result.withHardConstraintOnFitness(fitnessConstraint, fitnessConstraintComparator);
+ }
+ return result.withComparator(comparator).withLevel(level);
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return !hardConstraints.isEmpty() || super.isHardObjective();
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+
+ boolean result = true;
+
+ for (int i = 0; i < hardConstraints.size(); i++) {
+ ModelQueryType type = hardConstraints.get(i).type;
+ int countMatches = hardMatchers.get(i).countMatches();
+ hardMatches.set(i, Integer.valueOf(countMatches));
+ if ((type.equals(ModelQueryType.MUST_HAVE_MATCH) && countMatches <= 0)
+ || (type.equals(ModelQueryType.NO_MATCH) && countMatches > 0)) {
+ result = false;
+ }
+ }
+
+ result = super.satisifiesHardObjective(fitness) ? result : false;
+
+ return result;
+ }
+
+ public List getSoftConstraints() {
+ return softConstraints;
+ }
+
+ public List getHardConstraints() {
+ return hardConstraints;
+ }
+
+ public String getSoftName(int index) {
+ return softConstraints.get(index).name;
+ }
+
+ public String getHardName(int index) {
+ return hardConstraints.get(index).name;
+ }
+
+ public List getSoftMatches() {
+ return softMatches;
+ }
+
+ public List getHardMatches() {
+ return hardMatches;
+ }
+
+ public List getSoftNames() {
+ List softNames = new ArrayList<>(softConstraints.size());
+ for (QueryConstraint qc : softConstraints) {
+ softNames.add(qc.name);
+ }
+ return softNames;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java
new file mode 100644
index 00000000..b21da397
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/DepthHardObjective.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+
+/**
+ * This hard objective is fulfilled if the trajectory is in the specified interval (inclusive).
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class DepthHardObjective extends BaseObjective {
+
+ private static final String DEFAULT_NAME = "DepthHardObjective";
+ protected int minDepth;
+ protected int maxDepth;
+ private ThreadContext context;
+
+ public DepthHardObjective() {
+ this(DEFAULT_NAME, 0, Integer.MAX_VALUE);
+ }
+
+ public DepthHardObjective(String name) {
+ this(name, 0, Integer.MAX_VALUE);
+ }
+
+ public DepthHardObjective(int minDepth) {
+ this(DEFAULT_NAME, minDepth, Integer.MAX_VALUE);
+ }
+
+ public DepthHardObjective(String name, int minDepth) {
+ this(name, minDepth, Integer.MAX_VALUE);
+ }
+
+ public DepthHardObjective(int minDepth, int maxDepth) {
+ this(DEFAULT_NAME, minDepth, maxDepth);
+ }
+
+ public DepthHardObjective(String name, int minDepth, int maxDepth) {
+ super(name);
+ this.minDepth = minDepth;
+ this.maxDepth = maxDepth;
+ }
+
+ public DepthHardObjective withMinDepth(int minDepth) {
+ this.minDepth = minDepth;
+ return this;
+ }
+
+ public DepthHardObjective withMaxDepth(int maxDepth) {
+ this.maxDepth = maxDepth;
+ return this;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ super.init(context);
+ this.context = context;
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+ return 0d;
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return true;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+ return minDepth <= context.getDepth() && context.getDepth() <= maxDepth;
+ }
+
+ @Override
+ public IObjective createNew() {
+ return new DepthHardObjective(name, minDepth, maxDepth);
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java
new file mode 100644
index 00000000..7616b4a2
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueriesGlobalConstraint.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IGlobalConstraint;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher;
+import org.eclipse.viatra.query.runtime.exception.ViatraQueryException;
+
+/**
+ * This global constraint collects a list of VIATRA Query pattern and checks if any of them has a match on along a trajectory.
+ * If any of the patterns has a match then it is unsatisfied and the exploration should backtrack.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class ModelQueriesGlobalConstraint implements IGlobalConstraint {
+
+ public static final String GLOBAL_CONSTRAINT = "GlobalConstraint";
+ protected String name;
+ protected List>> constraints;
+ protected List> matchers = new ArrayList>();
+ protected ModelQueryType type = ModelQueryType.NO_MATCH;
+
+ public ModelQueriesGlobalConstraint(String name,
+ List>> constraints) {
+ Objects.requireNonNull(name, "Name of the global constraint cannot be null.");
+ Objects.requireNonNull(constraints, "The list of constraints cannot be null.");
+
+ this.name = name;
+ this.constraints = constraints;
+ }
+
+ public ModelQueriesGlobalConstraint(
+ List>> constraints) {
+ this(GLOBAL_CONSTRAINT, constraints);
+ }
+
+ public ModelQueriesGlobalConstraint(String name) {
+ this(name, new ArrayList>>());
+ }
+
+ public ModelQueriesGlobalConstraint() {
+ this(GLOBAL_CONSTRAINT,
+ new ArrayList>>());
+ }
+
+ /**
+ * Adds a new VIATRA Query pattern.
+ *
+ * @param constraint
+ * A VIATRA Query pattern.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public ModelQueriesGlobalConstraint withConstraint(
+ IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> constraint) {
+ constraints.add(constraint);
+ return this;
+ }
+
+ public ModelQueriesGlobalConstraint withType(ModelQueryType type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean checkGlobalConstraint(ThreadContext context) {
+ for (ViatraQueryMatcher extends IPatternMatch> matcher : matchers) {
+ if ((type.equals(ModelQueryType.NO_MATCH) && matcher.countMatches() > 0)
+ || (type.equals(ModelQueryType.MUST_HAVE_MATCH) && matcher.countMatches() == 0)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ try {
+ ViatraQueryEngine queryEngine = context.getQueryEngine();
+
+ for (IQuerySpecification extends ViatraQueryMatcher extends IPatternMatch>> querySpecification : constraints) {
+ ViatraQueryMatcher extends IPatternMatch> matcher = querySpecification.getMatcher(queryEngine);
+ matchers.add(matcher);
+ }
+
+ } catch (ViatraQueryException e) {
+ throw new DSEException("Couldn't get the VIATRA Query matcher, see inner exception", e);
+ }
+ }
+
+ @Override
+ public IGlobalConstraint createNew() {
+ return new ModelQueriesGlobalConstraint(name, constraints);
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java
new file mode 100644
index 00000000..76390352
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/ModelQueryType.java
@@ -0,0 +1,14 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+public enum ModelQueryType {
+ MUST_HAVE_MATCH,
+ NO_MATCH
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java
new file mode 100644
index 00000000..27cf139c
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NeverSatisfiedDummyHardObjective.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+
+/**
+ * This hard objective is never fulfilled. Use it if all states should be regarded as an invalid solution.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class NeverSatisfiedDummyHardObjective extends BaseObjective {
+
+ private static final String DEFAULT_NAME = "NeverSatisfiedDummyHardObjective";
+
+ public NeverSatisfiedDummyHardObjective() {
+ super(DEFAULT_NAME);
+ }
+
+ public NeverSatisfiedDummyHardObjective(String name) {
+ super(name);
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+ return 0d;
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return true;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+ return false;
+ }
+
+ @Override
+ public IObjective createNew() {
+ return this;
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java
new file mode 100644
index 00000000..756d94ec
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/NoRuleActivationsHardObjective.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.IObjective;
+
+/**
+ * This hard objective is satisfied if there are no rule activations from the current state (returning 1 in this case).
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class NoRuleActivationsHardObjective extends BaseObjective {
+
+ protected static final String DEFAULT_NAME = "NoMoreActivationHardObjective";
+ private ThreadContext context;
+
+ public NoRuleActivationsHardObjective(String name) {
+ super(name);
+ }
+
+ public NoRuleActivationsHardObjective() {
+ this(DEFAULT_NAME);
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+ return 0d;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ super.init(context);
+ this.context = context;
+ }
+
+ @Override
+ public IObjective createNew() {
+ return new NoRuleActivationsHardObjective(name);
+ }
+
+ @Override
+ public boolean isHardObjective() {
+ return true;
+ }
+
+ @Override
+ public boolean satisifiesHardObjective(Double fitness) {
+ return context.getConflictSet().getNextActivations().isEmpty();
+ }
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java
new file mode 100644
index 00000000..25ff45ae
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/objectives/impl/TrajectoryCostSoftObjective.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.objectives.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+import org.eclipse.viatra.dse.base.DesignSpaceManager;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.designspace.api.TrajectoryInfo;
+import org.eclipse.viatra.dse.objectives.ActivationFitnessProcessor;
+import org.eclipse.viatra.dse.objectives.Comparators;
+import org.eclipse.viatra.dse.objectives.IObjective;
+import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;
+import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRule;
+
+/**
+ * This soft objective calculates a fitness value based on the length of the trajectory. Costs to the rules can be
+ * assigned.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class TrajectoryCostSoftObjective extends BaseObjective {
+
+ public static final String DEFAULT_NAME = "TrajectoryCostObjective";
+ protected Map, Double> fixCosts;
+ protected Map, ActivationFitnessProcessor> activationCostProcessors;
+ protected double trajectoryLengthWeight = 0.0;
+ protected boolean calculateTrajectoryLengthWeight;
+
+ public TrajectoryCostSoftObjective(String name) {
+ super(name);
+ comparator = Comparators.LOWER_IS_BETTER;
+ }
+
+ public TrajectoryCostSoftObjective() {
+ this(DEFAULT_NAME);
+ }
+
+ /**
+ * Sets the cost of a rule.
+ *
+ * @param rule
+ * @param cost
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public TrajectoryCostSoftObjective withRuleCost(BatchTransformationRule, ?> rule, double cost) {
+ Objects.requireNonNull(rule);
+ if (fixCosts == null) {
+ fixCosts = new HashMap, Double>();
+ }
+ Preconditions.checkArgument(!fixCosts.containsKey(rule));
+ fixCosts.put(rule, cost);
+ return this;
+ }
+
+ /**
+ * Sets an activation processor for a rule.
+ *
+ * @param rule
+ * @param activationCostProcessor
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public TrajectoryCostSoftObjective withActivationCost(BatchTransformationRule, ?> rule,
+ ActivationFitnessProcessor activationCostProcessor) {
+ Objects.requireNonNull(rule);
+ Objects.requireNonNull(activationCostProcessor);
+ if (activationCostProcessors == null) {
+ activationCostProcessors = new HashMap, ActivationFitnessProcessor>();
+ }
+ Preconditions.checkArgument(!activationCostProcessors.containsKey(rule));
+ activationCostProcessors.put(rule, activationCostProcessor);
+ return this;
+ }
+
+ /**
+ * The length of the trajectory multiplied with given parameter will be added to the fitness value.
+ *
+ * @param trajectoryLengthWeight
+ * The weight of a transformation rule application.
+ * @return The actual instance to enable builder pattern like usage.
+ */
+ public TrajectoryCostSoftObjective withTrajectoryLengthWeight(double trajectoryLengthWeight) {
+ this.trajectoryLengthWeight = trajectoryLengthWeight;
+ this.calculateTrajectoryLengthWeight = true;
+ return this;
+ }
+
+ @Override
+ public Double getFitness(ThreadContext context) {
+
+ DesignSpaceManager dsm = context.getDesignSpaceManager();
+ TrajectoryInfo trajectoryInfo = dsm.getTrajectoryInfo();
+ List trajectory = trajectoryInfo.getTrajectory();
+ List> rules = trajectoryInfo.getRules();
+
+ double result = 0;
+
+ for (int i = 0; i < trajectory.size(); i++) {
+ BatchTransformationRule, ?> rule = rules.get(i);
+
+ Double cost = fixCosts.get(rule);
+ if (cost != null) {
+ result += cost;
+ }
+
+ Map costs = trajectoryInfo.getMeasuredCosts().get(i);
+ if (costs != null) {
+ cost = costs.get(name);
+ if (cost != null) {
+ result += cost;
+ }
+ }
+ }
+
+ if (calculateTrajectoryLengthWeight) {
+ result += trajectory.size() * trajectoryLengthWeight;
+ }
+
+ return result;
+ }
+
+ @Override
+ public void init(ThreadContext context) {
+ super.init(context);
+ DesignSpaceManager dsm = context.getDesignSpaceManager();
+ if (activationCostProcessors != null) {
+ for (Entry, ActivationFitnessProcessor> entry : activationCostProcessors.entrySet()) {
+ dsm.registerActivationCostProcessor(name, entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ @Override
+ public IObjective createNew() {
+ return this;
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java
new file mode 100644
index 00000000..8d74e856
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionFoundHandler.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.solutionstore.SolutionStore.ISolutionSaver;
+
+/**
+ * Contains callback methods which are called when a solution is found by the exploration {@link IStrategy}.
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface ISolutionFoundHandler {
+
+ /**
+ * Called when a solution is saved by the {@link ISolutionSaver}. Later, this solution can be omitted from the final
+ * set of solutions.
+ *
+ * @param context
+ * @param trajectory
+ */
+ void solutionFound(ThreadContext context, SolutionTrajectory trajectory);
+
+ /**
+ * Called when the exploration found a solution but it was not saved because of certain conditions.
+ *
+ * @param context
+ * @param trajectory
+ */
+ void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory);
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java
new file mode 100644
index 00000000..36e6b5b7
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ISolutionNameProvider.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+/**
+ * Provides file name when a model is searialzed.
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface ISolutionNameProvider {
+ String getName();
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java
new file mode 100644
index 00000000..43460015
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/IdBasedSolutionNameProvider.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+/**
+ * Provides file name with a String [prefix][id].[extension]
pattern.
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class IdBasedSolutionNameProvider implements ISolutionNameProvider {
+
+ private int id = 1;
+ private String prefix;
+ private String extension;
+
+ public IdBasedSolutionNameProvider(String prefix, String extension) {
+ this.extension = extension;
+ this.prefix = prefix;
+
+ }
+
+ @Override
+ public String getName() {
+ StringBuilder sb = new StringBuilder(prefix);
+ sb.append(id++);
+ sb.append('.');
+ sb.append(extension);
+ return sb.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java
new file mode 100644
index 00000000..118f0c75
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/LogSolutionHandler.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+import org.apache.log4j.Logger;
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.base.ThreadContext;
+
+public class LogSolutionHandler implements ISolutionFoundHandler {
+
+ Logger logger = Logger.getLogger(LogSolutionHandler.class);
+
+ @Override
+ public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) {
+ logger.info("Solution registered: " + trajectory.toPrettyString());
+ }
+
+ @Override
+ public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) {
+ logger.debug("Not good enough solution: " + trajectory.toPrettyString());
+ }
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java
new file mode 100644
index 00000000..bbbe60de
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/ModelSaverSolutionFoundHandler.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2017, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+import java.util.HashSet;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.util.EMFHelper;
+
+public class ModelSaverSolutionFoundHandler implements ISolutionFoundHandler {
+
+ private HashSet savedSolutions = new HashSet();
+ private ISolutionNameProvider solutionNameProvider;
+
+ public ModelSaverSolutionFoundHandler() {
+ solutionNameProvider = new IdBasedSolutionNameProvider("solution", "xmi");
+ }
+
+ public ModelSaverSolutionFoundHandler(String extension) {
+ solutionNameProvider = new IdBasedSolutionNameProvider("solution", extension);
+ }
+
+ public ModelSaverSolutionFoundHandler(String prefix, String extension) {
+ solutionNameProvider = new IdBasedSolutionNameProvider(prefix, extension);
+ }
+
+ public ModelSaverSolutionFoundHandler(ISolutionNameProvider solutionNameProvider) {
+ this.solutionNameProvider = solutionNameProvider;
+ }
+
+ @Override
+ public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) {
+ }
+
+ @Override
+ public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) {
+ Object stateCode = trajectory.getSolution().getStateCode();
+
+ if (savedSolutions.contains(stateCode)) {
+ return;
+ }
+
+ savedSolutions.add(stateCode);
+ Notifier clonedModel = EMFHelper.clone(context.getModel());
+ EMFHelper.saveModel(clonedModel, solutionNameProvider.getName());
+ }
+}
\ No newline at end of file
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java
new file mode 100644
index 00000000..578ae277
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/solutionstore/SolutionStore.java
@@ -0,0 +1,311 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.solutionstore;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.dse.api.Solution;
+import org.eclipse.viatra.dse.api.SolutionTrajectory;
+import org.eclipse.viatra.dse.base.DesignSpaceManager;
+import org.eclipse.viatra.dse.base.ThreadContext;
+import org.eclipse.viatra.dse.objectives.Fitness;
+import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper;
+import org.eclipse.viatra.dse.statecode.IStateCoderFactory;
+import org.eclipse.viatra.dse.util.EMFHelper;
+import org.eclipse.viatra.query.runtime.exception.ViatraQueryException;
+
+/**
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public class SolutionStore {
+
+ public interface ISolutionSaver {
+ void setSolutionsCollection(Map solutions);
+ boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory);
+ }
+
+ public interface IEnoughSolutions extends ISolutionFoundHandler {
+ boolean enoughSolutions();
+ }
+
+ public static class ANumberOfEnoughSolutions implements IEnoughSolutions {
+
+ private final AtomicInteger foundSolutions;
+ private final AtomicBoolean foundEnoughSolutions;
+
+ public ANumberOfEnoughSolutions(int number) {
+ foundSolutions = new AtomicInteger(number);
+ foundEnoughSolutions = new AtomicBoolean(false);
+ }
+
+ @Override
+ public boolean enoughSolutions() {
+ return foundEnoughSolutions.get();
+ }
+
+ @Override
+ public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) {
+ int solutionsToFind = foundSolutions.decrementAndGet();
+ if (solutionsToFind == 0) {
+ foundEnoughSolutions.set(true);
+ }
+ }
+
+ @Override
+ public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) {
+ }
+ }
+
+ public static class SimpleSolutionSaver implements ISolutionSaver {
+
+ private Map solutions;
+
+ @Override
+ public void setSolutionsCollection(Map solutions) {
+ this.solutions = solutions;
+ }
+
+ @Override
+ public boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) {
+ Solution solution = solutions.get(id);
+ if (solution != null) {
+ if (solution.getTrajectories().contains(solutionTrajectory)) {
+ return false;
+ } else {
+ solution.addTrajectory(solutionTrajectory);
+ solutionTrajectory.setSolution(solution);
+ }
+ } else {
+ solution = new Solution(id, solutionTrajectory);
+ solutions.put(id, solution);
+ solutionTrajectory.setSolution(solution);
+ }
+ return true;
+ }
+ }
+
+ public static class BestSolutionSaver implements ISolutionSaver {
+
+ private Map solutions;
+ private Map trajectories = new HashMap<>();
+
+ @Override
+ public void setSolutionsCollection(Map solutions) {
+ this.solutions = solutions;
+ }
+
+ @Override
+ public boolean saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) {
+
+ Fitness lastFitness = context.getLastFitness();
+ ObjectiveComparatorHelper comparatorHelper = context.getObjectiveComparatorHelper();
+
+ List dominatedTrajectories = new ArrayList<>();
+
+ for (Entry entry : trajectories.entrySet()) {
+ int isLastFitnessBetter = comparatorHelper.compare(lastFitness, entry.getValue());
+ if (isLastFitnessBetter < 0) {
+ return false;
+ }
+ if (isLastFitnessBetter > 0) {
+ dominatedTrajectories.add(entry.getKey());
+ }
+ }
+
+ boolean solutionSaved = false;
+
+ Solution solution = solutions.get(id);
+ if (solution != null) {
+ if (!solution.getTrajectories().contains(solutionTrajectory)) {
+ solution.addTrajectory(solutionTrajectory);
+ solutionTrajectory.setSolution(solution);
+ solutionSaved = true;
+ trajectories.put(solutionTrajectory, lastFitness);
+ }
+ } else {
+ solution = new Solution(id, solutionTrajectory);
+ solutions.put(id, solution);
+ solutionTrajectory.setSolution(solution);
+ solutionSaved = true;
+ trajectories.put(solutionTrajectory, lastFitness);
+ }
+
+ for (SolutionTrajectory st : dominatedTrajectories) {
+ trajectories.remove(st);
+ Solution s = st.getSolution();
+ if (!s.getTrajectories().remove(st)) {
+ throw new DSEException("Should not happen.");
+ }
+ if (s.getTrajectories().isEmpty()) {
+ Object stateCode = s.getStateCode();
+ solutions.remove(stateCode);
+ }
+ }
+
+ return solutionSaved;
+ }
+
+ }
+
+ protected boolean acceptOnlyGoalSolutions = true;
+ protected final Map solutions = new HashMap();
+ protected ISolutionSaver solutionSaver = new SimpleSolutionSaver();
+ protected List solutionFoundHandlers = new ArrayList(1);
+
+ protected final IEnoughSolutions enoughSolutions;
+
+ public SolutionStore() {
+ this(new IEnoughSolutions() {
+ @Override
+ public void solutionFound(ThreadContext context, SolutionTrajectory trajectory) {
+ }
+
+ @Override
+ public boolean enoughSolutions() {
+ return false;
+ }
+
+ @Override
+ public void solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) {
+ }
+ });
+ }
+
+ public SolutionStore(int numOfSolutionsToFind) {
+ this(new ANumberOfEnoughSolutions(numOfSolutionsToFind));
+ }
+
+ public SolutionStore(IEnoughSolutions enoughSolutionsImpl) {
+ enoughSolutions = enoughSolutionsImpl;
+ }
+
+ public synchronized void newSolution(ThreadContext context) {
+ solutionSaver.setSolutionsCollection(solutions);
+ Fitness fitness = context.getLastFitness();
+ DesignSpaceManager dsm = context.getDesignSpaceManager();
+ Object id = dsm.getCurrentState();
+ IStateCoderFactory stateCoderFactory = context.getGlobalContext().getStateCoderFactory();
+ SolutionTrajectory solutionTrajectory = dsm.getTrajectoryInfo().createSolutionTrajectory(stateCoderFactory, context.getDesignSpaceManager());
+ solutionTrajectory.setFitness(fitness);
+
+ if (acceptOnlyGoalSolutions && !fitness.isSatisifiesHardObjectives()) {
+ unsavedSolutionCallbacks(context, solutionTrajectory);
+ return;
+ }
+
+ boolean solutionSaved = solutionSaver.saveSolution(context, id, solutionTrajectory);
+
+ if (solutionSaved) {
+ enoughSolutions.solutionFound(context, solutionTrajectory);
+
+ savedSolutionCallbacks(context, solutionTrajectory);
+
+ if (enoughSolutions.enoughSolutions()) {
+ context.getGlobalContext().stopAllThreads();
+ }
+ } else {
+ unsavedSolutionCallbacks(context, solutionTrajectory);
+ }
+ }
+
+ private void unsavedSolutionCallbacks(ThreadContext context, SolutionTrajectory solutionTrajectory) {
+ for (ISolutionFoundHandler handler : solutionFoundHandlers) {
+ handler.solutionTriedToSave(context, solutionTrajectory);
+ }
+ }
+
+ private void savedSolutionCallbacks(ThreadContext context, SolutionTrajectory solutionTrajectory) {
+ for (ISolutionFoundHandler handler : solutionFoundHandlers) {
+ handler.solutionFound(context, solutionTrajectory);
+ }
+ }
+
+ public synchronized Collection getSolutions() {
+ return solutions.values();
+ }
+
+ public synchronized void registerSolutionFoundHandler(ISolutionFoundHandler handler) {
+ if (solutionFoundHandlers == null) {
+ solutionFoundHandlers = new ArrayList(1);
+ }
+ solutionFoundHandlers.add(handler);
+ }
+
+ public SolutionStore logSolutionsWhenFound() {
+ registerSolutionFoundHandler(new LogSolutionHandler());
+ Logger.getLogger(LogSolutionHandler.class).setLevel(Level.INFO);
+ return this;
+ }
+
+ public SolutionStore saveModelWhenFound() {
+ registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler());
+ return this;
+ }
+
+ public SolutionStore saveModelWhenFound(String extension) {
+ registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(extension));
+ return this;
+ }
+
+ public SolutionStore saveModelWhenFound(String prefix, String extension) {
+ registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(prefix, extension));
+ return this;
+ }
+
+ public SolutionStore saveModelWhenFound(ISolutionNameProvider solutionNameProvider) {
+ registerSolutionFoundHandler(new ModelSaverSolutionFoundHandler(solutionNameProvider));
+ return this;
+ }
+
+ public SolutionStore acceptGoalSolutionsOnly() {
+ acceptOnlyGoalSolutions = true;
+ return this;
+ }
+
+ public SolutionStore acceptAnySolutions() {
+ acceptOnlyGoalSolutions = false;
+ return this;
+ }
+
+ public SolutionStore withSolutionSaver(ISolutionSaver solutionSaver) {
+ this.solutionSaver = solutionSaver;
+ return this;
+ }
+
+ public SolutionStore storeBestSolutionsOnly() {
+ this.solutionSaver = new BestSolutionSaver();
+ return this;
+ }
+
+ public void saveModels(Notifier model, ISolutionNameProvider solutionNameProvider) {
+ try {
+ for (Solution solution : solutions.values()) {
+ SolutionTrajectory trajectory = solution.getArbitraryTrajectory();
+ trajectory.doTransformationUndoable(model);
+ EMFHelper.saveModel(model, solutionNameProvider.getName());
+ trajectory.undoTransformation();
+ }
+ } catch (ViatraQueryException e) {
+ Logger.getLogger(SolutionStore.class).error("Exception happened during model saving.", e);
+ }
+ }
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java
new file mode 100644
index 00000000..f163f1a5
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoder.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.statecode;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.viatra.query.runtime.api.IPatternMatch;
+
+/**
+ *
+ * To be able to efficiently explore a design space, a state that has been explored before through an other trajectory
+ * needs to be recognized and ignored accordingly.
+ *
+ *
+ *
+ * This is done by generating a pseudo-unique value (object) that is only depended on the relevant parts of the model's
+ * internal state, that is, the values of two states can only be equal if the states themselves can be considered equal.
+ *
+ *
+ *
+ * The processing engine however assumes, that any two states that share this pseudo-unique value has the same
+ * characteristics, meaning they have the same amount and type of outgoing transitions available, and firing the
+ * appropriate transitions from both states also result in states that share their pseudo-unique identifier. If this
+ * condition is not satisfied, the exploration process's result will be non-deterministic, and in consequence, solutions
+ * can be lost.
+ *
+ *
+ *
+ * In addition to providing pseudo-unique identifiers to model states, the state coder must provide pseud-unique
+ * identifiers to the outgoing transitions as well, but they only need to be unique on the scope of the particular
+ * state, not globally. Global addressing thus can be achieved by considering the pseudo-unique identifier of the state
+ * and the pseudo-unique identifier of the transition together if needed.
+ *
+ *
+ *
+ * Both identifiers can be arbitrary objects, and equality is checked by calling {@link Object#equals(Object)} on the
+ * two identifiers.
+ *
+ *
+ *
+ * For any particular implementation an {@link IStateCoderFactory} implementation must also be supplied that handles the
+ * creation of {@link IStateCoder} instances.
+ *
+ *
+ *
+ * Usually it is unnecessary to represent everything from the model in a state code, only the parts which are modified
+ * by the transformation rules.
+ *
+ *
+ * @author Miklos Foldenyi, Andras Szabolcs Nagy
+ *
+ */
+public interface IStateCoder {
+
+ /**
+ * Initializes the state coder on the given model.
+ *
+ * @param notifier
+ */
+ void init(Notifier notifier);
+
+ /**
+ * Returns a pseudo-unique identifier that describes the underlying model's current internal state.
+ *
+ * @return an arbitrary {@link Object} that can be used as the identifier.
+ */
+ Object createStateCode();
+
+ /**
+ * Returns a pseudo-unique identifier that describes the given {@link IPatternMatch} in the context of the
+ * underlying model's current internal state.
+ *
+ * @return an arbitrary {@link Object} that can be used as the identifier in the given state.
+ */
+ Object createActivationCode(IPatternMatch match);
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java
new file mode 100644
index 00000000..cf8bdf8d
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecode/IStateCoderFactory.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.statecode;
+
+/**
+ * Interface for a factory class that creates instances of {@link IStateCoder} objects. This is required because state
+ * coders have to be created on-demand if the design space exploration process decides that a new thread is to be
+ * spawned. Since each thread requires it's own working model instance and a state coder is linked to the underlying
+ * model, a new {@link IStateCoder} needs to be created per processing thread.
+ *
+ * @author Miklos Foldenyi, Andras Szabolcs Nagy
+ *
+ */
+public interface IStateCoderFactory {
+
+ /**
+ * Creates a new {@link IStateCoder} instance specific to this {@link IStateCoderFactory}.
+ *
+ * @return the new {@link IStateCoder} instance specific to this working model.
+ */
+ IStateCoder createStateCoder();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java
new file mode 100644
index 00000000..afcba7b6
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProvider.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.statecoding;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * Implementation of this interface is responsible to provide {@link EObject}s of a given {@link EClass} for
+ * {@link TheStateCoder}
+ *
+ * @author Andras Szabolcs Nagy
+ *
+ */
+public interface IObjectsProvider {
+
+ /**
+ * Initialize the {@link IObjectsProvider} on a given model and {@link StatecodingDependencyGraph}.
+ *
+ * @param notifier
+ * The root of the model.
+ * @param statecodingDependencyGraph
+ * The state coding dependency graph.
+ */
+ void init(Notifier notifier, StatecodingDependencyGraph statecodingDependencyGraph);
+
+ /**
+ * Returns the instances of an {@link EClass} in a model.
+ *
+ * @param eClass
+ * The class of the objects.
+ * @return The collection of the instances.
+ */
+ Collection getEObjects(EClass eClass);
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java
new file mode 100644
index 00000000..931eb1a2
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IObjectsProviderFactory.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.statecoding;
+
+/**
+ * Interface for creating {@link IObjectsProvider} instances.
+ *
+ * @author Andras Szabolcs Nagy
+ */
+public interface IObjectsProviderFactory {
+
+ /**
+ * Creates an {@link IObjectsProvider} implementation.
+ *
+ * @return The newly created {@link IObjectsProvider}.
+ */
+ IObjectsProvider createObjectsProvider();
+
+}
diff --git a/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java
new file mode 100644
index 00000000..e38d45d3
--- /dev/null
+++ b/Solvers/VIATRA-Solver/org.eclipse.viatra.dse/src/org/eclipse/viatra/dse/statecoding/IncrementalObjectProvider.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2015, Andras Szabolcs Nagy and Daniel Varro
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-v20.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.viatra.dse.statecoding;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.viatra.dse.api.DSEException;
+import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
+import org.eclipse.viatra.query.runtime.base.api.IndexingLevel;
+import org.eclipse.viatra.query.runtime.base.api.NavigationHelper;
+import org.eclipse.viatra.query.runtime.emf.EMFScope;
+import org.eclipse.viatra.query.runtime.exception.ViatraQueryException;
+
+public class IncrementalObjectProvider implements IObjectsProvider {
+
+ private Logger logger = Logger.getLogger(getClass());
+ private NavigationHelper baseIndex;
+
+ @Override
+ public void init(Notifier notifier, StatecodingDependencyGraph statecodingDependencyGraph) {
+
+ try {
+ EMFScope scope = new EMFScope(notifier);
+ ViatraQueryEngine queryEngine = ViatraQueryEngine.on(scope);
+
+ Set