Generate object coordinates in relation to neighbours - java

I am making a game in which i have randomly spawned objects. I also have a table that has the data of which objects are close to one another, say within a range of 200px - lets call them neighbors. What i want is to generate and assign coordinates to all the available objects so that this relationship is reflected. I want to view the structure of how they are.
I have made a greedy algorithm. Which works very slowly. and gets stuck sometimes. Does anyone have a better approach to this? - the coordinates can be assigned dynamically through trial and error no problem.
Below is the current code classes.
/**
* biggest problem
* */
public void assignInitialCoords( MyObject[] objects )
{
objects[0].setxCoor(rand.nextInt(1000));
objects[0].setyCoor(rand.nextInt(1000));
for(int i=0; i<objects.length; i++ )
{
ArrayList<MyObject> neighs = objects[i].getNeighbours();
System.out.println("Assigning " + objects[i].getId() + "'s coors");
setNonNeighborCoords(objects, i);
setNeighborCoordinates(objects, i, neighs);
System.out.println(objects[i].getId() + "(" + objects[i].getxCoor() + ", " + objects[i].getyCoor() + ")\n");
}
}
The classes
import java.util.ArrayList;
import java.util.HashMap;
public class MyObject
{
public ArrayList<MyObject> neighbours;
public ArrayList<MyObject> nonNeighbours;
public double fov = 360;
public double sRange = 100, xCoor, yCoor;
boolean isClustered = false;
public String id;
//Cluster[] clusters;
public MyObject()
{
neighbours = new ArrayList<MyObject>();
nonNeighbours = new ArrayList<MyObject>();
}
/**
* Find neighbours for this Object given a relations table
* example: if a MyObject has id A, and neighbor is B, then the key can be either: A_B or B_A
* Both represent the same relation, so we only need to check it once
* */
public void findNeighbours(HashMap<String, Integer> table, MyObject[] objects)
{
for (int i = 0; i < objects.length; i++)
{
String key1 = getId() + "_" + objects[i].getId(), key2 = objects[i].getId() +"_" + getId(), key="";
if(table.get(key1) != null)
{
key = key1;
if(table.get(key) <= getsRange())
getNeighbours().add(objects[i]);
}
if(table.get(key2) != null)
{
key = key2;
if(table.get(key) <= getsRange())
getNeighbours().add(objects[i]);
}
}
}
/**
* Check whether a given Object is the neighbour ArrayList of this object
* */
public boolean isInNeighbours( MyObject n )
{
if(neighbours.equals(null)) { return false; }
for(int i=0; i<getNeighbours().size(); i++)
if(getNeighbours().get(i).getId().equals(n.getId())) { return true; }
return false;
}
/**
* Check whether a given Object is the noneighbour ArrayList of this object
* */
public boolean isInNonNeighbours( MyObject n )
{
if(nonNeighbours.equals(null)) { return false; }
for(int i=0; i<getNonNeighbours().size(); i++)
if(getNonNeighbours().get(i).getId().equals(n.getId())) { return true; }
return false;
}
/**
* Check if given MyObject Can be a neighbour to this Object - for rand coord generation
* */
public boolean canBeANeighbour(MyObject n)
{
return distanceTo(n) <= sRange;
}
// return Euclidean distance between this and p
public double distanceTo(MyObject p) {
double dx = this.xCoor - p.xCoor;
double dy = this.yCoor - p.yCoor;
return Math.sqrt(dx*dx + dy*dy);
}
//Setters And Getters
public ArrayList<MyObject> getNeighbours(){ return neighbours; }
public void setNeighbours(ArrayList<MyObject> neighbours)
{
this.neighbours = neighbours;
}
public double getFov()
{
return fov;
}
public void setFov(double fov)
{
this.fov = fov;
}
public double getsRange()
{
return sRange;
}
public void setsRange(double sRange)
{
this.sRange = sRange;
}
public double getxCoor()
{
return xCoor;
}
public void setxCoor(double xCoor)
{
this.xCoor = xCoor;
}
public double getyCoor()
{
return yCoor;
}
public void setyCoor(double yCoor)
{
this.yCoor = yCoor;
}
public boolean isClustered()
{
return isClustered;
}
public void setClustered(boolean isClustered)
{
this.isClustered = isClustered;
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public ArrayList<MyObject> getNonNeighbours()
{
return nonNeighbours;
}
public void setNonNeighbours(ArrayList<MyObject> nonNeighbours)
{
this.nonNeighbours = nonNeighbours;
}
}
//The sample test:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
public class SampleField
{
Random rand = new Random();
public int range = 100;
HashMap<String, Integer> table = new HashMap<String, Integer>();
String[] nodeIds = {"A", "B", "C", "D", "E", "F"};
public MyObject[] objects = new MyObject[nodeIds.length];
public static void main(String[] args)
{
SampleField test = new SampleField();
for(MyObject n: test.objects)
{
n.findNeighbours(test.table, test.objects);
}
test.populateNonNeighbours(test.objects);
System.out.println(test.table);
test.printRelationsTable( test.objects );
test.assignInitialCoords(test.objects);
System.out.println(test.table);
test.printRelationsTable( test.objects );
}
public SampleField()
{
initialiseNodes();
generateTestTable(objects);
}
/**
* biggest problem
* */
public void assignInitialCoords( MyObject[] objects )
{
objects[0].setxCoor(rand.nextInt(1000));
objects[0].setyCoor(rand.nextInt(1000));
for(int i=0; i<objects.length; i++ )
{
ArrayList<MyObject> neighs = objects[i].getNeighbours();
System.out.println("Assigning " + objects[i].getId() + "'s coors");
setNonNeighborCoords(objects, i);
setNeighborCoordinates(objects, i, neighs);
System.out.println(objects[i].getId() + "(" + objects[i].getxCoor() + ", " + objects[i].getyCoor() + ")\n");
}
}
/**
* if this object has neighbours, try to set their coordinates so that they do not conflict
*
* #param objects
* #param i
* #param neighs
*/
private void setNeighborCoordinates(MyObject[] objects, int i, ArrayList<MyObject> neighs)
{
//it should have at least one neighbour
if(neighs != null )
for( int j=0; j<neighs.size(); j++ )
{
//Initial assignment to the first neighbor
neighs.get(j).setxCoor(rand.nextInt() + objects[i].getsRange() );
neighs.get(j).setyCoor(rand.nextInt() + objects[i].getsRange() );
//If not a neighbor keep generating coordinates until it keeps being a neighbor.
while( !objects[i].canBeANeighbour(neighs.get(j)) )
{
//go deeper? - later
neighs.get(j).setxCoor(rand.nextInt(1000) - shootRange() - 5 );
neighs.get(j).setyCoor(rand.nextInt(1000) - shootRange() - 5 );
}
}
}
/**
* try to set the coordinates of each object here
* #param objects
* #param i
*/
private void setNonNeighborCoords(MyObject[] objects, int i)
{
for(MyObject n : objects[i].getNonNeighbours())
{
n.setxCoor(rand.nextInt() + shootRange() - 5);
n.setyCoor(rand.nextInt() + shootRange() - 5);
//Make sure non neighbors remain non neighbors
while(objects[i].canBeANeighbour(n))
{
n.setxCoor(rand.nextInt() + shootRange() - 5 );
n.setyCoor(rand.nextInt() + shootRange() - 5 );
}
}
}
/* populate nonNeighbours */
public void populateNonNeighbours(MyObject[] objects)
{
for(int i=0; i<objects.length; i++)
{
for(int j=0; j<objects.length; j++ )
{
if( (objects[i].getId() != objects[j].getId()) && !objects[i].isInNeighbours(objects[j]) )
{
objects[i].getNonNeighbours().add(objects[j]);
}
}
}
}
/* Show each object and its neighbors/nonneighbors - just for output */
public void printRelationsTable( MyObject[] objects )
{
for(int i=0; i<objects.length; i++ )
{
System.out.print("MyObject " + objects[i].getId() + "'s neighbours: ");
for(int j=0; j<objects[i].getNeighbours().size(); j++)
{
System.out.print(objects[i].getNeighbours().get(j).getId() + " ");
}
System.out.println();
System.out.print("\t\t" +objects[i].getId()+ "' : ");
for(int j=0; j<objects[i].getNonNeighbours().size(); j++)
{
System.out.print(objects[i].getNonNeighbours().get(j).getId() + " ");
}
System.out.println();
}
}
/* Initialise Objects here - give basic information */
public void initialiseNodes()
{
for(int i=0; i<nodeIds.length; i++)
{
MyObject n = new MyObject();
n.setId(nodeIds[i]);
n.setsRange(shootRange());
objects[i] = n;
}
}
/* Generate a list of neighbors for testing */
public void generateTestTable(MyObject[] objects)
{
for(int i=0; i<objects.length; i++)
{
/* Get two objects' ids and make them neighbors - ids must be unique */
String firstId = objects[rand.nextInt(objects.length)].getId();
String secondId = objects[rand.nextInt(objects.length)].getId();
while( firstId.equals(secondId) || table.containsKey(firstId + "_" + secondId) || table.containsKey(secondId + "_" + firstId) )
{
firstId = objects[rand.nextInt(objects.length)].getId();
secondId = objects[rand.nextInt(objects.length)].getId();
}
table.put(firstId + "_" + secondId, shootRange());
}
}
/* Range within which they are neighbors */
public int shootRange()
{
return range;
}
public void setRange(int range)
{
this.range = range;
}
}

If you only compare distances (and if you are talking about neighbours, it seems so), then you don't need to count them at all. Instead of
range = sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
if (range >d)...
use
sqrange(a,b) = sqr(a.x-b.x)+sqr(a.y-b.y)
if (range> d_sqr) ...
That means, you don't use ranges, but their squares. That quickens the comparisons about 50 times (for double). So, you can use much more easy structures.

Related

Calculating distance between non directly-connected nodes in matrix

I made a adjacency matrix for cities and connecting between them. And for example A-B, B-C, C-D. Now I am wonder if I can calculate distance between cities that aren't connected. Is it possible to calculate distance in matrix between non connected nodes and find path?
Cities class
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class GraphCities {
private List<String> cities;
private int[][] matrix;
Scanner s = new Scanner(System.in);
public GraphCities() {
this.cities = new LinkedList<String>();
}
public void addCity(String name) {
if (!cities.contains(name)) {
cities.add(name);
} else {
System.out.println("City " + name + " is already added.");
}
}
public void makeGraph() {
System.out
.println("Distance between cities, if they aren't connected insert -1");
matrix = new int[cities.size()][cities.size()];
for (int i = 0; i < matrix.length; i++) {
for (int j = i; j < matrix.length; j++) {
if (i == j) {
matrix[i][j] = 0;
} else {
System.out.println("Distance from "
+ cities.get(i) + " to " + cities.get(j));
int distance = s.nextInt();
matrix[i][j] = distance;
matrix[j][i] = distance;
}
}
}
}
public void show() {
String show = "\t";
for (int i = 0; i < cities.size(); i++) {
show += cities.get(i) + "\t";
}
show += "\n";
for (int i = 0; i < matrix.length; i++) {
show += cities.get(i) + "\t";
for (int j = 0; j < matrix.length; j++) {
if (matrix[i][j] != -1) {
show += matrix[i][j] + "\t";
} else {
show += "-\t";
}
}
show += "\n";
}
System.out.println(show);
}
}
Main method
public class Main {
public static void main(String[] args) {
GraphCities c = new GraphCities();
c.addCity("A");
c.addCity("B");
c.addCity("C");
c.addCity("D");
c.addCity("E");
c.makeGraph();
System.out.println();
c.show();
}
}
This is my output when i run main method and i think everything is ok.
A B C D E
A 0 50 - - -
B 50 0 30 - -
C - 30 0 40 -
D - - 40 0 20
E - - - 20 0
Now I want to calculate distance from A to D, but i haven't any idea how to do it. I will appreciate any help. Thanks!
To find the shortest path in a weighted graph (each part of the route has a different weight) you can use Dijkstra's Shortest Path Algorithm.
The following code is a one-file mcve. It can be copy-pasted into one file (Main.java) , and executed.
(This answer is base on the code posted before editing the question)
Please note the comments:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) {
AdjList aList = new AdjList();
CityNode a = new CityNode("A");
CityNode b = new CityNode("B");
CityNode c = new CityNode("C");
CityNode d = new CityNode("D");
CityNode e = new CityNode("E");
aList.addCity(a);
aList.addCity(b);
aList.addCity(c);
aList.addCity(d);
aList.addCity(e);
aList.connectCities(a, b, 50);
aList.connectCities(b, c, 30);
aList.connectCities(c, d, 40);
aList.connectCities(d, e, 20);
aList.show();
FindPath findPath = new FindPath();
System.out.println(findPath.calculateShortestPath(aList, a, e)); //prints 140 as expected
//add some complexity
CityNode f = new CityNode("F");
aList.addCity(f);
aList.connectCities(b, f, 10);
aList.connectCities(f, d, 10);
System.out.println(findPath.calculateShortestPath(aList, a, e));//prints 90 as expected
}
}
class FindPath{
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
Map<CityNode, Integer> distances;
//using Dijkstra algorithm
public int calculateShortestPath(AdjList aList, CityNode from, CityNode to) {
//a container to hold which cities the algorithm has visited
Set<CityNode> settledCities = new HashSet<>();
//a container to hold which cities the algorithm has to visit
Set<CityNode> unsettledCities = new HashSet<>();
unsettledCities.add(from);
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
distances = new HashMap<>();
//initialize map with values: 0 distance to origin, infinite distance to all others
//infinite means no connection between nodes
for(CityNode city :aList.getCities()){
int distance = city.equals(from) ? 0 : Integer.MAX_VALUE;
distances.put(city, distance);
}
while (unsettledCities.size() != 0) {
//get the unvisited city with the lowest distance
CityNode currentCity = getLowestDistanceCity(unsettledCities);
//remove from unvisited, add to visited
unsettledCities.remove(currentCity); settledCities.add(currentCity);
Map<CityNode, Integer> connectedCities = currentCity.getConnectedCities();
for( CityNode city : connectedCities.keySet()){
//check if new distance is shorted than the previously found distance
if(distances.get(currentCity) + connectedCities.get(city) < distances.get(city)){
//if so, keep the shortest distance found
distances.put(city, distances.get(currentCity) + connectedCities.get(city));
//if city has not been visited yet, add it to unsettledCities
if(! settledCities.contains(city)) {
unsettledCities.add(city);
}
}
}
}
return distances.get(to);
}
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
return unsettledCities.stream()
.min((c1,c2)-> Integer.compare(distances.get(c1), distances.get(c2)))
.orElse(null);
}
}
class CityNode {
private static int counter =0;
private final String name;
//assign unique id to each node. safer than to rely on unique name
private final int id = counter ++;
//map to hold all connected cities and distance to each
private final Map<CityNode, Integer> connectedCities;
public CityNode(String name) {
super();
this.name = name;
connectedCities = new HashMap<>();
}
public String getName() {
return name;
}
//not null safe. distance must not be negative
public void connect(CityNode connectTo, int distance) {
if(connectTo.equals(this)) throw new IllegalArgumentException("Node can not connect to istself");
connectedCities.put(connectTo, distance);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder(name);
sb.append(connectedCities.keySet().isEmpty() ? " not connected" : " conntected to: " );
for ( CityNode city : connectedCities.keySet()) {
sb.append(city.getName()).append("-")
.append(connectedCities.get(city)).append("km ");
}
return sb.toString();
}
public int getId() {
return id;
}
public Map<CityNode, Integer> getConnectedCities(){
return connectedCities;
}
#Override
public boolean equals(Object o) {
if(o == null ||!(o instanceof CityNode)) return false;
CityNode c = (CityNode) o;
return c.getName().equalsIgnoreCase(name) && id == c.getId();
}
#Override
public int hashCode() {
int hash = 31 * 7 + id;
return name == null ? hash : name.hashCode();
}
}
class AdjList {
//use set which prevents duplicate entries
private final Set<CityNode> citiesList;
public AdjList() {
citiesList = new HashSet<>();
}
//adds city if is not already present. returns true if city was added
public boolean addCity(CityNode city) {
return citiesList.add(city);
}
//not null safe
public void connectCities(CityNode city1, CityNode city2, int distance) {
//assuming undirected graph
city1.connect(city2, distance);
city2.connect(city1, distance);
}
public CityNode getCityByName(String name) {
for (CityNode city : citiesList) {
if (city.getName().equalsIgnoreCase(name))
return city;
}
return null;
}
public void show() {
for (CityNode city : citiesList) {
System.out.println(city);
}
}
//get a copy of cities list
public Collection<CityNode> getCities(){
return new ArrayList<>(citiesList);
}
}
If you need a version of getLowestDistanceCity which does not use Stream use :
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
CityNode lowestDistanceCity = null;
int lowestDistance = Integer.MAX_VALUE;
for (CityNode city: unsettledCities) {
int nodeDistance = distances.get(city);
if (nodeDistance < lowestDistance) {
lowestDistance = nodeDistance;
lowestDistanceCity = city;
}
}
return lowestDistanceCity;
}
Edit: an implementation using adjacency matrix could look like this:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class DijkstraAdjacencyMatrix {
public static void main(String[] args) {
Set<CityNode> cities = new HashSet<>();
CityNode a = new CityNode("A");
CityNode b = new CityNode("B");
CityNode c = new CityNode("C");
CityNode d = new CityNode("D");
CityNode e = new CityNode("E");
cities.addAll(List.of(a,b,c,d,e));
CitiesGraph graph = new CitiesGraph(cities);
graph.connectCities(a, b, 50);
graph.connectCities(b, c, 30);
graph.connectCities(c, d, 40);
graph.connectCities(d, e, 20);
graph.show();
FindPath findPath = new FindPath();
System.out.println(findPath.calculateShortestPath(graph, a, e)); //prints 140 as expected
//to add some complexity we need to construct a new CitiesGraph. It is not reusable
CityNode f = new CityNode("F");
cities.add(f);
graph = new CitiesGraph(cities);
graph.connectCities(a, b, 50);
graph.connectCities(b, c, 30);
graph.connectCities(c, d, 40);
graph.connectCities(d, e, 20);
graph.connectCities(b, f, 10);
graph.connectCities(f, d, 10);
graph.show();
System.out.println(findPath.calculateShortestPath(graph, a, e));//prints 90 as expected
}
}
class FindPath{
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
Map<CityNode, Integer> distances;
//using Dijkstra algorithm
public int calculateShortestPath(CitiesGraph graph, CityNode from, CityNode to) {
//a container to hold which cities the algorithm has visited
Set<CityNode> settledCities = new HashSet<>();
//a container to hold which cities the algorithm has to visit
Set<CityNode> unsettledCities = new HashSet<>();
unsettledCities.add(from);
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
distances = new HashMap<>();
//initialize map with values: 0 distance to origin, infinite distance to all others
//infinite means no connection between nodes
for(CityNode city :graph.getCities()){
int distance = city.equals(from) ? 0 : Integer.MAX_VALUE;
distances.put(city, distance);
}
while (unsettledCities.size() != 0) {
//get the unvisited city with the lowest distance
CityNode currentCity = getLowestDistanceCity(unsettledCities);
//remove from unvisited, add to visited
unsettledCities.remove(currentCity); settledCities.add(currentCity);
Collection<CityNode> connectedCities = graph.getCitiesConnectedTo(currentCity);
//iterate over connected city to update distance to each
for( CityNode city : connectedCities){
//check if new distance is shorted than the previously found distance
int distanceToCity = graph.getDistanceBetween(city, currentCity);
if(distanceToCity <= 0) {
continue;
}
if(distances.get(currentCity) + distanceToCity < distances.get(city)){
//if so, keep the shortest distance found
distances.put(city,distances.get(currentCity) + distanceToCity);
//if city has not been visited yet, add it to unsettledCities
if(! settledCities.contains(city)) {
unsettledCities.add(city);
}
}
}
}
return distances.get(to);
}
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
return unsettledCities.stream()
.min((c1,c2)-> Integer.compare(distances.get(c1), distances.get(c2)))
.orElse(null);
}
}
class CityNode {
private static int counter =0;
private final String name;
//assign unique id to each node. safer than to rely on unique name
private final int id = counter ++;
public CityNode(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("City ");
sb.append(name).append(" (id=").append(id).append(")");
return sb.toString();
}
public int getId() {
return id;
}
#Override
public boolean equals(Object o) {
if(o == null || !(o instanceof CityNode)) return false;
CityNode c = (CityNode) o;
return c.getName().equalsIgnoreCase(name) && id == c.getId();
}
#Override
public int hashCode() {
int hash = 31 * 7 + id;
return name == null ? hash : name.hashCode();
}
}
class CitiesGraph{
//use set which prevents duplicate entries
private final Set<CityNode> cities;
private final int[][] adjacencyMatrix;
private static final int NOT_CONNECTED = -1;
public CitiesGraph(Set<CityNode> cities) {
this.cities = cities;
adjacencyMatrix = new int[cities.size()][cities.size()];
//initialize matrix
for(int row = 0; row < adjacencyMatrix.length ; row++){
for(int col = 0; col < adjacencyMatrix[row].length ; col++){
adjacencyMatrix[row][col] = row == col ? 0 : NOT_CONNECTED ;
}
}
}
public void connectCities(CityNode city1, CityNode city2, int distance) {
//assuming undirected graph
adjacencyMatrix[city1.getId()][city2.getId()] = distance;
adjacencyMatrix[city2.getId()][city1.getId()] = distance;
}
public int getDistanceBetween(CityNode city1, CityNode city2) {
return adjacencyMatrix[city1.getId()][city2.getId()];
}
public Collection<CityNode> getCitiesConnectedTo(CityNode city) {
Collection<CityNode> connectedCities = new ArrayList<>();
//iterate over row representing city's connections
int column = 0;
for(int distance : adjacencyMatrix[city.getId()]){
if(distance != NOT_CONNECTED && distance > 0) {
connectedCities.add(getCityById(column));
}
column++;
}
return connectedCities;
}
public CityNode getCityById(int id) {
for (CityNode city : cities) {
if (city.getId() == id) return city;
}
return null;
}
public void show() {
for(int[] row : adjacencyMatrix){
System.out.println(Arrays.toString(row));
}
}
//get a copy of cities list
public Collection<CityNode> getCities(){
return new ArrayList<>(cities);
}
}

Find the mode of a list of either Strings or Integers using a HashMap in Java?

I've been stuck on this code for a few days now and I cannot figure it out.
The getMedian method works fine and prints out the median of both the string list and integer list. The getMode function I know is close to correct but I cannot get it to work properly and I'm trying to use a HashMap to get it to work. Currently, it will not print mode unless I change the getMode method to "int". The big issue is getting it to output both the mode of the String list and Integer list, just like the median. I could really use some help with this.
/*
* Accepts Array of String or Integer and provides methods to return the mode and median
*
*/
package stats;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ModeNMedianProblem<E>
{
private final List<E> elements;
public ModeNMedianProblem(E[] items)
{
elements = new ArrayList<>();
elements.addAll(Arrays.asList(items));
}
private class GenericComparator implements Comparator<E>
{
#Override
public int compare(E o1, E o2)
{
if (o1.getClass() == Integer.class)
{
Integer v1 = (Integer)o1;
Integer v2 = (Integer)o2;
return v1.compareTo(v2);
}
else if (o1.getClass() == String.class)
{
String v1 = (String)o1;
String v2 = (String)o2;
return v1.compareTo(v2);
}
else
{
throw new IllegalArgumentException("Classes of type " + o1.getClass().toGenericString() + " are not supported.");
}
}
}
/**
*
* #param args
* #return
*/
public List<E> getSortedList()
{
Collections.sort(elements,new GenericComparator());
return elements;
}
public E getMedian() {
int half = elements.size() / 2;
return elements.get(half);
}
public E getMode() {
Map<E,Integer> freq = new HashMap<>();
int mode = 0, maxCount = 0;
int length = freq.size();
for (int i = 0; i < length; ++i)
{
int count = 0;
for (int j = 0; j < length; ++j)
{
if (freq.get(i) == freq.get(j))
++count;
if (count > maxCount)
{
maxCount = count;
mode = freq.get(i);
}
}
}
return mode;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
String[] s = {"and","an","the","my","but","may","an","the","the"};
Integer[] x = {1,5,9,2,4,3,7,100,2};
ModeNMedianProblem mn1 = new ModeNMedianProblem(s);
System.out.println("List: " + mn1.getSortedList());
System.out.println("Median: " + mn1.getMedian());
System.out.println("Mode: " + mn1.getMode());
mn1 = new ModeNMedianProblem(x);
System.out.println("List: " + mn1.getSortedList());
System.out.println("Median: " + mn1.getMedian());
System.out.println("Mode: " + mn1.getMode());
}
}

Simple prisoner's dilemma genetic algorithm

I have used an existing genetic algorithm from
here
and reworked it I but don't know what I'm doing wrong
This is the error that I get
Exception in thread "main" java.lang.NullPointerException at
simpleGa.Algorithm.crossover(Algorithm.java:69) at
simpleGa.Algorithm.evolvePopulation(Algorithm.java:34) at
simpleGa.GAprisonerdilemma.main(GAprisonerdilemma.java:41)
I can't figure out exactly where the mistake is. Read a lot about NullPointerException but couldn't figure it out
package simpleGa;
public class Population {
public static Individual[] individuals;
/*
* Constructors
*/
// Create a population
public Population(int populationSize, boolean initialise) {
individuals = new Individual[populationSize];
// Initialise population
if (initialise) {
// Loop and create individuals
for (int i = 0; i < size(); i++) {
Individual newIndividual = new Individual();
newIndividual.generateIndividual();
saveIndividual(i, newIndividual);
}
for(int i=0;i<size();i++)
{
if(i%2==1){Individual individual1=individuals[i-1];
Individual individual2=individuals[i];
if(individuals[i-1].getGene(i-1)==0 && individuals[i].getGene(i)==0){
individuals[i-1].fitness=individual1.fitness+1;
individuals[i].fitness=individual2.fitness+1;
}
if(individuals[i-1].getGene(i-1)==1 && individuals[i].getGene(i)==1){
individuals[i-1].fitness=individual1.fitness+2;
individuals[i].fitness=individual2.fitness+2;
}
if(individuals[i-1].getGene(i-1)==0 && individuals[i].getGene(i)==1){
individuals[i-1].fitness=individual1.fitness+3;
individuals[i].fitness=individual2.fitness+0;
}
if(individuals[i-1].getGene(i-1)==1 && individuals[i].getGene(i)==0){
individuals[i-1].fitness=individual1.fitness+0;
individuals[i].fitness=individual2.fitness+3;
}
}}}
}
/* Getters */
public Individual getIndividual(int index) {
return individuals[index];
}
public Individual getFittest() {
Individual fittest = individuals[0];
// Loop through individuals to find fittest
for (int i = 1; i < size(); i++) {
if (fittest.getFitness() <= getIndividual(i).getFitness()) {
fittest = getIndividual(i);
}
}
return fittest;
}
/* Public methods */
// Get population size
public int size() {
return individuals.length;
}
// Save individual
public void saveIndividual(int index, Individual indiv) {
individuals[index] = indiv;
}
}
package simpleGa;
public class Individual {
static int defaultGeneLength = 1000;
private long[] genes =new long [defaultGeneLength];
// Cache
public static int fitness = 0;
// Create a random individual
public void generateIndividual() {
for (int i = 0; i < size(); i++) {
long gene = Math.round(Math.random());
genes[i] = gene;
}
}
/* Getters and setters */
// Use this if you want to create individuals with different gene lengths
public static void setDefaultGeneLength(int length) {
defaultGeneLength = length;
}
public long getGene(int i) {
return genes[i];
}
public void setGene(int index, long value) {
genes[index] = value;
fitness = 0;
}
/* Public methods */
public int size() {
return genes.length;
}
public static int getFitness() {
return fitness;
}
public void setFitness(int i) {
fitness=i;
}
#Override
public String toString() {
String geneString = "";
for (int i = 0; i < size(); i++) {
geneString += getGene(i);
}
return geneString;
}
}
package simpleGa;
public class Algorithm {
/* GA parameters */
private static final double uniformRate = 0.5;
private static final double mutationRate = 0.015;
private static final int tournamentSize = 5;
private static final boolean elitism = true;
/* Public methods */
// Evolve a population
public static Population evolvePopulation(Population pop) {
Population newPopulation = new Population(pop.size(), false);
// Keep our best individual
if (elitism) {
newPopulation.saveIndividual(0, pop.getFittest());
}
// Crossover population
int elitismOffset;
if (elitism) {
elitismOffset = 1;
} else {
elitismOffset = 0;
}
// Loop over the population size and create new individuals with
// crossover
for (int i = elitismOffset; i < pop.size(); i++) {
Individual indiv1 = tournamentSelection(pop);
Individual indiv2 = tournamentSelection(pop);
Individual newIndiv = crossover(indiv1, indiv2);
newPopulation.saveIndividual(i, newIndiv);
}
// Mutate population
for (int i = elitismOffset; i < newPopulation.size(); i++) {
mutate(newPopulation.getIndividual(i));
}
for(int i=0;i<pop.size();i++)
{for(int j=0;j<pop.getIndividual(i).size();j++)
{if(i%2==1){Individual individual1=Population.individuals[i-1];
Individual individual2=Population.individuals[i];
if(Population.individuals[i-1].getGene(i-1)==0 && Population.individuals[i].getGene(i)==0){
Population.individuals[i-1].fitness=individual1.fitness+1;
Population.individuals[i].fitness=individual2.fitness+1;
}
if(Population.individuals[i-1].getGene(i-1)==1 && Population.individuals[i].getGene(i)==1){
Population.individuals[i-1].fitness=individual1.fitness+2;
Population.individuals[i].fitness=individual2.fitness+2;
}
if(Population.individuals[i-1].getGene(i-1)==0 && Population.individuals[i].getGene(i)==1){
Population.individuals[i-1].fitness=individual1.fitness+3;
Population.individuals[i].fitness=individual2.fitness+0;
}
if(Population.individuals[i-1].getGene(i-1)==1 && Population.individuals[i].getGene(i)==0){
Population.individuals[i-1].fitness=individual1.fitness+0;
Population.individuals[i].fitness=individual2.fitness+3;
} }}}``
return newPopulation;
}
// Crossover individuals
private static Individual crossover(Individual indiv1, Individual indiv2) {
Individual newSol = new Individual();
// Loop through genes
for (int i = 0; i < indiv1.size(); i++) {
// Crossover
if (Math.random() <= uniformRate) {
newSol.setGene(i, indiv1.getGene(i));
} else {
newSol.setGene(i, indiv2.getGene(i));
}
}
return newSol;
}
// Mutate an individual
private static void mutate(Individual indiv) {
// Loop through genes
for (int i = 0; i < indiv.size(); i++) {
if (Math.random() <= mutationRate) {
// Create random gene
long gene = Math.round(Math.random());
indiv.setGene(i, gene);
}
}
}
// Select individuals for crossover
private static Individual tournamentSelection(Population pop) {
// Create a tournament population
Population tournament = new Population(tournamentSize, false);
// For each place in the tournament get a random individual
for (int i = 0; i < tournamentSize; i++) {
int randomId = (int) (Math.random() * pop.size());
tournament.saveIndividual(i, pop.getIndividual(randomId));
}
// Get the fittest
Individual fittest = tournament.getFittest();
return fittest;
}
package simpleGa;
public class FitnessCalc {
/* Public methods */
// Set a candidate solution as a byte array
// To make it easier we can use this method to set our candidate solution
// with string of 0s and 1s
// Calculate inidividuals fittness by comparing it to our candidate solution
static int getFitness(Individual individual) {
int fitness = 0;
// Loop through our individuals genes and compare them to our cadidates
fitness=Individual.fitness;
return fitness;
}
}
// Get optimum fitness
}
package simpleGa;
import java.util.Scanner;
public class GAprisonerdilemma {
public static void main(String[] args) {
// Set a candidate solution
Scanner keyboard = new Scanner(System.in);
System.out.println("Input number of games!");
int k = keyboard.nextInt();
Individual.setDefaultGeneLength(k);
// Create an initial population
System.out.println("Input number of individuals in the population!");
int p = keyboard.nextInt();
Population myPop = new Population(p, true);
System.out.println("Input acceptable number of generations!");
int l = keyboard.nextInt();
// Evolve our population until we reach an optimum solution
int generationCount = 0;
int j=l+1;
System.out.println("Input requiered fitness value !");
int f = keyboard.nextInt();
int h=0;
// Evolve our population until we reach an optimum solution
for(int i=0;i<j;i++)
{
if(i==0){}
else{
if(myPop.getFittest().getFitness()>=f){if(h==0){h++;}
else{ System.out.println("Solution found!");
System.out.println("Generation: " + generationCount);
System.out.println( "Fitness(Points): " + myPop.getFittest().getFitness());
break;}
}else {myPop = Algorithm.evolvePopulation(myPop);
generationCount++;
System.out.println("Generation: " + generationCount + " Fittest: " + myPop.getFittest().getFitness());
}
if(i==j-1){ if(myPop.getFittest().getFitness()>=f)System.out.println("Solution found !");
else System.out.println("Solution not found closest solution is!");
System.out.println("Generation: " + generationCount);
System.out.println( " Fitness(Points): " + myPop.getFittest().getFitness());}
}
}
System.out.println("0 for betrays in that turn 1 for cooperates!");
System.out.println("Turns:");
System.out.println(myPop.getFittest());
}
}

Can't locate the problems in this simple Genetic Algorithm program

I have written a simple genetic algorithm program in java. What it is does is maximize the decimal value represented by the bits in the chromosome. Somehow mutation is not working as expected, e.g. causing two genes to mutate when just one is to change. The print statements I have included there show which to mutate, but in addition to that some more chromosomes get mutated. I can't figure out what the problem is :-(
Here are my java classes.
Gene.java
public class Gene {
private int value;
public Gene() {
value = Math.random() < 0.5 ? 0 : 1;
}
public Gene(int value) {
if (value != 0 && value != 1) {
throw new IllegalArgumentException("value must be either 0 or 1");
}
else {
this.value = value;
}
}
public void mutate() {
value = 1 - value;
}
public int value() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}
Chromosome.java
import java.util.ArrayList;
import java.util.List;
public class Chromosome implements Comparable {
private ArrayList<Gene> genes;
private final int chromosomeLength;
public Chromosome(int length) {
this.genes = new ArrayList<>();
this.chromosomeLength = length > 0 ? length : 16;
for (int i = 0; i < chromosomeLength; i++) {
this.genes.add(i, new Gene());
}
}
public List<Gene> getAllele(int fromIndex, int toIndex) {
return new ArrayList<>(genes.subList(fromIndex, toIndex));
}
public void setAllele(int fromIndex, List<Gene> allele) {
int lastIndex = fromIndex + allele.size();
if (lastIndex > chromosomeLength) {
throw new IndexOutOfBoundsException("the allele exceeds beyond the size of the chromosome");
}
for (int i = fromIndex, j = 0; i < lastIndex; i++, j++) {
genes.set(i, allele.get(j));
}
}
public int getChromosomeLength() {
return chromosomeLength;
}
public void setGeneAt(int index, Gene gene) {
genes.set(index, gene);
}
public Gene getGeneAt(int index) {
return genes.get(index);
}
public int value() {
return Integer.parseInt(this.toString(), 2);
}
#Override
public String toString() {
StringBuilder chromosome = new StringBuilder("");
genes.stream().forEach((Gene g) -> chromosome.append(g));
return chromosome.toString();
}
#Override
public int compareTo(Object anotherChromosome) {
Chromosome c = (Chromosome) anotherChromosome;
return this.value() - c.value();
}
}
GenePool.java
import java.util.ArrayList;
import java.util.Arrays;
public class GenePool {
private final ArrayList<Chromosome> genePool;
private final int genePoolSize;
private final int chromosomeLength;
private final double crossOverRate;
private final double mutationRate;
private int[] crossPoints;
public GenePool(int numOfChromosome, int chromosomeLength, double crossOverRate, double mutationRate) {
this.genePoolSize = numOfChromosome;
this.chromosomeLength = chromosomeLength > 0 ? chromosomeLength : 16;
this.crossOverRate = crossOverRate;
this.mutationRate = mutationRate;
crossPoints = new int[1];
crossPoints[0] = this.chromosomeLength / 2;
genePool = new ArrayList<>();
for (int i = 0; i < numOfChromosome; i++) {
genePool.add(new Chromosome(chromosomeLength));
}
}
public int getGenePoolSize() {
return genePoolSize;
}
public Chromosome getChromosomeAt(int index) {
return genePool.get(index);
}
public void setChromosomeAt(int index, Chromosome c) {
genePool.set(index, c);
}
public int getChromosomeLength() {
return chromosomeLength;
}
public Chromosome[] crossOver(Chromosome c1, Chromosome c2) {
Chromosome[] offsprings = new Chromosome[2];
offsprings[0] = new Chromosome(c1.getChromosomeLength());
offsprings[1] = new Chromosome(c1.getChromosomeLength());
Chromosome[] parentChromosomes = {c1, c2};
int selector = 0;
for (int i = 0, start = 0; i <= crossPoints.length; i++) {
int crossPoint = i == crossPoints.length ? c1.getChromosomeLength() : crossPoints[i];
offsprings[0].setAllele(start, parentChromosomes[selector].getAllele(start, crossPoint));
offsprings[1].setAllele(start, parentChromosomes[1 - selector].getAllele(start, crossPoint));
selector = 1 - selector;
start = crossPoint;
}
return offsprings;
}
public void mutateGenePool() {
int totalGeneCount = genePoolSize * chromosomeLength;
System.out.println("Mutating genes:");
for (int i = 0; i < totalGeneCount; i++) {
double prob = Math.random();
if (prob < mutationRate) {
System.out.printf("Chromosome#: %d\tGene#: %d\n", i / chromosomeLength, i % chromosomeLength);
genePool.get(i / chromosomeLength).getGeneAt(i % chromosomeLength).mutate();
}
}
System.out.println("");
}
public int getLeastFitIndex() {
int index = 0;
int min = genePool.get(index).value();
int currentValue;
for (int i = 1; i < genePoolSize; i++) {
currentValue = genePool.get(i).value();
if (currentValue < min) {
index = i;
min = currentValue;
}
}
return index;
}
public void saveFittest(ArrayList<Chromosome> offsprings) {
// sort in ascending order
offsprings.sort(null);
offsprings.stream().forEach((offspring) -> {
int leastFitIndex = getLeastFitIndex();
if (offspring.value() > genePool.get(leastFitIndex).value()) {
genePool.set(leastFitIndex, offspring);
}
});
}
public void evolve(int noOfGeneration) {
for (int generation = 1; generation <= noOfGeneration; generation++) {
System.out.println("Generation :" + generation);
ArrayList<Integer> selection = new ArrayList<>();
for (int i = 0; i < genePoolSize; i++) {
if (Math.random() <= crossOverRate) {
selection.add(i);
}
}
if (selection.size() % 2 == 1) {
selection.remove(selection.size() - 1);
}
ArrayList<Chromosome> offsprings = new ArrayList<>();
for (int i = 0; i < selection.size(); i += 2) {
int index1 = selection.get(i);
int index2 = selection.get(i + 1);
offsprings.addAll(Arrays.asList(crossOver(genePool.get(index1), genePool.get(index2))));
}
System.out.println("Before saving the offsprings");
displayChromosomes(genePool, "GenePool");
displayChromosomes(offsprings, "Offsprings");
saveFittest(offsprings);
System.out.println("Before mutation:");
displayChromosomes(genePool, "GenePool");
mutateGenePool();
System.out.println("After mutation:");
displayChromosomes(genePool, "GenePool");
System.out.println("\n\n");
}
}
public void displayChromosomes(ArrayList<Chromosome> geneList, String name) {
System.out.println(name);
if (geneList.isEmpty()) {
System.out.println("Empty list");
}
geneList.stream().forEach((c) -> {
System.out.println(c + " -> " + c.value());
});
System.out.println("");
}
}
GADemo.java
public class GADemo {
public static void main(String[] args) {
GenePool gp = new GenePool(6, 8, 0.25, 0.01);
gp.evolve(10);
}
}
After evolving for a number of generations, the chromosomes all tend to become exactly the same, or very similar. And the problem is that that value is not the maximum for that many bits, and sometimes even a small value. For example, for 8 bits the values should (tend to) approach 255, but this doesn't do so in my code. Someone please provide a hint where/how to look for and solve the problem.
Focus on these lines and imagine the references. These are from setAllele()
for (int i = fromIndex, j = 0; i < lastIndex; i++, j++) {
genes.set(i, allele.get(j));
}
You are basically copying the reference from one onto the other. They are the same Gene so whatever mutation you do on those genes, will also affect even other Chromosomes.
You must produce a deep copy here.
Initially each chromosome has an own list of genes. But when you do the crossover operation you set gene objects from one chromosome into the gene list of other chromosome.
When you evolve the system, the number of shared genes will rise and therefore ultimately all chromosomes will share the same genes. No matter how you mutate a gene the chromosomes are not affected.
EDIT:
As Incognito also answered the setAllele method seems to be the culprit where gene sharing starts. You may want to introduce a method in the gene class where you can set its value given another gene.

Sort dates in Java

I want to list dates from the most current date to the oldest date.
I don't want to use Collections.sort()so I made my own method.
When I do this :
List<Livre> maBibliotheque = new ArrayList<Livre>();
boolean tri = false;
int born = maBibliotheque.size();
while (tri == false)
{
tri = true ;
for (int i=0; i<born-1;i++)
{
if ( maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i+1).getNewPeriode())>0){
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i+1));
maBibliotheque.set(i+1,livre);
tri = false ; }
}
born -= born;
}
It works perfectly, but from the oldest to the newest date, but I want the otherwise.
I change this line to
if ( maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i+1).getNewPeriode())<0){
But it's doesn't make anything, no sort dates in this case. Please help
To reverse the order, replace > 0 with < 0
Doesn't
born -= born;
do the same as
born = 0;
I suspect this isn't needed.
This
public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException {
List<Livre> maBibliotheque = new ArrayList<Livre>();
maBibliotheque.add(new Livre("aaa"));
maBibliotheque.add(new Livre("abb"));
maBibliotheque.add(new Livre("bbb"));
maBibliotheque.add(new Livre("000"));
boolean tri;
int born = maBibliotheque.size();
do {
tri = true;
for (int i = 0; i < born - 1; i++) {
if (maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i + 1).getNewPeriode()) > 0) {
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i + 1));
maBibliotheque.set(i + 1, livre);
tri = false;
}
}
} while (!tri);
System.out.println("increasing: " + maBibliotheque);
do {
tri = true;
for (int i = 0; i < born - 1; i++) {
if (maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i + 1).getNewPeriode()) < 0) {
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i + 1));
maBibliotheque.set(i + 1, livre);
tri = false;
}
}
} while (!tri);
System.out.println("decreasing: " + maBibliotheque);
}
static class Livre {
private final String newPeriode;
Livre(String newPeriode) {
this.newPeriode = newPeriode;
}
public String getNewPeriode() {
return newPeriode;
}
#Override
public String toString() {
return "Livre{" +
"newPeriode='" + newPeriode + '\'' +
'}';
}
}
prints
increasing: [Livre{newPeriode='000'}, Livre{newPeriode='aaa'}, Livre{newPeriode='abb'}, Livre{newPeriode='bbb'}]
decreasing: [Livre{newPeriode='bbb'}, Livre{newPeriode='abb'}, Livre{newPeriode='aaa'}, Livre{newPeriode='000'}]
Sort from oldest to newest, then reverse it with Collections.reverse(maBibliotheque);
I would recommend implementing a Comparator. You set a field in the Comparator object that can tell it whether to sort Ascending or Descending, then call Collections.sort(maBibliotheque, new MyComparator(MyComparator.DESC))
Demo (adjust generics as needed, and if, as in this case, you know that you're comparing with a specific field use o1.getField().compareTo(o2.getField()). Alternately, you could implement Comparable in your Object and just call Collections.sort(List), but that's not as flexible.
public class MyComparator implements Comparator<String>
{
public static final int ASC = 0;
public static final int DESC = 1;
private final int sortOrder;
public MyComparator(int sortOrder)
{
this.sortOrder = sortOrder;
}
/* (non-Javadoc)
* #see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
#Override
public int compare(String o1, String o2)
{
switch(this.sortOrder)
{
case ASC:
return o1.compareTo(o2);
case DESC:
return o2.compareTo(o1);
}
return 0;
}
}

Categories

Resources