home *** CD-ROM | disk | FTP | other *** search
/ Programmer Plus 2007 / Programmer-Plus-2007.iso / Programming / XML Utilities / Professional Programmer XSL IDE / Xselerator25.msi / Data.Cab / F35418_random.xsl < prev    next >
Encoding:
Text File  |  2002-04-08  |  20.2 KB  |  392 lines

  1. <!--
  2. ===========================================================================
  3.  Stylesheet: random.xsl           Randomization Functions                  
  4.     Version: 1.0 (2002-03-16)                                              
  5.    Based on: Random number algorithms in Simon Thompson's                  
  6.              "Haskell, the craft of functional programming"                
  7.      Author: Dimitre Novatchev                                             
  8.      Notice: Copyright (c)2002 D.Novatchev  ALL RIGHTS RESERVED.           
  9.              No limitation on use - except this code may not be published, 
  10.              in whole or in part, without prior written consent of the     
  11.              copyright owner.                                              
  12. ===========================================================================-->
  13. <xsl:stylesheet version="1.0" 
  14.  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  15.  xmlns:vendor="http://icl.com/saxon"
  16.  xmlns:randScale="f:randScale"
  17.  xmlns:myRandNext="f:myRandNext" 
  18.  xmlns:mySingleRandDistFun="f:mySingleRandDistFun" 
  19.  xmlns:x="f:fxslRandom.xsl"
  20.  exclude-result-prefixes="xsl vendor randScale myRandNext mySingleRandDistFun x"
  21. >
  22.  
  23. <!--
  24.   ==========================================================================
  25.     Imported files:                                                         
  26.   ==========================================================================-->
  27.   <xsl:import href="map.xsl"/>
  28.   <xsl:import href="curry.xsl"/>
  29.   <xsl:import href="iter.xsl"/>
  30.   
  31. <!--
  32.   ==========================================================================
  33.     Global Randomizing constants:                                           
  34.   ==========================================================================-->
  35.   <xsl:variable name="seed"       select="17489"/>
  36.   <xsl:variable name="multiplier" select="25173"/>
  37.   <xsl:variable name="increment"  select="13849"/>
  38.   <xsl:variable name="modulus"    select="65536"/>
  39.   
  40. <!--
  41.     This is a linear congruental method of generating                          
  42.     a pseudo-random sequence of natural numbers                                
  43.     starting with a seed and then getting the next element                     
  44.     of the sequence from the previous value like this:                         
  45.                                                                                
  46.     nextRand :: Int -> Int                                                     
  47.     nextRand n = (multiplier * n + increment) `mod` modulus                    
  48. -->  
  49.   
  50. <!--
  51.       Template: randNext                                                     
  52.       Purpose : Return the value of the next random number from the current  
  53.     Parameters:                                                              
  54.          $arg1  - the current random number, from which to produce the next  
  55.   ========================================================================== -->
  56.   <xsl:template name="randNext" match="myRandNext:*">
  57.     <xsl:param name="arg1"/>
  58.     
  59.     <xsl:value-of select="($multiplier * $arg1 + $increment) mod $modulus"/>
  60.   </xsl:template>
  61.  
  62. <!--
  63.       Template: scaleSequence                                                
  64.       Purpose : Return a scaled version of a sequence from a given sequence  
  65.     Parameters:                                                              
  66.        $pStart  - [optional] the start of the interval, in which randoms     
  67.                    are to be produced                                        
  68.        $pEnd    - [optional] the end of the interval, in which randoms       
  69.                    are to be produced                                        
  70.        $pList   - the list of numbers that are to be scaled                  
  71.   ========================================================================== -->
  72.   <xsl:template name="scaleSequence">
  73.     <xsl:param name="pStart" select="0"/>
  74.     <xsl:param name="pEnd" select="1"/>
  75.     <xsl:param name="pList" select="/.."/>
  76.     
  77.     <xsl:variable name="vScaleFun" select="$x:st/randScale:*[1]"/>
  78.     <xsl:variable name="vRange" select="$pEnd - $pStart + 1"/>
  79.     
  80.     <xsl:variable name="vrtfCurriedScale">
  81.       <xsl:call-template name="curry">
  82.         <xsl:with-param name="pFun" select="$vScaleFun"/>
  83.         <xsl:with-param name="pNargs" select="3"/>
  84.         <xsl:with-param name="arg2" select="$pStart"/>
  85.         <xsl:with-param name="arg3" select="$vRange"/>
  86.       </xsl:call-template>
  87.     </xsl:variable>
  88.     
  89.     <xsl:variable name="vFixedScaleFun" 
  90.                   select="vendor:node-set($vrtfCurriedScale)/*"/>
  91.                   
  92.     <xsl:call-template name="map">
  93.       <xsl:with-param name="pFun" select="$vFixedScaleFun"/>
  94.       <xsl:with-param name="pList1" select="$pList"/>
  95.     </xsl:call-template>
  96.   </xsl:template>
  97.   
  98.   
  99. <!--
  100.       Template: randomSequence                                              
  101.       Purpose : Return a sequence of random numbers starting from a seed    
  102.     Parameters:                                                             
  103.       $pLength  - [optional] the length of the sequence of randoms          
  104.                   that must be produced                                     
  105.       $pSeed    - [optional] the seed for the randomization                 
  106.       $pStart   - [optional] the start of the interval,                     
  107.                   in which randoms are to be produced                       
  108.       $pEnd     - [optional] the end of the interval,                       
  109.                   in which randoms are to be produced                       
  110.   ==========================================================================-->
  111.   <xsl:template name="randomSequence">
  112.     <xsl:param name="pLength" select="1"/>
  113.     <xsl:param name="pSeed" select="$seed"/>
  114.     <xsl:param name="pStart" select="0"/>
  115.     <xsl:param name="pEnd" select="$modulus - 1"/>
  116.     
  117.     <xsl:variable name="vFunRandNext" select="$x:st/myRandNext:*[1]"/>
  118.     
  119.     <xsl:variable name="vrtfUnscaledSeq">
  120.         <xsl:call-template name="scanIter">
  121.           <xsl:with-param name="arg1" select="$pLength - 1"/><!-- n -->
  122.           <xsl:with-param name="arg2" select="$vFunRandNext"/><!-- f -->
  123.           <xsl:with-param name="arg3" select="$pSeed"/> <!-- x -->
  124.         </xsl:call-template>
  125.     </xsl:variable>
  126.     
  127.     <xsl:choose>
  128.       <xsl:when test="$pStart = 0 and $pEnd = $modulus - 1">
  129.         <xsl:copy-of select="vendor:node-set($vrtfUnscaledSeq)/*"/>
  130.       </xsl:when>
  131.       <xsl:otherwise>
  132.             <xsl:call-template name="scaleSequence">
  133.                 <xsl:with-param name="pStart" select="$pStart"/>
  134.                 <xsl:with-param name="pEnd" select="$pEnd"/>
  135.                 <xsl:with-param name="pList" select="vendor:node-set($vrtfUnscaledSeq)/*"/>
  136.             </xsl:call-template>
  137.       </xsl:otherwise>
  138.     </xsl:choose>
  139.   </xsl:template>
  140.   
  141. <!--
  142. Sometimes we want that each outcome must have a predefined probability.            
  143. First we define a "Distribution" type, which is a list of pairs of "outcome object"
  144. and "oucome object's probability":                                                 
  145.                                                                                    
  146. In order for this to make sense, the objects in the list must all be distinct,     
  147. and their probabilities must sum up to 1.                                          
  148.                                                                                    
  149. > type Distribution a  = [(a, Float)]                                              
  150.                                                                                    
  151.                                                                                    
  152. Suppose we need to model random outcomes 1 to 6 each with its given probability:   
  153.                                                                                    
  154.                                                                                    
  155. > dist1 :: Distribution Int                                                        
  156. > dist1 = [(1, 0.2), (2, 0.25), (3, 0.25), (4, 0.15), (5, 0.1), (6, 0.05)]         
  157.                                                                                    
  158.                                                                                    
  159. We will use a function, which given a distribution produces another function,      
  160. that maps the interval (0 to 65535) into the set of distinct objects according     
  161. to their probability. The idea is to divide the interval 0-65535 into N intervals  
  162. (where N = length(dist) is the number of distinct objects), but in such a way,     
  163. that the lengths of these intervals are proportional to the probabilities of the   
  164. corresponding objects.                                                             
  165.                                                                                    
  166.                                                                                    
  167. > makeFunction :: Distribution a -> (Float -> a)                                   
  168. > makeFunction dist = makeFun dist 0.0                                             
  169.                                                                                    
  170.                                                                                    
  171. > makeFun ((ob, p) : dist) nLast rand                                              
  172. >                                                                                  
  173. >   | nNext >= rand && rand > nLast                                                
  174. >         =  ob                                                                    
  175. >                                                                                  
  176. >   | otherwise                                                                    
  177. >         = makeFun dist nNext rand                                                
  178. >           where                                                                  
  179. >                nNext = p*fromInt modulus + nLast                                 
  180.                                                                                    
  181.                                                                                    
  182. Then the transformation of a list of random numbers into a list of                 
  183. (weighted) random numbers according to a distribution dist is given                
  184. by the expression:                                                                 
  185.                                                                                    
  186. map (makeFunction dist)                                                            
  187. -->
  188.  
  189. <!--
  190.       Template: dist-randomSequence                                          
  191.       Purpose : Return the value of the next random number from the current  
  192.     Parameters:                                                              
  193.       $pLength  - [optional] the length of the sequence of randoms           
  194.                    that must be produced                                     
  195.       $pDist    - a list of distributions (outcome,probability pairs)        
  196.                   e.g.:                                                      
  197.                     <myDistribution:myDistribution>                          
  198.                       <o>1</o><p>0.2</p>                                     
  199.                       <o>2</o><p>0.25</p>                                    
  200.                       <o>3</o><p>0.25</p>                                    
  201.                       <o>4</o><p>0.15</p>                                    
  202.                       <o>5</o><p>0.1</p>                                     
  203.                       <o>6</o><p>0.05</p>                                    
  204.                     </myDistribution:myDistribution>                         
  205.                                                                              
  206.     $pSeed      - [optional] the seed for the randomization                  
  207.   ========================================================================== -->
  208.   <xsl:template name="dist-randomSequence">
  209.     <xsl:param name="pLength" select="1"/>
  210.     <xsl:param name="pDist" select="/.."/>
  211.     <xsl:param name="pSeed" select="$seed"/>
  212.     
  213.     <xsl:variable name="vrtfNormalRandomSeq">
  214.       <xsl:call-template name="randomSequence">
  215.         <xsl:with-param name="pLength" select="$pLength"/>
  216.         <xsl:with-param name="pSeed" select="$pSeed"/>
  217.       </xsl:call-template>
  218.     </xsl:variable>
  219.  
  220.     <xsl:variable name="vmakeFun" 
  221.                   select="$x:st/mySingleRandDistFun:*[1]"/>
  222.     
  223.     <!-- build makeFun dist 0.0 -->
  224.     <xsl:variable name="vrtfDistFunction">
  225.       <xsl:call-template name="curry">
  226.         <xsl:with-param name="pFun" select="$vmakeFun"/>
  227.         <xsl:with-param name="pNargs" select="3"/>
  228.         <xsl:with-param name="arg2" select="$pDist"/>
  229.         <xsl:with-param name="arg3" select="'0.0'"/>
  230.       </xsl:call-template>
  231.     </xsl:variable>
  232.     
  233.     <xsl:call-template name="map">
  234.       <xsl:with-param name="pFun" select="vendor:node-set($vrtfDistFunction)/*"/>
  235.       <xsl:with-param name="pList1" 
  236.                       select="vendor:node-set($vrtfNormalRandomSeq)/*"/>
  237.     </xsl:call-template>
  238.   </xsl:template>
  239.   
  240. <!--
  241.       Template: randomSubSequence                                            
  242.       Purpose : Return a sub-sequence of random numbers                      
  243.                 starting from a given index                                  
  244.     Parameters:                                                              
  245.      $pLength   - [optional] the length of the sequence of randoms           
  246.                    that must be produced                                     
  247.      $pSubStart - [optional] the index at which the sub-sequence is to start 
  248.      $pSeed     - [optional] the seed for the randomization                  
  249.      $pStart    - [optional] the start of the interval,                      
  250.                   in which randoms are to be produced                        
  251.      $pEnd      - [optional] the end of the interval,                        
  252.                   in which randoms are to be produced                        
  253.   ========================================================================== -->
  254.   <xsl:template name="randomSubSequence">
  255.     <xsl:param name="pLength" select="1"/>
  256.     <xsl:param name="pSubStart" select="1"/>
  257.     <xsl:param name="pSeed" select="$seed"/>
  258.     <xsl:param name="pStart" select="0"/>
  259.     <xsl:param name="pEnd" select="$modulus - 1"/>
  260.     
  261.     <xsl:variable name="vrtfInitSequence">
  262.       <xsl:call-template name="randomSequence">
  263.         <xsl:with-param name="pLength" select="$pSubStart"/>
  264.         <xsl:with-param name="pSeed" select="$pSeed"/>
  265.       </xsl:call-template>
  266.     </xsl:variable>
  267.     
  268.     <xsl:call-template name="randomSequence">
  269.         <xsl:with-param name="pLength" select="$pLength"/>
  270.         <xsl:with-param name="pSeed" 
  271.                         select="vendor:node-set($vrtfInitSequence)/*[last()]"/>
  272.         <xsl:with-param name="pStart" select="$pStart"/>
  273.         <xsl:with-param name="pEnd" select="$pEnd"/>
  274.     </xsl:call-template>
  275.   </xsl:template>
  276.   
  277. <!--
  278.       Template: dist-randomSubSequence                                       
  279.       Purpose : Return a sub-sequence of random numbers                      
  280.                 starting from a given index, and according to                
  281.                 a given distribution                                         
  282.     Parameters:                                                              
  283.      $pLength   - [optional] the length of the sequence of randoms           
  284.                    that must be produced                                     
  285.      $pSubStart - The index at which the sub-sequence is to start            
  286.      $pDist     - a list of distributions (outcome,probability pairs)        
  287.                   e.g.:                                                      
  288.                     <myDistribution:myDistribution>                          
  289.                       <o>1</o><p>0.2</p>                                     
  290.                       <o>2</o><p>0.25</p>                                    
  291.                       <o>3</o><p>0.25</p>                                    
  292.                       <o>4</o><p>0.15</p>                                    
  293.                       <o>5</o><p>0.1</p>                                     
  294.                       <o>6</o><p>0.05</p>                                    
  295.                     </myDistribution:myDistribution>                         
  296.                                                                              
  297.      $pSeed     - [optional] the seed for the randomization                  
  298.   ========================================================================== -->
  299.   <xsl:template name="dist-randomSubSequence">
  300.     <xsl:param name="pLength" select="1"/>
  301.     <xsl:param name="pSubStart" select="1"/>
  302.     <xsl:param name="pDist" select="/.."/>
  303.     <xsl:param name="pSeed" select="$seed"/>
  304.  
  305.     <xsl:variable name="vrtfInitSequence">
  306.       <xsl:call-template name="randomSequence">
  307.         <xsl:with-param name="pLength" select="$pSubStart"/>
  308.         <xsl:with-param name="pSeed" select="$pSeed"/>
  309.       </xsl:call-template>
  310.     </xsl:variable>
  311.  
  312.     <xsl:call-template name="dist-randomSequence">
  313.         <xsl:with-param name="pLength" select="$pLength"/>
  314.         <xsl:with-param name="pSeed" 
  315.                         select="vendor:node-set($vrtfInitSequence)/*[last()]"/>
  316.         <xsl:with-param name="pDist" select="$pDist"/>
  317.     </xsl:call-template>
  318.   </xsl:template>
  319.   
  320.   <!-- ************************************************************* -->
  321.   <!-- ********************* INTERNAL USE ONLY ********************* -->
  322.   <!-- ************************************************************* -->
  323.   <!-- defined constants -->
  324.    <xsl:variable name="x:st" select="document('')/*"/>
  325.  
  326. <!--
  327.       a template reference to a scaling function                             
  328.   ========================================================================== -->
  329.    <randScale:randScale/>
  330. <!--
  331.       a template reference to a distribution-randomizing function            
  332.   ========================================================================== -->
  333.    <mySingleRandDistFun:mySingleRandDistFun/>
  334.   
  335. <!--
  336.       a template reference to randNext                                       
  337.   ========================================================================== -->
  338.   <myRandNext:myRandNext/>
  339.   
  340.   <xsl:template name="makeFun" match="mySingleRandDistFun:*">
  341.     <xsl:param name="arg1"/>              <!-- rand -->
  342.     <xsl:param name="arg2" select="/.."/> <!-- Distribution -->
  343.     <xsl:param name="arg3"/>              <!-- nLast -->
  344.     
  345.     <xsl:variable name="vP" select="$arg2[2]"/>
  346.     <xsl:variable name="vOutcome" select="$arg2[1]"/>
  347.     <xsl:variable name="vnNext" select="$vP * $modulus + $arg3"/>
  348.  
  349.     <xsl:choose>
  350.             <!--                                     
  351.                 >   | nNext >= rand && rand > nLast    
  352.                 >         =  ob                        
  353.             -->
  354.       <xsl:when test="$vnNext >= $arg1 and $arg1 > $arg3">
  355.         <xsl:copy-of select="$vOutcome/node()"/>
  356.       </xsl:when>
  357.             <!--
  358.                 >   | otherwise                             
  359.                 >         = makeFun dist nNext rand         
  360.             -->
  361.       <xsl:otherwise>
  362.         <xsl:call-template name="makeFun">
  363.           <xsl:with-param name="arg1" select="$arg1"/>
  364.           <xsl:with-param name="arg2" select="$arg2[position() > 2]"/>
  365.           <xsl:with-param name="arg3" select="$vnNext"/>
  366.         </xsl:call-template>
  367.       </xsl:otherwise>
  368.     </xsl:choose>    
  369.   </xsl:template>
  370.   
  371.   
  372. <!--   The following  scales a single number n 
  373.        from the interval [0, modulus - 1]      
  374.        to the interval [s, t]                  
  375.                                                
  376.        scale n = n `div` denom + s             
  377.        range   = t - s + 1                     
  378.        denom   = modulus `div` range           
  379.  
  380. -->  
  381.   <xsl:template match="randScale:*">
  382.     <xsl:param name="arg1"/> <!-- n -->
  383.     <xsl:param name="arg2"/> <!-- s -->
  384.     <xsl:param name="arg3"/> <!-- range -->
  385.     
  386.     <xsl:variable name="vDenom" select="floor($modulus div $arg3)"/>
  387.     
  388.     <xsl:value-of select="floor($arg1 div $vDenom) + $arg2"/>
  389.   
  390.   </xsl:template>
  391.  
  392. </xsl:stylesheet>