Skip to content

Commit a6e867d

Browse files
committed
addressing some comments (6)
1 parent 290f2f0 commit a6e867d

22 files changed

+764
-158
lines changed

fdb-extensions/src/main/java/com/apple/foundationdb/async/hnsw/StorageAdapter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.apple.foundationdb.Transaction;
2525
import com.apple.foundationdb.async.rabitq.EncodedRealVector;
2626
import com.apple.foundationdb.linear.DoubleRealVector;
27+
import com.apple.foundationdb.linear.FloatRealVector;
2728
import com.apple.foundationdb.linear.HalfRealVector;
2829
import com.apple.foundationdb.linear.RealVector;
2930
import com.apple.foundationdb.linear.VectorType;
@@ -278,6 +279,8 @@ static RealVector vectorFromBytes(@Nonnull final HNSW.Config config, @Nonnull fi
278279
switch (fromVectorTypeOrdinal(vectorTypeOrdinal)) {
279280
case HALF:
280281
return HalfRealVector.fromBytes(vectorBytes);
282+
case SINGLE:
283+
return FloatRealVector.fromBytes(vectorBytes);
281284
case DOUBLE:
282285
return DoubleRealVector.fromBytes(vectorBytes);
283286
case RABITQ:

fdb-extensions/src/main/java/com/apple/foundationdb/async/rabitq/EncodedRealVector.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package com.apple.foundationdb.async.rabitq;
2222

2323
import com.apple.foundationdb.linear.DoubleRealVector;
24+
import com.apple.foundationdb.linear.FloatRealVector;
2425
import com.apple.foundationdb.linear.HalfRealVector;
2526
import com.apple.foundationdb.linear.RealVector;
2627
import com.apple.foundationdb.linear.VectorType;
@@ -45,8 +46,14 @@ public class EncodedRealVector implements RealVector {
4546

4647
@Nonnull
4748
private final Supplier<Integer> hashCodeSupplier;
49+
@Nonnull
4850
private final Supplier<double[]> dataSupplier;
51+
@Nonnull
4952
private final Supplier<byte[]> rawDataSupplier;
53+
@Nonnull
54+
private final Supplier<HalfRealVector> toHalfRealVectorSupplier;
55+
@Nonnull
56+
private final Supplier<FloatRealVector> toFloatRealVectorSupplier;
5057

5158
public EncodedRealVector(final int numExBits, @Nonnull final int[] encoded, final double fAddEx, final double fRescaleEx,
5259
final double fErrorEx) {
@@ -56,8 +63,10 @@ public EncodedRealVector(final int numExBits, @Nonnull final int[] encoded, fina
5663
this.fErrorEx = fErrorEx;
5764

5865
this.hashCodeSupplier = Suppliers.memoize(this::computeHashCode);
59-
this.dataSupplier = Suppliers.memoize(() -> computeData(numExBits));
6066
this.rawDataSupplier = Suppliers.memoize(() -> computeRawData(numExBits));
67+
this.dataSupplier = Suppliers.memoize(() -> computeData(numExBits));
68+
this.toHalfRealVectorSupplier = Suppliers.memoize(this::computeHalfRealVector);
69+
this.toFloatRealVectorSupplier = Suppliers.memoize(this::computeFloatRealVector);
6170
}
6271

6372
@Nonnull
@@ -214,9 +223,25 @@ private void packEncodedComponents(final int numExBits, @Nonnull final ByteBuffe
214223
@Nonnull
215224
@Override
216225
public HalfRealVector toHalfRealVector() {
226+
return toHalfRealVectorSupplier.get();
227+
}
228+
229+
@Nonnull
230+
private HalfRealVector computeHalfRealVector() {
217231
return new HalfRealVector(getData());
218232
}
219233

234+
@Nonnull
235+
@Override
236+
public FloatRealVector toFloatRealVector() {
237+
return toFloatRealVectorSupplier.get();
238+
}
239+
240+
@Nonnull
241+
private FloatRealVector computeFloatRealVector() {
242+
return new FloatRealVector(getData());
243+
}
244+
220245
@Nonnull
221246
@Override
222247
public DoubleRealVector toDoubleRealVector() {

fdb-extensions/src/main/java/com/apple/foundationdb/async/rabitq/RaBitQuantizer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ Result encodeInternal(@Nonnull final RealVector data) {
9191
totalCode[i] = signedCode[i] + (sgn << numExBits);
9292
}
9393

94-
// 4) cb = -(2^b - 0.5), and xuCb = signedShift + cb
9594
final double cb = -(((1 << numExBits) - 0.5));
9695
double[] xuCbData = new double[dims];
9796
for (int i = 0; i < dims; i++) {

fdb-extensions/src/main/java/com/apple/foundationdb/linear/ColumnMajorRealMatrix.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,24 @@ public RealMatrix subMatrix(final int startRow, final int lengthRow, final int s
108108
return new ColumnMajorRealMatrix(subData);
109109
}
110110

111+
@Nonnull
112+
@Override
113+
public RowMajorRealMatrix toRowMajor() {
114+
return new RowMajorRealMatrix(transpose().getData());
115+
}
116+
117+
@Nonnull
118+
@Override
119+
public ColumnMajorRealMatrix toColumnMajor() {
120+
return this;
121+
}
122+
123+
@Nonnull
124+
@Override
125+
public RealMatrix quickTranspose() {
126+
return new RowMajorRealMatrix(data);
127+
}
128+
111129
@Override
112130
public final boolean equals(final Object o) {
113131
if (o instanceof ColumnMajorRealMatrix) {

fdb-extensions/src/main/java/com/apple/foundationdb/linear/DoubleRealVector.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,17 @@
3535
public class DoubleRealVector extends AbstractRealVector {
3636
@Nonnull
3737
private final Supplier<HalfRealVector> toHalfVectorSupplier;
38+
@Nonnull
39+
private final Supplier<FloatRealVector> toFloatVectorSupplier;
3840

3941
public DoubleRealVector(@Nonnull final Double[] doubleData) {
4042
this(computeDoubleData(doubleData));
4143
}
4244

4345
public DoubleRealVector(@Nonnull final double[] data) {
4446
super(data);
45-
this.toHalfVectorSupplier = Suppliers.memoize(this::computeHalfVector);
47+
this.toHalfVectorSupplier = Suppliers.memoize(this::computeHalfRealVector);
48+
this.toFloatVectorSupplier = Suppliers.memoize(this::computeFloatRealVector);
4649
}
4750

4851
public DoubleRealVector(@Nonnull final int[] intData) {
@@ -59,15 +62,26 @@ public HalfRealVector toHalfRealVector() {
5962
return toHalfVectorSupplier.get();
6063
}
6164

65+
@Nonnull
66+
public HalfRealVector computeHalfRealVector() {
67+
return new HalfRealVector(data);
68+
}
69+
6270
@Nonnull
6371
@Override
64-
public DoubleRealVector toDoubleRealVector() {
65-
return this;
72+
public FloatRealVector toFloatRealVector() {
73+
return toFloatVectorSupplier.get();
6674
}
6775

6876
@Nonnull
69-
public HalfRealVector computeHalfVector() {
70-
return new HalfRealVector(data);
77+
private FloatRealVector computeFloatRealVector() {
78+
return new FloatRealVector(data);
79+
}
80+
81+
@Nonnull
82+
@Override
83+
public DoubleRealVector toDoubleRealVector() {
84+
return this;
7185
}
7286

7387
@Nonnull
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* HalfRealVector.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.linear;
22+
23+
import com.apple.foundationdb.half.Half;
24+
import com.google.common.base.Suppliers;
25+
import com.google.common.base.Verify;
26+
27+
import javax.annotation.Nonnull;
28+
import java.nio.ByteBuffer;
29+
import java.nio.ByteOrder;
30+
import java.util.function.Supplier;
31+
32+
/**
33+
* A vector class encoding a vector over float components.
34+
*/
35+
public class FloatRealVector extends AbstractRealVector {
36+
@Nonnull
37+
private final Supplier<HalfRealVector> toHalfRealVectorSupplier;
38+
39+
public FloatRealVector(@Nonnull final float[] floatData) {
40+
this(computeDoubleData(floatData));
41+
}
42+
43+
public FloatRealVector(@Nonnull final double[] data) {
44+
super(truncateDoubleData(data));
45+
this.toHalfRealVectorSupplier = Suppliers.memoize(this::computeHalfRealVector);
46+
}
47+
48+
public FloatRealVector(@Nonnull final int[] intData) {
49+
this(fromInts(intData));
50+
}
51+
52+
public FloatRealVector(@Nonnull final long[] longData) {
53+
this(fromLongs(longData));
54+
}
55+
56+
@Nonnull
57+
@Override
58+
public HalfRealVector toHalfRealVector() {
59+
return toHalfRealVectorSupplier.get();
60+
}
61+
62+
@Nonnull
63+
public HalfRealVector computeHalfRealVector() {
64+
return new HalfRealVector(data);
65+
}
66+
67+
@Nonnull
68+
@Override
69+
public FloatRealVector toFloatRealVector() {
70+
return this;
71+
}
72+
73+
@Nonnull
74+
@Override
75+
public DoubleRealVector toDoubleRealVector() {
76+
return new DoubleRealVector(data);
77+
}
78+
79+
@Nonnull
80+
@Override
81+
public RealVector withData(@Nonnull final double[] data) {
82+
return new FloatRealVector(data);
83+
}
84+
85+
/**
86+
* Converts this {@link RealVector} of single precision floating-point numbers into a byte array.
87+
* <p>
88+
* This method iterates through the input vector, converting each {@link Half} element into its 16-bit short
89+
* representation. It then serializes this short into two bytes, placing them sequentially into the resulting byte
90+
* array. The final array's length will be {@code 2 * vector.size()}.
91+
* @return a new byte array representing the serialized vector data. This array is never null.
92+
*/
93+
@Nonnull
94+
@Override
95+
protected byte[] computeRawData() {
96+
final byte[] vectorBytes = new byte[1 + 4 * getNumDimensions()];
97+
final ByteBuffer buffer = ByteBuffer.wrap(vectorBytes).order(ByteOrder.BIG_ENDIAN);
98+
buffer.put((byte)VectorType.SINGLE.ordinal());
99+
for (int i = 0; i < getNumDimensions(); i ++) {
100+
buffer.putFloat((float)data[i]);
101+
}
102+
return vectorBytes;
103+
}
104+
105+
@Nonnull
106+
private static double[] computeDoubleData(@Nonnull float[] floatData) {
107+
double[] result = new double[floatData.length];
108+
for (int i = 0; i < floatData.length; i++) {
109+
result[i] = floatData[i];
110+
}
111+
return result;
112+
}
113+
114+
@Nonnull
115+
private static double[] truncateDoubleData(@Nonnull double[] doubleData) {
116+
double[] result = new double[doubleData.length];
117+
for (int i = 0; i < doubleData.length; i++) {
118+
result[i] = (float)doubleData[i];
119+
}
120+
return result;
121+
}
122+
123+
/**
124+
* Creates a {@link FloatRealVector} from a byte array.
125+
* <p>
126+
* This method interprets the input byte array as a sequence of 16-bit half-precision floating-point numbers. Each
127+
* consecutive pair of bytes is converted into a {@code Half} value, which then becomes a component of the resulting
128+
* vector.
129+
* @param vectorBytes the non-null byte array to convert
130+
* @return a new {@link FloatRealVector} instance created from the byte array
131+
*/
132+
@Nonnull
133+
public static FloatRealVector fromBytes(@Nonnull final byte[] vectorBytes) {
134+
final ByteBuffer buffer = ByteBuffer.wrap(vectorBytes).order(ByteOrder.BIG_ENDIAN);
135+
Verify.verify(buffer.get() == VectorType.SINGLE.ordinal());
136+
final int numDimensions = vectorBytes.length >> 2;
137+
final double[] vectorComponents = new double[numDimensions];
138+
for (int i = 0; i < numDimensions; i ++) {
139+
vectorComponents[i] = buffer.getFloat();
140+
}
141+
return new FloatRealVector(vectorComponents);
142+
}
143+
}

fdb-extensions/src/main/java/com/apple/foundationdb/linear/HalfRealVector.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,13 @@ public HalfRealVector toHalfRealVector() {
5656

5757
@Nonnull
5858
@Override
59-
public DoubleRealVector toDoubleRealVector() {
60-
return new DoubleRealVector(data);
59+
public FloatRealVector toFloatRealVector() {
60+
return new FloatRealVector(data);
6161
}
6262

6363
@Nonnull
64-
public DoubleRealVector computeDoubleVector() {
64+
@Override
65+
public DoubleRealVector toDoubleRealVector() {
6566
return new DoubleRealVector(data);
6667
}
6768

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* MatrixHelpers.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.linear;
22+
23+
import javax.annotation.Nonnull;
24+
import java.util.Random;
25+
26+
public class MatrixHelpers {
27+
@Nonnull
28+
public static RealMatrix randomOrthogonalMatrix(@Nonnull final Random random, final int dimension) {
29+
return QRDecomposition.decomposeMatrix(randomGaussianMatrix(random, dimension, dimension)).getQ();
30+
}
31+
32+
@Nonnull
33+
public static RealMatrix randomGaussianMatrix(@Nonnull final Random random,
34+
final int rowDimension,
35+
final int columnDimension) {
36+
final double[][] resultMatrix = new double[rowDimension][columnDimension];
37+
for (int row = 0; row < rowDimension; row++) {
38+
for (int column = 0; column < columnDimension; column++) {
39+
resultMatrix[row][column] = random.nextGaussian();
40+
}
41+
}
42+
return new RowMajorRealMatrix(resultMatrix);
43+
}
44+
}

fdb-extensions/src/main/java/com/apple/foundationdb/linear/Metric.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,9 @@ public double distance(@Nonnull final double[] vectorData1, @Nonnull final doubl
142142
public double distance(@Nonnull RealVector vector1, @Nonnull RealVector vector2) {
143143
return distance(vector1.getData(), vector2.getData());
144144
}
145+
146+
@Override
147+
public String toString() {
148+
return metricDefinition.toString();
149+
}
145150
}

0 commit comments

Comments
 (0)