s-webber / projog

Prolog programming for the Java platform.
Apache License 2.0
37 stars 9 forks source link

Queries not idempotent in projog #195

Closed ainouche closed 3 years ago

ainouche commented 3 years ago

Hi, I’ve downloaded projog recently and play a bit with very basic provided samples in tests source code. What a surprise to se that by calling the same query two times, projog provided a complete result for the first query and an empty one in the second call, in the same projog session. Just to compare, swi-prolog provided the same complete result, for both calls. As I am new in projog, is it a but or the expected result ? Thanks and kind regards, Salim

s-webber commented 3 years ago

Hi Salim,

Thank you for raising this issue. I'm sorry Projog is not working as you'd expect.

To help me investigate this issue can you please give me more information about exactly what you are trying to do. For example:

  1. Are you using the console application or are you calling Projog from a Java application?
  2. Can you let me know what query you are running and how the actual result differs from what you expected?

Incidentally, since you raised this issue a new version of Projog has been released. The latest version is 0.4.0. I don't think it will solve your issue but you might want to upgrade anyway. The following projects provide examples of how the latest version of Projog can be used to call Prolog from Java:

https://github.com/s-webber/prolog-wumpus-world https://github.com/s-webber/prolog-expert-system https://github.com/s-webber/projog-examples/tree/master/calling-prolog-from-java

If you are able to provide me with more information about the problem you are seeing then I will look into it and get back to you.

Thanks.

ainouche commented 3 years ago

Hi @s-webber,

First, thanks for your quick answer.

To help to better investigate/answer, I am currently using the latest 0.4.0 version. My bad, I've forgot to talk about a second consult call to update knowledge base. So, to reproduce this issue, I've used the following provided sample: https://github.com/s-webber/projog-examples/blob/master/calling-prolog-from-java/src/main/java/com/example/ProjogExample.java

and call the first query two times sequentially, like following:

 Projog p = new Projog();

  // Read Prolog facts and rules from a file to populate the "Projog" instance created in step 1.
  p.consultFile(new File("src/main/resources/test.pl"));
  // Create a query that will use the facts read in step 2.
  System.out.println("Query 1");
  QueryStatement s1 = p.query("test(X,Y).");
  // Execute the query created in step 3.
  QueryResult r1 = s1.getResult();
  while (r1.next()) {
     System.out.println("X = " + r1.getTerm("X") + " Y = " + r1.getTerm("Y"));
  }
  // Execute the query created in step 3.
  System.out.println("Query 2");
  p.consultFile(new File("src/main/resources/test1.pl"));
  s1 = p.query("test(X,Y).");
  r1 = s1.getResult();
  while (r1.next()) {
     System.out.println("X = " + r1.getTerm("X") + " Y = " + r1.getTerm("Y"));
  }

with test.pl content:

test(a,1). test(b,2). test(c,3). test(d,4). test(e,5). test(f,6). test(g,7). test(h,8). test(i,9). testRule(X) :- test(X, Y), Y mod 2 =:= 0.

and test1.pl content:

test(j,10).

RESULT

Query 1
X = a Y = 1
X = b Y = 2
X = c Y = 3
X = d Y = 4
X = e Y = 5
X = f Y = 6
X = g Y = 7
X = h Y = 8
X = i Y = 9
Query 2
X = j Y = 10

Process finished with exit code 0

The expected result is that the second consult call update the knowledge base and performing the second query, will produce the whole possibilities, in addition of the one provided by the last added predicate (test(j,10)). So:

Query 2
X = a Y = 1
X = b Y = 2
X = c Y = 3
X = d Y = 4
X = e Y = 5
X = f Y = 6
X = g Y = 7
X = h Y = 8
X = i Y = 9
X = j Y = 10

Thanks for your answer and sorry for the non accurate explanation.

s-webber commented 3 years ago

Hi Salim,

Thank you for your prompt and detailed response.

I have attached a zip that contains an example solution to this problem:

projog-issue-195.zip

If you run the org.projog.issue195.Issue195 class contained in the zip then you should see the following output:

Running org.projog.issue195.Issue195Test
INFO Reading prolog source in: projog-bootstrap.pl from classpath
INFO Reading prolog source in: issue-195a.pl from classpath
Query 1
X = a Y = 1
X = b Y = 2
X = c Y = 3
X = d Y = 4
X = e Y = 5
X = f Y = 6
X = g Y = 7
X = h Y = 8
X = i Y = 9
INFO Reading prolog source in: issue-195b.pl from classpath
Query 2
X = a Y = 1
X = b Y = 2
X = c Y = 3
X = d Y = 4
X = e Y = 5
X = f Y = 6
X = g Y = 7
X = h Y = 8
X = i Y = 9
X = j Y = 10
Query 3
Answers = [b, d, f, h, j]

To fix this problem I needed to do 2 things:

  1. I had to make a new commit to Projog. To use this change the pom.xml file of the attached zip references its own projog-core jar file (newly built from the latest source in Git, and stored in the lib directory of the zip) rather than using a version from the maven repository.
  2. To make the test/2 predicate updatable I needed to use the dynamic/1 predicate. I have added this statement to src/main/resources/issue-195a.pl - although, as mentioned in the comments, I could of instead executed it directly from Issue195.java.

I appreciate it would be more convenient if it was not necessary to use dynamic/1 to indicate that the predicate may be updated after originally defined. However, I have kept that constraint because if Projog knows that a predicate is not dynamic then it can make some performance optimisations. Therefore requiring updateable predicates to be marked as dynamic allows Projog to safely optimise the predicates that have not been marked as dynamic.

I hope this proposed approach is satisfactory. As this change has been committed to Git then it will be included in the next release of Projog - but I don't know when that will be. In the meantime, using a local version of the projog-core jar (as demonstrated in the attached zip) is a workaround.

Thank you again for raising this issue. If you are not happy with this response then please add a new comment to this issue and I will be happy to investigate further. If you have any more questions or comments about Projog then you are welcome to raise a new issue.

ainouche commented 3 years ago

Hi @s-webber, Thanks for your quick answer, the workaround and the provided solution bundle. It works perfectly on my end. I understand the performance optimisation constraint that is necessary for the software usability (UX) and adoption. I was wondering if instead of specifying explicitly the dynamic aspect of a predicate, that is bit code intrusive and UX disadvantaging, to keep by default, as it the case today, predicates static and once updated, move them to dynamic, in total transparent way. Off-course, I didn't read the code to see if it is feasible, but if it is the case, and maybe you can confirm that, the UX aspect of the software will be hugely increased.

WDYT?

s-webber commented 3 years ago

Thank you for your suggestion. Unfortunately I do not think this will be a small change, but I agree it deserves consideration. I don't know when I will be free to look at it but I have created a new issue - #196 - so it will not be forgotten.

Thanks again for your feedback. I will now close this issue. If you have any more questions or comments about Projog then you are welcome to raise a new issue. I will be happy to investigate any other issues you identify.

ainouche commented 3 years ago

Hi @s-webber, That’s fine @s-webber, I will use your workaround and sent patched library, waiting release 5. You can close this issue and keep the real improvement tracked by #196 issue. Thanks a lot for your reactivity and your kindness. Thanks again @s-webber, Kind regards, Salim