core

package
v0.0.0-...-dfee7fc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const (
	DefaultDiskANNMaxDegree    = 100
	DefaultDiskANNBuildList    = 50
	DefaultDiskANNQueryList    = 300
	DefaultDiskANNCacheNodes   = 1024
	DefaultDiskANNMaxOcclusion = 750
)
View Source
const (
	DiskANNSectorSize     = 4096
	MaxDiskANNReadSectors = 128
)
View Source
const (
	DefaultHNSWM              = 50
	DefaultHNSWEFConstruction = 500
	MaxHNSWLevel              = 14
	MaxHNSWM                  = 32767
)
View Source
const (
	DefaultHNSWEFSearch            = 300
	MaxHNSWEFSearch                = 2048
	DefaultHNSWBruteForceThreshold = 1000
	DefaultHNSWPrefetchOffset      = 8
	MaxHNSWPrefetchLines           = 256
)
View Source
const (
	DefaultIVFNList       = 1024
	DefaultIVFNIterations = 10
)
View Source
const (
	DefaultKMeansIterations = 20
	DefaultKMeansTolerance  = 1.1920928955078125e-7
)
View Source
const (
	PQBits                   = 8
	PQCentroidCount          = 1 << PQBits
	DefaultPQMaxTrainSamples = 200_000
	DefaultPQIterations      = 12
	DefaultPQKMC2ChainLength = 32
)
View Source
const (
	MinRaBitQDimension     = 64
	MaxRaBitQDimension     = 4095
	MinRaBitQTotalBits     = 1
	MaxRaBitQTotalBits     = 9
	DefaultRaBitQTotalBits = 7
	DefaultRaBitQClusters  = 16
)
View Source
const (
	MetricL2     = metric.L2
	MetricIP     = metric.IP
	MetricCosine = metric.Cosine
	MetricMIPSL2 = metric.MIPSL2
)
View Source
const (
	DefaultVamanaMaxDegree        = 64
	DefaultVamanaSearchListSize   = 100
	DefaultVamanaMaxOcclusionSize = 750
	DefaultVamanaAlpha            = float32(1.2)
	MaxVamanaDegree               = 65_535
)
View Source
const (
	DefaultVamanaEFSearch            = 200
	MaxVamanaEFSearch                = 2048
	DefaultVamanaBruteForceThreshold = 1000
	DefaultVamanaPrefetchOffset      = 8
)
View Source
const DefaultIVFNProbe = 10
View Source
const MaxRotationDimension = 65535

MaxRotationDimension matches the public dense-vector dimension ceiling.

Variables

View Source
var (
	ErrInvalidDiskANNOptions = errors.New("core: invalid DiskANN options")
	ErrDiskANNKeyNotFound    = errors.New("core: DiskANN key not found")
	ErrDiskANNClosed         = errors.New("core: DiskANN index is closed")
	ErrDiskANNCapacity       = errors.New("core: DiskANN index capacity exceeded")
)
View Source
var (
	ErrInvalidDiskANNFile             = errors.New("core: invalid DiskANN index file")
	ErrDiskANNIndexChecksumMismatch   = errors.New("core: DiskANN index checksum mismatch")
	ErrUnsupportedDiskANNIndexVersion = errors.New("core: unsupported DiskANN index version")
)
View Source
var (
	ErrInvalidDiskANNLayout      = errors.New("core: invalid DiskANN layout")
	ErrInvalidDiskANNNode        = errors.New("core: invalid DiskANN node")
	ErrDiskANNChecksumMismatch   = errors.New("core: DiskANN checksum mismatch")
	ErrUnsupportedDiskANNVersion = errors.New("core: unsupported DiskANN format version")
)
View Source
var (
	ErrInvalidDimension = errors.New("core: invalid vector dimension")
	ErrDuplicateKey     = errors.New("core: duplicate vector key")
	ErrBuilderClosed    = errors.New("core: builder is closed")
)
View Source
var (
	ErrInvalidGroupCount = errors.New("core: group count must be positive")
	ErrInvalidGroupTopK  = errors.New("core: per-group top-k must be positive")
	ErrGroupSizeOverflow = errors.New("core: group candidate count overflows int")
	ErrNilGroupResolver  = errors.New("core: nil group resolver")
)
View Source
var (
	ErrInvalidHNSWOptions = errors.New("core: invalid HNSW build options")
	ErrInvalidHNSWWorkers = errors.New("core: HNSW workers must be positive")
	ErrInvalidHNSWLevel   = errors.New("core: invalid HNSW level")
	ErrHNSWKeyNotFound    = errors.New("core: HNSW key not found")
	ErrHNSWCapacity       = errors.New("core: HNSW index capacity exceeded")
)
View Source
var (

	// ErrInvalidHNSWFile reports a structurally or semantically invalid native
	// Go HNSW artifact.
	ErrInvalidHNSWFile = errors.New("core: invalid HNSW file")
	// ErrHNSWChecksumMismatch distinguishes detected bit flips from other
	// format violations.
	ErrHNSWChecksumMismatch = errors.New("core: HNSW checksum mismatch")
	// ErrUnsupportedHNSWVersion reports a native Go HNSW artifact whose format
	// version is not supported by this library.
	ErrUnsupportedHNSWVersion = errors.New("core: unsupported HNSW file version")
)
View Source
var (
	ErrInvalidHNSWRaBitQFile        = errors.New("core: invalid HNSW-RaBitQ file")
	ErrHNSWRaBitQChecksumMismatch   = errors.New("core: HNSW-RaBitQ checksum mismatch")
	ErrUnsupportedHNSWRaBitQVersion = errors.New("core: unsupported HNSW-RaBitQ file version")
)
View Source
var (

	// ErrInvalidSparseHNSWFile reports a structurally or semantically invalid
	// native Go sparse HNSW artifact.
	ErrInvalidSparseHNSWFile = errors.New("core: invalid sparse HNSW file")
	// ErrSparseHNSWChecksumMismatch distinguishes bit flips from other format
	// violations.
	ErrSparseHNSWChecksumMismatch = errors.New("core: sparse HNSW checksum mismatch")
	// ErrUnsupportedSparseHNSWVersion reports an unsupported native Go sparse
	// HNSW format version.
	ErrUnsupportedSparseHNSWVersion = errors.New("core: unsupported sparse HNSW file version")
)
View Source
var (
	ErrInvalidIVFOptions = errors.New("core: invalid IVF build options")
	ErrInvalidIVFList    = errors.New("core: invalid IVF list")
)
View Source
var (

	// ErrInvalidIVFFile reports a structurally or semantically invalid native
	// Go IVF artifact.
	ErrInvalidIVFFile = errors.New("core: invalid IVF file")
	// ErrIVFChecksumMismatch distinguishes detected bit flips from other
	// format violations.
	ErrIVFChecksumMismatch = errors.New("core: IVF checksum mismatch")
	// ErrUnsupportedIVFVersion reports a well-identified artifact from an
	// unsupported native Go IVF format version.
	ErrUnsupportedIVFVersion = errors.New("core: unsupported IVF file version")
)
View Source
var (
	ErrInvalidKMeansOptions = errors.New("core: invalid k-means options")
	ErrEmptyTrainingSet     = errors.New("core: k-means training set is empty")
	ErrInvalidCentroid      = errors.New("core: invalid k-means centroid")
)
View Source
var (
	ErrInvalidPQOptions    = errors.New("core: invalid PQ options")
	ErrInvalidPQModel      = errors.New("core: invalid PQ model")
	ErrInvalidPQCode       = errors.New("core: invalid PQ code")
	ErrPQModelMismatch     = errors.New("core: PQ code belongs to a different model")
	ErrPQUnsupportedMetric = errors.New("core: PQ supports L2 and inner product only")
	ErrPQScoreOverflow     = errors.New("core: PQ score overflows float32")
)
View Source
var (
	ErrInvalidQuantization    = errors.New("core: invalid scalar quantization")
	ErrInvalidQuantizedVector = errors.New("core: invalid quantized vector")
	ErrQuantizationOverflow   = errors.New("core: value overflows quantized representation")
	ErrOddInt4Dimension       = errors.New("core: INT4 quantization requires an even dimension")
)
View Source
var (
	ErrInvalidTopK   = errors.New("core: top-k must be positive")
	ErrInvalidRadius = errors.New("core: radius must be finite and non-negative")
)
View Source
var (
	ErrInvalidRaBitQOptions  = errors.New("core: invalid RaBitQ options")
	ErrInvalidRaBitQModel    = errors.New("core: invalid RaBitQ model")
	ErrInvalidRaBitQCode     = errors.New("core: invalid RaBitQ code")
	ErrRaBitQModelMismatch   = errors.New("core: RaBitQ code belongs to a different model")
	ErrRaBitQUnsupportedType = errors.New("core: RaBitQ supports L2, IP, and cosine only")
)
View Source
var (
	ErrInvalidRefinerScale = errors.New("core: refiner scale factor must be finite and positive")
	ErrMissingRefineVector = errors.New("core: original vector is missing for refinement")
)
View Source
var (
	ErrInvalidRotator = errors.New("core: invalid vector rotator")
	ErrInvalidSigns   = errors.New("core: invalid rotation sign state")
)
View Source
var (
	ErrInvalidVamanaOptions = errors.New("core: invalid Vamana build options")
	ErrVamanaKeyNotFound    = errors.New("core: Vamana key not found")
	ErrVamanaCapacity       = errors.New("core: Vamana index capacity exceeded")
)
View Source
var (
	ErrInvalidVamanaFile        = errors.New("core: invalid Vamana file")
	ErrVamanaChecksumMismatch   = errors.New("core: Vamana checksum mismatch")
	ErrUnsupportedVamanaVersion = errors.New("core: unsupported Vamana file version")
)
View Source
var ErrDiskANNShortRead = errors.New("core: short DiskANN ReaderAt read")
View Source
var ErrIVFCapacity = errors.New("core: IVF index capacity exceeded")
View Source
var ErrInvalidDiskANNListSize = errors.New("core: invalid DiskANN list size")
View Source
var ErrInvalidHNSWEF = errors.New("core: HNSW EF must be in [1, 2048]")
View Source
var ErrInvalidHNSWRaBitQOptions = errors.New("core: invalid HNSW-RaBitQ build options")
View Source
var ErrInvalidIVFNProbe = errors.New("core: IVF NProbe must be positive")
View Source
var ErrInvalidVamanaEF = errors.New("core: Vamana EF must be in [1, 2048]")
View Source
var ErrSparseHNSWCapacity = errors.New("core: sparse HNSW index capacity exceeded")

ErrSparseHNSWCapacity reports that another node or coordinate cannot be represented by the current platform-native CSR layout.

Functions

func BatchTopK

func BatchTopK(
	ctx context.Context,
	metric Metric,
	queries [][]float32,
	candidates []Candidate,
	k int,
	workers int,
) ([][]Result, error)

BatchTopK computes independent top-k results for queries, preserving query order while using at most workers goroutines. A non-positive workers value uses GOMAXPROCS.

func ParallelReadAt

func ParallelReadAt(ctx context.Context, reader io.ReaderAt, requests []DiskANNReadRequest, workers int) ([][]byte, error)

ParallelReadAt executes exact ReaderAt requests concurrently and preserves request order. It is portable across regular files and custom ReaderAt implementations on Linux, macOS, and Windows.

func QuantizedDistance

func QuantizedDistance(metric Metric, left, right QuantizedVector) (float32, error)

QuantizedDistance calculates a metric directly from scalar codes. Both vectors must use the same encoding and logical dimension.

func QuantizedDistanceToFloat

func QuantizedDistanceToFloat(metric Metric, candidate QuantizedVector, query []float32) (float32, error)

QuantizedDistanceToFloat converts query with candidate's encoding and then scores the two quantized vectors. This matches streaming-query conversion in the baseline scalar-quantized indexes.

func RefinementCandidateCount

func RefinementCandidateCount(topK int, scaleFactor float32) (int, error)

RefinementCandidateCount applies the baseline floor(top-k*scale-factor) rule, with a minimum of one candidate and overflow validation.

Types

type Candidate

type Candidate struct {
	Key    uint64
	Vector []float32
}

Candidate is one immutable dense vector considered by exact search.

type CandidateFilter

type CandidateFilter func(key uint64) bool

CandidateFilter returns true when a document key may participate in vector scoring. Implementations used with segmented queries must be concurrency-safe.

type DenseBuilder

type DenseBuilder interface {
	Add(ctx context.Context, key uint64, vector []float32) error
	Build(ctx context.Context) (DenseIndex, error)
}

DenseBuilder collects vectors and transfers its index on Build.

type DenseFlatIndex

type DenseFlatIndex struct {
	// contains filtered or unexported fields
}

DenseFlatIndex stores FP32 vectors contiguously and scans every vector for exact search. Adds are serialized; any number of searches may run together.

func NewDenseFlatIndex

func NewDenseFlatIndex(dimension int, metric Metric) (*DenseFlatIndex, error)

NewDenseFlatIndex constructs an empty exact index.

func (*DenseFlatIndex) Add

func (i *DenseFlatIndex) Add(ctx context.Context, key uint64, vector []float32) error

Add clones and appends one finite vector. Keys are unique for the lifetime of an index so deterministic tie-breaking remains unambiguous.

func (*DenseFlatIndex) Dimension

func (i *DenseFlatIndex) Dimension() int

Dimension returns the fixed vector dimension.

func (*DenseFlatIndex) Len

func (i *DenseFlatIndex) Len() int

Len returns the number of indexed vectors.

func (*DenseFlatIndex) Metric

func (i *DenseFlatIndex) Metric() Metric

Metric returns the index score metric.

func (*DenseFlatIndex) Search

func (i *DenseFlatIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

Search performs an exact top-k scan. It holds a read lock so the contiguous vector storage cannot move while candidate slices are being scored.

func (*DenseFlatIndex) SearchGroups

func (i *DenseFlatIndex) SearchGroups(ctx context.Context, query []float32, options GroupByOptions) ([]GroupResult, error)

SearchGroups scans every eligible dense candidate. It retains only the best TopKPerGroup documents per group rather than first taking a global top-k.

func (*DenseFlatIndex) SearchWithOptions

func (i *DenseFlatIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

SearchWithOptions applies a candidate filter and metric-aware radius before retaining the exact top-k.

func (*DenseFlatIndex) Vector

func (i *DenseFlatIndex) Vector(key uint64) ([]float32, bool)

Vector returns a cloned vector by key.

type DenseFlatIndexBuilder

type DenseFlatIndexBuilder struct {
	// contains filtered or unexported fields
}

DenseFlatIndexBuilder is a one-shot builder. The built index remains streamable through DenseFlatIndex.Add.

func NewDenseFlatBuilder

func NewDenseFlatBuilder(dimension int, metric Metric) (*DenseFlatIndexBuilder, error)

NewDenseFlatBuilder constructs a builder for an exact dense index.

func (*DenseFlatIndexBuilder) Add

func (b *DenseFlatIndexBuilder) Add(ctx context.Context, key uint64, vector []float32) error

Add appends a vector while the builder is open.

func (*DenseFlatIndexBuilder) Build

Build closes the builder and returns its index. An empty index is valid.

type DenseGroupSearcher

type DenseGroupSearcher interface {
	Metric() Metric
	SearchGroups(ctx context.Context, query []float32, options GroupByOptions) ([]GroupResult, error)
}

DenseGroupSearcher executes one segment-local dense group-by query.

type DenseIndex

type DenseIndex interface {
	DenseProvider
	DenseSearcher
	DenseStreamer
}

DenseIndex is the common runtime contract implemented by exact and ANN indexes that retain original dense vectors.

type DenseProvider

type DenseProvider interface {
	Dimension() int
	Len() int
	Vector(key uint64) ([]float32, bool)
}

DenseProvider exposes vectors without prescribing their storage layout. Vector returns an independent copy so callers cannot mutate an index.

type DenseQuerySearcher

type DenseQuerySearcher interface {
	Metric() Metric
	SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)
}

DenseQuerySearcher executes one segment-local dense query.

type DenseRefiner

type DenseRefiner interface {
	Metric() Metric
	Refine(ctx context.Context, query []float32, candidates []Result, options SearchOptions) ([]Result, error)
}

DenseRefiner re-scores approximate candidates in an exact representation.

type DenseReformer

type DenseReformer interface {
	Dimension() int
	Transform(vector []float32) ([]float32, error)
	Revert(vector []float32) ([]float32, error)
}

DenseReformer transforms vectors into and out of an index representation. Implementations must be safe for concurrent calls.

type DenseSearcher

type DenseSearcher interface {
	Search(ctx context.Context, query []float32, k int) ([]Result, error)
}

DenseSearcher is the common exact/ANN search contract.

type DenseStreamer

type DenseStreamer interface {
	Add(ctx context.Context, key uint64, vector []float32) error
}

DenseStreamer accepts incremental vectors after an index is built.

type DiskANNBuildOptions

type DiskANNBuildOptions struct {
	Metric        Metric
	MaxDegree     int
	ListSize      int
	PQChunks      int
	Workers       int
	CacheCapacity int
}

DiskANNBuildOptions configures graph construction, product quantization, random-read concurrency, and the demand cache.

func DefaultDiskANNBuildOptions

func DefaultDiskANNBuildOptions(metric Metric) DiskANNBuildOptions

DefaultDiskANNBuildOptions returns the pinned public construction defaults.

func (DiskANNBuildOptions) Validate

func (o DiskANNBuildOptions) Validate() error

Validate checks invariants that do not depend on vector dimension.

type DiskANNBuilder

type DiskANNBuilder struct {
	// contains filtered or unexported fields
}

DiskANNBuilder collects original vectors for one immutable disk graph.

func NewDiskANNBuilder

func NewDiskANNBuilder(dimension int, options DiskANNBuildOptions) (*DiskANNBuilder, error)

func (*DiskANNBuilder) Add

func (b *DiskANNBuilder) Add(ctx context.Context, key uint64, vector []float32) error

Add validates and clones one unique original vector.

func (*DiskANNBuilder) Build

func (b *DiskANNBuilder) Build(ctx context.Context) (*DiskANNIndex, error)

Build constructs a Vamana topology, trains PQ traversal codes, and converts the graph to the native sector layout. The returned in-memory ReaderAt index has identical search semantics to an index reopened from disk.

type DiskANNCacheStats

type DiskANNCacheStats struct {
	Hits      uint64
	Misses    uint64
	Evictions uint64
}

DiskANNCacheStats is a point-in-time snapshot of cache activity.

type DiskANNIndex

type DiskANNIndex struct {
	// contains filtered or unexported fields
}

DiskANNIndex owns immutable key/PQ metadata and serves graph nodes through a sector-aware ReaderAt. An opened index owns its file until Close.

Example
package main

import (
	"context"
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	options := core.DefaultDiskANNBuildOptions(core.MetricL2)
	options.MaxDegree = 2
	options.ListSize = 4
	options.PQChunks = 1
	builder, err := core.NewDiskANNBuilder(2, options)
	if err != nil {
		panic(err)
	}
	for key, vector := range map[uint64][]float32{
		10: {0, 0}, 20: {1, 0}, 30: {0, 2}, 40: {3, 3},
	} {
		if err := builder.Add(context.Background(), key, vector); err != nil {
			panic(err)
		}
	}
	index, err := builder.Build(context.Background())
	if err != nil {
		panic(err)
	}
	results, err := index.SearchDiskANN(context.Background(), []float32{0.9, 0}, core.DiskANNSearchOptions{
		SearchOptions: core.SearchOptions{TopK: 2}, ListSize: 4,
	})
	if err != nil {
		panic(err)
	}
	for _, result := range results {
		fmt.Printf("%d %.2f\n", result.Key, result.Score)
	}
}
Output:
20 0.01
10 0.81

func OpenDiskANNIndex

func OpenDiskANNIndex(ctx context.Context, path string, cacheCapacity, workers int) (*DiskANNIndex, error)

OpenDiskANNIndex opens and validates a complete artifact. cacheCapacity zero disables node caching; workers zero lets the shared parallel helper choose.

func OpenDiskANNIndexWithMmap

func OpenDiskANNIndexWithMmap(ctx context.Context, path string, cacheCapacity, workers int, useMmap bool) (*DiskANNIndex, error)

OpenDiskANNIndexWithMmap opens a complete artifact through either ordinary file reads or a read-only memory mapping. The returned index owns the reader and releases it from Close.

func (*DiskANNIndex) BuildOptions

func (i *DiskANNIndex) BuildOptions() DiskANNBuildOptions

func (*DiskANNIndex) CacheStats

func (i *DiskANNIndex) CacheStats() DiskANNCacheStats

func (*DiskANNIndex) Close

func (i *DiskANNIndex) Close() error

Close releases an opened artifact. It is idempotent and waits for active searches that hold the immutable file generation.

func (*DiskANNIndex) Dimension

func (i *DiskANNIndex) Dimension() int

func (*DiskANNIndex) EntryPoint

func (i *DiskANNIndex) EntryPoint() (uint64, bool)

func (*DiskANNIndex) Len

func (i *DiskANNIndex) Len() int

func (*DiskANNIndex) Metric

func (i *DiskANNIndex) Metric() Metric

func (*DiskANNIndex) PQChunks

func (i *DiskANNIndex) PQChunks() int

func (*DiskANNIndex) Save

func (i *DiskANNIndex) Save(ctx context.Context, path string) error

Save atomically publishes a complete native DiskANN artifact.

func (*DiskANNIndex) Search

func (i *DiskANNIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*DiskANNIndex) SearchDiskANN

func (i *DiskANNIndex) SearchDiskANN(ctx context.Context, query []float32, options DiskANNSearchOptions) ([]Result, error)

SearchDiskANN performs a bounded best-first traversal. PQ scores order the frontier; every expanded node is read from the node artifact and receives its exact public score before filter, radius, and top-k selection.

func (*DiskANNIndex) SearchWithOptions

func (i *DiskANNIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*DiskANNIndex) Vector

func (i *DiskANNIndex) Vector(key uint64) ([]float32, bool)

Vector reads and clones one original FP32 vector by external key.

func (*DiskANNIndex) WarmCache

func (i *DiskANNIndex) WarmCache(ctx context.Context, count int) (int, error)

WarmCache follows graph edges breadth-first from the medoid and reads up to count nodes. The effective count never exceeds cache capacity.

type DiskANNLayout

type DiskANNLayout struct {
	// contains filtered or unexported fields
}

DiskANNLayout describes the sector-aligned random-access node section.

func NewDiskANNLayout

func NewDiskANNLayout(metric Metric, count, dimension, maxDegree int) (DiskANNLayout, error)

NewDiskANNLayout calculates the pinned packed-or-multi-sector node layout.

Example
package main

import (
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	layout, err := core.NewDiskANNLayout(core.MetricL2, 1000, 128, 64)
	if err != nil {
		panic(err)
	}
	fmt.Println(layout.RecordSize(), layout.NodesPerSector(), layout.SectorsPerNode(), layout.DataLength())
}
Output:
776 5 1 819200

func (DiskANNLayout) Count

func (l DiskANNLayout) Count() int

func (DiskANNLayout) DataChecksum

func (l DiskANNLayout) DataChecksum() uint32

func (DiskANNLayout) DataLength

func (l DiskANNLayout) DataLength() int64

func (DiskANNLayout) DataOffset

func (l DiskANNLayout) DataOffset() int64

func (DiskANNLayout) Dimension

func (l DiskANNLayout) Dimension() int

func (DiskANNLayout) MaxDegree

func (l DiskANNLayout) MaxDegree() int

func (DiskANNLayout) Metric

func (l DiskANNLayout) Metric() Metric

func (DiskANNLayout) NodesPerSector

func (l DiskANNLayout) NodesPerSector() int

func (DiskANNLayout) RecordSize

func (l DiskANNLayout) RecordSize() int

func (DiskANNLayout) SectorsPerNode

func (l DiskANNLayout) SectorsPerNode() int

func (DiskANNLayout) TotalLength

func (l DiskANNLayout) TotalLength() int64

type DiskANNNode

type DiskANNNode struct {
	ID        uint32
	Vector    []float32
	Neighbors []uint32
}

DiskANNNode is one original FP32 vector and its bounded outbound graph IDs.

type DiskANNNodeCache

type DiskANNNodeCache struct {
	// contains filtered or unexported fields
}

DiskANNNodeCache is a bounded concurrency-safe LRU of immutable node copies.

func NewDiskANNNodeCache

func NewDiskANNNodeCache(capacity int) (*DiskANNNodeCache, error)

func (*DiskANNNodeCache) Capacity

func (c *DiskANNNodeCache) Capacity() int

func (*DiskANNNodeCache) Clear

func (c *DiskANNNodeCache) Clear()

func (*DiskANNNodeCache) Get

func (c *DiskANNNodeCache) Get(id uint32) (DiskANNNode, bool)

func (*DiskANNNodeCache) Len

func (c *DiskANNNodeCache) Len() int

func (*DiskANNNodeCache) Put

func (c *DiskANNNodeCache) Put(node DiskANNNode)

func (*DiskANNNodeCache) Stats

type DiskANNNodeReader

type DiskANNNodeReader struct {
	// contains filtered or unexported fields
}

DiskANNNodeReader validates one complete node artifact, then serves cache-aware batched random reads.

func OpenDiskANNNodeReader

func OpenDiskANNNodeReader(ctx context.Context, reader io.ReaderAt, fileSize int64, cacheCapacity, workers int) (*DiskANNNodeReader, error)

func (*DiskANNNodeReader) CacheStats

func (r *DiskANNNodeReader) CacheStats() DiskANNCacheStats

func (*DiskANNNodeReader) Layout

func (r *DiskANNNodeReader) Layout() DiskANNLayout

func (*DiskANNNodeReader) ReadNode

func (r *DiskANNNodeReader) ReadNode(ctx context.Context, nodeID uint32) (DiskANNNode, error)

func (*DiskANNNodeReader) ReadNodes

func (r *DiskANNNodeReader) ReadNodes(ctx context.Context, nodeIDs []uint32) ([]DiskANNNode, error)

type DiskANNReadRequest

type DiskANNReadRequest struct {
	Offset int64
	Length int
}

DiskANNReadRequest describes one exact random read.

type DiskANNSearchOptions

type DiskANNSearchOptions struct {
	SearchOptions
	ListSize int
	Linear   bool
}

DiskANNSearchOptions combines common result controls with the graph candidate-list width. Linear is an exact disk scan used for diagnostics and query fallback.

func (DiskANNSearchOptions) Validate

func (o DiskANNSearchOptions) Validate() error

type FHTRotator

type FHTRotator struct {
	// contains filtered or unexported fields
}

FHTRotator implements the baseline four-round random-sign FHT/Kac rotation. Its immutable sign state makes concurrent transforms safe.

func NewFHTRotator

func NewFHTRotator(dimension int) (*FHTRotator, error)

NewFHTRotator creates a random rotator using crypto/rand. Persist Signs with an index so queries after reopen use the identical transform.

func NewFHTRotatorFromSigns

func NewFHTRotatorFromSigns(dimension int, signs []byte) (*FHTRotator, error)

NewFHTRotatorFromSigns restores a rotator from its exact four-round sign state. Extra and missing bytes are rejected to make persisted state canonical.

func NewFHTRotatorWithReader

func NewFHTRotatorWithReader(dimension int, random io.Reader) (*FHTRotator, error)

NewFHTRotatorWithReader creates a rotator from caller-provided randomness.

func (*FHTRotator) Dimension

func (r *FHTRotator) Dimension() int

Dimension returns the unchanged input and output dimension.

func (*FHTRotator) Rotate

func (r *FHTRotator) Rotate(vector []float32) ([]float32, error)

Rotate applies four random-sign FHT rounds and returns a new vector.

func (*FHTRotator) RotateBatch

func (r *FHTRotator) RotateBatch(ctx context.Context, vectors [][]float32, workers int) ([][]float32, error)

RotateBatch rotates vectors concurrently while preserving their order.

func (*FHTRotator) Signs

func (r *FHTRotator) Signs() []byte

Signs returns an independent copy of the canonical sign state.

func (*FHTRotator) Unrotate

func (r *FHTRotator) Unrotate(vector []float32) ([]float32, error)

Unrotate reverses Rotate and returns a new vector.

type GroupByOptions

type GroupByOptions struct {
	GroupCount   int
	TopKPerGroup int
	Radius       float32
	Filter       CandidateFilter
	Resolve      GroupResolver
}

GroupByOptions controls exact and ANN group-by search. Groups are ranked by their best document and documents inside a group use the index metric.

func (GroupByOptions) Validate

func (o GroupByOptions) Validate() error

Validate checks group-by query invariants.

type GroupResolver

type GroupResolver func(key uint64) (value string, ok bool)

GroupResolver maps a document key to its stable string group value. An empty value is a valid group (and is used for NULL by the pinned native baseline); ok=false explicitly excludes a candidate. Resolvers used by segmented queries must be safe for concurrent calls.

type GroupResult

type GroupResult struct {
	Value   string
	Results []Result
}

GroupResult contains one group value and its metric-ordered documents.

func MergeGroupResults

func MergeGroupResults(metric Metric, groupCount, topKPerGroup int, batches ...[]GroupResult) []GroupResult

MergeGroupResults combines segment-local groups. It first rebuilds each group's global top-k, then ranks groups by their best result. Ties between groups use their string values so segment order cannot affect output.

func QueryDenseGroups

func QueryDenseGroups(
	ctx context.Context,
	metric Metric,
	searchers []DenseGroupSearcher,
	query []float32,
	options GroupByOptions,
	workers int,
) ([]GroupResult, error)

QueryDenseGroups runs group-by searches concurrently across segments and merges groups before applying the final global GroupCount.

func QuerySparseGroups

func QuerySparseGroups(
	ctx context.Context,
	searchers []SparseGroupSearcher,
	query SparseVector,
	options GroupByOptions,
	workers int,
) ([]GroupResult, error)

QuerySparseGroups runs sparse IP group-by searches across segments and merges their per-group candidate lists deterministically.

type HNSWBuildOptions

type HNSWBuildOptions struct {
	Metric         Metric
	M              int
	EFConstruction int
	Seed           uint64
}

HNSWBuildOptions configures dense graph construction. Level sampling is reproducible for a fixed Seed; Build uses deterministic input-order insertion.

func DefaultHNSWBuildOptions

func DefaultHNSWBuildOptions(metric Metric) HNSWBuildOptions

DefaultHNSWBuildOptions returns the pinned public construction defaults.

func DefaultSparseHNSWBuildOptions

func DefaultSparseHNSWBuildOptions() HNSWBuildOptions

DefaultSparseHNSWBuildOptions returns the pinned HNSW construction defaults with the only metric supported by sparse vectors.

func (HNSWBuildOptions) Validate

func (o HNSWBuildOptions) Validate() error

Validate checks graph degree and construction-search invariants.

type HNSWBuilder

type HNSWBuilder struct {
	// contains filtered or unexported fields
}

HNSWBuilder collects dense originals and constructs one deterministic graph.

func NewHNSWBuilder

func NewHNSWBuilder(dimension int, options HNSWBuildOptions) (*HNSWBuilder, error)

NewHNSWBuilder constructs an empty one-shot dense HNSW builder.

func (*HNSWBuilder) Add

func (b *HNSWBuilder) Add(ctx context.Context, key uint64, vector []float32) error

Add validates and clones one unique vector while the builder is open.

func (*HNSWBuilder) Build

func (b *HNSWBuilder) Build(ctx context.Context) (*HNSWIndex, error)

Build assigns deterministic levels, inserts nodes in input order on one worker, and transfers builder-owned original storage to the resulting graph.

func (*HNSWBuilder) BuildWithWorkers

func (b *HNSWBuilder) BuildWithWorkers(ctx context.Context, workers int) (*HNSWIndex, error)

BuildWithWorkers constructs the graph with up to workers concurrent node insertions. A single worker is bit-for-bit deterministic; multiple workers preserve graph invariants but topology may vary with goroutine scheduling.

type HNSWGroupSearchOptions

type HNSWGroupSearchOptions struct {
	GroupByOptions
	EF             int
	PrefetchOffset uint32
	PrefetchLines  uint32
}

HNSWGroupSearchOptions combines group retention with the level-zero graph exploration controls shared by dense, sparse, scalar-quantized, and RaBitQ HNSW indexes.

func (HNSWGroupSearchOptions) Validate

func (o HNSWGroupSearchOptions) Validate() error

Validate checks group retention and graph exploration invariants.

type HNSWIndex

type HNSWIndex struct {
	// contains filtered or unexported fields
}

HNSWIndex stores original FP32 vectors and a bounded multi-layer proximity graph. Readers share one immutable generation while additions publish a complete copy-on-write generation.

func OpenHNSWIndex

func OpenHNSWIndex(ctx context.Context, path string) (*HNSWIndex, error)

OpenHNSWIndex reads and fully verifies a native Go HNSW artifact. The returned graph owns all decoded memory and does not retain the source file.

func (*HNSWIndex) Add

func (i *HNSWIndex) Add(ctx context.Context, key uint64, vector []float32) error

Add incrementally inserts one unique key and finite original vector. The insertion is planned on a private graph generation and becomes visible in one commit, so cancellation never exposes a half-linked node.

func (*HNSWIndex) BuildOptions

func (i *HNSWIndex) BuildOptions() HNSWBuildOptions

BuildOptions returns the value-semantic construction settings.

func (*HNSWIndex) Dimension

func (i *HNSWIndex) Dimension() int

Dimension returns the fixed dense vector dimension.

func (*HNSWIndex) EntryPoint

func (i *HNSWIndex) EntryPoint() (uint64, bool)

EntryPoint returns the current top-layer entry key.

func (*HNSWIndex) Len

func (i *HNSWIndex) Len() int

Len returns the number of graph nodes.

func (*HNSWIndex) Level

func (i *HNSWIndex) Level(key uint64) (int, bool)

Level returns a node's maximum graph level.

func (*HNSWIndex) MaxLevel

func (i *HNSWIndex) MaxLevel() int

MaxLevel returns the highest occupied level, or -1 for an empty graph.

func (*HNSWIndex) Metric

func (i *HNSWIndex) Metric() Metric

Metric returns the graph construction metric.

func (*HNSWIndex) Neighbors

func (i *HNSWIndex) Neighbors(key uint64, level int) ([]uint64, error)

Neighbors returns cloned neighbor keys in deterministic selection order.

func (*HNSWIndex) Save

func (i *HNSWIndex) Save(ctx context.Context, path string) error

Save durably publishes the immutable graph as one checksummed native Go HNSW file. Replacing an existing file is atomic to concurrent openers.

func (*HNSWIndex) Search

func (i *HNSWIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

Search uses the pinned default EF. A zero top-k returns an empty result for consistency with the common DenseSearcher contract.

func (*HNSWIndex) SearchHNSW

func (i *HNSWIndex) SearchHNSW(ctx context.Context, query []float32, options HNSWSearchOptions) ([]Result, error)

SearchHNSW executes a metric-aware hierarchical graph query with explicit EF. EF smaller than TopK is raised to TopK so the requested result count can be retained.

func (*HNSWIndex) SearchHNSWGroups

func (i *HNSWIndex) SearchHNSWGroups(
	ctx context.Context,
	query []float32,
	options HNSWGroupSearchOptions,
) ([]GroupResult, error)

SearchHNSWGroups performs native HNSW group traversal. It retains an initial groupCount*topKPerGroup candidate set and expands level zero when those candidates do not contain enough distinct groups.

func (*HNSWIndex) SearchWithOptions

func (i *HNSWIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

SearchWithOptions applies common filter and radius controls with default EF.

func (*HNSWIndex) Vector

func (i *HNSWIndex) Vector(key uint64) ([]float32, bool)

Vector returns a cloned original vector by key.

type HNSWRaBitQBuildOptions

type HNSWRaBitQBuildOptions struct {
	Metric         Metric
	TotalBits      int
	Clusters       int
	SampleCount    int
	MaxIterations  int
	Workers        int
	M              int
	EFConstruction int
	Seed           uint64
}

HNSWRaBitQBuildOptions configures original-vector graph construction and the RaBitQ model used for queries. Seed controls both components.

func DefaultHNSWRaBitQBuildOptions

func DefaultHNSWRaBitQBuildOptions(metric Metric) HNSWRaBitQBuildOptions

DefaultHNSWRaBitQBuildOptions returns the pinned public defaults.

func (HNSWRaBitQBuildOptions) Validate

func (o HNSWRaBitQBuildOptions) Validate() error

Validate checks graph and converter invariants that do not depend on data.

type HNSWRaBitQBuilder

type HNSWRaBitQBuilder struct {
	// contains filtered or unexported fields
}

HNSWRaBitQBuilder owns input originals until Build publishes one index.

Example
package main

import (
	"context"
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	options := core.DefaultHNSWRaBitQBuildOptions(core.MetricL2)
	options.TotalBits = 4
	options.Clusters = 4
	options.MaxIterations = 4
	options.M = 4
	options.EFConstruction = 16
	options.Seed = 42
	builder, err := core.NewHNSWRaBitQBuilder(64, options)
	if err != nil {
		panic(err)
	}
	for key := uint64(1); key <= 16; key++ {
		vector := make([]float32, 64)
		for dimension := range vector {
			vector[dimension] = float32(int(key)+dimension%5) / 8
		}
		if err := builder.Add(context.Background(), key, vector); err != nil {
			panic(err)
		}
	}
	index, err := builder.Build(context.Background())
	if err != nil {
		panic(err)
	}
	query, _ := index.Vector(5)
	results, err := index.SearchHNSWRaBitQ(context.Background(), query, core.HNSWRaBitQSearchOptions{
		SearchOptions: core.SearchOptions{TopK: 3}, EF: 16, Refine: true,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(index.Dimension(), index.Len(), index.BuildOptions().TotalBits)
	fmt.Println(results[0].Key, results[0].Score)
}
Output:
64 16 4
5 0

func NewHNSWRaBitQBuilder

func NewHNSWRaBitQBuilder(dimension int, options HNSWRaBitQBuildOptions) (*HNSWRaBitQBuilder, error)

func (*HNSWRaBitQBuilder) Add

func (b *HNSWRaBitQBuilder) Add(ctx context.Context, key uint64, vector []float32) error

func (*HNSWRaBitQBuilder) Build

type HNSWRaBitQIndex

type HNSWRaBitQIndex struct {
	// contains filtered or unexported fields
}

HNSWRaBitQIndex binds an original-vector HNSW graph, an immutable RaBitQ model, and one code per graph position. Adds publish complete generations.

func OpenHNSWRaBitQIndex

func OpenHNSWRaBitQIndex(ctx context.Context, path string) (*HNSWRaBitQIndex, error)

OpenHNSWRaBitQIndex reads and verifies a native Go HNSW-RaBitQ artifact.

func (*HNSWRaBitQIndex) Add

func (i *HNSWRaBitQIndex) Add(ctx context.Context, key uint64, vector []float32) error

Add encodes one vector with the fixed model and atomically publishes a graph generation containing both the new topology and code.

func (*HNSWRaBitQIndex) BuildOptions

func (i *HNSWRaBitQIndex) BuildOptions() HNSWRaBitQBuildOptions

func (*HNSWRaBitQIndex) Dimension

func (i *HNSWRaBitQIndex) Dimension() int

func (*HNSWRaBitQIndex) EntryPoint

func (i *HNSWRaBitQIndex) EntryPoint() (uint64, bool)

func (*HNSWRaBitQIndex) Len

func (i *HNSWRaBitQIndex) Len() int

func (*HNSWRaBitQIndex) Level

func (i *HNSWRaBitQIndex) Level(key uint64) (int, bool)

func (*HNSWRaBitQIndex) MaxLevel

func (i *HNSWRaBitQIndex) MaxLevel() int

func (*HNSWRaBitQIndex) Metric

func (i *HNSWRaBitQIndex) Metric() Metric

func (*HNSWRaBitQIndex) ModelState

func (i *HNSWRaBitQIndex) ModelState() RaBitQModelState

func (*HNSWRaBitQIndex) Neighbors

func (i *HNSWRaBitQIndex) Neighbors(key uint64, level int) ([]uint64, error)

func (*HNSWRaBitQIndex) Save

func (i *HNSWRaBitQIndex) Save(ctx context.Context, path string) error

Save durably and atomically publishes one complete graph/model/code generation in the native Go HNSW-RaBitQ format.

func (*HNSWRaBitQIndex) Search

func (i *HNSWRaBitQIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*HNSWRaBitQIndex) SearchGroups

func (i *HNSWRaBitQIndex) SearchGroups(
	ctx context.Context,
	vector []float32,
	options GroupByOptions,
) ([]GroupResult, error)

SearchGroups performs an exact scan over the immutable RaBitQ codes and groups the resulting public approximation scores.

func (*HNSWRaBitQIndex) SearchHNSWRaBitQ

func (i *HNSWRaBitQIndex) SearchHNSWRaBitQ(ctx context.Context, query []float32, options HNSWRaBitQSearchOptions) ([]Result, error)

func (*HNSWRaBitQIndex) SearchHNSWRaBitQGroups

func (i *HNSWRaBitQIndex) SearchHNSWRaBitQGroups(
	ctx context.Context,
	vector []float32,
	options HNSWGroupSearchOptions,
) ([]GroupResult, error)

SearchHNSWRaBitQGroups performs native HNSW traversal with RaBitQ estimates and expands level zero when the initial candidates lack enough groups.

func (*HNSWRaBitQIndex) SearchWithOptions

func (i *HNSWRaBitQIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*HNSWRaBitQIndex) Vector

func (i *HNSWRaBitQIndex) Vector(key uint64) ([]float32, bool)

type HNSWRaBitQSearchOptions

type HNSWRaBitQSearchOptions struct {
	SearchOptions
	EF     int
	Refine bool
	Linear bool
}

HNSWRaBitQSearchOptions configures graph exploration and optional exact reranking. Refine reranks up to EF approximate candidates from originals.

func (HNSWRaBitQSearchOptions) Validate

func (o HNSWRaBitQSearchOptions) Validate() error

type HNSWSearchOptions

type HNSWSearchOptions struct {
	SearchOptions
	EF             int
	PrefetchOffset uint32
	PrefetchLines  uint32
}

HNSWSearchOptions combines common result controls with the level-zero exploration width.

func (HNSWSearchOptions) Validate

func (o HNSWSearchOptions) Validate() error

Validate checks top-k, radius, and graph exploration invariants.

type IVFBuildOptions

type IVFBuildOptions struct {
	Metric      Metric
	NList       int
	NIterations int
	Tolerance   float64
	Workers     int
	Seed        uint64
}

IVFBuildOptions configures centroid training and deterministic list assignment. Quantization is layered onto the built layout separately.

func DefaultIVFBuildOptions

func DefaultIVFBuildOptions(metric Metric) IVFBuildOptions

DefaultIVFBuildOptions returns the public baseline defaults.

func (IVFBuildOptions) Validate

func (o IVFBuildOptions) Validate() error

Validate checks IVF build invariants.

type IVFBuilder

type IVFBuilder struct {
	// contains filtered or unexported fields
}

IVFBuilder collects original vectors and builds a one-shot IVF layout. The resulting index supports concurrent search and incremental streaming.

func NewIVFBuilder

func NewIVFBuilder(dimension int, options IVFBuildOptions) (*IVFBuilder, error)

NewIVFBuilder constructs an empty IVF builder.

func (*IVFBuilder) Add

func (b *IVFBuilder) Add(ctx context.Context, key uint64, vector []float32) error

Add clones one finite original vector. Keys remain unique for the builder's lifetime.

func (*IVFBuilder) Build

func (b *IVFBuilder) Build(ctx context.Context) (*IVFIndex, error)

Build trains at most NList centroids, assigns each vector to its best centroid, and transfers builder-owned storage into an immutable index. An empty builder produces a valid empty layout without invoking k-means.

type IVFIndex

type IVFIndex struct {
	// contains filtered or unexported fields
}

IVFIndex is the streamable output of IVF construction. It retains original vectors for exact refinement and stores list membership by vector position.

func OpenIVFIndex

func OpenIVFIndex(ctx context.Context, path string) (*IVFIndex, error)

OpenIVFIndex reads and fully verifies a native Go IVF artifact. It never returns an index backed by the source file.

func (*IVFIndex) Add

func (i *IVFIndex) Add(ctx context.Context, key uint64, vector []float32) error

Add incrementally inserts one unique key and finite original vector. While the index contains fewer vectors than configured lists, each new vector extends the centroid set and starts its own list. Once NList is reached, the trained centroids remain fixed and additions enter their metric-best list.

func (*IVFIndex) BuildOptions

func (i *IVFIndex) BuildOptions() IVFBuildOptions

BuildOptions returns the value-semantic construction settings.

func (*IVFIndex) Centroids

func (i *IVFIndex) Centroids() [][]float32

Centroids returns a deep copy of trained or online-bootstrapped centroids.

func (*IVFIndex) Dimension

func (i *IVFIndex) Dimension() int

Dimension returns the fixed vector dimension.

func (*IVFIndex) Len

func (i *IVFIndex) Len() int

Len returns the number of built vectors.

func (*IVFIndex) List

func (i *IVFIndex) List(list int) ([]Candidate, error)

List returns original candidate clones in stable builder insertion order.

func (*IVFIndex) ListForKey

func (i *IVFIndex) ListForKey(key uint64) (int, bool)

ListForKey returns the current list containing key.

func (*IVFIndex) Metric

func (i *IVFIndex) Metric() Metric

Metric returns the configured metric.

func (*IVFIndex) NList

func (i *IVFIndex) NList() int

NList returns the effective number of trained centroids. It is zero for an empty index and never exceeds the vector count or configured NList. Duplicate samples can still leave an empty assigned list.

func (*IVFIndex) ProbedLists

func (i *IVFIndex) ProbedLists(ctx context.Context, query []float32, nprobe int) ([]int, error)

ProbedLists returns up to nprobe centroid indexes in metric-best order.

func (*IVFIndex) Save

func (i *IVFIndex) Save(ctx context.Context, path string) error

Save durably publishes the immutable index as one checksummed native Go IVF file. Replacing an existing file is atomic to concurrent openers.

func (*IVFIndex) Search

func (i *IVFIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

Search uses the baseline default NProbe. A zero top-k returns an empty result for consistency with the common DenseSearcher contract.

func (*IVFIndex) SearchIVF

func (i *IVFIndex) SearchIVF(ctx context.Context, query []float32, options IVFSearchOptions) ([]Result, error)

SearchIVF probes the metric-best centroids and exact-scores originals in only those lists.

func (*IVFIndex) SearchWithOptions

func (i *IVFIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

SearchWithOptions applies a filter and exact-result radius while using the baseline default NProbe.

func (*IVFIndex) TrainingConverged

func (i *IVFIndex) TrainingConverged() bool

TrainingConverged reports whether centroid training stopped on tolerance.

func (*IVFIndex) TrainingCost

func (i *IVFIndex) TrainingCost() float64

TrainingCost returns the current list-assignment objective. Empty indexes return zero.

func (*IVFIndex) TrainingIterations

func (i *IVFIndex) TrainingIterations() int

TrainingIterations returns completed k-means rounds.

func (*IVFIndex) Vector

func (i *IVFIndex) Vector(key uint64) ([]float32, bool)

Vector returns a cloned original vector by key.

type IVFSearchOptions

type IVFSearchOptions struct {
	SearchOptions
	NProbe int
}

IVFSearchOptions combines common exact-result controls with the number of centroid lists to probe.

func (IVFSearchOptions) Validate

func (o IVFSearchOptions) Validate() error

Validate checks top-k, radius, and probe-count invariants.

type KMeansEmptyPolicy

type KMeansEmptyPolicy uint8

KMeansEmptyPolicy controls an empty centroid after an update.

const (
	// KMeansEmptyKeep retains the previous centroid.
	KMeansEmptyKeep KMeansEmptyPolicy = iota + 1
	// KMeansEmptyReseedFarthest moves each empty centroid to the worst assigned
	// training vector, without reusing a vector in the same update.
	KMeansEmptyReseedFarthest
	// KMeansEmptyDrop removes empty centroids.
	KMeansEmptyDrop
)

type KMeansInitializer

type KMeansInitializer uint8

KMeansInitializer selects initial centroids.

const (
	// KMeansInitReservoir selects samples uniformly without replacement,
	// matching the pinned baseline's default initialization family.
	KMeansInitReservoir KMeansInitializer = iota + 1
	// KMeansInitPlusPlus uses squared-L2 weighted sampling after its first
	// uniformly selected sample.
	KMeansInitPlusPlus
)

type KMeansModel

type KMeansModel struct {
	// contains filtered or unexported fields
}

KMeansModel is an immutable trained centroid set.

func TrainKMeans

func TrainKMeans(ctx context.Context, vectors [][]float32, options KMeansOptions) (*KMeansModel, error)

TrainKMeans runs deterministic Lloyd iterations over finite FP32 vectors. Assignment is parallel; accumulation is performed in input order so results are bit-for-bit stable across worker counts.

func (*KMeansModel) Centroids

func (m *KMeansModel) Centroids() [][]float32

Centroids returns a deep copy in deterministic centroid order.

func (*KMeansModel) Classify

func (m *KMeansModel) Classify(ctx context.Context, vectors [][]float32, workers int) ([]int, []float32, error)

Classify assigns vectors concurrently while preserving input order and deterministic lower-index tie breaking.

func (*KMeansModel) Converged

func (m *KMeansModel) Converged() bool

Converged reports whether training stopped on the configured tolerance.

func (*KMeansModel) Cost

func (m *KMeansModel) Cost() float64

Cost returns the final lower-is-better objective. It is the score sum for distance metrics and the negated similarity sum for inner product.

func (*KMeansModel) Counts

func (m *KMeansModel) Counts() []int

Counts returns final assignment counts in centroid order.

func (*KMeansModel) Dimension

func (m *KMeansModel) Dimension() int

Dimension returns the vector dimension.

func (*KMeansModel) Iterations

func (m *KMeansModel) Iterations() int

Iterations returns the number of completed Lloyd update rounds.

func (*KMeansModel) Len

func (m *KMeansModel) Len() int

Len returns the final centroid count.

func (*KMeansModel) Metric

func (m *KMeansModel) Metric() Metric

Metric returns the assignment metric.

func (*KMeansModel) Nearest

func (m *KMeansModel) Nearest(vector []float32) (int, float32, error)

Nearest returns the best centroid and metric score for one vector. Equal scores choose the lower centroid index.

type KMeansOptions

type KMeansOptions struct {
	Clusters         int
	MaxIterations    int
	Tolerance        float64
	Metric           Metric
	Workers          int
	Seed             uint64
	Initializer      KMeansInitializer
	EmptyPolicy      KMeansEmptyPolicy
	Spherical        bool
	InitialCentroids [][]float32
}

KMeansOptions configures deterministic Lloyd training. InitialCentroids, if present, replaces random initialization and must match the effective cluster count min(Clusters,len(training set)).

func DefaultKMeansOptions

func DefaultKMeansOptions(clusters int, metric Metric) KMeansOptions

DefaultKMeansOptions returns baseline-oriented defaults plus deterministic empty-cluster recovery suitable for index construction.

type Metric

type Metric = metric.Metric

Metric selects score computation and ordering for exact search.

type OriginalSparseVectorRefiner

type OriginalSparseVectorRefiner struct {
	// contains filtered or unexported fields
}

OriginalSparseVectorRefiner computes final inner-product scores from a provider that retains the unquantized sparse vectors.

func NewOriginalSparseVectorRefiner

func NewOriginalSparseVectorRefiner(provider SparseProvider) (*OriginalSparseVectorRefiner, error)

NewOriginalSparseVectorRefiner constructs an exact sparse candidate refiner.

func (*OriginalSparseVectorRefiner) Metric

func (r *OriginalSparseVectorRefiner) Metric() Metric

func (*OriginalSparseVectorRefiner) RefineSparse

func (r *OriginalSparseVectorRefiner) RefineSparse(
	ctx context.Context,
	query SparseVector,
	candidates []Result,
	options SearchOptions,
) ([]Result, error)

RefineSparse ignores approximate scores, resolves each unique candidate key to its original sparse vector, and returns deterministic exact top-k results.

type OriginalVectorRefiner

type OriginalVectorRefiner struct {
	// contains filtered or unexported fields
}

OriginalVectorRefiner computes final scores from a provider that retains original FP32 vectors.

func NewOriginalVectorRefiner

func NewOriginalVectorRefiner(provider DenseProvider, metric Metric) (*OriginalVectorRefiner, error)

NewOriginalVectorRefiner constructs an exact candidate refiner.

func (*OriginalVectorRefiner) Metric

func (r *OriginalVectorRefiner) Metric() Metric

Metric returns the exact scoring metric.

func (*OriginalVectorRefiner) Refine

func (r *OriginalVectorRefiner) Refine(ctx context.Context, query []float32, candidates []Result, options SearchOptions) ([]Result, error)

Refine ignores approximate scores, resolves each unique candidate key to its original vector, and returns exact deterministic top-k results.

type PQCode

type PQCode struct {
	// contains filtered or unexported fields
}

PQCode stores one unsigned 8-bit centroid ID per chunk.

func (PQCode) Bytes

func (c PQCode) Bytes() []byte

func (PQCode) Chunks

func (c PQCode) Chunks() int

type PQDistanceTable

type PQDistanceTable struct {
	// contains filtered or unexported fields
}

PQDistanceTable stores chunk-major public scores for one query. L2 entries are squared distances and inner-product entries are similarities.

func (*PQDistanceTable) Centroids

func (t *PQDistanceTable) Centroids() int

func (*PQDistanceTable) Chunks

func (t *PQDistanceTable) Chunks() int

func (*PQDistanceTable) Lookup

func (t *PQDistanceTable) Lookup(code PQCode) (float32, error)

Lookup sums one precomputed entry per code byte.

func (*PQDistanceTable) LookupBatch

func (t *PQDistanceTable) LookupBatch(ctx context.Context, codes []PQCode, workers int) ([]float32, error)

LookupBatch evaluates codes concurrently while preserving input order.

func (*PQDistanceTable) Metric

func (t *PQDistanceTable) Metric() Metric

func (*PQDistanceTable) Values

func (t *PQDistanceTable) Values() []float32

type PQModel

type PQModel struct {
	// contains filtered or unexported fields
}

PQModel is an immutable 8-bit product quantizer.

func RestorePQModel

func RestorePQModel(state PQModelState) (*PQModel, error)

RestorePQModel validates and clones a complete portable model snapshot.

func TrainPQ

func TrainPQ(ctx context.Context, vectors [][]float32, options PQOptions) (*PQModel, error)

TrainPQ partitions dimensions into contiguous chunks and trains one independent 256-entry codebook per chunk. When fewer than 256 samples are available, unused rows repeat centroid zero and therefore never win a tie.

Example
package main

import (
	"context"
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	vectors := [][]float32{
		{0, 0, 10, 10},
		{0, 1, 10, 11},
		{5, 5, 20, 20},
		{5, 6, 20, 21},
	}
	options := core.DefaultPQOptions(core.MetricL2)
	options.Chunks = 2
	model, err := core.TrainPQ(context.Background(), vectors, options)
	if err != nil {
		panic(err)
	}
	code, err := model.Encode(vectors[0])
	if err != nil {
		panic(err)
	}
	table, err := model.DistanceTable(vectors[0])
	if err != nil {
		panic(err)
	}
	score, err := table.Lookup(code)
	if err != nil {
		panic(err)
	}
	fmt.Println(model.Chunks(), len(code.Bytes()), score)
}
Output:
2 2 0

func (*PQModel) ChunkOffsets

func (m *PQModel) ChunkOffsets() []int

func (*PQModel) Chunks

func (m *PQModel) Chunks() int

func (*PQModel) Code

func (m *PQModel) Code(encoded []byte) (PQCode, error)

Code restores one immutable code owned by this model.

func (*PQModel) Decode

func (m *PQModel) Decode(code PQCode) ([]float32, error)

Decode reconstructs a vector from one centroid ID per chunk.

func (*PQModel) Dimension

func (m *PQModel) Dimension() int

func (*PQModel) Distance

func (m *PQModel) Distance(query []float32, code PQCode) (float32, error)

Distance builds a table and evaluates one code.

func (*PQModel) DistanceTable

func (m *PQModel) DistanceTable(query []float32) (*PQDistanceTable, error)

DistanceTable computes all 256 query scores for every chunk.

func (*PQModel) Encode

func (m *PQModel) Encode(vector []float32) (PQCode, error)

Encode selects the best centroid independently in every chunk.

func (*PQModel) EncodeBatch

func (m *PQModel) EncodeBatch(ctx context.Context, vectors [][]float32, workers int) ([]PQCode, error)

EncodeBatch converts vectors concurrently while preserving input order.

func (*PQModel) Metric

func (m *PQModel) Metric() Metric

func (*PQModel) Pivots

func (m *PQModel) Pivots() []float32

Pivots returns the full centroid-major pivot matrix.

func (*PQModel) State

func (m *PQModel) State() PQModelState

State returns an independent complete model snapshot.

type PQModelState

type PQModelState struct {
	Dimension    int
	Metric       Metric
	ChunkOffsets []int
	Pivots       []float32
}

PQModelState is the complete portable state of a trained quantizer. Pivots are centroid-major: row c contains all dimensions for centroid ID c, while ChunkOffsets determines which portion of each row belongs to each chunk.

type PQOptions

type PQOptions struct {
	Metric          Metric
	Chunks          int
	MaxTrainSamples int
	MaxIterations   int
	Workers         int
	Seed            uint64
}

PQOptions configures deterministic 8-bit product-quantizer training. Chunks zero resolves to half the vector dimension, matching DiskANN's public auto setting. Training uses the first MaxTrainSamples vectors.

func DefaultPQOptions

func DefaultPQOptions(metric Metric) PQOptions

DefaultPQOptions returns the pinned 256-centroid, 12-iteration defaults.

func (PQOptions) Validate

func (o PQOptions) Validate() error

Validate checks options that do not depend on vector dimension.

type Quantization

type Quantization uint8

Quantization identifies one scalar vector encoding. The values are internal and deliberately independent of the public and on-disk enum assignments.

const (
	QuantizationFP16 Quantization = iota + 1
	QuantizationInt8
	QuantizationInt4
)

type QuantizedVector

type QuantizedVector struct {
	// contains filtered or unexported fields
}

QuantizedVector is an immutable scalar-quantized dense vector. Integer encodings reconstruct element i as inverseScale*code[i]+offset. The integer moments allow distance kernels to avoid materializing decoded vectors.

func QuantizeBatch

func QuantizeBatch(ctx context.Context, kind Quantization, vectors [][]float32, workers int) ([]QuantizedVector, error)

QuantizeBatch converts vectors concurrently while preserving input order. No output aliases an input or another output.

func QuantizeVector

func QuantizeVector(kind Quantization, vector []float32) (QuantizedVector, error)

QuantizeVector scalar-quantizes one finite, non-empty FP32 vector. FP16 uses IEEE binary16. INT8 and INT4 use baseline-compatible per-vector affine ranges with signed codes; INT4 requires an even logical dimension.

func (QuantizedVector) Codes

func (v QuantizedVector) Codes() []byte

Codes returns an independent copy of the packed encoded data.

func (QuantizedVector) Decode

func (v QuantizedVector) Decode() ([]float32, error)

Decode returns the independently allocated FP32 vector represented by v.

func (QuantizedVector) Dimension

func (v QuantizedVector) Dimension() int

Dimension returns the number of logical vector elements.

func (QuantizedVector) InverseScale

func (v QuantizedVector) InverseScale() float32

InverseScale returns the integer reconstruction multiplier. It is zero for FP16 and for constant integer-quantized vectors.

func (QuantizedVector) Kind

func (v QuantizedVector) Kind() Quantization

Kind returns the vector encoding.

func (QuantizedVector) Offset

func (v QuantizedVector) Offset() float32

Offset returns the integer reconstruction offset. It is zero for FP16.

type RaBitQCode

type RaBitQCode struct {
	// contains filtered or unexported fields
}

RaBitQCode is one immutable split code. BinaryCode stores one sign bit per padded coordinate; ExtraCode stores the remaining bits in a portable least-significant-bit-first stream.

func (RaBitQCode) BinaryCode

func (c RaBitQCode) BinaryCode() []byte

func (RaBitQCode) Cluster

func (c RaBitQCode) Cluster() int

func (RaBitQCode) ExtraCode

func (c RaBitQCode) ExtraCode() []byte

func (RaBitQCode) PaddedDimension

func (c RaBitQCode) PaddedDimension() int

func (RaBitQCode) QuantizedValues

func (c RaBitQCode) QuantizedValues() ([]uint16, error)

QuantizedValues expands the portable code into one unsigned total-bit value per padded coordinate. It is intended for diagnostics and fixtures.

func (RaBitQCode) TotalBits

func (c RaBitQCode) TotalBits() int

type RaBitQEstimate

type RaBitQEstimate struct {
	Distance   float32
	LowerBound float32
	UpperBound float32
}

RaBitQEstimate is a lower-is-better approximate distance and the baseline's probabilistic error envelope. The bounds are useful for candidate pruning; they are not a deterministic guarantee. IP uses 1-inner-product, while cosine uses 1-cosine.

type RaBitQModel

type RaBitQModel struct {
	// contains filtered or unexported fields
}

RaBitQModel is an immutable trained centroid converter.

func RestoreRaBitQModel

func RestoreRaBitQModel(state RaBitQModelState) (*RaBitQModel, error)

RestoreRaBitQModel validates and restores exact portable model state.

func TrainRaBitQ

func TrainRaBitQ(ctx context.Context, vectors [][]float32, options RaBitQOptions) (*RaBitQModel, error)

TrainRaBitQ trains centroids, deterministic rotation state, and the expected extra-code scale used by the baseline's faster converter.

Example
package main

import (
	"context"
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	vectors := make([][]float32, 8)
	for row := range vectors {
		vectors[row] = make([]float32, 64)
		for column := range vectors[row] {
			vectors[row][column] = float32((row+1)*(column%7-3)) / 8
		}
	}

	options := core.DefaultRaBitQOptions(core.MetricL2)
	options.TotalBits = 3
	options.Clusters = 1
	options.MaxIterations = 2
	options.Seed = 42
	model, err := core.TrainRaBitQ(context.Background(), vectors, options)
	if err != nil {
		panic(err)
	}
	code, err := model.Encode(vectors[0])
	if err != nil {
		panic(err)
	}
	query, err := model.PrepareQuery(vectors[1])
	if err != nil {
		panic(err)
	}
	estimate, err := query.Estimate(code)
	if err != nil {
		panic(err)
	}

	fmt.Println(model.Dimension(), model.PaddedDimension(), model.TotalBits())
	fmt.Println(code.Cluster(), len(code.BinaryCode()), len(code.ExtraCode()))
	fmt.Println(estimate.LowerBound <= estimate.UpperBound)
}
Output:
64 64 3
0 8 16
true

func (*RaBitQModel) Centroids

func (m *RaBitQModel) Centroids() [][]float32

func (*RaBitQModel) Dimension

func (m *RaBitQModel) Dimension() int

func (*RaBitQModel) Encode

func (m *RaBitQModel) Encode(vector []float32) (RaBitQCode, error)

Encode converts one vector into an immutable split RaBitQ code.

func (*RaBitQModel) EncodeBatch

func (m *RaBitQModel) EncodeBatch(ctx context.Context, vectors [][]float32, workers int) ([]RaBitQCode, error)

EncodeBatch converts vectors concurrently while preserving input order.

func (*RaBitQModel) Len

func (m *RaBitQModel) Len() int

func (*RaBitQModel) Metric

func (m *RaBitQModel) Metric() Metric

func (*RaBitQModel) PaddedDimension

func (m *RaBitQModel) PaddedDimension() int

func (*RaBitQModel) PrepareQuery

func (m *RaBitQModel) PrepareQuery(vector []float32) (*RaBitQQuery, error)

PrepareQuery rotates a query and precomputes all centroid-dependent terms.

func (*RaBitQModel) State

func (m *RaBitQModel) State() RaBitQModelState

State returns an independent complete model snapshot.

func (*RaBitQModel) TotalBits

func (m *RaBitQModel) TotalBits() int

type RaBitQModelState

type RaBitQModelState struct {
	Dimension     int
	Metric        Metric
	TotalBits     int
	Centroids     [][]float32
	RotationSigns []byte
	ExtraScale    float64
}

RaBitQModelState is the complete portable state needed to restore a trained converter. Centroids are stored before rotation; RotationSigns contains four little-endian sign-bit rounds for the padded dimension.

type RaBitQOptions

type RaBitQOptions struct {
	Metric        Metric
	TotalBits     int
	Clusters      int
	SampleCount   int
	MaxIterations int
	Workers       int
	Seed          uint64
}

RaBitQOptions configures deterministic centroid and rotation training. SampleCount zero uses every vector. A fixed seed produces bit-for-bit stable model state across worker counts and supported platforms.

func DefaultRaBitQOptions

func DefaultRaBitQOptions(metric Metric) RaBitQOptions

DefaultRaBitQOptions returns the pinned public defaults.

func (RaBitQOptions) Validate

func (o RaBitQOptions) Validate() error

Validate checks options that do not depend on the training data.

type RaBitQQuery

type RaBitQQuery struct {
	// contains filtered or unexported fields
}

RaBitQQuery owns rotated query state and per-centroid factors. It is immutable and safe for concurrent estimates.

func (*RaBitQQuery) Estimate

func (q *RaBitQQuery) Estimate(code RaBitQCode) (RaBitQEstimate, error)

Estimate evaluates all configured bits. For a one-bit model it is identical to EstimateCoarse.

func (*RaBitQQuery) EstimateCoarse

func (q *RaBitQQuery) EstimateCoarse(code RaBitQCode) (RaBitQEstimate, error)

EstimateCoarse evaluates only the one-bit sign code.

type Result

type Result struct {
	Key   uint64
	Score float32
}

Result is a candidate key and its public score. Results are ordered best first, then by ascending key for equal scores.

func MergeSearchResults

func MergeSearchResults(metric Metric, k int, batches ...[]Result) []Result

MergeSearchResults selects a global top-k from segment-local results. Equal scores remain ordered by ascending key regardless of segment order.

func QueryDense

func QueryDense(
	ctx context.Context,
	metric Metric,
	searchers []DenseQuerySearcher,
	query []float32,
	options SearchOptions,
	workers int,
) ([]Result, error)

QueryDense runs segment-local exact/ANN searches and merges their already ordered results into one deterministic global top-k.

func QuerySparse

func QuerySparse(
	ctx context.Context,
	searchers []SparseQuerySearcher,
	query SparseVector,
	options SearchOptions,
	workers int,
) ([]Result, error)

QuerySparse runs segment-local sparse queries and globally merges them.

func RefinedSearch

func RefinedSearch(
	ctx context.Context,
	base DenseQuerySearcher,
	refiner DenseRefiner,
	query []float32,
	options SearchOptions,
	scaleFactor float32,
) ([]Result, error)

RefinedSearch expands the base candidate count, disables approximate-score radius pruning, and applies the exact filter/radius/top-k in the refiner.

func RefinedSparseSearch

func RefinedSparseSearch(
	ctx context.Context,
	base SparseQuerySearcher,
	refiner SparseRefiner,
	query SparseVector,
	options SearchOptions,
	scaleFactor float32,
) ([]Result, error)

RefinedSparseSearch expands the base candidate count, disables approximate radius pruning, and applies exact filter/radius/top-k in the sparse refiner.

func TopK

func TopK(
	ctx context.Context,
	metric Metric,
	query []float32,
	candidates []Candidate,
	k int,
) ([]Result, error)

TopK computes exact scores and returns at most k results. It uses O(k) memory and checks ctx between candidates.

type RotationReformer

type RotationReformer struct {
	// contains filtered or unexported fields
}

RotationReformer adapts any Rotator to the general DenseReformer contract.

func NewRotationReformer

func NewRotationReformer(rotator Rotator) (*RotationReformer, error)

NewRotationReformer constructs a reversible rotation preprocessor.

func (*RotationReformer) Dimension

func (r *RotationReformer) Dimension() int

func (*RotationReformer) Revert

func (r *RotationReformer) Revert(vector []float32) ([]float32, error)

Revert inverse-rotates a vector into original space.

func (*RotationReformer) Transform

func (r *RotationReformer) Transform(vector []float32) ([]float32, error)

Transform rotates a vector into index space.

type Rotator

type Rotator interface {
	Dimension() int
	Rotate(vector []float32) ([]float32, error)
	Unrotate(vector []float32) ([]float32, error)
}

Rotator is a dimension-preserving orthogonal dense-vector transform.

type ScalarQuantizedDiskANNIndex

type ScalarQuantizedDiskANNIndex struct {
	// contains filtered or unexported fields
}

ScalarQuantizedDiskANNIndex owns original vectors for refinement, scalar codes for public first-stage scoring, and a DiskANN graph/PQ representation built from the decoded scalar vectors. DiskANN's PQ remains an independent traversal encoding controlled by DiskANNBuildOptions.PQChunks.

func NewScalarQuantizedDiskANNIndex

func NewScalarQuantizedDiskANNIndex(
	ctx context.Context,
	dimension int,
	options DiskANNBuildOptions,
	kind Quantization,
	reformer DenseReformer,
	candidates []Candidate,
) (*ScalarQuantizedDiskANNIndex, error)

NewScalarQuantizedDiskANNIndex builds an immutable DiskANN index after applying an optional reformer and FP16/INT8/INT4 scalar quantization. The candidates' unmodified vectors remain available through Vector.

func OpenScalarQuantizedDiskANNIndex

func OpenScalarQuantizedDiskANNIndex(
	ctx context.Context,
	path string,
	cacheCapacity, workers int,
	kind Quantization,
	reformer DenseReformer,
	candidates []Candidate,
) (*ScalarQuantizedDiskANNIndex, error)

OpenScalarQuantizedDiskANNIndex reopens a persisted DiskANN graph and restores public scalar-code scoring from the collection-owned originals.

func OpenScalarQuantizedDiskANNIndexWithMmap

func OpenScalarQuantizedDiskANNIndexWithMmap(
	ctx context.Context,
	path string,
	cacheCapacity, workers int,
	kind Quantization,
	reformer DenseReformer,
	candidates []Candidate,
	useMmap bool,
) (*ScalarQuantizedDiskANNIndex, error)

OpenScalarQuantizedDiskANNIndexWithMmap reopens a persisted graph through the selected random-access reader and restores scalar-code scoring.

func (*ScalarQuantizedDiskANNIndex) BuildOptions

func (*ScalarQuantizedDiskANNIndex) CacheStats

func (*ScalarQuantizedDiskANNIndex) Close

Close releases the underlying DiskANN node artifact. It is idempotent.

func (*ScalarQuantizedDiskANNIndex) Dimension

func (i *ScalarQuantizedDiskANNIndex) Dimension() int

func (*ScalarQuantizedDiskANNIndex) Len

func (*ScalarQuantizedDiskANNIndex) Metric

func (i *ScalarQuantizedDiskANNIndex) Metric() Metric

func (*ScalarQuantizedDiskANNIndex) PQChunks

func (i *ScalarQuantizedDiskANNIndex) PQChunks() int

func (*ScalarQuantizedDiskANNIndex) Save

Save persists the DiskANN graph and its traversal representation. Original vectors remain in the collection segment and are supplied again on open.

func (*ScalarQuantizedDiskANNIndex) Search

func (i *ScalarQuantizedDiskANNIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*ScalarQuantizedDiskANNIndex) SearchDiskANN

func (i *ScalarQuantizedDiskANNIndex) SearchDiskANN(ctx context.Context, query []float32, options DiskANNSearchOptions) ([]Result, error)

SearchDiskANN traverses the graph using DiskANN's internal PQ over decoded scalar vectors, then ranks the visited candidates with the public scalar quantization kernel.

func (*ScalarQuantizedDiskANNIndex) SearchWithOptions

func (i *ScalarQuantizedDiskANNIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*ScalarQuantizedDiskANNIndex) Vector

func (i *ScalarQuantizedDiskANNIndex) Vector(key uint64) ([]float32, bool)

func (*ScalarQuantizedDiskANNIndex) WarmCache

func (i *ScalarQuantizedDiskANNIndex) WarmCache(ctx context.Context, count int) (int, error)

WarmCache delegates to the immutable DiskANN node cache.

type ScalarQuantizedFlatIndex

type ScalarQuantizedFlatIndex struct {
	// contains filtered or unexported fields
}

ScalarQuantizedFlatIndex stores original vectors for optional refinement and immutable FP16/INT8/INT4 codes for first-stage scoring.

func NewScalarQuantizedFlatIndex

func NewScalarQuantizedFlatIndex(
	ctx context.Context,
	dimension int,
	metric Metric,
	kind Quantization,
	reformer DenseReformer,
	candidates []Candidate,
) (*ScalarQuantizedFlatIndex, error)

NewScalarQuantizedFlatIndex validates and owns a scalar-quantized copy of candidates. An optional reformer is applied before quantization to both stored vectors and queries.

func (*ScalarQuantizedFlatIndex) Dimension

func (i *ScalarQuantizedFlatIndex) Dimension() int

func (*ScalarQuantizedFlatIndex) Len

func (i *ScalarQuantizedFlatIndex) Len() int

func (*ScalarQuantizedFlatIndex) Metric

func (i *ScalarQuantizedFlatIndex) Metric() Metric

func (*ScalarQuantizedFlatIndex) Search

func (i *ScalarQuantizedFlatIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*ScalarQuantizedFlatIndex) SearchGroups

func (i *ScalarQuantizedFlatIndex) SearchGroups(
	ctx context.Context,
	query []float32,
	options GroupByOptions,
) ([]GroupResult, error)

SearchGroups scans scalar codes and retains the best candidates inside each resolved group.

func (*ScalarQuantizedFlatIndex) SearchWithOptions

func (i *ScalarQuantizedFlatIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*ScalarQuantizedFlatIndex) Vector

func (i *ScalarQuantizedFlatIndex) Vector(key uint64) ([]float32, bool)

type ScalarQuantizedHNSWIndex

type ScalarQuantizedHNSWIndex struct {
	// contains filtered or unexported fields
}

ScalarQuantizedHNSWIndex owns a stable HNSW topology, original vectors for refinement, and scalar codes used for graph traversal and candidate scores. It is immutable; stream additions belong to the unquantized source index and require constructing a new quantized snapshot.

func NewScalarQuantizedHNSWIndex

func NewScalarQuantizedHNSWIndex(
	ctx context.Context,
	base *HNSWIndex,
	kind Quantization,
	reformer DenseReformer,
) (*ScalarQuantizedHNSWIndex, error)

NewScalarQuantizedHNSWIndex snapshots base and quantizes every vector after applying the optional dimension-preserving reformer.

func OpenScalarQuantizedHNSWIndex

func OpenScalarQuantizedHNSWIndex(ctx context.Context, path string, kind Quantization, reformer DenseReformer) (*ScalarQuantizedHNSWIndex, error)

OpenScalarQuantizedHNSWIndex reopens a persisted topology and reconstructs its immutable scalar-code scoring representation.

func (*ScalarQuantizedHNSWIndex) BuildOptions

func (i *ScalarQuantizedHNSWIndex) BuildOptions() HNSWBuildOptions

func (*ScalarQuantizedHNSWIndex) Dimension

func (i *ScalarQuantizedHNSWIndex) Dimension() int

func (*ScalarQuantizedHNSWIndex) Len

func (i *ScalarQuantizedHNSWIndex) Len() int

func (*ScalarQuantizedHNSWIndex) Metric

func (i *ScalarQuantizedHNSWIndex) Metric() Metric

func (*ScalarQuantizedHNSWIndex) Save

Save persists the immutable HNSW topology and original vectors. Scalar codes are deterministically reconstructed from the supplied quantizer and reformer when the artifact is reopened.

func (*ScalarQuantizedHNSWIndex) Search

func (i *ScalarQuantizedHNSWIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*ScalarQuantizedHNSWIndex) SearchHNSW

func (i *ScalarQuantizedHNSWIndex) SearchHNSW(ctx context.Context, query []float32, options HNSWSearchOptions) ([]Result, error)

SearchHNSW executes scalar-code graph traversal with explicit EF and prefetch controls.

func (*ScalarQuantizedHNSWIndex) SearchHNSWGroups

func (i *ScalarQuantizedHNSWIndex) SearchHNSWGroups(
	ctx context.Context,
	query []float32,
	options HNSWGroupSearchOptions,
) ([]GroupResult, error)

SearchHNSWGroups traverses the HNSW topology with scalar-code scores and expands level zero when the first candidate set lacks enough groups.

func (*ScalarQuantizedHNSWIndex) SearchWithOptions

func (i *ScalarQuantizedHNSWIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*ScalarQuantizedHNSWIndex) Vector

func (i *ScalarQuantizedHNSWIndex) Vector(key uint64) ([]float32, bool)

type ScalarQuantizedIVFIndex

type ScalarQuantizedIVFIndex struct {
	// contains filtered or unexported fields
}

ScalarQuantizedIVFIndex owns a stable IVF snapshot, scalar codes for list scoring, and the original vectors used by an optional exact refiner.

func NewScalarQuantizedIVFIndex

func NewScalarQuantizedIVFIndex(
	ctx context.Context,
	base *IVFIndex,
	kind Quantization,
	reformer DenseReformer,
) (*ScalarQuantizedIVFIndex, error)

NewScalarQuantizedIVFIndex snapshots base and scalar-quantizes its vectors.

func OpenScalarQuantizedIVFIndex

func OpenScalarQuantizedIVFIndex(ctx context.Context, path string, kind Quantization, reformer DenseReformer) (*ScalarQuantizedIVFIndex, error)

OpenScalarQuantizedIVFIndex reopens a persisted IVF topology and restores scalar-code scoring.

func (*ScalarQuantizedIVFIndex) BuildOptions

func (i *ScalarQuantizedIVFIndex) BuildOptions() IVFBuildOptions

func (*ScalarQuantizedIVFIndex) Dimension

func (i *ScalarQuantizedIVFIndex) Dimension() int

func (*ScalarQuantizedIVFIndex) Len

func (i *ScalarQuantizedIVFIndex) Len() int

func (*ScalarQuantizedIVFIndex) Metric

func (i *ScalarQuantizedIVFIndex) Metric() Metric

func (*ScalarQuantizedIVFIndex) NList

func (i *ScalarQuantizedIVFIndex) NList() int

func (*ScalarQuantizedIVFIndex) Save

func (i *ScalarQuantizedIVFIndex) Save(ctx context.Context, path string) error

Save persists the immutable IVF topology and original vectors. Scalar codes are reconstructed deterministically when reopened.

func (*ScalarQuantizedIVFIndex) Search

func (i *ScalarQuantizedIVFIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*ScalarQuantizedIVFIndex) SearchIVF

func (i *ScalarQuantizedIVFIndex) SearchIVF(ctx context.Context, query []float32, options IVFSearchOptions) ([]Result, error)

SearchIVF selects centroids with the original metric and scores vectors in the selected lists using scalar codes.

func (*ScalarQuantizedIVFIndex) SearchWithOptions

func (i *ScalarQuantizedIVFIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*ScalarQuantizedIVFIndex) Vector

func (i *ScalarQuantizedIVFIndex) Vector(key uint64) ([]float32, bool)

type ScalarQuantizedVamanaIndex

type ScalarQuantizedVamanaIndex struct {
	// contains filtered or unexported fields
}

ScalarQuantizedVamanaIndex owns an immutable Vamana topology, original vectors for refinement, and scalar codes used for traversal and ranking.

func NewScalarQuantizedVamanaIndex

func NewScalarQuantizedVamanaIndex(
	ctx context.Context,
	base *VamanaIndex,
	kind Quantization,
	reformer DenseReformer,
) (*ScalarQuantizedVamanaIndex, error)

NewScalarQuantizedVamanaIndex snapshots base and quantizes every vector after applying the optional dimension-preserving reformer.

func OpenScalarQuantizedVamanaIndex

func OpenScalarQuantizedVamanaIndex(ctx context.Context, path string, kind Quantization, reformer DenseReformer) (*ScalarQuantizedVamanaIndex, error)

OpenScalarQuantizedVamanaIndex reopens a persisted topology and restores scalar-code scoring.

func (*ScalarQuantizedVamanaIndex) BuildOptions

func (*ScalarQuantizedVamanaIndex) Dimension

func (i *ScalarQuantizedVamanaIndex) Dimension() int

func (*ScalarQuantizedVamanaIndex) Len

func (*ScalarQuantizedVamanaIndex) Metric

func (i *ScalarQuantizedVamanaIndex) Metric() Metric

func (*ScalarQuantizedVamanaIndex) Save

Save persists the immutable Vamana topology and original vectors. Scalar codes are reconstructed deterministically when reopened.

func (*ScalarQuantizedVamanaIndex) Search

func (i *ScalarQuantizedVamanaIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*ScalarQuantizedVamanaIndex) SearchVamana

func (i *ScalarQuantizedVamanaIndex) SearchVamana(ctx context.Context, query []float32, options VamanaSearchOptions) ([]Result, error)

func (*ScalarQuantizedVamanaIndex) SearchWithOptions

func (i *ScalarQuantizedVamanaIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*ScalarQuantizedVamanaIndex) Vector

func (i *ScalarQuantizedVamanaIndex) Vector(key uint64) ([]float32, bool)

type SearchOptions

type SearchOptions struct {
	TopK   int
	Radius float32
	Filter CandidateFilter
}

SearchOptions contains collection-query controls shared by exact and ANN indexes. Radius zero disables range filtering. For IP, a positive radius is a minimum similarity; for distance metrics it is a maximum distance.

func (SearchOptions) Validate

func (o SearchOptions) Validate() error

Validate checks the public query invariants.

type SparseBuilder

type SparseBuilder interface {
	AddSparse(ctx context.Context, key uint64, vector SparseVector) error
	Build(ctx context.Context) (SparseIndex, error)
}

SparseBuilder collects sparse vectors and transfers its index on Build.

type SparseFlatIndex

type SparseFlatIndex struct {
	// contains filtered or unexported fields
}

SparseFlatIndex stores vectors in compressed sparse row form and performs an exact inner-product scan. Sparse Flat supports only IP, matching the public schema constraints.

func NewSparseFlatIndex

func NewSparseFlatIndex(metric Metric) (*SparseFlatIndex, error)

NewSparseFlatIndex constructs an empty sparse IP index.

func (*SparseFlatIndex) AddSparse

func (i *SparseFlatIndex) AddSparse(ctx context.Context, key uint64, vector SparseVector) error

AddSparse validates, clones, and appends one canonical sparse vector.

func (*SparseFlatIndex) Len

func (i *SparseFlatIndex) Len() int

Len returns the number of indexed sparse vectors.

func (*SparseFlatIndex) Metric

func (i *SparseFlatIndex) Metric() Metric

Metric returns the only supported sparse metric.

func (*SparseFlatIndex) SearchSparse

func (i *SparseFlatIndex) SearchSparse(ctx context.Context, query SparseVector, k int) ([]Result, error)

SearchSparse evaluates exact inner products and returns highest scores first, breaking equal scores by ascending key.

func (*SparseFlatIndex) SearchSparseGroups

func (i *SparseFlatIndex) SearchSparseGroups(ctx context.Context, query SparseVector, options GroupByOptions) ([]GroupResult, error)

SearchSparseGroups scans every eligible sparse candidate using exact inner product and applies grouping only after the candidate filter and radius.

func (*SparseFlatIndex) SearchSparseWithOptions

func (i *SparseFlatIndex) SearchSparseWithOptions(ctx context.Context, query SparseVector, options SearchOptions) ([]Result, error)

SearchSparseWithOptions applies candidate and radius filtering before exact top-k retention.

func (*SparseFlatIndex) SparseVector

func (i *SparseFlatIndex) SparseVector(key uint64) (SparseVector, bool)

SparseVector returns an independent vector copy by key.

type SparseFlatIndexBuilder

type SparseFlatIndexBuilder struct {
	// contains filtered or unexported fields
}

SparseFlatIndexBuilder is a one-shot sparse Flat builder.

func NewSparseFlatBuilder

func NewSparseFlatBuilder(metric Metric) (*SparseFlatIndexBuilder, error)

NewSparseFlatBuilder constructs a sparse IP builder.

func (*SparseFlatIndexBuilder) AddSparse

func (b *SparseFlatIndexBuilder) AddSparse(ctx context.Context, key uint64, vector SparseVector) error

AddSparse appends while the builder is open.

func (*SparseFlatIndexBuilder) Build

Build closes the builder and returns its streamable sparse index.

type SparseGroupSearcher

type SparseGroupSearcher interface {
	Metric() Metric
	SearchSparseGroups(ctx context.Context, query SparseVector, options GroupByOptions) ([]GroupResult, error)
}

SparseGroupSearcher executes one segment-local sparse group-by query.

type SparseHNSWBuilder

type SparseHNSWBuilder struct {
	// contains filtered or unexported fields
}

SparseHNSWBuilder collects canonical sparse vectors and constructs one deterministic graph.

func NewSparseHNSWBuilder

func NewSparseHNSWBuilder(options HNSWBuildOptions) (*SparseHNSWBuilder, error)

NewSparseHNSWBuilder constructs an empty one-shot sparse HNSW builder.

func (*SparseHNSWBuilder) AddSparse

func (b *SparseHNSWBuilder) AddSparse(ctx context.Context, key uint64, vector SparseVector) error

AddSparse validates and clones one unique canonical vector while the builder remains open.

func (*SparseHNSWBuilder) Build

Build assigns deterministic levels, inserts nodes in input order on one worker, and transfers the builder-owned CSR vectors to the resulting graph.

func (*SparseHNSWBuilder) BuildWithWorkers

func (b *SparseHNSWBuilder) BuildWithWorkers(ctx context.Context, workers int) (*SparseHNSWIndex, error)

BuildWithWorkers constructs the graph with up to workers concurrent node insertions. A single worker is bit-for-bit deterministic; multiple workers preserve graph invariants but topology may vary with goroutine scheduling.

type SparseHNSWIndex

type SparseHNSWIndex struct {
	// contains filtered or unexported fields
}

SparseHNSWIndex stores canonical FP32 sparse vectors in CSR form and a bounded multi-layer proximity graph. Readers share one immutable generation while additions publish a complete copy-on-write generation.

func OpenSparseHNSWIndex

func OpenSparseHNSWIndex(ctx context.Context, path string) (*SparseHNSWIndex, error)

OpenSparseHNSWIndex reads and fully verifies a native Go sparse HNSW artifact. The returned graph owns its decoded memory.

func (*SparseHNSWIndex) AddSparse

func (i *SparseHNSWIndex) AddSparse(ctx context.Context, key uint64, vector SparseVector) error

AddSparse incrementally inserts one unique key and canonical sparse vector. The insertion is planned on a private graph generation and becomes visible in one commit, so cancellation never exposes partial CSR or topology state.

func (*SparseHNSWIndex) BuildOptions

func (i *SparseHNSWIndex) BuildOptions() HNSWBuildOptions

BuildOptions returns the value-semantic construction settings.

func (*SparseHNSWIndex) EntryPoint

func (i *SparseHNSWIndex) EntryPoint() (uint64, bool)

EntryPoint returns the current top-layer entry key.

func (*SparseHNSWIndex) Len

func (i *SparseHNSWIndex) Len() int

Len returns the number of graph nodes.

func (*SparseHNSWIndex) Level

func (i *SparseHNSWIndex) Level(key uint64) (int, bool)

Level returns a node's maximum graph level.

func (*SparseHNSWIndex) MaxLevel

func (i *SparseHNSWIndex) MaxLevel() int

MaxLevel returns the highest occupied graph level, or -1 for an empty graph.

func (*SparseHNSWIndex) Metric

func (i *SparseHNSWIndex) Metric() Metric

Metric returns inner product, the only supported sparse HNSW metric.

func (*SparseHNSWIndex) Neighbors

func (i *SparseHNSWIndex) Neighbors(key uint64, level int) ([]uint64, error)

Neighbors returns cloned neighbor keys in deterministic selection order.

func (*SparseHNSWIndex) Save

func (i *SparseHNSWIndex) Save(ctx context.Context, path string) error

Save durably publishes one complete graph snapshot as a checksummed native Go sparse HNSW file.

func (*SparseHNSWIndex) SearchSparse

func (i *SparseHNSWIndex) SearchSparse(ctx context.Context, query SparseVector, k int) ([]Result, error)

SearchSparse uses the pinned default EF. A zero top-k returns an empty result for consistency with the common SparseSearcher contract.

func (*SparseHNSWIndex) SearchSparseHNSW

func (i *SparseHNSWIndex) SearchSparseHNSW(ctx context.Context, query SparseVector, options HNSWSearchOptions) ([]Result, error)

SearchSparseHNSW executes an inner-product hierarchical graph query with an explicit EF. EF smaller than TopK is raised to TopK for candidate retention.

func (*SparseHNSWIndex) SearchSparseHNSWGroups

func (i *SparseHNSWIndex) SearchSparseHNSWGroups(
	ctx context.Context,
	query SparseVector,
	options HNSWGroupSearchOptions,
) ([]GroupResult, error)

SearchSparseHNSWGroups performs native sparse HNSW group traversal and expands level zero when the initial candidates do not cover enough groups.

func (*SparseHNSWIndex) SearchSparseWithOptions

func (i *SparseHNSWIndex) SearchSparseWithOptions(ctx context.Context, query SparseVector, options SearchOptions) ([]Result, error)

SearchSparseWithOptions applies common filter and radius controls with the pinned default EF.

func (*SparseHNSWIndex) SparseVector

func (i *SparseHNSWIndex) SparseVector(key uint64) (SparseVector, bool)

SparseVector returns a cloned canonical vector by key.

type SparseIndex

type SparseIndex interface {
	SparseProvider
	SparseSearcher
	SparseStreamer
}

SparseIndex combines sparse provider, search, and streaming capabilities.

type SparseProvider

type SparseProvider interface {
	Len() int
	SparseVector(key uint64) (SparseVector, bool)
}

SparseProvider exposes cloned sparse vectors by document key.

type SparseQuerySearcher

type SparseQuerySearcher interface {
	Metric() Metric
	SearchSparseWithOptions(ctx context.Context, query SparseVector, options SearchOptions) ([]Result, error)
}

SparseQuerySearcher executes one segment-local sparse query.

type SparseRefiner

type SparseRefiner interface {
	Metric() Metric
	RefineSparse(ctx context.Context, query SparseVector, candidates []Result, options SearchOptions) ([]Result, error)
}

SparseRefiner re-scores approximate sparse candidates in an exact representation. Sparse collection indexes use inner product exclusively.

type SparseSearcher

type SparseSearcher interface {
	SearchSparse(ctx context.Context, query SparseVector, k int) ([]Result, error)
}

SparseSearcher is the common sparse exact/ANN search contract.

type SparseStreamer

type SparseStreamer interface {
	AddSparse(ctx context.Context, key uint64, vector SparseVector) error
}

SparseStreamer accepts incremental canonical sparse vectors.

type SparseVector

type SparseVector struct {
	Indices []uint32
	Values  []float32
}

SparseVector is a canonical sparse FP32 vector. Indices must be strictly increasing and Values must be finite.

type VamanaBuildOptions

type VamanaBuildOptions struct {
	Metric           Metric
	MaxDegree        int
	SearchListSize   int
	Alpha            float32
	MaxOcclusionSize int
	SaturateGraph    bool
}

VamanaBuildOptions configures deterministic single-layer graph construction.

func DefaultVamanaBuildOptions

func DefaultVamanaBuildOptions(metric Metric) VamanaBuildOptions

DefaultVamanaBuildOptions returns the pinned public construction defaults.

func (VamanaBuildOptions) Validate

func (o VamanaBuildOptions) Validate() error

Validate checks graph degree, construction width, and RobustPrune settings.

type VamanaBuilder

type VamanaBuilder struct {
	// contains filtered or unexported fields
}

VamanaBuilder collects original vectors for one deterministic graph build.

Example
package main

import (
	"context"
	"fmt"

	"github.com/gorse-io/xvec/internal/core"
)

func main() {
	options := core.DefaultVamanaBuildOptions(core.MetricL2)
	builder, err := core.NewVamanaBuilder(2, options)
	if err != nil {
		panic(err)
	}
	for _, candidate := range []core.Candidate{
		{Key: 10, Vector: []float32{1, 0}},
		{Key: 20, Vector: []float32{0, 1}},
		{Key: 30, Vector: []float32{-1, 0}},
	} {
		if err := builder.Add(context.Background(), candidate.Key, candidate.Vector); err != nil {
			panic(err)
		}
	}
	index, err := builder.Build(context.Background())
	if err != nil {
		panic(err)
	}
	results, err := index.SearchVamana(context.Background(), []float32{.9, .1}, core.VamanaSearchOptions{
		SearchOptions: core.SearchOptions{TopK: 2}, EFSearch: 20,
	})
	if err != nil {
		panic(err)
	}
	keys := make([]uint64, len(results))
	for position, result := range results {
		keys[position] = result.Key
	}
	fmt.Println(keys)
}
Output:
[10 20]

func NewVamanaBuilder

func NewVamanaBuilder(dimension int, options VamanaBuildOptions) (*VamanaBuilder, error)

NewVamanaBuilder constructs an empty one-shot builder.

func (*VamanaBuilder) Add

func (b *VamanaBuilder) Add(ctx context.Context, key uint64, vector []float32) error

Add validates and clones one unique vector while the builder is open.

func (*VamanaBuilder) Build

func (b *VamanaBuilder) Build(ctx context.Context) (*VamanaIndex, error)

Build inserts vectors in input order, applies RobustPrune and reverse-link updates, then selects the persisted-search medoid entry point.

type VamanaIndex

type VamanaIndex struct {
	// contains filtered or unexported fields
}

VamanaIndex stores original FP32 vectors and one bounded directed graph. Readers share an immutable generation while Add publishes copy-on-write.

func OpenVamanaIndex

func OpenVamanaIndex(ctx context.Context, path string) (*VamanaIndex, error)

OpenVamanaIndex reads and verifies a native Go Vamana artifact.

func (*VamanaIndex) Add

func (i *VamanaIndex) Add(ctx context.Context, key uint64, vector []float32) error

Add streams one vector into a private graph copy and atomically publishes the complete topology/vector/medoid generation.

func (*VamanaIndex) BuildOptions

func (i *VamanaIndex) BuildOptions() VamanaBuildOptions

func (*VamanaIndex) Dimension

func (i *VamanaIndex) Dimension() int

func (*VamanaIndex) EntryPoint

func (i *VamanaIndex) EntryPoint() (uint64, bool)

func (*VamanaIndex) Len

func (i *VamanaIndex) Len() int

func (*VamanaIndex) Metric

func (i *VamanaIndex) Metric() Metric

func (*VamanaIndex) Neighbors

func (i *VamanaIndex) Neighbors(key uint64) ([]uint64, error)

Neighbors returns cloned outbound neighbor keys in prune-selection order.

func (*VamanaIndex) Save

func (i *VamanaIndex) Save(ctx context.Context, path string) error

Save atomically publishes one complete native graph generation.

func (*VamanaIndex) Search

func (i *VamanaIndex) Search(ctx context.Context, query []float32, k int) ([]Result, error)

func (*VamanaIndex) SearchVamana

func (i *VamanaIndex) SearchVamana(ctx context.Context, query []float32, options VamanaSearchOptions) ([]Result, error)

SearchVamana executes one metric-aware beam search. EFSearch smaller than TopK is raised to TopK, matching the pinned interface behavior.

func (*VamanaIndex) SearchWithOptions

func (i *VamanaIndex) SearchWithOptions(ctx context.Context, query []float32, options SearchOptions) ([]Result, error)

func (*VamanaIndex) Vector

func (i *VamanaIndex) Vector(key uint64) ([]float32, bool)

type VamanaSearchOptions

type VamanaSearchOptions struct {
	SearchOptions
	EFSearch       int
	PrefetchOffset uint32
	PrefetchLines  uint32
}

VamanaSearchOptions combines common result controls with beam width and portable cache-warming hints.

func (VamanaSearchOptions) Validate

func (o VamanaSearchOptions) Validate() error

Directories

Path Synopsis
Package metric provides dense-vector score computation and ordering.
Package metric provides dense-vector score computation and ordering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL