using System; using System.Collections.Generic; using System.Linq; using System.IO.Compression; using UnityEngine; namespace LLMUnity { /// @ingroup rag /// /// Class implementing a simple search that compares the enconding of the search query with all the search entries (brute-force). /// [DefaultExecutionOrder(-2)] public class SimpleSearch : SearchMethod { /// \cond HIDE protected SortedDictionary embeddings = new SortedDictionary(); protected Dictionary> incrementalSearchCache = new Dictionary>(); protected override void AddInternal(int key, float[] embedding) { embeddings[key] = embedding; } protected override void RemoveInternal(int key) { embeddings.Remove(key); } public override int IncrementalSearch(float[] embedding, string group = "") { int key = nextIncrementalSearchKey++; List<(int, float)> sortedLists = new List<(int, float)>(); if (dataSplits.TryGetValue(group, out List dataSplit)) { if (dataSplit.Count >= 0) { float[][] embeddingsSplit = new float[dataSplit.Count][]; for (int i = 0; i < dataSplit.Count; i++) embeddingsSplit[i] = embeddings[dataSplit[i]]; float[] unsortedDistances = InverseDotProduct(embedding, embeddingsSplit); sortedLists = dataSplit.Zip(unsortedDistances, (first, second) => (first, second)) .OrderBy(item => item.Item2) .ToList(); } } incrementalSearchCache[key] = sortedLists; return key; } public override ValueTuple IncrementalFetchKeys(int fetchKey, int k) { if (!incrementalSearchCache.ContainsKey(fetchKey)) throw new Exception($"There is no IncrementalSearch cached with this key: {fetchKey}"); bool completed; List<(int, float)> sortedLists; if (k == -1) { sortedLists = incrementalSearchCache[fetchKey]; completed = true; } else { int getK = Math.Min(k, incrementalSearchCache[fetchKey].Count); sortedLists = incrementalSearchCache[fetchKey].GetRange(0, getK); incrementalSearchCache[fetchKey].RemoveRange(0, getK); completed = incrementalSearchCache[fetchKey].Count == 0; } if (completed) IncrementalSearchComplete(fetchKey); int[] results = new int[sortedLists.Count]; float[] distances = new float[sortedLists.Count]; for (int i = 0; i < sortedLists.Count; i++) { results[i] = sortedLists[i].Item1; distances[i] = sortedLists[i].Item2; } return (results.ToArray(), distances.ToArray(), completed); } public override void IncrementalSearchComplete(int fetchKey) { incrementalSearchCache.Remove(fetchKey); } protected override void ClearInternal() { embeddings.Clear(); incrementalSearchCache.Clear(); } protected override void SaveInternal(ZipArchive archive) { ArchiveSaver.Save(archive, embeddings, GetSavePath("embeddings")); ArchiveSaver.Save(archive, incrementalSearchCache, GetSavePath("incrementalSearchCache")); } protected override void LoadInternal(ZipArchive archive) { embeddings = ArchiveSaver.Load>(archive, GetSavePath("embeddings")); incrementalSearchCache = ArchiveSaver.Load>>(archive, GetSavePath("incrementalSearchCache")); } /// \endcond } }