Related
I am trying to create a fast prime generator in Java. It is (more or less) accepted that the fastest way for this is the segmented sieve of Eratosthenes: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes. Lots of optimizations can be further implemented to make it faster. As of now, my implementation generates 50847534 primes below 10^9 in about 1.6 seconds, but I am looking to make it faster and at least break the 1 second barrier. To increase the chance of getting good replies, I will include a walkthrough of the algorithm as well as the code.
Still, as a TL;DR, I am looking to include multi-threading into the code
For the purposes of this question, I want to separate between the 'segmented' and the 'traditional' sieves of Eratosthenes. The traditional sieve requires O(n) space and therefore is very limited in range of the input (the limit of it). The segmented sieve however only requires O(n^0.5) space and can operate on much larger limits. (A main speed-up is using a cache-friendly segmentation, taking into account the L1 & L2 cache sizes of the specific computer). Finally, the main difference that concerns my question is that the traditional sieve is sequential, meaning it can only continue once the previous steps are completed. The segmented sieve however, is not. Each segment is independent, and is 'processed' individually against the sieving primes (the primes not larger than n^0.5). This means that theoretically, once I have the sieving primes, I can divide the work between multiple computers, each processing a different segment. The work of eachother is independent of the others. Assuming (wrongly) that each segment requires the same amount of time t to complete, and there are k segments, One computer would require total time of T = k * t, whereas k computers, each working on a different segment would require a total amount of time T = t to complete the entire process. (Practically, this is wrong, but for the sake of simplicity of the example).
This brought me to reading about multithreading - dividing the work to a few threads each processing a smaller amount of work for better usage of CPU. To my understanding, the traditional sieve cannot be multithreaded exactly because it is sequential. Each thread would depend on the previous, rendering the entire idea unfeasible. But a segmented sieve may indeed (I think) be multithreaded.
Instead of jumping straight into my question, I think it is important to introduce my code first, so I am hereby including my current fastest implementation of the segmented sieve. I have worked quite hard on it. It took quite some time, slowly tweaking and adding optimizations to it. The code is not simple. It is rather complex, I would say. I therefore assume the reader is familiar with the concepts I am introducing, such as wheel factorization, prime numbers, segmentation and more. I have included notes to make it easier to follow.
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
public class primeGen {
public static long x = (long)Math.pow(10, 9); //limit
public static int sqrtx;
public static boolean [] sievingPrimes; //the sieving primes, <= sqrtx
public static int [] wheels = new int [] {2,3,5,7,11,13,17,19}; // base wheel primes
public static int [] gaps; //the gaps, according to the wheel. will enable skipping multiples of the wheel primes
public static int nextp; // the first prime > wheel primes
public static int l; // the amount of gaps in the wheel
public static void main(String[] args)
{
long startTime = System.currentTimeMillis();
preCalc(); // creating the sieving primes and calculating the list of gaps
int segSize = Math.max(sqrtx, 32768*8); //size of each segment
long u = nextp; // 'u' is the running index of the program. will continue from one segment to the next
int wh = 0; // the will be the gap index, indicating by how much we increment 'u' each time, skipping the multiples of the wheel primes
long pi = pisqrtx(); // the primes count. initialize with the number of primes <= sqrtx
for (long low = 0 ; low < x ; low += segSize) //the heart of the code. enumerating the primes through segmentation. enumeration will begin at p > sqrtx
{
long high = Math.min(x, low + segSize);
boolean [] segment = new boolean [(int) (high - low + 1)];
int g = -1;
for (int i = nextp ; i <= sqrtx ; i += gaps[g])
{
if (sievingPrimes[(i + 1) / 2])
{
long firstMultiple = (long) (low / i * i);
if (firstMultiple < low)
firstMultiple += i;
if (firstMultiple % 2 == 0) //start with the first odd multiple of the current prime in the segment
firstMultiple += i;
for (long j = firstMultiple ; j < high ; j += i * 2)
segment[(int) (j - low)] = true;
}
g++;
//if (g == l) //due to segment size, the full list of gaps is never used **within just one segment** , and therefore this check is redundant.
//should be used with bigger segment sizes or smaller lists of gaps
//g = 0;
}
while (u <= high)
{
if (!segment[(int) (u - low)])
pi++;
u += gaps[wh];
wh++;
if (wh == l)
wh = 0;
}
}
System.out.println(pi);
long endTime = System.currentTimeMillis();
System.out.println("Solution took "+(endTime - startTime) + " ms");
}
public static boolean [] simpleSieve (int l)
{
long sqrtl = (long)Math.sqrt(l);
boolean [] primes = new boolean [l/2+2];
Arrays.fill(primes, true);
int g = -1;
for (int i = nextp ; i <= sqrtl ; i += gaps[g])
{
if (primes[(i + 1) / 2])
for (int j = i * i ; j <= l ; j += i * 2)
primes[(j + 1) / 2]=false;
g++;
if (g == l)
g=0;
}
return primes;
}
public static long pisqrtx ()
{
int pi = wheels.length;
if (x < wheels[wheels.length-1])
{
if (x < 2)
return 0;
int k = 0;
while (wheels[k] <= x)
k++;
return k;
}
int g = -1;
for (int i = nextp ; i <= sqrtx ; i += gaps[g])
{
if(sievingPrimes[( i + 1 ) / 2])
pi++;
g++;
if (g == l)
g=0;
}
return pi;
}
public static void preCalc ()
{
sqrtx = (int) Math.sqrt(x);
int prod = 1;
for (long p : wheels)
prod *= p; // primorial
nextp = BigInteger.valueOf(wheels[wheels.length-1]).nextProbablePrime().intValue(); //the first prime that comes after the wheel
int lim = prod + nextp; // circumference of the wheel
boolean [] marks = new boolean [lim + 1];
Arrays.fill(marks, true);
for (int j = 2 * 2 ;j <= lim ; j += 2)
marks[j] = false;
for (int i = 1 ; i < wheels.length ; i++)
{
int p = wheels[i];
for (int j = p * p ; j <= lim ; j += 2 * p)
marks[j]=false; // removing all integers that are NOT comprime with the base wheel primes
}
ArrayList <Integer> gs = new ArrayList <Integer>(); //list of the gaps between the integers that are coprime with the base wheel primes
int d = nextp;
for (int p = d + 2 ; p < marks.length ; p += 2)
{
if (marks[p]) //d is prime. if p is also prime, then a gap is identified, and is noted.
{
gs.add(p - d);
d = p;
}
}
gaps = new int [gs.size()];
for (int i = 0 ; i < gs.size() ; i++)
gaps[i] = gs.get(i); // Arrays are faster than lists, so moving the list of gaps to an array
l = gaps.length;
sievingPrimes = simpleSieve(sqrtx); //initializing the sieving primes
}
}
Currently, it produces 50847534 primes below 10^9 in about 1.6 seconds. This is very impressive, at least by my standards, but I am looking to make it faster, possibly break the 1 second barrier. Even then, I believe it can be made much faster still.
The whole program is based on wheel factorization: https://en.wikipedia.org/wiki/Wheel_factorization. I have noticed I am getting the fastest results using a wheel of all primes up to 19.
public static int [] wheels = new int [] {2,3,5,7,11,13,17,19}; // base wheel primes
This means that the multiples of those primes are skipped, resulting in a much smaller searching range. The gaps between numbers which we need to take are then calculated in the preCalc method. If we make those jumps between the the numbers in the searching range we skip the multiples of the base primes.
public static void preCalc ()
{
sqrtx = (int) Math.sqrt(x);
int prod = 1;
for (long p : wheels)
prod *= p; // primorial
nextp = BigInteger.valueOf(wheels[wheels.length-1]).nextProbablePrime().intValue(); //the first prime that comes after the wheel
int lim = prod + nextp; // circumference of the wheel
boolean [] marks = new boolean [lim + 1];
Arrays.fill(marks, true);
for (int j = 2 * 2 ;j <= lim ; j += 2)
marks[j] = false;
for (int i = 1 ; i < wheels.length ; i++)
{
int p = wheels[i];
for (int j = p * p ; j <= lim ; j += 2 * p)
marks[j]=false; // removing all integers that are NOT comprime with the base wheel primes
}
ArrayList <Integer> gs = new ArrayList <Integer>(); //list of the gaps between the integers that are coprime with the base wheel primes
int d = nextp;
for (int p = d + 2 ; p < marks.length ; p += 2)
{
if (marks[p]) //d is prime. if p is also prime, then a gap is identified, and is noted.
{
gs.add(p - d);
d = p;
}
}
gaps = new int [gs.size()];
for (int i = 0 ; i < gs.size() ; i++)
gaps[i] = gs.get(i); // Arrays are faster than lists, so moving the list of gaps to an array
l = gaps.length;
sievingPrimes = simpleSieve(sqrtx); //initializing the sieving primes
}
At the end of the preCalc method, the simpleSieve method is called, efficiently sieving all the sieving primes mentioned before, the primes <= sqrtx. This is a simple Eratosthenes sieve, rather than segmented, but it is still based on wheel factorization, perviously computed.
public static boolean [] simpleSieve (int l)
{
long sqrtl = (long)Math.sqrt(l);
boolean [] primes = new boolean [l/2+2];
Arrays.fill(primes, true);
int g = -1;
for (int i = nextp ; i <= sqrtl ; i += gaps[g])
{
if (primes[(i + 1) / 2])
for (int j = i * i ; j <= l ; j += i * 2)
primes[(j + 1) / 2]=false;
g++;
if (g == l)
g=0;
}
return primes;
}
Finally, we reach the heart of the algorithm. We start by enumerating all primes <= sqrtx, with the following call:
long pi = pisqrtx();`
which used the following method:
public static long pisqrtx ()
{
int pi = wheels.length;
if (x < wheels[wheels.length-1])
{
if (x < 2)
return 0;
int k = 0;
while (wheels[k] <= x)
k++;
return k;
}
int g = -1;
for (int i = nextp ; i <= sqrtx ; i += gaps[g])
{
if(sievingPrimes[( i + 1 ) / 2])
pi++;
g++;
if (g == l)
g=0;
}
return pi;
}
Then, after initializing the pi variable which keeps track of the enumeration of primes, we perform the mentioned segmentation, starting the enumeration from the first prime > sqrtx:
int segSize = Math.max(sqrtx, 32768*8); //size of each segment
long u = nextp; // 'u' is the running index of the program. will continue from one segment to the next
int wh = 0; // the will be the gap index, indicating by how much we increment 'u' each time, skipping the multiples of the wheel primes
long pi = pisqrtx(); // the primes count. initialize with the number of primes <= sqrtx
for (long low = 0 ; low < x ; low += segSize) //the heart of the code. enumerating the primes through segmentation. enumeration will begin at p > sqrtx
{
long high = Math.min(x, low + segSize);
boolean [] segment = new boolean [(int) (high - low + 1)];
int g = -1;
for (int i = nextp ; i <= sqrtx ; i += gaps[g])
{
if (sievingPrimes[(i + 1) / 2])
{
long firstMultiple = (long) (low / i * i);
if (firstMultiple < low)
firstMultiple += i;
if (firstMultiple % 2 == 0) //start with the first odd multiple of the current prime in the segment
firstMultiple += i;
for (long j = firstMultiple ; j < high ; j += i * 2)
segment[(int) (j - low)] = true;
}
g++;
//if (g == l) //due to segment size, the full list of gaps is never used **within just one segment** , and therefore this check is redundant.
//should be used with bigger segment sizes or smaller lists of gaps
//g = 0;
}
while (u <= high)
{
if (!segment[(int) (u - low)])
pi++;
u += gaps[wh];
wh++;
if (wh == l)
wh = 0;
}
}
I have also included it as a note, but will explain as well. Because the segment size is relatively small, we will not go through the entire list of gaps within just one segment, and checking it - is redundant. (Assuming we use a 19-wheel). But in a broader scope overview of the program, we will make use of the entire array of gaps, so the variable u has to follow it and not accidentally surpass it:
while (u <= high)
{
if (!segment[(int) (u - low)])
pi++;
u += gaps[wh];
wh++;
if (wh == l)
wh = 0;
}
Using higher limits will eventually render a bigger segment, which might result in a neccessity of checking we don't surpass the gaps list even within the segment. This, or tweaking the wheel primes base might have this effect on the program. Switching to bit-sieving can largely improve the segment limit though.
As an important side-note, I am aware that efficient segmentation is
one that takes the L1 & L2 cache-sizes into account. I get the
fastest results using a segment size of 32,768 * 8 = 262,144 = 2^18. I am not sure what the cache-size of my computer is, but I do
not think it can be that big, as I see most cache sizes <= 32,768.
Still, this produces the fastest run time on my computer, so this is
why it's the chosen segment size.
As I mentioned, I am still looking to improve this by a lot. I
believe, according to my introduction, that multithreading can result
in a speed-up factor of 4, using 4 threads (corresponding to 4
cores). The idea is that each thread will still use the idea of the
segmented sieve, but work on different portions. Divide the n
into 4 equal portions - threads, each in turn performing the
segmentation on the n/4 elements it is responsible for, using the
above program. My question is how do I do that? Reading about
multithreading and examples, unfortunately, did not bring to me any
insight on how to implement it in the case above efficiently. It
seems to me, as opposed to the logic behind it, that the threads were
running sequentially, rather than simultaneously. This is why I
excluded it from the code to make it more readable. I will really
appreciate a code sample on how to do it in this specific code, but a
good explanation and reference will maybe do the trick too.
Additionally, I would like to hear about more ways of speeding-up
this program even more, any ideas you have, I would love to hear!
Really want to make it very fast and efficient. Thank you!
An example like this should help you get started.
An outline of a solution:
Define a data structure ("Task") that encompasses a specific segment; you can put all the immutable shared data into it for extra neatness, too. If you're careful enough, you can pass a common mutable array to all tasks, along with the segment limits, and only update the part of the array within these limits. This is more error-prone, but can simplify the step of joining the results (AFAICT; YMMV).
Define a data structure ("Result") that stores the result of a Task computation. Even if you just update a shared resulting structure, you may need to signal which part of that structure has been updated so far.
Create a Runnable that accepts a Task, runs a computation, and puts the results into a given result queue.
Create a blocking input queue for Tasks, and a queue for Results.
Create a ThreadPoolExecutor with the number of threads close to the number of machine cores.
Submit all your Tasks to the thread pool executor. They will be scheduled to run on the threads from the pool, and will put their results into the output queue, not necessarily in order.
Wait for all the tasks in the thread pool to finish.
Drain the output queue and join the partial results into the final result.
Extra speedup may (or may not) be achieved by joining the results in a separate task that reads the output queue, or even by updating a mutable shared output structure under synchronized, depending on how much work the joining step involves.
Hope this helps.
Are you familiar with the work of Tomas Oliveira e Silva? He has a very fast implementation of the Sieve of Eratosthenes.
How interested in speed are you? Would you consider using c++?
$ time ../c_code/segmented_bit_sieve 1000000000
50847534 primes found.
real 0m0.875s
user 0m0.813s
sys 0m0.016s
$ time ../c_code/segmented_bit_isprime 1000000000
50847534 primes found.
real 0m0.816s
user 0m0.797s
sys 0m0.000s
(on my newish laptop with an i5)
The first is from #Kim Walisch using a bit array of odd prime candidates.
https://github.com/kimwalisch/primesieve/wiki/Segmented-sieve-of-Eratosthenes
The second is my tweak to Kim's with IsPrime[] also implemented as bit array, which is slightly less clear to read, although a little faster for big N due to the reduced memory footprint.
I will read your post carefully as I am interested in primes and performance no matter what language is used. I hope this isn't too far off topic or premature. But I noticed I was already beyond your performance goal.
I want to find all distinct triplets (a, b, c) in an array such that a + b + c = 0.
I implemented the algorithm in java but I am getting TLE when the input is large (for example 100,000 zeroes, etc).
For 100,000 zeroes, it should output (0, 0, 0) only.
Can someone give some idea about how to speed this up?
Below is the function which I have written. It takes an array as input and returns all unique triplets having the desired property as a list.
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ll = new ArrayList<List<Integer>>();
for(int i = 0; i < nums.length - 1; i++){
int x = nums[i];
int start = i + 1;
int end = nums.length - 1;
int sum = -x;
while(start < end){
int y = nums[start] + nums[end];
if(y == sum){
List<Integer> list = new ArrayList<Integer>();
list.add(nums[start]);
list.add(nums[end]);
list.add(x);
Collections.sort(list);
ll.add(list);
}
if(y < sum)
start++;
else
end--;
}
}
return ll.stream()
.distinct()
.collect(Collectors.toList());
}
I think that there is nothing you can do about the time complexity. Two indices must explore the array independently (except for starting/ending points), while the third can be constrained, like in your algorithm, which means that the complexity is O(n2). This dominates the preliminary sorting of the array, which is O(n·log(n)), and also a “demultiplication” step, which is O(n).
I wrote “demultiplication” because a “deduplication” is not desirable: suppose the array is [-1,-1,0,2]. Deduplicating it would eliminate the only solution. But a solution can't contain an integer more than twice, unless it's 0, in which case [0,0,0] is a solution. All integers appearing more than twice, or thrice in the case of 0, are redundant and can be eliminated in one pass after sorting and before the main algorithm.
As for the factor, it could be improved by limiting the exploration to what makes sense. I would modify your algorithm by making the pair of indices that you move until they meet, start outwards from where they meet, until the lower one hits the major index, or the upper one hits the end of the array. The starting point of the scan can be remembered across scans, adjusting it downwards as the major index moves upwards. If the starting point (actually a starting pair of adjacent indices) is outside the current range, the scan can be omitted tout court. Finding the initial starting point is an additional part of the algorithm which, after sorting, could be O(log(n)), but a very simple O(n) version would do just as well.
I have no time now to translate all the above into Java code, sorry. All I can do now is jot down the “demultiplication” code (untested) that goes right after the sorting of the array:
int len = 1;
int last = nums[0];
int count = 1;
for (int i = 1; i < nums.length; i++) {
int x = nums[i];
if (x != last) {
nums[len++] = x;
last = x;
count = 1;
} else if (count < 2 || x == 0 && count < 3) {
nums[len++] = x;
count++;
}
}
// use len instead of nums.length from this point on
The big time component I see, is that for the 100,000 zeroes example, you will hitting the if (y == sum) block for every single possible case. This appears to be the worst case for performance since you will never skip that block.
The largest improvement I can see is to first de-duplicate your input. Unfortunately sets won't work as we need still maintain up to three of the same entry. Thus, my recommendation is, after your sort, to loop through the input array and whenever you encounter more than three copies of a number in a row, remove the extras. They are not needed for the problem and just waste time.
You could create a List (an implementation of that is ArrayList) to store the combinations you already had. Always store a new value in the format of
a,b,c
where a <= b <= c
so, whenever you get a combination which may or may not already have been found, generate a String in the same format and check whether it is present in your List. If so, then do not add it. Otherwise add it to your List. After this you could convert the found values into numeric values. If you want to quicken it up, you could create a class like:
class XYZ {
public int x;
public int y;
public int z;
public XYZ(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public isMatch(int x, int y, int z) {
return (this.x == x) &&
(this.y == y) &&
(this.z == z);
}
public static boolean anyMatch(List<XYZ> list, int x, int y, int z) {
for (XYZ xyz : list) {
if (xyz.isMatch(x, y, z)) return true;
}
return false;
}
public static void addIfNotExists(List<XYZ> list, int x, int y, int z) {
if (!anyMatch(list, x, y, z)) list.add(new XYZ(x, y, z));
}
}
and you could use this class for your purpose, just make sure that x <= y <= z.
The filtering of non-unique triplets at the end can be eliminated by using a hash-table that stores the triplets in a sorted order, so all combinations of a triplet (with different ordering) gets stored exactly once.
Use a hashmap/hashset instead of an arraylist.
HashSet<List<Integer>> ll = new HashSet<List<Integer>>();
. . .
list.addAll(a,b,c)
Collections.sort(list)
ll.add(list)
In addition to this, You could also use another lookup table to ensure each repeating item in nums[] is used to calculate the triplets only once.
lookup_table = HashMap();
for(int i = 0; i < nums.length - 1; i++){
// we have already found triplets starting from nums[i]
// eg. [-1,-1,0,1], we don't need to calculate
// the same triplets for the second '-1'.
if (lookup_table.contains(nums[i]))
continue;
// Mark nums[i] as 'solved'
lookup_table.add(nums[i])
// usual processing here
int x = nums[i];
Or, since your nums[] list is already sorted, you could just skip repeating items, doing away the need for another lookup table.
i = 0;
while (i < nums.length - 1){
// we have already found triplets starting from nums[i]
// eg. [-1,-1,0,1], we don't need to calculate
// the same triplets for the second '-1'.
x = nums[i];
// skip repeating items
while (x == nums[i++]);
// usual processing here
. . .
i++;
}
and then you could just return the hashset as a list at the end.
I am trying to make a simple pitch detection application for an Android phone. I have gotten the phone to display a graph of the autocorrelation values I have computed, which are stored in a one dimensional array of doubles. Now I need to figure out how to detect repeating patterns within the array. Here is a screenshot of the autocorrelation graph with me humming a steady pitch:
I tried implementing the recursive peak-finding algorithm for 1D arrays given in this slide deck: http://courses.csail.mit.edu/6.006/spring11/lectures/lec02.pdf but I got out of memory errors on the Android.
Next I tried implementing something like this algorithm for finding the second derivative: https://stackoverflow.com/a/3869172 but the autocorrelation values coming from the phone are so jittery that it finds too many minima and maxima.
What I need to figure out how to do is to apply some kind of filter to the autocorrelation data to smooth it out but I suck at math and have no idea what to do. I tried rounding the autocorrelation values to only a few decimal places but I didn't get the results I was looking for.
Basically I need help in figuring out how I can find the overall maxima (actually just the first one would probably be ok) of a repeating pattern. In the screenshot above, the pattern is a tall peak followed by two shorter peaks. I need to know when the second tall peak happens so that I can calculate the pitch.
You are trying to estimate the frequency of the peaks of amplitude in the sample data. You can do this without having to manually find estimate the peaks and then work out frequency. Instead you can use a Fast Fourier Transform, this transforms from a graph of amplitude against time into a graph of frequency against time. There is a good description of the concept in general here http://en.wikipedia.org/wiki/Fast_Fourier_transform
...and there are several Java libraries that implement the transform including
Apache Commons Math - http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/transform/FastFourierTransformer.html
and
JTransform - https://sites.google.com/site/piotrwendykier/software/jtransforms
To answer my own question, this is what I ended up doing. (Sorry it took me so long to come back to this question to post the answer.)
double frequency = findFrequency(lowPassFilter(signal));
private double findFrequency(double[] signal) {
int[] signs = new int[signal.length];
for (int i = 0; i < signal.length - 1; i++) {
double diff = signal[i+1] - signal[i];
if (diff < 0) {
signs[i] = -1;
} else if (diff == 0) {
signs[i] = 0;
} else {
signs[i] = 1;
}
}
int[] secondDerivatives = new int[signs.length];
for (int i = 0; i < signs.length - 1; i++) {
secondDerivatives[i] = signs[i+1] - signs[i];
}
double biggestSoFar = 0.0;
int indexOfBiggestSoFar = 0;
for (int i = 0; i < secondDerivatives.length; i++) {
if (secondDerivatives[i] == -2 && signal[i] > biggestSoFar) {
biggestSoFar = signal[i];
indexOfBiggestSoFar = i;
}
}
return 1 / (double)indexOfBiggestSoFar * AudioListener.SAMPLE_RATE;
}
private double[] lowPassFilter(double[] signal) {
double alpha = 0.15;
for (int i = 1; i < signal.length; i++ ) {
signal[i] = signal[i] + alpha * (signal[i] - signal[i-1]);
}
return signal;
}
I'm making a game for a class and one element of the game is displaying a number of cabbages, which are stored in an ArrayList. This ArrayList must be a fixed number of 20, 10 of Good Cabbage and 10 of Bad Cabbage.
As the cabbages are created, I want to make sure they don't overlap when they are displayed. Where I'm running into trouble with this is that when I find a cabbage that overlaps, I'm not sure how to go back and create a new cabbage in its place. So far when the code finds an overlap, it just stops the loop. I guess I'm having trouble properly breaking out of a loop and restarting at the index that goes unfilled.
Here's what I have so far for this. Any suggestions would be much appreciated.
// Initialize the elements of the ArrayList = cabbages
// (they should not overlap and be in the garden) ....
int minX = 170 ;
int maxX = 480;
int minY = 15;
int maxY = 480;
boolean r = false;
Cabbage cabbage;
for (int i = 0; i < N_GOOD_CABBAGES + N_BAD_CABBAGES; i++){
if (i % 2 == 0){
cabbage = new GoodCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
else {
cabbage = new BadCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
if (i >= cabbages.size()){
// compares the distance between two cabbages
for (int j = 0; j < cabbages.size(); j++){
Point c1 = cabbage.getLocation();
Cabbage y = (Cabbage) cabbages.get(j);
Point c2 = y.getLocation();
int distance = (int) Math.sqrt((Math.pow((c1.x - c2.x), 2) + Math.pow((c1.y - c2.y),2)));
if (distance <= (CABBAGE_RADIUS*2) && !(i == j)){
r = true;
}
}
if (r){
break;
}
cabbage.draw();
cabbages.add(i, cabbage);
}
}
The easiest way to do this is probably to add another loop.
A do...while loop is suited to cases where you always need at least one iteration. Something like:
boolean overlapped;
do {
// create your new cabbage here
overlapped = /* check whether it overlaps another cabbage here */;
} while (overlapped);
cabbage.draw();
cabbages.add(i, cabbage);
It looks like you are making cabbage objects and then throwing them away, which is a (trivial) waste.
Why not pick the random X and Y, check if there is room at that spot, then make the cabbage when you have a good spot? You'll just churn through numbers, rather than making and discarding entire Objects. Plus you won't have to repeat the random location code for good and bad cabbages.
int x, y
do {
// pick x and y
} while (cabbageOverlaps(x,y,list)
// create a cabbage at that x,y, and add it to list
boolean cabbageOverlaps(int x, int y, ArrayList existingCabbages)
I'm writing a program to calculate a value that is a measure of the similarity between two objects. The comparison is commutative, so compare(a, b) == compare(b, a).
The program's output to the console is a matrix of all results. However, since the matrix has each comparison twice ((a, b) and (b, a)), I'd like to save time by only calculating it once. What is the best way to cache these results?
Rough example of what the output looks like:
a b c
a 0 20 9001
b 20 0 333
c 9001 333 0
It sounds like you're already caching the results really - in the matrix. Just compute one "triangle" of the matrix and fill in the rest from that:
// Compute one triangle
for (int i=0; i < size; i++)
{
for (int j=0; j <= i; j++)
{
matrix[i][j] = computeValue(i, j);
}
}
// Now mirror it
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
matrix[i][j] = matrix[j][i];
}
}
As others have mentioned, you should just calculate one side of the triangle. You don't hove to copy it or even allocate space for it either. Just transform your x and y coordinates into a single index, and you can have an array that's a little over half the size of the full square matrix. eg:
class SymmetricMatrix {
private final double[];
/**
* #param size the size of one dimension of the matrix. eg: 3 for a 3x3 matrix.
*/
SymmetricMatrix(int size) {
matrix = new double[index(size) + 1];
}
private index(int x, int y) {
if (x > y) {
int tmp = x;
x = y;
y = tmp;
}
// now x <= y
i = (y * y + y) / 2 + x;
}
public double get(int x, int y) {
return matrix[index(x, y)];
}
public void set(int x, int y, double value) {
matrix[index(x, y)] = value;
}
}
This example uses double values, but you can easily adjust that (or even make it generic, if you want to use objects).
To fill it in:
SymmetricMatrix matrix = new SymmetricMatrix(size);
for (int y = 0; y < size; y++) {
for (int x = 0; x <= y; x++) {
matrix.set(x, y, /* value */);
}
}
Calculate only one triangle, and make an access function like
get(int x, int y) {
if (x > y) { return matrix[x][y] };
return matrix[y][x];
Looks like you don't need it for this task but if you have an expensive function and need to cache the result there is a very good thread safe method here:
http://www.javaspecialists.eu/archive/Issue125.html
You need to be rather careful with caching results of methods like compareTo and equals.
If you have N array instances you potentially need to cache N^2 comparison results. (This is of course application dependent ...)
Also, if your application creates and discards large numbers of (matrix) instances, then you may end up with lots of entries in the cache, resulting in garbage retention problems. You can mitigate this with weak references, but they make garbage collection significantly slower.
If I was doing this, I'd first profile the application to determine if the compareTo and equals methods are really bottlenecks. Then if they were, I'd consider using something other than caching to speed up the methods; e.g. storing a lazily computed hash with each array could speed up equals.