From 2ecd7c2bd758ecf60402ae4c19deae1898714f37 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Thu, 14 Jun 2018 12:51:08 +0200
Subject: [PATCH] Added ACO solution from https://github.com/Ariyanic/TTC18

---
 jastadd-mquat-benchmark/build.gradle          |   1 +
 .../inf/st/mquat/benchmark/SolverFactory.java |   2 +
 .../src/main/resources/scenarios.json         |   3 +-
 jastadd-mquat-solver-aco/.gitignore           |   1 +
 jastadd-mquat-solver-aco/build.gradle         |  17 ++
 .../src/main/java/ir/ac/ui/eng/ACOSolver.java | 282 ++++++++++++++++++
 .../src/main/java/ir/ac/ui/eng/Ant.java       | 161 ++++++++++
 .../src/main/java/ir/ac/ui/eng/LoopBody.java  |  12 +
 .../src/main/java/ir/ac/ui/eng/Parallel.java  |  68 +++++
 .../java/ir/ac/ui/eng/ACOHandwrittenTest.java |  16 +
 .../test/java/ir/ac/ui/eng/ParallelTest.java  |  26 ++
 settings.gradle                               |   1 +
 12 files changed, 589 insertions(+), 1 deletion(-)
 create mode 100644 jastadd-mquat-solver-aco/.gitignore
 create mode 100644 jastadd-mquat-solver-aco/build.gradle
 create mode 100644 jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/ACOSolver.java
 create mode 100644 jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Ant.java
 create mode 100644 jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/LoopBody.java
 create mode 100644 jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Parallel.java
 create mode 100644 jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ACOHandwrittenTest.java
 create mode 100644 jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ParallelTest.java

diff --git a/jastadd-mquat-benchmark/build.gradle b/jastadd-mquat-benchmark/build.gradle
index 7e53177..173dc28 100644
--- a/jastadd-mquat-benchmark/build.gradle
+++ b/jastadd-mquat-benchmark/build.gradle
@@ -12,6 +12,7 @@ repositories {
 dependencies {
     compile project(':jastadd-mquat-base')
     compile project(':jastadd-mquat-solver')
+    compile project(':jastadd-mquat-solver-aco')
     compile project(':jastadd-mquat-solver-ilp')
     compile project(':jastadd-mquat-solver-emfer')
     compile project(':jastadd-mquat-solver-simple')
diff --git a/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java b/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java
index ad4a816..402cad7 100644
--- a/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java
+++ b/jastadd-mquat-benchmark/src/main/java/de/tudresden/inf/st/mquat/benchmark/SolverFactory.java
@@ -4,6 +4,7 @@ import de.tudresden.inf.st.mquat.solving.BenchmarkableSolver;
 import de.tudresden.inf.st.mquat.solving.ilp.ILPDirectSolver;
 import de.tudresden.inf.st.mquat.solving.ilp.ILPExternalSolver;
 import de.tudresden.inf.st.mquat.solving.simple.SimpleSolver;
+import ir.ac.ui.eng.ACOSolver;
 import uniks.EMFeRSolver;
 
 import java.util.Map;
@@ -23,6 +24,7 @@ public class SolverFactory {
   private static Map<String, BenchmarkableSolver> createAvailableSolversIfNeeded() {
     if (availableSolvers == null) {
       availableSolvers = Stream.of(
+          new ACOSolver(),
           new EMFeRSolver(),
           new ILPExternalSolver(),
           new ILPDirectSolver(),
diff --git a/jastadd-mquat-benchmark/src/main/resources/scenarios.json b/jastadd-mquat-benchmark/src/main/resources/scenarios.json
index b6521af..564e51f 100644
--- a/jastadd-mquat-benchmark/src/main/resources/scenarios.json
+++ b/jastadd-mquat-benchmark/src/main/resources/scenarios.json
@@ -2,9 +2,10 @@
   "path": "results",
   "logLevel": "info",
   "solvers": [
+    "aco",
+    "emfer",
     "ilp-direct",
 //    "ilp-external",
-    "emfer",
     "simple"
   ],
   "timeoutValue": 15,
diff --git a/jastadd-mquat-solver-aco/.gitignore b/jastadd-mquat-solver-aco/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/jastadd-mquat-solver-aco/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/jastadd-mquat-solver-aco/build.gradle b/jastadd-mquat-solver-aco/build.gradle
new file mode 100644
index 0000000..2ef5ffb
--- /dev/null
+++ b/jastadd-mquat-solver-aco/build.gradle
@@ -0,0 +1,17 @@
+
+apply plugin: 'java'
+
+sourceCompatibility = 1.8
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testCompile group: 'junit', name: 'junit', version: '4.12'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
+    compile project(':jastadd-mquat-base')
+    compile project(':jastadd-mquat-solver')
+    testCompile project(path: ':jastadd-mquat-solver', configuration: 'testArtifacts')
+}
diff --git a/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/ACOSolver.java b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/ACOSolver.java
new file mode 100644
index 0000000..2de63bd
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/ACOSolver.java
@@ -0,0 +1,282 @@
+package ir.ac.ui.eng;
+
+import de.tudresden.inf.st.mquat.jastadd.model.*;
+import de.tudresden.inf.st.mquat.solving.BenchmarkableSolver;
+import de.tudresden.inf.st.mquat.solving.Solver;
+import de.tudresden.inf.st.mquat.solving.SolverUtils;
+import de.tudresden.inf.st.mquat.solving.SolvingException;
+import de.tudresden.inf.st.mquat.utils.StopWatch;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Samaneh Hoseindoost
+ * @author Meysan Karimi
+ * @author Shekoufeh Kolahdouz-Rahimi
+ * @author Bahman Zamani
+ */
+public class ACOSolver implements BenchmarkableSolver {
+
+  int population_size = 100000;
+  int iteration_size = 20;
+
+  private static final Logger logger = LogManager.getLogger(ACOSolver.class);
+
+  private Solution lastSolution;
+  private long lastSolvingTime;
+
+  private int solutionCounter;
+
+  private long maxSolvingTime;
+  private StopWatch stopWatch;
+
+  private boolean timedOut;
+  int numAssignments = 0;
+
+  public ACOSolver() {
+    this(Long.MAX_VALUE);
+  }
+
+  public ACOSolver(long maxSolvingTime) {
+    this.maxSolvingTime = maxSolvingTime;
+    reset();
+  }
+
+  public Assignment ACOCreateSoftwareAssignment(Request request, Component component, boolean topLevel, int i) {
+    Assignment assignment = new Assignment();
+    assignment.setRequest(request);
+    assignment.setTopLevel(topLevel);
+
+    Implementation implementation = component.getImplementation(i);
+    assignment.setImplementation(implementation);
+
+    for (ComponentRequirement requirement : implementation.getComponentRequirementList()) {
+      for (Instance instance : requirement.getInstanceList()) {
+
+        int rangeMin = 0;
+        int rangeMax = requirement.getComponentRef().getRef().getImplementationList().getNumChild();
+
+        Assignment ass = null;
+        do{
+          int randomNum = ThreadLocalRandom.current().nextInt(rangeMin, rangeMax);
+          ass = ACOCreateSoftwareAssignment(request, requirement.getComponentRef().getRef(), false, randomNum);
+        }while(!ass.isSoftwareValid());
+
+        assignment.addComponentMapping(new ComponentMapping(instance, ass));
+
+      }
+    }
+
+    for (Instance instance : implementation.getResourceRequirement().getInstanceList()) {
+      assignment.setResourceMapping(new ResourceMapping(instance, null, new de.tudresden.inf.st.mquat.jastadd.model.List<>()));
+    }
+
+    return assignment;
+  }
+
+  private static void assignResource(Assignment assignment, Resource resource) {
+    Implementation impl = assignment.getImplementation();
+
+    ResourceMapping mapping = new ResourceMapping(impl.getResourceRequirement().getInstance(0), resource,
+        new de.tudresden.inf.st.mquat.jastadd.model.List<>());
+    SolverUtils.populateResourceMapping(mapping, impl.getResourceRequirement(), resource);
+    assignment.setResourceMapping(mapping);
+  }
+
+  @Override
+  public Solution solve(Root model) throws SolvingException {
+    reset();
+    if (model.getNumRequest() == 0) {
+      return Solution.emptySolutionOf(model);
+    }
+    int numSoftwareSolutions = 0;
+    int numTotalSoftwareSolutions = 0;
+
+    stopWatch = StopWatch.start();
+    List<Solution> solutions = new ArrayList<>();
+    List<Solution> currentSolutions = new ArrayList<>();
+    List<List<Set<Resource>>> currentPossibleResources = new ArrayList<>();
+    List<List<List<Double>>> currentTau = new ArrayList<>(); // Pheromone for each resources
+    List<List<List<Double>>> currentEta = new ArrayList<>(); // Objective for each resources
+    List<List<Double>> currentDenominatorP = new ArrayList<>();
+    List<List<List<Double>>> currentNumeratorP = new ArrayList<>();
+    List<Map<Integer, List<Integer>>> currentSort = new ArrayList<>();
+
+
+    for (int pop = 0; pop < population_size; pop++) {
+
+      System.out.println("pop: " + pop);
+      Solution currentSolution = new Solution();
+      currentSolution.setModel(model);
+      de.tudresden.inf.st.mquat.jastadd.model.List<Request> requests = model.getRequests();
+
+      for(Request request: requests){
+        int rangeMin = 0;
+        int rangeMax = request.getTarget().getRef().getImplementationList().getNumChild();
+        Assignment ass = null;
+        do{
+          int randomNum = ThreadLocalRandom.current().nextInt(rangeMin, rangeMax);
+          ass = ACOCreateSoftwareAssignment(request, request.getTarget().getRef(), true, randomNum);
+        }while(!ass.isSoftwareValid());
+
+        currentSolution.addAssignment(ass);
+      }
+
+      de.tudresden.inf.st.mquat.jastadd.model.List<Resource> resources = model.getHardwareModel().getResources();
+      numTotalSoftwareSolutions++;
+      List<Assignment> assignments = currentSolution.allAssignments();
+      List<Set<Resource>> possibleResources = new ArrayList<>(assignments.size());
+      boolean isHardwareValid = true;
+      double tau0 = 1;
+      List<List<Double>> tau = new ArrayList<>(); // Pheromone for each resources
+      List<List<Double>> eta = new ArrayList<>(); // Objective
+      double alpha = 1;
+      double beta = 1;
+      List<List<Double>> numeratorP = new ArrayList<>(); // soorate Probability
+      List<Double> denominatorP = new ArrayList<>(); // makhraje Probability
+      Map<Integer, List<Integer>> SortIndexByPossibleResource = new HashMap<>();
+
+      int index = 0;
+      for (Assignment assignment : assignments) {
+        Set<Resource> resourceList = new HashSet<>();
+        List<Double> taui = new ArrayList<>();
+        List<Double> etai = new ArrayList<>();
+        List<Double> numeratorPi = new ArrayList<>();
+        double sum = 0;
+        int i = 0;
+        for (Resource resource : resources) {
+          assignResource(assignment, resource);
+          if (assignment.isValid()) {
+            resourceList.add(resource);
+            taui.add(tau0); // Pheromone on antSolution.allAssignments().allResources;
+            etai.add(1 / assignment.computeObjective());
+            numeratorPi.add((taui.get(i) * alpha) + (etai.get(i) * beta));
+            sum += numeratorPi.get(i);
+            i++;
+          }
+        }
+        if(i == 0){
+          isHardwareValid = false;
+          break;
+        }
+        possibleResources.add(resourceList);
+        tau.add(taui);
+        eta.add(etai);
+        numeratorP.add(numeratorPi);
+        denominatorP.add(sum);
+        SortIndexByPossibleResource.computeIfAbsent(i, k -> new ArrayList<>()).add(index);
+        index++;
+      }
+      if(isHardwareValid == true){
+        numSoftwareSolutions++;
+        System.out.println("valid:" + numSoftwareSolutions);
+        Solution clone = currentSolution.deepCopy();
+        currentSolutions.add(clone);
+        currentPossibleResources.add(possibleResources);
+        currentTau.add(tau);
+        currentEta.add(eta);
+        currentNumeratorP.add(numeratorP);
+        currentDenominatorP.add(denominatorP);
+        currentSort.add(SortIndexByPossibleResource);
+      }
+    }
+
+    for (int iteration = 0; iteration < iteration_size; iteration++) {
+      List<Ant> population = new ArrayList<>();
+      for (int i = 0; i < currentSolutions.size(); i++) {
+        Ant ant = new Ant(i, currentSolutions.get(i), currentPossibleResources.get(i), currentEta.get(i), currentSort.get(i), numAssignments);
+        population.add(ant);
+      }
+
+      Parallel.ForEach(population, new LoopBody<Ant>() {
+        @Override
+        public void run(Ant ant) {
+
+          int ant_Number = ant.id;
+          List<List<Double>> tau = currentTau.get(ant_Number);  ///////////// BEFORE RUN
+          List<List<Double>> numeratorP = currentNumeratorP.get(ant_Number);
+          List<Double> denominatorP = currentDenominatorP.get(ant_Number);
+          Solution antSolution = ant.run(tau, numeratorP, denominatorP);		  ////////////  Tau CHANGE AFTER RUN.
+
+          if (antSolution != null) {
+            currentTau.set(ant_Number, tau);		///////////// AFTER RUN
+            currentNumeratorP.set(ant_Number, numeratorP);
+            currentDenominatorP.set(ant_Number, denominatorP);
+            numAssignments += ant.numAssignments;
+            solutionCounter++;
+            if (solutions.isEmpty() || antSolution.computeObjective() < solutions
+                .get(solutions.size() - 1).computeObjective()) {
+              Solution clone = antSolution.deepCopy();
+              solutions.add(clone);
+              logger.info("found a better solution with an objective of {}.",
+                  antSolution.computeObjective());
+            }
+          }
+          ant = null;
+        }
+      });
+      population = null;
+      System.gc();
+    }
+
+    logger.info("Number of total software solutions: {}", numTotalSoftwareSolutions);
+    logger.info("Number of iterated software solutions: {}", numSoftwareSolutions);
+    logger.info("Number of iterated solutions: {}", numAssignments);
+    logger.info("Number of correct solutions: {}", solutionCounter);
+
+    if (solutions.size() > 0) {
+      lastSolution = solutions.get(solutions.size() - 1);
+    } else {
+      lastSolution = Solution.emptySolutionOf(model);
+      logger.warn("Found no solution!");
+    }
+
+    lastSolvingTime = stopWatch.time(TimeUnit.MILLISECONDS);
+
+    return lastSolution;
+
+  }
+
+  private void reset() {
+    this.lastSolution = null;
+    this.solutionCounter = 0;
+    this.lastSolvingTime = 0;
+    this.timedOut = false;
+  }
+
+  @Override
+  public String getName() {
+    return "aco";
+  }
+
+  @Override
+  public long getLastSolvingTime() {
+    return lastSolvingTime;
+  }
+
+  @Override
+  public double getLastObjective() {
+    if (lastSolution != null) {
+      return lastSolution.computeObjective();
+    } else {
+      // TODO throw exception or do something reasonable
+      return 0d;
+    }
+  }
+
+  @Override
+  public Solver setTimeout(long timeoutValue, TimeUnit timeoutUnit) {
+    this.maxSolvingTime = timeoutUnit.toMillis(timeoutValue);
+    return this;
+  }
+
+  @Override
+  public boolean hadTimeout() {
+    return this.timedOut;
+  }
+}
diff --git a/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Ant.java b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Ant.java
new file mode 100644
index 0000000..61e26b9
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Ant.java
@@ -0,0 +1,161 @@
+package ir.ac.ui.eng;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.Stack;
+
+import de.tudresden.inf.st.mquat.jastadd.model.Assignment;
+import de.tudresden.inf.st.mquat.jastadd.model.Implementation;
+import de.tudresden.inf.st.mquat.jastadd.model.Resource;
+import de.tudresden.inf.st.mquat.jastadd.model.ResourceMapping;
+import de.tudresden.inf.st.mquat.jastadd.model.Solution;
+import de.tudresden.inf.st.mquat.solving.SolverUtils;
+
+/**
+ * @author Samaneh Hoseindoost
+ * @author Meysan Karimi
+ * @author Shekoufeh Kolahdouz-Rahimi
+ * @author Bahman Zamani
+ */
+public class Ant {
+
+  int id;
+  Solution currentSolution;
+  List<Set<Resource>> possibleResources;
+  List<List<Double>> eta;
+  Map<Integer, List<Integer>> Sort;
+  int numAssignments;
+
+
+  Ant(int i, Solution solu, List<Set<Resource>> pr, List<List<Double>> et, Map<Integer, List<Integer>> Sr, int a) {
+    id = i;
+    currentSolution = solu;
+    possibleResources = pr;
+    eta = et;
+    Sort = Sr;
+    numAssignments = a;
+  }
+
+  private static void assignResource(Assignment assignment, Resource resource) {
+    Implementation impl = assignment.getImplementation();
+
+    ResourceMapping mapping = new ResourceMapping(impl.getResourceRequirement().getInstance(0), resource,
+        new de.tudresden.inf.st.mquat.jastadd.model.List<>());
+    SolverUtils.populateResourceMapping(mapping, impl.getResourceRequirement(), resource);
+    assignment.setResourceMapping(mapping);
+  }
+
+  public int RoleteWhileSelection(double[] c) {
+
+    double rangeMin = 0.0f;
+    double rangeMax = c[c.length-1];
+    Random r = new Random();
+    double createdRanNum = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
+    int i;
+    for (i = 0; i < c.length-1; i++) {
+      if (createdRanNum <= c[i + 1])
+        break;
+    }
+    return i;
+  }
+
+  public Solution run(List<List<Double>> tau, List<List<Double>> numeratorP, List<Double> denominatorP) {
+
+    List<Assignment> assignments = currentSolution.allAssignments();
+    Stack<Resource> usedResources = new Stack<>();
+    double alpha = 1;
+    double beta = 1;
+    double rho = 0.1; // Evaporation rate
+    double Q = 2;
+
+    List<Integer> keys = new ArrayList<Integer>(Sort.keySet());
+
+    Collections.sort(keys);		// "keys" are number of possible resources
+    // "values" are index of the assignments
+
+    for (Integer key: keys) {
+
+      int siz = Sort.get(key).size();
+
+      for (int i = 0; i < siz; i++) {
+
+        int index = Sort.get(key).get(i);
+
+        Assignment assignment = assignments.get(index);
+
+        List<Resource> resources = new ArrayList<Resource>(possibleResources.get(index));
+/*
+				System.out.print("Ant_" + id + "    ");
+				System.out.print("assignment " + assignment.name() + "    ");
+				System.out.print("possible resources: " + resources.size() + "    ");
+				for (int j = 0; j < resources.size(); j++) {
+					System.out.println("po: " + resources.get(j).getName());
+				}
+*/
+        int remove = 0;
+        for (Iterator<Resource> resIt = resources.iterator(); resIt.hasNext();) {
+          Resource resource = resIt.next();
+          if (usedResources.contains(resource)) {
+            remove++;
+          }
+        }
+        if (resources.size() == remove) {
+          return null;
+        }
+
+        List<Double> numerator = numeratorP.get(index);
+        double denominator = denominatorP.get(index);
+        int size = resources.size();
+        double[] p = new double[size];
+        double[] c = new double[size + 1];
+        c[0] = 0;
+        for(int j=0; j<size; j++ ){
+          p[j] = numerator.get(j)/denominator;
+          c[j + 1] = c[j] + p[j];
+        }
+
+        int select = RoleteWhileSelection(c);
+        Resource resource = resources.get(select);
+
+        while (usedResources.contains(resource)) {
+          select = RoleteWhileSelection(c);
+          resource = resources.get(select);
+        }
+
+//				System.out.println("selected resource: " + resource.getName());
+
+        assignResource(assignment, resource);
+        usedResources.push(resource);
+
+
+        denominatorP.set(index, denominatorP.get(index) - numeratorP.get(index).get(select));
+
+        // tau[index][select] = tau[index][select] + (Q /assignment.computeObjective());
+        // tau[index][select] = (1 - rho) * tau[index][select];
+        List<Double> taui = tau.get(index);
+        // Upadte Pheromone
+        taui.set(select, taui.get(select) + (Q / assignment.computeObjective()));
+        // Evaporation on Pheromone of antSolution.allAssignments();
+        taui.set(select, (1 - rho) * taui.get(select));
+        tau.set(index, taui);
+
+        // p[index][select] = (tau[index][select] * alpha) + (eta[index][select] * beta);
+        List<Double> sIndex = numeratorP.get(index);
+        sIndex.set(select, (tau.get(index).get(select) * alpha) + (eta.get(index).get(select) * beta));
+        numeratorP.set(index, sIndex);
+
+        denominatorP.set(index, denominatorP.get(index) + numeratorP.get(index).get(select));
+
+      }
+    }
+
+    numAssignments++;
+    return currentSolution;
+
+  }
+}
diff --git a/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/LoopBody.java b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/LoopBody.java
new file mode 100644
index 0000000..0afa392
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/LoopBody.java
@@ -0,0 +1,12 @@
+package ir.ac.ui.eng;
+
+/**
+ * @author Samaneh Hoseindoost
+ * @author Meysan Karimi
+ * @author Shekoufeh Kolahdouz-Rahimi
+ * @author Bahman Zamani
+ */
+public interface LoopBody <T>
+{
+  void run(T i);
+}
diff --git a/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Parallel.java b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Parallel.java
new file mode 100644
index 0000000..a6c06c7
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/main/java/ir/ac/ui/eng/Parallel.java
@@ -0,0 +1,68 @@
+package ir.ac.ui.eng;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * @author Samaneh Hoseindoost
+ * @author Meysan Karimi
+ * @author Shekoufeh Kolahdouz-Rahimi
+ * @author Bahman Zamani
+ */
+public class Parallel {
+  static final int iCPU = Runtime.getRuntime().availableProcessors();
+
+  public static <T> void ForEach(Iterable<T> parameters, final LoopBody<T> loopBody) {
+    ExecutorService executor = Executors.newFixedThreadPool(iCPU);
+    List<Future<?>> futures = new LinkedList<Future<?>>();
+
+    for (final T param : parameters) {
+      Future<?> future = executor.submit(new Runnable() {
+        public void run() {
+          loopBody.run(param);
+        }
+      });
+
+      futures.add(future);
+    }
+
+    for (Future<?> f : futures) {
+      try {
+        f.get();
+      } catch (InterruptedException e) {
+      } catch (ExecutionException e) {
+      }
+    }
+
+    executor.shutdown();
+  }
+
+  public static void For(int start, int stop, final LoopBody<Integer> loopBody) {
+    ExecutorService executor = Executors.newFixedThreadPool(iCPU);
+    List<Future<?>> futures = new LinkedList<Future<?>>();
+
+    for (int i = start; i < stop; i++) {
+      final Integer k = i;
+      Future<?> future = executor.submit(new Runnable() {
+        public void run() {
+          loopBody.run(k);
+        }
+      });
+      futures.add(future);
+    }
+
+    for (Future<?> f : futures) {
+      try {
+        f.get();
+      } catch (InterruptedException e) {
+      } catch (ExecutionException e) {
+      }
+    }
+
+    executor.shutdown();
+  }
+}
diff --git a/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ACOHandwrittenTest.java b/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ACOHandwrittenTest.java
new file mode 100644
index 0000000..603967d
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ACOHandwrittenTest.java
@@ -0,0 +1,16 @@
+package ir.ac.ui.eng;
+
+import de.tudresden.inf.st.mquat.solving.HandwrittenTestSuite;
+import de.tudresden.inf.st.mquat.solving.Solver;
+
+/**
+ * Simple test case for ACOSolver.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class ACOHandwrittenTest extends HandwrittenTestSuite {
+  @Override
+  protected Solver getSolver() {
+    return new ACOSolver();
+  }
+}
diff --git a/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ParallelTest.java b/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ParallelTest.java
new file mode 100644
index 0000000..ebdb336
--- /dev/null
+++ b/jastadd-mquat-solver-aco/src/test/java/ir/ac/ui/eng/ParallelTest.java
@@ -0,0 +1,26 @@
+package ir.ac.ui.eng;
+
+/**
+ * @author Samaneh Hoseindoost
+ * @author Meysan Karimi
+ * @author Shekoufeh Kolahdouz-Rahimi
+ * @author Bahman Zamani
+ */
+public class ParallelTest {
+  int k;
+
+  public ParallelTest() {
+    k = 0;
+    Parallel.For(0, 10, new LoopBody<Integer>() {
+      public void run(Integer i) {
+        k += i;
+        System.out.println(i);
+      }
+    });
+    System.out.println("Sum = " + k);
+  }
+
+  public static void main(String[] argv) {
+    ParallelTest test = new ParallelTest();
+  }
+}
diff --git a/settings.gradle b/settings.gradle
index fcba86c..6eb5a59 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -6,4 +6,5 @@ include ':jastadd-mquat-solver'
 include ':jastadd-mquat-solver-ilp'
 include ':jastadd-mquat-solver-emfer'
 include ':jastadd-mquat-solver-simple'
+include 'jastadd-mquat-solver-aco'
 
-- 
GitLab