Note that there is no requirement that either of the args be >= 0.
?- random_between(-100,-10,X). X = -39.
See also
The comments under https://eu.swi-prolog.org/pldoc/doc_for?object=f(random_float/0)
Should work in "accept mode" too:
If the argument is instantiated, it should work exactly like between/3. Well, we don't know whether an instantiated 3rd argument is really "random", but we can ascertain that it is "between".
?- random_between(1,5,X). X = 4. ?- random_between(1,5,4). false.
Does the failure in the second case really make sense? If there is a parameter check, it should throw. But in this case, it should just succeed.
Together with the requirement that L =< U this would then reduce to a test `L =< R =< U`.
Example of selecting an id between 0 and 6 that is not in a (small) dict yet.
This is an example of a "failure-driven loop".
clashfree_id_selection(Dict,Id) :-
repeat,
random_between(0,6,Id),
(true;(format("CLASH for ~q\n",[Id]),fail)), % print CLASH on backtracking
\+ get_dict(Id,Dict,_),
format("FOUND ~q\n",[Id]),
!.
Then
?- clashfree_id_selection(_{3:x,4:x,5:x,6:x,7:x},Id).
CLASH for 3
CLASH for 3
CLASH for 3
FOUND 1
Id = 1.
Philosophically, it is weird that that random_between/3 is "semidet" (i.e. fails or succeeds once). It could propose another solution for Id on "redo" endlessly after all. But then one could not backtrack over it in the same clause or without ;, which would be inconvenient. So the "endless proposal" is done by the conjunction
repeat, random_between(X,Y,Z)
The code above is more cleanly written
clashfree_id_selection(Dict,Id) :-
endlessly_propose_id(Id),
print_clash_on_redo(Id),
\+ get_dict(Id,Dict,_),
format("FOUND ~q\n",[Id]),
!.
endlessly_propose_id(Id) :- repeat, random_between(0,6,Id).
print_clash_on_redo(_) :- true.
print_clash_on_redo(Id) :- format("CLASH for ~q\n",[Id]),fail.
Simple application: random pairs
list_of_random_pairs(List,Length) :-
length(List,Length),
maplist(
[Char-Num]>>( % this predicate with single arg "Char-Num" is properly deterministic
random_between(0,9,Num), % random number between 0 and 9 inclusive
random_between(97,122,Code), % random 16-bit Unicode codepoint of a character in the range a-z
atom_codes(Char,[Code]) % transform code into "character" aka. "char", i.e. atom of length 1
),
List).
Then:
?- set_prolog_flag(answer_write_options,[max_depth(100)]). true. ?- list_of_random_pairs(L,10). L = [q-6,d-4,d-9,s-3,g-0,e-6,w-5,u-7,v-8,a-8].
Simple application: random selection of an atom according to some probability
Use a dict to indicate the relative probability of a selection with a number of x or some other character, except space:
randomly_select(
_{
alfa : '' % selection probability = 0
,bravo : xxxxx % selection probability = 5/24
,charlie : xxx % selection probability = 3/24
,echo : xxxxxxxxxx % selection probability = 10/24
,foxtrott : xxxxxx}, % selection probability = 6/24
Selected).
Simple application: an infinite stream of 0/1
Via Stack Overflow from an idea by Will Ness:
A bit eager as it generates as it tosses a coin even if 0 bits are demanded:
random_bit_stream([X|Xs]) :-
random_between(0,1,X),
format("coin toss: ~q\n",[X]),
freeze(Xs, random_bit_stream(Xs)).
random_bits(Selection,Length) :-
random_bit_stream(Xs),
length(Selection,Length),
append(Selection,_More,Xs).
Better, does not toss a coin if 0 bits are demanded:
random_bit_stream_2([X|Xs]) :-
freeze(Xs,
(random_between(0,1,X),
format("coin toss: ~q\n",[X]),
random_bit_stream_2(Xs))).
random_bits_2(Selection,Length) :-
random_bit_stream_2(Xs),
length(Selection,Length),
append(Selection,[_|_],Xs).
A random_between allowing exclusion of the upper limit
% ============================================================================ % The same as random_between/3 but you can indicate where the upper limit % should be included. % % Helps you avoid adding spurious "ActualHigh is High-1" % % random_between(+HighInclusive:['high_yes','high_no'], +Low:int, +High:int, -Random:int) % ============================================================================ random_between(high_yes,Low,High,Random) :- !, random_between_check(Low,High,Random), random_between(Low,High,Random). random_between(high_no,Low,High,Random) :- !, random_between_check(Low,High,Random), ActualHigh is High-1, random_between(Low,ActualHigh,Random). random_between(HighInclusive,_,_,_) :- domain_error([high_yes,high_no],HighInclusive). random_between_check(Low,High,Random) :- assertion(integer(Low)), assertion(integer(High)), assertion(var(Random)).
