For an assignment I'm currently trying to measure the performance (space/time) difference between an iterative solution to the matrix chain problem and a recursive one.
The gist of the problem and the solution I'm using for the iterative version can be found here: http://www.geeksforgeeks.org/dynamic-programming-set-8-matrix-chain-multiplication/
I'm running a given input through both functions 10 times, measuring the space and time performance of each function. The very interesting thing is that while the recursive solution runs much slower than the iterative solution on the first call it's performance is much better on successive calls it is much faster. The functions are not making use of any class-global variables other than one for counting memory usage. Why is this occurring? Is it something the compiler is doing or am I missing something obvious?
Note: I know my way of measuring memory is wrong, planning on changing it.
Main: Initializes Array and passes it to run functions
public static void main(String[] args) {
int s[] = new int[] {30,35,15,5,10,100,25,56,78,55,23};
runFunctions(s, 15);
}
runFunctions: Runs both functions 2 * n times, measuring space and time and printing results at the end
private static void runFunctions(int[]arr , int n){
final Runtime rt = Runtime.getRuntime();
long iterativeTime[] = new long [n],
iterativeSpace[] = new long [n],
recursiveSpace[] = new long [n],
recursiveTime[] = new long [n];
long startTime, stopTime, elapsedTime, res1, res2;
for (int i = 0; i <n; i++){
System.out.println("Measuring Running Time");
//measure running time of iterative
startTime = System.nanoTime();
res1 = solveIterative(arr, false);
stopTime = System.nanoTime();
elapsedTime = stopTime - startTime;
iterativeTime[i] = elapsedTime;
//measure running time of recursive
startTime = System.nanoTime();
res2 = solveRecursive(arr, false);
stopTime = System.nanoTime();
elapsedTime = stopTime - startTime;
recursiveTime[i] = elapsedTime;
System.out.println("Measuring Space");
//measure space usage of iterative
rt.gc();
res1 = solveIterative(arr, true);
iterativeSpace[i] = memoryUsage;
//measure space usage of recursive
rt.gc();
res2 = solveRecursive(arr, true);
recursiveSpace[i] = memoryUsage;
rt.gc();
if (res1 != res2){
System.out.println("Error! Results do not match! Iterative Result: " + res1 + " Recursive Result: " + res2);
}
}
System.out.println("Time Iterative: " + Arrays.toString(iterativeTime));
System.out.println("Time Recursive: " + Arrays.toString(recursiveTime));
System.out.println("Space Iterative: " + Arrays.toString(iterativeSpace));
System.out.println("Space Recursive: " + Arrays.toString(recursiveSpace));
}
solveRecursive: bootstrap for doRecursion
private static int solveRecursive(int[] s, boolean measureMemory){
memoryUsage = 0;
maxMemory = 0;
int n = s.length - 1;
int[][] m = new int[n][n];
int result;
if (measureMemory){
memoryUsage += MemoryUtil.deepMemoryUsageOf(n);
memoryUsage += MemoryUtil.deepMemoryUsageOf(s);
memoryUsage += MemoryUtil.deepMemoryUsageOf(m);
result = doRecursion(0, n - 1, m, s);
memoryUsage += MemoryUtil.deepMemoryUsageOf(result);
System.out.println("Memory Used: " + memoryUsage);
}
else
{
result = doRecursion(0, n - 1, m, s);
}
return result;
}
doRecursion: solves the function recursively
private static int doRecursion(int i, int j, int[][] m, int s[]){
if (m[i][j] != 0){
return m[i][j];
}
if (i == j){
return 0;
}
else
{
m[i][j] = Integer.MAX_VALUE / 3;
for (int k = i; k <= j - 1; k++){
int q = doRecursion(i, k, m, s) + doRecursion(k + 1, j, m, s) + (s[i] * s[k + 1] * s[j + 1]);
if (q < m[i][j]){
m[i][j] = q;
}
}
}
return m[i][j];
}
solveIterative: Solves the problem iteratively
private static int solveIterative(int[] s, boolean measureMemory) {
memoryUsage = 0;
maxMemory = 0;
int n = s.length - 1;
int i = 0, j = 0, k= 0, v = 0;
int[][] m = new int[n][n];
for (int len = 2; len <= n; len++) {
for (i = 0; i + len <= n; i++) {
j = i + len - 1;
m[i][j] = Integer.MAX_VALUE;
for (k = i; k < j; k++) {
v = m[i][k] + m[k + 1][j] + s[i] * s[k + 1] * s[j + 1];
if (m[i][j] > v) {
m[i][j] = v;
}
}
}
}
if (measureMemory){
memoryUsage += MemoryUtil.deepMemoryUsageOf(n);
memoryUsage += MemoryUtil.deepMemoryUsageOf(m);
memoryUsage += MemoryUtil.deepMemoryUsageOf(i);
memoryUsage += MemoryUtil.deepMemoryUsageOf(j);
memoryUsage += MemoryUtil.deepMemoryUsageOf(k);
memoryUsage += MemoryUtil.deepMemoryUsageOf(v);
memoryUsage += MemoryUtil.deepMemoryUsageOf(s);
System.out.println("Memory Used: " + memoryUsage);
}
return m[0][n - 1];
}
Output:
Time Iterative: [35605, 12039, 20492, 17674, 17674, 12295, 11782, 19467, 16906, 18442, 21004, 19980, 18955, 12039, 13832]
Time Recursive: [79918, 4611, 8453, 6916, 6660, 6660, 4354, 6916, 18699, 7428, 13576, 5635, 4867, 3330, 3586]
Space Iterative: [760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760]
Space Recursive: [712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712]