-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added missing sparse cube implementation files
Missed in the original commit.
- Loading branch information
1 parent
5a28095
commit 113e789
Showing
8 changed files
with
4,152 additions
and
0 deletions.
There are no files selected for viewing
371 changes: 371 additions & 0 deletions
371
java/src/main/java/com/deshaw/hypercube/DoubleSparseHypercube.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,371 @@ | ||
package com.deshaw.hypercube; | ||
|
||
// Recreate with `cog -rc DoubleSparseHypercube.java` | ||
// [[[cog | ||
// import cog | ||
// import numpy | ||
// import primitive_sparse_hypercube | ||
// | ||
// cog.outl(primitive_sparse_hypercube.generate(numpy.float64)) | ||
// ]]] | ||
import com.deshaw.util.concurrent.LongToLongConcurrentCuckooHashMap; | ||
import com.deshaw.util.concurrent.LongToLongConcurrentCuckooHashMap.Iterator; | ||
|
||
import java.util.Map; | ||
import java.util.logging.Level; | ||
|
||
/** | ||
* A hypercube which has double values as its elements and stores them | ||
* in a sparse map. | ||
* | ||
* <p>The capacity of these sparse cubes currently maxes out somewhere around | ||
* 5e8 elements. The actual limit will depend on the distribution of your | ||
* entries in the cube. | ||
*/ | ||
public class DoubleSparseHypercube | ||
extends AbstractDoubleHypercube | ||
{ | ||
/** | ||
* The primitive null value as a long. | ||
*/ | ||
private static final long NULL = double2long(Double.NaN); | ||
|
||
/** | ||
* The map which we use to store the values. | ||
*/ | ||
private final LongToLongConcurrentCuckooHashMap myMap; | ||
|
||
// ---------------------------------------------------------------------- | ||
|
||
// Some simple mapping functions; named like this for ease of cogging. | ||
// They should be trivially inlined by the JVM. | ||
|
||
/** | ||
* Convert a {@code long} to a {@code double}. | ||
*/ | ||
private static double long2double(final long v) | ||
{ | ||
return Double.longBitsToDouble(v); | ||
} | ||
|
||
/** | ||
* Convert a {@code double} to a {@code long}. | ||
*/ | ||
private static long double2long(final double v) | ||
{ | ||
return Double.doubleToRawLongBits(v); | ||
} | ||
|
||
/** | ||
* Convert a {@code long} to a {@code float}. | ||
*/ | ||
private static float long2float(final long v) | ||
{ | ||
return Float.intBitsToFloat((int)(v & 0xffffffffL)); | ||
} | ||
|
||
/** | ||
* Convert a {@code float} to a {@code long}. | ||
*/ | ||
private static long float2long(final float v) | ||
{ | ||
return ((long)Float.floatToRawIntBits(v)) & 0xffffffffL; | ||
} | ||
|
||
/** | ||
* Convert a {@code long} to an {@code int}. | ||
*/ | ||
private static int long2int(final long v) | ||
{ | ||
return (int)v; | ||
} | ||
|
||
/** | ||
* Convert an {@code int} to a {@code long}. | ||
*/ | ||
private static long int2long(final int v) | ||
{ | ||
return v; | ||
} | ||
|
||
/** | ||
* Convert a {@code long} to a {@code long}. | ||
*/ | ||
private static long long2long(final long v) | ||
{ | ||
return v; | ||
} | ||
|
||
// ---------------------------------------------------------------------- | ||
|
||
/** | ||
* Constructor with a default loading of {@code 0.1}. | ||
*/ | ||
public DoubleSparseHypercube(final Dimension<?>[] dimensions) | ||
throws IllegalArgumentException, | ||
NullPointerException | ||
{ | ||
this(dimensions, 0.1); | ||
} | ||
|
||
/** | ||
* Constructor with a given loading. | ||
*/ | ||
public DoubleSparseHypercube(final Dimension<?>[] dimensions, final double loading) | ||
throws IllegalArgumentException, | ||
NullPointerException | ||
{ | ||
super(dimensions); | ||
|
||
final int capacity = | ||
(int)Math.max(13, | ||
Math.min(Integer.MAX_VALUE, | ||
getSize() * Math.max(0.0, Math.min(1.0, loading)))); | ||
myMap = new LongToLongConcurrentCuckooHashMap(capacity); | ||
|
||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void toFlattenedObjs(final long srcPos, | ||
final Double[] dst, | ||
final int dstPos, | ||
final int length) | ||
throws IllegalArgumentException, | ||
IndexOutOfBoundsException, | ||
UnsupportedOperationException | ||
{ | ||
if (LOG.isLoggable(Level.FINEST)) { | ||
LOG.finest( | ||
"Flattening with " + | ||
"srcPos=" + srcPos + " dst=" + dst + " dstPos=" + dstPos + " " + | ||
"length=" + length | ||
); | ||
} | ||
|
||
// Check the arguments | ||
checkFlattenArgs(srcPos, dst, dstPos, length); | ||
|
||
preRead(); | ||
for (int i=0; i < length; i++) { | ||
dst[dstPos + i] = long2double(myMap.get(srcPos + i)); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void fromFlattenedObjs(final Double[] src, | ||
final int srcPos, | ||
final long dstPos, | ||
final int length) | ||
throws IllegalArgumentException, | ||
IndexOutOfBoundsException, | ||
NullPointerException | ||
{ | ||
if (LOG.isLoggable(Level.FINEST)) { | ||
LOG.finest( | ||
"Unflattening with " + | ||
"src=" + src + " srcPos=" + srcPos + " dstPos=" + dstPos + " " + | ||
"length=" + length | ||
); | ||
} | ||
|
||
// Check input | ||
checkUnflattenArgs(srcPos, dstPos, length); | ||
if (src == null) { | ||
throw new NullPointerException("Given a null sparse"); | ||
} | ||
if (src.length - srcPos < length) { | ||
throw new IndexOutOfBoundsException( | ||
"Source position, " + srcPos + ", " + | ||
"plus length ," + length + ", " + | ||
"was greater than the sparse size, " + src.length | ||
); | ||
} | ||
|
||
// Safe to copy in | ||
for (int i=0; i < length; i++) { | ||
final Double value = src[srcPos + i]; | ||
mapPut( | ||
dstPos + i, | ||
double2long( | ||
(value == null) ? Double.NaN : value.doubleValue() | ||
) | ||
); | ||
} | ||
postWrite(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void toFlattened(final long srcPos, | ||
final double[] dst, | ||
final int dstPos, | ||
final int length) | ||
throws IllegalArgumentException, | ||
IndexOutOfBoundsException, | ||
UnsupportedOperationException | ||
{ | ||
if (LOG.isLoggable(Level.FINEST)) { | ||
LOG.finest( | ||
"Flattening with " + | ||
"srcPos=" + srcPos + " dst=" + dst + " dstPos=" + dstPos + " " + | ||
"length=" + length | ||
); | ||
} | ||
|
||
// Check the arguments | ||
checkFlattenArgs(srcPos, dst, dstPos, length); | ||
|
||
preRead(); | ||
for (int i=0; i < length; i++) { | ||
dst[dstPos + i] = long2double(myMap.get(srcPos + i, NULL)); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void fromFlattened(final double[] src, | ||
final int srcPos, | ||
final long dstPos, | ||
final int length) | ||
throws IllegalArgumentException, | ||
IndexOutOfBoundsException, | ||
NullPointerException | ||
{ | ||
if (LOG.isLoggable(Level.FINEST)) { | ||
LOG.finest( | ||
"Unflattening with " + | ||
"src=" + src + " srcPos=" + srcPos + " dstPos=" + dstPos + " " + | ||
"length=" + length | ||
); | ||
} | ||
|
||
// Sanitise input | ||
checkUnflattenArgs(srcPos, dstPos, length); | ||
if (src == null) { | ||
throw new NullPointerException("Given a null sparse"); | ||
} | ||
|
||
// Safe to copy in | ||
for (int i=0; i < length; i++) { | ||
mapPut(dstPos + i, double2long(src[srcPos + i])); | ||
} | ||
postWrite(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public double get(final long... indices) | ||
throws IndexOutOfBoundsException | ||
{ | ||
return getAt(toOffset(indices)); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void set(final double d, final long... indices) | ||
throws IndexOutOfBoundsException | ||
{ | ||
setAt(toOffset(indices), d); | ||
postWrite(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public Double getObjectAt(final long index) | ||
throws IndexOutOfBoundsException | ||
{ | ||
preRead(); | ||
return Double.valueOf(getAt(index)); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void setObjectAt(final long index, final Double value) | ||
throws IndexOutOfBoundsException | ||
{ | ||
setAt(index, (value == null) ? Double.NaN : value.doubleValue()); | ||
postWrite(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public double getAt(final long index) | ||
throws IndexOutOfBoundsException | ||
{ | ||
if (index < 0 || index >= getSize()) { | ||
throw new IndexOutOfBoundsException( | ||
"Index " + index + " was outside the range of the cube's size, " + getSize() | ||
); | ||
} | ||
preRead(); | ||
return long2double(myMap.get(index, NULL)); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void setAt(final long index, final double value) | ||
throws IndexOutOfBoundsException | ||
{ | ||
if (index < 0 || index >= getSize()) { | ||
throw new IndexOutOfBoundsException( | ||
"Index " + index + " was outside the range of the cube's size, " + getSize() | ||
); | ||
} | ||
mapPut(index, double2long(value)); | ||
postWrite(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
protected Map<String,Boolean> createFlags() | ||
{ | ||
final Map<String,Boolean> result = super.createFlags(); | ||
result.put("aligned", false); | ||
result.put("behaved", false); | ||
result.put("c_contiguous", false); | ||
result.put("owndata", true); | ||
result.put("writeable", true); | ||
return result; | ||
} | ||
|
||
/** | ||
* Put a value into the map, in such a way that understand NULLs. | ||
*/ | ||
private void mapPut(final long index, final long value) | ||
{ | ||
// If we happen to be inserting a NULL then that really means we are | ||
// removing an entry from the sparse map | ||
if (value == NULL) { | ||
myMap.remove(index); | ||
} | ||
else { | ||
myMap.put(index, value); | ||
} | ||
} | ||
} | ||
|
||
// [[[end]]] (checksum: 7a064e0963bdf6be05eededdb3904777) |
Oops, something went wrong.