Finding local minimum of minima - java

I have a list of double values (distances between point p0 and a point list L) and I'm looking for their minimum. Then I'm changing the list (which now contains distances between point p1 and the point list L) and compute this new minimum.
I repeat this until the new minimum is bigger than the minimum at the previous step.
In pseudo Java code:
double minDistanceTotal = Double.MAX_VALUE;
double minDistanceCurrent = ?????;
while (minDistanceCurrent < minDistanceTotal) {
Point curPoint = ... // take another point p0, p1, p2...
// compute current minimum distance
for (Point otherPoint : pointList) {
double curDistance = distance(curPoint, otherPoint);
if (curDistance < minDistanceCurrent) {
minDistanceCurrent = curDistance;
}
}
// compare it to the total minimum distance
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
}
}
My problem now is that I'm not sure about how to initialize minDistanceCurrent. First I tried Double.MAX_VALUE - 1, but then the while-loop isn't executed at all.
After checked the Java API to find the actual value of Double.MAX_VALUE which is 0x1.fffffffffffffP+1023. So I tried 0x1.ffffffffffffeP+1023 as the value for minDistanceCurrent, which seems to work.
But I'm not sure if this is really the second highest double value in Java.
So, what's the value I should initialize minDistanceCurrent with? Or is there some different approach to get what I want that I missed?
EDIT: After the answer of #resueman, I realized a flaw in the code. The check of current minimum and total minimum can just be done after a new current minimum is computed and not before (as it is in the condition of the while loop).
The problem was fixed using the following code:
double minDistanceTotal = Double.MAX_VALUE;
double minDistanceCurrent = Double.MAX_VALUE;
while (true) {
Point curPoint = ... // take another point
// compute current minimum distance
for (Point otherPoint : pointList) {
double curDistance = distance(curPoint, otherPoint);
if (curDistance < minDistanceCurrent) {
minDistanceCurrent = curDistance;
}
}
// compare it to the total minimum distance
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
} else {
break;
}
}
An alternative would be while(!pointList.isEmpty()) to avoid an infinite loop when the list is empty.

It looks like you only want to break out of the loop after this block of code is called
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
}
If that's the case, then I'd suggest changing your while loop to either while(true) and putting a break in the if statement, or making it while(minDistanceTotal != minDistanceCurrent)

If I'm not wrong, your loop will execute just once. Either the distances calculated by the 'distance' method are lower than MAX_VALUE or overflow the double. In any case, your last 'if' will set current and total distances equal, hence getting you out of the loop. I doubt this is what you really want.
Probably you want just to make minDistanceTotal = minDistanceCurrent just at beginning of the loop, and probably you want to use BigDecimal instead of double to avoid overflowing and inaccurate calculations, but I can't really say as I don't get the idea behind your algorithm.
Summarizing:
Be careful on how you calculate distances inside your "distance(curPoint, otherPoint)", in particular consider overflowing effects. Maybe use BigDecimal instead of Double.
Get ride of the last if and change it for whatever you really need to do.
Hope it helps somehow.

Related

K-means Algorithm with multiple parameters

I have a set of points on the map. I'm trying to create clusters. Along with the distance, I'm considering the maximum cost (as another parameter) of the each cluster.
Please find the below code snippet.
private void assignCluster(List<Cluster> finalClusters, List<Node> clusterNodes, int maxCostLimit) {
double max = Double.MAX_VALUE;
double min = max;
int clusterIndex = 0;
double distance = 0.0;
for (Node node : clusterNodes) {
min = max;
for (int i = 0; i < finalClusters.size(); i++) {
Cluster cluster = finalClusters.get(i);
distance = Point.getDistanceBetweenPoints(node.getPoint(), cluster.getPoint());
if (distance < min && (cluster.getTotalCost() + node.getCost()) <= maxCostLimit) {
min = distance;
clusterIndex = i;
}
}
if (min != max) {
Cluster cluster = finalClusters.get(clusterIndex);
cluster.setTotalCost(cluster.getTotalCost() + node.getCost());
cluster.addClusterNode(node);
}
}
}
If I try to create clusters, it is going to infinite loop. Alternatively, two points on the map are getting assigned to the two different clusters. In each iteration, the centroids of these two clusters are changing.
Please suggest me, How can I achieve this?
EDITS
Cluster.java
public class Cluster{
private List<Node> clusterNodes = new ArrayList<Node>();
private Integer totalCost = 0;
private Point2D point;
//getters and setters
}
Point.java
public class Point{
private double x = 0;
private double y = 0;
// getters and setters
//method to find the distance between 2 points
}
I'm referring this link for basic Kmeans Algorithm : http://www.dataonfocus.com/k-means-clustering-java-code/
Normally, the K-means algorithm can be shown to never repeat an assignment of nodes to clusters from a previous iteration.
Maybe this is possible in your case, due to the extra constraint of costs that you have introduced that is traditionally not present when using K-means, but maybe it still isn't, I'm not sure.
I am wondering about how you are using this assignCluster() method for which you have provided the code. Do you have another loop around it which keeps calling assignCluster() with finalClusters = a list of the latest assignments of clusters, and clusterNodes = a list of all nodes, and keeps looping until it ends up with an assignment that is equal to the previous one?
If so, are you sure that cluster.addClusterNode() correctly removes the node from its' previous cluster (as I assume it should if you implemented it as described above?). Another thing to look at may be the (cluster.getTotalDemand() + node.getCost()) calculation. I suspect that, if you happen to be looking at the cluster that this node is already in, you may not want to include node.getCost() in that calculation, since it'll be counted double if it's also included in cluster.getTotalDemand().
I had to make some assumptions about what exactly you want the code to do, or how you implemented other methods for which the code is not shown... so you'll have to point out if there are any errors in my assumptions.
Looking at the the code you provided with your question and through the link, I cannot see any reason for an infinite loop (assuming that you adapted the code correctly) except of the possibility, that the total number of clusters multiplied with the maximum cost per cluster is smaller than the total cost of all nodes together. You could check that by iterating over all nodes before entering the loop.
Another problem could be, that you forgot to reset the totalCost per cluster in your clearClusters() method, but I think that would not lead to an infinite loop.
Why is your centroid of class-type Point2D and not an object of your own Point class?

Finding nearest point excluding last point LibGDX Java

I am trying to find a way to get a bunch of points to connect via the ShapeRenderer`s method of line(Vector2 first, Vector2 second). So I will explain then show image and code to help.
There is a List of type Vector2 and I need to find the next closest vertice and then exclude the first point. Here is an image of what I mean. I labeled the iterations of the loop in the image.
1st iteration.) it finds the closest point.
2nd iteration.) it sees that the first point is closer but still chooses the third point. This is the core problem, I need to make sure the second point finds the third point even though the first point is the closer one.
Here is the code I have tried to do this.
private void cleanVertices(Array<Vector2> verts){
newVerts = new Array<Vector2>();
Vector2 tmpKey, tmpClose = null;
tmpKey = verts.get(0);
for(int i = 0; i < verts.size; i++){
for(int k = 0; k < (verts.size - 1); k++){
if(k == i)
continue;
//Distance formula
double dist = MathFactory.distance(verts.get(i), verts.get(k));
if(MathFactory.distance(verts.get(i), verts.get(k + 1)) < dist){
tmpClose = verts.get(k + 1);
}else
tmpClose = verts.get(i);
}
tmpKey = tmpClose;
newVerts.add(tmpClose);
}
}'
This does not accomplish what I need, instead, it seems to connect points closest on x-axis. I desperately need help with this. Thanks!
Make a deep copy of the input parameter verts (i.e. a new Array containing the same list of references in verts). Then iterate over that, but remove each point after you choose it as the next "nearest" neighbor.
I'm not familiar with the Array class, but an ArrayList would have the correct behavior when you remove an element. At each point only unvisited points would remain in the list.
since your problem is to find the closest vertex to the second vertex,which is the third in your case, without considering the first one. Make the second for loop starts from the position of the first for loop in every iteration ( k = i). Meaning that the second for loop will not consider the first vertex as point to calculate the distance from.

Sorting an array according to its Geolocation positions

I have an array with lat and lng in the custom model . i want to sort the array so that minimum distance from my location comes at the top position and so on.
Here is what i have tried
myLocation = new Location("");
myLocation.setLatitude(Double.valueOf(MyApplication.getInstance().getLatitude()));
myLocation.setLongitude(Double.valueOf(MyApplication.getInstance().getLongitude()));
Collections.sort(pings, new DistanceComparator());
private class DistanceComparator implements java.util.Comparator<PingModel>
{
#Override
public int compare(PingModel lhs, PingModel rhs)
{
Location lhsLocation = new Location("");
lhsLocation.setLatitude(Double.valueOf(lhs.latloc));
lhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
Location rhsLocation = new Location("");
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
}
}
The result is not sure what kind of sorting it is doing but its not according to distance.
You have a copy-paste error. Change these 2 lines:
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
to:
rhsLocation.setLatitude(Double.valueOf(rhs.latloc)); // It's rhs!
rhsLocation.setLongitude(Double.valueOf(rhs.lngloc)); // It's rhs!
Apart from this, you shouldn't convert to int before subtracting the distances. In fact, you should avoid using subtraction as the return value of a comparator. This has some well-known flaws, in particular, as distances are float values, they might not fit into an int. And what is more important, the result of the subtraction might not fit into an int. This means that the int you'd be returning might overflow, leading to unexpected results.
I'd recommend you to use clear, understandable code, instead of smartish, tricky code. Consider changing the last line of your comparator to a common tri-state if:
float lhsDistance = lhsLocation.distanceTo(myLocation);
float rhsDistance = rhsLocation.distanceTo(myLocation);
if (lhsDistance < rhsDistance) {
return -1;
} else if (lhsDistance > rhsDistance) {
return 1;
} else {
return 0;
}
Note: if the values you're comparing are in fact equal, then you must return 0 in your comparator. Otherwise, you might experience subtle, nasty bugs, as explained in this answer.
Not sure if this will help, but I was working on a similar project and found this link to be very helpful : http://www.geodatasource.com/developers/java .
Basically if you have you location; use the distance function to calculate new position - your position, and then sort based on this. Loop through the array of locations, and sort based on results.
Hope it helps.
Dan.
Can you try following
return Float.compare(lhsLocation.distanceTo(myLocation), rhsLocation.distanceTo(myLocation))
Converting to int before substraction might not always work. For example, if your distanceTo() function return km and the distance from your point and the data points is within 1 km then the result of subtraction may be 0.
Instead of
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
Try
return (rhsLocation.distanceTo(myLocation) - lhsLocation.distanceTo(myLocation)) > 0 ? 1 : -1;

Algorithm to detect and combine overlapping / colliding circles

I'm trying to write a time efficient algorithm that can detect a group of overlapping circles and make a single circle in the "middle" of the group that will represent that group. The practical application of this is representing GPS locations over a map, put the conversion in to Cartesian co-ordinates is already handled so that's not relevant, the desired effect is that at different zoom levels clusters of close together points just appear as a single circle (that will have the number of points printed in the centre in the final version)
In this example the circles just have a radius of 15 so the distance calculation (Pythagoras) is not being square rooted and compared to 225 for the collision detection. I was trying anything to shave off time, but the problem is this really needs to happen very quickly becasue it's a user facing bit of code that needs to be snappy and good looking.
I've given this a go and I it works with small data sets pretty well. 2 big problems, it takes too long and it can run out of memory if all the points are on top of one another.
The route I've taken is to calculate distance between each point in a first pass, and then take the shortest distance first and start to combine from there, anything that's been combined becomes ineligible for combination on that pass, and the whole list is passed back around to the distance calculations again until nothing changes.
To be honest I think it needs a radical shift in approach and I think it's a little beyond me. I've re factored my code in to one class for ease of posting and generated random points to give an example.
package mergepoints;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Merger {
public static void main(String[] args) {
Merger m = new Merger();
m.subProcess(m.createRandomList());
}
private List<Plottable> createRandomList() {
List<Plottable> points = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
Plottable p = new Plottable();
p.location = new Point((int) Math.floor(Math.random() * 1000),
(int) Math.floor(Math.random() * 1000));
points.add(p);
}
return points;
}
private List<Plottable> subProcess(List<Plottable> visible) {
List<PlottableTuple> tuples = new ArrayList<PlottableTuple>();
// create a tuple to store distance and matching objects together,
for (Plottable p : visible) {
PlottableTuple tuple = new PlottableTuple();
tuple.a = p;
tuples.add(tuple);
}
// work out each Plottable relative distance from
// one another and order them by shortest first.
// We may need to do this multiple times for one set so going in own
// method.
// this is the bit that takes ages
setDistances(tuples);
// Sort so that smallest distances are at the top.
// parse the set and combine any pair less than the smallest distance in
// to a combined pin.
// any plottable thats been combine is no longer eligable for combining
// so ignore on this parse.
List<PlottableTuple> sorted = new ArrayList<>(tuples);
Collections.sort(sorted);
Set<Plottable> done = new HashSet<>();
Set<Plottable> mergedSet = new HashSet<>();
for (PlottableTuple pt : sorted) {
if (!done.contains(pt.a) && pt.distance <= 225) {
Plottable merged = combine(pt, done);
done.add(pt.a);
for (PlottableTuple tup : pt.others) {
done.add(tup.a);
}
mergedSet.add(merged);
}
}
// if we haven't processed anything we are done just return visible
// list.
if (done.size() == 0) {
return visible;
} else {
// change the list to represent the new combined plottables and
// repeat the process.
visible.removeAll(done);
visible.addAll(mergedSet);
return subProcess(visible);
}
}
private Plottable combine(PlottableTuple pt, Set<Plottable> done) {
List<Plottable> plottables = new ArrayList<>();
plottables.addAll(pt.a.containingPlottables);
for (PlottableTuple otherTuple : pt.others) {
if (!done.contains(otherTuple.a)) {
plottables.addAll(otherTuple.a.containingPlottables);
}
}
int x = 0;
int y = 0;
for (Plottable p : plottables) {
Point position = p.location;
x += position.x;
y += position.y;
}
x = x / plottables.size();
y = y / plottables.size();
Plottable merged = new Plottable();
merged.containingPlottables.addAll(plottables);
merged.location = new Point(x, y);
return merged;
}
private void setDistances(List<PlottableTuple> tuples) {
System.out.println("pins: " + tuples.size());
int loops = 0;
// Start from the first item and loop through, then repeat but starting
// with the next item.
for (int startIndex = 0; startIndex < tuples.size() - 1; startIndex++) {
// Get the data for the start Plottable
PlottableTuple startTuple = tuples.get(startIndex);
Point startLocation = startTuple.a.location;
for (int i = startIndex + 1; i < tuples.size(); i++) {
loops++;
PlottableTuple compareTuple = tuples.get(i);
double distance = distance(startLocation, compareTuple.a.location);
setDistance(startTuple, compareTuple, distance);
setDistance(compareTuple, startTuple, distance);
}
}
System.out.println("loops " + loops);
}
private void setDistance(PlottableTuple from, PlottableTuple to,
double distance) {
if (distance < from.distance || from.others == null) {
from.distance = distance;
from.others = new HashSet<>();
from.others.add(to);
} else if (distance == from.distance) {
from.others.add(to);
}
}
private double distance(Point a, Point b) {
if (a.equals(b)) {
return 0.0;
}
double result = (((double) a.x - (double) b.x) * ((double) a.x - (double) b.x))
+ (((double) a.y - (double) b.y) * ((double) a.y - (double) b.y));
return result;
}
class PlottableTuple implements Comparable<PlottableTuple> {
public Plottable a;
public Set<PlottableTuple> others;
public double distance;
#Override
public int compareTo(PlottableTuple other) {
return (new Double(distance)).compareTo(other.distance);
}
}
class Plottable {
public Point location;
private Set<Plottable> containingPlottables;
public Plottable(Set<Plottable> plots) {
this.containingPlottables = plots;
}
public Plottable() {
this.containingPlottables = new HashSet<>();
this.containingPlottables.add(this);
}
public Set<Plottable> getContainingPlottables() {
return containingPlottables;
}
}
}
Map all your circles on a 2D grid first. You then only need to compare the circles in a cell with the other circles in that cell and in it's 9 neighbors (you can reduce that to five by using a brick pattern instead of a regular grid).
If you only need to be really approximate, then you can just group all the circles that fall into a cell together. You will probably also want to merge cells that only have a small number of circles together with there neighbors, but this will be fast.
This problem is going to take a reasonable amount of computation no matter how you do it, the question then is: can you do all the computation up-front so that at run-time it's just doing a look-up? I would build a tree-like structure where each layer is all the points that need to be drawn for a given zoom level. It takes more computation up-front, but at run-time you are simply drawing a list of point, fast.
My idea is to decide what the resolution of each zoom level is (ie at zoom level 1 points closer than 15 get merged; at zoom level 2 points closer than 30 get merged), then go through your points making groups of points that are within the 15 of each other and pick a point to represent group that group at the higher zoom. Now you have a 2 layer tree. Then you pass over the second layer grouping all points that are within 30 of each other, and so on all the way up to your highest zoom level. Now save this tree structure to file, and at run-time you can very quickly change zoom levels by simply drawing all points at the appropriate tree level. If you need to add or remove points, that can be done dynamically by figuring out where to attach them to the tree.
There are two downsides to this method that come to mind: 1) it will take a long time to compute the tree, but you only have to do this once, and 2) you'll have to think really carefully about how you build the tree, based on how you want the groupings to be done at higher levels. For example, in the image below the top level may not be the right grouping that you want. Maybe instead building the tree based off the previous layer, you always want to go back to the original points. That said, some loss of precision always happens when you're trying to trade-off for faster run-time.
EDIT
So you have a problem which requires O(n^2) comparisons, you say it has to be done in real-time, can not be pre-computed, and has to be fast. Good luck with that.
Let's analyze the problem a bit; if you do no pre-computation then in order to decide which points can be merged you have to compare every pair of points, that's O(n^2) comparisons. I suggested building a tree before-hand, O(n^2 log n) once, but then runtime is just a lookup, O(1). You could also do something in between where you do some work before and some at run-time, but that's how these problems always go, you have to do a certain amount of computation, you can play games by doing some of it earlier, but at the end of the day you still have to do the computation.
For example, if you're willing to do some pre-computation, you could try keeping two copies of the list of points, one sorted by x-value and one sorted by y-value, then instead of comparing every pair of points, you can do 4 binary searches to find all the points within, say, a 30 unit box of the current point. More complicated so would be slower for a small number of points (say <100), but would reduce the overall complexity to O(n log n), making it faster for large amounts of data.
EDIT 2
If you're worried about multiple points at the same location, then why don't you do a first pass removing the redundant points, then you'll have a smaller "search list"
list searchList = new list()
for pt1 in points :
boolean clean = true
for pt2 in searchList :
if distance(pt1, pt2) < epsilon :
clean = false
break
if clean :
searchList.add(pt1)
// Now you have a smaller list to act on with only 1 point per cluster
// ... I guess this is actually the same as my first suggestion if you make one of these search lists per zoom level. huh.
EDIT 3: Graph Traversal
A totally new approach would be to build a graph out of the points and do some sort of longest-edge-first graph traversal on them. So pick a point, draw it, and traverse its longest edge, draw that point, etc. Repeat this until you come to a point which doesn't have any untraversed edges longer than your zoom resolution. The number of edges per point gives you an easy way to tradeoff speed for correctness. If the number of edges per point was small and constant, say 4, then with a bit of cleverness you could build the graph in O(n) time and also traverse it to draw points in O(n) time. Fast enough to do it on the fly with no pre-computation.
Just a wild guess and something that occurred to me while reading responses from others.
Do a multi-step comparison. Assume your combining distance at the current zoom level is 20 meters. First, subtract (X1 - X2). If This is bigger than 20 meters then you are done, the points are too far. Next, subtract (Y1 - Y2) and do the same thing to reject combining the points.
You could stop here and be happy if you are good with using only horizontal/vertical distances as your metric for combining. Much less math (no squaring or square roots). Pythagoras wouldn't be happy but your users might.
If you really insist on exact answers, do the two subtraction/comparison steps above. If the points are within horizontal and vertical limits, THEN you do the full Pythagoras check with square roots.
Assuming all your points are not highly clustered very close to the combining limit, this should save some CPU cycles.
This is still approximately an O(n^2) technique, but the math should be simpler. If you have the memory, you could store distances between each set of points and then you never have to compute it again. This could take up more memory than you have and also grows at a rate of approximately O(n^2), so be careful.
Also, you could make a linked list or sorted array of all your points, sorted in order of increasing X or increasing Y. (I don't think you need both, just one). Then walk through the list in sorted order. For each point, check the neighbors out until (X1 - X2) is bigger than your combining distance. and then stop. You don't have to compare each set of points for O(N^2), you only have to compare neighbors that are close in one dimension to quickly prune your large list to a small one. As you move through the list, you only have to compare points that have a bigger X than your current candidate, because you already compared and combined with all previous X values. This gets you closer to the O(n) complexity you want. Of course, you would need to check the Y dimension and fully qualify the points to be combined before you actually do it. Don't just use the X distance to make your combining decision.

Implement random search algorithm in java

I'm tryin to implement a simple "random search algorithm" in Java
here's a piece of the code:
//execute the algorithm
double bestSolution; //INITIAL SOLUTION!
Vector bestVector=null;
for (int iter=0; iter<maxIterations; iter++) {
//generate random vector-solution
Vector v = Vector.generateRandomVector(problemSize, minOfSearchSpace, maxOfSearchSpace);
double currentObjValue = objectiveFunctionValue(v);
// if a better solution is found
if (currentObjValue < bestSolution); {
bestVector = v;
bestSolution = currentObjValue;
}
System.out.println("Iteration: "+(iter+1)+" Best solution: "+bestSolution);
} // end for
System.out.println("\n\nBest solution: "+bestVector.toString()+" Objective Value: "+bestSolution);
my problem is: somehow i have to initialize the initial solution "double bestSolution".
what initial value should i give? note that for certain objective function, values such as "0" while make the convergence harder.
It seems natural to me to use
double bestSolution = Double.MAX_VALUE
since presumably your first guess will be the best so far, no matter what it is.
or maybe even
double bestSolution = Double.POSITIVE_INFINITY
Check if you're at the first iteration (iter == 0), and initialize the bestSolution with the computed solution if it's the first iteration, else compare it with the previous bestSolution.

Categories