GaSubtle, all rights reserved. 2018 ©

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:

copy
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 more

JDK 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 more

Apache 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 more

Run 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:

copy
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

copy
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.

GaSubtle Home Directory
  • Expand all
  • Collapse all
  • 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
  • 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:

copy
package foo.my.package;

public class SomeClazz  {
    // a random class
}

Valid class for GaSubtle:

copy
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:

copy
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:

copy

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:

copy
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:

copy
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:

copy
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:

copy
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;
    }
}