I have an algorithm that should be able to tell a repeat in an audio. I used sliding window to implement this. The issue with this algorithm that I'm having is it works perfectly when I create a Sin_tone, but when I take a wav file and I concatenate it with itself, it will never recognize that second half. for some reason, the second half has different sample numbers than the first half.
The main question is why would concatenating a wave file of the exact same audio cuz the samples to be different at those two points (I concatenated using Adobe audition and Adobe audacity
I can get a double[] array of all the samples, but should I run a DFT on the sections of the sample and then compare them?
This takes a beat that I concatenated so I knew for sure there was an exact repeat, and it still fails, but when I use a sin tone I created then it can find the loop successfully
package Waves;
public class FindAudioAttempt2 {
public static void main(String[] args)
{
WavFile wavFile;
double[] buffer;
try
{
// Open the wav file specified as the first argument
wavFile = WavFile.openWavFile(new File("beat_on_repeat2.wav"));
// Display information about the wav file
wavFile.display();
// Find a matching loop that is 0.2 seconds
int numFramesinCut = (int) (0.2* wavFile.getSampleRate());
System.out.println("num frames in cut: " +numFramesinCut);
long numFrames = wavFile.getNumFrames();
// Create a buffer of half the frames
int framesRead;
// buffer size is 2 * the number of frames since it is stereo
buffer = new double[(int) (numFrames)*2];
framesRead = wavFile.readFrames(buffer, (int)numFrames);
System.out.println("Buffer Length: " +buffer.length);
HashMap<Double, ArrayList<Integer>> savedPoints = new HashMap<>();
// Read frames into buffer
int endPointer = buffer.length-1;
int beginPointer = 0;
boolean dictComplete = false;
boolean found = false;
for(int i=buffer.length-1-numFramesinCut; i>buffer.length/2; i--){
if(dictComplete){
if(!savedPoints.containsKey(buffer[i])){
continue;
}
ArrayList<Integer> pointers = savedPoints.get(buffer[i]);
for (int p:pointers) {
found = checkLoops(buffer,i,p, numFramesinCut);
if(found){
beginPointer = p;
endPointer = i;
break;
}
}
if(found){
break;
}
} else {
for (int j = 0; j < buffer.length/2; j++) {
handleDict(savedPoints,buffer[j],j);
if(buffer[i] == buffer[i]){
found = checkLoops(savedPoints,buffer, i,j,numFramesinCut);
}
if(found){
beginPointer = j;
endPointer = i;
break;
}
if(j == buffer.length/2 -1){
dictComplete = true;
}
}
}
if(found){
break;
}
}
int sampleRate = (int)wavFile.getSampleRate();
WavFile wavFile2 = WavFile.newWavFile(new File("beatLooping.wav"), 2, numFrames/2, 16, sampleRate);
double[] bufferFinal = new double[endPointer-beginPointer];
System.out.println("Final Buffer Length: " +bufferFinal.length);
System.arraycopy(buffer, buffer.length/2 -1, bufferFinal, 0, buffer.length/2);
wavFile2.writeFrames(bufferFinal, (endPointer-beginPointer)/2);
// Close the wavFile
wavFile.close();
wavFile2.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
static private boolean checkLoops(HashMap<Double, ArrayList<Integer>> savedPoints, double[] buffer, int i, int j, int framesinCut){
int frameCount =1;
while(frameCount < framesinCut && i<buffer.length && j<buffer.length/2){
handleDict(savedPoints, buffer[j], j);
if(buffer[i] != buffer[j]){
return false;
}
i = i+2;
j = j+2;
frameCount++;
}
if(frameCount == framesinCut){
return true;
} else {
return false;
}
}
static private boolean checkLoops( double[] buffer, int i, int j, int framesinCut){
int frameCount =1;
while(frameCount < framesinCut && i<buffer.length && j<buffer.length/2){
if(buffer[i] != buffer[j]){
return false;
}
i = i+1;
j = j+1;
frameCount++;
}
if(frameCount == framesinCut){
return true;
} else {
return false;
}
}
static public void handleDict(HashMap<Double, ArrayList<Integer>> dict, Double key, int pointer){
if(dict.containsKey(key)){
dict.get(key).add(pointer);
} else {
dict.put(key,new ArrayList<Integer>(){{add(pointer);}});
}
}
}
Related
I am making an android Hashikawekero puzzle game, I have implemented a algorithm to spawn nodes (Islands) at random positions using a 2-d array this works fine it creates the node at random position but most of the times the map cant be solved. The map nodes spawn at random.
BoardCreation.java Class - this generates the map.
package Island_and_Bridges.Hashi;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.Log;
import java.util.Random;
import static junit.framework.Assert.*;
//This class Creates the map by random using a 2d array
public class BoardCreation {
// This class member is used for random initialization purposes.
static private final Random random = new Random();
// The difficulty levels.
private static final int EASY = 0;
static public final int MEDIUM = 1;
static public final int HARD = 2;
static public final int EMPTY = 0;
private static int ConnectionFingerprint(BoardElement start, BoardElement end) {
int x = start.row * 100 + start.col;
int y = end.row * 100 + end.col;
// Swap to get always the same fingerprint independent whether we are called
// start-end or end-start
if (x > y ) {
int temp = x;
x = y;
y = temp;
}
Log.d("", String.format("%d %d" , x ,y));
return x ^ y;
}
public class State {
// The elements of the board are stored in this array.
// A value defined by "EMPTY" means that its not set yet.
public BoardElement [][] board_elements = null;
public int [][] cell_occupied = null;
// The width of the board. We only assume squared boards.
public int board_width=0;
public State(int width) {
board_width = width;
board_elements = new BoardElement[width][width];
cell_occupied = new int[width][width];
}
public State CloneWithoutConnections() {
State newstate = new State(board_width);
if (board_elements != null) {
newstate.board_elements = new BoardElement[board_elements.length][board_elements.length];
for (int i = 0; i < board_elements.length; ++i) {
for (int j = 0; j < board_elements.length; ++j) {
if (board_elements[i][j] == null)
continue;
newstate.board_elements[i][j] = board_elements[i][j].clone();
}
}
}
if (cell_occupied != null) {
assert board_elements != null;
newstate.cell_occupied = new int[board_elements.length][board_elements.length];
for (int i = 0; i < board_elements.length; ++i) {
System.arraycopy(cell_occupied[i], 0, newstate.cell_occupied[i], 0, board_elements.length);
}
}
return newstate;
}
public void AddToBridgeCache(BoardElement first, BoardElement second) {
if (first == null || second == null) { return; }
final int fingerprint = ConnectionFingerprint(first, second);
Log.d(getClass().getName(),
String.format("Fingerprint of this bridge %d", fingerprint));
// mark the end points as occupied.
cell_occupied[first.row][first.col] = fingerprint;
cell_occupied[second.row][second.col] = fingerprint;
int dcol = second.col - first.col;
int drow = second.row - first.row;
if (first.row == second.row) {
for (int i = (int) (first.col + Math.signum(dcol)); i != second.col; i += Math.signum(dcol)) {
cell_occupied[first.row][i] = fingerprint;
String.format("deleting bridge");
}
} else {
assert first.col == second.col;
for (int i = (int) (first.row + Math.signum(drow)); i != second.row; i+= Math.signum(drow)) {
cell_occupied[i][first.col] = fingerprint;
}
}
}
} // end of state
private State current_state, old_state;
static private final int WIDTH_EASY = 7;
private void NewGame(int hardness) {
switch(hardness) {
case EASY:
Log.d(getClass().getName(), "Initializing new easy game");
InitializeEasy();
old_state = getCurrentState().CloneWithoutConnections();
break;
}
}
public void ResetGame() {
if (old_state != null) {
Log.d(getClass().getName(), "Setting board_elements to old_elements");
setCurrentState(old_state.CloneWithoutConnections());
} else {
Log.d(getClass().getName(), "old_lements are zero");
}
}
public BoardCreation(int hardness) {
NewGame(hardness);
}
public boolean TryAddNewBridge(BoardElement start, BoardElement end, int count) {
assertEquals(count, 1);
assert (start != null);
assert (end != null);
final int fingerprint = ConnectionFingerprint(start, end);
Log.d(getClass().getName(),
String.format("considering (%d,%d) and (%d,%d)", start.row,start.col, end.row,end.col));
if (start.row == end.row && start.col == end.col) {
Log.d(getClass().getName(), "Same nodes selected!");
return false;
}
assert count > 0;
int dcol = end.col - start.col;
int drow = end.row - start.row;
// It must be a vertical or horizontal bridge:
if (Math.abs(dcol) > 0 && Math.abs(drow) > 0) {
Log.d(getClass().getName(), "not a horizontal or vertical bridge.");
return false;
}
// First we check whether start and end elements can take the specified bridge counts.
int count_start = start.GetCurrentCount();
int count_end = end.GetCurrentCount();
if (count_start + count > start.max_connecting_bridges ||
count_end + count > end.max_connecting_bridges) {
Log.d(getClass().getName(), "This Bridge is not allowed");
return false;
}
Log.d(getClass().getName(),
String.format("Sums:%d # (%d,%d) and %d # (%d,%d)",
count_start, start.row, start.col,
count_end, end.row, end.col));
Connection start_connection = null;
Connection end_connection = null;
// Next we check whether we are crossing any lines.
if (start.row == end.row) {
for (int i = (int) (start.col + Math.signum(dcol)); i != end.col; i += Math.signum(dcol)) {
if (getCurrentState().cell_occupied[start.row][i] > 0 &&
getCurrentState().cell_occupied[start.row][i] != fingerprint) {
Log.d(getClass().getName(), "Crossing an occupied cell.");
return false;
}
}
assert start.col != end.col;
if (start.col > end.col) {
start.connecting_east = GetOrCreateConnection(end, start.connecting_east);
end.connecting_west = GetOrCreateConnection(start, end.connecting_west);
start_connection = start.connecting_east;
end_connection = end.connecting_west;
} else {
start.connecting_west = GetOrCreateConnection(end, start.connecting_west);
end.connecting_east = GetOrCreateConnection(start, end.connecting_east);
start_connection = start.connecting_west;
end_connection = end.connecting_east;
}
} else {
assert start.col == end.col;
for (int i = (int) (start.row + Math.signum(drow)); i != end.row ; i += Math.signum(drow)) {
if (getCurrentState().cell_occupied[i][start.col] > 0 &&
getCurrentState().cell_occupied[i][start.col] != fingerprint) {
Log.d(getClass().getName(), "Crossing an occupied cell.");
return false;
}
}
if (start.row > end.row ) {
start.connecting_north = GetOrCreateConnection(end, start.connecting_north);
end.connecting_south = GetOrCreateConnection(start, end.connecting_south);
start_connection = start.connecting_north;
end_connection = end.connecting_south;
} else {
start.connecting_south= GetOrCreateConnection(end, start.connecting_south);
end.connecting_north = GetOrCreateConnection(start, end.connecting_north);
start_connection = start.connecting_south;
end_connection = end.connecting_north;
}
}
start_connection.destination = end;
end_connection.destination = start;
start_connection.second += count;
end_connection.second += count;
getCurrentState().AddToBridgeCache(start, end);
Log.d(getClass().getName(),
String.format("New bridge added. Sums:%d # (%d,%d) and %d # (%d,%d)",
count_start, start.row,start.col,
count_end, end.row,end.col));
return true;
}
private Connection GetOrCreateConnection(
BoardElement end,
Connection connection) {
if (connection!= null) { return connection; }
return new Connection();
}
#TargetApi(Build.VERSION_CODES.N)
private void InitializeEasy() {
Random rand = new Random();
String[][] debug_board_state = new String[7][7];
setCurrentState(new State(WIDTH_EASY));
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
debug_board_state[row][column] = String.valueOf(rand.nextInt(5));
}
}
for (int row = 0; row < debug_board_state.length; row++) {
for (int column = 0; column < debug_board_state[row].length; column++) {
System.out.print(debug_board_state[row][column] + " ");
}
System.out.println();
}
for (int row = 0; row < WIDTH_EASY; ++row) {
for (int column = 0; column < WIDTH_EASY; ++column) {
getCurrentState().board_elements[row][column] = new BoardElement();
getCurrentState().board_elements[row][column].max_connecting_bridges = Integer.parseInt(debug_board_state[row][column]);
getCurrentState().board_elements[row][column].row = row;
getCurrentState().board_elements[row][column].col = column;
if (getCurrentState().board_elements[row][column].max_connecting_bridges > 0) {
getCurrentState().board_elements[row][column].is_island = true;
}
}
}
}
private void setCurrentState(State new_state) {
this.current_state = new_state;
}
public State getCurrentState() {
return current_state;
}
}
What algorithm could I use to make sure the Map can be Solved (Islands Connected with Bridges) before spawning the nodes.
This is what the map looks like (don't mind the design)
One thing to consider would be to start with a blank board. Place an island. Then place another island that can be connected to the first one (i.e. on one of the four cardinal directions). Connect the two with a bridge, and increment each island's count.
Now, pick one of the two islands and place another island that it can connect. Add the bridge and increment.
Continue in this way until you've placed the number of islands that you want to place.
The beauty here is that you start with an empty board, and during construction the board is always valid.
You'll have to ensure that you're not crossing bridges when you place new islands, but that's pretty easy to do, since you know where the existing bridges are.
I am creating a program in Java to simulate evolution. The way I have it set up, each generation is composed of an array of Organism objects. Each of these arrays is an element in the ArrayList orgGenerations. Each generation, of which there could be any amount before all animals die, can have any amount of Organism objects.
For some reason, in my main loop when the generations are going by, I can have this code without errors, where allOrgs is the Organism array of the current generation and generationNumber is the number generations since the first.
orgGenerations.add(allOrgs);
printOrgs(orgGenerations.get(generationNumber));
printOrgs is a method to display an Organism array, where speed and strength are Organism Field variables:
public void printOrgs(Organism[] list)
{
for (int x=0; x<list.length; x++)
{
System.out.println ("For organism number: " + x + ", speed is: " + list[x].speed + ", and strength is " + list[x].strength + ".");
}
}
Later on, after this loop, when I am trying to retrieve the data to display, I call this very similar code:
printOrgs(orgGenerations.get(0));
This, and every other array in orgGenerations, return a null pointer exception on the print line of the for loop. Why are the Organism objects loosing their values?
Alright, here is all of the code from my main Simulation class. I admit, it might be sort of a mess. The parts that matter are the start and simulator methods. The battle ones are not really applicable to this problem. I think.
import java.awt.FlowLayout;
import java.util.*;
import javax.swing.JFrame;
public class Simulator {
//variables for general keeping track
static Organism[] allOrgs;
static ArrayList<Organism[]> orgGenerations = new ArrayList <Organism[]>();
ArrayList<Integer> battleList = new ArrayList<Integer>();
int deathCount;
boolean done;
boolean runOnce;
//setup
Simulator()
{
done = false;
Scanner asker = new Scanner(System.in);
System.out.println("Input number of organisms for the simulation: ");
int numOfOrgs = asker.nextInt();
asker.close();
Organism[] orgArray = new Organism[numOfOrgs];
for (int i=0; i<numOfOrgs; i++)
{
orgArray[i] = new Organism();
}
allOrgs = orgArray;
}
//graphsOrgs
public void graphOrgs() throws InterruptedException
{
JFrame f = new JFrame("Evolution");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000,500);
f.setVisible(true);
Drawer bars = new Drawer();
//System.out.println(orgGenerations.size());
for (int iterator=0;iterator<(orgGenerations.size()-1); iterator++)
{
printOrgs(orgGenerations.get(0));
//The 0 can be any number, no matter what I do it wont work
//System.out.println("first");
f.repaint();
bars.data = orgGenerations.get(iterator);
f.add(bars);
//System.out.println("before");
Thread.sleep(1000);
//System.out.println("end");
}
}
//prints all Orgs and their statistics
public void printOrgs(Organism[] list)
{
System.out.println("Number Of Organisms: " + list.length);
for (int x=0; x<list.length; x++)
{
System.out.println ("For organism number: " + x + ", speed is: " + list[x].speed + ", and strength is " + list[x].strength + ".");
}
System.out.println();
}
//general loop for the organisms lives
public void start(int reproductionTime) throws InterruptedException
{
int generationNumber = 0;
orgGenerations.add(allOrgs);
printOrgs(orgGenerations.get(0));
generationNumber++;
while(true)
{
deathCount = 0;
for(int j=0; j<reproductionTime; j++)
{
battleList.clear();
for(int m=0; m<allOrgs.length; m++)
{
if (allOrgs[m].alive == true)
oneYearBattleCheck(m);
}
battle();
}
reproduction();
if (done == true)
break;
orgGenerations.add(allOrgs);
printOrgs(orgGenerations.get(generationNumber));
generationNumber++;
}
printOrgs(orgGenerations.get(2));
}
//Checks if they have to fight this year
private void oneYearBattleCheck(int m)
{
Random chaos = new Random();
int speedMod = chaos.nextInt(((int)Math.ceil(allOrgs[m].speed/5.0))+1);
int speedSign = chaos.nextInt(2);
if (speedSign == 0)
speedSign--;
speedMod *= speedSign;
int speed = speedMod + allOrgs[m].speed;
if (speed <= 0)
speed=1;
Random encounter = new Random();
boolean battle = false;
int try1 =(encounter.nextInt(speed));
int try2 =(encounter.nextInt(speed));
int try3 =(encounter.nextInt(speed));
int try4 =(encounter.nextInt(speed));
if (try1 == 0 || try2 == 0 || try3 == 0 || try4 == 0 )
{
battle = true;
}
if(battle == true)
{
battleList.add(m);
}
}
//Creates the matches and runs the battle
private void battle()
{
Random rand = new Random();
if (battleList.size()%2 == 1)
{
int luckyDuck = rand.nextInt(battleList.size());
battleList.remove(luckyDuck);
}
for(int k=0; k<(battleList.size()-1);)
{
int competitor1 = rand.nextInt(battleList.size());
battleList.remove(competitor1);
int competitor2 = rand.nextInt(battleList.size());
battleList.remove(competitor2);
//Competitor 1 strength
int strengthMod = rand.nextInt(((int)Math.ceil(allOrgs[competitor1].strength/5.0))+1);
int strengthSign = rand.nextInt(2);
if (strengthSign == 0)
strengthSign--;
strengthMod *= strengthSign;
int comp1Strength = strengthMod + allOrgs[competitor1].strength;
//Competitor 2 strength
strengthMod = rand.nextInt(((int)Math.ceil(allOrgs[competitor2].strength/5.0))+1);
strengthSign = rand.nextInt(2);
if (strengthSign == 0)
strengthSign--;
strengthMod *= strengthSign;
int comp2Strength = strengthMod + allOrgs[competitor2].strength;
//Fight!
if (comp1Strength>comp2Strength)
{
allOrgs[competitor1].life ++;
allOrgs[competitor2].life --;
}
else if (comp2Strength>comp1Strength)
{
allOrgs[competitor2].life ++;
allOrgs[competitor1].life --;
}
if (allOrgs[competitor1].life == 0)
{
allOrgs[competitor1].alive = false;
deathCount++;
}
if (allOrgs[competitor2].life == 0)
{
allOrgs[competitor2].alive = false;
deathCount ++ ;
}
}
}
//New organisms
private void reproduction()
{
//System.out.println("Number of deaths: " + deathCount + "\n");
if (deathCount>=(allOrgs.length-2))
{
done = true;
return;
}
ArrayList<Organism> tempOrgs = new ArrayList<Organism>();
Random chooser = new Random();
int count = 0;
while(true)
{
int partner1 = 0;
int partner2 = 0;
boolean partnerIsAlive = false;
boolean unluckyDuck = false;
//choose partner1
while (partnerIsAlive == false)
{
partner1 = chooser.nextInt(allOrgs.length);
if (allOrgs[partner1] != null)
{
if (allOrgs[partner1].alive == true)
{
partnerIsAlive = true;
}
}
}
count++;
//System.out.println("Count 2: " + count);
partnerIsAlive = false;
//choose partner2
while (partnerIsAlive == false)
{
if (count+deathCount == (allOrgs.length))
{
unluckyDuck=true;
break;
}
partner2 = chooser.nextInt(allOrgs.length);
if (allOrgs[partner2] != null)
{
if (allOrgs[partner2].alive == true)
{
partnerIsAlive = true;
}
}
}
if (unluckyDuck == false)
count++;
//System.out.println("count 2: " + count);
if (unluckyDuck == false)
{
int numOfChildren = (chooser.nextInt(4)+1);
for (int d=0; d<numOfChildren; d++)
{
tempOrgs.add(new Organism(allOrgs[partner1].speed, allOrgs[partner2].speed, allOrgs[partner1].strength, allOrgs[partner2].strength ));
}
allOrgs[partner1] = null;
allOrgs[partner2] = null;
}
if (count+deathCount == (allOrgs.length))
{
Arrays.fill(allOrgs, null);
allOrgs = tempOrgs.toArray(new Organism[tempOrgs.size()-1]);
break;
}
//System.out.println(count);
}
}
}
Main method:
public class Runner {
public static void main(String[] args) throws InterruptedException {
Simulator sim = new Simulator();
int lifeSpan = 20;
sim.start(lifeSpan);
sim.graphOrgs();
}
}
Organism class:
import java.util.Random;
public class Organism {
static Random traitGenerator = new Random();
int life;
int speed;
int strength;
boolean alive;
Organism()
{
speed = (traitGenerator.nextInt(49)+1);
strength = (50-speed);
life = 5;
alive = true;
}
Organism(int strength1, int strength2, int speed1, int speed2)
{
Random gen = new Random();
int speedMod = gen.nextInt(((int)Math.ceil((speed1+speed2)/10.0))+1);
int speedSign = gen.nextInt(2);
if (speedSign == 0)
speedSign--;
speedMod *= speedSign;
//System.out.println(speedMod);
int strengthMod = gen.nextInt(((int)Math.ceil((strength1+strength2)/10.0))+1);
int strengthSign = gen.nextInt(2);
if (strengthSign == 0)
strengthSign--;
strengthMod *= strengthSign;
//System.out.println(strengthMod);
strength = (((int)((strength1+strength2)/2.0))+ strengthMod);
speed = (((int)((speed1+speed2)/2.0))+ speedMod);
alive = true;
life = 5;
}
}
The problem lies in the graphOrgs class when I try to print to check if it is working in preparation for graphing the results. This is when it returns the error. When I try placing the print code in other places in the Simulator class the same thing occurs, a null pointer error. This happens even if it is just after the for loop where the element has been established.
You have code that sets to null elements in your allOrgs array.
allOrgs[partner1] = null;
allOrgs[partner2] = null;
Your orgGenerations list contains the same allOrgs instance multiple times.
Therefore, when you write allOrgs[partner1] = null, the partner1'th element becomes null in all the list elements of orgGenerations, which is why the print method fails.
You should create a copy of the array (you can use Arrays.copy) each time you add a new generation to the list (and consider also creating copies of the Organism instances, if you want each generation to record the past state of the Organisms and not their final state).
I am using Comb Sort to sort out a given array of Strings. The code is :-
public static int combSort(String[] input_array) {
int gap = input_array.length;
double shrink = 1.3;
int numbOfComparisons = 0;
boolean swapped=true;
//while(!swapped && gap>1){
System.out.println();
while(!(swapped && gap==1)){
gap = (int)(gap/shrink);
if(gap<1){
gap=1;
}
int i = 0;
swapped = false;
String temp = "";
while((i+gap) < input_array.length){
numbOfComparisons++;
if(Compare(input_array[i], input_array[i+gap]) == 1){
temp = input_array[i];
input_array[i] = input_array[i+gap];
input_array[i+gap] = temp;
swapped = true;
System.out.println("gap: " + gap + " i: " + i);
ArrayUtilities.printArray(input_array);
}
i++;
}
}
ArrayUtilities.printArray(input_array);
return numbOfComparisons;
}
The problem is that while it sorts many arrays , it gets stuck in an infinite loop for some arrays, particularly small arrays. Compare(input_array[i], input_array[i+gap]) is a small method that returns 1 if s1>s2, returns -1 if s1
try this version. The string array is changed to integer array (I guess you can change it back to string version). The constant 1.3 is replaced with 1.247330950103979.
public class CombSort
{
private static final int PROBLEM_SIZE = 5;
static int[] in = new int[PROBLEM_SIZE];
public static void printArr()
{
for(int i=0;i<in.length;i++)
{
System.out.print(in[i] + "\t");
}
System.out.println();
}
public static void combSort()
{
int swap, i, gap=PROBLEM_SIZE;
boolean swapped = false;
printArr();
while ((gap > 1) || swapped)
{
if (gap > 1)
{
gap = (int)( gap / 1.247330950103979);
}
swapped = false;
for (i = 0; gap + i < PROBLEM_SIZE; ++i)
{
if (in[i] - in[i + gap] > 0)
{
swap = in[i];
in[i] = in[i + gap];
in[i + gap] = swap;
swapped = true;
}
}
}
printArr();
}
public static void main(String[] args)
{
for(int i=0;i<in.length;i++)
{
in[i] = (int) (Math.random()*PROBLEM_SIZE);
}
combSort();
}
}
Please find below implementation for comb sort in java.
public static void combSort(int[] elements) {
float shrinkFactor = 1.3f;
int postion = (int) (elements.length/shrinkFactor);
do {
int cursor = postion;
for(int i=0;cursor<elements.length;i++,cursor++) {
if(elements[i]>elements[cursor]) {
int temp = elements[cursor];
elements[cursor] = elements[i];
elements[i] = temp;
}
}
postion = (int) (postion/shrinkFactor);
}while(postion>=1);
}
Please review and let me know your's feedback.
I've been working on getting this program to work. I'm having a little trouble getting the program to read the files I have created, census2000 and census2010. These contain the 50 states and their population in 2000 and 2010. I believe that the rest of my program is correct. I was told to use methods to find the smallest population, largest population and the average. Here is two lines from the 2000 file:
Alabama 4447100
Alaska 626932
Here is my program:
public static void main(String[] args) throws IOException {
String state = "";
int population = 0;
int p = 0, s = 0, pop = 0, stat = 0, populate = 0, sum = 0;
File f = new File("census2000.txt");
Scanner infile = new Scanner(f);
infile.useDelimiter("[\t|,|\n|\r]+");
while (infile.hasNext()) {
checksmall(p, s);
checklargest(pop, stat);
checkAverage(populate, sum);
population = infile.nextInt();
state = infile.next("/t");
System.out.println(state + "has" + population + "people");
}
System.out.println(state + "has smallest population of" + population);
prw.close();
}
public static boolean checksmall(int p, int s) {
boolean returnValue;
if (p < s) {
returnValue = true;
} else {
returnValue = false;
}
return (returnValue);
}
public static boolean checklargest(int pop, int stat) {
boolean returnVal;
if (pop > stat) {
returnVal = true;
} else {
returnVal = false;
}
return (returnVal);
}
public static int checkAverage(int populate, int sum) {
int retVal;
retVal = populate + sum;
return (retVal);
}
}
What am I doing wrong?
I believe the problem is here:
state = infile.next("/t");
I think what you're trying to do is skip a tab in the file and read the state? You could do that by reading in the line and then splitting the line using \t as the delimiter.
String line;
while (infile.hasNextLine()){
line = infile.nextLine();
String data[] = line.split("\\s+");
state = data[0];
population = Integer.parseInt(data[1]);
}
edit: also as the other answer points out, you're attempting to perform functions on the file's data before it's read.
You need to be calling checksmall, checklargest and checkAverage after/while the file is loaded.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
Is there a way that I can optimize this code as to not run out of memory?
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.Stack;
public class TilePuzzle {
private final static byte ROWS = 4;
private final static byte COLUMNS = 4;
private static String SOLUTION = "123456789ABCDEF0";
private static byte RADIX = 16;
private char[][] board = new char[ROWS][COLUMNS];
private byte x; // Row of the space ('0')
private byte y; // Column of the space ('0') private String representation;
private boolean change = false; // Has the board changed after the last call to toString?
private TilePuzzle() {
this(SOLUTION);
int times = 1000;
Random rnd = new Random();
while(times-- > 0) {
try {
move((byte)rnd.nextInt(4));
}
catch(RuntimeException e) {
}
}
this.representation = asString();
}
public TilePuzzle(String representation) {
this.representation = representation;
final byte SIZE = (byte)SOLUTION.length();
if (representation.length() != SIZE) {
throw new IllegalArgumentException("The board must have " + SIZE + "numbers.");
}
boolean[] used = new boolean[SIZE];
byte idx = 0;
for (byte i = 0; i < ROWS; ++i) {
for (byte j = 0; j < COLUMNS; ++j) {
char digit = representation.charAt(idx++);
byte number = (byte)Character.digit(digit, RADIX);
if (number < 0 || number >= SIZE) {
throw new IllegalArgumentException("The character " + digit + " is not valid.");
} else if(used[number]) {
throw new IllegalArgumentException("The character " + digit + " is repeated.");
}
used[number] = true;
board[i][j] = digit;
if (digit == '0') {
x = i;
y = j;
}
}
}
}
/**
* Swap position of the space ('0') with the number that's up to it.
*/
public void moveUp() {
try {
move((byte)(x - 1), y);
} catch(IllegalArgumentException e) {
throw new RuntimeException("Move prohibited " + e.getMessage());
}
}
/**
* Swap position of the space ('0') with the number that's down to it.
*/
public void moveDown() {
try {
move((byte)(x + 1), y);
} catch(IllegalArgumentException e) {
throw new RuntimeException("Move prohibited " + e.getMessage());
}
}
/**
* Swap position of the space ('0') with the number that's left to it.
*/
public void moveLeft() {
try {
move(x, (byte)(y - 1));
} catch(IllegalArgumentException e) {
throw new RuntimeException("Move prohibited " + e.getMessage());
}
}
/**
* Swap position of the space ('0') with the number that's right to it.
*/
public void moveRight() {
try {
move(x, (byte)(y + 1));
} catch(IllegalArgumentException e) {
throw new RuntimeException("Move prohibited " + e.getMessage());
}
}
private void move(byte movement) {
switch(movement) {
case 0: moveUp(); break;
case 1: moveRight(); break;
case 2: moveDown(); break;
case 3: moveLeft(); break;
}
}
private boolean areValidCoordinates(byte x, byte y) {
return (x >= 0 && x < ROWS && y >= 0 && y < COLUMNS);
}
private void move(byte nx, byte ny) {
if (!areValidCoordinates(nx, ny)) {
throw new IllegalArgumentException("(" + nx + ", " + ny + ")");
}
board[x][y] = board[nx][ny];
board[nx][ny] = '0';
x = nx;
y = ny;
change = true;
}
public String printableString() {
StringBuilder sb = new StringBuilder();
for (byte i = 0; i < ROWS; ++i) {
for (byte j = 0; j < COLUMNS; ++j) {
sb.append(board[i][j] + " ");
}
sb.append("\r\n");
}
return sb.toString();
}
private String asString() {
StringBuilder sb = new StringBuilder();
for (byte i = 0; i < ROWS; ++i) {
for (byte j = 0; j < COLUMNS; ++j) {
sb.append(board[i][j]);
}
}
return sb.toString();
}
public String toString() {
if (change) {
representation = asString();
}
return representation;
}
private static byte[] whereShouldItBe(char digit) {
byte idx = (byte)SOLUTION.indexOf(digit);
return new byte[] { (byte)(idx / ROWS), (byte)(idx % ROWS) };
}
private static byte manhattanDistance(byte x, byte y, byte x2, byte y2) {
byte dx = (byte)Math.abs(x - x2);
byte dy = (byte)Math.abs(y - y2);
return (byte)(dx + dy);
}
private byte heuristic() {
byte total = 0;
for (byte i = 0; i < ROWS; ++i) {
for (byte j = 0; j < COLUMNS; ++j) {
char digit = board[i][j];
byte[] coordenates = whereShouldItBe(digit);
byte distance = manhattanDistance(i, j, coordenates[0], coordenates[1]);
total += distance;
}
}
return total;
}
private class Node implements Comparable<Node> {
private String puzzle;
private byte moves; // Number of moves from original configuration
private byte value; // The value of the heuristic for this configuration.
public Node(String puzzle, byte moves, byte value) {
this.puzzle = puzzle;
this.moves = moves;
this.value = value;
}
#Override
public int compareTo(Node o) {
return (value + moves) - (o.value + o.moves);
}
}
private void print(Map<String, String> antecessor) {
Stack toPrint = new Stack();
toPrint.add(SOLUTION);
String before = antecessor.get(SOLUTION);
while (!before.equals("")) {
toPrint.add(before);
before = antecessor.get(before);
}
while (!toPrint.isEmpty()) {
System.out.println(new TilePuzzle(toPrint.pop()).printableString());
}
}
private byte solve() {
if(toString().equals(SOLUTION)) {
return 0;
}
PriorityQueue<Node> toProcess = new PriorityQueue();
Node initial = new Node(toString(), (byte)0, heuristic());
toProcess.add(initial);
Map<String, String> antecessor = new HashMap<String, String>();
antecessor.put(toString(), "");
while(!toProcess.isEmpty()) {
Node actual = toProcess.poll();
for (byte i = 0; i < 4; ++i) {
TilePuzzle t = new TilePuzzle(actual.puzzle);
try {
t.move(i);
} catch(RuntimeException e) {
continue;
}
if (t.toString().equals(SOLUTION)) {
antecessor.put(SOLUTION, actual.puzzle);
print(antecessor);
return (byte)(actual.moves + 1);
} else if (!antecessor.containsKey(t.toString())) {
byte v = t.heuristic();
Node neighbor = new Node(t.toString(), (byte)(actual.moves + 1), v);
toProcess.add(neighbor);
antecessor.put(t.toString(), actual.puzzle);
}
}
}
return -1;
}
public static void main(String... args) {
TilePuzzle puzzle = new TilePuzzle();
System.out.println(puzzle.solve());
}
}
The problem
The root cause is the tons of String objects you are creating and storing in the toProcess Queue and the antecessor Map. Why are you doing that?
Look at your algorithm. See if you really need to store >2 million nodes and 5 million strings in each.
The investigation
This was hard to spot because the program is complex. Actually, I didn't even try to understand all of the code. Instead, I used VisualVM – a Java profiler, sampler, and CPU/memory usage monitor.
I launched it:
And took a look at the memory usage. The first thing I noticed was the (obvious) fact that you're creating tons of objects.
This is an screenshot of the app:
As you can see, the amount of memory used is tremendous. In as few as 40 seconds, 2 GB were consumed and the entire heap was filled.
A dead end
I initially thought the problem had something to do with the Node class, because even though it implements Comparable, it doesn't implement equals. So I provided the method:
public boolean equals( Object o ) {
if( o instanceof Node ) {
Node other = ( Node ) o;
return this.value == other.value && this.moves == other.moves;
}
return false;
}
But that was not the problem.
The actual problem turned out to be the one stated at the top.
The workaround
As previously stated, the real solution is to rethink your algorithm. Whatever else can be done, in the meantime, will only delay the problem.
But workarounds can be useful. One is to reuse the strings you're generating. You're very intensively using the TilePuzzle.toString() method; this ends up creating duplicate strings quite often.
Since you're generating string permutations, you may create many 12345ABCD strings in matter of seconds. If they are the same string, there is no point in creating millions of instances with the same value.
The String.intern() method allows strings to be reused. The doc says:
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals() method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
For a regular application, using String.intern() could be a bad idea because it doesn't let instances be reclaimed by the GC. But in this case, since you're holding the references in your Map and Queue anyway, it makes sense.
So making this change:
public String toString() {
if (change) {
representation = asString();
}
return representation.intern(); // <-- Use intern
}
Pretty much solves the memory problem.
This is a screenshot after the change:
Now, the heap usage doesn't reach 100 MB even after a couple of minutes.
Extra remarks
Remark #1
You're using an exception to validate if the movement is valid or not, which is okay; but when you catch them, you're just ignoring them:
try {
t.move(i);
} catch(RuntimeException e) {
continue;
}
If you're not using them anyway, you can save a lot of computation by not creating the exceptions in the first place. Otherwise you're creating millions of unused exceptions.
Make this change:
if (!areValidCoordinates(nx, ny)) {
// REMOVE THIS LINE:
// throw new IllegalArgumentException("(" + nx + ", " + ny + ")");
// ADD THIS LINE:
return;
}
And use validation instead:
// REMOVE THESE LINES:
// try {
// t.move(i);
// } catch(RuntimeException e) {
// continue;
// }
// ADD THESE LINES:
if(t.isValidMovement(i)){
t.move(i);
} else {
continue;
}
Remark #2
You're creating a new Random object for every new TilePuzzle instance. It would be better if you used just one for the whole program. After all, you are only using a single thread.
Remark #3
The workaround solved the heap memory problem, but created another one involving PermGen. I simply increased the PermGen size, like this:
java -Xmx1g -Xms1g -XX:MaxPermSize=1g TilePuzzle
Remark #4
The output was sometimes 49 and sometimes 50. The matrices were printed like:
1 2 3 4
5 6 7 8
9 A B C
D E 0 F
1 2 3 4
5 6 7 8
9 A B C
D E F 0
... 50 times