Install
Install JAR file
You can download the final version of GaSubtle form the GitHub repository in the releases section. If you installed the JAR file you can run it directly, skip to run section.

GaSubtle requires Java SE Runtime Environment (JRE) version 8 in order to run, you can download it from here.

Install source code
If you want to install the source code of GaSubtle you can head to the GitHub repository and click on clone or download then download ZIP.
Download ZIP GitHub Repository
Build
GaSubtle is based on JavaFX and requires Java SE Development Kit (JDK) version 8 in order to be built, you can download it from here . You will also need Apache Maven in order to build the project, you can download it from here. After downloading install the JDK and Maven on your machine and then download the source code from the GitHub repository.
After installing JDK and Maven and downloading the source code, extract the downloaded project ZIP file and using command line locate the source directory. In the project folder execute the following command:
mvn clean install
After the build is done you will find a folder named target under the project installation directory. Inside that folder you will find a JAR file named GaSubtle-${version}.jar.

JavaFX
JavaFX is a set of graphics and media packages that enables developers to design, create, test, debug, and deploy rich client applications that operate consistently across diverse platforms.
Learn moreJDK 8
The Java Platform, Standard Edition 8 Development Kit (JDK 8) is a feature release of the Java SE platform. It contains new features and enhancements in many functional areas.
Learn moreApache Maven
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
Learn moreRun GaSubtle
GaSubtle has two user interfaces, graphical and command line.
Graphical User Interface
The graphical user interface is the default. So in order to run GaSubtle in graphical mode just run the JAR file. To run the JAR file from the command line execute the following command:
java -jar GaSubtle-${version}.jar
After running the tool you will see a splash screen. GaSubtle User Interface is built using JavaFX along with Spring Boot. So at this point, Spring Boot is configuring.

After the tool is done configuring, the main screen will show up. In the main screen there are some options to set up the Genetic Algorithm. The following table describes these options:
Field Name | Mandatory | Description |
---|---|---|
Original File | yes | Path to the original .java file to be executed |
Test Cases Path | yes | Path the directory that contains .class junit test cases |
Mutation Percentage | yes | The percentage of the total population that the algorithm will select using some selection strategy |
Selection Strategy | yes | The selection strategy to be used |
Termination | yes - at least one | The termination condtion for the algorithm |
Repeat | yes | Determines how many times the algorithm should run in case of benchmarking |
After the tool is done running, it will store the results to the same path of the original file specified. The tool will export live and subtle mutants .java files along with an excel sheet report that contains details of each generation.
Caution
Closing the application while the tool is running will stop the algorithm and discard all the results.
Command Line
In order to run GaSubtle in command line mode, open the command line and locate to the directory that contains GaSubtle-${version}.jar. Then execute the following command
java -cp GaSubtle-${version}.jar -Dloader.main=org.hu.hom.ui.cmd.CmdLauncher org.springframework.boot.loader.PropertiesLauncher <args>
Replace <args> with the VM arguments that you want to pass to the tool. The arguments that can be passed are:
Argument | Mandatory | Description |
---|---|---|
-h or --home | No - Default: ${current.path}/GaSubtle-home | Specifies the working home directory. |
-s or --selection-strategy | No - Default: Uses all the selection strategies | Specifies the selection strategy to be used by the genetic algorithm. |
-b or --benchmark | Yes | Specifies the program to be mutated. |
IMPORTANT
The home directory passed to GaSubtle should contain the following directories. There is a working example here.
- benchmark -
this directory name should match the value passed by -b or --benchmark
- original_files
- benchmark.java - the program under execution, the name should match the value passed by -b or --benchmark
- test_set
- test_suite_1.class
- test_suite_2.class ...
- test_suite_n.class
- original_files
- app_config.properties - provides the tool with the genetic algorithm options

Caution
Closing the application while the tool is running will stop the algorithm and discard all the results.
Important Note
GaSubtle can only mutate one class at a time. And the provided class should be in the default package, meaning that the provided java file should NOT start with package foo.boo.some.package;
Invalid class for GaSubtle:
package foo.my.package;
public class SomeClazz {
// a random class
}
Valid class for GaSubtle:
public class SomeClazz {
// a random class
}
For Developers
We tried to make GaSubtle as portable as possible, so using the API can be enough for you to implement your own logic. However, you still can do changes in the core. In this section the technical details will be explained. So if you are not a developer or not familiar with Java you may not be interested in this section.
Prerequisites
To start editing GaSubtle, you will need the following:
Java SE Development Kit 8.
GaSubtle is based on Java 8, so in order to run, compile and build the tool Java SE Development Kit 8 is required.
An IDE.
To edit the code you will need a Java IDE (ex. Eclipse, NetBeans, IntelliJ IDEA). This section will explain the rest of the steps using Eclipse IDE, using another IDE should be the same. Download Eclipse IDE and install it on your machine. Make sure that you installed the JDK before this step.
Project Lombok.
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again. It is used to generate constructors, setter, getters, build methods, etc. using annotations only. Download Project Lombok and run the downloaded file. It will ask you to locate you IDE installation directory. Press install and restart your IDE.
Setup
Make sure you have installed Git on your machine. Then checkout the project from the GitHub repository by executing the following command on the command line:
git clone https://github.com/AbdullahAsendar/GaSubtle.git

After the project is done downloading, open eclipse and press on File > Import > Maven > Existing Maven Projects and navigate to the directory that contains the checked out project.

At this point you are good to go.
API Usage
There is a class called GeneticAlgorithm that is completely customizable, here is an example of customizing the GeneticAlgorithm:
GeneticAlgorithm
.builder()
.mutationPercentage(10) // the mutation percentage
.maxOrder(5) // max order of the HOMs not to be exceeded
.runRepeat(1) // how many time to run the algorithm [for benchmarking]
// stopping conditions, at least one should be provided
.requiredSubtleHoms(1000) // stopping condition: minimum subtle HOMs needed
.maxHoms(1500) // stopping condition: maximum HOMs to generate
.maxGeneration(300) // stopping condition: maximum generation to reach
.timeout(1000) // stopping condition: timeout in seconds
.originalFile("/some/.java/file") // path to the original file
.testCasesPath("/some/.class/test/path") // path to test cases
.resultPath("/some/path") // path to store the results in
.mutantsPath("/some/path") // path to store the mutants in
.evaluation(new EvaluationDefaultImpl())
.crossover(new CrossoverDefaultImpl())
.mutation(new MutationDefaultImpl())
.selection(new TournamentSelection())
.messageListener(new MessageListener() {
@Override
public void info(String value) {
System.out.println("Info message from the GA is: "+ value);
}
@Override
public void error(String value) {
System.out.println("There was an error:" + value);
}
@Override
public void debug(String value) {
System.out.println("Debugging: "+ value);
}
})
.geneticAlgorithmListener((int generation, int populationSize, int liveMutants, int subtleMutants)
-> LOG.info(String.format("Generation [%s] Population [%s] Live Mutants [%s] Subtle Mutants [%s]",
generation, populationSize, liveMutants, subtleMutants)))
.build()
.run();
The GeneticAlgorithm has four main operations, which are Selection, Crossover, Mutation and Evaluation. All these are defined as Interfaces so you can implement your own logic. However, there are default implementations for these interfaces in package org.hu.hom.api.algorithm.object.impl
Selection
At each generation a set of individuals out of the population should be selected in order to do mutation and crossover on these individuals. The selection process is based on the fitness of the individuals, where fitter solutions are more likely to be selected. Some selection strategies measure the fitness of each single one of the individuals and selects the top solutions. Other strategies measure only a sample of the population as the fitness function can be very time-consuming.
Any selection strategy should implement org.hu.hom.api.algorithm.object.SelectionStrategy so it can be passed to the GeneticAlgorithm. There are out of the box selection strategies implemented by GaSubtle, such as: Truncation, Random, Roulette wheel, Stochastic universal sampling and Tournament. All these selection strategies are located in the package org.hu.hom.api.algorithm.object.impl.selection
To create a new selection strategy create a new class that implements the org.hu.hom.api.algorithm.object.SelectionStrategy interface then pass the created class to the GeneticAlgorithm via the method: .selection(SelectionStrategy). Bellow is an example of a custom selection strategy:
public class MySelectionStrategy implements SelectionStrategy<HigherOrderMutant> {
@Override
public List<HigherOrderMutant> select(Population<HigherOrderMutant> population, int selectionSize) {
List<HigherOrderMutant> selectedMutants = Lists.newArrayList();
List<HigherOrderMutant> mutants = Lists.newArrayList(population.getMutants());
// implement your logic here and fill the selectedMutants list
selectedMutants.addAll(mutants.subList(0, selectionSize));
return selectedMutants;
}
}
Crossover
Crossover is done between two selected parents that are combined to create new two offspring. It is typically done by selecting a crossover point and swapping the two chromosomes's genes. This generates new two chromosomes, each carrying some genetic information from both parents.
Crossover should implement org.hu.hom.api.algorithm.object.Crossover so it can be passed to the GeneticAlgorithm. There is a default implementation of crossover in GaSubtle which is org.hu.hom.api.algorithm.object.impl.CrossoverDefaultImpl
To create a new crossover create a new class that implements the org.hu.hom.api.algorithm.object.Crossover interface then pass the created class to the GeneticAlgorithm via the method: .crossover(Crossover). Bellow is an example of a custom crossover:
public class MyCrossover implements Crossover<HigherOrderMutant> {
@Override
public List<HigherOrderMutant> crossover(HigherOrderMutant firstMutant, HigherOrderMutant secondMutant) {
HigherOrderMutant newMutant_1 = firstMutant.copy();
HigherOrderMutant newMutant_2 = secondMutant.copy();
// do your crossover here
crossover(newMutant_1, newMutant_2);
return Lists.newArrayList(newMutant_1, newMutant_2);
}
private void crossover(HigherOrderMutant firstMutant, HigherOrderMutant secondMutant){
// crossover
}
}
Mutation
Mutation is done to the selected set of individuals by adding or removing a gene. The decision of adding or removing a gene is made randomly. However, if the mutant under mutation is second order then the decision will be to add, that is to make sure that the mutation process will not output a FOM.
Mutation should implement org.hu.hom.api.algorithm.object.Mutation so it can be passed to the GeneticAlgorithm. There is a default implementation of mtation in GaSubtle which is org.hu.hom.api.algorithm.object.impl.MutationDefaultImpl
To create a new mutation create a new class that implements the org.hu.hom.api.algorithm.object.Mutation interface then pass the created class to the GeneticAlgorithm via the method: .mutation(Mutation). Bellow is an example of a custom mutation:
public class MutationDefaultImpl implements Mutation<HigherOrderMutant> {
private static final Random RANDOM = new Random();
@Override
public List<HigherOrderMutant> mutate(List<HigherOrderMutant> mutants) {
List<HigherOrderMutant> newMutants = Lists.newArrayList();
// do mutation and fill newMutants list
return newMutants;
}
private HigherOrderMutant removeAMutation(HigherOrderMutant mutant) {
int index = RANDOM.nextInt(mutant.getFirstOrderMutants().size());
List<FirstOrderMutant> mutatns = Lists.newArrayList(mutant.getFirstOrderMutants());
mutant.removeFirstOrderMutant(mutatns.get(index));
return mutant;
}
private HigherOrderMutant applyRandomMutation(HigherOrderMutant mutant) {
mutant.addFirstOrderMutant(MutationModel.getRandomMutant(mutant));
return mutant;
}
}
Evaluation
Evaluation is used in GaSubtle to provide the Fitness Function, which is a type of objective function used to evaluate a given set of candidate solutions to assign a fitness value for each candidate.
Evaluation should implement org.hu.hom.api.algorithm.object.Evaluation so it can be passed to the GeneticAlgorithm. There is a default implementation of evaluation in GaSubtle which is org.hu.hom.api.algorithm.object.impl.EvaluationDefaultImpl
To create a new evaluation create a new class that implements the org.hu.hom.api.algorithm.object.Evaluation interface then pass the created class to the GeneticAlgorithm via the method: .evaluation(Evaluation). Bellow is an example of a custom evaluation:
public class EvaluationDefaultImpl implements Evaluation<HigherOrderMutant> {
@Override
public List<HigherOrderMutant> evaluate(List<HigherOrderMutant> mutants) {
mutants.stream().forEach(this::setFitness);
return mutants;
}
private void setFitness(HigherOrderMutant mutant) {
mutant.setFitness(getFitnessValue(mutant);
}
private double getFitnessValue(HigherOrderMutant mutant) {
int fitness = 0;
// implement your logic here
return fitness;
}
}