108 lines
3.3 KiB
Plaintext
108 lines
3.3 KiB
Plaintext
:- object(buckets).
|
|
|
|
:- threaded.
|
|
|
|
:- public([start/0, start/4]).
|
|
|
|
% bucket representation
|
|
:- private(bucket_/2).
|
|
:- dynamic(bucket_/2).
|
|
|
|
% use the same mutex for all the predicates that access the buckets
|
|
:- private([bucket/2, buckets/1, transfer/3]).
|
|
:- synchronized([bucket/2, buckets/1, transfer/3]).
|
|
|
|
start :-
|
|
% by default, create ten buckets with initial random integer values
|
|
% in the interval [0, 10[ and print their contents ten times
|
|
start(10, 0, 10, 10).
|
|
|
|
start(N, Min, Max, Samples) :-
|
|
% create the buckets with random values in the
|
|
% interval [Min, Max[ and return their sum
|
|
create_buckets(N, Min, Max, Sum),
|
|
write('Sum of all bucket values: '), write(Sum), nl, nl,
|
|
% use competitive or-parallelism for the three loops such that
|
|
% the computations terminate when the display loop terminates
|
|
threaded((
|
|
display_loop(Samples)
|
|
; match_loop(N)
|
|
; redistribute_loop(N)
|
|
)).
|
|
|
|
create_buckets(N, Min, Max, Sum) :-
|
|
% remove all exisiting buckets
|
|
retractall(bucket_(_,_)),
|
|
% create the new buckets
|
|
create_buckets(N, Min, Max, 0, Sum).
|
|
|
|
create_buckets(0, _, _, Sum, Sum) :-
|
|
!.
|
|
create_buckets(N, Min, Max, Sum0, Sum) :-
|
|
random::random(Min, Max, Value),
|
|
asserta(bucket_(N,Value)),
|
|
M is N - 1,
|
|
Sum1 is Sum0 + Value,
|
|
create_buckets(M, Min, Max, Sum1, Sum).
|
|
|
|
bucket(Bucket, Value) :-
|
|
bucket_(Bucket, Value).
|
|
|
|
buckets(Values) :-
|
|
findall(Value, bucket_(_, Value), Values).
|
|
|
|
transfer(Origin, _, Origin) :-
|
|
!.
|
|
transfer(Origin, Delta, Destin) :-
|
|
retract(bucket_(Origin, OriginValue)),
|
|
retract(bucket_(Destin, DestinValue)),
|
|
% the buckets may have changed between the access to its
|
|
% values and the calling of this transfer predicate; thus,
|
|
% we must ensure that we're transfering a legal amount
|
|
Amount is min(Delta, OriginValue),
|
|
NewOriginValue is OriginValue - Amount,
|
|
NewDestinValue is DestinValue + Amount,
|
|
assertz(bucket_(Origin, NewOriginValue)),
|
|
assertz(bucket_(Destin, NewDestinValue)).
|
|
|
|
match_loop(N) :-
|
|
% randomly select two buckets
|
|
M is N + 1,
|
|
random::random(1, M, Bucket1),
|
|
random::random(1, M, Bucket2),
|
|
% access their contents
|
|
bucket(Bucket1, Value1),
|
|
bucket(Bucket2, Value2),
|
|
% make their new values approximately equal
|
|
Delta is truncate(abs(Value1 - Value2)/2),
|
|
( Value1 > Value2 ->
|
|
transfer(Bucket1, Delta, Bucket2)
|
|
; Value1 < Value2 ->
|
|
transfer(Bucket2, Delta, Bucket1)
|
|
; true
|
|
),
|
|
match_loop(N).
|
|
|
|
redistribute_loop(N) :-
|
|
% randomly select two buckets
|
|
M is N + 1,
|
|
random::random(1, M, FromBucket),
|
|
random::random(1, M, ToBucket),
|
|
% access bucket from where we transfer
|
|
bucket(FromBucket, Current),
|
|
Limit is Current + 1,
|
|
random::random(0, Limit, Delta),
|
|
transfer(FromBucket, Delta, ToBucket),
|
|
redistribute_loop(N).
|
|
|
|
display_loop(0) :-
|
|
!.
|
|
display_loop(N) :-
|
|
buckets(Values),
|
|
write(Values), nl,
|
|
thread_sleep(2),
|
|
M is N - 1,
|
|
display_loop(M).
|
|
|
|
:- end_object.
|