Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 77 additions & 16 deletions src/main/java/nl/uu/cs/ape/APE.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.SortedSet;
import java.util.*;


import org.json.JSONException;
import org.json.JSONObject;
Expand All @@ -28,6 +27,7 @@
import nl.uu.cs.ape.models.logic.constructs.TaxonomyPredicate;
import nl.uu.cs.ape.solver.SynthesisEngine;
import nl.uu.cs.ape.solver.minisat.SATSynthesisEngine;
import nl.uu.cs.ape.solver.solutionStructure.ModuleNode;
import nl.uu.cs.ape.solver.solutionStructure.SolutionWorkflow;
import nl.uu.cs.ape.solver.solutionStructure.SolutionsList;
import nl.uu.cs.ape.solver.solutionStructure.cwl.DefaultCWLCreator;
Expand Down Expand Up @@ -390,9 +390,10 @@ public static boolean writeSolutionToFile(SolutionsList allSolutions) throws IOE
* solutions and executing them.
*
* @param allSolutions Set of {@link SolutionWorkflow}.
* @param createPartialImplementations Sets whether implementations with missing code shall be created.
* @return true if the execution was successfully performed, false otherwise.
*/
public static boolean writeExecutableWorkflows(SolutionsList allSolutions) {
public static boolean writeExecutableWorkflows(SolutionsList allSolutions, boolean createPartialImplementations) {
Path executionsFolder = allSolutions.getRunConfiguration().getSolutionDirPath2Executables();
Integer noExecutions = allSolutions.getRunConfiguration().getNoExecutions();
if (executionsFolder == null || noExecutions == null || noExecutions == 0 || allSolutions.isEmpty()) {
Expand All @@ -413,9 +414,24 @@ public static boolean writeExecutableWorkflows(SolutionsList allSolutions) {
/* Creating the requested scripts in parallel. */
allSolutions.getParallelStream().filter(solution -> solution.getIndex() < noExecutions).forEach(solution -> {
try {
File script = executionsFolder.resolve(solution.getFileName() + ".sh").toFile();
APEFiles.write2file(solution.getScriptExecution(), script, false);

File script = executionsFolder.resolve(solution.getFileName() + ".sh").toFile();
if (createPartialImplementations) {
APEFiles.write2file(solution.getScriptExecution(), script, false);
} else {
List<String> emptyOperations = new ArrayList<>();
for (ModuleNode operation : solution.getModuleNodes()){
String code = operation.getUsedModule().getExecutionCommand();
if (code == null || code.equals("")) {
emptyOperations.add(String.format("'%s'", operation.getNodeLabel()));
}
}

if (emptyOperations.isEmpty()) {
APEFiles.write2file(solution.getScriptExecution(), script, false);
} else {
log.info("Cannot create {} due to missing code for: {}", script.getAbsolutePath(), String.join(", ", emptyOperations));
}
}
} catch (IOException e) {
log.error("Error occurred while writing an executable (workflow) script to the file system.");
e.printStackTrace();
Expand Down Expand Up @@ -610,9 +626,10 @@ public static boolean writeControlFlowGraphs(SolutionsList allSolutions, RankDir
*
* @param allSolutions Set of {@link SolutionWorkflow} which should be
* represented in CWL.
* @param createPartialImplementations Sets whether implementations with missing code shall be created.
* @return true if the execution was successfully performed, false otherwise.
*/
public static boolean writeCWLWorkflows(SolutionsList allSolutions) {
public static boolean writeCWLWorkflows(SolutionsList allSolutions, boolean createPartialImplementations) {

if (allSolutions.isEmpty()) {
return false;
Expand Down Expand Up @@ -643,8 +660,26 @@ public static boolean writeCWLWorkflows(SolutionsList allSolutions) {
// Write the cwl file to the file system
String titleCWL = solution.getFileName() + ".cwl";
File script = cwlFolder.resolve(titleCWL).toFile();
DefaultCWLCreator cwlCreator = new DefaultCWLCreator(solution);
APEFiles.write2file(cwlCreator.generate(), script, false);

if (createPartialImplementations) {
DefaultCWLCreator cwlCreator = new DefaultCWLCreator(solution);
APEFiles.write2file(cwlCreator.generate(), script, false);
} else {
List<String> emptyOperations = new ArrayList<>();
for (ModuleNode operation : solution.getModuleNodes()){
String instruction = operation.getUsedModule().getCwlFileReference();
if (instruction == null) {
emptyOperations.add(String.format("'%s'", operation.getNodeLabel()));
}
}

if (emptyOperations.isEmpty()) {
DefaultCWLCreator cwlCreator = new DefaultCWLCreator(solution);
APEFiles.write2file(cwlCreator.generate(), script, false);
} else {
log.info("Cannot create CWL file {} due to missing CWL reference for: {}", script.getAbsolutePath(), String.join(", ", emptyOperations));
}
}

} catch (IOException e) {
log.error("Error occurred while writing a CWL file to the file system.");
Expand All @@ -667,7 +702,16 @@ public static boolean writeCWLWorkflows(SolutionsList allSolutions) {
return true;
}

public static boolean writeSnakemakeWorkflows(SolutionsList allSolutions) {
/**
* Generate Snakemake scripts that represent executable versions of the workflows
* solutions.
*
* @param allSolutions Set of {@link SolutionWorkflow} which should be
* represented in Snakemake.
* @param createPartialImplementations Sets whether implementations with missing code shall be created.
* @return true if the execution was successfully performed, false otherwise.
*/
public static boolean writeSnakemakeWorkflows(SolutionsList allSolutions, boolean createPartialImplementations) {
if (allSolutions.isEmpty()) {
return false;
}
Expand All @@ -693,11 +737,28 @@ public static boolean writeSnakemakeWorkflows(SolutionsList allSolutions) {

allSolutions.getParallelStream().filter(solution -> solution.getIndex() < noSnakemakeFiles).forEach(solution -> {
try {
String titleSnakefile= solution.getFileName() + "_snakefile";
File script = snakemakeFolder.resolve(titleSnakefile).toFile();
SnakemakeCreator snakemakeCreator = new SnakemakeCreator(solution);
APEFiles.write2file(snakemakeCreator.generateSnakemakeRepresentation(), script, false);

String titleSnakefile = solution.getFileName() + "_snakefile";
File script = snakemakeFolder.resolve(titleSnakefile).toFile();

if (createPartialImplementations) {
SnakemakeCreator snakemakeCreator = new SnakemakeCreator(solution);
APEFiles.write2file(snakemakeCreator.generateSnakemakeRepresentation(), script, false);
} else {
List<String> emptyOperations = new ArrayList<>();
for (ModuleNode operation : solution.getModuleNodes()){
String code = operation.getUsedModule().getExecutionCommand();
if (code == null || code.equals("")) {
emptyOperations.add(String.format("'%s'", operation.getNodeLabel()));
}
}

if (emptyOperations.isEmpty()) {
SnakemakeCreator snakemakeCreator = new SnakemakeCreator(solution);
APEFiles.write2file(snakemakeCreator.generateSnakemakeRepresentation(), script, false);
} else {
log.info("Cannot create Snakemake file {} due to missing code for: {}", script.getAbsolutePath(), String.join(", ", emptyOperations));
}
}
} catch (IOException e) {
log.error("Error occurred while writing a Snakemake file to the file system.");
e.printStackTrace();
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/nl/uu/cs/ape/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ public static void executeSynthesis(String[] args) {
log.info("The problem is UNSAT.");
} else {
try {
boolean createPartialImplementations = solutions.getRunConfiguration().getCreatePartialScripts();
APE.writeSolutionToFile(solutions);
// The following method can be changed to write the solutions in different
// formats (e.g., control flow graph, data flow graph)
APE.writeTavernaDesignGraphs(solutions);
APE.writeExecutableWorkflows(solutions);
APE.writeCWLWorkflows(solutions);
APE.writeSnakemakeWorkflows(solutions);
APE.writeExecutableWorkflows(solutions, createPartialImplementations);
APE.writeCWLWorkflows(solutions, createPartialImplementations);
APE.writeSnakemakeWorkflows(solutions, createPartialImplementations);
} catch (IOException e) {
log.error("Error in writing the solutions. to the file system.");
e.printStackTrace();
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/nl/uu/cs/ape/configuration/APERunConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public class APERunConfig {
* Path to the directory that will contain all the solutions to the problem.
*/
private final APEConfigTag<Path> SOLUTION_DIR_PATH = new APEConfigTagFactory.TAGS.SOLUTION_DIR_PATH();
/**
* Mode is true if partial shell scripts are generated.
*/
private final APEConfigTag<Boolean> CREATE_PARTIAL_SCRIPTS = new APEConfigTagFactory.TAGS.CREATE_PARTIAL_SCRIPTS();
/**
* Min and Max possible length of the solutions (length of the automaton). For
* no upper limit, max length should be set to 0.
Expand Down Expand Up @@ -119,6 +123,7 @@ public class APERunConfig {
this.CONSTRAINTS_FILE,
this.CONSTRAINTS_CONTENT,
this.SOLUTION_DIR_PATH,
this.CREATE_PARTIAL_SCRIPTS,
this.SOLUTION_LENGTH_RANGE,
this.NO_SOLUTIONS,
this.NO_EXECUTIONS,
Expand All @@ -142,6 +147,7 @@ public class APERunConfig {
new CONSTRAINTS_FILE(),
new CONSTRAINTS_CONTENT(),
new SOLUTION_DIR_PATH(),
new CREATE_PARTIAL_SCRIPTS(),
new SOLUTION_LENGTH_RANGE(),
new NO_SOLUTIONS(),
new NO_EXECUTIONS(),
Expand Down Expand Up @@ -183,6 +189,7 @@ private APERunConfig(Builder builder) {
setMaxNoSolutions(builder.maxNoSolutions);
setToolSeqRepeat(builder.toolSeqRepeat);
setSolutionPath(builder.solutionDirPath);
setCreatePartialScrips(builder.createPartialScripts);
setNoExecutions(builder.noExecutions);
setNoGraphs(builder.noGraphs);
setNoCWL(builder.noCWL);
Expand Down Expand Up @@ -408,6 +415,22 @@ public void setSolutionPath(String solutionPath) {
SOLUTION_DIR_PATH.setValue(Paths.get(solutionPath));
}

/**
* Gets partial script output mode.
*
* @return the value of {@link #CREATE_PARTIAL_SCRIPTS}
*/
public boolean getCreatePartialScripts() {
return CREATE_PARTIAL_SCRIPTS.getValue();
}

/**
* @param createPartialScripts the partial script output mode to set
*/
public void setCreatePartialScrips(boolean createPartialScripts) {
CREATE_PARTIAL_SCRIPTS.setValue(createPartialScripts);
}

/**
* Gets solution min and max length.
*
Expand Down Expand Up @@ -679,6 +702,8 @@ public interface IBuildStage {

IBuildStage withSolutionDirPath(String solutionPath);

IBuildStage withCreatePartialScripts(boolean createPartialScripts);

IBuildStage withNoExecutions(int noExecutions);

IBuildStage withNoGraphs(int noGraphs);
Expand Down Expand Up @@ -712,6 +737,7 @@ public static final class Builder implements ISolutionMinLengthStage, ISolutionM
private JSONArray constraintsJSON;
private boolean toolSeqRepeat;
private String solutionDirPath;
private boolean createPartialScripts;
private int noExecutions;
private int noGraphs;
private int noCWL;
Expand Down Expand Up @@ -767,6 +793,12 @@ public IBuildStage withSolutionDirPath(String solutionDirPath) {
return this;
}

@Override
public IBuildStage withCreatePartialScripts(boolean createPartialScripts) {
this.createPartialScripts = createPartialScripts;
return this;
}

@Override
public IBuildStage withNoExecutions(int noExecutions) {
this.noExecutions = noExecutions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,33 @@ public String getDescription() {
}
}

/**
* Configuration field.
*/
public static class CREATE_PARTIAL_SCRIPTS extends TYPES.Bool {

@Override
public String getTagName() {
return "create_partial_scripts";
}

@Override
public String getLabel() {
return "Create partial script files";
}

@Override
public String getDescription() {
return "Tag to indicate whether partial shell scripts shall be created.";
}

@Override
public APEConfigDefaultValue<Boolean> getDefault() {
return APEConfigDefaultValue.withDefault(true);
}
}


/**
* Configuration field.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,14 @@ private void generateStepOut(ModuleNode moduleNode) {
*/
private void generateDefaultStepRun(ModuleNode moduleNode) {
final int baseInd = 2;
String moduleReference = "add-path-to-the-implementation/" + moduleNode.getUsedModule().getPredicateID()
+ ".cwl ";
String moduleName = moduleNode.getUsedModule().getPredicateID();
String moduleReference = "add-path-to-the-implementation/" + moduleName + ".cwl ";
if (moduleNode.getUsedModule().getCwlFileReference() != null) {
moduleReference = moduleNode.getUsedModule().getCwlFileReference();
} else {
log.info("No CWL reference for {} specified, using fallback reference \"{}\"", moduleName, moduleReference);
}

cwlRepresentation
// Main key
.append(ind(baseInd))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static guru.nidi.graphviz.model.Factory.node;
import static guru.nidi.graphviz.model.Factory.to;

import java.util.Collections;
import java.util.List;

import guru.nidi.graphviz.attribute.Attributes;
Expand Down Expand Up @@ -272,6 +273,12 @@ public static String generateScriptExecution(SolutionWorkflow workflow) {
List<TypeNode> workflowInputs = workflow.getWorkflowInputTypeStates();
List<TypeNode> workflowOutputs = workflow.getWorkflowOutputTypeStates();
List<ModuleNode> moduleNodes = workflow.getModuleNodes();

// Add the generation header
script.append(String.format("# WorkflowNo_%02d\n", workflow.getIndex()+1));
script.append("# This workflow is generated by APE (https://github.com/workflomics/ape).\n");

// Add input parameter check and assignment.
script.append("if [ $# -ne " + workflowInputs.size() + " ]\n\tthen\n");
script
.append("\t\techo \"" + workflowInputs.size()
Expand All @@ -281,10 +288,12 @@ public static String generateScriptExecution(SolutionWorkflow workflow) {
script.append(input.getShortNodeID() + "=$" + (in++) + "\n");
}
script.append("\n");

// Process nodes of the workflow.
for (ModuleNode operation : moduleNodes) {
String code = operation.getUsedModule().getExecutionCommand();
if (code == null || code.equals("")) {
script.append("\"Error. Tool '" + operation.getNodeLabel() + "' is missing the execution code.\"")
script.append("# Error: Tool '" + operation.getNodeLabel() + "' is missing the execution code. Skipping.")
.append("\n");
} else {
for (int i = 0; i < operation.getInputTypes().size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,15 @@ private void generateRuleOutput(ModuleNode moduleNode) {
* @param moduleNode The {@link ModuleNode} corresponding to the rule.
*/
private void generateRuleShell(ModuleNode moduleNode) {
String name = moduleNode.getUsedModule().getPredicateLabel();
String moduleName = moduleNode.getUsedModule().getPredicateLabel();
String command = moduleNode.getUsedModule().getExecutionCommand();
if (command == null || command.equals("")) {
log.info("No command for {} specified, using this name as fallback command \"{}\"", moduleName);
command = moduleName;
}
snakemakeRepresentation
.append(ind(1))
.append(String.format("shell: 'add-path-to-implementation/%s {input} {output}'", name))
.append(String.format("shell: 'add-path-to-implementation/%s {input} {output}'", command))
.append("\n");
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/nl/uu/cs/ape/test/sat/ape/UseCaseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void testUseCase(String name, String evaluationPath)

// Test the generation of CWL files if they should be generated
if (mutation.number_of_cwl_files != 0) {
boolean writingSuccess = APE.writeCWLWorkflows(solutions);
boolean writingSuccess = APE.writeCWLWorkflows(solutions, solutions.getRunConfiguration().getCreatePartialScripts());
assertTrue(writingSuccess);

String cwl_path = config.get("solutions_dir_path").toString();
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/cli/gmt/base_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"ontologyPrefixIRI": "http://www.co-ode.org/ontologies/ont.owl#",
"toolsTaxonomyRoot": "ToolsTaxonomy",
"dataDimensionsTaxonomyRoots": ["TypesTaxonomy"],
"create_partial_scripts": "true",
"solution_length": { "min": 1, "max": 8 },
"solutions": "100",
"number_of_execution_scripts": "3",
Expand Down
Loading