Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
17fd016
record_rotater
zzlin237 Jun 5, 2026
72e2592
init
zzlin237 Jun 7, 2026
89251a2
error
zzlin237 Jun 8, 2026
46a08a5
Int8StreamingConverter
zzlin237 Jun 8, 2026
8c553f1
debug
zzlin237 Jun 8, 2026
2c4b532
CosineInt8Converter
zzlin237 Jun 8, 2026
aa209b4
python
zzlin237 Jun 8, 2026
efb0443
over
zzlin237 Jun 9, 2026
342b8a3
debug
zzlin237 Jun 9, 2026
b23a648
add int8 rotate
zzlin237 Jun 9, 2026
4d46542
add int8 rotate
zzlin237 Jun 9, 2026
494bd74
add int8 rotate
zzlin237 Jun 9, 2026
252fbcc
add int8 rotate
zzlin237 Jun 9, 2026
95490cf
add int8 rotate
zzlin237 Jun 9, 2026
4ccbefe
add int8 rotate
zzlin237 Jun 10, 2026
4d3a4b3
common param
zzlin237 Jun 10, 2026
016f474
tmp
zzlin237 Jun 11, 2026
1b9e3f2
debug
zzlin237 Jun 11, 2026
d0fea3b
tmp
zzlin237 Jun 11, 2026
b49ea9d
unrotate
zzlin237 Jun 11, 2026
848677d
update int8 rotate
zzlin237 Jun 11, 2026
6b0d29c
Merge branch 'main' of https://github.com/alibaba/zvec into rotate-int8
zzlin237 Jun 11, 2026
51806dd
add c_api
zzlin237 Jun 15, 2026
a534d18
c_api ut
zzlin237 Jun 15, 2026
6a94a68
SSE
zzlin237 Jun 15, 2026
b5ffbc5
update c_api
zzlin237 Jun 15, 2026
5175c99
Merge remote-tracking branch 'upstream/main' into rotate-int8-preprocess
zzlin237 Jun 15, 2026
ec5b382
Fix clang-format violations
zzlin237 Jun 16, 2026
ee40d45
clang-format check
zzlin237 Jun 16, 2026
7acc196
cancel padden_dim
zzlin237 Jun 16, 2026
bd782f9
tmp
zzlin237 Jun 16, 2026
12e88c6
Remove redundancy
zzlin237 Jun 16, 2026
f5ff784
macOS compatible
zzlin237 Jun 16, 2026
879261a
macOS compatible
zzlin237 Jun 16, 2026
153435a
Merge remote-tracking branch 'upstream/main' into rotate-int8
zzlin237 Jun 16, 2026
21cda64
unrotate debug
zzlin237 Jun 16, 2026
b77eef7
remove cite of rabitq
zzlin237 Jun 17, 2026
4557bb8
MSVC
zzlin237 Jun 17, 2026
ad6d6a6
merge
zzlin237 Jun 17, 2026
d1cea6a
merge main
zzlin237 Jun 17, 2026
314509d
merge main
zzlin237 Jun 17, 2026
11cc02c
COMDAT section reduced in window
zzlin237 Jun 18, 2026
899de17
fht fix
zzlin237 Jun 18, 2026
45af565
MSVC
zzlin237 Jun 19, 2026
21efc61
cancel all-in-one
zzlin237 Jun 19, 2026
be215d1
MSVC
zzlin237 Jun 20, 2026
b8b664c
fix(ci): skip shared library builds on MSVC to avoid LNK1189
zzlin237 Jun 20, 2026
462f93e
add unittest
zzlin237 Jun 22, 2026
c1cf694
add unittest
zzlin237 Jun 22, 2026
e92218f
Merge remote-tracking branch 'upstream/main' into rotate-int8-v2
zzlin237 Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 45 additions & 40 deletions .github/workflows/05-windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,46 +110,51 @@ jobs:
python -m pytest python/tests/ --basetemp=./.pytest_tmp
shell: powershell

- name: Run C++ Examples
run: |
cd "$env:GITHUB_WORKSPACE\examples\c++"
mkdir build
cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
-DCMAKE_C_COMPILER_LAUNCHER=sccache `
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
cmake --build . --config Release --parallel $env:NPROC

# Copy zvec DLLs next to the example executables so Windows can find them.
# CMake places DLLs in bin/ (RUNTIME output) and import libs in lib/.
$buildDir = "$env:GITHUB_WORKSPACE\build"
foreach ($dllName in @("zvec.dll", "zvec_core.dll", "zvec_ailego.dll")) {
$found = $false
foreach ($sub in @("$buildDir\bin", "$buildDir\bin\Release", "$buildDir\lib", "$buildDir\lib\Release")) {
$dllPath = Join-Path $sub $dllName
if (Test-Path $dllPath) {
Copy-Item $dllPath -Destination . -Force
Write-Host "Copied $dllName from $sub"
$found = $true
break
}
}
if (-not $found) {
Write-Host "WARNING: $dllName not found, searching recursively..."
$dll = Get-ChildItem -Path $buildDir -Filter $dllName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
if ($dll) {
Copy-Item $dll.FullName -Destination . -Force
Write-Host "Copied $dllName from $($dll.DirectoryName)"
} else {
Write-Error "$dllName not found anywhere under $buildDir"
}
}
}

.\db-example.exe
.\core-example.exe
.\ailego-example.exe
shell: powershell
# C++ examples are NOT built on Windows: they require all-in-one shared
# libraries (zvec.dll), but DLL builds are disabled on MSVC due to the
# PE/COFF 65535-section hard limit (LNK1189). The Python binding links
# to static libraries directly and is unaffected. C++ examples are
# tested on Linux/macOS in 03-macos-linux-build.yml.
# - name: Run C++ Examples
# run: |
# cd "$env:GITHUB_WORKSPACE\examples\c++"
# mkdir build
# cd build
# cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
# -DCMAKE_C_COMPILER_LAUNCHER=sccache `
# -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
# cmake --build . --config Release --parallel $env:NPROC
#
# # Copy zvec DLLs next to the example executables so Windows can find them.
# # CMake places DLLs in bin/ (RUNTIME output) and import libs in lib/.
# $buildDir = "$env:GITHUB_WORKSPACE\build"
# foreach ($dllName in @("zvec.dll", "zvec_core.dll", "zvec_ailego.dll")) {
# $found = $false
# foreach ($sub in @("$buildDir\bin", "$buildDir\bin\Release", "$buildDir\lib", "$buildDir\lib\Release")) {
# $dllPath = Join-Path $sub $dllName
# if (Test-Path $dllPath) {
# Copy-Item $dllPath -Destination . -Force
# Write-Host "Copied $dllName from $sub"
# $found = $true
# break
# }
# }
# if (-not $found) {
# Write-Host "WARNING: $dllName not found, searching recursively..."
# $dll = Get-ChildItem -Path $buildDir -Filter $dllName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
# if ($dll) {
# Copy-Item $dll.FullName -Destination . -Force
# Write-Host "Copied $dllName from $($dll.DirectoryName)"
# } else {
# Write-Error "$dllName not found anywhere under $buildDir"
# }
# }
# }
#
# .\db-example.exe
# .\core-example.exe
# .\ailego-example.exe
# shell: powershell

- name: Show sccache statistics
if: always()
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@ allure-*
!build_android.sh
!build_ios.sh

# congfig
doc/
config/
examples/python/
examples/c_api/
logs/
5 changes: 5 additions & 0 deletions examples/c/index_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ int main() {
zvec_index_params_set_metric_type(hnsw_params_fast, ZVEC_METRIC_TYPE_L2);
zvec_index_params_set_hnsw_params(hnsw_params_fast, 16, 100);

// Demonstrate INT8 quantization with random rotation preprocessing
// (enable_rotate rotates vectors before INT8 quantization to reduce error)
zvec_index_params_set_quantize_type(hnsw_params_fast, ZVEC_QUANTIZE_TYPE_INT8);
zvec_index_params_set_quantizer_enable_rotate(hnsw_params_fast, true);

zvec_index_params_t *hnsw_params_balanced =
zvec_index_params_create(ZVEC_INDEX_TYPE_HNSW);
if (!hnsw_params_balanced) {
Expand Down
86 changes: 86 additions & 0 deletions python/tests/test_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
IndexType,
MetricType,
QuantizeType,
QuantizerParam,
DataType,
VectorSchema,
)
Expand Down Expand Up @@ -452,3 +453,88 @@ def test_isinstance_compatibility(self):
warnings.simplefilter("always")
vq = VectorQuery(field_name="embedding", id="doc123")
assert isinstance(vq, Query)


# ----------------------------
# QuantizerParam Test Case
# ----------------------------


class TestQuantizerParam:
def test_default(self):
qp = QuantizerParam()
assert qp.enable_rotate is False

def test_enable_rotate_true(self):
qp = QuantizerParam(enable_rotate=True)
assert qp.enable_rotate is True

def test_enable_rotate_false(self):
qp = QuantizerParam(enable_rotate=False)
assert qp.enable_rotate is False

def test_equality(self):
qp1 = QuantizerParam(enable_rotate=True)
qp2 = QuantizerParam(enable_rotate=True)
qp3 = QuantizerParam(enable_rotate=False)
assert qp1 == qp2
assert qp1 != qp3

def test_to_dict(self):
qp = QuantizerParam(enable_rotate=True)
d = qp.to_dict()
assert isinstance(d, dict)
assert d.get("enable_rotate") is True

def test_repr(self):
qp = QuantizerParam(enable_rotate=True)
r = repr(qp)
assert "enable_rotate" in r or "QuantizerParam" in r

def test_pickle_roundtrip(self):
import pickle

qp = QuantizerParam(enable_rotate=True)
data = pickle.dumps(qp)
qp2 = pickle.loads(data)
assert qp2.enable_rotate is True
assert qp == qp2


# ----------------------------
# HnswIndexParam with QuantizerParam
# ----------------------------


class TestHnswIndexParamQuantizer:
def test_default_quantizer_param(self):
param = HnswIndexParam()
assert param.quantizer_param is not None
assert param.quantizer_param.enable_rotate is False

def test_with_quantizer_param(self):
qp = QuantizerParam(enable_rotate=True)
param = HnswIndexParam(
metric_type=MetricType.L2,
quantize_type=QuantizeType.INT8,
quantizer_param=qp,
)
assert param.quantizer_param.enable_rotate is True
assert param.quantize_type == QuantizeType.INT8


# ----------------------------
# FlatIndexParam with QuantizerParam
# ----------------------------


class TestFlatIndexParamQuantizer:
def test_with_quantizer_param(self):
qp = QuantizerParam(enable_rotate=True)
param = FlatIndexParam(
metric_type=MetricType.L2,
quantize_type=QuantizeType.INT8,
quantizer_param=qp,
)
assert param.quantizer_param.enable_rotate is True
assert param.quantize_type == QuantizeType.INT8
2 changes: 2 additions & 0 deletions python/zvec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
IVFIndexParam,
IVFQueryParam,
OptimizeOption,
QuantizerParam,
VamanaIndexParam,
VamanaQueryParam,
)
Expand Down Expand Up @@ -171,6 +172,7 @@
"HnswQueryParam",
"HnswRabitqQueryParam",
"IVFQueryParam",
"QuantizerParam",
"VamanaIndexParam",
"VamanaQueryParam",
# Extensions
Expand Down
2 changes: 2 additions & 0 deletions python/zvec/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ from .model.param import (
IVFIndexParam,
IVFQueryParam,
OptimizeOption,
QuantizerParam,
VamanaIndexParam,
VamanaQueryParam,
)
Expand Down Expand Up @@ -74,6 +75,7 @@ __all__: list = [
"MetricType",
"OptimizeOption",
"QuantizeType",
"QuantizerParam",
"Query",
"ReRanker",
"RrfReRanker",
Expand Down
2 changes: 2 additions & 0 deletions python/zvec/model/param/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
IVFIndexParam,
IVFQueryParam,
OptimizeOption,
QuantizerParam,
VamanaIndexParam,
VamanaQueryParam,
)
Expand All @@ -53,6 +54,7 @@
"IndexOption",
"InvertIndexParam",
"OptimizeOption",
"QuantizerParam",
"VamanaIndexParam",
"VamanaQueryParam",
]
60 changes: 60 additions & 0 deletions python/zvec/model/param/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ __all__: list[str] = [
"IndexParam",
"InvertIndexParam",
"OptimizeOption",
"QuantizerParam",
"QueryParam",
"SegmentOption",
"VectorIndexParam",
Expand Down Expand Up @@ -145,6 +146,8 @@ class FlatIndexParam(VectorIndexParam):
quantize_type (QuantizeType): Optional quantization type for vector
compression (e.g., FP16, INT8). Use ``QuantizeType.UNDEFINED`` to
disable quantization. Default is ``QuantizeType.UNDEFINED``.
quantizer_param (QuantizerParam): Quantizer configuration (e.g., enable_rotate).
Default is ``QuantizerParam()``.

Examples:
>>> from zvec.typing import MetricType, QuantizeType
Expand All @@ -161,6 +164,7 @@ class FlatIndexParam(VectorIndexParam):
self,
metric_type: _zvec.typing.MetricType = ...,
quantize_type: _zvec.typing.QuantizeType = ...,
quantizer_param: QuantizerParam = ...,
) -> None:
"""
Constructs a FlatIndexParam instance.
Expand All @@ -169,6 +173,8 @@ class FlatIndexParam(VectorIndexParam):
metric_type (MetricType, optional): Distance metric. Defaults to MetricType.IP.
quantize_type (QuantizeType, optional): Vector quantization type.
Defaults to QuantizeType.UNDEFINED (no quantization).
quantizer_param (QuantizerParam, optional): Quantizer configuration.
Defaults to QuantizerParam().
"""

def __repr__(self) -> str: ...
Expand Down Expand Up @@ -224,6 +230,7 @@ class HnswIndexParam(VectorIndexParam):
ef_construction: typing.SupportsInt = 500,
quantize_type: _zvec.typing.QuantizeType = ...,
use_contiguous_memory: bool = False,
quantizer_param: QuantizerParam = ...,
) -> None: ...
def __repr__(self) -> str: ...
def __setstate__(self, arg0: tuple) -> None: ...
Expand Down Expand Up @@ -496,6 +503,7 @@ class IVFIndexParam(VectorIndexParam):
n_iters: typing.SupportsInt = 10,
use_soar: bool = False,
quantize_type: _zvec.typing.QuantizeType = ...,
quantizer_param: QuantizerParam = ...,
) -> None:
"""
Constructs an IVFIndexParam instance.
Expand All @@ -509,6 +517,8 @@ class IVFIndexParam(VectorIndexParam):
use_soar (bool, optional): Enable SOAR optimization. Defaults to False.
quantize_type (QuantizeType, optional): Vector quantization type.
Defaults to QuantizeType.UNDEFINED.
quantizer_param (QuantizerParam, optional): Quantizer configuration.
Defaults to QuantizerParam().
"""

def __repr__(self) -> str: ...
Expand Down Expand Up @@ -912,6 +922,49 @@ class SegmentOption:
bool: Whether the segment is read-only.
"""

class QuantizerParam:
"""

Parameters for quantizer configuration.

Encapsulates quantization-related settings such as enable_rotate.
Designed for future extensibility.

Attributes:
enable_rotate (bool): Whether to apply random rotation before INT8
quantization to reduce quantization error.
Only effective with quantize_type=INT8. Defaults to False.

Examples:
>>> qp = QuantizerParam(enable_rotate=True)
>>> print(qp.enable_rotate)
True
"""

def __getstate__(self) -> tuple: ...
def __init__(self, enable_rotate: bool = False) -> None:
"""
Constructs a QuantizerParam instance.

Args:
enable_rotate (bool, optional): Whether to apply random rotation
before INT8 quantization. Defaults to False.
"""

def __repr__(self) -> str: ...
def __setstate__(self, arg0: tuple) -> None: ...
def __eq__(self, arg0: typing.Any) -> bool: ...
def to_dict(self) -> dict:
"""
Convert to dictionary with all fields
"""

@property
def enable_rotate(self) -> bool:
"""
bool: Whether random rotation is enabled before INT8 quantization.
"""

class VectorIndexParam(IndexParam):
"""

Expand All @@ -923,6 +976,7 @@ class VectorIndexParam(IndexParam):
type (IndexType): The specific vector index type (e.g., HNSW, FLAT).
metric_type (MetricType): Distance metric used for similarity search.
quantize_type (QuantizeType): Optional vector quantization type.
quantizer_param (QuantizerParam): Quantizer configuration (e.g., enable_rotate).
"""

def __getstate__(self) -> tuple: ...
Expand All @@ -944,6 +998,12 @@ class VectorIndexParam(IndexParam):
QuantizeType: Vector quantization type (e.g., FP16, INT8).
"""

@property
def quantizer_param(self) -> QuantizerParam:
"""
QuantizerParam: Quantizer configuration including enable_rotate.
"""

class _SearchQuery:
field_name: str
filter: str
Expand Down
Loading
Loading