HashCode implementation for coordinates - java

To put you in context: I have a coordinate class where I have two attributes: x and y and those represent pixels. I have redefined the equals method and in it I have given a tolerance of C pixels to determine if two coordinates are equal.
I also tried to redefine the hashCode method because I need to put those coordinates as a key for a map. Here's my redefinition:
#Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + this.x;
hash = 67 * hash + this.y;
return hash;
}
Now what I want to do is to create a Coordinate whenever a click occurs and get() that coordinate from my map even if it is up to C pixels from the other coordinate. I think my problem is that since it is not the same x and y, they dont have the same hashcode so get() only works if the click occurs exactly at the same x and y. Is there a way to implement my hashcode so that it has a "tolerance" like my equals() does? Am I doing anything wrong?

Related

How can I cluster data using a distance matrix with the ELKI library?

I have a distance matrix and I want to use that distance matrix when clustering my data.
I've read the ELKI documentation and it states that I can overwrite the distance method when extending the AbstractNumberVectorDistanceFunction class.
The distance class however, returns the coordinates. So from coordinate x to coordinate y. This is troublesome because the distance matrix is filled only with distance values and we use the indexes to find the distance value from index x to index y. Here's the code from the documentation:
public class TutorialDistanceFunction extends AbstractNumberVectorDistanceFunction {
#Override
public double distance(NumberVector o1, NumberVector o2) {
double dx = o1.doubleValue(0) - o2.doubleValue(0);
double dy = o1.doubleValue(1) - o2.doubleValue(1);
return dx * dx + Math.abs(dy);
}
}
My question is how to correctly use the distance matrix when clustering with ELKI.
AbstractNumberVectorDistanceFunction is the approriate parent class only if your input data are number vectors. If your data type is abstract object identifiers, subclass AbstractDBIDRangeDistanceFunction instead. You then have to implement
double distance(int i1, int i2);
There are already different implementations of a distance function for precomputed distances, for example DiskCacheBasedDoubleDistanceFunction that memory-maps a distance matrix stored on disk. We should add a DoubleMatrixDistanceFunction though, for direct use from Java (in the next version, all class names and package names will be shortened, btw).
See also: https://elki-project.github.io/howto/precomputed_distances
in particular the section titled "Using without primary data", on how to set up a database with no primary data, when you only use a distance matrix.

Java Comparable Class - Comparison method violates its general contract

I'm writing an isometric game that renders objects based on their Y coordinate, using a comparable class, sorting by their Y value, which changes. I am getting the error "Comparison method violates its general contract!" and have read about how to return a negative number, 0, or a positive number so I have implemented this:
public boolean equals(Entity e) {
if ((e.y-y)==0)
return (e.id == id);
return (e.y == y);
}
public int compareTo(Entity e) {
if ((e.y-y)==0)
return (e.id - id);
return (int) (e.y - y); // Render order by y coordinate
}
But I'm still getting the error. Is the sorting not going to work if the values change or am I doing something else wrong?
The equals method is not involved in the contract, so we can ignore it.
I suspect that the problem is caused by integer overflow. The problem is that x - y does not always give you a positive answer if x > y and a negative number if x < y. If the difference between the numbers is large enough, then the express x - y will overflow and the result will have the wrong sign.
If that is the problem, then the simple solution is to use Integer.compare(x, y) instead of x - y
Another possibility is that the entities are being mutated at the same time as you are (for example) sorting them.
Float.compare(x, y) has worked much better.
I'd assumed that x and y were int. If they are float then the true cause of the problem is harder to understand. Either way, using Float.compare(x, y) is a better solution.
But if x and y are actually int, then using Float.compare(x, y) will give you incorrect answers for some x and y values. For close values of x and y with large enough magnitudes, the int to float conversion will lose precision, and Float.compare will say they are equal.

Good hashcode function for 2D coordinates

I would like to use a HashMap
to map (x, y) coordinates to values.
What is a good hashCode() function definition?
In this case, I am only storing integer coordinates of the form (x, y)
where y - x = 0, 1, ..., M - 1 for some parameter M.
To get unique Value from two numbers, you can use bijective algorithm described in here
< x; y >= x + (y + ( (( x +1 ) /2) * (( x +1 ) /2) ) )
This will give you unquie value , which can be used for hashcode
public int hashCode()
{
int tmp = ( y + ((x+1)/2));
return x + ( tmp * tmp);
}
I generally use Objects.hash(Object... value) for generating hash code for a sequence of items.
The hash code is generated as if all the input values were placed into an array, and that array were hashed by calling Arrays.hashCode(Object[]).
#Override
public int hashCode() {
return Objects.hash(x, y);
}
Use Objects.hash(x, y, z) for 3D coordinates.
If you wish to handle it manually, you could do compute hashCode using:-
// For 2D coordinates
hashCode = LARGE_PRIME * X + Y;
// For 3D coordinates
hashCode = LARGE_PRIME^2 * X + LARGE_PRIME * Y + Z;
To calculate a hash code for objects with several properties, often a generic solution is implemented. This implementation uses a constant factor to combine the properties, the value of the factor is a subject of discussions. It seems that a factor of 33 or 397 will often result in a good distribution of hash codes, so they are suited for dictionaries.
This is a small example in C#, though it should be easily adabtable to Java:
public override int GetHashCode()
{
unchecked // integer overflows are accepted here
{
int hashCode = 0;
hashCode = (hashCode * 397) ^ this.Hue.GetHashCode();
hashCode = (hashCode * 397) ^ this.Saturation.GetHashCode();
hashCode = (hashCode * 397) ^ this.Luminance.GetHashCode();
return hashCode;
}
}
This scheme should also work for your coordinates, simply replace the properties with the X and Y value. Note that we should prevent integer overflow exceptions, in DotNet this can be achieved by using the unchecked block.
Have you considered simply shifting either x or y by half the available bits?
For "classic" 8bit thats only 16 cells/axis, but with todays "standard" 32bit it grows to over 65k cells/axis.
#override
public int hashCode() {
return x | (y << 15);
}
For obvious reasons this only works as long as both x and y are in between 0 and 0xFFFF (0-65535, inclusive), but thats plenty of space, more than 4.2bio cells.
Edit:
Another option, but that requires you to know the actual size, would be to do x + y * width (where width ofc is in the direction of x)
That depends on what you intend on using the hash code for:
If you plan on using it as a sort of index, E.g. knowing x and y will hash into an index where (x, y) data is stored, it's better to use a vector for such a thing.
Coordinates[][] coordinatesBucket = new Coordinates[maxY][maxX];
But if you absolutely must have a unique hash for every (x, y) combination, then try applying the coordinates to a decimal table (rather than adding or multiplying). For example, x=20 y=40 would give you the simple and unique code xy=2040.

How to set edge's length proportional to edge's value

Using JDK 1.7+Jung2.
I have a similarity matrix and want to analyze it graphically using jung2 graphs. My dataset is composed by data like:
object1 object2 0.54454
object1 object3 0.45634
object2 object3 0.90023
[..]
For each line, the value represents the similarity between the previous objects (i.e.: object1 has 0.54454 similarity with object2)
I want to create a graph where the distance between vertices is proportional to their edge value.
For the example above, the object1 would be placed closer to object2 than to object3, because sim(object1,object2) > sim(object2,object3).
How can I achieve such task using Jung2? Default layouts dont seem to do this.
This depends on the layout that you intend to use. For the SpringLayout, you can pass a Transformer to the constructor as the length_function parameter, that you can simply implement as
class EdgeLengthTransformer implements Transformer<Edge, Integer> {
#Override
public Integer transform(Edge edge) {
int minLength = 100; // Length for similarity 1.0
int maxLength = 500; // Length for similarity 0.0
Vertex v0 = graph.getSource(edge);
Vertex v1 = graph.getDest(edge);
float similarity = obtainSimilarityFromYourDataset(v0, v1);
int length = (int)(minLength + (1.0 - similarity) * (maxLength - minLength));
return length;
}
}
You'll always have to take into account that - depending on the structure of the graph - it might simply not be possible to lay out the vertices as desired. For example, if the similarities do not obey the http://en.wikipedia.org/wiki/Triangle_inequality , then there is no suitable embedding of these similarities into the 2D space.

Searching for a different instance of the same exact object, within a set

I have a set, in the World class, for an object called collidable:
Set<Collidable> collidables = new HashSet<Collidable>();
While trying to develop a collision detection system (for a ball), I made two for loops, for X and Y.
cboxX = (int) Math.floor(position.x - RADIUS);
cboxY = (int) Math.floor(position.y - RADIUS);
cboxW = Math.abs((int) Math.ceil(nextPosition.x + RADIUS) - (int) Math.floor(position.x - RADIUS));
cboxH = Math.abs((int) Math.ceil(nextPosition.y + RADIUS) - (int) Math.floor(position.y - RADIUS));
for (int x = cboxX; x <= cboxW + cboxX - 1; x++)
{
for (int y = cboxY; y <= cboxH + cboxY; y++)
{
}
}
Everything is good here. However, inside the for loop, I am trying to check for collidables with x and y parameters, but due to the fact that I am creating a new instance of a collidable (albeit with the exact same parameters as one that was previously generated), it will always turn up false:
world.collidables.add(new Block(new Vector2(x, y)));
System.out.println(world.collidables.contains(new Block(new Vector2(x, y)))); //returns false
However, if I use the same instance of block, it will turn up true:
Block b = new Block(new Vector2(x, y))
world.collidables.add(b);
System.out.println(world.collidables.contains(b)); //returns true
This is unacceptable however, as the entire reason for having two for loops was to not have to iterate over every collidable, every update.
What I'm asking is, does anyone know of a way to get whether a collidable is at the location I am specifying, without having to iterate over the entire set?
You need to provide you own implementation of two methods:
int hashCode()
boolean equals(Object o)
These methods should be implemented such that c1.hashCode() == c2.hashCode() if and only if the attributes (vectors) of the two instances are equal. At the same time hashCode() must be consistent with equals(Object o) in the sense stated by documentation:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

Categories