can i do this in ruby? a simulation process

B

brabuhr

sorry I'm totally suck in ruby here is my code:

Don't worry about it so much, we all start as beginners :)
=A0$depart =3D rand(35)

This will give you:
0 <=3D $depart < 35
but, you want:
5 <=3D $depart <=3D 35
=A0$travelTime =3D rand(70)

Similarly, this gives you:
0 <=3D $travelTime < 70
but, you want:
50 <=3D $travelTime <=3D 70

As a sidenote, in Ruby you don't need "$" on all your variables (only
for global variables, which you generally don't need):
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Variables_and_Constant=
s

That's all the further I've been able to look at your code for now.
 
B

Brian Candler

sorry I'm totally suck in ruby here is my code:

For a newbie, it's a fine start, and this is the best way to learn.

In addition to the previous comments, I make the following observations:
$depart = rand(35)

I don't see any need to process the first car any differently from the
subsequent ones, which means you should be able to simplify your code a
lot, by putting *all* the car processing inside the loop.

In my case I assumed the first car left at time 0, but you could equally
have it start at time 5-35.

Both cases are easily handled. Just initialize depart to 0 outside the
loop, and then add 5-35 either at the top of the loop, or at the end (if
the first car departs at time 0).
if $delay1==0;
$delay1 = $delay1+(1);
elsif $delay1==1
$delay1 = $delay1+(1);
end

I'm not sure what the above is trying to do. Both branches of the 'if'
are saying $delay1 = $delay1 + 1, so you could replace all that with
just

$delay1 = $delay1 + 1

Or there is an equivalent shortcut,

$delay1 += 1

If you want an integer random number between 1 and 30, you can do
rand(30)+1

In my case I decided to go with floating point random numbers - rand*30
gives a value between 0 and 29.99999 ... - but both are reasonable
intepretations of the original question.

If you've decided to use integers, you have to decide if 5..35 includes
both ends of the range. To get a value between 0 and 20 *inclusive* you
need rand(21).
sleep($delay1)
$EXT = Time.now
sleep($delay2)
$CEXT = Time.now

I'd take this out. Firstly it's very slow to run the simulation in real
time; secondly, you can't wait until the first car has arrived before
the second one sets off; and thirdly, you can't rely on Time.now because
your computer could be very busy doing other things which could result
the sleep taking longer than you think. That is, sleep(n) only
guarantees to sleep for *at least* n seconds, not exactly n seconds.

I suggest you simply calculate arrival time as departure time plus
transit time.
$passenger2= 1;
$delay101 = rand(10)

Here you calculate $delay101, but then never use it.

$passenger2 and $passenger1 are fixed, so at some point you need to
consider some logic for choosing the number of passengers at random. But
this can wait for now; simplifying the problem so that all cars have 2
passengers, for example, will get you going more quickly.
$i = 1+1;

That's the same as $i = 2

By the way, you don't need semicolons at the end of the line. You only
need them if you're putting multiple statements on the same line.
if $delay1==0
$delay1+(2)
elsif $delay1==1
$delay1+(2)
end

Those lines don't do anything at all. Note that

$delay1+(2)

is the same as

$delay1 + 2

which calculates a value, and then discards it, because it's not
assigned anywhere.

I can't see what the $ET logic in this loop is doing, so I think you
should add some comments to describe it, and if you can't, then think
about rewriting it :)
$totalTravel = $timewait.to_i

You haven't initialised $timewait, so this is the same as nil.to_i,
which always returns zero. As a result, you always see a Total Traveling
Time of 0 for the second and subsequent cars.

This is another good reason for not using global variables. If you had
written

total_travel = timewait.to_i

then ruby could have given you a helpful runtime error. You have not
assigned to timewait earlier, so it's not a local variable, and neither
do you have a method called 'timewait'.

This is also another good reason for treating all the cars the same, so
that there's only one set of logic.

A minor stylistic point: conventionally, foo_bar is preferred over
fooBar as a local variable name.

Finally: running the program with ruby -w will also spring up a few more
warnings. These are because

puts ("hello")

is considered bad form. Either omit the space before the parentheses, or
leave out the parentheses altogether. i.e.

puts("hello") # fine
puts( "hello" ) # also fine
puts "hello" # also fine

I hope there are a few useful pointers in there. So in summary:
* use local variables (foo) not global variables ($foo)
* process all cars inside the loop, so the first car isn't special
* calculate the departure and arrival times, don't use sleep and
Time.now

I think you should now be able to assemble a program which loops round,
printing the start and end times of each journey. Then you can add the
random choice of number of passengers. Feel free to post your revised
code as you go.

Once you've done that, all we need to do is work out the earliest time
in which 500 people have arrived.

HTH,

Brian.
 
B

Brian Candler

if $delay1==0;
I'm not sure what the above is trying to do. Both branches of the 'if'
are saying $delay1 = $delay1 + 1, so you could replace all that with
just

$delay1 = $delay1 + 1

Sorry, what I said was completely wrong there; I misread your code.

What you're actually doing is if $delay1 is 0 or 1, then you increment
it, otherwise you leave it alone. But I don't think you really want to
do that.
 
J

Jean-Julien Fleck

2010/8/17 Jean-Julien Fleck said:
Sure. I have no time left to play with it today, but I will try it tomorrow.
If I recall right, the mean distance from the origin of a 1D random
walk behaves like a diffusive process: it's growing like the square
root of time (with a constant factor before it). Here, there are some
complications, but I would expect it to behave quite the same: if you
know the average time to get a 50 people difference between the two
cities, it will take 10**2 = 100 times more time to get a 500 people
difference in mean.

Well, in the end, it did not take too long: less than 3 hours in mean
for all simulations (all done launching 5000 vehicules from each city)
to reach an increase of 500 people in one of the two cities.

-----
In mean, it took 8785.5 seconds to get a 500 difference.
from 1000 simulations over 1000 that have been ran
Median time being 6490.5
Max time: 57162.5
Min time: 746.1
Dispersion: 7413.6
-----

If you look at the distribution of the times (rw_time.pdf) you see
that there are only a few (around 10%) that take a very long time
(>20000s) to get to this 500 increase. I also included a typical run
(rw_typical_run.pdf) of evolution of the two populations along time.

Cheers,

JJ

PS: Thanks Bruce for this interesting problem: I'm sure my students
will appreciate it in the coming year :eek:)
 
B

Bruce Wayner

i already erase some codes: but the thing is how can i get the total
number of seconds every time vehicle arrive in the second city.

Example:
Vehicle Number 1:
Departure Time: 3 seconds
Travel Time: 45seconds
# of people transfer: 1
Total Time Consume: 48 --> how can get that one

Vehicle Number 2:
Departure Time: 8 seconds
Travel Time: 35 seconds
# of people transfer: 2 ->(is it possible to store this one in an array
so that if Vehicle Number 2 reaches the 30% (150) of people transfer it
will
compute for the total spent in transferring those people) how?
Total Time Consume: 43

and then if the loop reaches the last loop which is the bus
it will compute also the time etc..
also let say the there 50 already transferred that is less than 500 so
there are 450 more how can i loop again so that it will loop again and
it will give again 50people transfer until it reaches 500.. after
reaching the 500 people it will calculate all the seconds consume...
this is too complicated to understand i hope you get the point sorry...

Here is my code which i delete some stuff to make it little:
print "Number of Vehicle: " #That will be maximum of 5 only
n = gets().to_i

print "\n Vehicle number 1: "
$delay1 = rand(4)
$delay2 = rand(10)
$depart = rand(36)
$travelTime= rand(71)
$ET = $depart
$ET1= $travelTime
$delay1 +=1
sleep($delay1)
sleep($delay2)
$passenger2= 1
$delay101 = rand(10)
puts ("\nDeparture Time: #$ET seconds");
puts ("Traveling Time: #$ET1 seconds");
puts ("# of passenger Arrive in Second City: #{$passenger2}");
puts ("Total Traveling Time: #{$delay1} seconds");
$i = 1+1;
$num = n+1;

while $i < $num do

puts ("\n Vehicle number: #{$i}");
$i +=1;

$depart1 = rand(36)
$travelTime1 = rand(71)
$ET = $depart1
$ET1= $travelTime1
$passenger1=2
puts ("\nDeparture Time: #$depart seconds");
puts ("Traveling Time: #$travelTime1 seconds");
puts ("# of people Arrive in second city: #{$passenger1}");
puts ("Total Traveling Time: #$totalTravel");

end
puts("# of people transfer:");
puts("Total Time:");
 
B

brabuhr

i already erase some codes: but the thing is how can i get the total
number of seconds every time vehicle arrive in the second city.

Example:
Vehicle Number 1:
Departure Time: 3 seconds
Travel Time: 45seconds
# of people transfer: 1
Total Time Consume: 48 --> how can get that one

For any given vehicle:
arrival_time =3D departure_time + travel_time

If I read your problem statement correctly, what you are being asked
for is the arrival time of the last vehicle (well, arrival time of the
vehicle that has arrived-passenger number 500)
Here is my code which i delete some stuff to make it little:
print "Number of Vehicle: " #That will be maximum of 5 only
n =3D gets().to_i

print "\n Vehicle number 1: "
=A0$delay1 =3D rand(4)
=A0$delay2 =3D rand(10)
=A0$depart =3D rand(36)
=A0$travelTime=3D rand(71)
=A0$ET =3D $depart
=A0$ET1=3D $travelTime
=A0$delay1 +=3D1
=A0sleep($delay1)
=A0sleep($delay2)
=A0$passenger2=3D 1
=A0$delay101 =3D rand(10)
=A0puts ("\nDeparture Time: =A0#$ET seconds");
=A0puts ("Traveling Time: =A0#$ET1 seconds");
=A0puts ("# of passenger Arrive in Second City: #{$passenger2}");
=A0puts ("Total Traveling Time: =A0 =A0 #{$delay1} seconds");
=A0$i =3D 1+1;
=A0$num =3D n+1;

Remove this whole vehicle 1 thing and just start the loop w/ i set to 1:
=A0while $i < $num =A0do

=A0puts ("\n Vehicle number: #{$i}");
=A0$i +=3D1;

=A0$depart1 =3D rand(36)
=A0$travelTime1 =3D rand(71)
=A0$ET =3D $depart1
=A0$ET1=3D $travelTime1

What are ET and ET1 intended to be?
=A0$passenger1=3D2
=A0 =A0 puts ("\nDeparture Time: =A0#$depart seconds");
=A0 =A0 puts ("Traveling Time: =A0#$travelTime1 seconds");
=A0 =A0puts ("# of people Arrive in second city: #{$passenger1}");
=A0 =A0puts ("Total Traveling Time: =A0#$totalTravel");

You never increment $totalTravel; it could be something like
"$totalTravel +=3D $travelTime1". Though that would not be the value
your problem statement asked for.

Consider the vehicle 1 leaves at time 0 and takes 30 seconds and
vehicle 2 leaves at time 15 and takes 30 seconds. Adding the travel
times together would give a total time of 60 seconds. However, both
vehicles were on the road at the same time, so the actual time taken
to deliver the passengers was 45 seconds.

More importantly, in the loop you do not keep a running total of
arrived passengers. Then, the loop should be keyed off of number of
arrived passengers instead of number of vehicles.
 
B

Bruce Wayner

can someone edit my code:
i've been trying to change the thing you said but it shows nothing. :(
print "Number of Vehicle: " #That will be maximum of 5 only
n = gets().to_i

print "\n Vehicle number 1: "
$delay1 = rand(4)
$delay2 = rand(10)
$departure_Time = rand(36)
$travel_Time= rand(71)

$delay1 +=1
sleep($delay1)
sleep($delay2)
$passenger2= 1
$delay101 = rand(10)
puts ("\nDeparture Time: #$departure_Time seconds");
puts ("Traveling Time: #$travel_Time seconds");
puts ("# of passenger Arrive in Second City: #{$passenger2}");
puts ("Total Traveling Time: #{$delay1} seconds");
$i = 1+1;
$num = n+1;

while $i < $num do

puts ("\n Vehicle number: #{$i}");
$i +=1;

$departure_time2 = rand(36)
$travel_time2 = rand(71)
$passenger1=2
puts ("\nDeparture Time: #$departure_time2 seconds");
puts ("Traveling Time: #$travel_time2 seconds");
puts ("# of people Arrive in second city: #{$passenger1}");
puts ("Total Traveling Time: #$totalTravel");

end
puts("# of people transfer:");
puts("Total Time:");

Cheers,
 
B

brabuhr

can someone edit my code:
i've been trying to change the thing you said but it shows nothing. :(
print "Number of Vehicle: " #That will be maximum of 5 only
n =3D gets().to_i

START DELETE
print "\n Vehicle number 1: "
=A0$delay1 =3D rand(4)
=A0$delay2 =3D rand(10)
=A0$departure_Time =3D rand(36)
=A0$travel_Time=3D rand(71)

=A0$delay1 +=3D1
=A0sleep($delay1)
=A0sleep($delay2)
=A0$passenger2=3D 1
=A0$delay101 =3D rand(10)
=A0puts ("\nDeparture Time: =A0#$departure_Time seconds");
=A0puts ("Traveling Time: =A0#$travel_Time seconds");
=A0puts ("# of passenger Arrive in Second City: #{$passenger2}");
=A0puts ("Total Traveling Time: =A0 =A0 #{$delay1} seconds");
=A0$i =3D 1+1;
END DELETE

Add: $i =3D 1
=A0$num =3D n+1;

=A0while $i < $num =A0do

=A0puts ("\n Vehicle number: #{$i}");
=A0$i +=3D1;

=A0$departure_time2 =3D rand(36)
=A0$travel_time2 =3D rand(71)
=A0$passenger1=3D2
=A0 =A0 puts ("\nDeparture Time: =A0#$departure_time2 seconds");
=A0 =A0 puts ("Traveling Time: =A0#$travel_time2 seconds");
=A0 =A0puts ("# of people Arrive in second city: #{$passenger1}");
=A0 =A0puts ("Total Traveling Time: =A0#$totalTravel");

=A0end
=A0puts("# of people transfer:");
=A0puts("Total Time:");

That's a start to cut down the amount of code you have to deal with
and still give pretty much the same result.
 
B

Bruce Wayner

unknown said:
Add: $i = 1
That's a start to cut down the amount of code you have to deal with
and still give pretty much the same result.

i already done that Thanks

take a look at the problem:
A superhighway connects one large metropolitan area to another.
A vehicle leaves the first city every 5-35sec. 20% of the vehicles have
1 passenger, 30% have 2 passengers, 10% have 3 passengers and and 10%
have 4 passengers. the remaining 30% of the vehicles are buses, which
carry 40 people.
It takes 50sec-1min &10sec for vehicles to travel between the two
metropolitan
areas. How long does it take for 500 people to arrive in the second
city.

how can i set the passenger for each vehicle? like for example
i input vehicles number: 5
how can set the passenger of vehicle 1 which is it only allow 1
passenger
next for vehicle 2 (2 passenger) and vehicle 3 (3 passenger) and vehicle
4 (4passenger) and lastly the vehicle which have 40 passenger: how can i
set all of those in loop? is it possible:

Cheers,
 
J

Jean-Julien Fleck

Hello,
how can i set the passenger for each vehicle? like for example
i input vehicles number: 5
how can set the passenger of vehicle 1 which is it only allow 1
passenger

I think you misread the problem: nobody says that the first vehicle
have to have 1 passenger. All it says is that if you take a pool of
100 vehicles, 20 of them will have only 1 passenger, 30 2 passengers,
10 3 passengers, 10 4 passengers and the 30 remaining will be buses of
40 passengers.

Each time, you have to choose randomly one vehicle in all this pool of
vehicles to let him go on the road.

Cheers,

--=20
JJ Fleck
PCSI1 Lyc=E9e Kl=E9ber
 
B

brabuhr

I think you misread the problem: nobody says that the first vehicle
have to have 1 passenger. All it says is that if you take a pool of
100 vehicles, 20 of them will have only 1 passenger, 30 2 passengers,
10 3 passengers, 10 4 passengers and the 30 remaining will be buses of
40 passengers.

Bruce,

Consider a simpler case w/ pencil, paper, and a coin. Assume that 50%
of vehicles have 2 passengers and 50% have 3. How would you do it?
Maybe something like:

Flip coin
If result is heads then
vehicle will have 2 passengers
Otherwise, if result is tails
vehicle will have 3 passengers
Otherwise
wow, edge!?

Let's make that more code-like:

result = rand(2)
if result == 0
puts "2"
else
puts "3"
end
 
I

Ian Hobson

still i don't know how to begin my program on this problem:

A superhighway connects one large metropolitan area to another.
A vehicle leaves the first city every 5-35sec. 20% of the vehicles have
1 passenger, 30% have 2 passengers, 10% have 3 passengers and and 10%
have 4 passengers. the remaining 30% of the vehicles are buses, which
carry 40 people.
It takes 50sec-1min&10sec for vehicles to travel between the two
metropolitan
areas. How long does it take for 500 people to arrive in the second
city.

Requirements:
1. A simulation process of the movement of vehicles from one point to
another.
2. The time (in minutes) for 500 people to arrive in the second city.

i can't even think on how can i start this one in ruby a newbie like me
have only limited knowledge on ruby. can someone help with my program?
Hi Bruce,

Some concepts for you. A simulation has exactly three types of "events".

a) Processes that start immediately resources that they need become
available.

b) Processes that free resources a known time later. These processes can
continue but they must not require more resources (the resources may not
be available).

c) Events that happen on the clock and report the status.

To run a simulation, you need a queue of time based events to handle,
and a loop that will handle them as follows.
1) Step forward to the next time point (pop the head of the queue).
2) Do all the type b events that can be done at this time, freeing
the resources.
3) Starts all the type a) processes that can be started with the
freed resource(s) (most urgent first), booking the resources as you go.
4) Reports the situation if required.
5) Determine if you should stop or continue.

You will also need queues of "work" waiting to be done when resources
become available.

For your problem you can forget the c events - you need to test the
status after each car arrives.

For your problem you have to clarify what "A vehicle leaves the first
city every 5-35sec " means. Vehicles usually arrive at a queue according
to a Poisson distribution, but a Poisson distribution is defined by a
single parameter (this is all of its mean, its standard deviation, and
the number of vehicles expected per unit of time). That you don't have.
The phrase *may* mean that the departure times are uniformly distributed
between 5 and 35 seconds.

You also have to clarify how the arrival occurs - do the vehicles have
to exit the super-highway using an off-ramp that also is limited to one
every 5 seconds?

Assuming both, I would simulate the movement as something like this.

There are two queues of "work" - one is the notional arrival of the
vehicles. These could be generated in advance, but, with the arrival
distribution given it will be better to generate the next vehicle as the
previous one leaves. The second queue of work is the queue to use the
off-ramp.

There are two "a" events:
When the on-ramp is free, you create a vehicle that can use the
on-ramp. Use random variables to decide what it is, how full it is, how
long into the 5-35 gap it will take before it leaves. Book the on-ramp
and queue the "departure" event.
If there is a vehicle waiting to use the off-ramp and the off-ramp
is free, book the off-ramp, and queue up the arrival event in 5 seconds
time.

There are three "b" type events
depart: free the on-ramp, compute how long the journey will take
and and queue up the exit-highway event.
exit-highway : queue the vehicle to exit the highway.
arrive : free the off-ramp, and accumulate the people who have
arrived. If you have over 500, stop the program.

Although in this simple scenario it may be possible to book the car
directly on the off-ramp if it is free, don't do this. It will
complicate your code for no benefit.

Regards

Ian
 
R

Rob Biedenharn

Bruce,

Consider a simpler case w/ pencil, paper, and a coin. Assume that 50%
of vehicles have 2 passengers and 50% have 3. How would you do it?
Maybe something like:

Flip coin
If result is heads then
vehicle will have 2 passengers
Otherwise, if result is tails
vehicle will have 3 passengers
Otherwise
wow, edge!?

Let's make that more code-like:

result = rand(2)
if result == 0
puts "2"
else
puts "3"
end


OK, I know this thread is going for some kind of record, but like any
good wreck it's so hard not to look.

Why isn't anyone saying "make an object"? Well, I will!

http://gist.github.com/536140

(Yeah, I know Bruce ought to do this himself, but I'm tired and this
allowed me to procrastinate a bit.)

-Rob

Rob Biedenharn
(e-mail address removed) http://AgileConsultingLLC.com/
(e-mail address removed) http://GaslightSoftware.com/
 
J

Jean-Julien Fleck

2010/8/18 said:
What kind of record would that be?

I think Rob is talking about the number of mails in the thread (53 at
the time being), which is quite impressive for such a simple question
:eek:)
Well, JJ Fleck did suggest making a Vehicle class :)

Indeed. Here is what I did (with no comment and no mean value
computation, to let Bruce think about what happens)

class Vehicle
attr_reader :departure_time,:arrival_time,:type,:passengers

def initialize(present_time)
@departure_time =3D present_time
@arrival_time =3D @departure_time + 50 + rand(21)
@type,@passengers =3D decide_type
end

def decide_type
r =3D rand(10)
return 'car',1 if r < 2
return 'car',2 if r < 5
return 'car',3 if r < 6
return 'car',4 if r < 7
return 'bus',40
end
end

vehicles =3D Array.new
time =3D 0
500.times do
vehicles << Vehicle.new(time)
time =3D vehicles[-1].departure_time + 5 + rand(31)
end

sum =3D 0
vehicles.sort_by {|e| e.arrival_time}.each do |e|
sum +=3D e.passengers
puts "#{sum} passengers were there after #{e.arrival_time} seconds"
break if sum > 500
end

Nice. =A0I like the Config class.

Yes. Perhaps a bit of overkill for the given problem :eek:)

Cheers,

--=20
JJ Fleck
PCSI1 Lyc=E9e Kl=E9ber
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top