Print out the following pages and bring them with you to class.
As with LP, you use MOR to run your simulation problems. BOSS (Block Oriented System Simulation) uses the same MOR program as LP (Linear Programming). Thus you still type your model into MOR, but you then hit F10 to get to the menu, S to get to System, and then hit S for Simulation (BOSS).
Note that in this document, BOSS program key words are listed in UPPER CASE, whereas variable names which are selected by you, the programmer, are shown in lower case. The case is actually ignored in BOSS, as is the horizontal location of the command on the input page. I have listed these names in upper and lower case only so you can tell which is which.
Please note that the variable names used in the commands below are examples only. You can use any name you like in your program, except that you cannot use key words. Thus it is not required that you use the variable name “answers” for the name of an array. You can just as well call it “cat.”
Entities: These are little people born using an “ARRIVE” statement. They run around in your system doing whatever you tell them to do. They are born with little eyes to read your commands, and little feet to walk down successive lines of code. Surprisingly they have no “names” and you must keep track of why you brought them into existence, who they are, where they are, and what they are doing at all times. Thus ARRIVE {TIME = EXPD(2)}; would born a policeman (or a pizza, or a student, or a truck) about every two seconds, or minutes, or years, distributed exponentially, with no limit on the number born as time progresses.
There are 5 blocks of BOSS code:
- PROGRAM
- DEFINITION
- CONTROL
- LOGIC
- END.
Note the period that is required after the word END.
Typical commands within the blocks: (Note that what you see below is simply a listing of typical commands. It is to show you the syntax used. The list of commands shown below does not comprise a program, nor would it have any chance of running. The words “PROGRAM” , “DEFINITION”, etc, are header statements and must be typed into the model. Note also that comment statements can be included on a line and are enclosed in ” “.)
- PROGRAM
- “Title of program can be typed here”
- DEFINITION – This is where you define everything.
- ARRAYS: – Places to put answers. (Click here for notes on how used):
- moreanswers: ARRAY[<1..500>] = ALL(1.6); “Generates a 500 cell array called moreanswers in which to store results, each cell having an initial value of 1.6”
- HISTOGRAMS: – Places to put answers. (Click here for notes on how used):
- answerhistogram: HISTOGRAM = {CELLS = 20, PROTECT = ON, MINVALUE = 10, MAXVALUE = 50}; “Generate a histogram to keep track of how many times something has happened. This histogram will have 22 cells, or bins. Computed values are expected to range from a low of 10 to a maximum of 50. Two more cells will be automatically placed on each end in which to place any numbers below 10 and above 50.”
- DISK FILES: – How to write answers to disks. (Click here for notes on how used):
- myfilename: TEXTFILE = {NAME = ‘d:\junk\dirtdump.out’, STATUS = WRITE}; “Generate an output file for writing answers to drive d:, in the subdirectory junk. In the program, this file will be referred to as myfilename, and will be given the name dirtdump.out on the disk. Filenames and directories must be OLD DOS specs (8 characters max, no spaces, etc.)”
- QUEUES: – Where entities go when they are unable to seize a resource:
- burgerline1: QUEUE = {CAPACITY = 6, DISCIPLINE = FIFO/LIFO/CHOICE}; “Generate a named, non-standard queue where the entities are asked to stand in line while waiting for a resource. This particular queue has 6 spaces where entities can stand in line, and operates on a FIFO (first-in first-out) basis, or LIFO (last-in first-out) or CHOICE(some_attribute). Note that you usually do not need to generate a non-standard queue. You just use a default queue generated by the program.”
- burgerline2: QUEUE = { }; Same as line1 except this queue defaults to CAPACITY=infinite, DISCIPLINE = FIFO. This is a named, non-standard queue. Standard queues do not need names, and are set up automatically by the computer, with infinite space using FIFO. They are used if no special queue is specified.
- bigline: QUEUE = {DISCIPLINE = CHOICE(goldcard) }; (Click here for notes on how used) When entities are born they can be assigned an attribute of “goldcard” where goldcard = 1 is assigned to special members, 2 to regular members, and 3 to bums. Thus whenever a customer has to get in line because they cannot seize the resource, those with the lower numbers (higher priority) will be placed ahead of those in the queue with higher numbers – i.e. the lower numbers have priority. Thus at any time you might see the following 8 people in line, with the following values of their goldcard attributes: 1 1 1 2 2 2 3 3. If a number 2 customer then arrived, the queue would look: 1 1 1 2 2 2 2 3 3. This is not possible with a “default” queue, so you will have to define a special queue it and tie it to its resource to use it. NOTE: In general you do not have to define a special queue for a resource if you can live with the default queue of infinite length, using FIFO (first-in, first-out.)
- RESOURCES – Things that do the work and can be seized, to the exclusion of others:
- loader1: RESOURCE = {CAPACITY = 3, QUEUE = line3}; “Generate a resource named loader1, which will do work on entities as they come through the system, and which can be seized by the entities to the exclusion of other entities. This resource has the ability to handle 3 customers at once, and uses a non-standard queue (specified as bigline.) The special queue must have been previously defined above this statement.”
- loader2: RESOURCE = {CAPACITY = 6}; “Generate a resource which can handle 6 trucks at once, using a standard unnamed default queue having unlimited space.”
- loader3: RESOURCE = { }; “Generate a resource with a default capacity = 1, using a standard (unnamed) queue having unlimited room to stand in line”
- DISTRIBUTIONS – Ways of indicating how things arrive/behave (Click here for notes on how used):
- leftturn: DISTRIBUTION(DISCRETE) = ((0.2,1),(1.0,0)); “Generate a discrete distribution wherein any time the distribution is called, 20% of the return values will be assigned the discrete value of 1, and 80% will be assigned the discrete value of 0.”
- buy_howmany_tvs: DISTRIBUTION(DISCRETE)= ((0.1,0),(0.4,1),(0.9,2),(1.0,3)); “Generate a discrete distribution wherein 10% of the customers will not buy anything (= 0), 30% of the customers will buy 1 tv (= 1), 50% of the customers will buy 2 tvs, and 10% of the customers will buy 3 tvs.”
- cow_weight: DISTRIBUTION(CONTINUOUS)= ((0.0, 100),(0.4,120),(0.9,200),(1.0,220)); “Generate a continuous distribution wherein the cow weighs no less than 100 pounds, and no more than 220 pounds. For the casting of a random number between 0 and 0.4 the cow will weigh between 100 and 120 pounds. Thus if RANDOM = 0, cow will weigh 100 pounds. If RANDOM = 0.2, cow will weigh 110 pounds, since halfway between the 0 to 0.4 gives halfway between 100 and 120 pounds. If RANDOM comes out 0.88, cow will weigh ((0.88-0.40)/(0.90-0.40))*(200-120) + 120 = 196.8 pounds. If RANDOM comes out 0.98, cow will weigh ((0.98-0.90)/(1.00-0.9))*(220-200) + 200 = 216 pounds.”
- GATES – Things that open and close, and block the progress of entities:
- gate1: GATE = {STATUS = CLOSE, DISCIPLINE = FIFO}; “Generate a gate, which can be used to stop the flow of entities if closed. The gate can be born closed, as here, or open, and can release entities FIFO or LIFO.”
- LABELS – Code line indicators – gives you the ability to have your customer skip lines of code you don’t want them to read:
- LABELS = {starthere, checkgate, stuckintraffic, goleft, gostraight, firstline, line1}; “Places (lines of code) to branch to in the program. Labels are actually line labels, such as line1. This could be a line label. A label is a line identifier like a street address. For example if I told you to GOTO 2117 Texas Ave. you would know exactly where to go. If I told you to go to Room 217, you would know exactly where to go. Similarly if you tell an entity to GOTO line1, that’s what he will do – transfer control to the line of code preceded by the label line1: Label names MUST be preceded by a letter, i.e. a810 is a legal label name, whereas 810 is not.
- LOCAL AND GLOBAL VARIABLES – Local variables (ATTRIBUTES) are personalized variables, accessible only to an individual entity. Global variables are community property, and are accessible to all entities.
- ATTRIBUTES = {wantstoturnleft = 0, size = 1, color = 5}; “wantstoturnleft, size and color are attributes (local variable names) made up by the programmer. An attribute is a “personal” variable, and every entity born has his own personal value. In this case, as entities are born they will all be born with the following (for example) personal attributes: they don’t want to turn left (wantstoturnleft=0), they are the size of a car (size=1), and they are blue (color=5). If you ran an entity past the statement: size = 2, then that entity, and that entity only would have its size changed to the size of a truck (size = 2.) All other entities would remain unchanged.”
- moneymade = 400; “A global variable name made up by the programmer, and initialized as 400. A global variable is one that can be viewed and changed by any entity running around in the system. Thus if an entity later came by and was told moneymade = moneymade + 40, he would change moneymade to 440. Then if a second entity came by and was told the same thing, moneymade would be changed to 480.”
- payperload = 36.1; “Another global variable name”
- ARRAYS: – Places to put answers. (Click here for notes on how used):
- CONTROL – How to tell the computer program how long to run, etc.
- STOPTIME = 240; “How many units of time you wish to run the simulation. Here, the simulation will run 240 nanoseconds, or 240 days, or whatever. This is where, in effect, you set the units of time for the model. Every other time in the model must agree with the units used here.”
- STOPCOUNT = 100; “How many departures you want to run through the DEPART{ } statements before stopping the simulation. Here, the simulation will count some number to things to be made and stop. These go through any or all of your DEPART { } statements. This is where, in effect, you set number of the entities leaving the system as the stopping criteria. To get this to work, one or more of your DEPART{ } statements must say how many to deduct from STOPCOUNT before stopping the simulation. Thus you might have DEPART{QUANTITY = 1} at one point in the code, and DEPART{QUANTITY = 3} elsewhere. Every time an entity went through the quantity = 1 depart statement, STOPCOUNT would be reduced by one, and every time some entity went through the quantity = 3 statement, STOPCOUNT would be reduced by 3. When STOPCOUNT gets to zero or negative, the simulation stops. QUANTITY defaults to 0 so DEPART{ } will not reduce STOPCOUNT.
- WATCHLIST = { loader1, loader2, line1, bucket}; “A list of resources that you wish to watch during the simulation.”
- RANDOMIZE = ON; “Note: Without this statement, you get same answer every time, for debugging purposes.”
- PRINTTIME = xxx; “This will print the state of the system at every xxx seconds (minutes, eons, etc.) Very useful if your simulation crashes before finishing, since you can see where it crashes. Just put PRINTTIME = 100; or PRINTTIME = 10; or PRINTTIME = 1;”
- EXITLOGIC – Used to clean up any required calculations after STOPTIME or STOPCOUNT has been reached, and the computer is ready to stop the simulation and report statistics. For example:
PROGRAM
“Show how EXITLOGIC works”
DEFINITION
frontend :RESOURCE = {CAPACITY = 1};
dumpsite :RESOURCE = {CAPACITY = 1};
LABELS = {start};
payperload = 400;
costpertruck = 1000;
numberoftrucks = 3; “Number of trucks to begin study”
trucksdumped = 0; “initialize number of loads”
gross=0; “initialize gross”
expenses = costpertruck * numberoftrucks; “total cost”
profit = 0; “initialize profit”
CONTROL
STOPTIME=480; “run simulation for 480 minutes”
RANDOMIZE = ON;
EXITLOGIC
“NOTE! You cannot have both a WATCHLIST and EXITLOGIC, and print to the screen. It’s a bug” - “The EXITLOGIC won’t show on the screen. Take out the WATCHLIST first”
“You can print to a file on your hard drive, but not to the screen.”
profit = gross – expenses; “calculate final profit after simulation ceases”
PRINTLN{‘ Profit = ‘, profit: 15:2 }; “print out total profit, 15 digits, 2 decimals”
END; “End of Exitlogic”
LOGIC “Logic for controlling arriving trucks”
ARRIVE {TIME=0,LIMIT=numberoftrucks};
start: SEIZE{NAME=frontend, UNITS=1}; “seize front end loader”
WAIT{TIME=EXPD(10)}; “wait to be loaded”
RELEASE {NAME=frontend}; “release front end loader”
WAIT{TIME=CUNIFORM(30,35)}; “travel to pit”
SEIZE{NAME=dumpsite}; “seize pit”
WAIT{TIME=EXPD(2)}; “unload”
RELEASE {NAME=dumpsite}; “release pit”
gross = gross + payperload; “add this loads payment”
trucksdumped = trucksdumped+1; “increment number of truckloads”
WAIT{TIME=CUNIFORM(20,25)}; “return trip time”
GOTO start;
END. - LOGIC – How you tell the computer what to do:
- THE ARRIVE STATEMENT – Bringing entities into the system to work for you:
- ARRIVE{TIME = CUNIFORM(0.5,6.5)}; “Borns multiple entities (people, policemen, cars, trucks, computers, etc.) wherein their interarrival times form a continuous uniform distribution between 0.5 and 6.5 seconds, or minutes, or eons. Additional entities continue to be born using this distribution as long as the simulation runs.”
- ARRIVE{TIME = EXPD(2)}; “Borns repetitive entities having an exponential distribution with a mean of 2 days. Additional entities continue to be born as long as the simulation runs.”
- ARRIVE{TIME = 0, LIMIT = 6}; “Note you MUST put a LIMIT here!!! Borns 6 entities at the beginning of the simulation, at time = 0 minutes, then quits borning entities.”
- ARRIVE{TIME = 8}; “Borns repetitive entities, one every 8.00000 days, exactly.”
- ARRIVE{TIME = 0 MAX NORMAL(20,6)}; “Borns repetitive entities with a normal distribution having a mean of 20 seconds and a sigma of 6 seconds, for as long as the simulation continues.”
- ARRIVE{TIME = 0 MAX NORMAL(20,6), LIMIT = 32}; “Borns repetitive entities with a normal distribution having a mean of 20 seconds and a sigma of 6 seconds, for as long as the simulation continues or until a maximum of 32 entities have been generated, whichever comes first. The 0 MAX is used to insure that a negative interarrival time is not generated.”
- ARRIVE{TIME = NORMAL(500,3)}; “Probably ok, since 500-3*3 is pretty far from negative.”
- ARRIVE{TIME = NORMAL(5,2)}: “Note: VERY DANGEROUS! Will probably crash the system.”
- SEIZING RESOURCES TO THE EXCLUSION OF OTHER ENTITIES:
- SEIZE{NAME = loader1}; “This tells the entity who read the statement to seize one unit of capacity from the resource loader1, if possible. If not possible because all of loader1’s capacity is in use, stand in the default queue associated with loader1 until able to do so.”
- SEIZE{NAME = loader2, UNITS = 2}; “Seize 2 UNITS from loader2 if available, and stand in the default queue associated with loader2 until able to do so.”
- SEIZE{NAME = loader3, UNITS = 2, REXCESS = ifresourceisbusy, QEXCESS = ifqueueisfull }; “Seize 2 UNITS from loader3 if possible. If the resource is busy, or if you cannot get the 2 requested units then go to the line of code labeled ifresourceisbusy:, and if the queue is full go to ifqueueisfull:. Note that to use QEXCESS, the queue associated with loader2 MUST be a special “named” queue, since un-named queues have, by default, infinite capacity, and hence cannot get full, and will thus never appear to get full. The REXCESS can be used to send entities to special lines of code where they can be given special consideration if they are unwilling to wait in line. For example they can be DEPARTed, they can be sent to do something else while the line gets shorter and then come back later, etc.”
- RELEASE – Releasing the resource so others can use it after you are through with it:
- RELEASE{NAME = loader1}; “After having seized the resource named loader1, release it so other entities can use it.”
- RELEASE{NAME = loader2, UNITS = 2}; “After having seized two units from the resource named loader2, release them so other entities can use them. Note that if you have someone SEIZE a resource, they must release it before DEPARTing.”
- WAIT – Waiting while something gets done:
- WAIT{TIME = 1}; “Tell the entity which reads this line to wait 1 year (month, nanosecond, etc.)before proceeding to the next line.”
- WAIT{TIME = CUNIFORM(9,11)}; “Tell the entity to wait a continuous random time, between 9 and 11 seconds. The result will be for her to wait 9.11, 10.47, 10.99 nanoseconds, etc.”
- WAIT{TIME = DUNIFORM(9,11)}; “Tell the entity to wait a discrete random time, between 9 and 11. The result will be 9, 10, 10, 11, 9, 11, etc.”
- WAIT{TIME = 0 MAX NORMAL(10,2)}; “Wait for a random time, normally distributed, with a mean of 10, and a sigma of 2.”
- WAIT{TIME = EXPD(3)}; “Wait for a random time, exponentially distributed, with a mean of 3.”
- WAIT{TIME = 3 + EXPD(2) + repairtime}; “Wait for some appropriate time.”
- CLOCKTIME – Seeing what time it is during the simulation:
- time1 = CLOCKTIME; “Look up at the master clock on the wall and see what time it is now, and store it under the variable named time1.”
- time2 = CLOCKTIME; “Look up at the master clock and see what time it is now.”
- GENERAL CALCULATIONS:
- timeittook = time2 – time1; “Compute how long it took to do the preceding lines.”
- cost = cost + 300*(time2-time1); Cost is a variable, either local (an attribute) or global. If you initialized it in the DEFINITION block using cost = 0, it is global. If you initialized it in the DEFINITION block using an ATTRIBUTES = {cost}; then it is local, and there is one personal “cost” for every entity.
- value = EXP(LN(LOG10(SQR(SQRT(ABS(FLOOR(junk))))))); “Takes the exp of the natural log of the log base 10 of the squared of the square root of the absolute value of the floor of junk and puts it in value.”
- HOW TO FIND OUT HOW MUCH OF A RESOURCE IS CURRENTLY IN USE
- loader1capacity = CAPACITY[loader1] will tell you loader1’s capacity.
- loader1usedup = USED[loader1] will tell you how much of loader1’s capacity is currently in use.
- loader1stillavailable = AVAILABLE[loader1] will tell you how much of loader1’s capacity is currently available for use. Probably don’t need these if the CAPACITY = 1.
- HOW TO FIND OUT HOW MUCH OF A QUEUE IS CURRENTLY IN USE
- loader1queuecapacity = CAPACITY[loader1:QUEUE] will tell you loader1’s queue capacity. Don’t use this statement on a queue that you know has infinite capacity, only on defined queues of limited capacity.
- loader1queueusedup = USED[loader1:QUEUE] will tell you how much of loader1’s queue capacity is currently in use. Very useful for deciding which line to get in.
- loader1queuestillavailable = AVAILABLE[loader1:QUEUE] will tell you how much of loader1’s queue capacity is currently available for use. Don’t use this statement on a queue that you know has infinite capacity, only on defined queues of limited capacity.
- FLOW CONTROL – Testing and directing entities to locations depending on what is happening in the model:
- IF statementistrue THEN GOTO trueline ELSE GOTO falseline (This branches to trueline if statementistrue is true, and branches to falseline if statementistrue is false.)
- IF statementistrue THEN GOTO trueline (This branches to trueline if statementistrue is true, and if statementistrue is false, drops down to the next statement immediately below this one.
- IF USED[counter1:QUEUE] <= USED[counter2:QUEUE] THEN GOTO getcounter1 ELSE GOTO getcounter2; “This statement tests the number of people in counter1’s default queue, to see if it is currently smaller than the number of people in counter2’s default queue. If so, the entity is directed to go to the line of code labeled getcounter1, and if not he is sent to getcounter2. Note that here the queues are default, standard, unnamed queues.”
- IF USED[quebie1] >= USED[quebie2] THEN GOTO dog; “This syntax can only be used for DEFINED (non-standard) queues, associated with resources. This statement tests the current number of people in the queue defined as quebie1, to see if it is less than the current use of quebie2, and if so, the entity goes to the line of code labeled dog. If not, he goes to the next line of code.”
- IF((junk1 > junk2) AND ((a<b) OR (a>junk2))) THEN a = b ELSE a = 2*b; “Logical assignment. Note use of parentheses WHICH ARE REQUIRED!”
- IF((junk1 > junk2) AND ((a=b) OR (a>junk2))) THEN GOTO label1; “Logical branch.”
- IF cars > 2 THEN SETGATE{NAME=cargate, STATUS=CLOSED} ELSE GOTO gate1;
- IF junk1 < junk2 THEN GOTO cat;
- IF turnleft = 1 THEN GOTO leftturn ELSE GOTO straight; “If logical branch.”
- GOTO leftturnlabel; “Direct the entity to go to the line of code labeled leftturnlabel .”
- BRANCHING – Using labels on lines of code, to identify where you want your customer to go for the next command.:
- leftturnlabel: a = a+b; “A line of code labeled leftturnlabel, where an entity can be sent.”
- straightlabel: a = a-b;
- DEPART – Removing the entity from the system after you are finished with it:
- DEPART{ }; “Departs the entity, releasing its memory back to the memory pool.”
- GATES – Things such as red lights that can be opened and closed. Used to impede (appropriately) the progress of entities:
- SETGATE{NAME = gate1, STATUS = OPEN/CLOSE/INVERT}; “Opens and closes a gate named gate1.”
- TESTGATE{NAME = dog}; “Tests to see if the gate named dog is open. If so, proceed to the next line of code. If not, stay behind the gate, continuously checking its status, and do not proceed until someone, somewhere, opens it.”
- TESTGATE{NAME = gate1, IFCLOSED = gohere}; “Tests to see if gate1 is open. If so, proceed to the next line of code. If not, send the entity to the line of code labeled gohere. IFCLOSED can be used to send the entity to a gohere: WAIT=1; timedelay = timedelay+1; GOTO backwhereicamefrom loop to count how many minutes the entity had to wait for the gate to open.”
- USE OF DISTRIBUTIONS:
- doiwanttoturnleft = leftturn(RANDOM); “Asks the entity to cast a random 0-1 number on his calculator, take it to the “leftturn” distribution house and give it to the guy inside. The guy inside the “leftturn” distribution house will then issue him an appropriate desire to turn left (yes or no), according to the DISTRIBUTION(DISCRETE) statement listed in the DEFINITION block.”
- iwillbuy = buy_howmany_tvs(RANDOM); “Casts a random number, takes it to the “buy_howmany_tvs” distribution specified in the DEFINITION block, and get assigned an appropriate number of TVs to buy.”
- howmuchdoesmycowweigh = cow_weight(RANDOM); “Casts a random number, takes it to the “cow_weight” distribution (see DISTRIBUTION above) specified in the DEFINITION block, and get assigned an appropriate weight of your new cow purchase.”
- DISK OUTPUT:
- PRINTLN{myfilename, ‘ ‘ }; “Prints a blank line in the output file called myfilename”
- PRINTLN{myfilename, ‘ answers1 answers2 time car number color ‘ }; “Prints a text header line, hopefully aligned over the answers to be printed out next.”
- PRINTLN { myfilename, answers1[i], answers2[i], clock, car, carcolor }; “Prints a line of answers formatted however he feels like formatting them. Note that “i” can vary by putting it inside a loop.”
- PRINTLN { myfilename, answers1[i]:15:0, answers2[i]:10:2, clock:5:0, car:5:0, carcolor:5:0 }; “Prints a line of answers formatted to your specs, in this case similar to Fortran F15.0, F10.2, F5.0, F5.0, F5.0”
- PRINTLN{myfilename,”};
PRINTLN{myfilename,’ For # of trucks = ‘,numberoftrucks};
PRINTLN{myfilename,’ # Loads $ Profit’};
i=1;
REPEAT “repeat the following two lines of code”
PRINTLN {myfilename, answers[i]: 15:0, answers1[i]: 15:0 };
i=i+1;
UNTIL “until the number i gets bigger than the number count”
i>count;
- QUITTING IN THE MIDDLE OF A SIMULATION:
- IF numberoftrucks > maxtrucks THEN HALT; “This is an absolute ‘quit, stop, cease, desist’ statement. It stops the run immediately. I don’t think you get any statistical output if you do this.”
- ENTERING COMPUTED VALUES INTO AN ARRAY FOR LATER VIEWING:
- answers[i] = currentcount; Puts the current value of currentcount into the ith cell of the “answers” array. To generate the “answers” array, see the DEFINITION block above.
- answers[6] = currentcount; Puts the current value of currentcount into the 6th cell of the “answers” array.
- moreanswers[cat] = presentmoney; Stores the current value of presentmoney in the catth (integer) cell of the “moreanswers” array.
- ENTERING COMPUTED VALUES INTO A HISTOGRAM FOR LATER VIEWING:
- Example of how a histogram value is entered:
enteringtime = CLOCKTIME; “look up at the clock and see what time it is now”
WAIT{TIME = EXPD(5)};
leavingtime = CLOCKTIME; “note that the clock has now advanced since it was previously called”
answerhistogram = leavingtime – enteringtime; “Takes the difference between the variable named “enteringtime” and the current clocktime, and puts it in the correct “bin” in the histogram named “answerhistogram.” To generate a histogram, see the DEFINITION block above. Note that a histogram does not have to end with the word histogram – you can call it cat.”
- Example of how a histogram value is entered:
- THE ARRIVE STATEMENT – Bringing entities into the system to work for you:
- END. “Note the period at the end of the END statement. It is required.”
Note you can press ESC during a run and speed up the screen by changing the delay duration from 300 ms to a lower number, or turn the watch status off entirely. You can also have the program do a single step, etc. Hit “C” after making changes to continue the run.
Typical Illegal Statements and Code:
cost = .5;
ILLEGAL! You must use cost = 0.5 because .5 looks like the use of 1..500 in the ARRAY statement above.
LABELS={first};
ILLEGAL! FIRST is a keyword. Don’t use it.
You CANNOT run an entity through an ARRIVE block! You MUST go AROUND it! Otherwise, the entity will try and “born” another person like himself, which is not permitted. Only YOU can born people with an ARRIVE statement, which then becomes the FIRST line in a new block of code. For example:
[ 12] ARRIVE{TIME = 0, LIMIT = 1}; The following three lines will crash the program. This line borns a truck.
[ 13] dirthauled = dirthauled + 10; The truck then increments the amount of dirt hauled by 10 cy.”
[ 14] ARRIVE{TIME = 5, LIMIT = 1}; Unfortunately the truck is now instructed to born a truck, which he cannot do, and the program crashes. YOU personally can born trucks. ENTITIES are not permitted to born new entities or even read the lines that born trucks.
Correction:
[ 12] ARRIVE{TIME = 8}; “The following lines will work. This first line borns a 10 cy truck every 8 seconds.”
[ 13] dirthauled = dirthauled + 10; “The truck then increments the amount of dirt by 10 cy.”
[ 14] GOTO goaroundthearrive; “The 10 cy truck is now sent around the arrive statement.”
[ 15] ARRIVE{TIME = 12}; “Big 30 cy trucks are born every 12 seconds.”
[ 16] dirthauled = dirthauled + 30; “Add 30 cy for the big truck.”
[ 17] goaroundthearrive: WAIT{TIME = 2}: “or whatever is appropriate”
You CANNOT run an entity through an END. statement. You must depart the entity before you say the word END:
[ 1] ARRIVE{TIME = 0, LIMIT = 1};
[ 2] dirthauled = dirthauled + 10;
[ 3] END.
This will crash because you asked an entity to say the word END. He is not permitted to do this. Only you can end the simulation. Just DEPART{ }; him before the END statement.
Correction:
[ 1] ARRIVE{TIME = 0, LIMIT = 1};
[ 2] dirthauled = dirthauled + 10;
[ 3] DEPART{ };
[ 4] END.
[ 8] seeiffinished: IF dirt <= 100 then GOTO seeiffinished ELSE GOTO morework;
[ 9] morework: dirt = dirt + 200;
This is called a zero time loop. Its purpose was probably to test to see if we had enough dirt for something, which is a good idea. However, when the statement finds out we don’t have at least 100 cubic yards of dirt and should not proceed, the entity is then instantly sent back to “seeiffinished” to check again, to see if we now have enough dirt. However, it only takes 0 seconds to do this, so the entity churns around in this statement, with zero time elapsing, and nobody else in the program can get any work done. The program just sits there and spins. The correction is to write:
[ 8] seeiffinished: IF dirt <= 100 then GOTO dog ELSE GOTO morework;
[ 9] dog: WAIT{TIME = 1};
[10] GOTO seeiffinished;
[11] morework: dirt = dirt + 200;
That way the person is only checking for dirt every second or so, or for some reasonable length of time, rather than checking every nanosecond.
[ 65] CLOCKTIME = 6; “You are trying to use the name “clocktime” as a variable, and are trying to reset the simulation time to 6. The word CLOCKTIME is a system variable and can only be used by the program to report the current time in the simulation. It can only be used in statements like:
[ 88] entertime = CLOCKTIME;
[ 89] WAIT{TIME = EXPD(3)};
[ 90] deltatime = CLOCKTIME-entertime;
Note that the two CLOCKTIMEs above will be different by the random time EXPD(3), since time will have advanced.
[ 26] ARRIVE{TIME=EXPD(31*24*60)};
[ 27] SETGATE{NAME=dockinggate,STATUS=OPEN};
[ 28]END.
Error logic on line [28]: Attempted execution of END statement by an entity progressing through the model.
You asked the guy you borned to END. He cannot END, anymore than he can ARRIVE. You must depart him before the END. statement.
REPEAT-UNTIL Statements:
[ 4] i = 1; “Initialize i at 1”
[ 5] REPEAT “Please repeat the following statements”
[ 6] i=i+1; “Increment i by 1”
[ 7] PRINTLN {myfilename, answers[i], answers1[i] }; “Print a line in a file called myfilename on disk”
[ 8] UNTIL i >= 12; “Until i gets as big as, or becomes greater than, 12, and then go to the next line”
How to assign attributes to some percentage of those born:
Say 20% of the cars born want to turn left, and you are using wanttoturnleft as that attribute:
[ 43] IF RANDOM <= 0.2 then wanttoturnleft = 1 ELSE wanttoturnleft = 0; “Assuming 1 = yes, I want to turn left.”
Say 30% of the cars are blue (carcolor = 1), 50% are black (carcolor = 2) and 20% are white (carcolor = 3):
[ 3] IF RANDOM <= 0.3 THEN GOTO setcolor ELSE GOTO tryagain;
[ 4] setcolor: carcolor = 1;
[ 5] GOTO finishedcoloring;
[ 6] tryagain: IF RANDOM <= 50/70 THEN carcolor = 2 ELSE carcolor = 3; “Note carefully why we have 50/70!!!”
[ 7] finishedcoloring:
Say 30% of the cars are blue (carcolor = 1), 50% are black (carcolor = 2) and 20% are white (carcolor = 3):
[ 3] number = RANDOM;
[ 4] IF number <= 0.3 THEN GOTO setcolor ELSE GOTO tryagain;
[ 5] setcolor: carcolor = 1;
[ 6] GOTO finishedcoloring;
[ 7] tryagain: IF number <= 0.8 THEN carcolor = 2 ELSE carcolor = 3;
[ 8] finishedcoloring:
Say 30% of the cars are blue (carcolor = 1), 50% are black (carcolor = 2) and 20% are white (carcolor = 3):
[ 3] number = RANDOM;
[ 4] IF number IN [ 0, 0.3 ] then carcolor = 1; “This says that if the variable ‘number’ is between 0 and 0.3, then set the attribute ‘carcolor’ to blue, assuming 1 is blue, 2 is black, etc.”
[ 5] IF number IN [ 0.3, 0.8 ] then carcolor = 2;
[ 6] IF number IN [ 0.8, 1.0 ] then carcolor = 3;
But the simplest and most powerful way by far is to use a DISTRIBUTION:
Say 30% of the cars are blue (carcolor = 1), 50% are black (carcolor = 2) and 20% are white (carcolor = 3):
In the DEFINITION block, say:
color: DISTRIBUTION(DISCRETE)= ((0.3,1),(0.8,2),(1.0,3));
Then when you want to give a car a color, in the LOGIC block you simply put the statement:
carcolor = color(RANDOM);
where carcolor is an attribute.
If you want to know what number comes up on a rolled die:
dienumber: DISTRIBUTION(DISCRETE)= ((1/6,1),(2/6,2),(3/6,3),(4/6,4),(5/6,5),(6/6,6));
and then just ask him what came up:
thistime = dienumber(RANDOM) where thistime is a variable, not an attribute.
If the die is loaded (crooked), with the load opposite the 4 face:
dienumber: DISTRIBUTION(DISCRETE)= ((0.1,1),(0.2,2),(0.3,3),(0.8,4),(0.9,5),(1.0,6));
Thinning and Logical IFs
PROGRAM
“Thinning and Logical Tests”
DEFINITION
LABELS = {thin0,thin30,thin60,thin90,print1};
filename1:TEXTFILE={NAME=’d:\junk\thins.out’,STATUS=WRITE};”Name Output File”
CONTROL
STOPTIME=400;
LOGIC
ARRIVE {TIME=EXPD(5)};
start: IF(CLOCKTIME<100) THEN GOTO thin0;
IF(CLOCKTIME>100) AND (CLOCKTIME<200) THEN GOTO thin30;
IF CLOCKTIME IN [200,300] THEN GOTO thin60;
IF CLOCKTIME>300 THEN GOTO thin90;
thin0: GOTO print1;
thin30: IF RAND < 0.3 THEN DEPART{ }; “thin out 30% of arrivals”
GOTO print1;
thin60: IF RAND < 0.6 THEN DEPART{ }; “thin out 60% of arrivals”
GOTO print1;
thin90: IF RAND < 0.9 THEN DEPART{ }; “thin out 90% of arrivals”
GOTO print1;
print1: PRINTLN {filename1, CLOCKTIME:15:0};
DEPART{ };
END.
Miscellaneous:
The RANDOMIZE = ON statement:
Several people have asked why, when they run their cases a second time, they get answers identical to their previous run. That’s not a bug, it’s a feature.
BOSS uses the same initial random number string whenever you first turn it on. That enables you to recreate errors you spot in a run. Without that feature, you would never be able to recreate a problem that you stumbled across in a run, because when you ran it again, a different random number would be generated, which might not cause the same error as before. Thus, once you are through debugging your program and are ready for real random numbers to be used (not that the others weren’t also random, they were) then you should add the following statement in the control block:
RANDOMIZE = ON;
ERROR: EMPTY MODEL
Sometimes, the program will run out of things to do. For example, you may bring in students into a classroom, make them wait there until class is over, and let them leave. If they all leave before STOPTIME is reached, this worries the program and it gives an empty model error. This doesn’t hurt anything and he still gives you the statistics gathered, it just bothers him that he has nothing to do, and the clock is still running. Ignore it. I have been told that sometimes the program won’t generate the answer statistics in the Print Output mode with an empty model. If you run across this, just ARRIVE a phony entity and make him wait STOPTIME+2, and then DEPART{ }. Then the program will see him there throughout the run, doing nothing, and be happy. A happy program is a good program.
WHEN TO USE A RESOURCE AND WHEN TO USE A GATE:
When you want to have only one person at a time use a resource, you can use a resource. For example, on the race pit model or on the dredging model you can use the capture of resources, since both the race car and dredge operator can be stopped. You could also probably use gates for these. However, you cannot use capturing a RESOURCE on something like a train coming through an intersection, since he waits for no one. I.E. if you had an intersection where cars had captured 10 spaces on the tracks, the computer would tell the train to wait until the cars released the resource. In the real world the train plows them under.
From: Randy Deatherage
Sent: Tuesday, April 28, 2009 11:18 PM
To: Lowery@tamu.edu
Subject: Seizing a Resource
I had a question about how we wrote the dredge program in class today. We described the patch of ocean where the dredge was scooping as a resource. We gave it a value of 50. The [arriving}] little boats would seize one of these and the dredge would seize all 50 so as not to let the boats through. But what would happen if the boats were being born at a rate faster than the time it takes to cross the path of the scoop. Since the resource still had capacity available, could this stream of boats prevent the scoop from ever getting an opportunity to seize the resource? Or would the scoop be in the queue for the resource first? I guess to make the question more general, if a resource has enough capacity for one individual to seize it but not another, can the individual with the lower needed capacity jump in the queue line?
Randy:
As you surmised, it’s an all or nothing deal. If little boats keep seizing the resource, the poor old dredge, unable to ever find 50 open units, will never dredge again.
In that case, we use gates. Or, we born a cop in a boat and put him upstream, and after a certain time of dredge inactivity, he closes a gate with a gun where the little boats are flooding in, and stops them. Then after say 1/2 hour, he opens the gate. Good question. L^3
Example program where CHOICE is used in a QUEUE:
DEFINITION “Note the following statements which are used to get rich people put in the front of the queue”
ATTRIBUTES={goldcard=2}; “Everyone will be born a bum, with a lowly 2 value. Rich customer’s goldcard will later be altered to a better (lower) number for after birth. After the entities are born, their “bum” attribute status will be changed to a 1 if they are rich.”
bigline: QUEUE = {DISCIPLINE = CHOICE(goldcard)}; “This says any people who are told to stand in this queue will have their goldcard number checked. Whenever a customer has to get in line because they cannot seize the resource, those with the lower numbers will be placed ahead of those in the queue with higher numbers – i.e. the lower numbers have priority. Thus at any time you might see the following 8 people in line, with the following values of their goldcard attributes: 1 1 1 2 2 2 2 2 If a number 1 customer later arrives, the queue would look: 1 1 1 1 2 2 2 2 2 Note that this is not possible with a “default” queue, so you will have to define a special queue, and tie it to its resource to use it.”
attendant: RESOURCE = {CAPACITY = 3, QUEUE = bigline}; “Generate a resource named attendant, which will do work on entities as they come through the system, and which can be seized, to the exclusion of other entities. This resource has the ability to handle up to 3 customers at once, and uses a non-standard queue, defined as bigline above. The special queue must have been previously defined before this RESOURCE statement.”
LOGIC
ARRIVE{TIME = EXPD(10)};
IF RANDOM < 0.1 THEN goldcard = 1; “Changes 10% of the customers from bums to goldcard = high priority”
SEIZE{NAME = attendant}; “This tells the entity who reads the statement to seize one unit of capacity from the resource which is named attendant, if possible. If not possible because all of attendant’s capacity is in use, move the requesting entity into the queue associated with attendant (the QUEUE with the name bigline) until he is able to seize the resource. Since attendant’s QUEUE is bigline, and since bigline operates under DISCIPLINE = CHOICE(goldcard), the entity’s “goldcard” will be checked and he will be placed in the QUEUE according to his goldcard priority (low numbers get moved ahead of large numbers.)
Typical Output:
MOR/DS 1.00
Date: 4/13/99 Time: 18:39:11
E:\JUNK1\bestmac1.txt
MODEL DESCRIPTION
****************************************************
PROGRAM
“McDondalds with two counters – simple, default que”
“d:\homework\422\bestmac1.bos”
“Last run 4/11/99 – uses valid queue statements”
DEFINITION
counter1:RESOURCE = {};
counter2:RESOURCE = {};
LABELS = {getcounter1,getcounter2};
CONTROL
STOPTIME=240;
WATCHLIST = {counter1,counter2};
LOGIC
[ 1] ARRIVE {TIME=CUNIFORM(0.5,1)}; [ 2] IF USED[counter1:QUEUE] <= USED[counter2:QUEUE] [ 3] THEN GOTO getcounter1 [ 4] ELSE GOTO getcounter2; [ 5]getcounter1: SEIZE {NAME = counter1}; [ 6] WAIT {TIME = 30 + EXPD(22)}; [ 7] RELEASE {NAME = counter1}; [ 8] DEPART{ }; [ 9] [ 10]getcounter2: SEIZE{NAME = counter2}; [ 11] WAIT {TIME = 0 MAX NORMAL(3,2)}; [ 12] RELEASE {NAME = counter2}; [ 13] DEPART{ }; [ 14 END.—————————————————-
Simulation Clock : 240.00
Block Information
___Stmt___Line______Label________Name___Total___Current
1 1 ARRIVE 318 1
2 2 IF 317 0
3 3 GOTO 120 0
4 4 GOTO 197 0
5 5 GETCOUNTER SEIZE 120 114
6 6 WAIT 6 1
7 7 RELEASE 5 0
8 8 DEPART 5 5
9 10 GETCOUNTER SEIZE 197 113
10 11 WAIT 84 1
11 12 RELEASE 83 0
12 13 DEPART 83 83
——————— Resources ———————–
COUNTER1
Capacity = 1 Current Units = 1
Total Number = 6 Maximum Entities = 1
Maximum Average Average Std Dev Average
Units Util. Units Units Time
1 0.979 0.98 0.14 47.00
What it means: COUNTER1 is a resource. It has the ability (capacity) to handle 1 customer at a time. It is currently working with one unit (customer) The total number of customers it has handled during this simulation has been 6. The maximum number of entities it has handled at one time during the simulation has been 1 – i.e. if it had the capacity to handle 6 units at a time, it may have handled 3 or 4 customers at once, at some time during the simulation. The maximum number of units that COUNTER1 has handled at the same time during the simulation is 1, and it has been utilized 97.9% of the time. The average (over all time during the simulation) number of units that COUNTER1 has handled is 0.98/time period. The Standard Deviation of the number of units served is 0.14 based on an analysis of the statistics taken during the simulation. If this number is very small, you could expect successive runs to give almost the same results as this run. If it is very large, you can expect different results in successive runs. In this case, the program does not expect additional runs to give results outside +/- 3Sigma. The average time it took Counter1 to serve a customer was 47 time units.
Default Queue Statistics
Capacity = Inf Current Number = 114
Maximum Total Average Std Dev Average
Number Number Number Number Time
114 119 55.99 32.24 2687.33
What it means: No defined queue was set up with COUNTER1, so the computer set up a default queue for you. The default queue has (by default) an infinite capacity to hold waiting customers. Currently there are 114 customers in the COUNTER1’s default queue. The maximum number of customers ever seen in this queue, at any time during the simulation, was 114. The total number of customers who ever had to stand in this queue was 119. The average number of people who had to stand in this queue during the simulation was 55.99. The standard deviation of that number was 32.24. Again, high standard deviations indicate that the run will probably change significantly if run again. Low sigma values indicate that the numbers are not likely to change significantly if run again. The average time a customer had to stand in this queue (thus far, because it looks like some of them will die here hungry) was 2687.33. The numbers below for COUNTER2 and its queue, have the same meanings. Note that because you did not set up the queue, and name it yourself, you have limited access to customizing the queue.
COUNTER2
Capacity = 1 Current Units = 1
Total Number = 84 Maximum Entities = 1
Maximum Average Average Std Dev Average
Units Util. Units Units Time
1 0.987 0.99 0.11 2.85
Default Queue Statistics
Capacity = Inf Current Number = 113
Maximum Total Average Std Dev Average
Number Number Number Number Time
113 196 55.71 32.25 161.08
Compile time: 0.05 (Secs.)
Run time : 9.89 (Secs.)
Total memory available : 241146
Memory used by model : 5903
Maximum dynamic memory used: 32336
Total memory used : 38239
Typical Exam Point Deductions:
- Cannot send an entity to, or through, an ARRIVE statement (-10 points)
- Cannot send an entity to, or through, an END. statement (-10 points)
- No entity has yet been born to read and perform this line of code (-10 points)
- Cannot get to this line of code (-5 points)
- Caught in a zero-time loop (-10 points)
- ARRIVE{TIME = 0}; Ten trillion entities will arrive, then crash the computer for lack of additional resources (-10 points)
- All statements require a semi-colon “;” at the end of the line, except for headers (PROGRAM, DEFINITION; CONTROL, etc.) (-2 points)
- weightofvehicle is an attribute, not a global variable. (-10 points)
- Cannot read your code, or follow your logic, or both. (-100 points)