Refactor vectorization support in Lucene (#12410)

This commit is contained in:
Uwe Schindler 2023-07-03 11:39:19 +02:00 committed by GitHub
parent 907883f701
commit fde2e50d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 364 additions and 110 deletions

View File

@ -159,6 +159,9 @@ Other
* GITHUB#12404: Remove usage and add some legacy java.util classes to forbiddenapis (Stack, Hashtable, Vector).
(Uwe Schindler)
* GITHUB#12410: Refactor vectorization support (split provider from implementation classes).
(Uwe Schindler, Chris Hegarty)
======================== Lucene 9.7.0 =======================
API Changes

View File

@ -15,12 +15,11 @@
* limitations under the License.
*/
package org.apache.lucene.util;
package org.apache.lucene.internal.vectorization;
/** The default VectorUtil provider implementation. */
final class VectorUtilDefaultProvider implements VectorUtilProvider {
final class DefaultVectorUtilSupport implements VectorUtilSupport {
VectorUtilDefaultProvider() {}
DefaultVectorUtilSupport() {}
@Override
public float dotProduct(float[] a, float[] b) {

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.internal.vectorization;
/** Default provider returning scalar implementations. */
final class DefaultVectorizationProvider extends VectorizationProvider {
private final VectorUtilSupport vectorUtilSupport;
DefaultVectorizationProvider() {
vectorUtilSupport = new DefaultVectorUtilSupport();
}
@Override
public VectorUtilSupport getVectorUtilSupport() {
return vectorUtilSupport;
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.internal.vectorization;
/**
* Interface for implementations of VectorUtil support.
*
* @lucene.internal
*/
public interface VectorUtilSupport {
/** Calculates the dot product of the given float arrays. */
float dotProduct(float[] a, float[] b);
/** Returns the cosine similarity between the two vectors. */
float cosine(float[] v1, float[] v2);
/** Returns the sum of squared differences of the two vectors. */
float squareDistance(float[] a, float[] b);
/** Returns the dot product computed over signed bytes. */
int dotProduct(byte[] a, byte[] b);
/** Returns the cosine similarity between the two byte vectors. */
float cosine(byte[] a, byte[] b);
/** Returns the sum of squared differences of the two byte vectors. */
int squareDistance(byte[] a, byte[] b);
}

View File

@ -15,9 +15,10 @@
* limitations under the License.
*/
package org.apache.lucene.util;
package org.apache.lucene.internal.vectorization;
import java.lang.Runtime.Version;
import java.lang.StackWalker.StackFrame;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.AccessController;
@ -25,36 +26,51 @@ import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.apache.lucene.util.SuppressForbidden;
import org.apache.lucene.util.VectorUtil;
/** A provider of VectorUtil implementations. */
interface VectorUtilProvider {
/**
* A provider of vectorization implementations. Depending on the Java version and availability of
* vectorization modules in the Java runtime this class provides optimized implementations (using
* SIMD) of several algorithms used throughout Apache Lucene.
*
* @lucene.internal
*/
public abstract class VectorizationProvider {
/** Calculates the dot product of the given float arrays. */
float dotProduct(float[] a, float[] b);
/**
* Returns the default instance of the provider matching vectorization possibilities of actual
* runtime.
*
* @throws UnsupportedOperationException if the singleton getter is not called from known Lucene
* classes.
*/
public static VectorizationProvider getInstance() {
ensureCaller();
return Objects.requireNonNull(
Holder.INSTANCE, "call to getInstance() from subclass of VectorizationProvider");
}
/** Returns the cosine similarity between the two vectors. */
float cosine(float[] v1, float[] v2);
VectorizationProvider() {
// no instance/subclass except from this package
}
/** Returns the sum of squared differences of the two vectors. */
float squareDistance(float[] a, float[] b);
/**
* Returns a singleton (stateless) {@link VectorUtilSupport} to support SIMD usage in {@link
* VectorUtil}.
*/
public abstract VectorUtilSupport getVectorUtilSupport();
/** Returns the dot product computed over signed bytes. */
int dotProduct(byte[] a, byte[] b);
// *** Lookup mechanism: ***
/** Returns the cosine similarity between the two byte vectors. */
float cosine(byte[] a, byte[] b);
/** Returns the sum of squared differences of the two byte vectors. */
int squareDistance(byte[] a, byte[] b);
// -- provider lookup mechanism
static final Logger LOG = Logger.getLogger(VectorUtilProvider.class.getName());
private static final Logger LOG = Logger.getLogger(VectorizationProvider.class.getName());
/** The minimal version of Java that has the bugfix for JDK-8301190. */
static final Version VERSION_JDK8301190_FIXED = Version.parse("20.0.2");
private static final Version VERSION_JDK8301190_FIXED = Version.parse("20.0.2");
static VectorUtilProvider lookup(boolean testMode) {
// visible for tests
static VectorizationProvider lookup(boolean testMode) {
final int runtimeVersion = Runtime.version().feature();
if (runtimeVersion >= 20 && runtimeVersion <= 21) {
// is locale sane (only buggy in Java 20)
@ -62,32 +78,34 @@ interface VectorUtilProvider {
LOG.warning(
"Java runtime is using a buggy default locale; Java vector incubator API can't be enabled: "
+ Locale.getDefault());
return new VectorUtilDefaultProvider();
return new DefaultVectorizationProvider();
}
// is the incubator module present and readable (JVM providers may to exclude them or it is
// build with jlink)
if (!vectorModulePresentAndReadable()) {
LOG.warning(
"Java vector incubator module is not readable. For optimal vector performance, pass '--add-modules jdk.incubator.vector' to enable Vector API.");
return new VectorUtilDefaultProvider();
return new DefaultVectorizationProvider();
}
if (!testMode && isClientVM()) {
LOG.warning("C2 compiler is disabled; Java vector incubator API can't be enabled");
return new VectorUtilDefaultProvider();
return new DefaultVectorizationProvider();
}
try {
// we use method handles with lookup, so we do not need to deal with setAccessible as we
// have private access through the lookup:
final var lookup = MethodHandles.lookup();
final var cls = lookup.findClass("org.apache.lucene.util.VectorUtilPanamaProvider");
final var cls =
lookup.findClass(
"org.apache.lucene.internal.vectorization.PanamaVectorizationProvider");
final var constr =
lookup.findConstructor(cls, MethodType.methodType(void.class, boolean.class));
try {
return (VectorUtilProvider) constr.invoke(testMode);
return (VectorizationProvider) constr.invoke(testMode);
} catch (UnsupportedOperationException uoe) {
// not supported because preferred vector size too small or similar
LOG.warning("Java vector incubator API was not enabled. " + uoe.getMessage());
return new VectorUtilDefaultProvider();
return new DefaultVectorizationProvider();
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable th) {
@ -95,15 +113,15 @@ interface VectorUtilProvider {
}
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new LinkageError(
"VectorUtilPanamaProvider is missing correctly typed constructor", e);
"PanamaVectorizationProvider is missing correctly typed constructor", e);
} catch (ClassNotFoundException cnfe) {
throw new LinkageError("VectorUtilPanamaProvider is missing in Lucene JAR file", cnfe);
throw new LinkageError("PanamaVectorizationProvider is missing in Lucene JAR file", cnfe);
}
} else if (runtimeVersion >= 22) {
LOG.warning(
"You are running with Java 22 or later. To make full use of the Vector API, please update Apache Lucene.");
}
return new VectorUtilDefaultProvider();
return new DefaultVectorizationProvider();
}
private static boolean vectorModulePresentAndReadable() {
@ -112,7 +130,7 @@ interface VectorUtilProvider {
.filter(m -> m.getName().equals("jdk.incubator.vector"))
.findFirst();
if (opt.isPresent()) {
VectorUtilProvider.class.getModule().addReads(opt.get());
VectorizationProvider.class.getModule().addReads(opt.get());
return true;
}
return false;
@ -143,4 +161,32 @@ interface VectorUtilProvider {
return false;
}
}
private static boolean isValidCaller(String cn) {
// add any class that is allowed to call getInstance()
// NOTE: the list here is lazy
return Stream.of(VectorUtil.class).map(Class::getName).anyMatch(cn::equals);
}
private static void ensureCaller() {
final boolean validCaller =
StackWalker.getInstance()
.walk(
s ->
s.skip(2)
.limit(1)
.map(StackFrame::getClassName)
.allMatch(VectorizationProvider::isValidCaller));
if (!validCaller) {
throw new UnsupportedOperationException(
"VectorizationProvider is internal and can only be used by known Lucene classes.");
}
}
/** This static holder class prevents classloading deadlock. */
private static final class Holder {
private Holder() {}
static final VectorizationProvider INSTANCE = lookup(false);
}
}

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Internal implementations to support SIMD vectorization. This package is for internal Lucene use
* only!
*
* @see org.apache.lucene.internal.vectorization.VectorizationProvider
*/
package org.apache.lucene.internal.vectorization;

View File

@ -17,10 +17,14 @@
package org.apache.lucene.util;
import org.apache.lucene.internal.vectorization.VectorUtilSupport;
import org.apache.lucene.internal.vectorization.VectorizationProvider;
/** Utilities for computations with numeric arrays */
public final class VectorUtil {
private static final VectorUtilProvider PROVIDER = VectorUtilProvider.lookup(false);
private static final VectorUtilSupport IMPL =
VectorizationProvider.getInstance().getVectorUtilSupport();
private VectorUtil() {}
@ -33,7 +37,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
float r = PROVIDER.dotProduct(a, b);
float r = IMPL.dotProduct(a, b);
assert Float.isFinite(r);
return r;
}
@ -47,7 +51,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
float r = PROVIDER.cosine(a, b);
float r = IMPL.cosine(a, b);
assert Float.isFinite(r);
return r;
}
@ -57,7 +61,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
return PROVIDER.cosine(a, b);
return IMPL.cosine(a, b);
}
/**
@ -69,7 +73,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
float r = PROVIDER.squareDistance(a, b);
float r = IMPL.squareDistance(a, b);
assert Float.isFinite(r);
return r;
}
@ -79,7 +83,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
return PROVIDER.squareDistance(a, b);
return IMPL.squareDistance(a, b);
}
/**
@ -144,7 +148,7 @@ public final class VectorUtil {
if (a.length != b.length) {
throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length);
}
return PROVIDER.dotProduct(a, b);
return IMPL.dotProduct(a, b);
}
/**

View File

@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.util;
package org.apache.lucene.internal.vectorization;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Logger;
import jdk.incubator.vector.ByteVector;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.IntVector;
@ -28,8 +25,7 @@ import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorShape;
import jdk.incubator.vector.VectorSpecies;
/** A VectorUtil provider implementation that leverages the Panama Vector API. */
final class VectorUtilPanamaProvider implements VectorUtilProvider {
final class PanamaVectorUtilSupport implements VectorUtilSupport {
private static final int INT_SPECIES_PREF_BIT_SIZE = IntVector.SPECIES_PREFERRED.vectorBitSize();
@ -37,14 +33,6 @@ final class VectorUtilPanamaProvider implements VectorUtilProvider {
private static final VectorSpecies<Byte> PREF_BYTE_SPECIES;
private static final VectorSpecies<Short> PREF_SHORT_SPECIES;
/**
* x86 and less than 256-bit vectors.
*
* <p>it could be that it has only AVX1 and integer vectors are fast. it could also be that it has
* no AVX and integer vectors are extremely slow. don't use integer vectors to avoid landmines.
*/
private final boolean hasFastIntegerVectors;
static {
if (INT_SPECIES_PREF_BIT_SIZE >= 256) {
PREF_BYTE_SPECIES =
@ -59,39 +47,10 @@ final class VectorUtilPanamaProvider implements VectorUtilProvider {
}
}
// Extracted to a method to be able to apply the SuppressForbidden annotation
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}
private final boolean useIntegerVectors;
VectorUtilPanamaProvider(boolean testMode) {
if (!testMode && INT_SPECIES_PREF_BIT_SIZE < 128) {
throw new UnsupportedOperationException(
"Vector bit size is less than 128: " + INT_SPECIES_PREF_BIT_SIZE);
}
// hack to work around for JDK-8309727:
try {
doPrivileged(
() ->
FloatVector.fromArray(PREF_FLOAT_SPECIES, new float[PREF_FLOAT_SPECIES.length()], 0));
} catch (SecurityException se) {
throw new UnsupportedOperationException(
"We hit initialization failure described in JDK-8309727: " + se);
}
// check if the system is x86 and less than 256-bit vectors:
var isAMD64withoutAVX2 = Constants.OS_ARCH.equals("amd64") && INT_SPECIES_PREF_BIT_SIZE < 256;
this.hasFastIntegerVectors = testMode || false == isAMD64withoutAVX2;
var log = Logger.getLogger(getClass().getName());
log.info(
"Java vector incubator API enabled"
+ (testMode ? " (test mode)" : "")
+ "; uses preferredBitSize="
+ INT_SPECIES_PREF_BIT_SIZE);
PanamaVectorUtilSupport(boolean useIntegerVectors) {
this.useIntegerVectors = useIntegerVectors;
}
@Override
@ -301,7 +260,7 @@ final class VectorUtilPanamaProvider implements VectorUtilProvider {
int res = 0;
// only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit
// vectors (256-bit on intel to dodge performance landmines)
if (a.length >= 16 && hasFastIntegerVectors) {
if (a.length >= 16 && useIntegerVectors) {
// compute vectorized dot product consistent with VPDPBUSD instruction
if (INT_SPECIES_PREF_BIT_SIZE >= 256) {
// optimized 256/512 bit implementation, processes 8/16 bytes at a time
@ -358,7 +317,7 @@ final class VectorUtilPanamaProvider implements VectorUtilProvider {
int norm2 = 0;
// only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit
// vectors (256-bit on intel to dodge performance landmines)
if (a.length >= 16 && hasFastIntegerVectors) {
if (a.length >= 16 && useIntegerVectors) {
if (INT_SPECIES_PREF_BIT_SIZE >= 256) {
// optimized 256/512 bit implementation, processes 8/16 bytes at a time
int upperBound = PREF_BYTE_SPECIES.loopBound(a.length);
@ -448,7 +407,7 @@ final class VectorUtilPanamaProvider implements VectorUtilProvider {
int res = 0;
// only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit
// vectors (256-bit on intel to dodge performance landmines)
if (a.length >= 16 && hasFastIntegerVectors) {
if (a.length >= 16 && useIntegerVectors) {
if (INT_SPECIES_PREF_BIT_SIZE >= 256) {
// optimized 256/512 bit implementation, processes 8/16 bytes at a time
int upperBound = PREF_BYTE_SPECIES.loopBound(a.length);

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.internal.vectorization;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Logger;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.IntVector;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.SuppressForbidden;
/** A vectorization provider that leverages the Panama Vector API. */
final class PanamaVectorizationProvider extends VectorizationProvider {
private final VectorUtilSupport vectorUtilSupport;
/**
* x86 and less than 256-bit vectors.
*
* <p>it could be that it has only AVX1 and integer vectors are fast. it could also be that it has
* no AVX and integer vectors are extremely slow. don't use integer vectors to avoid landmines.
*/
private final boolean hasFastIntegerVectors;
// Extracted to a method to be able to apply the SuppressForbidden annotation
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}
PanamaVectorizationProvider(boolean testMode) {
final int intPreferredBitSize = IntVector.SPECIES_PREFERRED.vectorBitSize();
if (!testMode && intPreferredBitSize < 128) {
throw new UnsupportedOperationException(
"Vector bit size is less than 128: " + intPreferredBitSize);
}
// hack to work around for JDK-8309727:
try {
doPrivileged(
() ->
FloatVector.fromArray(
FloatVector.SPECIES_PREFERRED,
new float[FloatVector.SPECIES_PREFERRED.length()],
0));
} catch (SecurityException se) {
throw new UnsupportedOperationException(
"We hit initialization failure described in JDK-8309727: " + se);
}
// check if the system is x86 and less than 256-bit vectors:
var isAMD64withoutAVX2 = Constants.OS_ARCH.equals("amd64") && intPreferredBitSize < 256;
this.hasFastIntegerVectors = testMode || false == isAMD64withoutAVX2;
this.vectorUtilSupport = new PanamaVectorUtilSupport(hasFastIntegerVectors);
var log = Logger.getLogger(getClass().getName());
log.info(
"Java vector incubator API enabled"
+ (testMode ? " (test mode)" : "")
+ "; uses preferredBitSize="
+ intPreferredBitSize);
}
@Override
public VectorUtilSupport getVectorUtilSupport() {
return vectorUtilSupport;
}
}

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.internal.vectorization;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.junit.BeforeClass;
public abstract class BaseVectorizationTestCase extends LuceneTestCase {
protected static final VectorizationProvider LUCENE_PROVIDER = new DefaultVectorizationProvider();
protected static final VectorizationProvider PANAMA_PROVIDER = VectorizationProvider.lookup(true);
@BeforeClass
public static void beforeClass() throws Exception {
assumeTrue(
"Test only works when JDK's vector incubator module is enabled.",
PANAMA_PROVIDER.getClass() != LUCENE_PROVIDER.getClass());
}
}

View File

@ -14,20 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.util;
package org.apache.lucene.internal.vectorization;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.stream.IntStream;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.junit.BeforeClass;
public class TestVectorUtilProviders extends LuceneTestCase {
public class TestVectorUtilSupport extends BaseVectorizationTestCase {
private static final double DELTA = 1e-3;
private static final VectorUtilProvider LUCENE_PROVIDER = new VectorUtilDefaultProvider();
private static final VectorUtilProvider JDK_PROVIDER = VectorUtilProvider.lookup(true);
private static final int[] VECTOR_SIZES = {
1, 4, 6, 8, 13, 16, 25, 32, 64, 100, 128, 207, 256, 300, 512, 702, 1024
@ -35,7 +31,7 @@ public class TestVectorUtilProviders extends LuceneTestCase {
private final int size;
public TestVectorUtilProviders(int size) {
public TestVectorUtilSupport(int size) {
this.size = size;
}
@ -44,13 +40,6 @@ public class TestVectorUtilProviders extends LuceneTestCase {
return () -> IntStream.of(VECTOR_SIZES).boxed().map(i -> new Object[] {i}).iterator();
}
@BeforeClass
public static void beforeClass() throws Exception {
assumeFalse(
"Test only works when JDK's vector incubator module is enabled.",
JDK_PROVIDER instanceof VectorUtilDefaultProvider);
}
public void testFloatVectors() {
var a = new float[size];
var b = new float[size];
@ -73,11 +62,16 @@ public class TestVectorUtilProviders extends LuceneTestCase {
assertFloatReturningProviders(p -> p.cosine(a, b));
}
private void assertFloatReturningProviders(ToDoubleFunction<VectorUtilProvider> func) {
assertEquals(func.applyAsDouble(LUCENE_PROVIDER), func.applyAsDouble(JDK_PROVIDER), DELTA);
private void assertFloatReturningProviders(ToDoubleFunction<VectorUtilSupport> func) {
assertEquals(
func.applyAsDouble(LUCENE_PROVIDER.getVectorUtilSupport()),
func.applyAsDouble(PANAMA_PROVIDER.getVectorUtilSupport()),
DELTA);
}
private void assertIntReturningProviders(ToIntFunction<VectorUtilProvider> func) {
assertEquals(func.applyAsInt(LUCENE_PROVIDER), func.applyAsInt(JDK_PROVIDER));
private void assertIntReturningProviders(ToIntFunction<VectorUtilSupport> func) {
assertEquals(
func.applyAsInt(LUCENE_PROVIDER.getVectorUtilSupport()),
func.applyAsInt(PANAMA_PROVIDER.getVectorUtilSupport()));
}
}

View File

@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.internal.vectorization;
import org.apache.lucene.tests.util.LuceneTestCase;
public class TestVectorizationProvider extends LuceneTestCase {
public void testCallerOfGetter() {
expectThrows(UnsupportedOperationException.class, TestVectorizationProvider::illegalCaller);
}
private static void illegalCaller() {
VectorizationProvider.getInstance();
}
}