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

227 lines
4.5 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 *
* *
*************************************************************************/
/**
* @file random.yap
* @author original code from RA O'Keefe.
* @author VITOR SANTOS COSTA <vsc@VITORs-MBP.lan>
* @date Wed Nov 18 00:05:21 2015
*
* @brief Integer Random Number Generator
*
*
*/
:- module(random, [
random/1,
random/3,
randseq/3,
randset/3,
getrand/1,
setrand/1
]).
/**
@{
@defgroup random Random Number Generator
@ingroup library
Since YAP-4.3.19 YAP uses
the O'Keefe public-domain algorithm, based on the "Applied Statistics"
algorithm AS183.
The following random number operations are included with the
`use_module(library(random))` command.
In ROK's words: ``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.''
*/
/** @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 library
@{
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)`.
*/
%:- use_module(library(pairs)).
:- 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).
/** @} */
/** @} */