From: <jom...@us...> - 2013-11-04 11:27:53
|
Revision: 1756 http://sourceforge.net/p/jason/svn/1756 Author: jomifred Date: 2013-11-04 11:27:47 +0000 (Mon, 04 Nov 2013) Log Message: ----------- initial implementation of tail recursion optimisation Modified Paths: -------------- trunk/applications/as-unit-test/src/jason/tests/BugListReturnUnification.java trunk/applications/as-unit-test/src/jason/tests/TestAll.java trunk/release-notes.txt trunk/src/jason/asSemantics/Intention.java trunk/src/jason/asSemantics/TransitionSystem.java trunk/src/jason/asSemantics/Unifier.java trunk/src/jason/runtime/Settings.java Added Paths: ----------- trunk/applications/as-unit-test/src/jason/tests/TestTRO.java Modified: trunk/applications/as-unit-test/src/jason/tests/BugListReturnUnification.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/BugListReturnUnification.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/applications/as-unit-test/src/jason/tests/BugListReturnUnification.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -28,8 +28,8 @@ "+!a(Y)[x(Z),kk] <- Y=3; Z=4. "+ "+!a(Y)[x(Z),source(self)] <- Y=1; Z=2. "+ - "+!test4 <- X = [a,b,c]; !deleteb(X,Y); jason.asunit.print(Y)."+ - "+!test5 <- X = [a,b,c]; !deleteb2(X,Y); jason.asunit.print(Y)."+ + "+!test4 <- X = [a,b,c,b,b,d]; !deleteb(X,Y); jason.asunit.print(Y)."+ + "+!test5 <- X = [a,b,c,b,b,d]; !deleteb2(X,Y); jason.asunit.print(Y)."+ "+!deleteb([], [])."+ "+!deleteb([b|L1], L2)"+ @@ -64,12 +64,12 @@ @Test(timeout=2000) public void testDelete1() { ag.addGoal("test4"); - ag.assertPrint("[a,c]", 10); + ag.assertPrint("[a,c,d]", 10); } @Test(timeout=2000) public void testDelete2() { ag.addGoal("test5"); - ag.assertPrint("[a,c]", 10); + ag.assertPrint("[a,c,d]", 20); } } Modified: trunk/applications/as-unit-test/src/jason/tests/TestAll.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/TestAll.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/applications/as-unit-test/src/jason/tests/TestAll.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -26,6 +26,7 @@ TestVarInContext.class, TestUnnamedVar.class, TestCopyTerm.class, - TestNegatedVar.class + TestNegatedVar.class, + TestTRO.class }) public class TestAll { } Added: trunk/applications/as-unit-test/src/jason/tests/TestTRO.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/TestTRO.java (rev 0) +++ trunk/applications/as-unit-test/src/jason/tests/TestTRO.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -0,0 +1,31 @@ +package jason.tests; + +import jason.asunit.TestAgent; + +import org.junit.Before; +import org.junit.Test; + +// test Tail Recursion Optimization +public class TestTRO { + + TestAgent ag; + + // initialisation of the agent test + @Before + public void setupAg() { + ag = new TestAgent(); + + // defines the agent's AgentSpeak code + ag.parseAScode( + "+!run <- !fat(5,1,F); jason.asunit.print(F). "+ + "+!fat(1,V,V). "+ + "+!fat(N,A,X) <- !fat(N-1,N*A,X)." + ); + } + + @Test(timeout=2000) + public void testGoalSrouce() { + ag.addGoal("run"); + ag.assertPrint("120", 50); + } +} Modified: trunk/release-notes.txt =================================================================== --- trunk/release-notes.txt 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/release-notes.txt 2013-11-04 11:27:47 UTC (rev 1756) @@ -1,3 +1,10 @@ +New features + +- implementation of tail recursion optimisation for sub-goals. + It can be turned off in agent options, e.g.: + agents: bob [tro=false]; + + --------------------------- version 1.3.10b @@ -218,7 +225,7 @@ these events can than be handled by plans such as ^!goto(X,Y)[state(S)] <- .print("goto state is ",S). for the state suspended, another annotation contains the - suspension reason (.wait, .suspend, É) + suspension reason (.wait, .suspend, ...) ^!goto(X,Y)[state(S)[reason(R)]] <- .print("goto state is ",S," due to ",R). Modified: trunk/src/jason/asSemantics/Intention.java =================================================================== --- trunk/src/jason/asSemantics/Intention.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/src/jason/asSemantics/Intention.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -193,7 +193,7 @@ } public String toString() { - StringBuilder s = new StringBuilder("intention "+id+": "); + StringBuilder s = new StringBuilder("intention "+id+": \n"); for (IntendedMeans im: intendedMeans) s.append(" " + im + "\n"); if (isFinished()) Modified: trunk/src/jason/asSemantics/TransitionSystem.java =================================================================== --- trunk/src/jason/asSemantics/TransitionSystem.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/src/jason/asSemantics/TransitionSystem.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -493,6 +493,41 @@ confP.C.addIntention(intention); } else { // Rule IntEv + + // begin tail recursion optimisation (TRO) + if (setts.isTROon()) { + IntendedMeans top = confP.C.SE.intention.peek(); // top = the IM that will be removed from the intention due to TRO + if (top.getTrigger().isGoal() && im.getTrigger().isGoal() && // are both goal + top.getTrigger().getPredicateIndicator().equals( im.getTrigger().getPredicateIndicator()) && // are they equals + top.getCurrentStep().getBodyNext() == null) { // the plan below is finished + confP.C.SE.intention.pop(); // remove the top IM + + IntendedMeans imBase = confP.C.SE.intention.peek(); // base = where the new IM will be place on top of + // move top relevant values into the base (relevant = renamed vars in base) + for (VarTerm v: imBase.renamedVars) { + VarTerm vvl = (VarTerm)imBase.renamedVars.function.get(v); + Term t = top.unif.get(vvl); + if (t != null) { // if v has got a value in top unif, put the value in the unifier + if (t instanceof Literal) { + Literal l= (Literal)t.clone(); + l.apply(top.unif); + l.makeVarsAnnon(top.renamedVars); + im.unif.function.put(vvl, l); + } else { + im.unif.function.put(vvl, t); + } + } else { + // the vvl was renamed again in top, just replace in base the new value + VarTerm v0 = (VarTerm)top.renamedVars.function.get(vvl); + if (v0 != null) { + imBase.renamedVars.function.put(v, v0); + } + } + } + } + // end of TRO + } + confP.C.SE.intention.push(im); confP.C.addIntention(confP.C.SE.intention); } @@ -807,10 +842,30 @@ body = body.copy(); body.apply(u); Unifier renamedVars = new Unifier(); - if (imRenamedVars != null) + //System.out.println("antes "+body+" "+u+" "); + body.makeVarsAnnon(renamedVars); // free variables in an event cannot conflict with those in the plan + if (imRenamedVars != null) { imRenamedVars.renamedVars = renamedVars; - body.makeVarsAnnon(renamedVars); // free variables in an event cannot conflict with those in the plan - //body.makeVarsAnnon(u); // free variables in an event cannot conflict with those in the plan + + // Code for TRO (Tail Recursion Opt) + if (setts.isTROon()) { + // renamed vars binded with another var in u need to be preserved (since u will be lost in TRO) + Map<VarTerm, Term> adds = null; + for (VarTerm v: renamedVars) { + Term t = u.function.get(v); + if (t != null) { + //System.out.println("adding "+t+"="+renamedVars.function.get(v)); + if (adds == null) + adds = new HashMap<VarTerm, Term>(); + adds.put((VarTerm)t,renamedVars.function.get(v)); + } + } + if (adds != null) + renamedVars.function.putAll(adds); + //System.out.println("depois "+body+" "+renamedVars+" u="+u); + // end code for TRO + } + } body = body.forceFullLiteralImpl(); if (!body.hasSource()) { // do not add source(self) in case the programmer set the source body.addAnnot(BeliefBase.TSelf); @@ -883,52 +938,23 @@ // old code: /*topLiteral.apply(topIM.unif); topLiteral.makeVarsAnnon(); - im.unif.unifies(im.removeCurrentStep(), topLiteral); + Literal cstep = (Literal)im.removeCurrentStep(); + boolean r = im.unif.unifies(cstep,topLiteral); */ // new code optimised: handle directly renamed vars for the call - //System.out.println("* "+topLiteral+topIM.unif+" "+im.unif+" "+im.renamedVars); - /*VarTerm[] lvt = null; - Term[] lvl = null; - int n = 0; - // get vars in the unifier that comes from makeVarAnnon - for (Term t: im.unif.function.values()) { - if (t instanceof UnnamedVar) { - UnnamedVar vt = (UnnamedVar)t; - if (vt.isFromMakeVarAnnon()) { - Term vl = topIM.unif.function.get(vt); - if (vl != null) { // vt has value in top - vl = vl.clone(); - vl.apply(topIM.unif); - if (vl.isLiteral()) - ((Literal)vl).makeVarsAnnon(); - if (lvt == null) { - int s = Math.max(im.unif.size(),topIM.unif.size()); - lvt = new VarTerm[s]; - lvl = new Term[s]; - } - lvt[n] = vt; - lvl[n] = vl; - n++; - } - } - } - } - for (int il=0; il<n; il++) { - im.unif.bind(lvt[il], lvl[il]); - } - */ - - // get vars in the unifier that comes from makeVarAnnon (stored in renamedVars) if (im.renamedVars != null) { for (VarTerm ov: im.renamedVars.function.keySet()) { + //System.out.println("looking for a value for "+ov+" in "+im.renamedVars+" and "+topIM.unif); UnnamedVar vt = (UnnamedVar)im.renamedVars.function.get(ov); + //System.out.println(" via "+vt); im.unif.unifiesNoUndo(ov, vt); // introduces the renaming in the current unif // if vt has got a value from the top (a "return" value), include this value in the current unif Term vl = topIM.unif.function.get(vt); //System.out.println(ov+"="+vt+"="+vl); if (vl != null) { // vt has value in top + //System.out.println(" and found "+vl); vl = vl.clone(); vl.apply(topIM.unif); if (vl.isLiteral()) @@ -937,8 +963,7 @@ } } } - //System.out.println("=> "+im.unif); - im.removeCurrentStep(); + im.removeCurrentStep(); } } } Modified: trunk/src/jason/asSemantics/Unifier.java =================================================================== --- trunk/src/jason/asSemantics/Unifier.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/src/jason/asSemantics/Unifier.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -103,6 +103,16 @@ } return vl; } + + public VarTerm getVarFromValue(Term vl) { + for (VarTerm v: function.keySet()) { + Term vvl = function.get(v); + if (vvl.equals(vl)) { + return v; + } + } + return null; + } public boolean unifies(Trigger te1, Trigger te2) { return te1.sameType(te2) && unifies(te1.getLiteral(), te2.getLiteral()); Modified: trunk/src/jason/runtime/Settings.java =================================================================== --- trunk/src/jason/runtime/Settings.java 2013-10-31 20:20:03 UTC (rev 1755) +++ trunk/src/jason/runtime/Settings.java 2013-11-04 11:27:47 UTC (rev 1756) @@ -52,6 +52,7 @@ private boolean sync = ODefaultSync; private boolean qCache = false; // whether to use query cache private boolean qProfiling = false; // whether has query profiling + private boolean troON = true; // tail recursion optimisation is on by default private Map<String,Object> userParameters = new HashMap<String,Object>(); @@ -108,6 +109,8 @@ } else if (key.equals("synchronised")) { setSync("true".equals((String)options.get("synchronised"))); + } else if (key.equals("tro")) { + setTRO("true".equals((String)options.get("tro"))); } else if (key.equals("qcache")) { setQueryCache( "cycle".equals((String)options.get("qcache")) ); } else if (key.equals("qprofiling")) { @@ -200,6 +203,13 @@ sync = pSync; } + public boolean isTROon() { + return troON; + } + public void setTRO(boolean tro) { + troON = tro; + } + public boolean hasQueryCache() { return qCache; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |