How to graphically simulate the result of the K-Means Algorithm? - java

I'm a student in computing sciences in Paris. In mathematics this year we have to use the K-means algorithm to solve a problem (the Clustered Capacited Vehicle Routing Problem applied to the resupplying of self-service bicycles' stations). Here is my algorithm :
public void run() {
boolean hasConverged = false;
List<Integer> nearestClusters = null;
//A list used to check if the nearestClusters list has evolved
//If it isn't the case, the algorithm is finish
List<Integer> previousList = new ArrayList<Integer>();
//Random initialization of the clusters' centroids
for (int i = 0; i < clustersNumber; ++i) {
clusters.add(ClusterGenerator.Generate(stationsList,colorList.get(i) ,latMin, latMax, lngMin, lngMax));
}
while (!hasConverged) {
if (nearestClusters != null) {
previousList.clear();
previousList.addAll(nearestClusters);
}
nearestClusters= new ArrayList<Integer>();
//Each point is connected to it nearest cluster
for (int j = 0; j < stationsList.size(); ++j) {
nearestClusters.add(getIndexOfTheNearestCluster(stationsList.get(j)));
}
//We move the clusters centroids to the center of the points they are connected to
for (int k = 0; k < clusters.size(); ++k) {
clusters.get(k).setCentre(stationsCenters(getStationsOfCluster(clusters.get(k), nearestClusters)));
}
if (!nearestClusters.isEmpty() && previousList.equals(nearestClusters))
hasConverged = true;
}
}
Yet, I wanted to show the result of my algorithm with the clusters formed and I found this work on the Internet : https://github.com/ertugrulozcan/K-Means-Simulation
I imported in my project the class ClusterGenerator which creates clusters along with random elements, the class Item, the class Graphic (I didn't touch anything there) and the class MainWindow which initiates all the graphic elements.
I did not manage to display the plots and there are no errors in Eclipse that could give me any clue.
Can someone please explain to me where is the problem ?
Thanks

The problem was that my algorithm was generating clusters for the stations but I did not configure the class Graphic (which I understood later was very important for the display) to render correctly my points. Since, I used latitude and longitude as coordinates for my station, I had to put these coordinates to scale for the window. Here is how I did that (using cross multiplications) : I calculate the "gap" between two units in the graph and added an adjustment because I don't start at zero.
double gapX = (this.getWidth() - 2 * edgeSpace) / (topX-bottomX+1);
int adjustmentX =(int) (-bottomX*gapX);
(getWidth() gives the actual width of the panel where is the graph, edgespace is the padding space between the graph and the edge of the panel, topX is the maximum value of a coordinate and bottomX the minimum value)

Related

Performance Related Problem in strategy-game map loading algorithm (Java, lwjgl)

I'm creating a game where you pick a nation and you have to manage it, but I can't find a way to load the map without crashing the program due to massive computation (lack of performance).
I made an algorithm that loops trough every pixel of an image containing the provinces (the spatial unit in the game) of the map, each has their own color, this way, when I encounter a color not yet seen in a pixel, I know that's a new province, and I can therefor load it the new Province() instance with the information from a file.
Everything above said works just fine and takes almost no time at all, but to edit the map when various nations attack each other I need a way to render singularly every province to give it its nation's color with a shader.
I've added this piece of code that gets the current pixel position and it scales it down to openGL coordinates, saving it in an arrayList (currVertices), this is then put into an another ArrayList (provinceVertices) of float[] once a new province is found.
(I know the code is not beautiful and I'm not an expert programmer (also I'm 14) so please try to be kind when telling me what I did wrong,
I've tried just storing a vertex every 4 pixel to make the list smaller, but it still crashes)
List<Float> currVertices = new ArrayList<Float>(); // the vertices of the current province
for (int y = 0; y < worldImage.getHeight(); y++) {
for (int x = 0; x < worldImage.getWidth(); x++) {
if (!currColors.contains(worldImage.getRGB(x, y))) {
if (!currVertices.isEmpty())
provinceVertices.add(Utils.toFloatArray(currVertices)); // store the current province's vertices into the total database
currVertices.clear();
}
if (x % 4 == 0)
currVertices.add((float) (x) / EngineManager.getWindowWidth());
if (y % 4 == 0)
currVertices.add((float) (y) / EngineManager.getWindowHeight());
}
}
I've only included the code representing the loading of the vertices
public static float[] toFloatArray(List<Float> list) {
float[] array = new float[list.size()];
ListIterator<Float> iterator = list.listIterator();
while (iterator.hasNext()) {
array[iterator.nextIndex()] = list.get(iterator.nextIndex());
}
return array;
}
the goal would be for the second ArrayList to have all the vertices in the right order, but when I try and add the currVertices to the provinceVertices the game just crashes with no error message, which is why I'm guessing the problem is performance-related.
(The vertices load fine into the currVertices list)
Using nextIndex() doesn't increse the index. Try to use instead:
while (iterator.hasNext()) {
array[iterator.nextIndex()] = iterator.next();
}

Colouring problem (with 2 colours) where each vertex has a specific area and finding min area coloured using DFS

I have a list of islands/areas, initially white. All vertices connected to each other by 1 edge must have opposite colours. (Either black or white). I wish to use the minimum amount of black to colour the islands. Each island has a different size, and index of islands start from 1.
I have used DFS, and a global object to track both the white and black areas, then giving me the minimum of the two. Assuming the entire graph is not connected and has multiple components. I have reset the global variable for every new component. I don't get the correct answers, and I have no idea where is the mistake in my logic. (I am pretty sure my DFSrec method is correct though)
// this will be the DFS spanning tree for 1 component
private void DFSrec(int v,
boolean[] visitedArr, int[] predecessorArr) {
visitedArr[v] = true;
if (islandsList.get(v).colour.equals("WHITE")) {
p.whiteArea += islandsList.get(v).area;
} else {
p.blackArea += islandsList.get(v).area;
}
for (int neighbour : adjList.get(v)) {
if (!visitedArr[neighbour]) {
predecessorArr[neighbour] = v;
if (islandsList.get(v).colour.equals("WHITE")) {
islandsList.get(neighbour).setColour("BLACK");
} else {
islandsList.get(neighbour).setColour("WHITE");
}
DFSrec(neighbour, visitedArr, predecessorArr);
}
}
}
// covers all components
private int DFS(boolean[] visitedArr, int[] predecessorArr, int numIslands){
int minArea = 0;
for (int v = 1; v <= numIslands; v++) {
if ( !visitedArr[v] ) {
DFSrec(v, visitedArr, predecessorArr);
int minAreaOfComponent = p.minArea();
minArea += minAreaOfComponent;
p = new Pair();
}
}
return minArea;
}
Okay, the DFS answer works.
I just realized that the problem occurred because I didn't add in ALL the edges, because the graph is undirected. If I add edge 2 -> 3 in the list, I needed to add in 3 -> 2 as well.

Finding the next location in a grid

I am creating a method to help me find the next position in a grid of islands/objects in a 3d world(but ignoreing the Y coordinate for now), they have a distance of 200 for each island(islandDistance).
What I currently have is this:
public static Location findLocation(String latest,String server) {
if (latest == null) {
latest = sql.findLatestIslandEntry(server);
if (latest != null && latest.isEmpty()) // first creation
latest = "0,4,0";
else if (latest == null)
return null;
}
String split[] = latest.split(",");
List<String> locationString = Arrays.asList(split);
List<Double> locations = new ArrayList<>();
for (String xyz : locationString) {
locations.add(Double.valueOf(xyz));
}
String world = CC.getSTDConfig().getString("worldname");
Location l = new Location(Bukkit.getWorld(world),0,4,0);
if (locations.get(0) <= 0) {
l.setX(Math.abs(locations.get(0)) + islandDistance);
} else {
l.setX(0 - locations.get(0));
}
if (locations.get(2) <= 0) {
l.setZ(Math.abs(locations.get(2)) + islandDistance);
} else {
l.setZ(0 - locations.get(2));
}
return l;
}
Even before testing I could see that this wouldn't work. I would end always adding to both x and z when thats not always what I want. I made an example of the dataset I want as output here:
Basicly what I want to is to get the next position depending on how many I have already inserted and maybe the last one inserted ? thats the info I use in my code currently atleast. Say I just inserted island number 25 and now want island 26 I should get the result 0,600(the order can be different I just want to fill the grid out)
You want to generate integer coordinates ordered by Euclidean distance. To diminish calculation, it is enough to generate coordinates in the first octant (for 2d case), so X and Y are non-negative and Y<=X. For every calculated (X,Y)pair just generate also (X,-Y), (-X,Y), (-X,-Y),(Y,X),(Y,-X), (-Y,X), (-Y,-X) (except for zero components).
Create priority queue where comparison key is sum of squares (squared distance X*X+Y*Y). Push (0,0) item. At every step extract minimum item (MX, MY) and push next points
Output MX, MY and all permutations
if (MY = 0) and (MX < SomeBorderValue)
push (MX+1, 0)
if MY < MX
push (MX, MY+1)

Finding the minimum-cut value of graph using Kruskal's algorithm

I'm a beginner and I am trying to find the minimum cut of a graph using Kruskal's algorithm in Java.
I have gotten to where I can read the input and create vertexCount^2 number of MST's with random weights for the edges. All I have left to do is figure out from my MST how many cuts are required to separate S and V-S. This will allow me to choose the minimum out of the vertexCount^2 number of choices.
I think I understand correctly that I am supposed to ignore the last edge of the MST to get S and V-S. But I'm lost on how to figure out how many edges are connecting S and V-S.
So my question is: 1) Is vertexCount^2 random MST's enough to be confident that it will contain the minimum-cut? 2) How can I find how many edges are connecting S and V-S?
PS. This is a snippet form my code:
// create weighted edge graph from input.txt
int vertexCount, edgeCount;
Edge edgeTemp;
vertexCount = s.nextInt();
edgeCount = s.nextInt();
EdgeWeightedGraph G = new EdgeWeightedGraph(vertexCount, edgeCount);
for (int j = 0; j < edgeCount; j++) {
edgeTemp = new Edge(s.nextInt(), s.nextInt(), new Random().nextInt(edgeCount));
G.addEdge(edgeTemp);
}
// create kruskal's mst from graph G
for (int j = 0; j < vertexCount*vertexCount; j++) {
KruskalMST mst = new KruskalMST(G);
for (Edge e : mst.edges()) {
System.out.println(e);
}
System.out.println(NEWLINE);
if (j != vertexCount*vertexCount - 2)
G.randomizeWeight(edgeCount);
}
PSS. In case this is relevant, I looked at the code from http://algs4.cs.princeton.edu/43mst/ when writing my code.
When getting the MST from the graph, I used Kruskal's algorithm. That means I must have used union and find methods.
Each vertex is its own parent in the beginning. When getting the union of distinct components from the graph, I assign the combining components (including singletons) to have a single parent. So by the time I'm left with S and V-S, all the vertices of each component will have the same parent!
Therefore, I go back to my EdgeWeightedGraph and iterate all the edges in the graph (not the MST!). When I find an edge whose two vertices have different parents, that means that the edge connects component S and V-S. I count++ every time I see an edge like this.
This gives me the total number of cuts needed in the graph!

Karger's Algorithm

I'm trying to implement the min-cut Karger's algorithm in Java. For this, I created a Graph class which stores a SortedMap, with an integer index as key and a Vertex object as value, and an ArrayList of Edge objects. Edges stores the index of its incident vertices. Than I merge the vertices of some random edge until the number of vertices reach 2. I repeat this steps a safe number of times. Curiously, in my output I get 2x the number of crossing edges. I mean, if the right answer is 10, after execute n times the algorithm (for n sufficient large), the min of these execution results is 20, what makes me believe the implementation is almost correct.
This is the relevant part of code:
void mergeVertex(int iV, int iW) {
for (int i = 0; i < edges.size(); i++) {
Edge e = edges.get(i);
if (e.contains(iW)) {
if (e.contains(iV)) {
edges.remove(i);
i--;
} else {
e.replace(iW, iV);
}
}
}
vertices.remove(iW);
}
public int kargerContraction(){
Graph copy = new Graph(this);
Random r = new Random();
while(copy.getVertices().size() > 2){
int i = r.nextInt(copy.getEdges().size());
Edge e = copy.getEdges().get(i);
copy.mergeVertex(e.getVertices()[0], e.getVertices()[1]);
}
return copy.getEdges().size()/2;
}
Actually the problem was much more simple than I thought. While reading the .txt which contains the graph data, I was counting twice each edge, so logically the minCut returned was 2 times the right minCut.

Categories