Archive for November 2008
Java: Rediscovering the basics
It’s been a while since I did some Java but now it seems to be the right tool for the job at hand so I am rediscovering Java with a masochistic twist, ‘look boss no IDEs’.
I am experimenting with the SSJ Java library for Stochastic Simulation as I mentioned in an earlier post and here is some sample source code:
import umontreal.iro.lecuyer.randvar.*;
import umontreal.iro.lecuyer.probdist.*;
import umontreal.iro.lecuyer.rng.*;
public class GenerateDemandArrivals {
private RandomStream randomStream;
private RandomVariateGen expArrival;
private RandomVariateGen poissonArrival;
private double lambda;
private int times;
public GenerateDemandArrivals() {
randomStream = new MRG32k3a();
lambda = 10.0;
times = 5;
expArrival = new RandomVariateGen(randomStream, new ExponentialDist(lambda));
poissonArrival = new PoissonGen(randomStream, new PoissonDist(lambda));
}
public void demandArrival() {
for (int i = 0; i < times; i++) {
System.out.println("Here is the next random int : " + randomStream.nextInt(0, 10));
}
}
public void demandArrivalExpDist() {
for (int i = 0; i < times; i++) {
System.out.println("Here is the next exponential dist double : " + expArrival.nextDouble());
}
}
public void demandArrivalPoissonDist() {
for (int i = 0; i < times; i++) {
System.out.println("Here is the next poisson dist double : " + poissonArrival.nextDouble());
}
}
public static void main(String[] arg) {
new GenerateDemandArrivals().demandArrival();
new GenerateDemandArrivals().demandArrivalExpDist();
new GenerateDemandArrivals().demandArrivalPoissonDist();
}
}
I was tried of doing the following everytime I changed the source code in my favorite editor Vim:
javac -cp "C:\Program Files\Java\jdk1.6.0_02\lib\ext\ssj.jar;." GenerateDemandArrivals.java java -cp "C:\Program Files\Java\jdk1.6.0_02\lib\ext\ssj.jar;." GenerateDemandArrivals
I already had ant installed on my Windows machine but so I said why not take advantage of it, I looked for simple ant file and found something quite close in apache ant manual.
After little bit more search and refinement here is what I came up with:
<project name="Sim" default="run" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="."/>
<property name="build" location="."/>
<path id="project.class.path">
<pathelement path="C:\Program Files\Java\jdk1.6.0_02\lib\ext\ssj.jar"/>
<pathelement path="."/>
</path>
<target name="run"
description="run the program"
depends="compile">
<java classname="GenerateDemandArrivals">
<classpath refid="project.class.path"/>
</java>
</target>
<target name="compile"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}">
<classpath refid="project.class.path"/>
</javac>
</target>
</project>
Now I can simple type ant (while I am in the directory containing the build.xml file above) after any changes to the file and it compiles and run my code.
I feeling ashamed of feeling good and writing about such basic stuff but I am thinking there would be another person like me (could be myself at some future point where I have to leave my lovely Ruby world and come back to Java out of necessity).
JRuby: Stochastic Simulation with SSJ
I needed to work on a simulation project that involved working with the SSJ java library.
If I haven’t mentioned before I love Ruby (the programming language) and Java, though a tool in my toolkit, does not evoke the same feeling.
So my first reaction was I can use JRuby to benefit from the existing java library and beauty of Ruby.
The SSJ library comes with a comprehensive sets of examples and documentation. I started exploring that.
Fortunately at RubyConf 2008 with some help from Charles Nutter I was able to install jruby on my laptop, getting jruby installed and running was not trivial. I wish somebody can do a one click installer for jruby same as they did for Ruby and Rails.
I downloaded SSJ and unzipped the downloaded file containing jar files into C:\Program Files\Java\jdk1.6.0_02\lib\ext directory. Added the CLASSPATH variable in my windows environment set to this directory.
I tried the following example from examples.pdf
import umontreal.iro.lecuyer.rng.*;
import umontreal.iro.lecuyer.stat.*;
public class Collision {
int k; // Number of locations.
int m; // Number of items.
double lambda; // Theoretical expectation of C (asymptotic).
boolean[] used; // Locations already used.
public Collision (int k, int m) {
this.k = k;
this.m = m;
lambda = (double) m * m / (2.0 * k);
used = new boolean[k];
}
// Generates and returns the number of collisions.
public int generateC (RandomStream stream) {
int C = 0;
for (int i = 0; i < k; i++) used[i] = false;
for (int j = 0; j < m; j++) {
int loc = stream.nextInt (0, k-1);
if (used[loc]) C++;
else used[loc] = true;
}
return C;
}
// Performs n indep. runs using stream and collects statistics in statC.
public void simulateRuns (int n, RandomStream stream, Tally statC) {
statC.init();
for (int i=0; i<n; i++) statC.add (generateC (stream));
statC.setConfidenceIntervalStudent();
System.out.println (statC.report (0.95, 3));
System.out.println (" Theoretical mean: " + lambda);
}
public static void main (String[] args) {
Tally statC = new Tally ("Statistics on collisions");
Collision col = new Collision (10000, 500);
col.simulateRuns (100000, new MRG32k3a(), statC);
}
}
I compiled and ran the Java code above to ensure I was getting the same results using the following steps:
javac -cp "C:\Program Files\Java\jdk1.6.0_02\lib\ext\ssj.jar" Collision.java java -cp "C:\Program Files\Java\jdk1.6.0_02\lib\ext\ssj.jar;C:\code\ruby\jruby" Collision
As you can notice my code was in the C:\code\ruby\jruby directory and I was in this directory when I ran the above program.
Here is the same code example in jruby code:
require 'java'
require 'ssj.jar'
import 'umontreal.iro.lecuyer.rng.RandomStream'
import 'umontreal.iro.lecuyer.stat.Tally'
import 'umontreal.iro.lecuyer.rng.MRG32k3a'
class Collision
def initialize(k, m)
@k = k
@m = m
@lambda = m * m / (2.0 * k)
@used = Array.new(k, false)
end
def generate_c(stream)
c = 0
@k.times { |i| @used[i] = false }
@m.times do |j|
loc = stream.nextInt(0, @k-1)
if @used[loc]
c += 1
else
@used[loc] = true
end
end
return c
end
def simulate_runs(n, stream, stat_c)
stat_c.init
n.times { stat_c.add(generate_c(stream)) }
stat_c.setConfidenceIntervalStudent()
puts stat_c.report(0.95, 3)
puts " Theoretical mean: #{@lambda} "
end
def self.run
stat_c = Tally.new("Statistics on collision")
col = Collision.new(10000,500)
col.simulate_runs(100000, MRG32k3a.new, stat_c)
end
end
Collision.run
The jruby code runs comparatively slower (my feeling is 5 times slower but I will measure and add it later). I am using the latest available jruby 1.1.5 at the time of this post.
Update: The JRuby version takes around 13 minutes while the equivalent Java code above takes 17 seconds. This seems to be unacceptable performance, I am not sure if this is specific to SSJ or other libraries too. If I understand correctly, JRuby should be running inside the JVM and when I call SSJ library that is the same Java code that runs so I don’t understand why it is so slow unless I have used some technique that slows down my JRuby version.