package solving;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import configuration.ASPSolver;
import configuration.Settings;
import externaltools.ExternalSolver;
import parser.ASTdisplay;
import parser.ASTnonRelAtom;
import parser.ASTpredSymbol;
import parser.ASTprogram;
import parser.SimpleNode;
import querying.parsing.AnswerSets.AnswerSet;
import querying.parsing.AnswerSets.AnswerSetParser;
import querying.parsing.AnswerSets.ClingoAnswerSetParser;
import querying.parsing.AnswerSets.DLVAnswerSetParser;
public class Runner {
/**
* Output answer sets of the SPARC program stored in sparcProgramTree by running the solver instance
* @param sparcProgramTree - AST representing the program
* @param solverInstance - an instance of a solver containing a sparc program
*/
public void outputAnswerSets(SimpleNode sparcProgramTree, ExternalSolver solverInstance) {
String[] displayPredicates = getDisplayPredicates(solverInstance);
HashMap<String,String> mapDisplay = mapDisplayToOrigin(displayPredicates, (ASTprogram)sparcProgramTree);
ArrayList<AnswerSet> answerSets = getAnswerSets(solverInstance);
outputFilteredAnswerSets(answerSets, mapDisplay);
}
/**
* Compute answer sets of the SPARC program stored in sparcProgramTree by running the solver instance
* and store them in a hashset
* @param sparcProgramTree - AST representing the program
* @param solverInstance - an instance of a solver containing a sparcProgramTree
* @return answer sets filtered by the display section in the A
*/
public HashSet<HashSet<String>> computeAnswerSets(SimpleNode sparcProgramTree, ExternalSolver solverInstance) {
String[] displayPredicates = getDisplayPredicates(solverInstance);
HashMap<String,String> mapDisplay = mapDisplayToOrigin(displayPredicates, (ASTprogram)sparcProgramTree);
ArrayList<AnswerSet> answerSets = getAnswerSets(solverInstance);
return filterAnswerSets(answerSets,mapDisplay);
}
/**
* Take the answer sets output by solver, and convert them into the set of answer sets
* @param answerSets - answer sets obtain from the solver
* @param mapDisplayToOrigin - a mapping which maps auxiliary predicates used to their original names
*/
private HashSet<HashSet<String>> filterAnswerSets(ArrayList<AnswerSet> answerSets, HashMap<String, String> mapDisplay) {
HashSet<HashSet<String>> assets = new HashSet<HashSet<String>>();
for(AnswerSet a: answerSets) {
HashSet<String> answerSet = new HashSet<String>();
for (String literal: a.literals) {
String pname = getPredicateName(literal);
if(mapDisplay.containsKey(pname)) {
answerSet.add(setNewName(literal, mapDisplay.get(pname)));
}
}
assets.add(answerSet);
}
return assets;
}
/**
* Fetch the array of predicates that need to be shown in the answer sets
* @param solverInstance (from this we can obtain the translated program, which, in turn, contains
* a comment containing all necessary predicates)
* @return String[] - the array of predicates that need to be shown in the answer sets
*/
private String[] getDisplayPredicates(ExternalSolver solverInstance) {
String program = solverInstance.getProgram();
StringBuilder comment = new StringBuilder();
int index = program.length()-1;
while(program.charAt(index) != '%') {
comment.append(program.charAt(index));
--index;
}
comment.reverse();
String [] displayArray = comment.toString().trim().split("\\s+");
// note, if the display section is empty, we, the split returns an empty string
// which is put into display array as its only element
// we don't want that, we want an empty array instead!!
if(displayArray[0].matches("\\s*")) {
displayArray = new String[0];
}
return displayArray;
}
/**
* Create a map from display predicates to their original names in the program
*
* @param displayP - array of the display predicates
* @param sparcProgramTree - AST of the program which allows us to find the necessary mapping
* @return a map from display predicates to their original names
*/
private HashMap<String, String> mapDisplayToOrigin(String [] displayP, ASTprogram sparcProgramTree) {
HashMap<String,String> mapDisplayToOrigin = new HashMap<String,String>();
ASTdisplay display = (ASTdisplay) sparcProgramTree.jjtGetChild(3);
for(int i = 0; i< displayP.length; i++) {
ASTnonRelAtom atom = (ASTnonRelAtom)display.jjtGetChild(i);
ASTpredSymbol predS = (ASTpredSymbol) atom.jjtGetChild(0);
mapDisplayToOrigin.put(displayP[i], (predS.hasPoundSign()?"#":"") + predS.toString());
}
return mapDisplayToOrigin;
}
/**
* Compute answer sets of a program loaded into a specific solver
* @param solverInstance - a solver instance containing a program
* @return a list of answer sets of the program
*/
private ArrayList<AnswerSet> getAnswerSets(ExternalSolver solverInstance) {
AnswerSetParser aParser = null;
if (Settings.getSolver() == ASPSolver.DLV)
{
aParser = new DLVAnswerSetParser();
}
else
{
aParser = new ClingoAnswerSetParser();
}
return aParser.getAnswerSets(solverInstance.run(true));
}
/**
* Take the answer sets output by solver and convert it to a user-readable (and understable%) format
* using the mapping
* @param answerSets - answer sets obtain from the solver
* @param mapDisplayToOrigin - a mapping which maps auxiliary predicates used to their original names
*/
private void outputFilteredAnswerSets(ArrayList<AnswerSet> answerSets, HashMap<String, String> mapDisplayToOrigin) {
if(!Settings.isLOutputFormat()) {
boolean firstAnswerSet = true;
for(AnswerSet a: answerSets) {
if(!firstAnswerSet)
System.out.println(System.getProperty("line.separator"));
firstAnswerSet = false;
System.out.print("{");
boolean firstLit = true;
for (String literal: a.literals) {
String pname = getPredicateName(literal);
if(mapDisplayToOrigin.containsKey(pname)) {
if(!firstLit) {
System.out.print(", ");
}
firstLit = false;
System.out.print(setNewName(literal, mapDisplayToOrigin.get(pname)));
}
}
System.out.print("}");
}
System.out.print(System.getProperty("line.separator"));
} else {
for(AnswerSet a: answerSets) {
boolean firstLit = true;
for (String literal: a.literals) {
String pname = getPredicateName(literal);
if(mapDisplayToOrigin.containsKey(pname)) {
if(!firstLit) {
System.out.print(" ");
}
firstLit = false;
System.out.print(setNewName(literal, mapDisplayToOrigin.get(pname)));
}
}
System.out.print(System.getProperty("line.separator"));
}
System.out.println(answerSets.isEmpty()?"UNSATISFIABLE":"SATISFIABLE");
}
}
/**
* Given a string representing a literal (e.g, -p(a)), obtain the name of the predicate
* used to form the literal (for -p(a) it is p)
* @param lit - a string representing the literal
* @return the name of the predicate used to form the literal
*
*/
private String getPredicateName(String lit) {
if (lit.startsWith("-")) {
lit = lit.substring(1);
}
StringBuilder predName = new StringBuilder();
int index = 0;
while(index < lit.length() && (Character.isLetter(lit.charAt(index)) ||
Character.isDigit(lit.charAt(index)) || lit.charAt(index) == '_')) {
predName.append(lit.charAt(index));
++index;
}
return predName.toString();
}
/**
* Given a string representing a literal, repace it's predicate with a new one
* @param lit - a string representing a literal
* @param newPredicataName - a new predicate name
* @return - a string representing a new literal, where predicate name of lit is replaced with newPredicataName
*/
private String setNewName(String lit, String newPredicataName) {
StringBuilder newLit = new StringBuilder();
int index = 0;
if(lit.startsWith("-")) {
++index;
newLit.append("-");
}
while(index < lit.length() && (Character.isLetter(lit.charAt(index)) ||
Character.isDigit(lit.charAt(index)) || lit.charAt(index) == '_')) {
++index;
}
newLit.append(newPredicataName);
newLit.append(lit.substring(index));
return newLit.toString();
}
}