/* RANDOM.PL */ /* This module exports a random-number generator needed by "spin". */ :- module random. :- public random/2, randomise/0, randomise/1, random_element/3, random_element/2, random_permutation/2. /* SPECIFICATION ------------- PUBLIC random( N+, I? ): Given an integer N >= 1, random(N, I) unifies I with a random integer between 0 and N - 1. PUBLIC randomise: Restart the random sequence from the beginning PUBLIC randomise( Seed+ ): Instantiate the seeds to your own favourite value PUBLIC random_element( List+, Elem?, Rest? ): Given an non-empty List, unifies Elem with a random element of List and Rest with the other elements. PUBLIC random_element( List+, Elem? ): Equivalent to random_element( List, Elem, _ ). PUBLIC random_permutation( List+, Perm? ): Unifies Perm with a random permutation of List. What good this may be I'm not sure, and there's bound to be a more efficient way of doing it. Oh well. */ /* IMPLEMENTATION -------------- I have adapted this file from RANDOM.PL in the DEC-10 public-domain library. The original heading was Author : R.A.O'Keefe Updated: 1 October 1984 NIP version: 13 May 1987 Purpose: Random number generator. The code should be portable (I don't know if there are any dependencies on word size), except that you will need to change 'intof' as a right operand of 'is' in 'random' to whatever your system uses for converting reals to integers with truncation towards zero. */ :- dynamic '\$random_seed'/1. :- needs bug / 2, length / 2, nth1 / 4. random( N, I ) :- ( '\$random_seed'( [A0,A1,A2] ) -> retractall( '\$random_seed'(_) ) ; A0 = 3172, A1 = 9814, A2 = 20125 ), B0 is (A0*171) mod 30269, B1 is (A1*172) mod 30307, B2 is (A2*170) mod 30323, asserta( '\$random_seed'([B0,B1,B2]) ), R is A0/30269 + A1/30307 + A2/30323, I is intof((R - intof(R)) * N). /* The next bit: K R Johnson, 13-5-87 */ randomise :- ( '\$random_seed'( _ ) -> retractall( '\$random_seed'(_) ) ; true ), asserta( '\$random_seed'([3172,9814,20125]) ). randomise(Seed) :- integer(Seed), Seed > 0, !, ( '\$random_seed'(_) -> retractall( '\$random_seed'(_) ) ; true ), S0 is Seed mod 30269, S1 is Seed mod 30307, S2 is Seed mod 30323, asserta( '\$random_seed'([S0,S1,S2]) ). randomise( Seed ) :- bug( 'randomise: Seed must be a positive integer', [Seed] ). random_element( [E], E, [] ) :- !. random_element( List, Elem, Rest ) :- length( List, N ), N > 0, random( N, I ), I_ is I + 1, nth1( I_, List, Elem, Rest ). random_element( List, Elem ) :- random_element( List, Elem, _ ). random_permutation([], []). random_permutation([H1|T1], [H2|T2]) :- random_element([H1|T1], H2, T3), random_permutation(T3, T2). :- endmodule.