Le support aux utilisateurs et les demandes de création de comptes externes doivent être faites depuis les issues du projet GitLab HEFR (https://gitlab.forge.hefr.ch/forge-hefr/gitlab-hefr)

Commit cb839fd4 authored by Tony Licata's avatar Tony Licata
Browse files

Removed use of Java stack to resolve a query, can now run benchmark without...

Removed use of Java stack to resolve a query, can now run benchmark without stackoverflow exception.
Fixed </2 , >=/2 , ... predicates names (were '<'/2, '>='/2, ...)
parent ff7e921e
......@@ -45,7 +45,6 @@ public final class ProloGraalConsultBuiltin extends ProloGraalBuiltinClause {
ProloGraalTerm consultContentTerm = arg.getRootValue();
if(consultContentTerm instanceof ProloGraalAtom){
String filename = ((ProloGraalAtom) consultContentTerm).getName();
filename = filename.substring(1,filename.length()-1);
File loadedFile = new File(filename);
if(loadedFile.exists()) {
String fileContent;
......
......@@ -21,7 +21,7 @@ public final class ProloGraalEqualBuiltin extends ProloGraalBuiltinClause {
// create the head of this clause
// since we do not need custom unification, a simple structure is enough
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "'='"));
head.setFunctor(new ProloGraalAtom(getVariables(), "="));
// we create and store the variables to access them more easily later in the execute method
arg = new ProloGraalVariable(getVariables(), "A");
......
......@@ -21,7 +21,7 @@ public final class ProloGraalGEBuiltin extends ProloGraalBuiltinClause {
// create the head of this clause
// since we do not need custom unification, a simple structure is enough
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "'>='"));
head.setFunctor(new ProloGraalAtom(getVariables(), ">="));
// we create and store the variables to access them more easily later in the execute method
arg = new ProloGraalVariable(getVariables(), "A");
......
......@@ -26,7 +26,7 @@ public final class ProloGraalGTBuiltin extends ProloGraalBuiltinClause {
// create the head of this clause
// since we do not need custom unification, a simple structure is enough
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "'>'"));
head.setFunctor(new ProloGraalAtom(getVariables(), ">"));
// we create and store the variables to access them more easily later in the execute method
arg = new ProloGraalVariable(getVariables(), "A");
......
......@@ -21,7 +21,7 @@ public final class ProloGraalLEBuiltin extends ProloGraalBuiltinClause {
// create the head of this clause
// since we do not need custom unification, a simple structure is enough
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "'=<'"));
head.setFunctor(new ProloGraalAtom(getVariables(), "=<"));
// we create and store the variables to access them more easily later in the execute method
arg = new ProloGraalVariable(getVariables(), "A");
......
......@@ -21,7 +21,7 @@ public final class ProloGraalLTBuiltin extends ProloGraalBuiltinClause {
// create the head of this clause
// since we do not need custom unification, a simple structure is enough
ProloGraalStructure head = new ProloGraalStructure(getVariables());
head.setFunctor(new ProloGraalAtom(getVariables(), "'<'"));
head.setFunctor(new ProloGraalAtom(getVariables(), "<"));
// we create and store the variables to access them more easily later in the execute method
arg = new ProloGraalVariable(getVariables(), "A");
......
......@@ -2,7 +2,6 @@ package ch.heiafr.prolograal.nodes;
import ch.heiafr.prolograal.ProloGraalLanguage;
import ch.heiafr.prolograal.builtins.predicates.ProloGraalBuiltinClause;
import ch.heiafr.prolograal.builtins.predicates.ProloGraalTraceBuiltin;
import ch.heiafr.prolograal.exceptions.ProloGraalExistenceError;
import ch.heiafr.prolograal.runtime.*;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
......@@ -24,9 +23,21 @@ import java.util.stream.IntStream;
public class ProloGraalProofTreeNode extends Node {
private final Map<ProloGraalTerm<?>, List<ProloGraalClause>> clauses; // reference to the context clauses
private final Deque<ProloGraalTerm<?>> goals; // the goals of this node
//Stacks used to simulate a recursive call with a while loop
private final Stack<Deque<Integer>> branchesStack; // the goals of this node
private final Stack<Deque<ProloGraalTerm<?>>> goalsStack; // the goals of this node
private final Stack<Integer> startStack; // used to skip visited branches in case of redo
private final Stack<List<ProloGraalClause>> unifiableClausesStack; // store clauses that can resolve the current goal
private final Stack<ProloGraalTerm<?>> currentGoalStack; // store the current goal
private final boolean traceFlag; // is the trace ON ?
private final int depth; // depth of the node in the proof tree
private enum ExecuteState {
BEGIN,
RUNNING,
RETURN
}
public static final String TRACE_CALL_TEXT = "Call: ";
public static final String TRACE_EXIT_TEXT = "Exit: ";
......@@ -35,11 +46,15 @@ public class ProloGraalProofTreeNode extends Node {
public static final String TRACE_QUESTION_MARK = "?";
public ProloGraalProofTreeNode(Map<ProloGraalTerm<?>, List<ProloGraalClause>> clauses,
Deque<ProloGraalTerm<?>> goals, int depth, boolean traceFlag) {
Deque<ProloGraalTerm<?>> goals, boolean traceFlag) {
this.clauses = clauses;
this.goals = goals;
this.traceFlag = traceFlag;
this.depth = depth;
this.branchesStack = new Stack<>();
this.goalsStack = new Stack<>();
goalsStack.push(goals);
this.startStack = new Stack<>();
this.unifiableClausesStack = new Stack<>();
this.currentGoalStack = new Stack<>();
}
/**
......@@ -55,102 +70,155 @@ public class ProloGraalProofTreeNode extends Node {
*/
@TruffleBoundary
public ProloGraalObject execute(Deque<Integer> branches) throws ProloGraalExistenceError {
ExecuteState executeState = ExecuteState.BEGIN;
ProloGraalObject returnedValue = null;
//using a while loop to simulate a recursive call without using the java stack
while(!goalsStack.isEmpty()){
//switch case used to jump where we stopped if we simulated a new call
//executeState enum is manipulated through the code to simulate this behaviour
switch (executeState) {
case BEGIN:
executeState = ExecuteState.RUNNING;
Deque<ProloGraalTerm<?>> currentGoals = goalsStack.pop();
if (ProloGraalLanguage.DEBUG_MODE) {
System.out.println("ProofTreeNode : " + currentGoals);
}
if (ProloGraalLanguage.DEBUG_MODE) {
System.out.println("ProofTreeNode : " + goals);
}
int start = 0;
if (!branches.isEmpty()) {
// if we're redoing we need to skip to the right branch directly
start = branches.pop();
}
if (goals.isEmpty()) { // leaf node
return new ProloGraalSuccess();
}
ProloGraalTerm<?> currentGoal = goals.peek();
if (traceFlag) {
System.out.println(TRACE_LEFT_WHITE_SPACE + depth + TRACE_LEFT_WHITE_SPACE + (start+1)
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_CALL_TEXT + currentGoal.toString()
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_QUESTION_MARK);
}
int start = 0;
if (!branches.isEmpty()) {
// if we're redoing we need to skip to the right branch directly
start = branches.pop();
}
// get the list of all possible clauses based on the name of the predicate
List<ProloGraalClause> possibleClauses = clauses.get(currentGoal);
if (possibleClauses == null || possibleClauses.isEmpty()) // if no match, throw an error
{
throw new ProloGraalExistenceError(currentGoal);
}
if (currentGoals.isEmpty()) { // leaf node
returnedValue = new ProloGraalSuccess();
executeState = ExecuteState.RETURN;
break;
}
// filter clauses that are unifiable with the current goal, creating copies and saving variables state as needed
List<ProloGraalClause> unifiableClauses =
IntStream.range(0, possibleClauses.size())
.filter(x -> {
ProloGraalClause clause = possibleClauses.get(x).copy();
currentGoal.save();
boolean r = clause.getHead().unify(currentGoal);
currentGoal.undo();
return r;
})
.mapToObj(x -> possibleClauses.get(x).copy()) // create a copy of each filtered clauses
.collect(Collectors.toList());
for (int i = start; i < unifiableClauses.size(); i++) {
// no need to copy here since it is already one
ProloGraalClause unifiableClause = unifiableClauses.get(i);
currentGoal.save();
// unify the head with the current goal
unifiableClause.getHead().unify(currentGoal);
if (ProloGraalLanguage.DEBUG_MODE) {
System.out.println("Unified " + currentGoal + " with " + unifiableClause.getHead());
}
ProloGraalTerm<?> currentGoal = currentGoals.peek();
// only execute built-in the first time we traverse their nodes
if (branches.isEmpty()) {
if (unifiableClause instanceof ProloGraalBuiltinClause) {
// if the clause is a built-in, execute its internal behaviour
if(!((ProloGraalBuiltinClause) unifiableClause).execute().asBoolean()){
return new ProloGraalFailure();
if (traceFlag) {
System.out.println(TRACE_LEFT_WHITE_SPACE + goalsStack.size() + 1 + TRACE_LEFT_WHITE_SPACE + (start + 1)
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_CALL_TEXT + currentGoal.toString()
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_QUESTION_MARK);
}
}
}
// create a copy of the current goals
Deque<ProloGraalTerm<?>> newGoals = new ArrayDeque<>(goals);
// get the list of all possible clauses based on the name of the predicate
List<ProloGraalClause> possibleClauses = clauses.get(currentGoal);
if (possibleClauses == null || possibleClauses.isEmpty()) // if no match, throw an error
{
throw new ProloGraalExistenceError(currentGoal);
}
List<ProloGraalTerm<?>> body = unifiableClause.getGoals();
// copy used for lambda
ProloGraalTerm<?> currentGoalCopy = currentGoal.copy(currentGoal.getVariables());
// filter clauses that are unifiable with the current goal, creating copies and saving variables state as needed
List<ProloGraalClause> unifiableClauses =
IntStream.range(0, possibleClauses.size())
.filter(x -> {
ProloGraalClause clause = possibleClauses.get(x).copy();
currentGoalCopy.save();
boolean r = clause.getHead().unify(currentGoalCopy);
currentGoalCopy.undo();
return r;
})
.mapToObj(x -> possibleClauses.get(x).copy()) // create a copy of each filtered clauses
.collect(Collectors.toList());
//we push everything into their stacks because
//we need to be sure that those variables are initialized with the right value
//when accessing directly to the RETURN case.
currentGoalStack.push(currentGoal);
unifiableClausesStack.push(unifiableClauses);
startStack.push(start);
goalsStack.push(currentGoals);
//we don't break since we want to continue the standard behaviour of the ProofTreeNode
case RETURN:
//retrieve local variables from their stacks
currentGoal = currentGoalStack.pop();
unifiableClauses = unifiableClausesStack.pop();
start = startStack.pop();
currentGoals = goalsStack.pop();
for (int i = start; i < unifiableClauses.size(); i++) {
if(executeState!=ExecuteState.RETURN) {
// no need to copy here since it is already one
ProloGraalClause unifiableClause = unifiableClauses.get(i);
// always remove the first goal since it will be replaced
newGoals.poll();
currentGoal.save();
// no need for distinction between facts and regular clauses
// add all the new goals
Collections.reverse(body);
body.forEach(newGoals::addFirst);
ProloGraalObject result = new ProloGraalProofTreeNode(clauses, newGoals, depth+1, traceFlag).execute(branches);
if (result instanceof ProloGraalBoolean && ((ProloGraalBoolean) result).asBoolean()) {
// skip last possible nodes if empty, or always add if we already have added a path
if (!branches.isEmpty() || i + 1 < unifiableClauses.size()) {
if (branches.isEmpty()) {
i = i + 1; // if we're at the bottom go directly to next node
// unify the head with the current goal
unifiableClause.getHead().unify(currentGoal);
if (ProloGraalLanguage.DEBUG_MODE) {
System.out.println("Unified " + currentGoal + " with " + unifiableClause.getHead());
}
// only execute built-in the first time we traverse their nodes
if (branches.isEmpty()) {
if (unifiableClause instanceof ProloGraalBuiltinClause) {
// if the clause is a built-in, execute its internal behaviour
if (!((ProloGraalBuiltinClause) unifiableClause).execute().asBoolean()) {
//if the builtin don't provide a success, return a failure and break the switch case
returnedValue = new ProloGraalFailure();
executeState = ExecuteState.RETURN;
break;
}
}
}
// create a copy of the current goals
Deque<ProloGraalTerm<?>> newGoals = new ArrayDeque<>(currentGoals);
List<ProloGraalTerm<?>> body = unifiableClause.getGoals();
// always remove the first goal since it will be replaced
newGoals.poll();
// no need for distinction between facts and regular clauses
// add all the new goals
Collections.reverse(body);
body.forEach(newGoals::addFirst);
//push i because when we will pop it, we want to continue the for loop from where it stopped.
startStack.push(i);
currentGoalStack.push(currentGoal);
unifiableClausesStack.push(unifiableClauses);
goalsStack.push(currentGoals);
goalsStack.push(newGoals);
executeState = ExecuteState.BEGIN;
break;
}
executeState = ExecuteState.RUNNING;
ProloGraalObject result = returnedValue;
if (result instanceof ProloGraalBoolean && ((ProloGraalBoolean) result).asBoolean()) {
// skip last possible nodes if empty, or always add if we already have added a path
if (!branches.isEmpty() || i + 1 < unifiableClauses.size()) {
if (branches.isEmpty()) {
i = i + 1; // if we're at the bottom go directly to next node
}
branches.push(i); // add the path that gave the success
}
if (traceFlag) {
System.out.println(TRACE_LEFT_WHITE_SPACE + goalsStack.size() + 1 + TRACE_LEFT_WHITE_SPACE + (start + 1)
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_EXIT_TEXT + currentGoal + TRACE_BETWEEN_WHITE_SPACE + TRACE_QUESTION_MARK);
}
//set the returned value as a success and break the for loop to simulate a return statement
returnedValue = new ProloGraalSuccess();
executeState = ExecuteState.RETURN;
break;
}
// undo all changes that the unification may have done
currentGoal.undo();
}
branches.push(i); // add the path that gave the success
}
if (traceFlag) {
System.out.println(TRACE_LEFT_WHITE_SPACE + depth + TRACE_LEFT_WHITE_SPACE + (start+1)
+ TRACE_BETWEEN_WHITE_SPACE + TRACE_EXIT_TEXT + currentGoal + TRACE_BETWEEN_WHITE_SPACE + TRACE_QUESTION_MARK);
}
return new ProloGraalSuccess();
//if we broke the for to return something or simulate another call,
//break before we set returnedValue to failure (behaviour of no unifiable clause)
if(executeState == ExecuteState.BEGIN || executeState == ExecuteState.RETURN)break;
returnedValue = new ProloGraalFailure();
executeState = ExecuteState.RETURN;
break;
}
// undo all changes that the unification may have done
currentGoal.undo();
}
return new ProloGraalFailure();
return returnedValue;
}
}
......@@ -20,7 +20,6 @@ public final class ProloGraalResolverNode extends RootNode {
private final ProloGraalContext context; // the context
private final Map<ProloGraalTerm<?>, List<ProloGraalClause>> clauses; // reference to the context clauses
private static final int FIRST_PROOF_TREE_NODE_DEPTH = 1;
public ProloGraalResolverNode(ProloGraalLanguage language) {
super(language);
......@@ -48,7 +47,7 @@ public final class ProloGraalResolverNode extends RootNode {
// also, the javadoc for the Stack encourages the use of a Deque instead
Deque<ProloGraalTerm<?>> goals = new ArrayDeque<>(clause.getGoals());
// create the root node of the proof tree
ProloGraalProofTreeNode proofTreeNode = new ProloGraalProofTreeNode(clauses, goals, FIRST_PROOF_TREE_NODE_DEPTH, context.isTraceFlag());
ProloGraalProofTreeNode proofTreeNode = new ProloGraalProofTreeNode(clauses, goals, context.isTraceFlag());
// start the execution of the proof tree, and stores the result
ProloGraalObject r = proofTreeNode.execute(branches);
if(r instanceof ProloGraalBoolean){
......
% This test checks the following things :
% - redo command
% - redo command with side-effects builtins
recommendedN(1000).
recommendedN(100000).
benchmark(0).
benchmark(N):-
is(N1,'-'(N,1)),
benchmark(N1),
benchmark(N1).
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment