// Path: src/main/java/org/oscii/math/VectorMath.java
// public final class VectorMath {
// 
//     private VectorMath() {
//     }
// 
//     /**
//      * Cosine similarity. Undefined for zero vectors.
//      *
//      * @param v1
//      * @param v2
//      * @return
//      */
//     public static double cosineSimilarity(float[] v1, float[] v2) {
//         if (v1.length != v2.length) throw new IllegalArgumentException();
//         double v1Dotv2 = 0.0;
//         double v1SS = 0.0;
//         double v2SS = 0.0;
//         for (int i = 0; i < v1.length; i++) {
//             v1Dotv2 += v1[i] * v2[i];
//             v1SS += v1[i] * v1[i];
//             v2SS += v2[i] * v2[i];
//         }
//         if (v1SS == 0.0f || v2SS == 0.0f)
//             throw new IllegalArgumentException("Cosine similarity undefined for zero vectors");
//         return v1Dotv2 / (Math.sqrt(v1SS) * Math.sqrt(v2SS));
//     }
// 
//     public static double cosineSimilarity(Vector v1, Vector v2) {
//         if (v1.size() != v2.size()) throw new IllegalArgumentException();
//         double v1v2 = v1.dot(v2);
//         double v1Norm = v1.norm(Vector.Norm.Two);
//         double v2Norm = v2.norm(Vector.Norm.Two);
//         if (v1Norm == 0.0 || v2Norm == 0.0)
//             throw new IllegalArgumentException("Cosine similarity undefined for zero vectors");
//         return v1v2 / (v1Norm * v2Norm);
//     }
// 
//     /**
//      * @param dest
//      * @param v1
//      */
//     public static void addInPlace(float[] dest, float[] v1) {
//         if (dest.length != v1.length) throw new IllegalArgumentException();
//         for (int i = 0; i < dest.length; ++i) dest[i] += v1[i];
//     }
// 
//     /**
//      * @param v1
//      * @param scalar
//      */
//     public static void multiplyInPlace(float[] v1, float scalar) {
//         if (scalar == 0.0f) throw new IllegalArgumentException();
//         for (int i = 0; i < v1.length; ++i) v1[i] *= scalar;
//     }
// 
// }


import com.eatthepath.jvptree.VPTree;
import no.uib.cipr.matrix.DenseVector;
import no.uib.cipr.matrix.Vector;
import org.oscii.math.VectorMath;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.LineNumberReader;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.toList;
        }
        if (n == 0) {
            return new DenseVector(dimension());
        }
        avgVec.scale(1.0f / n);
        return avgVec;
    }

    /**
     * Return k words nearest to a word. The result will include the word.
     */
    public List<String> neighbors(String word, int k) {
        return neighbors(embeddings[word2Index.get(word)], k);
    }

    /**
     * Return k words nearest to an embedding vector.
     */
    public List<String> neighbors(Vector embedding, int k) {
        if (neighborIndex == null) {
            neighborIndex = new VPTree<Vector>(EmbeddingContainer::angularDistance, Arrays.asList(embeddings));
        }
        return neighborIndex.getNearestNeighbors(embedding, k)
                .stream().map(e -> vocab[embedding2Index.get(e)]).collect(toList());
    }

    /**
     * Distance metric based on angle between vectors.
     */
    static double angularDistance(Vector a, Vector b) {
// Path: src/main/java/org/oscii/math/VectorMath.java
// public final class VectorMath {
// 
//     private VectorMath() {
//     }
// 
//     /**
//      * Cosine similarity. Undefined for zero vectors.
//      *
//      * @param v1
//      * @param v2
//      * @return
//      */
//     public static double cosineSimilarity(float[] v1, float[] v2) {
//         if (v1.length != v2.length) throw new IllegalArgumentException();
//         double v1Dotv2 = 0.0;
//         double v1SS = 0.0;
//         double v2SS = 0.0;
//         for (int i = 0; i < v1.length; i++) {
//             v1Dotv2 += v1[i] * v2[i];
//             v1SS += v1[i] * v1[i];
//             v2SS += v2[i] * v2[i];
//         }
//         if (v1SS == 0.0f || v2SS == 0.0f)
//             throw new IllegalArgumentException("Cosine similarity undefined for zero vectors");
//         return v1Dotv2 / (Math.sqrt(v1SS) * Math.sqrt(v2SS));
//     }
// 
//     public static double cosineSimilarity(Vector v1, Vector v2) {
//         if (v1.size() != v2.size()) throw new IllegalArgumentException();
//         double v1v2 = v1.dot(v2);
//         double v1Norm = v1.norm(Vector.Norm.Two);
//         double v2Norm = v2.norm(Vector.Norm.Two);
//         if (v1Norm == 0.0 || v2Norm == 0.0)
//             throw new IllegalArgumentException("Cosine similarity undefined for zero vectors");
//         return v1v2 / (v1Norm * v2Norm);
//     }
// 
//     /**
//      * @param dest
//      * @param v1
//      */
//     public static void addInPlace(float[] dest, float[] v1) {
//         if (dest.length != v1.length) throw new IllegalArgumentException();
//         for (int i = 0; i < dest.length; ++i) dest[i] += v1[i];
//     }
// 
//     /**
//      * @param v1
//      * @param scalar
//      */
//     public static void multiplyInPlace(float[] v1, float scalar) {
//         if (scalar == 0.0f) throw new IllegalArgumentException();
//         for (int i = 0; i < v1.length; ++i) v1[i] *= scalar;
//     }
// 
// }


// Path: src/main/java/org/oscii/neural/EmbeddingContainer.java
import com.eatthepath.jvptree.VPTree;
import no.uib.cipr.matrix.DenseVector;
import no.uib.cipr.matrix.Vector;
import org.oscii.math.VectorMath;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.LineNumberReader;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.toList;

        }
        if (n == 0) {
            return new DenseVector(dimension());
        }
        avgVec.scale(1.0f / n);
        return avgVec;
    }

    /**
     * Return k words nearest to a word. The result will include the word.
     */
    public List<String> neighbors(String word, int k) {
        return neighbors(embeddings[word2Index.get(word)], k);
    }

    /**
     * Return k words nearest to an embedding vector.
     */
    public List<String> neighbors(Vector embedding, int k) {
        if (neighborIndex == null) {
            neighborIndex = new VPTree<Vector>(EmbeddingContainer::angularDistance, Arrays.asList(embeddings));
        }
        return neighborIndex.getNearestNeighbors(embedding, k)
                .stream().map(e -> vocab[embedding2Index.get(e)]).collect(toList());
    }

    /**
     * Distance metric based on angle between vectors.
     */
    static double angularDistance(Vector a, Vector b) {
        return Math.acos(VectorMath.cosineSimilarity(a, b)) / Math.PI;