xquery version "3.0"; (: : Copyright 2006-2009 The FLWOR Foundation. : : Licensed under the Apache License, Version 2.0 (the "License"); : you may not use this file except in compliance with the License. : You may obtain a copy of the License at : : http://www.apache.org/licenses/LICENSE-2.0 : : Unless required by applicable law or agreed to in writing, software : distributed under the License is distributed on an "AS IS" BASIS, : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. : See the License for the specific language governing permissions and : limitations under the License. :) (:~ : This module provides several functions for generating (pseudo-)random : numbers and strings. : : @author Matthias Brantner, Sorin Nasoi : @project XDM/atomic : :) module namespace r = "http://www.zorba-xquery.com/modules/random"; declare namespace ann = "http://www.zorba-xquery.com/annotations"; declare namespace zerr = "http://www.zorba-xquery.com/errors"; declare namespace ver = "http://www.zorba-xquery.com/options/versioning"; declare option ver:module-version "2.0"; (:~ : This function generates an arbitrary number of pseudo-random numbers. : The sequence is repeatable by calling the function with the same : seed. : : <p>The function is based on posix function <tt>srand()</tt> and : <tt>rand()</tt>. Specifically, it invokes <tt>srand($seed)</tt> : and then returns the values returned by invoking <tt>rand()</tt> : <tt>$num</tt>-times.</p> : : <p>Sequences returned by this function are not thread-safe (i.e. : if multiple XQuery programs invoking this function are executed : concurrently in several threads). This is because the function is : based on <tt>srand()</tt> and <tt>rand()</tt>.</p> : : @param $seed the initial seed value for the sequence : @param $num the length of the sequence returned : @return <tt>$num</tt> pseudo-random integers, or the empty : sequence if <tt>$num</tt> is negative. : : @error zerr:ZQXD0004 if the given seed is negative or great : than the max value of <tt>unsigned int</tt> on the given platform. :) declare function r:seeded-random( $seed as xs:integer, $num as xs:integer ) as xs:integer* external; (:~ : This function generates an arbitrary number of random numbers. : The function is nondeterministic because the sequence is : <b>not</b> repeatable. : : <p>However, the function is based on posix function <tt>srand()</tt> and : <tt>rand()</tt>. Specifically, it invokes <tt>srand()</tt> : with some random number based on the current time : and then returns the values returned by invoking : <tt>rand()</tt> <tt>$num</tt>-times.</p> : : @param $num the length of the sequence returned : @return <tt>$num</tt> random integers, or the empty : sequence if <tt>$num</tt> is negative. :) declare %ann:nondeterministic function r:random( $num as xs:integer ) as xs:integer* external; (:~ : This function generates one random number. : The function is nondeterministic. : : <p>The function is based on <tt>r:random#1</tt>. Specifically, it : returns the value of invoking <tt>r:random(1)</tt>.</p> : : @return a random integer :) declare %ann:nondeterministic function r:random() as xs:integer { r:random(1) }; (:~ : This function generates an arbitrary number of pseudo-random numbers : within a given range. The sequence is repeatable by calling the : function with the same seed and boundaries. : : <p>The function is based on the function <tt>r:seeded-random#2</tt>. : Specifically, it's result is repeatable if called with the : same arguments.</p> : : @param $seed the initial seed value for the sequence : @param $lower the lower bound for every value within the sequence : @param $upper the upper bound for every value within the sequence : @param $num the length of the sequence returned : @return <tt>$num</tt> pseudo-random integers within (and including) the : range specified by <tt>$lower</tt> and <tt>$upper</tt>. It returns : <tt>$num</tt>-times <tt>$lower</tt> if <tt>$lower</tt> is : equal to <tt>$upper</tt> and the empty sequence if <tt>$num</tt> : is negative. : : @error zerr:ZQXD0004 if the given seed is negative or great : than the max value of <tt>unsigned int</tt> on the given platform. : @error r:invalid-arg if <tt>$lower</tt> is greater than <tt>$upper</tt> :) declare function r:seeded-random-between( $seed as xs:integer, $lower as xs:integer, $upper as xs:integer, $num as xs:integer ) as xs:integer* { if ( $lower eq $upper ) then $lower else if ( $lower > $upper ) then fn:error( fn:QName("http://www.zorba-xquery.com/modules/random", "invalid-arg"), "$lower must be smaller or equal than $upper", ($lower, $upper) ) else for $i in r:seeded-random( $seed, $num ) return if ( ( $upper - $lower ) lt 10000 ) then xs:integer( fn:round( xs:double( $i mod 10000 ) div 10000 * ( $upper - $lower) ) + $lower ) else xs:integer( fn:round( xs:double( $i ) mod ( $upper - $lower ) ) + $lower ) }; (:~ : This function generates an arbitrary number of random numbers : within a given range. The function is nondeterministic because : the sequence is <b>not</b> repeatable. : : @param $lower the lower bound for every value within the sequence : @param $upper the upper bound for every value within the sequence : @param $num the length of the sequence returned : @return <tt>$num</tt> pseudo-random integers within (and including) the : range specified by <tt>$lower</tt> and <tt>$upper</tt>. It returns : <tt>$num</tt>-times <tt>$lower</tt> if <tt>$lower</tt> is : equal to <tt>$upper</tt> and the empty sequence if <tt>$num</tt> : is negative. : : @error r:invalid-arg if <tt>$lower</tt> is greater than <tt>$upper</tt> :) declare %ann:nondeterministic function r:random-between( $lower as xs:integer, $upper as xs:integer, $num as xs:integer) as xs:integer* { if ( $lower eq $upper ) then $lower else if ( $lower > $upper ) then fn:error( fn:QName("http://www.zorba-xquery.com/modules/random", "invalid-arg"), "$lower must be smaller or equal than $upper", ($lower, $upper) ) else for $i in r:random( $num ) return if ( ( $upper - $lower ) lt 10000 ) then xs:integer( fn:round( xs:double( $i mod 10000 ) div 10000 * ( $upper - $lower) ) + $lower ) else xs:integer( fn:round( xs:double( $i ) mod ( $upper - $lower ) ) + $lower ) }; (:~ : This function generates one random number within a given range. : The function is nondeterministic. : : <p>The function is based on <tt>r:random-between#3</tt>. : Specifically, it returns the value of invoking : <tt>r:random-betwen($lower, $upper, 1)</tt>.</p> : : @param $lower the lower bound for the random number : @param $upper the upper bound for the random number : @return a random integer within the given range :) declare %ann:nondeterministic function r:random-between( $lower as xs:integer, $upper as xs:integer ) as xs:integer { r:random-between($lower, $upper, 1) }; (:~ : This function returns a uuid. Note, that the function is not stable, : that is, it returns a different UUID everytime the function is invoked. : : @return the generated UUID as xs:string :) declare %ann:nondeterministic function r:uuid() as xs:string external;