API Reference¶
Complete API documentation for PyVq.
Distance¶
class Distance:
"""Compute vector distances with SIMD acceleration."""
@staticmethod
def euclidean() -> Distance
@staticmethod
def squared_euclidean() -> Distance
@staticmethod
def manhattan() -> Distance
@staticmethod
def cosine() -> Distance
def compute(self, a: np.ndarray, b: np.ndarray) -> float
"""Compute distance between two float32 arrays."""
Example:
dist = pyvq.Distance.euclidean()
result = dist.compute(np.array([1.0, 2.0], dtype=np.float32),
np.array([3.0, 4.0], dtype=np.float32))
BinaryQuantizer¶
class BinaryQuantizer:
"""Maps values to 0 or 1 based on a threshold."""
def __init__(self, threshold: float, low: int = 0, high: int = 1)
def quantize(self, values: np.ndarray) -> np.ndarray
"""Input: float32, Output: uint8"""
def dequantize(self, codes: np.ndarray) -> np.ndarray
def quantize_batch(self, vectors: np.ndarray) -> np.ndarray
def dequantize_batch(self, codes: np.ndarray) -> np.ndarray
"""Input: uint8, Output: float32"""
# Properties
threshold: float
low: int
high: int
Example:
bq = pyvq.BinaryQuantizer(threshold=0.0)
codes = bq.quantize(np.array([-0.5, 0.5], dtype=np.float32))
# Returns: [0, 1]
ScalarQuantizer¶
class ScalarQuantizer:
"""Uniformly quantizes values to discrete levels."""
def __init__(self, min: float, max: float, levels: int = 256)
def quantize(self, values: np.ndarray) -> np.ndarray
"""Input: float32, Output: uint8"""
def dequantize(self, codes: np.ndarray) -> np.ndarray
def quantize_batch(self, vectors: np.ndarray) -> np.ndarray
def dequantize_batch(self, codes: np.ndarray) -> np.ndarray
"""Input: uint8, Output: float32"""
# Properties
min: float
max: float
levels: int
step: float
Example:
sq = pyvq.ScalarQuantizer(min=-1.0, max=1.0, levels=256)
codes = sq.quantize(np.array([0.0, 0.5], dtype=np.float32))
reconstructed = sq.dequantize(codes)
ProductQuantizer¶
class ProductQuantizer:
"""Divides vectors into subspaces and quantizes each separately."""
def __init__(
self,
training_data: np.ndarray, # 2D float32 array
num_subspaces: int,
num_centroids: int,
max_iters: int = 10,
distance: Distance = None,
seed: int = 42
)
def quantize(self, vector: np.ndarray) -> np.ndarray
"""Input: float32, Output: float16"""
def dequantize(self, codes: np.ndarray) -> np.ndarray
def quantize_batch(self, vectors: np.ndarray) -> np.ndarray
def dequantize_batch(self, codes: np.ndarray) -> np.ndarray
"""Input: float16, Output: float32"""
# Properties
num_subspaces: int
sub_dim: int
dim: int
Example:
training = np.random.randn(100, 16).astype(np.float32)
pq = pyvq.ProductQuantizer(
training_data=training,
num_subspaces=4,
num_centroids=8,
distance=pyvq.Distance.euclidean()
)
codes = pq.quantize(training[0])
TSVQ¶
class TSVQ:
"""Tree-structured vector quantizer using hierarchical clustering."""
def __init__(
self,
training_data: np.ndarray, # 2D float32 array
max_depth: int,
distance: Distance = None
)
def quantize(self, vector: np.ndarray) -> np.ndarray
"""Input: float32, Output: float16"""
def dequantize(self, codes: np.ndarray) -> np.ndarray
def quantize_batch(self, vectors: np.ndarray) -> np.ndarray
def dequantize_batch(self, codes: np.ndarray) -> np.ndarray
"""Input: float16, Output: float32"""
# Properties
dim: int
Example:
training = np.random.randn(100, 32).astype(np.float32)
tsvq = pyvq.TSVQ(
training_data=training,
max_depth=5,
distance=pyvq.Distance.squared_euclidean()
)
codes = tsvq.quantize(training[0])
Training Shortcuts¶
ProductQuantizer.fit_transform and TSVQ.fit_transform take the constructor arguments, train the quantizer, and return it together with the codes for the training data:
pq, codes = pyvq.ProductQuantizer.fit_transform(training, 8, 256, seed=42)
tsvq, codes = pyvq.TSVQ.fit_transform(training, 6)
Batch Methods¶
Every quantizer also accepts a 2-D array of shape (n, dim):
codes = sq.quantize_batch(np.random.rand(1000, 128).astype(np.float32))
reconstructed = sq.dequantize_batch(codes)
quantize_batch and dequantize_batch release the GIL and, when the extension is built with the parallel feature, process rows in parallel. They raise ValueError on the first row with an invalid dimension. Inputs must be C-contiguous.
Persistence¶
Trained quantizers can be saved and restored:
pq.save("model.vq")
restored = pyvq.ProductQuantizer.load("model.vq")
blob = tsvq.to_bytes()
restored = pyvq.TSVQ.from_bytes(blob)
from_bytes raises ValueError for malformed data. save and load raise OSError on file errors. Files written by the Rust crate and by PyVq use the same format.
Utility Functions¶
Type Summary¶
| Quantizer | Input | quantize() Output | dequantize() Output |
|---|---|---|---|
| BinaryQuantizer | float32 | uint8 | float32 |
| ScalarQuantizer | float32 | uint8 | float32 |
| ProductQuantizer | float32 | float16 | float32 |
| TSVQ | float32 | float16 | float32 |