This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/library/random.yap
Vítor Santos Costa 6453ca395c more doc changes
2014-09-15 13:42:35 -05:00

214 lines
4.4 KiB
Prolog

/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: random.yap *
* Last rev: 5/12/99 *
* mods: *
* comments: Random operations *
* *
*************************************************************************/
% original code from RA O'Keefe.
% This is algorithm AS 183 from Applied Statistics. I also have a C
% version. It is really very good. It is straightforward to make a
% version which yields 15-bit random integers using only integer
% arithmetic.
/** @defgroup Pseudo_Random Random Number Generator
@ingroup YAPLibrary
@{
The following random number operations are included with the
`use_module(library(random))` command. Since YAP-4.3.19 YAP uses
the O'Keefe public-domain algorithm, based on the "Applied Statistics"
algorithm AS183.
@pred getrand(- _Key_)
Unify _Key_ with a term of the form `rand(X,Y,Z)` describing the
current state of the random number generator.
*/
/** @pred random(+ _LOW_, + _HIGH_, - _NUMBER_)
Unify _Number_ with a number in the range
`[LOW...HIGH)`. If both _LOW_ and _HIGH_ are
integers then _NUMBER_ will also be an integer, otherwise
_NUMBER_ will be a floating-point number.
*/
/** @defgroup Pseudo_Random Pseudo Random Number Integer Generator
@ingroup YAPLibrary
@{
The following routines produce random non-negative integers in the range
0 .. 2^(w-1) -1, where w is the word size available for integers, e.g.
32 for Intel machines and 64 for Alpha machines. Note that the numbers
generated by this random number generator are repeatable. This generator
was originally written by Allen Van Gelder and is based on Knuth Vol 2.
*/
/** @pred random(- _Number_)
Unify _Number_ with a floating-point number in the range `[0...1)`.
*/
/** @pred randseq(+ _LENGTH_, + _MAX_, - _Numbers_)
Unify _Numbers_ with a list of _LENGTH_ unique random integers
in the range `[1... _MAX_)`.
*/
/** @pred randset(+ _LENGTH_, + _MAX_, - _Numbers_)
Unify _Numbers_ with an ordered list of _LENGTH_ unique random
integers in the range `[1... _MAX_)`.
*/
/** @pred setrand(+ _Key_)
Use a term of the form `rand(X,Y,Z)` to set a new state for the
random number generator. The integer `X` must be in the range
`[1...30269)`, the integer `Y` must be in the range
`[1...30307)`, and the integer `Z` must be in the range
`[1...30323)`.
*/
:- module(random, [
random/1,
random/3,
randseq/3,
randset/3,
getrand/1,
setrand/1
]).
:- use_module(library(pairs)).
:- use_module(library(error)).
:- use_module(library(lists)).
:- load_foreign_files([yap_random], [], init_random).
% random(R) binds R to a new random number in [0.0,1.0)
% random(L, U, R) binds R to a random integer in [L,U)
% when L and U are integers (note that U will NEVER be generated),
% or to a random floating number in [L,U) otherwise.
random(L, U, R) :-
( integer(L), integer(U) ->
U > L,
random(X),
R is L+integer((U-L)*X)
;
number(L), number(U),
U > L,
random(X),
R is L+((U-L)*X)
).
/* There are two versions of this operation.
randset(K, N, S)
generates a random set of K integers in the range 1..N.
The result is an ordered list, such as setof might produce.
randseq(K, N, L)
generates a random sequence of K integers, the order is as
random as we can make it.
*/
randset(K, N, S) :-
K >= 0,
K =< N,
randset(K, N, [], S).
randset(0, _, S, S) :- !.
randset(K, N, Si, So) :-
random(X),
X * N < K, !,
J is K-1,
M is N-1,
randset(J, M, [N|Si], So).
randset(K, N, Si, So) :-
M is N-1,
randset(K, M, Si, So).
randseq(K, N, S) :-
randseq(K, N, L, []),
keysort(L, R),
strip_keys(R, S).
randseq(0, _, S, S) :- !.
randseq(K, N, [Y-N|Si], So) :-
random(X),
X * N < K, !,
random(Y),
J is K-1,
M is N-1,
randseq(J, M, Si, So).
randseq(K, N, Si, So) :-
M is N-1,
randseq(K, M, Si, So).
strip_keys([], []) :- !.
strip_keys([_-K|L], [K|S]) :-
strip_keys(L, S).
setrand(rand(X,Y,Z)) :-
integer(X),
integer(Y),
integer(Z),
X > 0,
X < 30269,
Y > 0,
Y < 30307,
Z > 0,
Z < 30323,
setrand(X,Y,Z).
getrand(rand(X,Y,Z)) :-
getrand(X,Y,Z).