I am looking for suggestions about design patterns for how to describe systems of equations in Prolog, where each equation is a general statement about classes of objects and points in time.
Say that i have: A = 0.5 * B + C^2, and B = 5 * D. Given, e.g. D = 1 and C = 12, I want Prolog to compute the value of A. But I want to do this in a case where A, B, C, and D are general classes of objects and time. The code below is working but I find it to wordy, specially the description predicate in the body of the causes predicate (I have longer description predicates than in the example). My goal is also to have code which is transparent and easy to read for somebody else.
Does anybody have suggestions for how problems such as the one in my example code can be represented?
Thanks!
predator(fox).
predator(lion).
prey(rabbit).
prey(deer).
time(1).
time(2).
time(3).
value(description(fox, at, 1), 100).
value(Description, Value):-
causes(
_,
variable(name(_), value(Value), Description)
).
causes(
variable(name(predators), value(X), description(Predator, at, Time1)),
variable(name(prey), value(Y), description(Prey, at, Time2))
)
:-
predator(Predator), prey(Prey), time(Time1), time(Time2), Time2 > Time1,
value(description(Predator, at, Time1), X), Y is 10 / X.
causes(
variable(name(prey), value(X), description(Prey, at, Time1)),
variable(name(predators), value(Y), description(Predator, at, Time2))
)
:-
predator(Predator), prey(Prey), time(Time1), time(Time2), Time2 > Time1,
value(description(Prey, at, Time1), X), Y is 20 / X.
EDIT 1: An example call to the above knowledge base:
?-causes(A, B).
e.g. returns:
A = variable(name(predators), value(100), description(fox, at, 1)),
B = variable(name(prey), value(0.1), description(rabbit, at, 3))
EDIT 2: An example with three variables:
relation(
effect(variable(name(prey), value(Y), description(Prey, at, Time2))),
causes([
variable(name(predators), value(X), description(Predator, at, Time1)),
variable(name(amountOfFood), value(Z), description(Food, at, Time1))
])
)
:-
predator(Predator), prey(Prey), time(Time1), time(Time2), Time2 > Time1, food(Food),
value(description(Predator, at, Time1), X), value(description(Food, at, Time1), Z),
Y is 20 / X * 3 * Z.
A way to go seems to use constraints and to instantiate some variables, e.g.
Which, given e.g. the goal:
Yields:
...and so on.
My first piece of advice is probably obvious to you, which is just to reduce the amount of matching going on in the head with some predicates:
Then you can simplify some of your predicates like so:
This "simplification" is of somewhat dubious value.
Another thing, it occurs to me as I'm writing, is that maybe you don't need as much wrapping around your functor arguments as you have. Would you be content with something like this?
Another approach that I think would be profitable would be to write these predicates ignoring Prolog at first, as if you had a special programming language of your own custom devising and see what you come up with. Then perhaps you can find a way to bridge between the two using a interpreter or even a custom metainterpreter. For instance, maybe your time handling is always the same. If so you could factor it out completely with some code that might look like this:
Such things are possible if you define new operators with the right precedence orders; the table of existing operators is given in the documentation. You could create some custom operators for these and devise a way to evaluate these expressions by converting a bare atom class into something akin to
variable(Class, Name, Value, _)
and have it automatically advance the clock by one step. You could even go further and have it first try as a class and map over the results, or else try using it as a specific name.