Logtalk 2.30.7 files.
git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1973 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -8,8 +8,14 @@ Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
|
||||
This folder contains some examples of multi-threading programming.
|
||||
Multi-threading programming is only supported on some Prolog compilers.
|
||||
Currently this includes SWI-Prolog and YAP (make sure that you use the
|
||||
multi-threading versions of these Prolog compilers!). Moreover,
|
||||
multi-threading may be turned off by default. In order to run the
|
||||
examples, you may need to first turn on multi-threading support on the
|
||||
Prolog config files.
|
||||
Currently this includes SWI-Prolog, YAP, and XSB CVS (make sure that you
|
||||
use the multi-threading versions of these Prolog compilers!). Moreover,
|
||||
multi-threading may be turned off by default. In order to run the examples,
|
||||
you may need to first turn on multi-threading support on the Prolog config
|
||||
files.
|
||||
|
||||
Some of the examples try to benchmark single-threaded and multi-threaded
|
||||
solutions. Depending on the Prolog compiler, the operating-system, and the
|
||||
computer used, you may need to adjust the size of the problem data in order
|
||||
to find the threshold where multi-threading solutions begin to outperform
|
||||
the single-threaded solutions.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,4 +1,4 @@
|
||||
|
||||
:- initialization((
|
||||
logtalk_load(library(random_loader), [reload(skip)]),
|
||||
logtalk_load(library(random_loader), [reload(skip)]), % allow for static binding
|
||||
logtalk_load(blackboard))).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -14,25 +14,55 @@ Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
|
||||
% start the producer and the consumer, each one running in its own thread:
|
||||
|
||||
| ?- threaded_ignore(producer::run(10)), threaded_ignore(consumer::run(10)).
|
||||
| ?- threaded_ignore(producer(2)::run(25)), threaded_ignore(consumer(5)::run(25)).
|
||||
|
||||
producer wrote item 0
|
||||
consumer read item 0
|
||||
producer wrote item 1
|
||||
consumer read item 1
|
||||
producer wrote item 2
|
||||
consumer read item 2
|
||||
producer wrote item 3
|
||||
consumer read item 3
|
||||
producer wrote item 4
|
||||
consumer read item 4
|
||||
producer wrote item 5
|
||||
consumer read item 5
|
||||
producer wrote item 6
|
||||
consumer read item 6
|
||||
producer wrote item 7
|
||||
consumer read item 7
|
||||
producer wrote item 8
|
||||
consumer read item 8
|
||||
producer wrote item 9
|
||||
consumer read item 9
|
||||
produced item 0 (1/7 items in the buffer)
|
||||
consumed item 0 (0/7 items in the buffer)
|
||||
produced item 1 (1/7 items in the buffer)
|
||||
produced item 2 (2/7 items in the buffer)
|
||||
produced item 3 (3/7 items in the buffer)
|
||||
produced item 4 (4/7 items in the buffer)
|
||||
consumed item 1 (3/7 items in the buffer)
|
||||
produced item 5 (4/7 items in the buffer)
|
||||
produced item 6 (5/7 items in the buffer)
|
||||
produced item 7 (6/7 items in the buffer)
|
||||
consumed item 2 (5/7 items in the buffer)
|
||||
produced item 8 (6/7 items in the buffer)
|
||||
consumed item 3 (5/7 items in the buffer)
|
||||
produced item 9 (6/7 items in the buffer)
|
||||
consumed item 4 (5/7 items in the buffer)
|
||||
produced item 10 (6/7 items in the buffer)
|
||||
consumed item 5 (5/7 items in the buffer)
|
||||
produced item 11 (6/7 items in the buffer)
|
||||
produced item 12 (7/7 items in the buffer)
|
||||
consumed item 6 (6/7 items in the buffer)
|
||||
produced item 13 (7/7 items in the buffer)
|
||||
consumed item 7 (6/7 items in the buffer)
|
||||
produced item 14 (7/7 items in the buffer)
|
||||
consumed item 8 (6/7 items in the buffer)
|
||||
produced item 15 (7/7 items in the buffer)
|
||||
consumed item 9 (6/7 items in the buffer)
|
||||
produced item 16 (7/7 items in the buffer)
|
||||
consumed item 10 (6/7 items in the buffer)
|
||||
produced item 17 (7/7 items in the buffer)
|
||||
consumed item 11 (6/7 items in the buffer)
|
||||
produced item 18 (7/7 items in the buffer)
|
||||
consumed item 12 (6/7 items in the buffer)
|
||||
produced item 19 (7/7 items in the buffer)
|
||||
consumed item 13 (6/7 items in the buffer)
|
||||
produced item 20 (7/7 items in the buffer)
|
||||
consumed item 14 (6/7 items in the buffer)
|
||||
produced item 21 (7/7 items in the buffer)
|
||||
consumed item 15 (6/7 items in the buffer)
|
||||
produced item 22 (7/7 items in the buffer)
|
||||
consumed item 16 (6/7 items in the buffer)
|
||||
produced item 23 (7/7 items in the buffer)
|
||||
consumed item 17 (6/7 items in the buffer)
|
||||
produced item 24 (7/7 items in the buffer)
|
||||
consumed item 18 (6/7 items in the buffer)
|
||||
consumed item 19 (5/7 items in the buffer)
|
||||
consumed item 20 (4/7 items in the buffer)
|
||||
consumed item 21 (3/7 items in the buffer)
|
||||
consumed item 22 (2/7 items in the buffer)
|
||||
consumed item 23 (1/7 items in the buffer)
|
||||
consumed item 24 (0/7 items in the buffer)
|
||||
|
@@ -2,21 +2,19 @@
|
||||
:- object(buffer(_MaxCapacity)).
|
||||
|
||||
:- info([
|
||||
version is 2.0,
|
||||
version is 2.1,
|
||||
author is 'Paulo Moura',
|
||||
date is 2007/6/20,
|
||||
date is 2007/9/16,
|
||||
comment is 'Producer-consumer problem with a bounded buffer.']).
|
||||
|
||||
:- threaded.
|
||||
|
||||
:- public(put/1).
|
||||
:- dynamic(put/1).
|
||||
:- mode(put(?integer), one).
|
||||
:- info(put/1, [
|
||||
comment is 'Put an item in the buffer.']).
|
||||
|
||||
:- public(get/1).
|
||||
:- dynamic(get/1).
|
||||
:- mode(get(?integer), one).
|
||||
:- info(get/1, [
|
||||
comment is 'Get an item from the buffer.']).
|
||||
@@ -29,6 +27,26 @@
|
||||
|
||||
size_(0).
|
||||
|
||||
:- synchronized([put_item/1, get_item/1]).
|
||||
|
||||
put_item(Item) :-
|
||||
parameter(1, MaxCapacity),
|
||||
assertz(item_(Item)),
|
||||
retract(size_(N)),
|
||||
N2 is N + 1,
|
||||
assertz(size_(N2)),
|
||||
write(' produced item '), write(Item),
|
||||
write(' ('), write(N2), write('/'), write(MaxCapacity), write(' items in the buffer'), write(')'), nl.
|
||||
|
||||
get_item(Item) :-
|
||||
parameter(1, MaxCapacity),
|
||||
retract(item_(Item)),
|
||||
retract(size_(N)),
|
||||
N2 is N - 1,
|
||||
assertz(size_(N2)),
|
||||
write(' consumed item '), write(Item),
|
||||
write(' ('), write(N2), write('/'), write(MaxCapacity), write(' items in the buffer'), write(')'), nl.
|
||||
|
||||
put(Item) :-
|
||||
parameter(1, MaxCapacity),
|
||||
size_(N),
|
||||
@@ -55,24 +73,6 @@
|
||||
)
|
||||
).
|
||||
|
||||
:- synchronized([put_item/1, get_item/1]).
|
||||
|
||||
put_item(Item) :-
|
||||
assertz(item_(Item)),
|
||||
retract(size_(N)),
|
||||
N2 is N + 1,
|
||||
assertz(size_(N2)),
|
||||
sender(Sender),
|
||||
writeq(Sender), write(' stored item '), write(Item), nl.
|
||||
|
||||
get_item(Item) :-
|
||||
retract(item_(Item)),
|
||||
retract(size_(N)),
|
||||
N2 is N - 1,
|
||||
assertz(size_(N2)),
|
||||
sender(Sender),
|
||||
writeq(Sender), write(' consumed item '), write(Item), nl.
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
|
||||
:- initialization((
|
||||
logtalk_load(library(random_loader), [reload(skip)]),
|
||||
logtalk_load(library(random_loader), [reload(skip)]), % allow for static binding
|
||||
logtalk_load(buffer))).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -14,31 +14,31 @@ Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
|
||||
% find the roots of some functions using each one of provided methods:
|
||||
|
||||
| ?- bisection::find_root(f1, 1.0, 2.3, 1e-15, Zero).
|
||||
| ?- bisection::find_root(f1, 1.0, 2.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 2.0
|
||||
yes
|
||||
|
||||
| ?- newton::find_root(f1, 1.0, 2.3, 1e-15, Zero).
|
||||
| ?- newton::find_root(f1, 1.0, 2.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 2.0
|
||||
yes
|
||||
| ?- muller::find_root(f1, 1.0, 2.3, 1e-15, Zero).
|
||||
| ?- muller::find_root(f1, 1.0, 2.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 2.0
|
||||
yes
|
||||
|
||||
| ?- bisection::find_root(f2, 1.0, 1.3, 1e-15, Zero).
|
||||
| ?- bisection::find_root(f2, 1.0, 1.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 1.25809265664599
|
||||
yes
|
||||
|
||||
| ?- newton::find_root(f2, 1.0, 1.3, 1e-15, Zero).
|
||||
| ?- newton::find_root(f2, 1.0, 1.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 1.25809265664599
|
||||
yes
|
||||
|
||||
| ?- muller::find_root(f2, 1.0, 1.3, 1e-15, Zero).
|
||||
| ?- muller::find_root(f2, 1.0, 1.3, 1.0e-15, Zero).
|
||||
|
||||
Zero = 1.25809265664599
|
||||
yes
|
||||
@@ -46,20 +46,26 @@ yes
|
||||
|
||||
% find the roots of some functions running all methods at once using multi-threading:
|
||||
|
||||
| ?- function_root::find_root(f1, 1.0, 2.3, 1e-15, Zero, Method).
|
||||
| ?- function_root::find_root(f1, 1.0, 2.3, 1.0e-15, Zero, Method).
|
||||
|
||||
Zero = 2.0
|
||||
Method = bisection
|
||||
yes
|
||||
|
||||
| ?- function_root::find_root(f2, 1.0, 1.3, 1e-15, Zero, Method).
|
||||
| ?- function_root::find_root(f2, 1.0, 1.3, 1.0e-15, Zero, Method).
|
||||
|
||||
Zero = 1.25809265664599
|
||||
Method = newton
|
||||
yes
|
||||
|
||||
| ?- function_root::find_root(f3, 0.0, 3.0, 1e-15, Zero, Method).
|
||||
| ?- function_root::find_root(f3, 0.0, 3.0, 1.0e-15, Zero, Method).
|
||||
|
||||
Zero = 1.4142135623731
|
||||
Method = newton
|
||||
yes
|
||||
|
||||
| ?- function_root::find_root(f4, -1.0, 2.0, 1.0e-15, Zero, Method).
|
||||
|
||||
Zero = -8.88178419700125e-16
|
||||
Method = bisection
|
||||
yes
|
||||
|
@@ -13,15 +13,10 @@
|
||||
comment is 'Find the root of a function in the interval [A, B] given a maximum aproximation error.',
|
||||
argnames is ['Function', 'A', 'B', 'Error', 'Zero']]).
|
||||
|
||||
:- public(find_root/6).
|
||||
:- mode(find_root(+object_identifier, +float, +float, +float, -float, -object_identifier), one).
|
||||
:- info(find_root/6, [
|
||||
comment is 'Find the root of a function in the interval [A, B] given a maximum aproximation error. Return the method used.',
|
||||
argnames is ['Function', 'A', 'B', 'Error', 'Zero', 'Method']]).
|
||||
|
||||
:- end_protocol.
|
||||
|
||||
|
||||
|
||||
:- protocol(functionp).
|
||||
|
||||
:- info([
|
||||
@@ -33,18 +28,19 @@
|
||||
:- public(eval/2).
|
||||
:- mode(eval(+float, -float), one).
|
||||
:- info(eval/2, [
|
||||
comment is 'Calculate the function value.',
|
||||
comment is 'Calculates the function value.',
|
||||
argnames is ['X', 'Fx']]).
|
||||
|
||||
:- public(evald/2).
|
||||
:- mode(evald(+float, -float), one).
|
||||
:- info(evald/2, [
|
||||
comment is 'Calculate the value of the function derivative.',
|
||||
comment is 'Calculates the value of the function derivative.',
|
||||
argnames is ['X', 'DFx']]).
|
||||
|
||||
:- end_protocol.
|
||||
|
||||
|
||||
|
||||
:- object(f1,
|
||||
implements(functionp)).
|
||||
|
||||
@@ -53,12 +49,14 @@
|
||||
|
||||
eval(X, Y) :-
|
||||
Y is X * X - 4.
|
||||
|
||||
evald(X, Y) :-
|
||||
Y is 2 * X.
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
||||
:- object(f2,
|
||||
implements(functionp)).
|
||||
|
||||
@@ -74,6 +72,7 @@
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
||||
:- object(f3,
|
||||
implements(functionp)).
|
||||
|
||||
@@ -89,41 +88,30 @@
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(function_root,
|
||||
implements(find_rootp)).
|
||||
|
||||
:- info([
|
||||
version is 1.1,
|
||||
author is 'Paulo Moura and Paulo Nunes',
|
||||
date is 2006/11/26,
|
||||
comment is 'Multi-threading interface to root finding algorithms.']).
|
||||
:- object(f4,
|
||||
implements(functionp)).
|
||||
|
||||
:- threaded.
|
||||
% x + x^2*sin(2.0/x)
|
||||
% 0.0
|
||||
|
||||
eval(X, Y) :-
|
||||
Y is X + (X**2)*sin(2.0/X).
|
||||
|
||||
find_root(Function, A, B, Error, Zero) :-
|
||||
find_root(Function, A, B, Error, Zero, _).
|
||||
|
||||
find_root(Function, A, B, Error, Zero, Algorithm) :-
|
||||
threaded_race(
|
||||
( try_method(bisection, Function, A, B, Error, Zero)
|
||||
; try_method(newton, Function, A, B, Error, Zero)
|
||||
; try_method(muller, Function, A, B, Error, Zero)
|
||||
)),
|
||||
threaded_exit(try_method(Algorithm, Function, A, B, Error, Zero)).
|
||||
|
||||
try_method(Algorithm, Function, A, B, Error, Zero) :-
|
||||
Algorithm::find_root(Function, A, B, Error, Zero).
|
||||
evald(X, Y) :-
|
||||
Y is 1 + 2*X*sin(2.0/X) - 2*cos(2.0/X).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
||||
:- object(bisection,
|
||||
implements(find_rootp)).
|
||||
|
||||
:- info([
|
||||
version is 1.1,
|
||||
version is 1.2,
|
||||
author is 'Paulo Moura and Paulo Nunes',
|
||||
date is 2006/11/26,
|
||||
date is 2007/7/7,
|
||||
comment is 'Bisection algorithm.']).
|
||||
|
||||
find_root(Function, A, B, Error, Zero) :-
|
||||
@@ -133,19 +121,15 @@
|
||||
true
|
||||
; Fa < 0.0, Fb > 0.0
|
||||
),
|
||||
X0 is (A + B) / 2,
|
||||
X0 is (A + B) / 2.0,
|
||||
Function::eval(X0, F0),
|
||||
bisection(Function, A, B, X0, F0, Error, Zero).
|
||||
|
||||
bisection(_, _, _, Xn1, 0.0, _, Xn1) :-
|
||||
bisection(_, _, _, Xn, Fn, Error, Xn) :-
|
||||
abs(Fn) < Error,
|
||||
!.
|
||||
|
||||
bisection(_, Xn1, Xn, _, _, Error, Xn1) :-
|
||||
abs(Xn1 - Xn) < Error,
|
||||
!.
|
||||
|
||||
bisection(Function, An, Bn, _, _, Error, Zero) :-
|
||||
Xn1 is (An + Bn) / 2,
|
||||
Xn1 is (An + Bn) / 2.0,
|
||||
Function::eval(Xn1, Fn1),
|
||||
Function::eval(An, FAn),
|
||||
( Fn1*FAn < 0.0 ->
|
||||
@@ -159,42 +143,29 @@
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
||||
:- object(newton,
|
||||
implements(find_rootp)).
|
||||
|
||||
:- info([
|
||||
version is 1.1,
|
||||
author is 'Paulo Moura and Paulo Nunes',
|
||||
date is 2006/11/26,
|
||||
version is 1.2,
|
||||
author is 'Paul Crocker... No More Coffee',
|
||||
date is 2007/07/06,
|
||||
comment is 'Newton algorithm.']).
|
||||
|
||||
find_root(Function, Xa, Xb, Deviation, Zero) :-
|
||||
X0 is (Xa + Xb) / 2,
|
||||
newton(Function, X0, Deviation, Zero).
|
||||
find_root(Function, Xa, Xb, Deviation, Zero) :-
|
||||
Ac is (Xb - Xa) / 2,
|
||||
newton(Function, Xa, Ac, Deviation, Zero).
|
||||
|
||||
newton(Function, X0, Deviation, Zero) :-
|
||||
Xn1 is X0,
|
||||
Function::eval(Xn1, Fn1),
|
||||
Function::evald(Xn1, DFn1),
|
||||
Ac is -(Fn1 / DFn1),
|
||||
newton(Function, Xn1, Deviation, Fn1, Ac, Zero).
|
||||
|
||||
% test deviation
|
||||
newton(_, Xn1, Deviation, _, Ac, Xn1) :-
|
||||
abs(Ac) < Deviation,
|
||||
newton(_, Zero, Ac, Deviation, Zero) :-
|
||||
abs(Ac) < Deviation,
|
||||
!.
|
||||
|
||||
% test solution
|
||||
newton(_, Xn1, _, 0.0, _, Xn1) :-
|
||||
!.
|
||||
|
||||
% calc
|
||||
newton(Function, Xn, Deviation, _, Ac, Zero) :-
|
||||
Xn1 is Xn + Ac,
|
||||
Function::eval(Xn1, Fn1),
|
||||
Function::evald(Xn1, DFn1),
|
||||
Ac1 is (-(Fn1 / DFn1)),
|
||||
newton(Function, Xn1, Deviation, Fn1, Ac1, Zero).
|
||||
newton(Function, X0, Ac, Deviation, Zero):-
|
||||
Xn1 is X0 + Ac,
|
||||
Function::eval(Xn1, Fx),
|
||||
Function::evald(Xn1, DFx),
|
||||
Ac2 is -(Fx/DFx),
|
||||
newton(Function, Xn1, Ac2, Deviation, Zero).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -203,66 +174,90 @@
|
||||
implements(find_rootp)).
|
||||
|
||||
:- info([
|
||||
version is 1.1,
|
||||
version is 1.2,
|
||||
author is 'Paulo Moura and Paulo Nunes',
|
||||
date is 2006/11/26,
|
||||
comment is 'Muller algorithm.']).
|
||||
|
||||
find_root(Function, Xa, Xb, Deviation, Zero) :-
|
||||
Xc is (Xa + Xb) / 2,
|
||||
Xc is (Xa + Xb) / 2.0,
|
||||
muller(Function, Xa, Xc, Xb, Deviation, Zero).
|
||||
|
||||
muller(Function, Xa, Xb, Xc, Deviation, Zero) :-
|
||||
Function::eval(Xa, Ya),
|
||||
Function::eval(Xb, Yb),
|
||||
Function::eval(Xc, Yc),
|
||||
H1 is (Xb - Xa),
|
||||
DDba is ((Yb - Ya) / H1),
|
||||
Ac is (Deviation + 1),
|
||||
H1 is Xb - Xa,
|
||||
DDba is (Yb - Ya) / H1,
|
||||
Ac is Deviation + 1.0,
|
||||
muller(Function, Xa, Xb, Xc, Deviation, Ya, Yb, Yc, Ac, H1, DDba, Zero).
|
||||
|
||||
% complex
|
||||
muller(_, _, _, complex, _, _, _, _, _, _, _, complex) :-
|
||||
!.
|
||||
|
||||
% test deviation
|
||||
muller(_, _, _, Xc, Deviation, _, _, _, Ac, _, _, Xc) :-
|
||||
abs(Ac) < Deviation,
|
||||
!.
|
||||
|
||||
% test solution
|
||||
muller(_, _, _, Xc, _, _, _, 0.0, _, _, _, Xc) :-
|
||||
!.
|
||||
|
||||
% calc
|
||||
muller(Function, Xa, Xb, Xc, Deviation, _, Yb, Yc, _, _, DDba, Zero) :-
|
||||
H2n is (Xc - Xb),
|
||||
DDcbn is ((Yc - Yb) / H2n),
|
||||
Cn is ((DDcbn - DDba) / (Xc - Xa)),
|
||||
Bn is (DDcbn + H2n * Cn),
|
||||
Rn is (Bn * Bn - 4.0 * Yc * Cn),
|
||||
% complex
|
||||
% write(Rn),
|
||||
H2n is Xc - Xb,
|
||||
DDcbn is (Yc - Yb) / H2n,
|
||||
Cn is (DDcbn - DDba) / (Xc - Xa),
|
||||
Bn is DDcbn + H2n * Cn,
|
||||
Rn is Bn * Bn - 4.0 * Yc * Cn,
|
||||
( Rn < 0.0 ->
|
||||
muller(Function, _, _, complex, Deviation, _, _, _, _, _, _, Zero),
|
||||
!, fail
|
||||
fail
|
||||
; V is sqrt(Rn)
|
||||
),
|
||||
( Bn > 0.0 ->
|
||||
Dn is (Bn + V)
|
||||
; Dn is (Bn - V)
|
||||
Dn is Bn + V
|
||||
; Dn is Bn - V
|
||||
),
|
||||
Acn is (-(2 * Yc / Dn)),
|
||||
Acn is -(2 * Yc / Dn),
|
||||
Xan is Xb,
|
||||
Xbn is Xc,
|
||||
Xcn is Xc + Acn,
|
||||
|
||||
Yan is Yb,
|
||||
Ybn is Yc,
|
||||
Function::eval(Xcn, Ycn),
|
||||
|
||||
H1n is H2n,
|
||||
DDban is DDcbn,
|
||||
muller(Function, Xan, Xbn, Xcn, Deviation, Yan, Ybn, Ycn, Acn, H1n, DDban, Zero).
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
|
||||
:- object(function_root,
|
||||
implements(find_rootp)).
|
||||
|
||||
:- info([
|
||||
version is 2.0,
|
||||
author is 'Paulo Moura and Paulo Nunes',
|
||||
date is 2007/07/05,
|
||||
comment is 'Multi-threading interface to root finding algorithms.']).
|
||||
|
||||
:- threaded.
|
||||
|
||||
:- public(find_root/6).
|
||||
:- mode(find_root(+object_identifier, +float, +float, +float, -float, -object_identifier), one).
|
||||
:- info(find_root/6, [
|
||||
comment is 'Finds the root of a function in the interval [A, B] given a maximum aproximation error. Returns the method used.',
|
||||
argnames is ['Function', 'A', 'B', 'Error', 'Zero', 'Method']]).
|
||||
|
||||
find_root(Function, A, B, Error, Zero, Algorithm) :-
|
||||
threaded((
|
||||
(bisection::find_root(Function, A, B, Error, Zero), Algorithm = bisection)
|
||||
; (newton::find_root(Function, A, B, Error, Zero), Algorithm = newton)
|
||||
; (muller::find_root(Function, A, B, Error, Zero), Algorithm = muller)
|
||||
)).
|
||||
|
||||
% an alternative, possibly better definition would be to make the methods simply fail in case of error:
|
||||
%
|
||||
% find_root(Function, A, B, Error, Zero, Algorithm) :-
|
||||
% threaded((
|
||||
% (catch(bisection::find_root(Function, A, B, Error, Zero), _, fail), Algorithm = bisection)
|
||||
% ; (catch(newton::find_root(Function, A, B, Error, Zero), _, fail), Algorithm = newton)
|
||||
% ; (catch(muller::find_root(Function, A, B, Error, Zero), _, fail), Algorithm = muller)
|
||||
% )).
|
||||
|
||||
find_root(Function, A, B, Error, Zero) :-
|
||||
find_root(Function, A, B, Error, Zero, _).
|
||||
|
||||
:- end_object.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -8,8 +8,5 @@ Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
|
||||
To load this example and for sample queries, please see the SCRIPT file.
|
||||
|
||||
This folder contains a simple multi-threading example with calculating
|
||||
prime numbers on a given interval. Try to run the example in single and
|
||||
multi-processor (or multi-core) computers and compare the results. Most
|
||||
Prolog compilers allows you to measure the time taken for proving a goal
|
||||
using proprietary predicates.
|
||||
This folder illustrates non-deterministic multi-threading calls and the
|
||||
use of tags to distinguish between multi-threading calls.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -42,3 +42,63 @@ yes
|
||||
|
||||
X = 1 ;
|
||||
no
|
||||
|
||||
|
||||
% when two or more variant calls are made...
|
||||
|
||||
| ?- threaded_call(lists::member(X, [1,2,3])), threaded_call(lists::member(Y, [1,2,3])).
|
||||
|
||||
X = _G189 Y =_G190
|
||||
yes
|
||||
|
||||
% ...the first threaded_exit/1 call will pick one of them:
|
||||
|
||||
| ?- threaded_exit(lists::member(X, [1,2,3])).
|
||||
|
||||
X = 1 ;
|
||||
X = 2 ;
|
||||
X = 3 ;
|
||||
no
|
||||
|
||||
% ...and a second threaded_exit/1 call will pick the remaining one:
|
||||
|
||||
| ?- threaded_exit(lists::member(X, [1,2,3])).
|
||||
|
||||
X = 1 ;
|
||||
X = 2 ;
|
||||
X = 3 ;
|
||||
no
|
||||
|
||||
|
||||
% tags may be used to distinguish between threaded calls if needed:
|
||||
|
||||
| ?- threaded_call(lists::member(X, [1,2,3]), Tag).
|
||||
|
||||
Tag = 1
|
||||
yes
|
||||
|
||||
| ?- threaded_call(lists::member(X, [1,2,3]), Tag).
|
||||
|
||||
Tag = 2
|
||||
yes
|
||||
|
||||
| ?- threaded_exit(lists::member(X, [1,2,3]), 2).
|
||||
|
||||
X = 1 ;
|
||||
X = 2 ;
|
||||
X = 3 ;
|
||||
no
|
||||
|
||||
|
||||
% use a subsumed goal instead of a variant of the original goal:
|
||||
|
||||
| ?- threaded_call(lists::member(X, [1,2,3,2])).
|
||||
|
||||
X = _G189
|
||||
yes
|
||||
|
||||
| ?- threaded_exit(lists::member(2, [1,2,3,2])).
|
||||
|
||||
More ;
|
||||
More ;
|
||||
no
|
||||
|
@@ -1,8 +1,6 @@
|
||||
|
||||
:- object(lists).
|
||||
|
||||
:- threaded.
|
||||
|
||||
:- public(member/2).
|
||||
|
||||
member(H, [H| _]).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -10,3 +10,13 @@ To load this example and for sample queries, please see the SCRIPT file.
|
||||
|
||||
This folder contains a Logtalk implementation of the classical "dining
|
||||
philosophers" multi-threading problem.
|
||||
|
||||
For more information, consult e.g. the following URL:
|
||||
|
||||
http://en.wikipedia.org/wiki/Dining_philosophers_problem
|
||||
|
||||
Two different implementations are provided, both using the same solution for
|
||||
avoiding deadlock (which is having one philosopher picking its chopsticks
|
||||
in a different order from the other philosophers; see the URL above for
|
||||
details): one implementations uses a category and five philosopher objects
|
||||
while the second implementation uses a parametric object.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -106,3 +106,7 @@ Philosopher p4 eating for 3 seconds with chopsticks cs4 and cs3.
|
||||
p4 terminated.
|
||||
p2 terminated.
|
||||
|
||||
|
||||
% same problem as above but using a parametric object for representing the philosophers:
|
||||
|
||||
| ?- threaded_ignore(philosopher(p1,cs1,cs2)::run(5, 5)), threaded_ignore(philosopher(p2,cs2,cs3)::run(5, 5)), threaded_ignore(philosopher(p3,cs3,cs4)::run(5, 5)), threaded_ignore(philosopher(p4,cs4,cs5)::run(5, 5)), threaded_ignore(philosopher(p5,cs1,cs5)::run(5, 5)).
|
||||
|
@@ -1,4 +1,4 @@
|
||||
|
||||
:- initialization((
|
||||
logtalk_load(library(random_loader), [reload(skip)]),
|
||||
logtalk_load(library(random_loader), [reload(skip)]), % allow for static binding
|
||||
logtalk_load(philosophers))).
|
||||
|
@@ -2,13 +2,11 @@
|
||||
:- category(chopstick).
|
||||
|
||||
:- info([
|
||||
version is 1.2,
|
||||
version is 2.0,
|
||||
author is 'Paulo Moura',
|
||||
date is 2007/3/19,
|
||||
comment is 'Dining philosophers problem: chopstick representation.']).
|
||||
|
||||
:- synchronized.
|
||||
|
||||
:- public(pick_up/0).
|
||||
:- mode(pick_up, zero_or_one).
|
||||
:- info(pick_up/0, [
|
||||
@@ -19,22 +17,14 @@
|
||||
:- info(put_down/0, [
|
||||
comment is 'A Philosopher puts down the chopstick.']).
|
||||
|
||||
:- private(available/0).
|
||||
:- dynamic(available/0).
|
||||
:- mode(available, zero_or_one).
|
||||
:- info(available/0, [
|
||||
comment is 'Chopstick state (either available or in use).']).
|
||||
|
||||
% chopstick actions (picking up and putting down) are synchronized using the same mutex
|
||||
% chopstick actions (picking up and putting down) are synchronized using a notification
|
||||
% such that a chopstick can only be handled by a single philosopher at a time:
|
||||
|
||||
pick_up :-
|
||||
::available,
|
||||
::retract(available).
|
||||
threaded_wait(available).
|
||||
|
||||
put_down :-
|
||||
\+ ::available,
|
||||
::asserta(available).
|
||||
threaded_notify(available).
|
||||
|
||||
:- end_category.
|
||||
|
||||
@@ -42,9 +32,8 @@
|
||||
:- object(cs1,
|
||||
imports(chopstick)).
|
||||
|
||||
:- dynamic(available/0).
|
||||
|
||||
available.
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -52,9 +41,8 @@
|
||||
:- object(cs2,
|
||||
imports(chopstick)).
|
||||
|
||||
:- dynamic(available/0).
|
||||
|
||||
available.
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -62,9 +50,8 @@
|
||||
:- object(cs3,
|
||||
imports(chopstick)).
|
||||
|
||||
:- dynamic(available/0).
|
||||
|
||||
available.
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -72,9 +59,8 @@
|
||||
:- object(cs4,
|
||||
imports(chopstick)).
|
||||
|
||||
:- dynamic(available/0).
|
||||
|
||||
available.
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -82,9 +68,8 @@
|
||||
:- object(cs5,
|
||||
imports(chopstick)).
|
||||
|
||||
:- dynamic(available/0).
|
||||
|
||||
available.
|
||||
:- threaded.
|
||||
:- initialization(threaded_notify(available)).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -92,7 +77,7 @@
|
||||
:- category(philosopher).
|
||||
|
||||
:- info([
|
||||
version is 1.1,
|
||||
version is 2.0,
|
||||
author is 'Paulo Moura',
|
||||
date is 2007/1/3,
|
||||
comment is 'Dining philosophers problem: philosopher representation.']).
|
||||
@@ -129,12 +114,11 @@
|
||||
message([Philosopher, ' terminated.']).
|
||||
|
||||
run(Count, MaxTime) :-
|
||||
Count > 0,
|
||||
think(MaxTime),
|
||||
( eat(MaxTime) ->
|
||||
Count2 is Count - 1,
|
||||
run(Count2, MaxTime)
|
||||
; run(Count, MaxTime)
|
||||
).
|
||||
eat(MaxTime),
|
||||
Count2 is Count - 1,
|
||||
run(Count2, MaxTime).
|
||||
|
||||
think(MaxTime):-
|
||||
this(Philosopher),
|
||||
@@ -142,25 +126,20 @@
|
||||
message(['Philosopher ', Philosopher, ' thinking for ', ThinkTime, ' seconds.']),
|
||||
thread_sleep(ThinkTime).
|
||||
|
||||
% deadlock while a philosopher is trying to eat is prevented by putting
|
||||
% down the first chopstick when picking up the second one fails:
|
||||
eat(MaxTime):-
|
||||
this(Philosopher),
|
||||
random(1, MaxTime, EatTime),
|
||||
::left_chopstick(LeftStick),
|
||||
::right_chopstick(RightStick),
|
||||
LeftStick::pick_up,
|
||||
( RightStick::pick_up ->
|
||||
message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
|
||||
thread_sleep(EatTime),
|
||||
::LeftStick::put_down,
|
||||
::RightStick::put_down
|
||||
; ::LeftStick::put_down,
|
||||
fail
|
||||
).
|
||||
RightStick::pick_up,
|
||||
message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
|
||||
thread_sleep(EatTime),
|
||||
::LeftStick::put_down,
|
||||
::RightStick::put_down.
|
||||
|
||||
% writing a message needs to be synchronized as it's accomplished
|
||||
% using a combination of individual write/1 (and nl/0) calls:
|
||||
% using a combination of individual write/1 and nl/0 calls:
|
||||
message([]) :-
|
||||
nl,
|
||||
flush_output.
|
||||
@@ -174,10 +153,8 @@
|
||||
:- object(p1,
|
||||
imports(philosopher)).
|
||||
|
||||
:- threaded.
|
||||
|
||||
left_chopstick(cs5).
|
||||
right_chopstick(cs1).
|
||||
left_chopstick(cs1).
|
||||
right_chopstick(cs2).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -185,10 +162,8 @@
|
||||
:- object(p2,
|
||||
imports(philosopher)).
|
||||
|
||||
:- threaded.
|
||||
|
||||
left_chopstick(cs1).
|
||||
right_chopstick(cs2).
|
||||
left_chopstick(cs2).
|
||||
right_chopstick(cs3).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -196,10 +171,8 @@
|
||||
:- object(p3,
|
||||
imports(philosopher)).
|
||||
|
||||
:- threaded.
|
||||
|
||||
left_chopstick(cs3).
|
||||
right_chopstick(cs2).
|
||||
right_chopstick(cs4).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -207,10 +180,8 @@
|
||||
:- object(p4,
|
||||
imports(philosopher)).
|
||||
|
||||
:- threaded.
|
||||
|
||||
left_chopstick(cs4).
|
||||
right_chopstick(cs3).
|
||||
right_chopstick(cs5).
|
||||
|
||||
:- end_object.
|
||||
|
||||
@@ -218,9 +189,89 @@
|
||||
:- object(p5,
|
||||
imports(philosopher)).
|
||||
|
||||
:- threaded.
|
||||
|
||||
left_chopstick(cs5).
|
||||
right_chopstick(cs4).
|
||||
left_chopstick(cs1). % change order so that the chopsticks are picked
|
||||
right_chopstick(cs5). % in different order from the other philosophers
|
||||
|
||||
:- end_object.
|
||||
|
||||
|
||||
:- object(philosopher(_Philosopher, _LeftChopstick, _RightShopstick)).
|
||||
|
||||
:- info([
|
||||
version is 2.0,
|
||||
author is 'Paulo Moura',
|
||||
date is 2007/1/3,
|
||||
comment is 'Dining philosophers problem: philosopher representation.']).
|
||||
|
||||
:- public(left_chopstick/1).
|
||||
:- mode(left_chopstick(?object_identifier), zero_or_one).
|
||||
:- info(left_chopstick/1, [
|
||||
comment is 'Chopstick at the left of a philosopher.',
|
||||
argnames is ['Chopstick']]).
|
||||
|
||||
:- public(right_chopstick/1).
|
||||
:- mode(right_chopstick(?object_identifier), zero_or_one).
|
||||
:- info(right_chopstick/1, [
|
||||
comment is 'Chopstick at the right of a philosopher.',
|
||||
argnames is ['Chopstick']]).
|
||||
|
||||
:- public(run/2).
|
||||
:- mode(run(+integer, +integer), one).
|
||||
:- info(run/2, [
|
||||
comment is 'Runs Count number of thinking/eating cycles, with each activity taking MaxTime (in seconds).',
|
||||
argnames is ['Count', 'MaxTime']]).
|
||||
|
||||
:- private(message/1).
|
||||
:- synchronized(message/1).
|
||||
:- mode(message(+list), one).
|
||||
:- info(message/1, [
|
||||
comment is 'Writes all the terms on a list as an atomic operation.',
|
||||
argnames is ['Atoms']]).
|
||||
|
||||
:- uses(random, [random/3]).
|
||||
|
||||
left_chopstick(LeftStick) :-
|
||||
parameter(2, LeftStick).
|
||||
|
||||
rigth_chopstick(RightStick) :-
|
||||
parameter(3, RightStick).
|
||||
|
||||
run(0, _) :-
|
||||
parameter(1, Philosopher),
|
||||
message([Philosopher, ' terminated.']).
|
||||
|
||||
run(Count, MaxTime) :-
|
||||
Count > 0,
|
||||
think(MaxTime),
|
||||
eat(MaxTime),
|
||||
Count2 is Count - 1,
|
||||
run(Count2, MaxTime).
|
||||
|
||||
think(MaxTime):-
|
||||
random(1, MaxTime, ThinkTime),
|
||||
parameter(1, Philosopher),
|
||||
message(['Philosopher ', Philosopher, ' thinking for ', ThinkTime, ' seconds.']),
|
||||
thread_sleep(ThinkTime).
|
||||
|
||||
eat(MaxTime):-
|
||||
random(1, MaxTime, EatTime),
|
||||
parameter(2, LeftStick),
|
||||
parameter(3, RightStick),
|
||||
LeftStick::pick_up,
|
||||
RightStick::pick_up,
|
||||
parameter(1, Philosopher),
|
||||
message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
|
||||
thread_sleep(EatTime),
|
||||
::LeftStick::put_down,
|
||||
::RightStick::put_down.
|
||||
|
||||
% writing a message needs to be synchronized as it's accomplished
|
||||
% using a combination of individual write/1 and nl/0 calls:
|
||||
message([]) :-
|
||||
nl,
|
||||
flush_output.
|
||||
message([Atom| Atoms]) :-
|
||||
write(Atom),
|
||||
message(Atoms).
|
||||
|
||||
:- end_object.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -17,3 +17,7 @@ a goal using proprietary predicates.
|
||||
Note that this example is only meant to illustrate how to use Logtalk
|
||||
multi-threading predicates, not to taken as the efficient solution for
|
||||
finding primes numbers on a given interval (with or without threads).
|
||||
|
||||
You probably want to play with the list size in order to find out when the
|
||||
list is big enough to make the use of multi-threading worth performance-wise
|
||||
(i.e. to compensate the overhead of thread creation and management).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
@@ -10,7 +10,7 @@ To load this example and for sample queries, please see the SCRIPT file.
|
||||
|
||||
This folder contains a multi-threading implementation of the merge sort
|
||||
algorithm. Depending on the size of the lists that are ordered, using
|
||||
only one thread can be faster. The number of threads to use in sorting
|
||||
only one thread can be faster. The number of threads to be use in sorting
|
||||
is set using the msort/1 object parameter. You may need to adjust the
|
||||
size of the memory areas used by your Prolog compiler, depending on the
|
||||
size of the lists you want to sort.
|
||||
@@ -30,3 +30,7 @@ other purpose, you may find the following paper a worthwhile reading:
|
||||
year = "1993",
|
||||
url = "citeseer.ist.psu.edu/apt93modular.html" }
|
||||
|
||||
You probably want to play with the list sizes in order to find out when the
|
||||
lists to be sorted are big enough to make the use of multi-threading worth
|
||||
performance-wise (i.e. to compensate the overhead of thread creation and
|
||||
management).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,4 +1,4 @@
|
||||
|
||||
:- initialization((
|
||||
logtalk_load(library(random_loader), [reload(skip)]),
|
||||
logtalk_load(library(random_loader), [reload(skip)]), % allow for static binding
|
||||
logtalk_load([generator, qsort, msort]))).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
@@ -1,6 +1,6 @@
|
||||
================================================================
|
||||
Logtalk - Open source object-oriented logic programming language
|
||||
Release 2.30.2
|
||||
Release 2.30.7
|
||||
|
||||
Copyright (c) 1998-2007 Paulo Moura. All Rights Reserved.
|
||||
================================================================
|
||||
|
Reference in New Issue
Block a user