Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accumulating while in recursion/backtracking

Tags:

prolog

I run into this beginners problem, and i don't know how to solve this. Here is my code:

worker( w1, d1, 2000 ) .    
worker( w2, d1, 2500 ) .
worker( w2, d2, 1000 ) .
worker( w3, d2, 2000 ) .
worker( w4, d2, 4000 ) .

% worker( W, D, S ) means that worker W works in department D and has salary S

department( d1, w2 ) .
department( d2, w4 ) .

% department( D, B ) means that worker B is director of department D(this is not important in this case)

I need to get sum of all salaries form one of department, like this:

?- department_costs( d1 , T ) .
T = 4500;
no
?- department_costs( D, T ) .
D = d1
T = 4500;
D = d2
T = 7000;
no
?- department_costs( d3 , T ) .
no

I tried this:

department_costs( D, T ):- worker( _X, D, T1 ), T is T1.

And I get this:

?- department_costs( o1, T ).
T=2000;
T=2500;
no

now I need to sum T+T for total costs, but I don't know how to do that. I would like to solve this without using findall/setof/bagof.

EDIT:

I tried with findall:

sumL([], 0).
sumL([G|R], S):-
   sumL(R, S1),
   S is S1 + G.

department_costs( D, T ):-
   findall(P, worker( _X, D, P ), R ),
   sumL(R, S),
   T=S.

It works fine with department_costs( d1, T ), and department_costs( d2, T ), but when I enter department_costs( D, T ). i get this:

 department_costs( D, T ).
 O=_h159
 T=11500

and it should be like this:

 ?- department_costs( D, T ) .
 D = d1
 T = 4500;
 D = d2
 T = 7000;

can someone tell what is the problem now?

like image 365
user1598696 Avatar asked Aug 07 '26 21:08

user1598696


2 Answers

Wanting to solve this without findall/3 will just result in a poor attempt at recoding said findall/3. If you really wanna skip findall/3, represent your data in a different way, for example:

workers([w1-d1-2000, w2-d1-2500, w2-d2-1000, w3-d2-2000, w4-d2-4000]).
departments([d1-w2, d2-w4]).

In this format you will be able to use recursion and list processing techniques to achieve a good result. In the previous one you will have to go with either database manipulation and/or global variables. Not really Prolog-ish.

For your edit, the problem is that you use findall/3, and that findall/3 will give you all the results for the one variable you're interested in, but will not precise the bindings that led to those results.

Try bagof/3 instead:

bagof(S, W^worker( W, D, S ), R ).

And see this man page (even if it's SWI, those are ISO Prolog predicates anyway) for more information.

like image 177
m09 Avatar answered Aug 10 '26 11:08

m09


library(aggregate) is meant to solve exactly such kind of problems. It's worth to study.

department_costs( D, T ) :- aggregate_all(sum(C), worker( _, D, C ), T).

edit

XSB has 'Tabling Aggregate Predicates' that should allow you to solve efficiently your problem.

like image 22
CapelliC Avatar answered Aug 10 '26 13:08

CapelliC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!