I have been reviewing some material on the representation of an AI plan given the STRIPS format, and found that different people seem to formulate the same problem in different ways.
For instance, Wikipedia has an example regarding the Monkey in the lab problem. The problem states that:
A box is available that will enable the monkey to reach the bananas hanging from the ceiling if he climbs up on it. Initially, the monkey is at A, the bananas at B, and the box at C. The monkey and the box have height Low, but if the monkey climbs onto the box, he will have height High, the same as the bananas. The actions available to the monkey include Go from one place to another, Push an object from one place to another, ClimbUp onto or CLimbDown from an object, and Grasp or UnGrasp an object. Grasping the object results in holding the object if the monkey and the object are in the same place at the same height.
Here is the Wikipedia plan (please note that it is not matched exactly to this problem description, but it is the same problem. It doesn't seem to implement Ungrasp, which is not important for this discussion):
Now nowhere in this plan can I see that the bananas are located at Level(high), so the only way this could actually be divulged from the plan would be to read through the entire set of Actions and deduce from there that the Monkey must be at Level(high) to interact with the bananas, hence they must be at Level(high).
Would it be a good idea to put this information in the Initial State, and have something like:
Monkey(m) & Bananas(ba) & Box(bx) & Level(low) & Level(high) & Position(A) & Position(B) & Position(C) & At(m, A, low) & At(ba, B, high) & At(bx, C, low)
It looks quite verbose like that, but at the same time, it allows the reader to understand the scenario just through reading the Initial State. I've also been told that we should not be using constants anywhere in STRIPS, so I thought declaring the A, B, and C as Positions was a good idea.
Is it that some people do it differently (which I feel would kind of ruin the idea of having a standardized language to represent things), or is it that one of the ways I have presented isn't in the correct format? I am new to STRIPS, so it is entirely possible (and likely) that I am missing some key points.
This is not the greatest wikipedia ever. The description of STRIPS is accurate, but a little outdated.
Generally you don't need to worry about defining all the variables in the initial state because the variables are defined by the domain (the P in the quadruple in the linked article). For an intuition as to why, you have an operator for MONKEY in your initial state, but you're still introducing a free variable m that is not defined anywhere else. You end up with a chicken and egg problem if you try to do it that way, so instead the facts in the system are just propositional variables which are effectively sentinel values that mean something to the users of the system, not the system itself.
You are correct that you need to define the level for each item as part of the initial state, but the initial state of the example actually correct considering the constraints that the bananas are always high, the box is always low and the monkey is the only thing that changes level. I would probably change the example to have the At proposition take into account the object in question instead of using different proposition names for each object but that's just a style choice; the semantics are the same.
Operators in STRIPS are generally represented by 3 distinct components:
preconditions - each variable in the preconditions list must exactly match the corresponding variable in the current state (trues must be true, falses must be falses) but you ignore all other variables not explicit in the preconditions
add effects - when the action is performed, these are the effects that variables that are added to the state
delete effects - when the action is performed, these are the effects that are deleted from the state
and sometimes a 4th cost component when considering cost optimality
The post conditions listed in your example are the union of the add effects and delete effects. The advantage of separating them will come later when you get into delete relaxation abstractions.
In your proposed initial state you have propositions that contain multiple properties for the same object (e.g. At(bx, C, low)). This is typically avoided in favor of having a proposition for each property of each object in the state. Doing it this way makes you end up with a larger state, but makes for a much simpler implementation since you don't have to decompose a state variable in order to identify the value of a specific property of an object in the preconditions list.
Related
Say the agent is looking to perform a series of actions requiring different "targets" (picking up an item, eating a food, etc.). The way we chose to implement this is for each agent to store its current target as a field which can then be represented as key-value state (along with the other state) to be fed to the GOAP planner.
The problem arises if a series of actions requires the agent to let's say first eat a mushroom m and then go pick up a sword s. Ideally, the planner might find an action path similar to this:
locate m -> go to m -> pick up m -> eat m -> locate s -> go to s -> pick up s
Of course, we would like to generalize our actions as much as possible, so our current design has actions like goTo, pickUp, eat, etc. generalized to simply trust the preceding "locate x" action to have located a valid target.
In other words, locate x will have a promise state of target == x whereas an action like goTo will have the required state of hasTarget == true and a promise state of isNearTarget == true. A similar "generalized" set of requirements and goals are present for pickUp. The eat action will then have a requirement akin to holdingTarget == true and target == Food, while also setting target to null after the food has been consumed.
The big problem then is that what happens when m is eaten? How can the planner know that the next thing to locate is a sword and not something else? How can this be represented in GOAP-states in a way that ensures that the following actions will behave as expected?
One idea that came up was to divide actions into 3 categories:
Designating - Actions that promise to set the target to a thing (i.e. locateFood)
Intermediary - Actions that make generalized target promises (i.e. goTo)
Terminal - Actions that "consume" the target, nulling it (i.e. eat)
This approach then comes with the question of knowing what actions are terminal and which aren't, which seems like a nasty problem on its own.
I'm sorry if this is too abstracted and hard to understand - I'm trying to generalize the problem away from our specific code since I don't think it's something specific to our implementation, but likely a misunderstanding on our part of how state is supposed to be represented in GOAP. I can provide code as well as any clarification if needed.
First of all, it would be good if you showed some code.
Second, I'm hoping you've already looked at this goap demo
This should answer your question. Preconditions are to be met before an action is presented. So for example, if you require the AI to eat the muchroom m before picking up a sword, I would do something like this:
Eat mushroom action:
effect: "mushroomEaten" == true
Pick up sword action:
precondition: if "mushroomEaten" == true
then
effect: "goPickUpSword"
I have to generalize since your question is also general with no specific code example given. Look at the link provided and you will understand how actions can be chained together to accomplish a goal.
In an implementation of the Game of Life, I need to handle user events, perform some regular (as in periodic) processing and draw to a 2D canvas. The details are not particularly important. Suffice it to say that I need to keep track of a large(-ish) number of variables. These are things like: a structure representing the state of the system (live cells), pointers to structures provided by the graphics library, current zoom level, coordinates of the origin and I am sure a few others.
In the main function, there is a game loop like this:
// Setup stuff
while (!finished) {
while (get_event(&e) != 0) {
if (e.type == KEYBOARD_EVENT) {
switch (e.key.keysym) {
case q:
case x:
// More branching and nesting follows
The maximum level of nesting at the moment is 5. It quickly becomes unmanageable and difficult to read, especially on a small screen. The solution then is to split this up into multiple functions. Something like:
while (!finished {
while (get_event(&e) !=0) {
handle_event(state, origin_x, origin_y, &canvas, e...) //More parameters
This is the crux of the question. The subroutine must necessarily have access to the state (represented by the origin, the canvas, the live cells etc.) in order to function. Passing them all explicitly is error prone (which order does the subroutine expect them in) and can also be difficult to read. Aside from that, having functions with potentially 10+ arguments strikes me as a symptom of other design flaws. However the alternatives that I can think of, don't seem any better.
To summarise:
Accept deep nesting in the game loop.
Define functions with very many arguments.
Collate (somewhat) related arguments into structs - This really only hides the problem, especially since the arguments are only loosely related.
Define variables that represent the application state with file scope (static int origin_x; for example). If it weren't for the fact that it has been drummed into me that global variable are usually a terrible idea, this would be my preferred option. But if I want to display two views of the same instance of the Game of Life in the future, then the file scope no longer looks so appealing.
The question also applies in slightly more general terms I suppose: How do you pass state around a complicated program safely and in a readable way?
EDIT:
My motivations here are not speed or efficiency or performance or anything like this. If the code takes 20% longer to run as a result of the choice made here that's just fine. I'm primarily interested in what is less likely to confuse me and cause the least headache in 6 months time.
I would consider the canvas as one variable, containing a large 2D array...
consider static allocation
bool canvas[ROWS][COLS];
or dynamic
bool *canvas = malloc(N*M*sizeof(int));
In both cases you can refer to the cell at position i,j as canvas[i][j]
though for dynamic allocation, do not forget to free(canvas) at the end. You can then use a nested loop to update your state.
Search for allocating/handling a 2d array in C and examples or tutorials... Possibly check something like this or similar? Possibly this? https://www.geeksforgeeks.org/nested-loops-in-c-with-examples/
Also consider this Fastest way to zero out a 2d array in C?
When we converting from nfa to dfa there may be result like the image below... My question is, is it necessary to write that from state {4} it's going to Zero state? I mean that without showing the input symbol 1 of {4} is the same with picture below right? or no?
It’s a matter of convention. Personally, I prefer not to clutter my DFA with unnecessary states, especially since DFAs obtained via transformation from NFAs tend to become quite complex anyway, and since it’s deterministic we know that any non-displayed transition must be invalid.
However, I’ve experienced that many people in academia teach / use the other convention, and require all transitions to be explicitly shown. When working as a TA (tutor) I’ve actually had a discussion with a professor about this – he wanted us tutors to deduct points on the final tests for missing transitions in DFAs but I convinced him that deducting points for this was unfair.
it is not necessary to write {4}-> 0 transition because the automat is already accepting the word. this transition means only that this is "nothing" meaningful for our solution. but for details, it is useful to give it, to show the whole automaton.
It matters only if you are trying to draw the MinimalFA (MFA).
Actually you can generate infinite number of DFA s from a single NFA, each of which differ in number of states.
If you remove 'Dead States' in the figure,you will get the MFA.
The figure is OK if you just want a DFA
I am looking for an algorithm to convert a Deterministic Finite Automata to Push Down Automata.
Any help appreciated.
Thanks!
The PDA version of DFA would look the same except each state transition also pushes nothing on the stack and pops nothing off the stack.
Since a PDA is an extension of a DFA with just one additional feature : stack.
Because the transition of a PDA is determined by a triple (current state, input, element at the top of the stack) while transition of a DFA is determined by a tuple (current state, input). And the only difference is the element at the top of the stack. You can convert all the transitions of DFA by transforming the tuple to a triple, e (empty string) inserted as the element at the top of the stack
And after changing the state, push e (empty string) to the stack.
I'm answering this old question just in case someone else looks at it.
The conversions of DFA to PDA can be automated easily by just adding a stack. But there could be possible changes to the semantics of the DFA and after you change it that way manually you could end up in a PDA with less number of states. I faced this problem recently. Its somewhat like this,
In a system (not a compiler or anything like that) the code written earlier was written using an DFA due to some reasons. The transitions occur as the user progress through the code using various functions. After some time a new set of transitions functions arrived which can be used in any order. and also the state after any of these new functions can change back to previous state by one of these functions. The only way to solve this using FST was to add a large number of new states to support this behavior which i a huge amount of work. But instead I just changed from DFA to a PDA. The stack keeps track of the transitions very nicely and the problem is solved with far less number of states. Actually i only had to add N number of states where N is the number of new functions that arrived.
I do not know if someone can automate this kind of a process easily. But there you go, just in case someone is curious about it.
The wikipedia article says
Pushdown automata differ from finite
state machines in two ways:
They can use the top of the stack to decide which transition to
take.
They can manipulate the stack as part of performing a transition.
Pushdown automata choose a transition
by indexing a table by input signal,
current state, and the symbol at the
top of the stack. This means that
those three parameters completely
determine the transition path that is
chosen. Finite state machines just
look at the input signal and the
current state: they have no stack to
work with. Pushdown automata add the
stack as a parameter for choice.
...
Pushdown automata are equivalent to
context-free grammars: for every
context-free grammar, there exists a
pushdown automaton such that the
language generated by the grammar is
identical with the language generated
by the automaton, which is easy to
prove. The reverse is true, though
harder to prove: for every pushdown
automaton there exists a context-free
grammar such that the language
generated by the automaton is
identical with the language generated
by the grammar.
(this is a C-like environment) Say I have two instance objects, a car and a bodyShop. The car has a color iVar and corresponding accesors. The bodyShop has a method named "paintCar" that will take in a car object and change its color.
As far as implementation, in order to get the bodyShop to actually be able to change a car object's color, I see two ways to go about it.
Use the "&" operator to pass in a pointer to the car. Then the bodyShop can either tell the car to perform some method that it has to change color, or it can use the car's accessors directly.
Pass in the car object by value, do the same sort of thing to get the color changed, then have the method return a car object with a new color. Then assign the original car object to the new car object.
Option 1 seems more straightforward to me, but I'm wondering if it is in-line with OOP best practices. In general for "maximum OOP", is the "&" operator good or bad? Or, maybe I'm completely missing a better option that would make this super OOPer. Please advise :)
Option 1 is prefered:
The bodyShop can either tell the car
to perform some method that it has to
change color, or it can use the car's
accessors directly.
Even better still...create an IPaintable interface. Have Car implement IPaintable. Have BodyShop depend on IPaintable instead of Car. The benefits of this are:
Now BodyShop can paint anything that implements IPaintable (Cars, Boats, Planes, Scooters)
BodyShop is no longer tightly coupled to Car.
BodyShop has a more testable design.
I would assume that the responsibility of the bodyShop is to modify car objects, so #1 seems like the right way to go to me. I've never used a language where the "&" operator is necessary. Normally, my bodyShop object would call car.setColor(newColor) and that would be that. This way you don't have to worry about the rest of the original car's attributes, including persistence issues - you just leave them alone.
Since you're interested in the best OOP practice, you should ignore the performance hit you get with option 2. The only things you should be interested in is do either option unnecessarily increase coupling between the two classes, is encapsulation violated and is identity preserved.
Given this, option 2 is less desirable since you can't determine which other objects are holding references to the original car or worse, contain the car. In short you violate the identity constraint since two objects in the system may have different ideas of the state of the car. You run the risk of making the overall system inconsistent.
Of-course your particular environment may avoid this but it certainly would be best practice to avoid it.
Last point, does your bodyShop object have state; behaviour and identity? I realise that you have explained only the minimum necessary but possibly the bodyShop isn't really an object.
Functional v OO approaches
As an interesting aside, option 2 would close to the approach in a functional programming environment - since state changes are not allowed, your only approach would be to create a new car if it's colour changed. That's not quite what you're suggesting but it's close.
That may sound like complete overkill but it does have some interesting implications for proving the correctness of the code and parallelism.
Option 1 wins for me. The & operator is implicit in many OO languages (like Java, Python etc). You don't use "passing by value" in that languages often - only primitive types are passed in that way.
Option 2 comes with multiple problems: You might have a collection of cars, and some function unaware of it might send a car to bodyShop for painting, receive new car in return and don't update your collection of cars. See? And from more ideologic point of view - you don't create new object each time you want to modify it in real world - why should you do so in virtual one? This will lead to confusion, because it's just counterintuitive. :-)
I am not sure what this "C-like environment" mean. In C, you need this:
int paintCar(const bodyShop_t *bs, car_t *car);
where you modify the contents pointed by car. For big struct in C, you should always pass the pointer, rather than the value to a function. So, use solution 1 (if by "&" you mean the C operator).
I too agree with the first 1. I can't say it's best practice because i'm never really sure what best practice is in other peoples minds... I can tell you that best practice in my mind is the most simple method that works for the job. I've also seen this aproach taken in the hunspell win api and other c-ish api's that i've had to use. So yea i agree with scott.
http://hunspell.sourceforge.net/
//just in-case your interested in looking at other peoples code
It depends on whether the body shop's method can fail and leave the car in an indeterminate state. In that case, you're better off operating on a copy of the car, or a copy of all relevant attributes of the car. Then, only when the operation succeeds, you copy those values to the car. So you end up assigning the new car to the old car within the body shop method. Doing this correctly is necessary for exception safety in C++, and can get nasty.
It's also possible and sometimes desirable to use the other pattern - returning a new object on modification. This is useful for interactive systems which require Undo/Redo, backtracking search, and for anything involving modelling how a system of objects evolves over time.
In addition to other optinions, option 1 lets paintCar method return a completion code that indicates if the car has changed the color successfully or there were problems with it