Non-Trivial Java Math exercise - java

I was given this question to test my programming ability. Though I feel it is as much math as it is programming. I have failed honestly, but I would like to know how it is done for future reference.
The ideal answer will use recursion and threads.
Your niece was given a set of blocks for her birthday, and she has decided to build a panel using 3”×1” and 4.5”×1" blocks. For structural integrity, the spaces between the blocks must not line up in adjacent rows. For example, the 13.5”×3” panel below is unacceptable, because some of the spaces between the blocks in the first two rows line up (as indicated by the dotted line).
There are 2 ways in which to build a 7.5”×1” panel, 2 ways to build a 7.5”×2” panel, 4 ways to build a 12”×3” panel, and 7958 ways to build a 27”×5” panel. How many different ways are there for your niece to build a 48”×10” panel? The answer will fit in a 64-bit integer. Write a program to calculate the answer.
That is the issue, I am not sure where to begin in terms of math. I understand I need to compute all possible combinations for the first row. But I am not really sure how. Then you could at this point on a particular thread calculate all possible combos for the next row and so on. And then each first row combination could get its own thread and pass its setup into a recursive algorithm that compares the current row to the last one, and finds a possible answer. But I can't really program it because I don't know how to calculate the possible combinations for any row. If I did, then maybe I could check to see if its a legal row (no two blocks exactly on top of each other (staggered)) and move on to the next one. Possibly each row would be a for loop for nested around the next one in terms of Code. But again I don't know what to do for the mathematical aspect of it.

I think you have a good initial grasp of the problem. If I understand your thoughts correctly, you ought to be recursing on each block placement, not on each row placement - as blocks that are oriented vertically will quickly preclude any ordinary rows.
Here's the approach I would take: you will end up building a tree (either explicitly in memory or implicit: the tree can be an argument that is passed in your recursive function). The node of the tree will be a state of the tree - so the root is "no blocks placed". You place a first block "somehow" (we'll get to that) and that represents a new state.
The goal will be to construct a set of leaf nodes which are all complete (the board is filled in) and legal (no cracks line up). So how do we get there?
For each block placement, there are 4 "alternate realities": a 3x1 block placed horizontally, a 3x1 placed vertically (call this 1x3), a 4.5x1 placed horizontally, and a 1x4.5. For each of these options, you will attempt to "legally" place the block at the next point in the row. If it is legal (legal being someting along the lines of "block doesn't overlap the board edges, block doesn't share a vertical edge") then you can accept that board as an intermediate state and recurse with that new state. If it is not legal, then that state must be abandoned.
Thinking this way, the first 4 children nodes will be a block in the bottom-left corner as [3x1, 1x3, 4.5x1, 1x4.5]. Each of those four states will have a block "just to the right" in one of 4 configurations, and so on.
In order to move across the rows, when you hit the right edge, I would find the "lowest" empty spaces and fill them arbitrarily when they tie from left to right. This is eager enough to prune large sets when the edges are ragged, but still works well when the levels are flat, like when you're first starting out.
In essence, your tree will have (up to) 4 nodes for each intermediate state, with the edges representing an "attempted placement". If you cannot legally place the block at that "attempted placement", you do not recurse, pruning that possibility and all descendents from the tree.
This brute-force method should get you a completed board, even if its computational complexity is astronomical. It is only at the point that you can correctly solve some problems that you should consider parallelizing with threads. Recursive problems tend to lend themselves well to threads, as each recursion can often be parallelized without too much pain. Just make sure you get it right first.

This post is almost 5 years old but maybe my answer will be usefull for someone. There are two solutions below. First is without multithreading. Second one uses four threads to solve the problem. It calculates 48x4 panel (48x10 lasts very long) but it can be easilly modified by changing initial values:
nbOfRows, nbOfCols, wallWidth and wall
Solution without multithreading:
import java.io.*;
import java.util.*;
class WallFlexOld
{
static final float blocks[] = {3.0f, 4.5f};
static final int nbOfRows = 4;
static final int nbOfCols = 16;
static final float wallWidth = 48.0f;
static final float wall[][] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
static long nbOfCombinations = 0;
public static void main(String args[])
{
long startTime = System.currentTimeMillis();
addBlock(0, 0);
long workingTime = System.currentTimeMillis() - startTime;
System.out.println("Working time: " + workingTime + "ms");
System.out.println("noc: " + nbOfCombinations);
}
static void addBlock(int row, int col)
{
for(float b: blocks)
{
wall[row][col] = b;
if(blockFit(row, col))
{
if(rowWidth(row) <= wallWidth)
{
if(rowWidth(row) == wallWidth)
{
if(row == (nbOfRows - 1))
nbOfCombinations++;
else
addBlock(row + 1, 0);
}
else //rowWidth < wallWidth
addBlock(row, col + 1);
}
}
wall[row][col] = 0;
}
}
static float rowWidth(int row)
{
float width = 0;
for(float b: wall[row])
width = width + b;
return width;
}
static boolean blockFit(int row, int col)
{
if(row == 0)
return true;
boolean fit = true;
float currentLenght = 0;
for(int i = 0; i < col; i++)
currentLenght = currentLenght + wall[row][i];
float lowerRowCurLenght = 0;
for(float b: wall[row - 1])
{
lowerRowCurLenght = lowerRowCurLenght + b;
if((currentLenght == lowerRowCurLenght) & (currentLenght != wallWidth))
fit = false;
}
return fit;
}
}
Solution with multithreading:
import java.io.*;
import java.util.*;
class Wall implements Runnable
{
private float blocks[];
private int nbOfRows;
private int nbOfCols;
private float wallWidth;
private float wall[][];
private long nbOfCombinations = 0;
private int row, col;
public long getNbOfCombinations() { return this.nbOfCombinations; }
Wall(float blocks[], int nbOfRows, int nbOfCols, float wallWidth, float wall[][], int row, int col)
{
this.blocks = blocks;
this.nbOfRows = nbOfRows;
this.nbOfCols = nbOfCols;
this.wallWidth = wallWidth;
this.wall = wall;
this.row = row;
this.col = col;
}
private boolean blockFit(int row, int col)
{
if(row == 0)
return true;
boolean fit = true;
float currentLenght = 0;
for(int i = 0; i < col; i++)
currentLenght = currentLenght + wall[row][i];
float lowerRowCurLenght = 0;
for(float b: wall[row - 1])
{
lowerRowCurLenght = lowerRowCurLenght + b;
if((currentLenght == lowerRowCurLenght) & (currentLenght != wallWidth))
fit = false;
}
return fit;
}
private float rowWidth(int row)
{
float width = 0;
for(float b: wall[row])
width = width + b;
return width;
}
private void addBlock(int row, int col)
{
for(float b: blocks)
{
wall[row][col] = b;
if(blockFit(row, col))
{
if(rowWidth(row) <= wallWidth)
{
if(rowWidth(row) == wallWidth)
{
if(row == (nbOfRows - 1))
nbOfCombinations++;
else
addBlock(row + 1, 0);
}
else //rowWidth < wallWidth
{
addBlock(row, col + 1);
}
}
}
wall[row][col] = 0;
}
}
#Override
public void run()
{
addBlock(row, col);
}
}
class WallMT
{
static final float blocks[] = {3.0f, 4.5f};
static final int nbOfRows = 4;
static final int nbOfCols = 16;
static final float wallWidth = 48.0f;
static final float wall[][] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
public static void main(String args[])
{
wall[0][0] = blocks[0];
wall[0][1] = blocks[0];
Wall myWall1 = new Wall(blocks, nbOfRows, nbOfCols, wallWidth, getWallCopy(wall), 0, 2);
Thread t1 = new Thread(myWall1);
wall[0][0] = blocks[0];
wall[0][1] = blocks[1];
Wall myWall2 = new Wall(blocks, nbOfRows, nbOfCols, wallWidth, getWallCopy(wall), 0, 2);
Thread t2 = new Thread(myWall2);
wall[0][0] = blocks[1];
wall[0][1] = blocks[0];
Wall myWall3 = new Wall(blocks, nbOfRows, nbOfCols, wallWidth, getWallCopy(wall), 0, 2);
Thread t3 = new Thread(myWall3);
wall[0][0] = blocks[1];
wall[0][1] = blocks[1];
Wall myWall4 = new Wall(blocks, nbOfRows, nbOfCols, wallWidth, getWallCopy(wall), 0, 2);
Thread t4 = new Thread(myWall4);
long startTime = System.currentTimeMillis();
t1.start();
t2.start();
t3.start();
t4.start();
try
{
t1.join();
t2.join();
t3.join();
t4.join();
}
catch(InterruptedException ie)
{
System.out.println("Thread " + t1 + " interrupted.");
}
long workingTime = System.currentTimeMillis() - startTime;
System.out.println("Working time: " + workingTime + "ms");
System.out.println("noc: " + (myWall1.getNbOfCombinations() + myWall2.getNbOfCombinations() + myWall3.getNbOfCombinations() + myWall4.getNbOfCombinations()));
}
static private float[][] getWallCopy(float wall[][])
{
float tmpWall[][] = new float[nbOfRows][nbOfCols];
for(int i = 0; i < nbOfRows; i++)
for(int j = 0; j < nbOfCols; j++)
tmpWall[i][j] = wall[i][j];
return tmpWall;
}
}

Related

Method to find if a snake in a snake game has made a loop

I am relatively new to java, and I have an idea for a mechanic I want to implement in to my game. However, I have no idea how to go about solving this problem. My snake game works on a basic coordinate system. I want it to be so that when the snake makes a closed loop (a rectangle or square) the game will detect it has made a loop. I have tried writing a method to locate the part of the snake's body that is the most upper-left, and then checking from there, but it seems to not work very well. Here is the method I attempted to write, if It helps at all. Thank you for any help!!
public boolean checkRing()
{
int topLeftX = 5000;
int topLeftY = 5000;
for(int i = bodyParts;i>0;i--)
{
// Finds coordinates of top left box
if(x[i] < topLeftX)
{
topLeftX = x[i];
}
if(y[i] < topLeftY)
{
topLeftY = y[i];
}
}
// Use isBody() method below (not bug tested) to check for rectangle
boolean lineFoundVert = false;
int checkingX = topLeftX;
int checkingY = topLeftY;
int vertCounter = 1;
while(!lineFoundVert)
{
if(isBody(checkingX, checkingY))
{
vertCounter++;
checkingX++;
}
else
lineFoundVert = true;
}
boolean lineFoundHori = false;
checkingX = topLeftX;
checkingY = topLeftY;
int horiCounter = 1;
while(!lineFoundHori)
{
if(isBody(checkingX, checkingY))
{
horiCounter++;
checkingY++;
}
else
lineFoundHori = true;
}
debug1X = topLeftX + 1;
debug1Y = topLeftY + vertCounter;
debug2X = topLeftX + horiCounter;
debug2Y = topLeftY + 1;
if(isBody(topLeftX + 1, topLeftY + vertCounter) && isBody(topLeftX + horiCounter, topLeftY + 1))
{
return true;
}
return false;
}```
Here is an approximate solution:
private boolean isEdgeCoordinate(Coordinate[] bodyparts, int index) {
// for every bodypart check that its neighbours (bodypart one before and
// bodypart one after) dont share X axis and dont share Y axis. As long
// as that is the case it is an edge.
//additionally for the last bodypart you needto check that it has first
// bodypart as a neighbour and check them as neighbours otherwise no
// rectangle to begin with
}
using this method check the amount of edges in your bodyparts array. If the total number of edges == 4 you have got a square/rectangle

Generic Number Tweening (Help me do one strange trick..)

I am trying to make as generic as possible method for tweening between various types of values.
So, given a start and end value thats, say, either an Int,Float or Double as well as the number of steps (int), it will return values evenly distributed along those steps in the same type.
However, I am starting to suspect;
a) My knowledge of generics is terrible.
b) This might not be possible :(
So, just to be clear, one example;
SpiffyTween<Double> meep = new SpiffyTween<Double>(1d,10d, 100);
while (meep.hasNext()){
Log.info("value="+meep.next());
}
Would return 0.0,0.1,0.2..etc upto 9.9
But SpiffyTween could also work with other number types without needing separate code for each.
Heres the code I have right now;
class SpiffyTween<T extends Number> implements SpiffyGenericTween<T>
{
static Logger Log = Logger.getLogger("SpiffyTween <Number>");
private T start;
private T end;
int totalsteps=0;
int CurrentStep = 0;
ArrayList<T> steps = new ArrayList<T>();
public SpiffyTween(T start,T end, int steps) {
this.start = start;
this.end = end;
this.totalsteps = steps;
precalculate();
}
private void precalculate() {
//calc step difference
double dif = ((end.doubleValue() -start.doubleValue())/totalsteps);
Log.info("dif="+dif);
int i=0;
while(i<totalsteps){
T stepvalue = (T)((Number)(start.doubleValue() +(dif*i)));
steps.add(stepvalue);
Log.info("add step="+stepvalue);
i++;
}
}
public T next(){
T currentVal = steps.get(CurrentStep);
CurrentStep++;
return currentVal;
}
#Override
public boolean hasNext() {
if (CurrentStep<totalsteps){
return true;
}
return false;
}
}
This works...ish.
While the numbers come out aproximately right occasionally theres values like;
9.600000000000001
or
2.4000000000000004
I am assuming thats to do with the unchecked type conversion here;
T stepvalue = (T)((Number)(start.doubleValue() +(dif*i)));
But I cant work out how to do it better.
Whatever the solution (if theres one), my longterm plan is to try to make similar code that can also work on arrays of various number types. So, you could tween between 3 dimensional points by feeding it an array of the x/y/z co-ordinates of the start and end.
Also, possibly more relevantly, in the code example here its basic addition being done. I probably want other types of tweening possible, so that would make the maths more complex.
Is the better route to convert to, say, BigNumber, and then (somehow) back to the initial T later after all the processing is done?
Thanks in advance for any help or pointers.
YOu don't really need Generics to write code once. Consider the code below. Your exercise is to extend to other dimensions and to ensure caller does not use less than one step:
Tween Class
package com.example.stepup;
public class Tween {
public static int[] get1DimSteps (int start, int end, int steps) {
double[] preciseResult = get1DimSteps((double) start, (double) end, steps);
int[] result = new int[steps];
for (int i=0; i<steps; i++) {
result[i] = (int) (preciseResult[i] + 0.5D);
}
return result;
}
public static double[] get1DimSteps (float start, float end, int steps) {
double[] result = get1DimSteps((double)start, (double)end, steps);
return result;
}
public static double[] get1DimSteps (double start, double end, int steps) {
double distance;
double stepSize;
double[] result = new double[steps];
distance = end - start;
stepSize = distance / steps;
for (int i=0; i < steps; i++) {
result[i] = start + stepSize*i;
}
return result;
}
}
StepupTest Class
package com.example.stepup;
public class StepupTest {
public static void main(String[] args) {
// get steps from "start" to "finish"
int startI = -1;
int endI =999;
float start = (float) startI;
float end = (float) endI;
double startD = (double) startI;
double endD = (double) endI;
int numberOfSteps = 100;
double[] steps = Tween.get1DimSteps( start, end, numberOfSteps);
double[] stepsD = Tween.get1DimSteps(startD, endD, numberOfSteps);
int[] stepsI = Tween.get1DimSteps(startI, endI, numberOfSteps);
for (int i=0; i < numberOfSteps; i++) {
System.out.println(" " + i + ". " + steps[i] + ", " + stepsD[i] + ", " + stepsI[i]);
}
}
}

printing the turns of a recursive maze solution in Java

So I've been working on the following problem:
I buried my sapphire then started walking. I always walked in a
straight line following a compass direction (N, S, E, W). When I
stopped, I made a 90 degree turn and continued walking. I might have
crossed my path, but I don’t remember. Below are the number of meters
I travelled in each direction. I’m now lost and must abandon this
record while I search for a way out. I’m placing this note under a
rock at my final location. Perhaps some lucky adventurer will decode
my note and retrace my steps to earn the treasure. Unfortunately,
there is no record of where in the ruins the note was found. Instead,
you must write a program to find the treasure. Input The first
line contains two integers X Y, representing the number of rows and
columns in the ruins. Maximum of 20 rows and 50 columns. The next X
lines show a grid map of the space. A period “.” is an empty square. A
hash “#” is a large boulder, marking a square that cannot be entered.
The next line has an integer N, the count of the straight paths
walked. Maximum of 20 paths. The last line contains N integers
separated by spaces, showing the successive path-lengths.. 5 10
####
........#
.#...##.#
...#....#
#### 8 2 4 2 2 2 5 2 1 Output Your program must print the same map, with the location of both the Sapphire (S) and the final
location of the message (F) marked. Also, label every turning point
with successive lowercase letters (if the same point is used more
than once, print the letter for the later turn.) There is only one
route which follows the path-lengths in the list.
####
b.e.a..f#
.#...##.#
c.d#S.Fg#
#
and I have made a recursive method that checks every direction starting from every open position of the maze until it finds the solution, however the output of the problem needs to be the mazes with the turns.
The problem is, when I use a recursive solution and edit the actual char[][] map, it never knows which path will lead to the actual finish, so it will create output like this:
d...d
.....
cbabc
d...d
but instead I would like it to show only one path, like this:
....d
.....
..abc
.....
Here is my incomplete solution:
import java.util.Scanner;
public class SapphireSearch {
private static int rs; // Row Size
private static int cs; // Column Size
private static int sr; // Save row (saves solution row)
private static int sc; // Save col (saves solution col)
private static Direction sd; // Save direction (saves solution dir)
private static char[][] map; // the maze to traverse
private static int n; // number of turns
private static int[] go; // length of the turns
public static void main(String[] args) {
getInput();
for (int r = 0; r < rs; r++)
for (int c = 0; c < cs; c++)
for (Direction d : Direction.values())
solve(sr = r, sc = c, sd = d, 0, false);
}
public static void solve(int r, int c, Direction d, int start,
boolean printing) {
if (isSolid(r, c))
return;
if (printing) {
if (start == 0)
map[r][c] = 'S';
else
map[r][c] = (char) (start - 1 + 'a');
if (start == n) {
map[r][c] = 'F';
return;
}
}
if (start == n - 1 && !printing) {
solve(sr, sc, sd, 0, true);
printArray(map);
System.exit(0);
}
int count = 0;
while (start < go.length && count < go[start]) {
count++;
r += d.dr;
c += d.dc;
if (isSolid(r, c))
return;
}
for (Direction t : d.turn())
solve(r, c, t, start + 1, printing);
}
public static boolean isSolid(int r, int c) {
return map[r][c] == '#';
}
public static void printArray(char[][] o) {
for (int r = 0; r < o.length; r++) {
for (int c = 0; c < o[r].length; c++)
System.out.print(o[r][c]);
System.out.println();
}
}
private static void getInput() {
Scanner s = new Scanner(System.in);
rs = s.nextInt();
cs = s.nextInt();
s.nextLine(); // clear buffer
map = new char[rs][cs];
for (int r = 0; r < rs; r++) {
int c = 0;
char[] f = s.nextLine().trim().toCharArray();
for (char t : f)
map[r][c++] = t;
}
n = s.nextInt();
go = new int[n];
for (int i = 0; i < n; i++)
go[i] = s.nextInt();
}
}
enum Direction {
// deltaR, deltaC
up(-1, 0), down(1, 0), left(0, -1), right(0, 1);
public int dr;
public int dc;
private Direction(int dr, int dc) {
this.dr = dr;
this.dc = dc;
}
public Direction[] turn() {
Direction[] out = new Direction[2];
switch (this) {
case up:
case down:
out[0] = left;
out[1] = right;
break;
case left:
case right:
out[0] = up;
out[1] = down;
}
return out;
}
}
The question is: building upon my recursive solve algorithm, what would be the best way to print the solution path (where it doesn't print out every path it tries to take)?
You need to build up your list of turns as you do the recursive search (I'm just listing the direction here for simplicity but you could store an object with co-ordinates as well for example).
If the path is (N,E,N,W,S) and then save that as you exit.
To do that keep the partial list so far and each recursive call COPY the list so far and add to it.
i.e.:
n
ne
nw Fail
nen
nes Fail
nenw
etc.
At the end you can either return the completed solution or if you need to handle multiple solutions have a final results list of lists that you insert the completed one into.
The key step is to copy the list so far so that recursion branches cannot interfere with each other.

Java comb sort caught in an infinite loop

I'm doing a combsort algorithim as a class assignment, and it loops whenever I run it. I'm not sure what I did wrong (I got it working in C++, but that was a while ago, and those skills don't translate as well as I'd like them to). I've been poring over it for an hour and a half now, and emailed some friends, but nobody has any ideas, unfortunately. I think I just need someone with some more experience to tell me what I screwed up. Thanks!
import java.util.ArrayList;
public class CombSort {
public CombSort()
{
super();
}
public ArrayList<Integer> combSort(ArrayList<Integer> sortMe)
{
int swap;
int size = sortMe.size();
int gap = size;
boolean swapped = false;
while ((gap > 1) || swapped)
{
if (gap > 1)
{
gap = (int) ((size)*((double)gap / 1.247330950103979));
}
swapped = false;
for (int i = 0; gap + i < size; ++i)
{
if (sortMe.get(i) - sortMe.get(i + gap) > 0)
{
swap = sortMe.get(i);
sortMe.set(i, sortMe.get(i + gap));
sortMe.set(i + gap, swap);
swapped = true;
}
}
}
return sortMe;
}
public static void main(String[] args)
{
ArrayList<Integer> randomArrayList = new ArrayList<Integer>(7);
randomArrayList.add(5);
randomArrayList.add(7);
randomArrayList.add(2);
randomArrayList.add(6);
randomArrayList.add(8);
randomArrayList.add(2);
randomArrayList.add(9);
CombSort combSorter = new CombSort();
System.out.println(combSorter.combSort(randomArrayList).toString());
}
}
Your gap value is getting bigger with each iteration inside the while loop, hence why it is infinitely looping.
You should only multiply the gap by the comb factor, not by the size.
(int) ((size)*((double)gap / 1.247330950103979)); should be
(int) ((double)gap / 1.247330950103979);

how to speed up this code? calculus iterating through rows and cols of a matrix

I have a piece of code which performs calculations on a matrix by iterating through its rows and columns. The piece of calculus performed is a cosine distance measure, with a code I found on Internet (could not retrieve the link right now).
There can be 10,000 rows and col. The matrix is symmetric so I just need to iterate half of it. Values are float.
The problem: it is very slow (will take 3 to 6 hours it seems). Can anyone point me to improvements? Thx!
Note on the code: it uses an abstract class for flexibility: this way, the cosine calculation defined in a separate class could be easily replaced by another one.
The code:
import Jama.Matrix;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.ExecutionException;
public abstract class AbstractSimilarity {
HashSet<Triple<Double, Integer, Integer>> set = new HashSet();
public ArrayList<Thread> listThreads = new ArrayList();
public void transform(Matrix matrixToBeTransformed) throws InterruptedException,
ExecutionException {
int numDocs = termDocumentMatrix.getColumnDimension();
Main.similarityMatrix = new Matrix(numDocs, numDocs);
System.out.println("size of the matrix: " + numDocs + "x " + numDocs);
//1. iteration through all rows of the matrixToBeTransformed
for (int i = numDocs - 1; i >0 ; i--) {
System.out.println("matrix treatment... " + ((float) i / (float) numDocs * 100) + "%");
//2. isolates the row i of this matrixToBeTransformed
Matrix sourceDocMatrix = matrixToBeTransformed.getMatrix(
0, matrixToBeTransformed.getRowDimension() - 1, i, i);
// 3. Iterates through all columns of the matrixToBeTransformed
// for (int j = 0; j < numDocs; j++) {
// if (j < i) {
//
// //4. isolates the column j of this matrixToBeTransformed
// Matrix targetDocMatrix = matrixToBeTransformed.getMatrix(
// 0, matrixToBeTransformed.getRowDimension() - 1, j, j);
//5. computes the similarity between this given row and this given column and writes it in a resultMatrix
// Main.resultMatrix.set(i, j, computeSimilarity(sourceDocMatrix, targetDocMatrix));
// } else {
// Main.resultMatrix.set(i, j, 0);
// }
//
// }
}
The class which defines the computation to be done:
import Jama.Matrix;
public class CosineSimilarity extends AbstractSimilarity{
#Override
protected double computeSimilarity(Matrix sourceDoc, Matrix targetDoc) {
double dotProduct = sourceDoc.arrayTimes(targetDoc).norm1();
double eucledianDist = sourceDoc.normF() * targetDoc.normF();
return dotProduct / eucledianDist;
}
}
You appear to be dealing with a n^3 algorithm. n^2 because you're filling a (half) matrix. Times n again because the methods to fill each element(dot product/fnorm) take time n. The good news is that because the calculations don't depend on each other, you could multithread this to speed it up.
public class DoCalc extends Thread
{
public Matrix localM;
int startRow;
int endRow;
public DoCalc(Matrix mArg, int startArg, int endArg)
{
localM=mArg;
startRow=startArg;
endRow=endArg;
}
public void doCalc()
{
//Pseudo-code
for each row from startRow to endRow
for each column 0 to size-1
result[i][j] = similarityCalculation
}
public void run()
{
doCalc();
}
}
public void transform(Matrix toBeTransformed)
{
int numDocs = termDocumentMatrix.getColumnDimension();
Main.similarityMatrix = new Matrix(numDocs, numDocs);
Vector<DoCalc> running = new Vector<DoCalc>();
int blockSize = 10;
for (int x = 0; x < numDocs-1;x+=blockSize)
{
DoCalc tempThread = new DoCalc(toBeTransformed,x,(x+blockSize>numDocs-1)?numDocs-1:x+blockSize);
tempThread.start();
running.add(tempThread);
}
for (DoCalc dc : running)
dc.join();
}
Important notes:
This is a very naive implementation. If you try to run it with arrays of your size, it will spawn 1000 threads. You can either fiddle with the blockSize or look into thread pooling.
At best this will give you a multiple times increase in speed, 4x etc. If you want order of magnitude gains, you will need to properly profile and/or change your algorithm to something more efficient. Given the task you're trying to perform(running a relatively expensive task on each element in a Matrix), the latter may not be possible.
Edit: Multithreading will only increase speed significantly if you are cpu bound and have a multicore cpu with cores sitting relatively idle.

Categories

Resources