From: Jomi H. <jom...@gm...> - 2009-12-18 19:29:07
|
Hi Tim, I include (partially) your suggestions into the SVN of Jason. (details attached -- I've tried to optimise some parts.... If you could check...) notes: 1. we cannot comment the makeVarAnnon in TransitionSystem (I added a new test to show it) 2. with this line uncommented, one of the tests do not pass. (it could be a problem in "if" ... I'll see) best, Jomi Revision: 1566 http://jason.svn.sourceforge.net/jason/?rev=1566&view=rev Author: jomifred Date: 2009-12-18 19:24:45 +0000 (Fri, 18 Dec 2009) Log Message: ----------- add some code from Tim to solve makeVarsAnnon problem (not finished) Modified Paths: -------------- trunk/applications/as-unit-test/src/jason/tests/BugUnamedVars.java trunk/applications/as-unit-test/src/jason/tests/TestAll.java trunk/src/jason/asSyntax/ArithFunctionTerm.java trunk/src/jason/asSyntax/Literal.java trunk/src/jason/asSyntax/Pred.java trunk/src/jason/asSyntax/Rule.java trunk/src/jason/asSyntax/Structure.java trunk/src/jason/asSyntax/VarTerm.java trunk/src/test/RuleTest.java trunk/src/test/TermTest.java Added Paths: ----------- trunk/applications/as-unit-test/src/jason/tests/TestUnnamedVar.java Modified: trunk/applications/as-unit-test/src/jason/tests/ BugUnamedVars.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/BugUnamedVars.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/applications/as-unit-test/src/jason/tests/BugUnamedVars.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -20,15 +20,26 @@ ag.parseAScode( "wrap([],[]). "+ "wrap([_ | Rest], [wrapped(_) | Result]) :- wrap(Rest, Result). "+ + + "wrap2([], _). "+ + "wrap2([_ | Rest], Result) :- wrap2(Rest, Temp) & Result = wrapped(_, Temp). "+ + "+!start : wrap([a,b,c],R) & R = [wrapped(a), wrapped(b), wrapped(c)] <- jason.asunit.print(ok)."+ - "+!start : wrap([a,b,c],R) & R = [wrapped(a), wrapped(a), wrapped(a)] <- jason.asunit.print(nok). " + "+!start : wrap([a,b,c],R) & R = [wrapped(a), wrapped(a), wrapped(a)] <- jason.asunit.print(nok). " + + "+!test2 : wrap2([1, 2, 3], Result) & Result = wrapped(1, wrapped(2, wrapped(3, 4))) <- jason.asunit.print(ok). " ); } @Test(timeout=2000) - public void testWrap() { + public void testWrap1() { ag.addGoal("start"); ag.assertPrint("ok", 20); } + + @Test(timeout=2000) + public void testWrap2() { + ag.addGoal("test2"); + ag.assertPrint("ok", 20); + } } Modified: trunk/applications/as-unit-test/src/jason/tests/TestAll.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/TestAll.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/applications/as-unit-test/src/jason/tests/TestAll.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -23,6 +23,7 @@ TestLoop.class, TestPlanbodyAsTerm.class, TestPlanFailure.class, - TestVarInContext.class + TestVarInContext.class, + TestUnnamedVar.class }) public class TestAll { } Added: trunk/applications/as-unit-test/src/jason/tests/ TestUnnamedVar.java =================================================================== --- trunk/applications/as-unit-test/src/jason/tests/ TestUnnamedVar.java (rev 0) +++ trunk/applications/as-unit-test/src/jason/tests/ TestUnnamedVar.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -0,0 +1,22 @@ +package jason.tests; + +import jason.asunit.TestAgent; + +import org.junit.Test; + +public class TestUnnamedVar { + + @Test(timeout=2000) + public void testUnnamedVar() { + TestAgent ag = new TestAgent(); + + // defines the agent's AgentSpeak code + ag.parseAScode( + "+!test <- A=a(B); !t(A); jason.asunit.print(A). "+ + "+!t(A) <- B=3. " + ); + ag.addGoal("test"); + ag.assertPrint("a(B)", 10); // cannot print(a(3) + } + +} Modified: trunk/src/jason/asSyntax/ArithFunctionTerm.java =================================================================== --- trunk/src/jason/asSyntax/ArithFunctionTerm.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/ArithFunctionTerm.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -66,8 +66,17 @@ public boolean isStructure() { return false; } - + @Override + public Literal makeVarsAnnon(Unifier un) { + if (isEvaluated()) { + return null; + } else { + return super.makeVarsAnnon(un); + } + } + + @Override public boolean isLiteral() { return false; } @@ -81,7 +90,7 @@ public boolean isEvaluated() { return value != null; } - + @Override public boolean isGround() { return isEvaluated() || super.isGround(); @@ -97,7 +106,8 @@ */ @Override public boolean apply(Unifier u) { - if (isEvaluated()) return false; + if (isEvaluated()) + return false; super.apply(u); if ((function != null && function.allowUngroundTerms()) || isGround()) { Modified: trunk/src/jason/asSyntax/Literal.java =================================================================== --- trunk/src/jason/asSyntax/Literal.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/Literal.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -264,7 +264,6 @@ Unifier current = null; Iterator<Unifier> ruleIt = null; // current rule solutions iterator Rule rule; // current rule - Literal cloneAnnon = null; // a copy of the literal with makeVarsAnnon boolean needsUpdate = true; public boolean hasNext() { @@ -291,40 +290,28 @@ while (ruleIt != null && ruleIt.hasNext()) { // unifies the rule head with the result of rule evaluation Unifier ruleUn = ruleIt.next(); // evaluation result - Literal rhead = rule.headClone(); - - // unnamed vars should be replaced (see bug of Tim Cleaver) - replaceUnnamedVarsToUnnamedVars(rhead); - - // then apply and replace other free variables - rhead.apply(ruleUn); - rhead.makeVarsAnnon(ruleUn); - - - Unifier unC = un.clone(); - if (unC.unifiesNoUndo(Literal.this, rhead)) { - current = unC; + if (ruleUn.unifiesNoUndo(Literal.this, rule)) { + current = ruleUn; return; } } // try literal iterator + // + // we make the variables in the belief (be it a fact or rule) and not + // in this as this may be included in the scope of a plan. if we rename + // the variables in this and it is in the scope of a plan then the + // variables in the event and the body of the plan won't reflect the + // naming. thus, making the resulting unifier not reflect the entire + // scope of the plan. while (il.hasNext()) { Literal b = il.next(); // b is the relevant entry in BB if (b.isRule()) { - rule = (Rule)b; - - // create a copy of this literal, ground it and - // make its vars anonymous, - // it is used to define what will be the unifier used - // inside the rule. - if (cloneAnnon == null) { - cloneAnnon = Literal.this.copy(); - cloneAnnon.apply(un); - cloneAnnon.makeVarsAnnon(un); - } - Unifier ruleUn = new Unifier(); - if (ruleUn.unifiesNoUndo(cloneAnnon, rule)) { // the rule head unifies with the literal + rule = (Rule)b.clone(); + rule.makeVarsAnnon(); // make the variables in the rule anonymous + Unifier ruleUn = un.clone(); + if (ruleUn.unifiesNoUndo(Literal.this, rule)) { + // the rule head unifies with the literal so match the body ruleIt = rule.getBody().logicalConsequence(ag,ruleUn); get(); if (current != null) { // if it get a value @@ -333,7 +320,7 @@ } } else { Unifier u = un.clone(); - if (u.unifiesNoUndo(Literal.this, b)) { + if (u.unifiesNoUndo(Literal.this, b)) { // b.copy().makeVarsAnnon())) { current = u; return; } @@ -345,18 +332,6 @@ }; } - private void replaceUnnamedVarsToUnnamedVars(Literal l) { - final int size = l.getArity(); - for (int i=0; i<size; i++) { - Term ti = l.getTerm(i); - if (ti.isUnnamedVar()) { - l.setTerm(i, new UnnamedVar()); - } else if (ti instanceof Literal) { - replaceUnnamedVarsToUnnamedVars((Literal)ti); - } - } - } - /** returns this literal as a list with three elements: [functor, list of terms, list of annots] */ public ListTerm getAsListOfTerms() { ListTerm l = new ListTermImpl(); @@ -425,6 +400,11 @@ public Iterator<Unifier> logicalConsequence(final Agent ag, final Unifier un) { return LogExpr.createUnifIterator(un); } + + @Override + public Literal clone() { + return this; + } } @SuppressWarnings("serial") @@ -442,5 +422,10 @@ public Iterator<Unifier> logicalConsequence(final Agent ag, final Unifier un) { return LogExpr.EMPTY_UNIF_LIST.iterator(); } + + @Override + public Literal clone() { + return this; + } } } Modified: trunk/src/jason/asSyntax/Pred.java =================================================================== --- trunk/src/jason/asSyntax/Pred.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/Pred.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -400,7 +400,7 @@ VarTerm uv = varToReplace(ta, un); if (uv != null) lt.setTerm(uv); - else if (ta.isStructure()) + else if (ta instanceof Structure) ((Structure)ta).makeVarsAnnon(un); if (lt.isTail()) { uv = varToReplace(lt.getNext(), un); Modified: trunk/src/jason/asSyntax/Rule.java =================================================================== --- trunk/src/jason/asSyntax/Rule.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/Rule.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -23,6 +23,8 @@ package jason.asSyntax; +import jason.asSemantics.Unifier; + import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -77,6 +79,13 @@ return body; } + @Override + public Literal makeVarsAnnon(Unifier un) { + if (body instanceof Literal) + ((Literal)body).makeVarsAnnon(un); + return super.makeVarsAnnon(un); + } + public Rule clone() { Rule r = new Rule((Literal)super.clone(), (LogicalFormula)body.clone()); r.predicateIndicatorCache = null; Modified: trunk/src/jason/asSyntax/Structure.java =================================================================== --- trunk/src/jason/asSyntax/Structure.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/Structure.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -281,20 +281,48 @@ for (int i=0; i<size; i++) { Term ti = getTerm(i); VarTerm uv = varToReplace(ti, un); - if (uv != null) { + if (uv != null) setTerm(i,uv); - } else if (ti.isStructure()) { - Structure tis = (Structure)ti; - if (tis.hasTerm()) { - tis.makeVarsAnnon(un); - } - } + else if (ti instanceof Structure) + ((Structure)ti).makeVarsAnnon(un); } resetHashCodeCache(); return this; } protected VarTerm varToReplace(Term t, Unifier un) { + if (!t.isVar()) + return null; + VarTerm vt = (VarTerm)t; + VarTerm deref = un.deref(vt); + if (deref.isUnnamedVar()) + return new UnnamedVar(); + + // if the variable hasn't been renamed given the input unifier, then rename it. + if (deref.equals(vt)) { + // forget the name + VarTerm var = new VarTerm("_" + UnnamedVar.getUniqueId() + t); + // if deref has annotations then we need to replicate these in the new variable + if (deref.hasAnnot()) { + var.setAnnots(deref.getAnnots().cloneLT()); + var.makeVarsAnnon(un); + } + un.bind(deref, var); + return var; + } + // otherwise it has already been renamed in this scope so return + // the existing renaming + // ensure that if the input term has an annotation and the existing + // renaming doesn't then we add the anonymized annotations + if (vt.hasAnnot() && !deref.hasAnnot()) { + deref.setAnnots(vt.getAnnots().cloneLT()); + deref.makeVarsAnnon(un); + } + return deref; + } + + /* + protected VarTerm varToReplace(Term t, Unifier un) { if (t.isVar() && !t.isUnnamedVar()) { // replace t to an unnamed var VarTerm vt = un.deref((VarTerm)t); @@ -309,6 +337,7 @@ return null; } } + */ @Override public void makeTermsAnnon() { Modified: trunk/src/jason/asSyntax/VarTerm.java =================================================================== --- trunk/src/jason/asSyntax/VarTerm.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/jason/asSyntax/VarTerm.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -414,6 +414,16 @@ } @Override + public Literal makeVarsAnnon(Unifier un) { + if (value == null) + return super.makeVarsAnnon(un); + else if (getValue().isLiteral()) + return ((Literal)getValue()).makeVarsAnnon(un); + else + return null; + } + + @Override public String toString() { if (value == null) { String s = getFunctor(); @@ -436,7 +446,7 @@ public void setAnnots(ListTerm l) { if (value != null) if (getValue().isPred()) - ((Pred) value).setAnnots(l); + ((Pred) getValue()).setAnnots(l); else logger.log(Level.WARNING, "The setAnnots '"+l+"' in "+this+" was lost, since this var value is not a Pred. The value's class is "+getValue().getClass().getName(), new Exception()); else Modified: trunk/src/test/RuleTest.java =================================================================== --- trunk/src/test/RuleTest.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/test/RuleTest.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -2,9 +2,11 @@ import jason.asSemantics.Agent; import jason.asSemantics.Unifier; +import jason.asSyntax.ASSyntax; import jason.asSyntax.Literal; import jason.asSyntax.LogExpr; import jason.asSyntax.Rule; +import jason.asSyntax.Structure; import jason.asSyntax.VarTerm; import java.util.HashMap; @@ -80,12 +82,20 @@ ag.getBB().add(r); Iterator<Unifier> iun = Literal.parseLiteral("r([],a(20),X)").logicalConsequence(ag, new Unifier()); - assertEquals(iun.next().get("X").toString(),"b(20,4)"); - + //assertEquals(iun.next().get("X").toString(),"b(20,4)"); + assertTrue(iun.hasNext()); + Literal result = Literal.parseLiteral("r([],a(20),X)"); + Unifier u = iun.next(); + assertTrue(u.get("X").isStructure()); + assertEquals( ((Structure)u.get("X")).getArity(), 2); + assertEquals( ((Structure)u.get("X")).getFunctor(), "b"); + result.apply(u); + assertEquals(result, Literal.parseLiteral("r([],a(20),b(20,4))")); + iun = Literal.parseLiteral("r([],a(20),b(X,Y))").logicalConsequence(ag, new Unifier()); - Unifier u = iun.next(); - assertEquals(u.get("X").toString(),"20"); - assertEquals(u.get("Y").toString(),"4"); + u = iun.next(); + assertEquals(u.get("X"), ASSyntax.createNumber(20)); + assertEquals(u.get("Y"), ASSyntax.createNumber(4)); } Modified: trunk/src/test/TermTest.java =================================================================== --- trunk/src/test/TermTest.java 2009-12-18 14:10:31 UTC (rev 1565) +++ trunk/src/test/TermTest.java 2009-12-18 19:24:45 UTC (rev 1566) @@ -16,6 +16,7 @@ import jason.asSyntax.ObjectTermImpl; import jason.asSyntax.Plan; import jason.asSyntax.Pred; +import jason.asSyntax.StringTermImpl; import jason.asSyntax.Structure; import jason.asSyntax.Term; import jason.asSyntax.Trigger; @@ -27,9 +28,11 @@ import jason.bb.BeliefBase; import jason.bb.DefaultBeliefBase; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import junit.framework.TestCase; @@ -601,10 +604,21 @@ l2.makeVarsAnnon(); u.clear(); assertTrue(u.unifies(l1, l2)); + + // ensure that the anonymized instance of AgY unified to 32 + assertEquals(u.get((VarTerm) l1.getTerm(0)), new NumberTermImpl(32)); + // ensure that the first anonymized instance of QuadY2 unifies to 33 + assertEquals(u.get((VarTerm) l1.getTerm(1)), new NumberTermImpl(33)); + // ensure that the second anonymized instance of QuadY2 unifies to 33 + assertEquals(u.get((VarTerm) l1.getTerm(2)), new NumberTermImpl(33)); + // ensure that the anonymized instance of V unifies to 33 + assertEquals(u.get((VarTerm) l2.getTerm(2)), new NumberTermImpl(33)); + l2.apply(u); assertEquals("calc(32,33,33)", l2.toString()); l1.apply(u); assertEquals("calc(32,33,33)", l1.toString()); + } public void testMakeVarAnnon3() { @@ -636,7 +650,17 @@ } */ l.makeVarsAnnon(u); - assertEquals("p(_2)", l.toString()); + // ensure that X derefs to _2 + assertTrue(u.deref(new VarTerm("X")).equals(new UnnamedVar(2))); + // ensure that unifying a value with X will bind a value for all aliases as well. + Term val = new StringTermImpl("value"); + u.unifies(new VarTerm("X"), val); + assertTrue(u.get(new VarTerm("X")).equals(val)); + assertTrue(u.get(new VarTerm("Y")).equals(val)); + assertTrue(u.get(new VarTerm("Z")).equals(val)); + assertTrue(u.get(new UnnamedVar(4)).equals(val)); + assertTrue(u.get(new UnnamedVar(2)).equals(val)); + assertTrue(u.get(new UnnamedVar(10)).equals(val)); } public void testMakeVarAnnon5() { @@ -648,6 +672,32 @@ assertEquals("[s("+l.getTerm(0)+")]", l.getAnnots().toString()); } + // test from Tim Cleaver + public void testMakeVarsAnnon6() { + // if we make a literal anonymous multiple times, the instances should not + // be equal but should eb unifiable. + Literal literal = Literal.parseLiteral("literal(Variable, _)"); + List<Literal> literals = new ArrayList<Literal>(); + literals.add(literal); + // create a list of anonymized l1s + for (int i = 0; i < 5; i++) { + literals.add((literal.copy()).makeVarsAnnon()); + } + // ensure that all the anonymizations of Variable are different + // ensure that all the anonymizations of _ are different + // ensure that all pairs are unifiable + for (Literal l1 : literals) { + for (Literal l2 : literals) { + if (l1 == l2) { + continue; + } + assertFalse(l1.getTerm(0).equals(l2.getTerm(0))); + assertFalse(l1.getTerm(1).equals(l2.getTerm(1))); + assertTrue(new Unifier().unifies(l1, l2)); + } + } + } + public void testAddAnnots() { Literal p1 = Literal.parseLiteral("p1"); Literal p2 = Literal.parseLiteral("p2[a1,a2]"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ This SF.Net email is sponsored by the Verizon Developer Community Take advantage of Verizon's best-in-class app development support A streamlined, 14 day to market process makes app distribution fast and easy Join now and get one step closer to millions of Verizon customers http://p.sf.net/sfu/verizon-dev2dev _______________________________________________ Jason-developers mailing list Jas...@li... https://lists.sourceforge.net/lists/listinfo/jason-developers On 14/12/2009, at 21:17, Tim Cleaver wrote: > Jomi, > > Having sent you my updated patch I returned to my personal project. > However, it seems that your solution isn't sufficient for my needs. > I had figured that my simplified example was sufficient to capture > the entire issue. It wasn't. Here is another simple demonstration of > insufficient anonymous variable renaming that my project > necessitates. I hope this test case captures all my needs so you > don't have to reopen this bug again. I am trying to avoid sending my > actual project code as its complexity hides the real issues. > > wrap([], _). > wrap([_ | Rest], Result) :- wrap(Rest, Temp) & Result = wrapped(_, > Temp). > > !test. > > !test : wrap([1, 2, 3], Result) & Result = wrapped(1, wrapped(2, > wrapped(3, 4))) <- .print("ok"). > > Similar to last time, each anonymous variable in wrapped(_, Temp) > should be unique. Unfortunately it seems your fix does not provide > this. The patch sent in my previous email does. Perhaps it can be > adapted to work with your fix? > > regards, > Tim > > > > __________________________________________________________________________________ > See what's on at the movies in your area. Find out now: http://au.movies.yahoo.com/session-times/ -- Jomi Fred Hubner Department of Automation and Systems Engineering Federal University of Santa Catarina PO Box 476, Florianópolis, SC 88040-900 Brasil http://www.das.ufsc.br/~jomi |