There is probably no practical application for this, but - delaying a Desire until some Belief becomes true #122
Replies: 1 comment
-
Also, FWIW, I think you could achieve a similar, but not identical, effect in pure AgentSpeak. I haven't tried to code it up, but I was thinking you'd do something like have the !foobar Desire. In the plan for +!foobar, have a context test for the foobaz belief. If it's false, there's no relevant plan, so you get a failure. Then, using the plan failure mechanism to handle that failure, and just reassert the !foobar Desire. I think this will loop forever until foobaz becomes true. The difference would be, I think, that you get a cycle of Desire -> Intention -> failure -> Desire -> Intention -> failure -> ... instead of Desire -> pause, pause , pause, pause, -> Intention Is that relevant to anything? Probably not. :-) |
Beta Was this translation helpful? Give feedback.
-
So in the process of trying to understand how all of this works "under the hood" I found myself wanting to "delay" a Desire from being selected as an Intention for a while, so I could have time to "mess with it". That is, inspect it using .desire(), possibly drop it using .drop_desire(), etc.
The problem is, with normal Jason processing, at least using the super simple examples I'm using, there's almost 0 delta between the event that establishes the Desire and the Desire being selected as an Intention. And that makes perfect sense in normal usage. I'm just playing around here for didactic purposes.
Anyway, I found a way to delay the processing of a given Event until a chosen Belief becomes true (appears in the BB). Again, this probably has zero practical utility, but somebody else who is playing around with understanding Jason might find this instructive or something.
Briefly, here's how it works. There may be (almost certainly are) better ways to do this, but this worked for me.
First, in your AgentSpeak code, include a Desire like
and a corresponding plan that does nothing.
Then in AgentSpeak, establish the Desire you want to delay: I used "foobar" in this example.
and then my plan/intention for foobar just prints to the log and stops the system.
If you were to run this now, you'd see "Foobar'ing!" printed immediately and the MAS would stop. But we want that to wait, so...
Add another event, like "started" or whatever and a plan like this:
Now we have an Intention that will delay for 8 seconds and then assert the belief "foobaz". There's no corresponding Plan for the +foobaz event, as that is only dealt with in the Agent code.
Now, create a custom Agent class, and override the selectEvent method. In this code, do a quick loop over the Events in the Queue, find the "dummy" event, store it in an instance scoped variable, and remove it from the Queue.
Then, loop over the Events and test each one in turn to see if it's the one we flagged to delay (based on the name of the event and the presence or absence of our "foobaz" belief). If not, just take the first "non delayed" event, assign it as the "selectedEvent" and continue processing. If we are looking at the "delay" event, this is where things get tricky. Push that event to an auxiliary Queue instance (in case there are multiple "delay" events), and remove it from the events Queue. Then return the stored "dummy" Event as the "selectedEvent" for this cycle. Note again though, we only set selectedEvent if it's null, meaning we have in our hand the the first event we would otherwise return.
Note the need to remove the "selectedEvent" Event from the events Queue in either path in this code. That's just an artifact of my choice to use a for loop over the Queue, which doesn't consume the items as they are visited. It might be easier to use a loop calling events.poll() instead.
After this loop finishes, we put any Events in the auxiliary queue back onto the end of the events Queue so they'll be candidates to process again in a subsequent cycle.
Net-net, the whole cycle looks like this:
Put all that together and when you run the system you'll see your Started message print out, and then 8 seconds later (or whatever delay you put in that inital event before asserting "foobaz") you'll see "Foobar'ing!" emitted to the console and the system will stop.
Now, to make things more interesting, we can confirm that the "foobar" desire exists, and we can even drop it before it is ever selected, meaning that when we run the system we'll see "Started" and then it will just run forever.
In the AgentSpeak code:
Now we see this, and then system just pauses forever.
If anybody is wondering, "why do the business with the 'dummy' event?" That is because, so far as I can tell, things break down if you return null from selectEvent. And if there's some event you're going to skip, regardless of the ordering and what-not, eventually you hit a cycle where you would otherwise return that event, but you're holding it back. So you have to return some Event there, or things just get all wedged up. You could probably write code in your Agent class to hand instantiate a "dummy" event instead of writing it in the AgentSpeak and pulling it out of the Queue like I did, but that felt like a lot of work as the Event has dependencies on other things and trying to do that is kinda going down a rabbit hole.
Of course this whole exercise is already a rabbit hole! But for me at least it was a good learning exercise as I now understand more about how the event selection stuff works and how Desires transition to Intentions (or not) and so on.
Complete source code can be found here.
Beta Was this translation helpful? Give feedback.
All reactions