APE as a Java Library

Run APE from a Java environment

Like the CLI, the APE API relies on a configuration file or object that references the domain ontology, tool annotations, workflow specification and execution parameters. All the parameters can either be set by a JSONObject/JSON file or be set programmatically.

APE API functions

Environment Setup

Setup the APE framework with a JSON file or provide the required information programmatically:

 // JSON
APE framework1 = new APE("path/to/setup-configuration.json");

 // programmatically
APECoreConfig config = new APECoreConfig(
      new File("GeoGMT/GMT_UseCase_taxonomy.owl"),
      "http://www.co-ode.org/ontologies/ont.owl#",
      "ToolsTaxonomy",
      Arrays.asList("TypesTaxonomy"),
      new File("GeoGMT/tool_annotations.json")
);

APE framework2 = new APE(config);

Domain information retreval

After setting up the environment, APE will process the domain data (Taxonomies and Tool annotations). This includes creating object that correspond to tool and data terms provided, with the corresponding subclass relations. In addition, the library will filter out the terms that are not used in the domain (e.g. data formats that cannot be used nor generated by any of the tools), and thus trimming the ontology.

APE provides a domain model object that contains all the mentioned information.

// get domain setup from the APE object
APEDomainSetup domainSetup = framework.getDomainSetup();

APEDomainSetup provides all the available information regarding: 1. The annotated tools and their structure. The user can fetch the root of the tool taxonomy and extract the whole ontology structure recursivlty (using the getSubPredicates() method) , or simply retreive a single tool annotation.

//get the root operation and its subclasses
TaxonomyPredicate rootOperation = domainOperations.getRootModule();
Set<TaxonomyPredicate> subOperations = rootOperation.getSubPredicates();

// get a specific tool from the domain
AbstractModule operation = domainOperations.get("operationID");
List<Type> inputs = operation.getModuleInput();
List<Type> outputs = operation.getModuleOutput();
  1. Structure of the domain types, for each of the dimensions.

AllTypes domainTypes = domainSetup.getAllTypes();
// get all dimensions in the domain
List<TaxonomyPredicate> dataDimensionRoots = domainTypes.getRootPredicates();

for(TaxonomyPredicate dataDimensionRoot : dataDimensionRoots) {
        // print dimension in human readable format
        System.out.println("Processing data dimension: " + dataDimensionRoot.getPredicateLabel());
        Set<TaxonomyPredicate> subDataTypes = dataDimensionRoot.getSubPredicates();
}

Run Specifications Setup

After setting up the framework, create a Run configuration with a JSON file or provide the required information programmatically:

// JSON
APERunConfig runConfig1 = new APERunConfig("path/to/run-configuration.json");

// programmatically
APERunConfig runConfig2 = APERunConfig.builder()
                            .withSolutionMinLength(1)
                            .withSolutionMaxLength(10)
                            .withMaxNoSolutions(100)
                            .withApeDomainSetup(framework.getDomainSetup())
                            .build();

Run the Synthesis

APE framework = new APE( .. );
APERunConfig runConfig = .. ;

SATsolutionsList solutions = framework.runSynthesis(runConfig);

// write the solutions to the file system
APE.writeSolutionToFile(solutions); // write solutions to ./sat_solutions.txt
APE.writeDataFlowGraphs(solutions, Rank.RankDir.TOP_TO_BOTTOM); // save images to ./Figures/
APE.writeExecutableWorkflows(solutions); // save scripts to ./Executables/

The API allows to generate and edit the configuration file programmatically between runs:

// set up the framework
APE framework = new APE( .. );
APERunConfig runConfig = .. ;

// run the synthesis
SATsolutionsList solutions1 = framework.runSynthesis(runConfig);

// run the synthesis again with altered parameters
runConfig.setUseWorkflowInput(ConfigEnum.ONE);
SATsolutionsList solutions2 = ape.runSynthesis(runConfig);

SATsolutionsList

Functions to retrieve data (that can be visualized).

  • SATsolutionsList: The solution set retrieved from the synthesis execution.

    • int getNumberOfSolutions() Amount of solutions.

    • SolutionWorkflow get(int index) Get solution i.

  • SolutionWorkFlow: One solution workflow.

    • int getSolutionlength() The length of the solution.

    • List<ModuleNode> getModuleNodes() The tools represented in the workflow.

    • List<TypeNode> getWorkflowInputTypeStates() Data instances used as input of the workflow.

    • List<TypeNode> getWorkflowOutputTypeStates() Data instances representing the output of the workflow.

  • ModuleNode: contains information about a tool in a workflow.

    • String getNodeID() The ID of the tool.

    • String getNodeLabel() The name of the tool.

    • boolean hasNextModule() The output of this tool is used as input for another tool (outgoing arrow).

    • ModuleNode getNextModuleNode() Get the next tool.

    • boolean hasPrevModule() The input of this tool was the output of another tool (incoming arrow).

    • ModuleNode getPrevModuleNode() Get the previous tool.

    • List<TypeNode> getInputTypes() Data instances used as input of the tool.

    • List<TypeNode> getOutputTypes() Data instances used as output of the tool.

  • TypeNode: a data instance

    • String getNodeID() The ID of the data instance.

    • String getShortNodeID() The name of the data instance (e.g. node12345).

    • SortedSet<Type> getTypes() Containing n values for the n-dimensions.

The following example prints a SolutionWorkflow to the console.

/**
* Print SolutionWorkflow to the console
*/
public static void printReadableWorkflowSolution(SolutionWorkflow solution) {
    System.out.println("INPUT:" + inputTypesToString(solution.getWorkflowInputTypeStates()) + "\n");
    // print the first solution
    solution.getModuleNodes().forEach(node -> {
        System.out.printf("Tool %s" +
                        "\n\tInput data: %s" +
                        "\n\tOutput data %s" +
                        "\n\tNext tool: %s" +
                        "\n\tPrevious tool: %s\n\n",
                node.getNodeLabel(),
                inputTypesToString(node.getInputTypes()),
                inputTypesToString(node.getOutputTypes()),
                node.hasNextModule() ? node.getNextModuleNode().getNodeLabel() : "",
                node.hasPrevModule() ? node.getPrevModuleNode().getNodeLabel() : ""
        );
    });

    System.out.println("\nOUTPUT:" + inputTypesToString(solution.getWorkflowOutputTypeStates()));
}

/**
* If a type node is a PNG as well as an Image (2 dimensions) and has id node12345,
* this method returns "(node12345[PNG, Image])"
* SortedSet Type  can be obtained from typeNode.getTypes();
*/
private static String inputTypesToString(List<TypeNode> types){
    return types.stream()
            .map(data -> "(" + data.getShortNodeID() + typeToString(data.getTypes()) + ")")
            .collect(Collectors.toList())
            .toString();
}

/**
* If a data instance is a PNG as well as an Image (2 dimensions),
* this method returns "[PNG, Image]"
* SortedSet Type  can be obtained from typeNode.getTypes();
*/
private static String typeToString(SortedSet<Type> dimensions){
    return dimensions.stream()
            .map(Type::getPredicateLabel)
            .collect(Collectors.toList())
            .toString();
}

APE as a Web plug-in

Note

The following documentation is for APE 1.0.2, which will be released soon. If you cannot wait to get started with this part, use APE-1.0.2_0e3633-executable.jar (30-09-2020) for now, generated from this commit.

Tag information

Tag Types

Tags can have the following type enummerations:

Type

Description

FILE_PATH

A path to a file

FOLDER_PATH

A path to a folder

URI

URI of the ontology file

INTEGER

One integer with boundaries

INTEGER_RANGE

Two integers with boundaries

BOOLEAN

Yes/No, True/False

ENUM

A setting

DATA_DIMENSIONS

Root names of the data dimensions

DATA_INSTANCES

Data instances based on the data dimensions

MODULE

A class from the ontology (in this case a tool)

Info by JSON

Request information about the (run)configuration fields in JSON format. Note that "type" is one of the enummerations mentioned above:

JSONObject tag_info = APERunConfig.TAGS.toJSON();
System.out.println(tag_info.toString(2));

This results in the following (partial) JSON:

{"tags": [
    {
        "default": true,
        "description": "",
        "optional": true,
        "tag": "shared_memory",
        "label": "Use shared memory",
        "type": "BOOLEAN"
    },
    {
        "description": "",
        "optional": false,
        "tag": "max_solutions",
        "label": "Maximum number of solutions",
        "type": "INTEGER",
        "constraints": {
            "min": 0,
            "max": 2147483647
        }
    },
    {
        "default": "ONE",
        "description": "",
        "optional": true,
        "tag": "use_all_generated_data",
        "label": "Use all generated data",
        "type": "ENUM",
        "constraints": {"options": [
            "NONE",
            "ONE",
            "ALL"
        ]}
    }
]}

Info by API

Request information about the (run)configuration fields by calling TAGS statically. This will return a list of Info’s that can be queried. At the moment, constraints.tags returns a JSONObject and can contain the following tags: min, min, options.

for(APEConfigTag.Info<?> tag : APERunConfig.TAGS.getAll()){

    if(tag.type == APEConfigTag.TagType.INTEGER){
        System.out.printf("`%s` needs a value from %s to %s\n",
                tag.label,
                tag.constraints.getInt("min"),
                tag.constraints.getInt("max")
        );
    }

    else if(tag.type == APEConfigTag.TagType.ENUM){
        JSONArray arr = tag.constraints.getJSONArray("options");
        String[] options = new String[arr.length()];
        for(int i = 0; i < arr.length(); i++){
            options[i] = arr.get(i).toString();
        }
        System.out.printf("`%s` needs a setting from this list: %s\n",
                tag.label,
                Arrays.toString(options)
        );
    }

    else if(tag.type == APEConfigTag.TagType.FILE_PATH){
        System.out.printf("`%s` needs a file.\n", tag.label);
    }
}

Evaluating a configuration object

Use APERunConfig and APECoreConfig statically to check if your configuration file is correct.

In this first example, the number of solutions "-10" is not checked as it is not part of the core configuration setup.

JSONObject config = ..;
config.put("tool_annotations_path", "does/not/exist.json");
config.put("max_solutions", "-10");

ValidationResults results = APECoreConfig.validate(config);
System.out.println("Configuration file is correct: " + results.success());

for(ValidationResult result : results.getFails()){
    System.out.println(result.getTag() + ": " + result.getRuleDescription());
}

To check the run configuration tags, you will need a valid framework instance of APE, because the run configuration setup is based on a valid domain.

JSONObject config = ..;
config.put("max_solutions", "-10");

ValidationResults results = APECoreConfig.validate(config);
System.out.println("Core configuration file is correct: " + results.success());

APE framework = new APE(config);

results = APERunConfig.validate(config, framework.getDomainSetup());
System.out.println("Run configuration file is correct: " + results.success());

for(ValidationResult result : results.getFails()){
    System.out.println(result.getTag() + ": " + result.getRuleDescription());
}

To make things easier, you could also call APE statically to check both the run and core configuration setup.

JSONObject config = ..;
config.put("max_solutions", "-10");

ValidationResults results = APE.validate(config);
System.out.println("Configuration file is correct: " + results.success());

for(ValidationResult result : results.getFails()){
    System.out.println(result.getTag() + ": " + result.getRuleDescription());
}