Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IllegalArgumentException while doing a query on vardemo.sneps with some additional assertions. #3

Open
martinodb opened this issue May 30, 2018 · 2 comments

Comments

@martinodb
Copy link

So, I'm trying to get a hang of CSNePS (from the command-line, eventually to use it as a library), but I'm running into problems. I started with the demo "vardemo.sneps", in particular I'm intrested in how "Every farmer who owns a Donkey, beats it" is handled. I did a slightly modified version, where the rellevant "assert" commands are turned into "assert!" to trigger forward inference, and I added assertions about a particular farmer (Sancho) and a particular donkey (Rucio):

;;; Every farmer that owns a donkey beats it
(assert! '(Beats (every x (Isa x Farmer) (Isa x Agent) (Owns x (some y(x) (Isa y Donkey) (Isa y Agent))))  y))

;; Sancho is an Agent, Rucio is an Agent.
(assert! '(Isa Sancho Agent))
(assert! '(Isa Rucio Agent))

;;; Sancho is a Farmer
(assert! '(Isa Sancho Farmer))

;;; Rucio is a Donkey
(assert! '(Isa Rucio Donkey))

;;; Sancho Owns Rucio
(assert! '(Owns Sancho Rucio))

So far, so good. Then I ask a trivial question and it answers correctly:

csneps.core.snuser=> (ask '(Owns Sancho Rucio))
I wonder if wft49!: (Owns Sancho Rucio)
I know that wft49!: (Owns Sancho Rucio)
#{wft49!: (Owns Sancho Rucio)}

But then I ask whether Sancho beats Rucio, and BOOM, error:

csneps.core.snuser=> (ask '(Beats Sancho Rucio))
I wonder if wft50?: (Beats Sancho Rucio)
I will consider using Slot&Path-Based inference.
Exception in thread "pool-3-thread-2" java.lang.IllegalArgumentException: No implementation of method: :get-new-messages of protocol: #'csneps.snip/MessageStructure found for class: nil
	at clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)
	at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)
	at csneps.snip$eval7940$fn__7980$G__7923__7987.invoke(snip_message.clj:5)
	at csneps.snip$initiate_node_task.invokeStatic(snip_inference_graph.clj:1320)
	at csneps.snip$initiate_node_task.invoke(snip_inference_graph.clj:1177)
	at clojure.core$partial$fn__5563.invoke(core.clj:2622)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.lang.AFunction$1.doInvoke(AFunction.java:29)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:844)

csneps.core.snuser=> quit
Bye for now!

Here's the modified demo file in my fork of CSNePS:
https://github.com/martinodb/CSNePS/blob/semtype-objectlang/Demo/vardemo-modified.sneps

Can you please confirm as bug or explain my mistake? Thanks!

@digitalneoplasm
Copy link
Member

Hi there... I'll admit you're testing a bunch of things I haven't looked into very carefully! It's a summer plan of mine to really get this codebase solidified. I really appreciate the report!

I actually think there are two things here:

  1. The crash is definitely a bug. I have a note to myself in the code that indicates that instantiating indefinites is broken (which, I believe, is what it's trying to do here when it crashes). The issue might partially be a concurrency issue, with some part of the new indefinite not being fully built before an incoming message tries to use its message processing parts, but there are other issues with this part being slightly unfinished. (I think I managed to get this same issue to show up in instantiating arbitraries in some weird ways no one probably ever has tried, so more investigation needed on my part.)

  2. If instantiation worked, I would expect it to actually result in something like:
    (Beats Sancho (some y(Sancho) (Isa y Donkey) (Isa y Agent)))

Because if Sancho owns more than one donkey, we don't know that he beats all of them, and if not, which one he beats. Without the closed world assumption, with only one donkey we can't say there aren't more that we don't know about.

On the other hand, if we said that the arbitrary farmer beats the arbitrary donkey that they own:
(Beats (every x (Isa x Farmer) (Isa x Agent)) (every y (Isa y Donkey) (Isa y Agent) (Owns x y)))

This one would theoretically do the inference you want it to. On my current build it isn't working, but I can see that both arbs are emitting messages for the substitutions. What isn't happening is that
(every y (Isa y Donkey) (Isa y Agent) (Owns x y))
needs to emit a substitution containing both x and y. It's currently only emitting the y, so it's not quite working. I think it's a minor fix in how messages are combined (essentially, just retain the nested arb substitutions), but I'll have to look into it further.

Another thing I've considered: adding a quantifier for saying something like "If a farmer owns a single donkey, they beat that donkey", then we could do the inference you want... let me know if that would be useful. I'd imagine it would look something like:
(Beats (every x (Isa x Farmer) (Isa x Agent) (Owns x (the y(x) (Isa y Donkey) (Isa y Agent)))) y))

Thanks again! If you want to shoot me an email about what you're doing, perhaps I can be more helpful!

@martinodb
Copy link
Author

Hello, thanks for answering so soon! :)

I'll have a closer look during the weekend, but let's see very quickly now. Sorry if I mess up.

Because if Sancho owns more than one donkey, we don't know that he beats all of them, and if not, which one he beats. Without the closed world assumption, with only one donkey we can't say there aren't more that we don't know about.

Ah! I see. This (Skolemized?) SNePS notation can be tricky at first, if one is used to typical prefix scoped quantifier notation, like in Cyc, Snark, Powerloom, etc.

So I guess, yes, what I was thinking of is like "Every farmer beats every donkey he owns", as you wrote in that new formula. So I changed that accordingly:

;; Every farmer beats every donkey he owns:
(assert! '(Beats (every x (Isa x Farmer) (Isa x Agent)) (every y (Isa y Donkey) (Isa y Agent) (Owns x y))))

Here's the new file, vardemo-modified-v2.sneps:

https://github.com/martinodb/CSNePS/blob/semtype-objectlang/Demo/vardemo-modified-v2.sneps

And here's the result of loading it and asking the same questions:

csneps.core.snuser=> (ask '(Owns Sancho Rucio))
I wonder if wft49!: (Owns Sancho Rucio)
I know that wft49!: (Owns Sancho Rucio)
#{wft49!: (Owns Sancho Rucio)}
csneps.core.snuser=> (ask '(Beats Sancho Rucio))
I wonder if wft50?: (Beats Sancho Rucio)
I will consider using Slot&Path-Based inference.
I wonder if wft51?: (not (Beats Sancho Rucio))
I will consider using Slot&Path-Based inference.
#{}
csneps.core.snuser=> quit
Bye for now!

OK, so now there's no errror, but, as you said, not the expected result (it gives zero results, while it should give one). I can try other stuff during the weekend.

Another thing I've considered: adding a quantifier for saying something like "If a farmer owns a single donkey, they beat that donkey", then we could do the inference you want... let me know if that would be useful. I'd imagine it would look something like:
(Beats (every x (Isa x Farmer) (Isa x Agent) (Owns x (the y(x) (Isa y Donkey) (Isa y Agent)))) y))

Yes, no doubt it would be useful. But now I have doubts about its name ("the"). Maybe there should be a "the" operator and a "the-if-any", or similar? So, for instance, if I ask "Does Sancho beat the-if-any donkey he owns?" the answer would be something like "No (because he doesn't own one).". But if I ask "Does Sancho beat the donkey he owns" the answer would be something like "That question doesn't make sense. Sancho doesn't own a donkey". I don't know to what extent that makes sense in the context of SNePS, but ultimately I think I would need a feature like that. I can elaborate all day, but I don't want to make this issue comment too long. Which leads me to..

Thanks again! If you want to shoot me an email about what you're doing, perhaps I can be more helpful!

Thank you, that's very encouraging! :) Sure, I'll take your word for it and send you an email. Anyway, the sort version is, I want to make a really smart Clojure chatbot that can communicate in a controlled natural language expressive enough to handle time, events, beliefs and other typical notions of natural language. I would leave machine learning techniques (as will probably be needed to understand unrestricted natural language) for later, once the CNL interaction works well and the language is expressive enough. This is a personal, toy project, nothing "serious", and of course I'm a novice in both Clojure and AI-related stuff, like logic, NLU, etc. That said, with those caveats, here's what I've got for now:

https://github.com/martinodb/bobtailbot

It can connect to IRC or it can be tried as a CLI program. You can also try different "brains". The main one I'm using now is based on Instaparse and Clara.

https://github.com/martinodb/bobtailbot/tree/master/src/bobtailbot/brains/general

It can store facts about individuals in the form of triples (like "Mary likes Brad Pitt"), and also rules with the usual Horn-clause limitations (like "Brad Pitt likes ?x when ?x likes Brad Pitt"), but not much is implemented regarding that last part (connectives are probably still missing, I'll have to check). Anyway, going beyond that into actual FOL seems a big challege (for a novice like me, at least), so I thought it would make sense to grab some ready-made, open source FOL reasoner, written in Clojure or at least in Java, so I would only have to work on the CNL and the actual KR model. Well, even that turned out to be harder than I thought! So far, the best candidate seems to be SNePS, once confirmed that it works reliably. I wouldn't need the GUI, of course, just snuser and its dependencies.

Anyway, I ended up turning this comment into an email. Sorry about that!

Looking forward to getting advice, etc, by email ;)

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants