System State in Prolog - prolog

I have a small program that runs in python. Basically, it has a pretty simple loop: Query a Prolog program, do something with the result, change some state back in Prolog.
I have written a logical way (no mutations) to change a state in Prolog.
The queries use a state as their argument, and result in a new state. The question is, where do I store the new state?
I can pass it back and forth from Prolog to Python, but as the state grows large it might become problematic.
I can also store a global variable, but that seems like a bad solution.
This is the basic flow of my program:
some_query(OldState, NewState) :-
% do some stuff here
python code:
state = '[]'
while Not_Exit:
query = MyLogic(state) # state is not actually used here (python-wise), just to pass it to prolog
result = prologBridge.Query(query)
state = result["NewState"] # how do I change that in Prolog without passing the state back and forth?
EDIT:
The state contains a list of terms, and state changes revolve around adding and removing terms. For example. S1 = [T1, T2, T3] changes into S2 = [T2, T3, T4].

Possible solutions:
Store state or other facts in a file that you reconsult in Prolog.
Use data bases to persist state
Keep Prolog running as a separate process in the background, then current state should be available.
What is your choice ? what about functional programming ?

As long as each query runs in the same Prolog session (i.e., you don't start a new Prolog each time), you can use Prolog's built-in database. This is a store of "dynamic" Prolog clauses that can be modified at runtime.
You declare a dynamic predicate using a :- dynamic directive. You remove old facts using rectract or retractall and assert new ones using asserta or assertz. Querying a dynamic predicate is done by calling it as usual.
For example, you can declare your state like this:
:- dynamic mystate/1.
A predicate querying the state, computing the next one, and updating the database, looks like this:
query_and_update_state :-
mystate(OldState),
some_query(OldState, NewState),
write('new state: '),
write(NewState),
nl,
retractall(mystate(_)),
asserta(mystate(NewState)).
This assumes the existence of your some_query predicate. Some initial state must be set at the beginning as well. For example, if the state is just a counter:
init_state :-
retractall(mystate(_)),
asserta(mystate(0)).
some_query(Old, New) :-
succ(Old, New).
Running this interactively:
?- init_state.
true.
?- query_and_update_state.
new state: 1
true.
?- query_and_update_state.
new state: 2
true.
?- query_and_update_state.
new state: 3
true.
?- query_and_update_state.
new state: 4
true.
Your Python code would call init_state once and then call query_and_update_state repeatedly, presumably for some side effect. (It's not clear to me from your question.)
Caveat: If you're worried about the costs of copying the state, you might not be happy about this either. Asserting a state and querying it both involve making a complete deep copy of the data structure. Such a Prolog-Prolog copy might indeed be cheaper than a Prolog-Python copy. But depending on your Python-Prolog bridge, maybe it doesn't make a deep copy and could be cheaper? I don't know.

Related

Prolog: Storing result of an operation

just started programming with prolog and I'm having a few issues. I wanna store the result on an operation , for example:
transformer(kilo,1000).
transformer(hecto,100).
transformer(deca,10).
transformer(unite,1).
transformer(deci,0.1).
transformer(centi,0.01).
transformer(milli,0.001).
transformerT(sec,1).
transformerT(min,60).
transformerT(h,3600).
plus(V1,U,V2,U,UniteType,R,U) :-
dif(UniteType,temps),R is V1+V2.
plus(V1,U1,V2,U2,UniteType,R,unite) :-
dif(UniteType,temps),
dif(U1,U2),
trans(U1,Res1),
trans(U2,Res2),
R is V1*Res1+V2*Res2.
I want to store the result of this operation to call it later (like the ANS or M Buttons in a calculator) in another operation. Is it Possible?
If you want the information to survive a program termination (i.e. a return to the Prolog REPL, aka. toplevel) you can use predicates asserta/2 and assertz/2.
See this section for SWI Prolog, should be similar for SICStus: Database
Alternatively you may want to keep the program "alive" and store information in a term that is passed between predicates. Association lists library(assoc) or, for SWI Prolog, built-in dicts, or simpler data structure like lists can be used for that.

Prolog - Update a value in list of list

I have a fact :
available_resources([[r1, 0], [r2, 0]]).
I need when a specified condition is true increase the zero by 1 . like:
release(X):-
allocated(X , R1):-
increase r1 by one
I don't know how to update a fact.
You are asking about "changeable state". As in functional languages (i.e. LISP et al.), this is harder to come by in Prolog! (For a functional view in the context of Clojure, see Values and Change: Clojure’s approach to Identity and State)
What you can do is have a specific value for "time". Then you can have facts in the Prolog database like these:
available_resources(10, [this, and, that]).
available_resources(20, [hither, and, yon]).
Here we state that at time 10, the resources were [this, and, that], and at time 20, the resources were [hither, and, yon].
Then you can use assertz to add facts to the database and retract to remove old ones.
release(X) :- available_resources(Tprev, Rprev),
compute_new_resource_term(X,Rprev,Rcur),
% get current time from an extralogical oracle
get_time(Tcur),
retract(available_resources(Tprev, Rprev)),
assertz(available_resources(Tcur,Rcur)).
But if you do not need to have the "resources" term survive across program runs (i.e. through a return to the toplevel), you wuld just construct new terms and hand them from predicate to predicate without storing them in the database.

How to check whether some variable returns something in predicate

Lets assume I have facts as follows:
airport(nyc,'newyork').
I want want to display a message if the user inputs an airport that doesn't exist.
My Attempt:
isAirport(Air) :-
airport(Air,T),
(var(T) -> true
;
write('Airport not found'),
fail
).
However, this doesn't seem to work.
First let's see what happens if you query a conjunction (the , operator) first:
?- airport(nyc, _), write('found!').
found!
true.
?- airport(abc, _), write('found!').
false.
This means, isAirport(abc) directly fails after trying airport(abc,_) without the rest of your predicate being evaluated. In many cases, you can therefore get by without an explicit if-then-else construct and just write something of the form
predicate(X) :-
first_condition(X),
second_condition(X).
and it will only succeed if both conditions are fulfilled for X.
In case you really want to create some user interface, this is a bit more tricky, because I/O is inherently non-logical, in particular when there is backtracking involved. We usually call a program which behaves like we would expect from a logical formula pure and when it contains non-logical constructs like I/O or the cut operator ! are called impure.
Unfortunately, the if-then-else construct (-> and ;) and negation (\+) are implemented via cut and therefore impure as well. Luckily, most of the time people want a conditional, a pure disjunction is sufficient:
case(1,a).
case(2,b).
We have an automatic branching from the execution mechanism of Prolog:
?- case(X,Y).
X = 1,
Y = a ;
X = 2,
Y = b.
But sometimes we really want to do something that needs the impure constructs, like user input. Then the easiest way to keep the nice logical properties of our program is to separate the task into pure and impure ones:
main :-
uinput(Data),
pure_predicate(Data, Result),
write(Result).
After we have done all the impure parts, Data is unified with the user data we wanted. Let's have a look at the implementation of uinput/1:
uinput(data(Airport,D-M-Y)) :-
format('~nAirport? '),
read(Airport),
( ground(Airport), airport(Airport, _) )
->
(
format('~nDay? '),
read(D),
format('~nMonth? '),
read(M),
format('~nYear? '),
read(Y),
( ground(D-M-Y), isDate(D-M-Y) )
->
true
;
throw(failure('unknown date'))
)
;
throw(failure('unknown airport'))
.
We successively read terms from the input and throw an exception if we can't handle it. For the if-then-else construct to work, we need to take special care. If we compare the two queries:
?- between(1,3,X), write(X).
1
X = 1 ;
2
X = 2 ;
3
X = 3.
and
?- between(1,3,X) -> write(X); false.
1
X = 1.
you can see that the if-then-else is losing solutions. This means we need to make sure that our condition is deterministic. Asking for a user input term to be ground is already a good idea, because without variables, there is only one solution term. Still, a call to one of the data-predicates airport/1 and isDate/1 might generate the same term multiple times or not terminate at all. In this particular case, we just need to make sure that each airport has a unique shortcut name, we can also generate dates without repetition:
airport(nyc, 'New York City').
airport(wdc, 'Washington DC').
isDate(X-Y-Z) :-
between(1,31,X),
between(1,12,Y),
between(1970,2100,Z).
Another trick in the implementation of uinput is that we just succeed with true when we have validated everything. The only effect of is now that Data is instantiated with whatever the user entered.
If we give a dummy implementation of the actual implementation, we can already try the implementation oursevles:
pure_predicate(_Data, Result) :-
% here goes the actual stuff
Result='we have found something awesome'.
On the prompt we can use the pure predicate without trouble:
?- pure_predicate(someinputdata,Y).
Y = 'we have computed something awesome'.
On the other hand, we can also use the full predicate as follows:
?- main(_).
Airport? wdc.
Day? |: 1.
Month? |: 2.
Year? |: 2000.
we have found something awesome
true.
Since we are using read, we have to input prolog terms and terminate with a dot ., but everything worked as expected.
In case the user input fails, we get:
?- main(_).
Airport? bla(X).
ERROR: Unhandled exception: failure('unknown airport')
Please note that we only went through this trouble to actually fail early and give a user message in that case. For the actual computation, this is completely unneccessary.
In the code below you are making false assumption that T will remain unbound in case if airport will not be found in database:
airport(Air, T)
What happens actually is that call to airport(Air, T) will make isAirport(Air) to fail immediately and your var(T) and other parts will not be executed at all.
Try this code instead:
isAirport(Air) :-
airport(Air, _T), ! ; write('Airport not found'), fail.

In Prolog (SWI), how to build a knowledge base of user supplied pairs and assert to be equal

I am very new to Prolog and trying to learn.
For my program, I would like to have the user provide pairs of strings which are "types of".
For example, user provides at command line the strings "john" and "man". These atoms would be made to be equal, i.e. john(man).
At next prompt, then user provides "man" and "tall", again program asserts these are valid, man(tall).
Then the user could query the program and ask "Is john tall?". Or in Prolog: john(tall) becomes true by transitive property.
I have been able to parse the strings from the user's input and assign them to variables Subject and Object.
I tried a clause (where Subject and Object are different strings):
attribute(Subject, Object) :-
assert(term_to_atom(_ , Subject),
term_to_atom(_ , Object)).
I want to assert the facts that Subject and Object are valid pair. If the user asserts it, then they belong to together. How do I force this equality of the pairs?
What's the best way to go about this?
Questions of this sort have been asked a lot recently (I guess your professors all share notes or something) so a browse through recent history might have been productive for you. This one comes to mind, for instance.
Your code is pretty wide of the mark. This is what you're trying to do:
attribute(Subject, Object) :-
Fact =.. [Object, Subject],
assertz(Fact).
Using it works like this:
?- attribute(man, tall).
true.
?- tall(X).
X = man.
So, here's what you should notice about this code:
We're using =../2, the "univ" operator, to build structures from lists. This is the only way to create a fact from some atoms.
I've swapped subject and object, because doing it the other way is almost certainly not what you want.
The predicate you want is assertz/1 or asserta/1, not assert/2. The a and z on the end just tells Prolog whether you want the fact at the beginning or end of the database.
Based on looking at your code, I think you have a lot of baggage you need to shed to become productive with Prolog.
Prolog predicates do not return values. So assert(term_to_atom(... wasn't even on the right track, because you seemed to think that term_to_atom would "return" a value and it would get substituted into the assert call like in a functional or imperative language. Prolog just plain works completely differently from that.
I'm not sure why you have an empty variable in your term_to_atom predicates. I think you did that to satisfy the predicate's arity, but this predicate is pretty useless unless you have one ground term and one variable.
There is an assert/2, but it doesn't do what you want. It should be clear why assert normally only takes one argument.
Prolog facts should look like property(subject...). It is not easy to construct facts and then query them, which is what you'd have to do using man(tall). What you want to say is that there is a property, being tall, and man satisfies it.
I would strongly recommend you back up and go through some basic Prolog tutorials at this point. If you try to press forward you're only going to get more lost.
Edit: In response to your comment, I'm not sure how general you want to go. In the basic case where you're dealing with a 4-item list with [is,a] in the middle, this is sufficient:
build_fact([Subject,is,a,Object], is_a(Subject, Object)).
If you want to isolate the first and last and create the fact, you have to use univ again:
build_fact([Subject|Rest], Fact) :-
append(PredicateAtoms, [Object], Rest),
atomic_list_concat(PredicateAtoms, '_', Predicate),
Fact =.. [Predicate, Subject, Object].
Not sure if you want to live with the articles ("a", "the") that will wind up on the end though:
?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)
Don't do variable fact heads. Prolog works best when the set of term names is fixed. Instead, make a generic place for storing properties using predefined, static term name, e.g.:
is_a(john, man).
property(man, tall).
property(john, thin).
(think SQL tables in a normal form). Then you can use simple assertz/1 to update the database:
add_property(X, Y) :- assertz(property(X, Y)).

Prolog Relational Tracking without Lists

I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.
For example,
let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.
Prolog Code
mailRoom(m).
gotFrom(annie,brock).
gotFrom(brock,cara).
gotFrom(cara,daniel).
gotFrom(daniel,m).
gotFrom(X,Y) :- gotFrom(Y,_).
So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.
Unfortunately when I run this predicate, it reads out,
Who = annie.
Who = brock.
Who = cara.
etc.etc....
I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.
I tried using a backcut (!) in my program but it gives me the same error.
Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.
Thanks.
I'm afraid this rule is meaningless:
gotFrom(X,Y) :- gotFrom(Y,_).
There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:
?- gotFrom([1,2,3], dogbert).
true ;
true ;
What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:
gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).
This produces an interesting result:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack
The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.
got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).
gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).
This gives us the desired behavior:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.
Notice this one is resilient to my attack of meaningless data:
?- gotFrom([1,2,3], dogbert).
false.
Some general advice:
Never ignore singleton variable warnings. They are almost always a bug.
Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.

Resources