« Back to University of Vienna - OMILAB

Generating random values based on distributions for simulations in ADOxx

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
One common issue when conducting simulations is to generate random values based on given distributions. In the following I may provide an example for doing this for the case of triangular distributions which are common in many Monte Carlo simulation approaches.

The approach has been used in the ADOscript implementation based on SeMFIS (http://www.omilab.org/web/semfis/overview) as described here:
  • Fill, Hans-Georg (2012): An Approach for Analyzing the Effects of Risks on Business Processes Using Semantic Annotations, European Conference on Information Systems (ECIS'2012), Barcelona, Spain. (pdf)


 1SET m:0
 2TRIANGULAR_DISTR trilow:3 trimed:8 trihigh:35 result:m
 3CC "AdoScript" INFOBOX (STR m)
 4
 5PROCEDURE TRIANGULAR_DISTR trilow:real trimed:real trihigh:real result:reference
 6{
 7# Calculate the value for a random draw from a triangular distribution
 8
 9    SET fc:(2/(trihigh-trilow))
10    SET randomVal:(random())
11    SET randomtri:0
12    IF (randomVal < fc AND randomVal>0) {
13        SET randomtri:(trilow + sqrt(randomVal*(trihigh-trilow)*(trimed-trilow)))
14    }
15    ELSE {
16        SET randomtri:(trihigh - sqrt((1-randomVal)*(trihigh-trilow)*(trihigh-trimed)))
17    }
18SET result:(randomtri)
19}

RE: Generating random values based on distributions for simulations in ADOx
Answer
8/3/15 1:31 PM as a reply to Hans-Georg Fill.
Dear Hans-Georg,

The simulation algorithms that the ADOxx platform offers as standard generate random values based on the distributions
  • Normal distribution
  • Uniform distribution
  • Exponential distribution
  • Discrete distribution
There is no direct suppot for triangular distributions, and it is not possible to extend the standard ADOxx simulation algorithms to include them. The random values are generated exclusively during a simulation run, it is not possible to use the simulation functionality to retrieve a random value based on a given distribution outside of this.

However, the most straightforward way to generate a random number based on a given distribution would indeed be via an AdoScript of the type written in your post. As shown in your code in line 10, the generation of a uniformly distributed random number in the range [0, 1) is done by the AdoScript command "random()". This value can then be used to generate a random value with a certain distribution as you have done. As an alternative, one could also generate values using third party software or a program written in another programming language and then import this value.  

To illustrate how this might be done, a library is presented here called "Random Generator". In this library, a single class is represented - "Random Generator". The notebook of this object has a number of different fields, and two push buttons



To define the distribution type and the parameters, the dialogue button to the right of the attribute "Distribution Type" is pressed (indicated with the red box).



This brings up a dialogue box where the type of distribution and its parameters can be defined.



Note that, even though the distribution type "Triangle" is not selectable from the list, one can still specify the triangular distribution. To do this, simply type directly into the field for the attribute "Distribution Type" the following string: Triangle(<lower limit> ; <mode> ; <upper limit>)
where one replaces "<lower limit>" etc. with a numerical value for the parameter.



In the notebook for this class there are two push-buttons:

  • Get random value using AdoScript
  • Get random value using JAVA

On pushing either of these, the distribution type and parameters are read from the attribute "Distribution Type" and a random value is generated and saved in the attribute "Random Value". Note that, for the Java script to execute temporary files need to be created. Hence, in order for the Java generation of random numbers to work, one needs to log into the Modelling Toolkit with Windows Administrator privileges. One can do this, for example, by right clicking on the Modelling Toolkit icon and selecting the option "Run as Administrator". Alternatively, one can change where the temporary files are created in the code itself so that is does not need Administrator privileges (see further explanation below the code for details).

Get random value using AdoScript:

In the AdoScript case, the AdoScript "fetchValue.asc" is called, which reads in the distribution type and parameters and writes back a random value into the attribute "Random Value". This uses defined functions and algorithms to calculate the random values based on a uniform distributed random value in [0, 1) and is anologous to the code that you presented in your question. The code for this is presented below

  1##########################################################################
  2# Returns the value of distributions for a random value based on the inverse CDF
  3##########################################################################   
  4
  5# Disclaimer: Although the generated values from these routines do not appear to be at least obviously
  6#              wrong and are using standard techniques, they are unchecked to ensure they are correct statistically.
  7
  8# We will be handling the following types of distributions
  9# Normal distribution
 10# Uniform distribution
 11# Exponential distribution
 12# Triangle distribution
 13# Discrete distribution
 14
 15CC "Core" GET_ATTR_VAL objid: (nObjID) attrname:"Distribution Type"
 16SET sDistTypeAttrString: (val)
 17IF ((tokcnt(sDistTypeAttrString, "(")) > 2) {
 18    CC "AdoScript" ERRORBOX ("Error: Only one distribution type allowed at a time")
 19    EXIT   
 20}
 21
 22# Determine the distribution type
 23SET sDistType: (copy(sDistTypeAttrString, 0, search(sDistTypeAttrString,"(", 0)))
 24# Initialise a map to place all parameters in
 25SET mParameters: (map())
 26
 27IF (sDistType = "Normal") {
 28    # Parse the string to find the parameters
 29    SET fMuInit: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,";", 0) - 1), ",", "."))
 30    SET fSigmaInit: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,";", 0) + 2, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 31    # Place these values in our parameters map
 32    SET mParameters["Normal"]: ({fMuInit, fSigmaInit})   
 33}
 34ELSIF (sDistType = "Uniform") {
 35    # Parse the string to find the parameters
 36    SET fLowerUniformInit: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,";", 0) - 1), ",", "."))
 37    SET fUpperUniformInit: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,";", 0) + 2, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 38    # Place these values in our parameters map
 39    SET mParameters["Uniform"]: ({fUpperUniformInit, fLowerUniformInit})
 40}
 41ELSIF (sDistType = "Exponential") {
 42    # Parse the string to find the parameters
 43    SET fExponentialExpectationInit: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 44    # Place these values in our parameters map
 45    SET mParameters["Exponential"]: ({fExponentialExpectationInit})
 46}
 47ELSIF (sDistType = "Triangle") {
 48    # Parse parameters when the dialog box has the triangle option
 49    SET sDistTypeAttrString: (replall(sDistTypeAttrString, "Triangle", ""))
 50    SET sDistTypeAttrString: (replall(sDistTypeAttrString, "(", ""))
 51    SET sDistTypeAttrString: (replall(sDistTypeAttrString, " ", ""))
 52    SET sDistTypeAttrString: (replall(sDistTypeAttrString, ")", ""))
 53    SET nFirstPos: (search(sDistTypeAttrString,";", 0))
 54    SET nSecondPos: (search(sDistTypeAttrString,";", nFirstPos + 1))
 55
 56    SET fLowerTriangleInit: (VAL copy(sDistTypeAttrString, 0, nFirstPos))
 57    SET fMediumTriangleInit: (VAL copy(sDistTypeAttrString, nFirstPos + 1, nSecondPos - 1))
 58    SET fUpperTriangleInit: (VAL copy(sDistTypeAttrString, nSecondPos + 1, LEN (sDistTypeAttrString)))
 59    # Place these values in our parameters map
 60    SET mParameters["Triangle"]: ({fUpperTriangleInit, fMediumTriangleInit, fLowerTriangleInit})
 61}
 62ELSIF (sDistType = "Discrete") {
 63    SET nNumberParams: (tokcnt(sDistTypeAttrString, ";")) # Actually, this is 1 less, but count from zero later
 64   
 65    SET sParamString: (replall(sDistTypeAttrString, "; ", ";"))
 66    SET sParamString: (replall(sParamString, "Discrete", ""))
 67    SET sParamString: (replall(sParamString, "(", ""))
 68    SET sParamString: (replall(sParamString, ")", ""))
 69   
 70    SET aVars: (array(0))
 71    SET aProbs: (array(0))
 72
 73    FOR sPairString in: (sParamString) sep:";" {
 74        SET nSpacePos: (search(sPairString, " ", 0))
 75        SET dummy: (aappend(aVars, copy(sPairString, 0, nSpacePos)))
 76        SET dummy: (aappend(aProbs, copy(sPairString, nSpacePos + 1, LEN(sPairString))))
 77
 78    }
 79    SET mParameters["Discrete_vars"]: (aVars)
 80    SET mParameters["Discrete_vals"]: (aProbs)
 81}
 82ELSE {
 83    CC "AdoScript" ERRORBOX ("Error: Distribution type not found/recognised")
 84    EXIT
 85}
 86
 87# Initially get a random value in range [0,1)
 88SET fRandomValInit: (random())
 89SET fPi: (3.14159265)
 90
 91# Get the random value based on the distribution type using a procedure
 92GET_DIST_VAL sDistribType: (sDistType) mParamMap: (mParameters) fRandomVal: (fRandomValInit) fResult:fResult
 93
 94# We write the random value to the attribute "Random Value". Note: Since we have to allow for the case of distribution of type "Discrete"
 95# this attribute is a string.
 96CC "Core" SET_ATTR_VAL objid: (nObjID) attrname:"Random Value" val: (fResult)
 97
 98# Procedure to produce the value of a distribution for a given random value
 99PROCEDURE GET_DIST_VAL sDistribType:string mParamMap:map fRandomVal:real fResult:reference {
100    IF (sDistribType = "Normal") {
101        SET fMu: ((mParamMap["Normal"])[0])
102        SET fSigma: ((mParamMap["Normal"])[1])
103       
104        SET fResult: ((1/(2 * fSigma * sqrt(fPi))) * (exp(-(((fRandomVal - fMu) * (fRandomVal - fMu))/(2 * fSigma * fSigma)))))
105    }
106    IF (sDistribType = "Exponential") {
107        SET fLambda: ((mParamMap["Exponential"])[0])
108
109        SET fResult: (-(1/fLambda) * (log(1 - fRandomVal)))
110    }
111    IF (sDistribType = "Uniform") {
112        SET fUpperUniform: ((mParamMap["Uniform"])[0])
113        SET fLowerUniform: ((mParamMap["Uniform"])[1])
114       
115        IF (fUpperUniform = fLowerUniform) {
116            CC "AdoScript" ERRORBOX ("Error: Uniform distribution undefined on zero length interval (Lower bound = Upper bound)")
117            EXIT
118        }
119        ELSIF (fUpperUniform < fLowerUniform) {
120            CC "AdoScript" ERRORBOX ("Error: Upper bound < Lower bound")
121            EXIT
122        }
123        ELSE {
124            SET fResult: (fLowerUniform + fRandomVal * (fUpperUniform - fLowerUniform))
125        }   
126    }
127
128    IF (sDistribType = "Triangle") {
129        SET fUpperTriangle: ((mParamMap["Triangle"])[0])
130        SET fMediumTriangle: ((mParamMap["Triangle"])[1])
131        SET fLowerTriangle: ((mParamMap["Triangle"])[2])
132        # There is a problem with the inverse CDF if the random value is exactly one or zero
133        IF ((fRandomVal = 1) OR (fRandomVal = 0)) {
134            CC "AdoScript" ERRORBOX ("Error: Exception occurred, please try again")
135            EXIT
136        }       
137        IF ((fUpperTriangle < fLowerTriangle) OR (fUpperTriangle < fMediumTriangle) OR (fMediumTriangle < fLowerTriangle)) {
138            CC "AdoScript" ERRORBOX ("Error: Parameters need to be Lower < Medium < Upper")
139            EXIT
140        }
141        ELSE {
142            SET fc: ((fMediumTriangle - fLowerTriangle)/(fUpperTriangle - fLowerTriangle))
143            
144            IF ((fRandomVal < fc) AND (fRandomVal > 0)) {
145                SET fResult: (fLowerTriangle + sqrt(fRandomVal * (fUpperTriangle - fLowerTriangle) * (fMediumTriangle - fLowerTriangle)))
146            }
147            ELSE ((fc <= fRandomVal) AND (fRandomVal < 1)) {
148                SET fResult: (fUpperTriangle - sqrt((1 - fRandomVal) * (fUpperTriangle - fLowerTriangle) * (fUpperTriangle - fMediumTriangle)))
149            }   
150        }
151    }
152
153    IF (sDistribType = "Discrete") {
154        SET aProbs: (mParamMap["Discrete_vals"])
155        SET aVariables: (mParamMap["Discrete_vars"])
156
157        SET nNumProbs: (LEN aProbs)
158        # This loop orders the prob vals in increasing order, and arranges the variables
159        # in the corresponding order
160        FOR i from: (0) to: (nNumProbs - 1) {
161            FOR j from: (i) to: (nNumProbs - 1) {
162                SET fCurrentProb: (aProbs[i])
163                SET fCompProb: (aProbs)
164                SET sCurrentVar: (aVariables[i])
165                SET sCompVar: (aVariables)
166                    IF (fCompProb <= fCurrentProb) {
167                        SET dummy: (areplace(aProbs, i, fCompProb))
168                        SET dummy: (areplace(aProbs, j, fCurrentProb))
169                        SET dummy: (areplace(aVariables, i, sCompVar))
170                        SET dummy: (areplace(aVariables, j, sCurrentVar))                   
171                    }       
172            }            
173        }
174
175        # Next we cumulate the probabilities, which will then allow us to choose one of them
176        # according to the random variable
177        SET aCumProbs: (array(nNumProbs))
178        SET fCumulator: (VAL aProbs[0])
179        SET aCumProbs[0]: (fCumulator)
180        FOR i from: (1) to: (nNumProbs - 1) {
181            SET fCumulator: (fCumulator + (VAL aProbs[i]))
182            SET aCumProbs[i]: (fCumulator)
183        }
184
185        IF (fRandomVal < aCumProbs[0]) {
186            SET fResult: (aVariables[0])
187        }
188        ELSE {
189            FOR j from: (0) to: (nNumProbs - 2) {
190                IF ((aCumProbs <= fRandomVal) AND (fRandomVal < aCumProbs[j+1])) {
191                    SET fResult: (aVariables[j+1])
192                }
193            }
194        }
195    }
196
197    # We use the Box-Muller transform to get the value for the Gaussian (Normal) case
198    IF (sDistribType = "Normal") {
199        # First load the parameters
200        SET fMu: ((mParamMap["Normal"])[0])
201        SET fSigma: ((mParamMap["Normal"])[1])
202        # We need two random numbers in [0,1) for this
203        SET fRanVal1: (fRandomVal)
204        SET fRanVal2: (random())
205        # This gives a Normal distributed rand number with mean 0 and std. dev. 1
206        SET fResult: (sqrt(-2 * log(fRanVal1)) * cos(2 * fPi * fRanVal2))
207        # We now add the mean and multiply by the std. dev. accordingly
208        SET fResult: (fMu + fSigma * fResult)
209    }
210}


Get random value using JAVA:

When the "Generate random value using JAVA" button is pushed, the AdoScript "fetchValueJAVA.asc" is called which reads in the distribution type and parameters and in turn calls a Java program "GenerateRandomValue" to generate a random value based on the distribution. To do this, as commented in the code, a temporary file is created where the result of the Java program is stored. This generated value is then read from this temporary file and again saved back into the attribute "Random Value". In the case of a normal distribution this uses a Java library to generate the value, whereas in the other cases it uses the same algorithms as implemented in the AdoScript code just written in Java. The key point about this is the method of implementation of how the AdoScript code calls the Java. This could be expanded to perform more complicated procedures or, for example, to generate not just one value, but many. In principle, a similar method could be used to link to an external statistics package such as R. The AdoScript code is then as follows


  1#######################################################################
  2# Returns a random variable based on a given distribution using JAVA  #
  3#######################################################################
  4
  5# Get the current working directory, and set the names for temporary files to be used
  6CC "AdoScript" GET_CWD
  7SET sCWD: (cwd)
  8SET sJavaFileTemp: (sCWD + "\\tools\\GenerateRandomValue.class")
  9SET sTempResultsFile: (sCWD + "\\tools\\RandValTemp.txt")
 10
 11# Copy the Java program to a temporary location to be run. If there is an error in copying, inform the user
 12CC "AdoScript" FILE_COPY from: ("db:\\GenerateRandomValue.class") to: (sJavaFileTemp)
 13IF (ecode != 0) {
 14    CC "AdoScript" ERRORBOX "Error copying file, you might need to start modelling toolkit with Windows administrator privileges"
 15}
 16
 17# Load the string that defines the distribution, which is stored in the attribute "Distribution Type"
 18CC "Core" GET_ATTR_VAL objid: (nObjID) attrname:"Distribution Type"
 19SET sDistTypeAttrString: (val)
 20
 21# Determine which distribution type it is by parsing the string. For the moment, assume only one type is present.
 22SET sDistType: (copy(sDistTypeAttrString, 0, search(sDistTypeAttrString,"(", 0)))
 23
 24IF (sDistType = "Normal") {
 25    # Parse the string to find the parameters
 26    SET fMu: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,";", 0) - 1), ",", "."))
 27    SET fSigma: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,";", 0) + 2, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 28
 29    # Run the Java program, passing the distribution parameters and the location of a temporary file where the random value is written
 30    SET sJavaTempResultsFile: (replall(sTempResultsFile, "\\", "/"))
 31    SYSTEM ("cmd /c java -cp \"" + sCWD + "\\tools\" GenerateRandomValue " + "\"" + sJavaTempResultsFile + "\"" + " " + sDistType + " " + (STR fMu) + " " +  (STR fSigma))   
 32}
 33ELSIF (sDistType = "Uniform") {
 34    # Parse the string to find the parameters
 35    SET fLowerUniform: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,";", 0) - 1), ",", "."))
 36    SET fUpperUniform: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,";", 0) + 2, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 37   
 38    IF (fUpperUniform = fLowerUniform) {
 39        CC "AdoScript" ERRORBOX ("Error: Uniform distribution undefined on zero length interval (Lower bound = Upper bound)")
 40        EXIT
 41    }
 42    ELSIF (fUpperUniform < fLowerUniform) {
 43        CC "AdoScript" ERRORBOX ("Error: Upper bound < Lower bound")
 44        EXIT
 45    }
 46    ELSE {
 47        # Run the Java program, passing the distribution parameters and the location of a temporary file where the random value is written
 48        SET sJavaTempResultsFile: (replall(sTempResultsFile, "\\", "/"))
 49        SYSTEM ("cmd /c java -cp \"" + sCWD + "\\tools\" GenerateRandomValue " + "\"" + sJavaTempResultsFile + "\"" + " " + sDistType + " " + (STR fUpperUniform) + " " +  (STR fLowerUniform))
 50    }   
 51}
 52ELSIF (sDistType = "Exponential") {
 53    # Parse the string to find the parameters
 54    SET fLambda: (VAL replall(copy(sDistTypeAttrString, search(sDistTypeAttrString,"(", 0) + 1, search(sDistTypeAttrString,")", 0) - 1), ",", "."))
 55
 56    IF (fLambda = 0) {
 57        CC "AdoScript" ERRORBOX ("Error: Rate cannot be zero for exponential distribution")
 58        EXIT
 59    }
 60    ELSE {
 61    # Run the Java program, passing the distribution parameters and the location of a temporary file where the random value is written
 62    SET sJavaTempResultsFile: (replall(sTempResultsFile, "\\", "/"))
 63    SYSTEM ("cmd /c java -cp \"" + sCWD + "\\tools\" GenerateRandomValue " + "\"" + sJavaTempResultsFile + "\"" + " " + sDistType + " " + (STR fLambda))
 64    }
 65}
 66ELSIF (sDistType = "Triangle") {
 67    # Parse parameters when the dialog box has the triangle option
 68    SET sDistTypeAttrString: (replall(sDistTypeAttrString, "Triangle", ""))
 69    SET sDistTypeAttrString: (replall(sDistTypeAttrString, "(", ""))
 70    SET sDistTypeAttrString: (replall(sDistTypeAttrString, " ", ""))
 71    SET sDistTypeAttrString: (replall(sDistTypeAttrString, ")", ""))
 72    SET nFirstPos: (search(sDistTypeAttrString,";", 0))
 73    SET nSecondPos: (search(sDistTypeAttrString,";", nFirstPos + 1))
 74
 75    SET fLowerTriangle: (VAL copy(sDistTypeAttrString, 0, nFirstPos))
 76    SET fMediumTriangle: (VAL copy(sDistTypeAttrString, nFirstPos + 1, nSecondPos - 1))
 77    SET fUpperTriangle: (VAL copy(sDistTypeAttrString, nSecondPos + 1, LEN (sDistTypeAttrString)))
 78
 79    IF ((fUpperTriangle < fLowerTriangle) OR (fUpperTriangle < fMediumTriangle) OR (fMediumTriangle < fLowerTriangle)) {
 80        CC "AdoScript" ERRORBOX ("Error: Parameters need to be Lower < Medium < Upper")
 81        EXIT
 82    }
 83    ELSE {
 84        # Run the Java program, passing the distribution parameters and the location of a temporary file where the random value is written
 85        SET sJavaTempResultsFile: (replall(sTempResultsFile, "\\", "/"))
 86        SYSTEM ("cmd /c java -cp \"" + sCWD + "\\tools\" GenerateRandomValue " + "\"" + sJavaTempResultsFile + "\"" + " " + sDistType + " " + (STR fUpperTriangle) + " " +  (STR fMediumTriangle) + " " + (STR fLowerTriangle))
 87    }
 88}
 89ELSIF (sDistType = "Discrete") {
 90    CC "AdoScript" INFOBOX "Discrete distribution not presently supported using Java"   
 91}
 92
 93ELSE {
 94    CC "AdoScript" ERRORBOX ("Error: Distribution type not found/recognised")
 95    EXIT
 96}
 97
 98# The Java program will have saved a random value in the temporary file. We now read in this value from the file.
 99CC "AdoScript" FREAD file: (sTempResultsFile)
100SET sRandVal: (VAL text)   
101
102# We write the random value to the attribute "Random Value". Note: Since we have to allow for the case of distribution of type "Discrete"
103# this attribute is a string.
104CC "Core" SET_ATTR_VAL objid: (nObjID) attrname:"Random Value" val: (sRandVal)
105
106# Clean up the temporary files that were created.
107CC "AdoScript"  DELETE_FILES (sTempResultsFile)
108CC "AdoScript"  DELETE_FILES (sJavaFileTemp)

As mentioned previously, the reason that the modelling toolkit needs to be run with windows administrator privileges for Java to work is simply because the temporary files are saved to a system directory. It is not necessary to change this. However, if you want you can change certain lines appropriately so that it, for example, loads to a folder that you have specified instead. As long as the folder you choose is not a system or protected folder the modellnig toolkit can then be run normally. For example, if you wanted it to save to "C:\MyTempFolder" you would create a folder with this name and change the following lines of code so that they read

Line 9 would now read:

1SET sJavaFileTemp: ("C:\\MyTempFolder\\GenerateRandomValue.class")


Line 10 would now read:

1SET sTempResultsFile: ("C:\\MyTempFolder\\RandValTemp.txt")


Lines 32, 50, 64 and 87 would now read:

1SYSTEM ("cmd /c java -cp \"C:\\MyTempFolder" + "\" GenerateRandomValue " + "\"" + ....

where the dots indicate that the rest of the string remains the same with only the first part changing.

As mentioned, the AdoScript calls some Java code. The code that is called reads

 1import java.util.Random;
 2import java.io.PrintWriter;
 3import java.io.*;
 4import java.lang.*;
 5
 6public final class GenerateRandomValue {
 7
 8  public static void main(String[] args){
 9    String FileNameArg = args[0];
10    GenerateRandomValue distrandom = new GenerateRandomValue();
11
12    if (args[1].equals("Normal")) {
13    double MEAN = Double.parseDouble(args[2]);
14    double VARIANCE = Double.parseDouble(args[3]);
15
16    WriteToFile(FileNameArg, distrandom.getGaussian(MEAN, VARIANCE));
17    }
18    else if (args[1].equals("Exponential")) {
19    double lambda = Double.parseDouble(args[2]);
20   
21    WriteToFile(FileNameArg, distrandom.getExponential(lambda));
22    }
23    else if (args[1].equals("Uniform")) {
24    double lowerlim = Double.parseDouble(args[2]);
25    double upperlim = Double.parseDouble(args[3]);
26   
27    WriteToFile(FileNameArg, distrandom.getUniform(lowerlim, upperlim));
28    }
29    else if (args[1].equals("Triangle")) {
30    double upperlim = Double.parseDouble(args[2]);
31    double middleval = Double.parseDouble(args[3]);
32    double lowerlim = Double.parseDouble(args[4]);
33
34    WriteToFile(FileNameArg, distrandom.getTriangle(upperlim, middleval, lowerlim));
35    }
36   
37  }
38   
39  private Random fRandom = new Random();
40
41  private double getGaussian(double aMean, double aVariance){
42    return aMean + fRandom.nextGaussian() * aVariance;
43  }
44
45  private double getExponential(double lambda){
46    double x = ( - 1/lambda) * Math.log(1 - fRandom.nextDouble());
47    return x;
48  }
49
50  private double getUniform(double lower, double upper){
51    double x = lower + fRandom.nextDouble() * (upper - lower);
52    return x;
53  }
54
55  private double getTriangle(double upper, double middle, double lower){
56    double u = fRandom.nextDouble();
57    double fc = (middle - lower)/(upper - lower);
58    double result = 0.0;
59    if ((u < fc) && (u > 0)) {
60       
61        result = lower + Math.sqrt(u * (upper - lower) * (middle - lower));
62    }
63    else if ((fc <= u) && (u < 1)) {
64   
65        result = upper - Math.sqrt((1 - u) * (upper - lower) * (upper - middle));
66    }
67    return result;
68  }
69
70  private static void     WriteToFile(String filename, Object aMsg){
71
72    File file = new File (filename);
73
74    try
75    {
76        PrintWriter printWriter = new PrintWriter(filename);
77        printWriter.println(aMsg);
78        printWriter.close();      
79    }
80    catch (FileNotFoundException ex) 
81    {
82        System.out.println(ex);
83    }
84  }
85}

Hope this helps, but please get back to us if this doesn't answer your questions sufficiently or you have further questions.

The library:
Random Generator Library.abl

AdoScripts:

fetchValue.asc
fetchValueJAVA.asc

Java script and class:

GenerateRandomValue.java
GenerateRandomValue.class

RE: Generating random values based on distributions for simulations in ADOx
Answer
4/27/17 10:07 AM as a reply to David Burke.
Dear All,

inspired by the here provided solutions (and out of necessity for a project) I created a few functions which provide random variables according to several different distributions. Since they are functions, they can be directly called in AdoScript expressions (e.g. SET). The currently implemented distributions are:
  • randomStandardUniformDist() --> a random value from a uniform distribution between (including) 0.0 and (excluding) 1.0, so it is very close to the Standard Uniform Distribution. It is simply the random() function from ADOxx.
  • randomUniformDist(lower_limit, upper_limit) --> a random value from a uniform distribution between (including) the lower limit and (excluding) the upper limit.
  • randomStandardNormalDist() --> a random value from a standard normal distribution (i.e. expectancy value = 0, standard deviation = 1) based on Box-Muller transformation using a natural logarithm.
  • randomNormalDist(expectancy_value, standard_deviation) --> a random value from a normal distribution with a specific expectancy and standard deviation based on Box-Muller transformation using a natural logarithm.
  • randomTriangularDist(lower_limit, mode, upper_limit) --> a random value from a triangular distribution based on inverse CDF from "Beyond Beta - Other Continuous Families of Distributions with Bounded Support and Applications". The triangle is build from lower_limit to upper_limit with its peak at mode.
  • randomExponentialDist(inverse_scale) --> a random value from an exponential distribution based on inverse CDF using the inverse scale provided (lambda).
  • randomDiscreteDistPositions(probabilities) --> a random value from a discrete set of probabilities. The probabilities have to be an array and the returned value is a position index (0 to (LEN probabilities)-1) from the array. The sum of all probabilities should be 1.0.
  • randomDiscreteDistValues(value_probabilities) --> a random value from a discrete set of values and their corresponding probabilities. The value_probabilities have to be a map (key-value pairs), where the keys are the possible values (either strings or numbers, keys should not contain a comma) and their values should be their probability. The sum of all probabilities should be 1.0.
  • randomDiscreteUniformDist(lower_limit, upper_limit) --> a random value from a discrete uniform distribution of integers between (including) the lower limit and (excluding) the upper limit.
  • randomBernoulliDist(probability) --> either 1 or 0 based on the Bernoulli distribution, with the parameter indicating the probability of the value 1. A probability of 0.5 can be considered a coin-toss.
  • randomRademacherDist() --> either 1 or -1 based on the Rademacher distribution, where the probabilities of both cases are 50%.
  • randomCoinToss() --> either 1 or 0 based on a fair coin, with 50/50 chance. So same as randomRademacherDist, only with other outcomes.
Some additional details can be found as comments in the attached code.

Best regards,
Patrik
Attachments: ASC_RandomDistributions.asc (9.1k)