Breadth-first traversal of a tree of slider puzzle configurations java - java

I need help with my PuzzleSolver class. I get a notice saying
Note: SliderPuzzleSolver.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
I don't understand what this means and also when I run my tester I get this
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
Index 0 out of bounds for length 0 at
SPS_Tester.main(SPS_Tester.java:23)
If anyone would have some guesses about any of these please shoot them my way.
public class SliderPuzzleSolver {
/* Returns a String encoding a shortest sequence of moves leading from
** the given starting configuration to the standard goal configuration,
** or null if there is no such sequence.
** pre: !start.equals( the standard goal configuration )
*/
public static String solution(SliderPuzzleConfig start) {
int numRows = start.numRows();
int numCols = start.numColumns();
SliderPuzzleConfig standardGoal = new SliderPuzzleConfig(numRows, numCols);
return solution(start, standardGoal);
}
public static String solution(SliderPuzzleConfig start,
SliderPuzzleConfig goal) {
SliderPuzzleSolverNode treeNode = new SliderPuzzleSolverNode(start, "");
QueueViaLink1<SliderPuzzleSolverNode> toBeExplored = new QueueViaLink1();
toBeExplored.enqueue(treeNode);
while (!toBeExplored.isEmpty()) {
treeNode = toBeExplored.dequeue();
SliderPuzzleConfig config = treeNode.config;
char[] direction = { 'U', 'D', 'L', 'R' };
for(int i = 0; i <= 4; i++) {
if(config.canMove(direction[i])) {
SliderPuzzleConfig newConfig = config.clone();
newConfig.move(direction[i]);
if(newConfig != goal) { //newConfig was not discovered earlier
String moveSeq = treeNode.moveSeq + direction;
SliderPuzzleSolverNode newTreeNode = new SliderPuzzleSolverNode(newConfig, moveSeq);
toBeExplored.enqueue(newTreeNode);
if (newConfig == goal) {
return moveSeq;
}
}
}
}
}
return null;
}
}
public class SPS_Tester {
/* Provided with command line arguments (or what jGrasp refers to as
** "run arguments") indicating the dimensions of a puzzle, a seed
** for a pseudo-random number generator, and a number of pseudo-random
** moves to make --starting with the standard goal configuration-- to
** obtain an initial configuration, this method uses the solution()
** method in the SliderPuzzleSolver class to find a minimum-length
** sequence of moves that transforms that initial configuration into
** the standard goal configuration. This method then displays the
** configurations along that path of moves.
*/
public static void main(String[] args) {
int numRows = Integer.parseInt(args[0]);
int numCols = Integer.parseInt(args[1]);
int seed = Integer.parseInt(args[2]);
Random rand = new Random(seed);
int numMoves = Integer.parseInt(args[3]);
SliderPuzzleConfig start =
new SliderPuzzleConfig(numRows, numCols, rand, numMoves);
System.out.println("Starting configuration is");
start.display();
System.out.println();
String solution = SliderPuzzleSolver.solution(start);
if (solution == null) {
System.out.println("No solution was found.");
}
else {
System.out.printf("Path of length %d found:\n\n", solution.length());
displayPath(start, solution);
}
System.out.println("\nGoodbye.");
}
/* Displays the sequence of configurations starting with the one
** given and proceeding according to the given sequence of moves.
*/
public static void displayPath(SliderPuzzleConfig config, String moveSeq) {
SliderPuzzleConfig spc = config.clone();
spc.display();
for (int i = 0; i != moveSeq.length(); i++) {
char dir = moveSeq.charAt(i);
spc.move(dir);
System.out.printf("\nAfter moving %c:\n", dir);
spc.display();
}
}
}

Note: SliderPuzzleSolver.java uses unchecked or unsafe operations
It means you are not using a generic type somewhere that you could or should. This is just a warning. It looks like the only place is
QueueViaLink1<SliderPuzzleSolverNode> toBeExplored = new QueueViaLink1();
It should be new QueViaLink1<SliderPuzzleSolverNode>() or in recent versions of Java you can also use newQueViaLink1<>() . You can use the compiler settings in jGRASP, or whatever IDE you're using if it's not that, to add the suggested compiler flag if you want the specific error messages.
java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for
length 0
It appears you are not passing any command line arguments. Your program should test the length of args[] before accessing the elements, and fail with an error message if there are not enough.

Related

Reading a text file into an array and performing a sort in Java

I have a homework question I need help with
We have been given a text file containing one word per line, of a story.
We need to read this file into an array, perform a sort on the array and then perform a binary search.
The task also says I'll need to use an overload method, but I'm unsure where
I have a bubble sort, that I've tested on a small array of characters which works
public static void bubbleV1String(String[]numbers)
{
for(int i = 0; i < numbers.length-1; i++)
{
for(int j = 0; j < numbers.length-1; j++)
{
if(numbers[j] .compareTo(numbers[j+1])>0)
{
String temp = numbers[j+1];
numbers[j+1] = numbers[j];
numbers[j] = temp;
}
}
}
}`
And my binary search which I've tested on the same small array
public static String binarySearch(int[] numbers, int wanted)
{
ArrayUtilities.bucketSort(numbers);
int left = 0;
int right = numbers.length-1;
while(left <= right)
{
int middle = (left+right)/2;
if (numbers[middle] == wanted)
{
return (wanted + " was found at position " + middle);
}
else if(numbers[middle] > wanted)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return wanted + " was not found";
}
Here is my code in an app class to read in a file and sort it
String[] myArray = new String[100000];
int index = 0;
File text = new File("threebears.txt");
try {
Scanner scan = new Scanner(text);
while(scan.hasNextLine() && index < 100000)
{
myArray[index] = scan.nextLine();
index++;
}
scan.close();
} catch (IOException e) {
System.out.println("Problem with file");
e.printStackTrace();
}
ArrayUtilities.bubbleV1String(myArray);
try {
FileWriter outFile = new FileWriter("sorted1.txt");
PrintWriter out = new PrintWriter(outFile);
for(String item : myArray)
{
out.println(item);
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
When I go to run the code, I get a null pointer exception and the following message
Exception in thread "main" java.lang.NullPointerException
at java.base/java.lang.String.compareTo(Unknown Source)
at parrayutilities.ArrayUtilities.bubbleV1String(ArrayUtilities.java:129)
at parrayutilities.binarySearchApp.main(binarySearchApp.java:32)
Line 129 refers to this line of code of my bubblesort
if(numbers[j] .compareTo(numbers[j+1])>0)
And line 32 refers to the piece of code where I call the bubblesort
ArrayUtilities.bubbleV1String(myArray);
Does anyone know why I'm getting a null pointer exception when I've tested the bubblesort on a small string array? I'm thinking possibly something to do with the overloaded method mentioned earlier but I'm not sure
Thanks
You are creating an array of length 100000 and fill the lines as they are read. Initially all elements will be null and after reading the file quite a number of them is likely to still be null. Thus when you sort the array numbers[j] will eventually be a null element and thus calling compareTo(...) on that will throw a NullPointerException.
To fix that you need to know where in the array the non-null part ends. You are already tracking the number of read lines in index so after reading the file that would be the index of the first null element.
Now you basically have 2 options:
Pass index to bubbleV1String() and do for(int i = 0; i < index-1; i++) etc.
Make a copy of the array after reading the lines and before sorting it:
String[] copy = new String[index];
StringSystem.arrayCopy(myArray,0,copy,0,index);
//optional but it can make the rest of the code easier to handle: replace myArray with copy
myArray = copy;
Finally you could also use a List<String> which would be better than using arrays but I assume that's covered by a future lesson.
It seems that you have some null values in your numbers array. Try to debug your code (or just print array's content) and verify what you have there. Hard to tell anything not knowing what is in your input file.
Method overloading is when multiple functions have the same name but different parameters.
e.g. (taken from wikipedia - function overloading)
// volume of a cube
int volume(const int s)
{
return s*s*s;
}
// volume of a cylinder
double volume(const double r, const int h)
{
return 3.1415926*r*r*static_cast<double>(h);
}
Regarding your null pointer exception, you've created an array of size 100000, but it's likely you haven't read in enough information to fill that size. Therefore some of the array is empty when you try to access it. There are multiple ways you can go about this, off the top of my head that includes array lists, dynamic arrays or even moving the contents of the array to another one, once you know the size of the contents (however this is inefficient).

Java - Return random index of specific character in string

So given a string such as: 0100101, I want to return a random single index of one of the positions of a 1 (1, 5, 6).
So far I'm using:
protected int getRandomBirthIndex(String s) {
ArrayList<Integer> birthIndicies = new ArrayList<Integer>();
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) == '1')) {
birthIndicies.add(i);
}
}
return birthIndicies.get(Randomizer.nextInt(birthIndicies.size()));
}
However, it's causing a bottle-neck on my code (45% of CPU time is in this method), as the strings are over 4000 characters long. Can anyone think of a more efficient way to do this?
If you're interested in a single index of one of the positions with 1, and assuming there is at least one 1 in your input, you can just do this:
String input = "0100101";
final int n=input.length();
Random generator = new Random();
char c=0;
int i=0;
do{
i = generator.nextInt(n);
c=input.charAt(i);
}while(c!='1');
System.out.println(i);
This solution is fast and does not consume much memory, for example when 1 and 0 are distributed uniformly. As highlighted by #paxdiablo it can perform poorly in some cases, for example when 1 are scarce.
You could use String.indexOf(int) to find each 1 (instead of iterating every character). I would also prefer to program to the List interface and to use the diamond operator <>. Something like,
private static Random rand = new Random();
protected int getRandomBirthIndex(String s) {
List<Integer> birthIndicies = new ArrayList<>();
int index = s.indexOf('1');
while (index > -1) {
birthIndicies.add(index);
index = s.indexOf('1', index + 1);
}
return birthIndicies.get(rand.nextInt(birthIndicies.size()));
}
Finally, if you need to do this many times, save the List as a field and re-use it (instead of calculating the indices every time). For example with memoization,
private static Random rand = new Random();
private static Map<String, List<Integer>> memo = new HashMap<>();
protected int getRandomBirthIndex(String s) {
List<Integer> birthIndicies;
if (!memo.containsKey(s)) {
birthIndicies = new ArrayList<>();
int index = s.indexOf('1');
while (index > -1) {
birthIndicies.add(index);
index = s.indexOf('1', index + 1);
}
memo.put(s, birthIndicies);
} else {
birthIndicies = memo.get(s);
}
return birthIndicies.get(rand.nextInt(birthIndicies.size()));
}
Well, one way would be to remove the creation of the list each time, by caching the list based on the string itself, assuming the strings are used more often than they're changed. If they're not, then caching methods won't help.
The caching method involves, rather than having just a string, have an object consisting of:
current string;
cached string; and
list based on the cached string.
You can provide a function to the clients to create such an object from a given string and it would set the string and the cached string to whatever was passed in, then calculate the list. Another function would be used to change the current string to something else.
The getRandomBirthIndex() function then receives this structure (rather than the string) and follows the rule set:
if the current and cached strings are different, set the cached string to be the same as the current string, then recalculate the list based on that.
in any case, return a random element from the list.
That way, if the list changes rarely, you avoid the expensive recalculation where it's not necessary.
In pseudo-code, something like this should suffice:
# Constructs fastie from string.
# Sets cached string to something other than
# that passed in (lazy list creation).
def fastie.constructor(string s):
me.current = s
me.cached = s + "!"
# Changes current string in fastie. No list update in
# case you change it again before needing an element.
def fastie.changeString(string s):
me.current = s
# Get a random index, will recalculate list first but
# only if necessary. Empty list returns index of -1.
def fastie.getRandomBirthIndex()
me.recalcListFromCached()
if me.list.size() == 0:
return -1
return me.list[random(me.list.size())]
# Recalculates the list from the current string.
# Done on an as-needed basis.
def fastie.recalcListFromCached():
if me.current != me.cached:
me.cached = me.current
me.list = empty
for idx = 0 to me.cached.length() - 1 inclusive:
if me.cached[idx] == '1':
me.list.append(idx)
You also have the option of speeding up the actual searching for the 1 character by, for example, useing indexOf() to locate them using the underlying Java libraries rather than checking each character individually in your own code (again, pseudo-code):
def fastie.recalcListFromCached():
if me.current != me.cached:
me.cached = me.current
me.list = empty
idx = me.cached.indexOf('1')
while idx != -1:
me.list.append(idx)
idx = me.cached.indexOf('1', idx + 1)
This method can be used even if you don't cache the values. It's likely to be faster using Java's probably-optimised string search code than doing it yourself.
However, you should keep in mind that your supposed problem of spending 45% of time in that code may not be an issue at all. It's not so much the proportion of time spent there as it is the absolute amount of time.
By that, I mean it probably makes no difference what percentage of the time being spent in that function if it finishes in 0.001 seconds (and you're not wanting to process thousands of strings per second). You should only really become concerned if the effects become noticeable to the user of your software somehow. Otherwise, optimisation is pretty much wasted effort.
You can even try this with best case complexity O(1) and in worst case it might go to O(n) or purely worst case can be infinity as it purely depends on Randomizer function that you are using.
private static Random rand = new Random();
protected int getRandomBirthIndex(String s) {
List<Integer> birthIndicies = new ArrayList<>();
int index = s.indexOf('1');
while (index > -1) {
birthIndicies.add(index);
index = s.indexOf('1', index + 1);
}
return birthIndicies.get(rand.nextInt(birthIndicies.size()));
}
If your Strings are very long and you're sure it contains a lot of 1s (or the String you're looking for), its probably faster to randomly "poke around" in the String until you find what you are looking for. So you save the time iterating the String:
String s = "0100101";
int index = ThreadLocalRandom.current().nextInt(s.length());
while(s.charAt(index) != '1') {
System.out.println("got not a 1, trying again");
index = ThreadLocalRandom.current().nextInt(s.length());
}
System.out.println("found: " + index + " - " + s.charAt(index));
I'm not sure about the statistics, but it rare cases might happen that this Solution take much longer that the iterating solution. On case is a long String with only a very few occurrences of the search string.
If the Source-String doesn't contain the search String at all, this code will run forever!
One possibility is to use a short-circuited Fisher-Yates style shuffle. Create an array of the indices and start shuffling it. As soon as the next shuffled element points to a one, return that index. If you find you've iterated through indices without finding a one, then this string contains only zeros so return -1.
If the length of the strings is always the same, the array indices can be static as shown below, and doesn't need reinitializing on new invocations. If not, you'll have to move the declaration of indices into the method and initialize it each time with the correct index set. The code below was written for strings of length 7, such as your example of 0100101.
// delete this and uncomment below if string lengths vary
private static int[] indices = { 0, 1, 2, 3, 4, 5, 6 };
protected int getRandomBirthIndex(String s) {
int tmp;
/*
* int[] indices = new int[s.length()];
* for (int i = 0; i < s.length(); ++i) indices[i] = i;
*/
for (int i = 0; i < s.length(); i++) {
int j = randomizer.nextInt(indices.length - i) + i;
if (j != i) { // swap to shuffle
tmp = indices[i];
indices[i] = indices[j];
indices[j] = tmp;
}
if ((s.charAt(indices[i]) == '1')) {
return indices[i];
}
}
return -1;
}
This approach terminates quickly if 1's are dense, guarantees termination after s.length() iterations even if there aren't any 1's, and the locations returned are uniform across the set of 1's.

Getting an"index:0" and "size:0" error from ArrayList.size()

I have been working on this program for hours, and have worked out nearly all of the errors that have cropped up in every other class. This one, however, I can's seem to fix the receive method. The receive method should first check (by comparing SKUs) whether or not the incoming product is already in myCatalog. If not, add the product (via its SKU) to the catalog. After that, in any case -- as long as there is still some of the incoming product not yet been placed in a bin -- I want to locate which bin contains the least total quantity. (If all the bins are full, add a new, empty bin to use)I'd add that specific product to that bin until the bin is either full -- at which point I'd repeat -- or I run out of the product. This repeats until no more incoming product is left.
public class Warehouse
{
private int myBinMax;
private ArrayList<MusicMedia> myCatalog;
private ArrayList<Bin> myBins;
public Warehouse( int binMax )
{
myBinMax = binMax;
myCatalog = new ArrayList<MusicMedia>();
myBins = new ArrayList<Bin>( 5 );
}
public String toString()
{
return Tester.detailedInventory(myCatalog,myBins);
}
public void addBin()
{
myBins.add( new Bin( "B" + myBins.size() ) );
}
public void receive( MusicMedia product, int quantity )
{
boolean contained = false;
int lowestAmount = myBinMax,
leastFullBinIndex,
i,
insertQuantity;
for(MusicMedia entry : myCatalog)
{
if(entry.getSKU().equals(product.getSKU()))
{
contained = true;
}
}
if(!contained)
{
myCatalog.add(product);
}
while(quantity > 0)
{
lowestAmount = myBinMax;
for(i = 0; i < myBins.size(); i++)
{
if(myBins.get(i).totalQuantity() < lowestAmount)
{
lowestAmount = myBins.get(i).totalQuantity();
leastFullBinIndex = i;
}
if((i == myBins.size() - 1 && lowestAmount == myBinMax)||(myBins.size() == 0))
{
myBins.add(new Bin("bin" + Integer.toString(i)));
}
}
if(quantity >= myBinMax - lowestAmount)
{
insertQuantity = myBinMax - lowestAmount;
}
else
{
insertQuantity = quantity;
}
quantity -= insertQuantity;
myBins.get(i).add(new BinItem(product.getSKU(), insertQuantity));
}
}
}
Before my last edit, nothing would print -- just a blank console -- but in an attempt to fix that, I added this (also contained within the code above):
if((i == myBins.size() - 1 && lowestAmount == myBinMax)||(myBins.size() == 0))
{
myBins.add(new Bin("bin" + Integer.toString(i)));
}
Now, it won't run without giving me an error:
java.lang.IndexOutOfBoundsException
Index: 0, Size 0 (in java.util.ArrayList)
As well as highlighting the following line:
myBins.get(i).add(new BinItem(product.getSKU(), insertQuantity));
Here's a breakdown on the various classes that have been created for this colossal program:
MusicMedia has three private variables, but the only one that has any bearing here is the String mySKU, obtained by getSKU()
Bin has a private String, name, which is also its only argument, as well as a private ArrayList of class BinItem. In order to access this ArrayList of BinItems from another class, you would use getContents(). It also has method totalQuantity(), which returns the total quantity of objects already in a bin.
BinItem has private variables mySKU (String) and myQuantity (int) and methods getSKU() and getQuantity(), both being its arguments in that order
So to start with you have no bins.
Your "for" block is skipped because size is zero;
So we get to the final line of the "while" loop, and we execute myBins.get(i)...
This is where we get the error because we can't get the bin at index 0, because we got no bins at all.
The problem is we reached this line of code without adding any bins...
I'm not sure if you realized, the line below doesn't start your program with 5 bins.
myBins = new ArrayList<Bin>( 5 );
The 5 in this code sets the internal buffer for the array to hold 5 items. If we supplied no number it would start with 10. But the numbers are just there to give programmers control over how much memmory is initalized.
If your goal was to start with 5 bins, you should do something as follows:
myBins = new ArrayList<Bin>( 5 );
for(int i=0; i<5; i++){
myBins.add(new myBin());
}

Error resolving variables and left-side side assignments and figuring ++ tokens

I'm starting to get blind looking at my code and my brain is about to overheat. I'm new when it comes to programming.
public class RecyclingSystem {
public static void main(String[] args) {
System.out.println("Please put in a valid bottle");
Scanner sc = new Scanner(System.in);
while ( sc.nextInt() != -1) {
if (sc.nextInt(char a) = getaBottle);
int bottleAcount++;
} else if { (sc.nextInt(char b) = getbBottle);
int bottleBcount++;
} else if { (sc.nextInt(char c) = getcBottle);
int bottleCcount++;
} else { throw new EmptyStackException();
System.out.println("Bottle not recognized");
}
System.out.println("The total number of bottles is " + totalBottlecount);
System.out.println();
System.out.println("The total amount returned is " + sumOfBottles );
}
sc.close();
}
}}
public class Bottle {
private static final double A_BOTTLE = 1.0;
/**
* #return the aBottle
*/
public static double getaBottle() {
return A_BOTTLE;
}
/**
* #return the bBottle
*/
public static double getbBottle() {
return B_BOTTLE;
}
/**
* #return the cBottle
*/
public static double getcBottle() {
return C_BOTTLE;
}
private static final double B_BOTTLE = 1.5;
private static final double C_BOTTLE = 3.0;
}
public class EmptyStackException extends Exception {
}
public class bottleCount {
int bottleAcount = 0;
int bottleBcount = 0;
int bottleCcount = 0;
int totalBottleCount = bottleAcount + bottleBcount + bottleCcount;
}
I have seperate classes for the getbottle, totalBottlecount and bottlecount variables.
I want to make a user-input based recycling system simulator, if that makes any sense, with 3 different types of bottles, which are assigned different values, a total bottle count and the sum of the values of the 3 bottle types combined.
I get several compiler errors and I have spend HOURS trying to resolve them all, but every time I do, new errors occur and now I get a "coders-block".
I get asked to delete the ++ tokens, the compiler cannot resolve my variables and syntax errors. I would really appreciate some insight, since I'm only ~3weeks into java programming.
UPDATED: Compiler errors exact copy pasta
Multiple markers at this line
- Syntax error, insert ")" to complete Expression
- Duplicate method nextInt(char) in type RecyclingSystem
- Syntax error, insert "}" to complete Block
- Syntax error, insert "AssignmentOperator Expression" to complete Assignment
- Return type for the method is missing
- Syntax error on tokens, delete these tokens
- The left-hand side of an assignment must be a variable
- Syntax error, insert "AssignmentOperator Expression" to complete Expression
- The left-hand side of an assignment must be a variable
- Syntax error, insert ";" to complete BlockStatements
- Syntax error on tokens, delete these tokens
- Syntax error on token ")", { expected after this token
- Syntax error, insert ";" to complete Statement
int bottleAcount++;
In java you need to declare the local variable like
type name = intial value;
then do any operation on that like increament or decrement.
In youe case declar the variable before while loop with zero as intial value like
int bottleAcount = 0;
then inside while increament it by 1, like bottleAcount++;
or
bottleAcount += 1;
So... If this is all the code there are many problems and what can I recommend in the beginning - go back to some basic Java programming course.
Let's look at one of the first lines:
if (sc.nextInt(char a) = getaBottle);
Firstly, it's a condition, and you are assigning the value of a getaBottle to the sc.nextInt(char a).
Secondly, nextInt(char a) looks like method declaring, not like a method call.
Thirdly, getaBottle is never declared before
Fourthly, you have a getaBottle() method in a Bottle class, which you probably want to use instead of getaBottle which is (should) be a variable
...etc., etc.
This code is not even valid Java code. It's hard to help you somehow in that problem, you just need to learn a bit more, which I encourage you to do.
Good luck and in case of any specific question - come and ask!
else if { (sc.nextInt(char b) = getbBottle);
int bottleBcount++;
}
Syntax is totally wrong for if.Also condition is checked using == not = It should be :
else if (sc.nextInt(char b) == getbBottle);
int bottleBcount++;
Also you cant do int bottleBcount++. Its meaningless. Since you already declared bottleBcount in another class, you have to access it using the object of that class. Before that change the declaration in the class from int bottleAcount = 0; to public int bottleAcount = 0; . Do this for all bottles.
Now you can use it as :
public static void main(String[] args) {
System.out.println("Please put in a valid bottle");
bottleCount counter = new bottleCount();
Scanner sc = new Scanner(System.in);
while ( sc.nextInt() != -1) {
if (sc.nextInt(char a) == getaBottle);
counter.bottleAcount++;
} else if (sc.nextInt(char b) == getbBottle);
counter.bottleBcount++;
else if (sc.nextInt(char c) == getcBottle);
counter.bottleCcount++;
else { throw new EmptyStackException();
System.out.println("Bottle not recognized");
}
System.out.println("The total number of bottles is " + totalBottlecount);
System.out.println();
System.out.println("The total amount returned is " + sumOfBottles );
}
sc.close();
}
Also the statement int totalBottleCount = bottleAcount + bottleBcount + bottleCcount; doesnt make sense. It won't work as you wanted it to. You need to write a function to do this addition and then call it. Or if you want this to happen just once ( which I doubt) , you can put it in a constructor.
I suggest you brush up on class and variable declaration concepts before proceeding
You just have problem in this:
else {
throw new EmptyStackException();
System.out.println("Bottle not recognized");
}
Check the proper syntax and error will be resolved.

Copy instance variable of type java.util.Random to create object in same state

I'm implementing a simulated annealing (SA) algorithm, where I need to copy states (e. g. to remember best solution so far).
I implemented a copy method, since it's discouraged to use java's clone().
SA is a heuristic algorithm, so the next step to take is determined randomly. This is done by using a Random object, which I want to copy too.
Although it's not requiered by the algorithm, I want the copy to have exactly the same state.
But this is only the case, if I make a 'copy' direct after object creation and initialize it with the same seed.
But if I perform some operations on the random before the copy process , the intrinsic state (i. e. the seed) of theRandom object changes and the copy behaves differently.
So how can I get an exact copy of an instance of java.util.Random?
EXAMPLE
public class State
{
private final Random r;
private final long seed;
private Object currentOperand;
public State()
{
this(System.nanoTime(), null);
}
private State(long seed, Object currentOperand)
{
this.seed = seed;
this.r = new Random(seed);
this.currentOperand = currentOperand;
}
public State copy()
{
return new State(seed, currentOperand);
}
public void doSth()
{
/* operation with random operand */
currentOperand = r.nextInt(100);
}
public void redo()
{
// redo then set to null
currentOperand = null;
}
/* for completeness' sake... since it's simulated annealing */
public int computeEnergy() { return 0; }
}
I came up with an own solution. It mainly overrides next() in Random (since all other methods rely on that one), and some other stuff to keep the consistency.
It delivers an exact copy of the instance this method was invoked on (whether it makes sense to make a copy of a random instance is another topic...^^). It should exactly behave like its super class, at least that was my intention.
Feel free to add your thoughts!
Since other questions were about getting the seed: One could easily add a getSeed() method to my solution. Or getInitialSeed(), getCurrentSeed().
/* Bounded parameter type since a class that implements this interface
* should only be able to create copies of the same type (or a subtype).
*/
public interface Copyable<T extends Copyable<T>>
{
public T copy();
}
public class CopyableRandom extends Random implements Copyable<CopyableRandom>
{
private final AtomicLong seed = new AtomicLong(0L);
private final static long multiplier = 0x5DEECE66DL;
private final static long addend = 0xBL;
private final static long mask = (1L << 48) - 1;
public CopyableRandom() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
public CopyableRandom(long seed) { this.seed.set((seed ^ multiplier) & mask); }
/* copy of superclasses code, as you can seed the seed changes */
#Override
protected int next(int bits)
{
long oldseed, nextseed;
AtomicLong seed_ = this.seed;
do
{
oldseed = seed_.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed_.compareAndSet(oldseed, nextseed));
return (int) (nextseed >>> (48 - bits));
}
/* necessary to prevent changes to seed that are made in constructor */
#Override
public CopyableRandom copy() { return new CopyableRandom((seed.get() ^ multiplier) & mask); }
public static void main(String[] args)
{
CopyableRandom cr = new CopyableRandom();
/* changes intern state of cr */
for (int i = 0; i < 10; i++)
System.out.println(cr.nextInt(50));
Random copy = cr.copy()
System.out.println("\nTEST: INTEGER\n");
for (int i = 0; i < 10; i++)
System.out.println("CR\t= " + cr.nextInt(50) + "\nCOPY\t= " + copy.nextInt(50) + "\n");
Random anotherCopy = (copy instanceof CopyableRandom) ? ((CopyableRandom) copy).copy() : new Random();
System.out.println("\nTEST: DOUBLE\n");
for (int i = 0; i < 10; i++)
System.out.println("CR\t= " + cr.nextDouble() + "\nA_COPY\t= " + anotherCopy.nextDouble() + "\n");
}
}
And here the output of the main method:
19
23
26
37
41
34
17
28
29
6
TEST: INTEGER
CR = 3
COPY = 3
CR = 18
COPY = 18
CR = 25
COPY = 25
CR = 9
COPY = 9
CR = 24
COPY = 24
CR = 5
COPY = 5
CR = 15
COPY = 15
CR = 5
COPY = 5
CR = 30
COPY = 30
CR = 26
COPY = 26
TEST: DOUBLE
CR = 0.7161924830704971
A_COPY = 0.7161924830704971
CR = 0.06333509362539957
A_COPY = 0.06333509362539957
CR = 0.6340753697524675
A_COPY = 0.6340753697524675
CR = 0.13546677259518425
A_COPY = 0.13546677259518425
CR = 0.37133033932410586
A_COPY = 0.37133033932410586
CR = 0.796277965335522
A_COPY = 0.796277965335522
CR = 0.8610310118615391
A_COPY = 0.8610310118615391
CR = 0.793617231340077
A_COPY = 0.793617231340077
CR = 0.3454111197621874
A_COPY = 0.3454111197621874
CR = 0.25314618087856255
A_COPY = 0.25314618087856255
I also had a test where I compared CopyableRandom against Random. It yielded the same results.
long seed = System.nanoTime();
Random cr = new CopyableRandom(seed);
Random cmp = new Random(seed);
I know this is an old question with an accepted answer, but I came across this while looking for an answer myself, and I wound up taking a different approach.
Seeing mike's note above that Random implements Serializable, I just used that to make the copy:
/**
* Uses serialization to create a copy of the given Random, needed for
* repeatability in some tests.
*/
public static Random cloneRandom(Random src) throws Exception {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bo);
oos.writeObject(src);
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(bo.toByteArray()));
return (Random)(ois.readObject());
}
It probably doesn't perform as well as mike's CopyableRandom, but it's a lot simpler, and sufficent for my little unit test.
(I had an existing unit test which started with a Random with a known seed & then performed a series of operations; I was trying to add a bit in the middle of the test, and wanted a copy of the Random; calling nextLong() or similar in the middle of the test to get the/a seed was going to change the seed, blowing up the rest of the test. Really I just wanted something like Random.getSeed().)
I think you should store in your State class, not only starting seed but also number of calls to nextInt() you already did. This is due to the intrisic fact that Random generates pseudo-random sequence of numbers. That is:
A pseudo random number generator can be started from an arbitrary starting state using a seed state. It will always produce the same sequence thereafter when initialized with that state
Let me explain show you with a sample first:
public static void main(String[] args){
Random r = new Random(42);
Random s = new Random(42);
for(int i = 0; i < 5; i++){
System.out.println("First random " +r.nextInt());
}
for(int i = 0; i < 5; i++){
System.out.println("Second random " +s.nextInt());
}
}
which result is:
First random -1170105035
First random 234785527
First random -1360544799
First random 205897768
First random 1325939940
Second random -1170105035
Second random 234785527
Second random -1360544799
Second random 205897768
Second random 1325939940
Since both Random instances start with same seed, I always get the same sequence of numbers.
So, when copying object you should init the new Random to the same seed of source (you already do this) and "consume" as much calls of nextInt() that you already used in source object (this is why you have to keep that number).
After done this, calling the nextInt() on the copy will give you the same result that source object. I hope my code is enough to refactor yours and let you understand my solution.
To understand better pseudorandom number generators (PRNG), also known as a deterministic random bit generators (DRBG), you can look at this Wikipedia article

Categories