From: <mar...@us...> - 2008-02-04 04:32:39
|
Revision: 85 http://gridsim.svn.sourceforge.net/gridsim/?rev=85&view=rev Author: marcos_dias Date: 2008-02-03 20:32:43 -0800 (Sun, 03 Feb 2008) Log Message: ----------- This update includes a workload class that generates gridlets according to Lublin and Feitelson's workload model. The model is described in: Uri Lublin and Dror G. Feitelson, The Workload on Parallel Supercomputers: Modeling the Characteristics of Rigid Jobs. J. Parallel & Distributed Comput. 63(11), pp. 1105-1122, Nov 2003. This update also includes a short example on how to use the Lubin99Workload class. Added Paths: ----------- branches/gridsim4.0-branch3/examples/examples/workload/parallel/LublinWorkloadExample01.java branches/gridsim4.0-branch3/source/gridsim/turbo/Lublin99Workload.java Added: branches/gridsim4.0-branch3/examples/examples/workload/parallel/LublinWorkloadExample01.java =================================================================== --- branches/gridsim4.0-branch3/examples/examples/workload/parallel/LublinWorkloadExample01.java (rev 0) +++ branches/gridsim4.0-branch3/examples/examples/workload/parallel/LublinWorkloadExample01.java 2008-02-04 04:32:43 UTC (rev 85) @@ -0,0 +1,182 @@ + +package examples.workload.parallel; + +import gridsim.GridResource; +import gridsim.GridSim; +import gridsim.Machine; +import gridsim.MachineList; +import gridsim.turbo.Lublin99Workload; +import gridsim.turbo.TResourceCharacteristics; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.LinkedList; +import java.util.Random; + +/** + * Test Driver class for this example + */ +public class LublinWorkloadExample01 +{ + /** + * Creates main() to run this example + */ + public static void main(String[] args) + { + long startTime = System.currentTimeMillis(); + + try { + + ////////////////////////////////////////// + // Get the workload to be used The format should be: + // ASCII text, gzip or zip. + + ArrayList<GridResource> resources = new ArrayList<GridResource>(); + + ////////////////////////////////////////// + // Initialize the GridSim package. It should be called + // before creating any entities. We can't run this example without + // initializing GridSim first. We will get run-time exception + // error. + + // number of grid user entities + any Workload entities. + int num_user = 1; + Calendar calendar = Calendar.getInstance(); + boolean trace_flag = false; // mean trace GridSim events + + long seed = 1062348; + + // Initialize the GridSim package without any statistical + // functionalities. Hence, no GridSim_stat.txt file is created. + System.out.println("Initializing GridSim package"); + GridSim.init(num_user, calendar, trace_flag); + + ////////////////////////////////////////// + // Creates one or more GridResource entities + int totalResource = 1; // total number of Grid resources + int rating = 377; // rating of each PE in MIPS + int totalPE = 9; // total number of PEs for each Machine + int totalMachine = 128; // total number of Machines + int i = 0; + + String[] resArray = new String[totalResource]; + for (i = 0; i < totalResource; i++) { + String resName = "Res_" + i; + GridResource resource = createGridResource(resName, rating, totalMachine, totalPE); + resources.add(resource); + + // add a resource name into an array + resArray[i] = resName; + } + + ////////////////////////////////////////// + // Creates one Workload trace entity. + + int resID = 0; + Random r = new Random(); + resID = r.nextInt(totalResource); + Lublin99Workload workload = + new Lublin99Workload("Load_1", resArray[resID], rating, false, seed); + + // uHi is going to contain log2 of the maximum number of PEs that a + // parallel job can require + double uHi = Math.log(totalPE * totalMachine) / Math.log(2d); + double uMed = uHi-2.5; + + workload.setParallelJobProbabilities(Lublin99Workload.BATCH, + Lublin99Workload.ULOW_BATCH, uMed, uHi, + Lublin99Workload.UPROB_BATCH); + + // sets the workload to create 1000 jobs + workload.setNumJobs(1000); + + ////////////////////////////////////////// + // Starts the simulation in debug mode +// GridSim.startGridSimulation(true); + + // Start the simulation in normal mode + GridSim.startGridSimulation(); + + ////////////////////////////////////////// + // Final step: Prints the Gridlets when simulation is over + long finishTime = System.currentTimeMillis(); + System.out.println("The simulation took " + (finishTime - startTime) + " milliseconds"); + + // prints the Gridlets inside a Workload entity + // workload.printGridletList(trace_flag); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Creates one Grid resource. A Grid resource contains one or more + * Machines. Similarly, a Machine contains one or more PEs (Processing + * Elements or CPUs). + * @param name a Grid Resource name + * @param peRating rating of each PE + * @param totalMachine total number of Machines + * @param totalPE total number of PEs for each Machine + */ + private static GridResource createGridResource(String name, int peRating, + int totalMachine, int totalPE) + { + + ////////////////////////////////////////// + // Here are the steps needed to create a Grid resource: + // 1. We need to create an object of MachineList to store one or more + // Machines + MachineList mList = new MachineList(); + + for (int i = 0; i < totalMachine; i++) + { + ////////////////////////////////////////// + // 4. Create one Machine with its id and list of PEs or CPUs + mList.add( new Machine(i, totalPE, peRating) ); + } + + ////////////////////////////////////////// + // 5. Create a ResourceCharacteristics object that stores the + // properties of a Grid resource: architecture, OS, list of + // Machines, allocation policy: time- or space-shared, time zone + // and its price (G$/PE time unit). + String arch = "Sun Ultra"; // system architecture + String os = "Solaris"; // operating system + double time_zone = 0.0; // time zone this resource located + double cost = 3.0; // the cost of using this resource + + TResourceCharacteristics resConfig = new TResourceCharacteristics( + arch, os, mList, TResourceCharacteristics.CB_PARALLEL_SPACE_SHARED, + time_zone, cost); + + ////////////////////////////////////////// + // 6. Finally, we need to create a GridResource object. + double baud_rate = 10000.0; // communication speed + long seed = 11L*13*17*19*23+1; + double peakLoad = 0.0; // the resource load during peak hour + double offPeakLoad = 0.0; // the resource load during off-peak hr + double holidayLoad = 0.0; // the resource load during holiday + + // incorporates weekends so the grid resource is on 7 days a week + LinkedList weekends = new LinkedList(); + weekends.add(new Integer(Calendar.SATURDAY)); + weekends.add(new Integer(Calendar.SUNDAY)); + + // incorporates holidays. However, no holidays are set in this example + LinkedList holidays = new LinkedList(); + GridResource gridRes = null; + try { + gridRes = new GridResource(name, baud_rate, seed, + resConfig, peakLoad, offPeakLoad, holidayLoad, weekends, + holidays); + } + catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("Creates one Grid resource with name = " + name); + return gridRes; + } +} // end class + Added: branches/gridsim4.0-branch3/source/gridsim/turbo/Lublin99Workload.java =================================================================== --- branches/gridsim4.0-branch3/source/gridsim/turbo/Lublin99Workload.java (rev 0) +++ branches/gridsim4.0-branch3/source/gridsim/turbo/Lublin99Workload.java 2008-02-04 04:32:43 UTC (rev 85) @@ -0,0 +1,1422 @@ +/* + * Title: GridSim Toolkit + * Description: GridSim (Grid Simulation) Toolkit for Modeling and Simulation + * of Parallel and Distributed Systems such as Clusters and Grids + * Licence: GPL - http://www.gnu.org/copyleft/gpl.html + * + */ + +package gridsim.turbo; + +import eduni.simjava.*; +import gridsim.*; +import gridsim.net.*; +import java.util.*; + +/** + * The main purpose of this class is to create a realistic simulation + * environment where your jobs or Gridlets are competing with others. + * In other words, the grid resource might not be available at certain times. + * In addition, the arrival time of jobs are also captured in the workload model. + * <p> + * This class is responsible for creating jobs according to the workload model + * generator presented by Lublin and Feitelson and send Gridlets to only + * <tt>one</tt> destinated resource. <br> + * <b>NOTE:</b> + * <ul> + * <li> This class can be classified as <b>one grid user entity</b>. + * Hence, you need to incorporate this entity into <tt>numUser</tt> + * during {@link gridsim.GridSim#init(int, Calendar, boolean)} + * <li> If you need to use multiple trace files to submit Gridlets to + * same or different resources, then you need to create multiple + * instances of this class <tt>each with a unique entity name</tt>. + * <li> If you are running an experiment using the network extension, + * i.e. the gridsim.net package, then you need to use + * {@link #Lublin99Workload(String, double, double, int, String, String, int)} + * instead. + * <li> The default job file size for sending to and receiving from + * a resource is {@link gridsim.net.Link#DEFAULT_MTU}. + * However, you can specify + * the file size by using {@link #setGridletFileSize(int)}. + * <li> A job run time is only for 1 PE <tt>not</tt> the total number of + * allocated PEs. + * Therefore, a Gridlet length is also calculated for 1 PE.<br> + * For example, job #1 in the trace has a run time of 100 seconds + * for 2 processors. This means each processor runs + * job #1 for 100 seconds, if the processors have the same + * specification. + * </ul> + * <p> + * For more information on the workload model, please read the following paper: <br> + * Uri Lublin and Dror G. Feitelson, The Workload on Parallel Supercomputers: + * Modeling the Characteristics of Rigid Jobs. J. Parallel & Distributed Comput. 63(11), + * pp. 1105-1122, Nov 2003. + * <br> + * + * @see gridsim.GridSim#init(int, Calendar, boolean) + * @author Marcos Dias de Assuncao + * @since GridSim Turbo Alpha 0.1 + * @invariant $none + */ +public class Lublin99Workload extends GridSim { + + private String resName_; // resource name + private int resID_; // resource ID + private int rating_; // a PE rating + private int gridletID_; // gridletID + private int size_; // job size for sending it through a network + private ArrayList list_; // a list for getting all the Gridlets + private Random random_ = null; // the number generator to be used + + // Log PI for lgamma method + private static final double LOGPI = 1.14472988584940017414; + protected final int INTERVAL = 10; // number of intervals + + // ------------ CONSTANTS USED BY THE WORKLOAD MODEL -------------- + + // number of jobs generated by this entity + private static final int SIZE = 1000; + + // no more than two days =exp(12) for runtime + private static final int TOO_MUCH_TIME = 12; + + // no more than 5 days =exp(13) for arrivetime + private static final int TOO_MUCH_ARRIVE_TIME = 13; + + // number of buckets in one day -- 48 half hours + private static final int BUCKETS = 48; + + // we now define (calculate) how many seconds are in one hour,day,bucket + private static final int SECONDS_IN_HOUR = 3600; + private static final int SECONDS_IN_DAY = (24*SECONDS_IN_HOUR); + private static final int SECONDS_IN_BUCKET = (SECONDS_IN_DAY/BUCKETS); + private static final int HOURS_IN_DAY = 24; + + // The hours of the day are being moved cyclically. + // instead of [0,23] make the day [CYCLIC_DAY_START,(24+CYCLIC_DAY_START-1)] + private static final int CYCLIC_DAY_START = 11; + + // max iterations number for the iterative calculations + private static final int ITER_MAX = 1000; + + // small epsilon for the iterative algorithm's accuracy + private static final double EPS = 1E-10; + + /** Represents interactive jobs */ + public static final int INTERACTIVE = 0; + + /** Represents batch jobs */ + public static final int BATCH = 1; + + // ------------------- MODEL DEFAULT PARAMETERS ----------------------- + + /* The parameters for number of nodes: + * serial_prob is the proportion of the serial jobs + * pow2_prob is the proportion of the jobs with power 2 number of nodes + * ULow , UMed , UHi and Uprob are the parameters for the two-stage-uniform + * which is used to calculate the number of nodes for parallel jobs. + * ULow is the log2 of the minimal size of job in the system (you can add or + * subtract 0.2 to give less/more probability to the minimal size) . + * UHi is the log2 of the maximal size of a job in the system (system's size) + * UMed should be in [UHi-1.5 , UHi-3.5] + * Uprob should be in [0.7 - 0.95] + */ + public static final double SERIAL_PROB_BATCH = 0.2927; + public static final double POW2_PROB_BATCH = 0.6686; + public static final double ULOW_BATCH = 1.2f; // smallest parallel batch job has 2 nodes + public static final double UMED_BATCH = 5; + public static final double UHI_BATCH = 7; // biggest batch job has 128 nodes + public static final double UPROB_BATCH = 0.875; + + public static final double SERIAL_PROB_ACTIVE = 0.1541; + public static final double POW2_PROB_ACTIVE = 0.625; + public static final double ULOW_ACTIVE = 1; // smallest interactive parallel job has 2 nodes + public static final double UMED_ACTIVE = 3; + public static final double UHI_ACTIVE = 5.5f; // biggest interactive job has 45 nodes + public static final double UPROB_ACTIVE = 0.705; + + /* The parameters for the running time + * The running time is computed using hyper-gamma distribution. + * The parameters a1,b1,a2,b2 are the parameters of the two gamma distributions + * The p parameter of the hyper-gamma distribution is calculated as a straight + * (linear) line p = pa*nodes + pb. + * 'nodes' will be calculated in the program, here we defined the 'pa','pb' + * parameters. + */ + public static final double A1_BATCH = 6.57; + public static final double B1_BATCH = 0.823; + public static final double A2_BATCH = 639.1; + public static final double B2_BATCH = 0.0156; + public static final double PA_BATCH = -0.003; + public static final double PB_BATCH = 0.6986; + + public static final double A1_ACTIVE = 3.8351; + public static final double B1_ACTIVE = 0.6605; + public static final double A2_ACTIVE = 7.073; + public static final double B2_ACTIVE = 0.6856; + public static final double PA_ACTIVE = -0.0118; + public static final double PB_ACTIVE = 0.9156; + + + /* The parameters for the inter-arrival time + * The inter-arriving time is calculated using two gamma distributions. + * gamma(aarr,barr) represents the inter_arrival time for the rush hours. It is + * independent on the hour the job arrived at. + * The cdf of gamma(bnum,anum) represents the proportion of number of jobs which + * arrived at each time interval (bucket). + * The inter-arrival time is calculated using both gammas + * Since gamma(aarr,barr) represents the arrive-time at the rush time , we use + * a constant ,ARAR (Arrive-Rush-All-Ratio), to set the alpha parameter (the new + * aarr) so it will represent the arrive-time at all hours of the day. + */ + public static final double AARR_BATCH = 6.0415; + public static final double BARR_BATCH = 0.8531; + public static final double ANUM_BATCH = 6.1271; + public static final double BNUM_BATCH = 5.2740; + public static final double ARAR_BATCH = 1.0519; + + public static final double AARR_ACTIVE = 6.5510; + public static final double BARR_ACTIVE = 0.6621; + public static final double ANUM_ACTIVE = 8.9186; + public static final double BNUM_ACTIVE = 3.6680; + public static final double ARAR_ACTIVE = 0.9797; + + /* + * Here are the model's parameters for typeless data (no batch nor interactive) + * We use those parameters when INCLUDE_JOBS_TYPE is off (0) + */ + public static final double SERIAL_PROB = 0.244; + public static final double POW2_PROB = 0.576; + public static final double ULOW = 0.8f; // The smallest parallel job is 2 nodes + public static final double UMED = 4.5f; + public static final double UHI = 7f; // SYSTEM SIZE is 2^UHI == 128 + public static final double UPROB = 0.86; + + public static final double A1 = 4.2; + public static final double B1 = 0.94; + public static final double A2 = 312; + public static final double B2 = 0.03; + public static final double PA = -0.0054; + public static final double PB = 0.78; + + public static final double AARR = 10.2303; + public static final double BARR = 0.4871; + public static final double ANUM = 8.1737; + public static final double BNUM = 3.9631; + public static final double ARAR = 1.0225; + + // start the simulation at midnight (hour 0) + private static final int START = 0; + + // -------------- Variable dependent attributes -------------------- + + // The workload duration, that is, for how long the workload can + // go creating and submitting gridlets. numJobs keeps the number of + // jobs that this workload should generate. The workload will + // finish when it apporaches whichever of these values + private double workloadDuration_; + private int numJobs_; + + private double[] a1, b1, a2, b2, pa, pb; + private double[] aarr, barr, anum, bnum; + private double[] serialProb, pow2Prob, uLow, uMed, uHi, uProb; + + // the appropriate weight (points) for each + // time-interval used in the arrive function + double[][] weights = new double[2][BUCKETS]; + + /* useJobType us if we should differ between batch and interactive + * jobs or not. If the value is true, then we use both batch and interactive + * values for the parameters and the output sample includes both interactive + * and batch jobs. We choose the type of the job to be the type whose next + * job arrives to the system first (smaller next arrival time). + * If the value is false, then we use the "whole sample" parameters. The output + * sample includes jobs from the same type (arbitrarily we choose batch). + * We force the type to be interactive by setting the next arrival time of + * interactive jobs to be Long.MAX_VALUE -- always larger than the batchs's + * next arrival. */ + private boolean useJobType_ = true; + + /* current time interval (the bucket's number) */ + private int[] current_; + + /* the number of seconds from the beginning of the simulation*/ + private long[] timeFromBegin_; + + /** + * Create a new Workload object <b>without</b> using the network extension. + * This means this entity directly sends Gridlets to a destination resource + * without going through a wired network. <br> + * <tt>NOTE:</tt> + * You can not use this constructor in an experiment that uses a wired + * network topology. + * @param name this entity name + * @param resourceName the resource name + * @param rating the resource's PE rating + * @param useJobType useJobType us if we should differ between batch and interactive + * jobs or not. If the value is <tt>true</tt>, then we use both batch and interactive + * values for the parameters and the output sample includes both interactive + * and batch jobs. We choose the type of the job to be the type whose next + * job arrives to the system first (smaller next arrival time). + * If the value is <tt>false</tt>, then we use the "whole sample" parameters. The output + * sample includes jobs from the same type (arbitrarily we choose batch). + * We force the type to be interactive by setting the next arrival time of + * interactive jobs to be <tt>Long.MAX_VALUE</tt> -- always larger than the batchs's + * next arrival. + * @param seed seed used by the random number generator + * @throws Exception This happens when creating this entity before + * initialising GridSim package or this entity name is + * <tt>null</tt> or empty + * @throws ParameterException This happens for the following conditions: + * <ul> + * <li>the entity name is null or empty + * <li>the resource entity name is null or empty + * <li>the resource PE rating <= 0 + * </ul> + * @pre name != null + * @pre fileName != nullb2 + * @pre resourceName != null + * @pre rating > 0 + * @post $none + */ + public Lublin99Workload(String name, String resourceName, + int rating, boolean useJobType, long seed) + throws ParameterException, Exception { + super(name, GridSimTags.DEFAULT_BAUD_RATE); + + // check the input parameters first + String msg = name + "(): Error - "; + if (resourceName == null || resourceName.length() == 0) { + throw new ParameterException(msg + "invalid resource name."); + } + else if (rating <= 0) { + throw new ParameterException(msg+"resource PE rating must be > 0."); + } + + System.out.println(name + ": Creating a workload object ..."); + init(resourceName, rating, useJobType, seed); + } + + /** + * Create a new Workload object <b>with</b> the network extension. + * This means this entity directly sends Gridlets to a destination resourceb2 + * through a link. The link is automatically created by this constructor. + * + * @param name this entity name + * @param baudRate baud rate of this link (bits/s) + * @param propDelay Propagation delay of the Link in milliseconds + * @param MTU Maximum Transmission Unit of the Link in bytes. + * Packets which are larger than the MTU should be split + * up into MTU size units. + * For example, a 1024 byte packet trying to cross a 576 + * byte MTU link should get split into 2 packets of 576 + * bytes and 448 bytes. + * @param resourceName the resource name + * @param rating the resource's PE rating + * @param useJobType useJobType us if we should differ between batch and interactive + * jobs or not. If the value is <tt>true</tt>, then we use both batch and interactive + * values for the parameters and the output sample includes both interactive + * and batch jobs. We choose the type of the job to be the type whose next + * job arrives to the system first (smaller next arrival time). + * If the value is <tt>false</tt>, then we use the "whole sample" parameters. The output + * sample includes jobs from the same type (arbitrarily we choose batch). + * We force the type to be interactive by setting the next arrival time of + * interactive jobs to be <tt>Long.MAX_VALUE</tt> -- always larger than the batchs's + * next arrival. + * @param seed seed used by the random number generator + * @throws Exception This happens when creating this entity before + * initialising GridSim package or this entity name is + * <tt>null</tt> or empty + * @throws ParameterException This happens for the following conditions: + * <ul> + * <li>the entity name is null or empty + * <li> baudRate <= 0 + * <li> propDelay <= 0 + * <li> MTU <= 0 + * <li>the resource entity name is null or empty + * <li>the resource PE rating <= 0 + * </ul> + * @pre name != null + * @pre baudRate > 0 + * @pre propDelay > 0 + * @pre MTU > 0 + * @pre fileName != null + * @pre resourceName != null + * @pre rating > 0 + * @post $none + */ + public Lublin99Workload(String name, double baudRate, double propDelay, int MTU, + String resourceName, int rating, boolean useJobType, long seed) + throws ParameterException, Exception { + super( name, new SimpleLink(name+"_link", baudRate, propDelay, MTU) ); + + // check the input parameters first + String msg = name + "(): Error - "; + if (resourceName == null || resourceName.length() == 0) { + throw new ParameterException(msg + "invalid resource name."); + } + else if (rating <= 0) { + throw new ParameterException(msg+"resource PE rating must be > 0."); + } + + System.out.println(name + ": Creating a workload object ..."); + init(resourceName, rating, useJobType, seed); + } + + /** + * Create a new Workload object <b>with</b> the network extension. + * This means this entity directly sends Gridlets to a destination resource + * through a link. The link is automatically created by this constructor. + * + * @param name this entity name + * @param link the link that will be used to connect this Workload + * to another entity or a Router. + * @param resourceName the resource name + * @param rating the resource's PE rating + * @param useJobType useJobType us if we should differ between batch and interactive + * jobs or not. If the value is <tt>true</tt>, then we use both batch and interactive + * values for the parameters and the output sample includes both interactive + * and batch jobs. We choose the type of the job to be the type whose next + * job arrives to the system first (smaller next arrival time). + * If the value is <tt>false</tt>, then we use the "whole sample" parameters. The output + * sample includes jobs from the same type (arbitrarily we choose batch). + * We force the type to be interactive by setting the next arrival time of + * interactive jobs to be <tt>Long.MAX_VALUE</tt> -- always larger than the batchs's + * next arrival. + * @param seed seed used by the random number generator + * @throws Exception This happens when creating this entity before + * initialising GridSim package or this entity name is + * <tt>null</tt> or empty + * @throws ParameterException This happens for the following conditions: + * <ul> + * <li>the entity name is null or empty + * <li>the link is empty + * <li>the resource entity name is null or empty + * <li>the resource PE rating <= 0 + * </ul> + * @pre name != null + * @pre link != null + * @pre fileName != null + * @pre resourceName != null + * @pre rating > 0 + * @post $none + */ + public Lublin99Workload(String name, Link link, + String resourceName, int rating, boolean useJobType, long seed) + throws ParameterException, Exception { + super(name, link); + + // check the input parameters first + String msg = name + "(): Error - "; + if (resourceName == null || resourceName.length() == 0) { + throw new ParameterException(msg + "invalid resource name."); + } + else if (rating <= 0) { + throw new ParameterException(msg+"resource PE rating must be > 0."); + } + + System.out.println(name + ": Creating a workload object ..."); + init(resourceName, rating, useJobType, seed); + } + + /** + * Initialises all the attributes + * @param fileName trace file name + * @param resourceName resource entity name + * @param rating resource PE rating + * @param useJobType <tt>true</tt> whether the workload should generate + * both interactive and batch jobs; <tt>false</tt> if the workload + * should generate only batch jobs. + * @pre $none + * @post $none + */ + private void init(String resourceName, int rating, + boolean useJobType, long seed) { + + useJobType_ = useJobType; + resName_ = resourceName; + resID_ = GridSim.getEntityId(resName_); + rating_ = rating; + gridletID_ = 1; // starts at 1 to make it the same as in a trace file + list_ = null; + size_ = Link.DEFAULT_MTU; + random_ = new Random(seed); + workloadDuration_ = Double.MAX_VALUE; + numJobs_ = 1000; + + a1 = new double[2]; b1 = new double[2]; + a2 = new double[2]; b2 = new double[2]; + pa = new double[2]; pb = new double[2]; + aarr = new double[2]; barr = new double[2]; + anum = new double[2]; bnum = new double[2]; + serialProb = new double[2]; pow2Prob = new double[2]; + uLow = new double[2]; uMed = new double[2]; + uHi = new double[2]; uProb = new double[2]; + current_ = new int[2]; + timeFromBegin_ = new long[2]; + + // separate batch from interactive + if (useJobType_) { + serialProb[BATCH] = SERIAL_PROB_BATCH; + pow2Prob[BATCH] = POW2_PROB_BATCH; + uLow[BATCH] = ULOW_BATCH; + uMed[BATCH] = UMED_BATCH; + uHi[BATCH] = UHI_BATCH; + uProb[BATCH] = UPROB_BATCH; + + serialProb[INTERACTIVE] = SERIAL_PROB_ACTIVE; + pow2Prob[INTERACTIVE] = POW2_PROB_ACTIVE; + uLow[INTERACTIVE] = ULOW_ACTIVE; + uMed[INTERACTIVE] = UMED_ACTIVE; + uHi[INTERACTIVE] = UHI_ACTIVE; + uProb[INTERACTIVE] = UPROB_ACTIVE; + + a1[BATCH] = A1_BATCH; b1[BATCH] = B1_BATCH; + a2[BATCH] = A2_BATCH; b2[BATCH] = B2_BATCH; + pa[BATCH] = PA_BATCH; pb[BATCH] = PB_BATCH; + + a1[INTERACTIVE] = A1_ACTIVE; b1[INTERACTIVE] = B1_ACTIVE; + a2[INTERACTIVE] = A2_ACTIVE; b2[INTERACTIVE] = B2_ACTIVE; + pa[INTERACTIVE] = PA_ACTIVE; pb[INTERACTIVE] = PB_ACTIVE; + + aarr[BATCH] = AARR_BATCH*ARAR_BATCH; barr[BATCH] = BARR_BATCH; + anum[BATCH] = ANUM_BATCH; bnum[BATCH] = BNUM_BATCH; + + aarr[INTERACTIVE] = AARR_ACTIVE*ARAR_ACTIVE; + barr[INTERACTIVE] = BARR_ACTIVE; + anum[INTERACTIVE] = ANUM_ACTIVE; + bnum[INTERACTIVE] = BNUM_ACTIVE; + } + else { + // whole sample -- make all batch jobs + serialProb[BATCH] = serialProb[INTERACTIVE] = SERIAL_PROB; + pow2Prob[BATCH] = pow2Prob[INTERACTIVE] = POW2_PROB; + uLow[BATCH] = uLow[INTERACTIVE] = ULOW ; + uMed[BATCH] = uMed[INTERACTIVE] = UMED ; + uHi[BATCH] = uHi[INTERACTIVE] = UHI ; + uProb[BATCH] = uProb[INTERACTIVE] = UPROB ; + + a1[BATCH] = a1[INTERACTIVE] = A1; + b1[BATCH] = b1[INTERACTIVE] = B1; + a2[BATCH] = a2[INTERACTIVE] = A2; + b2[BATCH] = b2[INTERACTIVE] = B2; + pa[BATCH] = pa[INTERACTIVE] = PA; + pb[BATCH] = pb[INTERACTIVE] = PB; + + aarr[BATCH] = aarr[INTERACTIVE] = AARR * ARAR; + barr[BATCH] = barr[INTERACTIVE] = BARR; + anum[BATCH] = anum[INTERACTIVE] = ANUM; + bnum[BATCH] = bnum[INTERACTIVE] = BNUM; + } + + if ( ! useJobType_ ) // make all jobs batch + timeFromBegin_[INTERACTIVE] = Long.MAX_VALUE; + } + + /** + * Sets the probability for serial jobs + * @param jobType the type of jobs + * @param prob the probability + * @return <tt>true</tt> if the probability has been set, or + * <tt>false</tt> otherwise. + * @see #INTERACTIVE + * @see #BATCH + */ + public boolean setSerialProbability(int jobType, double prob) { + if(jobType > BATCH || jobType < INTERACTIVE) + return false; + + if(useJobType_) + serialProb[jobType] = prob; + else + serialProb[INTERACTIVE] = serialProb[BATCH] = prob; + + return true; + } + + /** + * Sets the probability for power of two jobs + * @param jobType the type of jobs + * @param prob the probability + * @return <tt>true</tt> if the probability has been set, or + * <tt>false</tt> otherwise. + * @see #INTERACTIVE + * @see #BATCH + */ + public boolean setPower2Probability(int jobType, double prob) { + if(jobType > BATCH || jobType < INTERACTIVE) + return false; + + if(useJobType_) + pow2Prob[jobType] = prob; + else + pow2Prob[INTERACTIVE] = pow2Prob[BATCH] = prob; + + return true; + } + + /** + * Sets the parameters for the two-stage-uniform + * which is used to calculate the number of nodes for parallel jobs. + * @param jobType the type of jobs + * @param uLow is the log2 of the minimal size of job in the system (you can add or + * subtract 0.2 to give less/more probability to the minimal size). + * @param uMed should be in [uHi-1.5 , uHi-3.5] + * @param uHi is the log2 of the maximal size of a job in the system (system's size) + * @param uProb should be in [0.7 - 0.95] + * @return <tt>true</tt> if the probabilities have been set, or + * <tt>false</tt> otherwise.b2 + * @see #INTERACTIVE + * @see #BATCH + */ + public boolean setParallelJobProbabilities(int jobType, + double uLow, double uMed, double uHi, double uProb) { + if(jobType > BATCH || jobType < INTERACTIVE) + return false; + else if (uLow > uHi) + return false; + else if (uMed > uHi-1.5 || uMed < uHi-3.5) + return false; + else if(uProb < 0.7 || uProb > 0.95) + return false; + + if(useJobType_) { + this.uLow[jobType] = uLow; + this.uMed[jobType] = uMed; + this.uHi[jobType] = uHi; + this.uProb[jobType] = uProb; + } + else { + this.uLow[INTERACTIVE] = this.uLow[BATCH] = uLow; + this.uMed[INTERACTIVE] = this.uMed[BATCH] = uMed; + this.uHi[INTERACTIVE] = this.uHi[BATCH] = uHi; + this.uProb[INTERACTIVE] = this.uProb[BATCH] = uProb; + } + + return true; + } + + /** Sets the parameters for the running time + * The running time is computed using hyper-gamma distribution. + * The parameters a1,b1,a2,b2 are the parameters of the two gamma distributions + * The p parameter of the hyper-gamma distribution is calculated as a straight + * (linear) line p = pa*nodes + pb. * 'nodes' will be calculated + * in the program, here we defined the 'pa','pb' + * parameters. + * @param a1 hyper-gamma distribution parameter. + * @param a2 hyper-gamma distribution parameter. + * @param b1 hyper-gamma distribution parameter. + * @param b2 hyper-gamma distribution parameter. + * @param pa hyper-gamma distribution parameter. + * @param pb hyper-gamma distribution parameter. + * @return <tt>true</tt> if the parameters have been set, or + * <tt>false</tt> otherwise. + */ + public boolean setRunTimeParameters(int jobType, + double a1, double a2, double b1, double b2, + double pa, double pb) { + if(jobType > BATCH || jobType < INTERACTIVE) + return false; + + if(useJobType_) { + this.a1[jobType] = a1; this.b1[jobType] = b1; + this.a2[jobType] = a2; this.b2[jobType] = b2; + this.pa[jobType] = pa; this.pb[jobType] = pb; + } + else { + this.a1[INTERACTIVE] = this.a1[BATCH] = a1; + this.b1[INTERACTIVE] = this.a1[BATCH] = b1; + this.a2[INTERACTIVE] = this.a1[BATCH] = a2; + this.b2[INTERACTIVE] = this.a1[BATCH] = b2; + this.pa[INTERACTIVE] = this.a1[BATCH] = pa; + this.pb[INTERACTIVE] = this.a1[BATCH] = pb; + } + + return true; + } + + /** + * Sets the parameters for the inter-arrival time + * The inter-arriving time is calculated using two gamma distributions. + * gamma(aarr,barr) represents the inter_arrival time for the rush hours. It is + * independent on the hour the job arrived at. + * The cdf of gamma(bnum,anum) represents the proportion of number of jobs which + * arrived at each time interval (bucket). + * The inter-arrival time is calculated using both gammas + * Since gamma(aarr,barr) represents the arrive-time at the rush time , we use + * a constant ,ARAR (Arrive-Rush-All-Ratio), to set the alpha parameter (the new + * aarr) so it will represent the arrive-time at all hours of the day. + */ + public boolean setInterArrivalTimeParameters(int jobType, + double aarr, double barr, double anum, double bnum, double arar) { + if(jobType > BATCH || jobType < INTERACTIVE) + return false; + + if(useJobType_) { + this.aarr[jobType] = aarr * arar; + this.barr[jobType] = barr; + this.anum[jobType] = anum; + this.bnum[jobType] = bnum; + } + else { + this.aarr[INTERACTIVE] = this.aarr[BATCH] = aarr * arar; + this.barr[INTERACTIVE] = this.barr[BATCH] = barr; + this.anum[INTERACTIVE] = this.barr[BATCH] = anum; + this.bnum[INTERACTIVE] = this.barr[BATCH] = bnum; + } + + return true; + } + + /** + * Sets the maximum number of jobs to be generated by this workload model + * @param numJobs the number of jobs + * @returns <tt>true</tt> if the number of jobs has been set; + * <tt>false</tt> othwerwise. + */ + public boolean setNumJobs(int numJobs) { + if(numJobs < 1) + return false; + + numJobs_ = numJobs; + return true; + } + + /** + * Sets the maximum time duration of the workload. The workload will create + * jobs whose time of submission is less or equals to workloadDuration. + * The workload model will stop when it approaches workloadDuration. + * @param workloadDuration the maximum duration of the workload. + * @return <tt>true</tt> if the duration has been set; + * <tt>false</tt> othwerwise. + */ + public boolean setMaximumWorkloadDuration(double workloadDuration) { + if(workloadDuration <= 0) + return false; + + workloadDuration_ = workloadDuration; + return true; + } + + /** + * Sets a Gridlet file size (in byte) for sending to/from a resource. + * @param size a Gridlet file size (in byte) + * @return <tt>true</tt> if it is successful, <tt>false</tt> otherwise + * @pre size > 0 + * @post $none + */ + public boolean setGridletFileSize(int size) { + if (size < 0) { + return false; + } + + size_ = size; + return true; + } + + /** + * Gets a list of completed Gridlets + * @return a list of Gridlets + * @pre $none + * @post $none + */ + public ArrayList getGridletList() { + return list_; + } + + /** + * Prints the Gridlet objects + * @param history <tt>true</tt> means printing each Gridlet's history, + * <tt>false</tt> otherwise + * @pre $none + * @post $none + */ + public void printGridletList(boolean history) { + String name = super.get_name(); + int size = list_.size(); + Gridlet gridlet; + + String indent = " "; + System.out.println(); + System.out.println("========== OUTPUT for " + name + " =========="); + System.out.println("Gridlet_ID" + indent + "STATUS" + indent + + "Resource_ID" + indent + "Cost"); + + int i = 0; + for (i = 0; i < size; i++) + { + gridlet = (Gridlet) list_.get(i); + System.out.print(indent + gridlet.getGridletID() + indent + + indent); + + // get the status of a Gridlet + System.out.print( gridlet.getGridletStatusString() ); + System.out.println( indent + indent + gridlet.getResourceID() + + indent + indent + gridlet.getProcessingCost() ); + } + + System.out.println(); + if (history == true) + { + // a loop to print each Gridlet's history + System.out.println(); + for (i = 0; i < size; i++) + { + gridlet = (Gridlet) list_.get(i); + System.out.println( gridlet.getGridletHistory() ); + + System.out.print("Gridlet #" + gridlet.getGridletID() ); + System.out.println(", length = " + gridlet.getGridletLength() + + ", finished so far = " + + gridlet.getGridletFinishedSoFar() ); + System.out.println("========================================="); + System.out.println(); + } + } + } + + /** + * Reads from a given file when the simulation starts running. + * Then submits Gridlets to a resource and collects them before exiting. + * To collect the completed Gridlets, use {@link #getGridletList()} + * @pre $none + * @post $none + */ + public void body() { + System.out.println(); + System.out.println(super.get_name() + ".body() :%%%% Start ..."); + + // get the resource id + if (resID_ < 0) + { + System.out.println(super.get_name() + + ".body(): Error - invalid resource name: " + resName_); + return; + } + + boolean success = createGridlets(); + + // if all the gridlets have been submitted + if (success == true) { + collectGridlet(); + } + else { + System.out.println(super.get_name() + + ".body(): Error - unable to parse from a file."); + } + + // shut down all the entities, including GridStatistics entity since + // we used it to record certain events. + shutdownGridStatisticsEntity(); + shutdownUserEntity(); + terminateIOEntities(); + + System.out.println(super.get_name() + ".body() : %%%% Exit ..."); + } + + //////////////////////// PROTECTED METHODS /////////////////////// + + /** + * Collects Gridlets sent and stores them into a list. + * @pre $none + * @post $none + */ + protected void collectGridlet() { + System.out.println(super.get_name() + ": Collecting Gridlets ..."); + list_ = new ArrayList(gridletID_ + 1); + + Object data = null; + Gridlet gl = null; + + int counter = 1; // starts at 1, since gridletID_ starts at 1 too + Sim_event ev = new Sim_event(); + while ( Sim_system.running() ) + { + super.sim_get_next(ev); // get the next available event + data = ev.get_data(); // get the event's data + + // handle ping request + if (ev.get_tag() == GridSimTags.INFOPKT_SUBMIT) + { + processPingRequest(ev); + continue; + } + + // get the Gridlet data + if (data != null && data instanceof Gridlet) { + gl = (Gridlet) data; + list_.add(gl); + counter++; + } + + // if all the Gridlets have been collected + if (counter == gridletID_) { + break; + } + } + } + + /** + * Processes a ping request. + * @param ev a Sim_event object + * @pre ev != null + * @post $none + */ + protected void processPingRequest(Sim_event ev) { + InfoPacket pkt = (InfoPacket) ev.get_data(); + pkt.setTag(GridSimTags.INFOPKT_RETURN); + pkt.setDestID( pkt.getSrcID() ); + + // sends back to the sender + super.send(super.output, GridSimTags.SCHEDULE_NOW, + GridSimTags.INFOPKT_RETURN, + new IO_data(pkt, pkt.getSize(), pkt.getSrcID()) ); + } + + //////////////////////// PRIVATE METHODS /////////////////////// + + /** + * Creates the gridlets according to the workload model and sends them + * to the grid resource entity. + * @return <tt>true</tt> if the gridlets were created successfully or + * <tt>false</tt> otherwise. + */ + private boolean createGridlets() { + + int type = INTERACTIVE; + int nodes; long arrTime; int runTime; + + arrivalInit(aarr, barr, anum, bnum, START, weights); + + for (int i=0; i<numJobs_; i++) { + long[] info = arrive(type, weights, aarr, barr); + type = (int)info[0]; + arrTime = (long)info[1]; + + if(arrTime > workloadDuration_) { + return true; + } + + nodes = calcNumberOfNodes(serialProb[type] , pow2Prob[type], + uLow[type], uMed[type], uHi[type], uProb[type]); + + runTime = (int)timeFromNodes(a1[type], b1[type], a2[type], b2[type], + pa[type], pb[type], nodes); + + submitGridlet(i+1, arrTime, runTime, nodes); + } + + return true; + } + + /*----------------------------------------------------------------------------*/ + /* CALC_NUMBER_OF_NODES (NUMBER OF NODES) */ + /* -------------------------------------------------------------------------- */ + /* + * we distinguish between serial jobs , power2 jobs and other. + * for serial job (with probability SerialProb) the number of nodes is 1 + * for all parallel jobs (both power2 and other jobs) we randomly choose a + * number (called 'par') from two-stage-uniform distribution. + * if the job is a power2 job then we make it an integer (par = round(par)), + * the number of nodes will be 2^par but since it must be an integer we return + * round(pow(2,par)). + * if we made par an integer then 2^par is ,obviously, a power of 2. + */ + private int calcNumberOfNodes(double serialProb, double pow2Prob, double uLow, + double uMed, double uHi, double uProb) { + double u,par; + + u = random_.nextDouble(); + if (u <= serialProb) // serial job + return 1; + par = twoStageUniform(uLow, uMed, uHi, uProb); + if (u <= (serialProb + pow2Prob)) // power of 2 nodes parallel job + par = (int)(par + 0.5); // par = round(par) + + return (int)(Math.pow(2, par) + 0.5); // return round(2^par) + } + + /*----------------------------------------------------------------------------*/ + /* TIMES_FROM_NODES (RUNTIME) */ + /* -------------------------------------------------------------------------- */ + /* + * time_from_nodes returns a value of a random number from hyper_gamma + * distribution. + * The a1,b1,a2,b2 are the parameters of both gammas. + * The 'p' parameter is calculated from the 'nodes' 'pa' and 'pb' arguments + * using the formula: p = pa * nodes + pb. + * we keep 'p' a probability by forcing its value to be in the interval [0,1]. + * if the value that was randomly chosen is too big (larger than + * TOO_MUCH_TIME) then we choose another random value. + */ + private long timeFromNodes(double alpha1, double beta1, + double alpha2, double beta2, + double pa, double pb, int nodes) { + double hg; + double p = pa*nodes + pb; + + if (p>1) + p=1; + else if (p<0) + p=0; + do { + hg = hyperGamma(alpha1 , beta1 , alpha2 , beta2 , p); + } while (hg > TOO_MUCH_TIME); + + return (long)Math.exp(hg); + } + + /* The arrive process. + * 'arrive' returns arrival time (from the beginning of the simulation) of + * the current job. + * The (gamma distribution) parameters 'aarr' and 'barr' represent the + * inter-arrival time at rush hours. + * The (gamma distribution) parameters 'anum' and 'bnum' represent the number + * of jobs arriving at different times of the day. Those parameters fit a day + * that contains the hours [CYCLIC_DAY_START..24+CYCLIC_DAY_START] and are + * cyclically moved back to 0..24 + * 'start' is the starting time (in hours 0-23) of the simulation. + * If the inter-arrival time randomly chosen is too big (larger than + * TOO_MUCH_ARRIVE_TIME) then another value is chosen. + * + * The algorithm (briefly): + * A. Preparations (calculated only once in 'arrive_init()': + * 1. foreach time interval (bucket) calculate its proportion of the number + * of arriving jobs (using 'anum' and 'bnum'). This value will be the + * bucket's points. + * 2. calculate the mean number of points in a bucket () + * 3. divide the points in each bucket by the points mean ("normalize" the + * points in all buckets) + * B. randomly choosing a new arrival time for a job: + * 1. get a random value from distribution gamma(aarr , barr). + * 2. calculate the points we have. + * 3. accumulate inter-arrival time by passing buckets (while paying them + * points for that) until we do not have enough points. + * 4. handle reminders - add the new reminder and subtract the old reminder. + * 5. update the time variables ('current' and 'time_from_begin') + */ + private void arrivalInit(double[] aarr, double[] barr, + double[] anum, double[] bnum, int start_hour, double weights[][]) { + + int idx, moveto = CYCLIC_DAY_START; + double[] mean = new double[] {0,0}; + + for(int i=0; i<weights.length; i++) + for(int j=0; j<weights[i].length; j++) + weights[i][j] = 0; + + current_[BATCH] = current_[INTERACTIVE] = start_hour * BUCKETS / HOURS_IN_DAY; + + /* + * for both batch and interactive calculate the propotion of each bucket , + * and their mean */ + for (int j=0 ; j<=1 ; j++) { + for (int i=moveto ; i<BUCKETS+moveto ; i++) { + idx = (i-1)%BUCKETS; /* i-1 since array indices are 0..47 and not 1..48 */ + weights[j][idx] = + gamcdf(i+0.5, anum[j], bnum[j]) - gamcdf(i-0.5, anum[j],bnum[j]); + mean[j] += weights[j][idx]; + } + mean[j] /= BUCKETS; + } + + /* normalize it so we associates between seconds and points correctly */ + for (int j=0 ; j<=1 ; j++) + for (int i=0 ; i<BUCKETS ; i++) + weights[j][i] /= mean[j]; + + calcNextArrival(BATCH ,weights,aarr,barr); + calcNextArrival(INTERACTIVE,weights,aarr,barr); + } + + /* + * 'calcNextArrival' calculates the next inter-arrival time according + * to the current time of the day. + * 'type' is the type of the next job -- interactive or batch + * alpha and barr are the parameters of the gamma distribution of the + * inter-arrival time. + * NOTE: this function changes the global variables concerning the arrival time. + */ + private void calcNextArrival(int type, double[][] weights, + double[] aarr, double[] barr) { + + double[] points = new double []{0,0}; + double[] reminder = new double[]{0,0}; + int bucket; + double gam, nextArrival, newReminder, moreTime; + + bucket = current_[type]; // the bucket of the current time + do { // randomly choose a (not too big) number from gamma distribution + gam = gamrnd(aarr[type],barr[type]); + } while (gam > TOO_MUCH_ARRIVE_TIME); + + points[type] += (Math.exp(gam) / SECONDS_IN_BUCKET); // number of points + nextArrival = 0; + while (points[type] > weights[type][bucket]) { // while have more points + points[type] -= weights[type][bucket]; // pay points to this bucket + bucket = (bucket+1) % 48; // ... and goto the next bucket + nextArrival += SECONDS_IN_BUCKET; // accumulate time in next_arrive + } + + newReminder = points[type]/weights[type][bucket]; + moreTime = SECONDS_IN_BUCKET * ( newReminder - reminder[type]); + nextArrival += moreTime; // add reminders + reminder[type] = newReminder; // save it for next call + + // update the attributes + timeFromBegin_[type] += nextArrival; + current_[type] = bucket; + } + + /*----------------------------------------------------------------------------*/ + /* ARRIVE (ARRIVAL TIME AND TYPE) */ + /*----------------------------------------------------------------------------*/ + /* + * return the time for next job to arrive the system. + * returns also the type of the next job , which is the type that its + * next arrive time (time_from_begin) is closer to the start (smaller). + * notice that since calc_next_arrive changes time_from_begin[] we must save + * the time_from_begin in 'res' so we would be able to return it. + */ + private long[] arrive(int type, double[][] weights, double[] aarr, double[] barr) { + long res; + + type = (timeFromBegin_[BATCH] < timeFromBegin_[INTERACTIVE]) ? BATCH : INTERACTIVE; + res = timeFromBegin_[type]; // save the job's arrival time + + // randomly choose the next job's (of the same type) arrival time + calcNextArrival(type, weights, aarr, barr); + return new long[] {type, res}; + } + + /** + * Creates a Gridlet with the given information, then submit it to a + * resource + * @param id a Gridlet ID + * @param submitTime Gridlet's submit time + * @param runTime Gridlet's run time + * @param numProc number of processors + * @pre id >= 0 + * @pre submitTime >= 0 + * @pre runTime >= 0 + * @pre numProc > 0 + * @post $none + */ + protected void submitGridlet(int id, long submitTime, int runTime, int numProc) + { + // create the gridlet + int len = runTime * rating_; // calculate a job length for each PE + Gridlet gl = new Gridlet(id, len, size_, size_, GridSim.isTraceEnabled()); + gl.setUserID( super.get_id() ); // set the owner ID + gl.setNumPE(numProc); // set the requested num of proc + + // printing to inform user + if (gridletID_ == 1 || gridletID_ % INTERVAL == 0) + { + System.out.println(super.get_name() + ": Submitting Gridlets to " + + resName_ + " ..."); + } + + // check the submit time + if (submitTime < 0) { + submitTime = 0; + } + + gridletID_++; // increment the counter + + // submit a gridlet to resource + super.send(super.output, submitTime, GridSimTags.GRIDLET_SUBMIT, + new IO_data(gl, gl.getGridletFileSize(), resID_) ); + } + + + // --- Methods required by the distributions used by the workload model --- + + /* + * hyper_gamma returns a value of a random variable of mixture of two + * gammas. its parameters are those of the two gammas: a1,b1,a2,b2 and the + * relation between the gammas (p = the probability of the first gamma). we + * first randomly decide which gamma will be active ((a1,b1) or (a2,b2)). + * then we randomly choose a number from the chosen gamma distribution. + */ + double hyperGamma(double a1, double b1, double a2, double b2, double p) { + double a, b, hg, u = random_.nextDouble(); + + if (u <= p) { /* gamma(a1,b1) */ + a = a1; + b = b1; + } else { /* gamma(a2,b2) */ + a = a2; + b = b2; + } + + /* generate a value of a random variable from distribution gamma(a,b) */ + hg = gamrnd(a, b); + return hg; + } + + /* + * gamrnd returns a value of a random variable of gamma(alpha,beta). + * gamma(alpha,beta) = gamma(int(alpha),beta) + + * gamma(alpha-int(alpha),beta). This function and the following 3 functions + * were written according to Jain Raj, 'THE ART OF COMPUTER SYSTEMS + * PERFORMANCE ANALYSIS Techniques for Experimental Design, Measurement, + * Simulation, and Modeling'. Jhon Wiley & Sons , Inc. 1991. Chapter 28 - + * RANDOM-VARIATE GENERATION (pages 484,485,490,491) + * can be improved by getting 'diff' and 'intalpha' as function's parameters + */ + + private double gamrnd(double alpha, double beta) { + double diff, gam = 0; + long intalpha = (long) alpha; + if (alpha >= 1) + gam += gamrndIntAlpha(intalpha, beta); + if ((diff = alpha - intalpha) > 0) + gam += gamrndAlphaSmaller1(diff, beta); + return gam; + } + + /* + * gamrnd_int_alpha returns a value of a random variable of gamma(n,beta) + * distribution where n is integer(unsigned long actually). gamma(n,beta) == + * beta*gamma(n,1) == beta* sum(1..n){gamma(1,1)} == beta* sum(1..n){exp(1)} == + * beta* sum(1..n){-ln(uniform(0,1))} + */ + private double gamrndIntAlpha(long n, double beta) { + double acc = 0; + for (int i = 0; i < n; i++) + acc += Math.log(random_.nextDouble()); /* sum the exponential + * random variables + */ + return (-acc * beta); + } + + /* + * gamrnd_alpha_smaller_1 returns a value of a random variable of + * gamma(alpha,beta) where alpha is smaller than 1. This is done using the + * Beta distribution. (alpha<1) ==> (1-alpha<1) ==> we can use + * beta_less_1(alpha,1-alpha) gamma(alpha,beta) = exponential(beta) * + * Beta(alpha,1-alpha) + */ + private double gamrndAlphaSmaller1(double alpha, double beta) { + double x = betarndLess1(alpha, 1 - alpha); /* beta random variable */ + double y = -Math.log(random_.nextDouble()); /* exponential random + * variable */ + return (beta * x * y); + } + + /* + * betarnd_less_1 returns a value of a random variable of beta(alpha,beta) + * distribution where both alpha and beta are smaller than 1 (and larger + * than 0) + */ + private double betarndLess1(double alpha, double beta) { + double x, y, u1, u2; + do { + u1 = random_.nextDouble(); + u2 = random_.nextDouble(); + x = Math.pow(u1, 1 / alpha); + y = Math.pow(u2, 1 / beta); + } while (x + y > 1); + return (x / (x + y)); + } + + /* + * Returns the cumulative distribution function of gamma(alpha, beta) + * distribution at the point 'x'; return -1 if an error (non-convergence) + * occurs. + * This function and the following two functions were written + * according to William H. Press , Brian P. Flannery , Saul A. Teukolsky and + * William T. Vetterling. NUMERICAL RECIPES IN PASCAL The Art of Scientific + * Computing. Cambridge University Press 1989 Chapter 6 - Special Functions + * (pages 180-183). + */ + private double gamcdf(double x, double alpha, double beta) { + x /= beta; + if (x < (alpha + 1)) { + return gser(x, alpha); + } + + /* x >= a+1 */ + r... [truncated message content] |