Files
faiss/benchs/bench_fw_codecs.py
T
Alibek Zhakubayev a238933d17 Finish E501 line-length lint sweep across faiss (183 violations, 52 files) (#5444)
Summary:
Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5444

We fix every remaining flake8 E501 (line > 80 chars) violation in
fbcode/faiss/ (excluding gpu/), closing out a lint-cleanup initiative that a
June 29, 2026 diff stack (9a05463576 -> d304e29b9a -> 7d140d86ca) explicitly
promised but left 41% incomplete. The middle diff in that stack aligned
.flake8's max-line-length to black's 80-char width and stated the remaining
277 violations after the config change were "genuine lint (E501 long
strings/URLs, F401/F841/B011, etc.), addressed in later commits in this
stack." The follow-up commit fixed only the F401/F403/F841/B011 categories
(45 issues) and never touched E501, leaving 192 violations across 53 files
live in trunk. A direct re-scan today found 201 violations across 54 files
(two files gained lines since the original count).

We fixed 183 violations across 52 files. Two of the originally-flagged
files, benchs/bench_rabitq.py and
demos/index_pq_flat_separate_codes_from_codebook.py, already carry a
file-level `# flake8: noqa` directive (the second is a Bento/Grimaldi
notebook export that also fails standalone py_compile due to embedded shell
magic) -- flake8 ignores both files entirely, so no changes were needed
there and they are excluded from this diff.

Fix approach, by category:
- The large majority of violations are prose: docstrings and comments
  rewrapped at word boundaries, preserving each file's existing indentation
  and docstring conventions. No wording was changed.
- Code lines (function calls, f-strings, assert messages, long argument
  lists) were reflowed in black-compatible style: parenthesization, comma
  breaks, or implicit adjacent string-literal concatenation. Every touched
  file is confirmed unchanged by `black --line-length 80 --diff` after the
  edit.
- A small number of genuinely unwrappable long URLs (no reasonable break
  point) were suppressed with `# noqa: E501` rather than force-wrapped,
  matching the precedent set by the original black-format diff stack.
- demos/offline_ivf/offline_ivf.py: a repeated, non-trivial ratio expression
  used in both an assert condition and its (lazily-evaluated) failure
  message was hoisted into a single local variable, eliminating the
  duplicate computation. The expression is pure and deterministic (built
  from already-computed arrays), so this is behaviorally identical to the
  original -- not a functional change.
- `arc lint -a` additionally auto-fixed a real bug it detected while
  processing these files: `raise NotImplemented` -> `raise
  NotImplementedError` in contrib/evaluation.py (the sentinel object
  NotImplemented is not an exception type; raising it produces a TypeError
  masking the intended NotImplementedError). It also added a missing
  trailing newline in benchs/fb/bench_index_binary_from_float.py and, in
  the same file, rewrote the `#!/usr/bin/env python2` shebang to
  `#!/usr/bin/env fbpython` -- that rewrite was reverted by hand, since the
  file still does `import cPickle` (a Python 2-only module), so the
  auto-fix would have made the shebang describe an interpreter the script
  cannot actually run under. Fixing the underlying py2-to-py3 migration is
  out of scope for this line-length-only sweep.
- Rebasing onto master (this diff's base commit had drifted) surfaced two
  concurrent upstream fixes to `check_ref_knn_with_draws(...)` calls in
  tests/test_ivf_flat_panorama.py and tests/test_refine_panorama.py (an
  unrelated in-flight correctness fix passing `D_panorama`/`atol` instead
  of a stale `D_regular` arg with no `atol`). The rebase took upstream's
  corrected arguments and re-applied only this diff's line-wrap on top.

We verified zero functional change with an AST-level check: every string
and f-string literal in every touched file was extracted before and after
the edit and compared with whitespace normalized, confirming no wording,
value, or expression was altered beyond the intended `# noqa: E501`
suffixes and the one documented ratio-hoisting simplification above.

Reviewed By: mnorris11

Differential Revision: D112525458

fbshipit-source-id: e4b85d73dafcaac779f3522a383a66e490fa942a
2026-07-17 10:20:42 -07:00

196 lines
5.7 KiB
Python

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import argparse
import logging
import os
from faiss.benchs.bench_fw.benchmark import Benchmark
from faiss.benchs.bench_fw.benchmark_io import BenchmarkIO
from faiss.benchs.bench_fw.descriptors import (
DatasetDescriptor,
IndexDescriptorClassic,
)
logging.basicConfig(level=logging.INFO)
def factory_factory(d):
return (
[
("SQ4", None, 256 * (2**10), None),
("SQ8", None, 256 * (2**10), None),
("SQfp16", None, 256 * (2**10), None),
("ITQ64,LSH", None, 256 * (2**10), None),
("Pad128,ITQ128,LSH", None, 256 * (2**10), None),
("Pad256,ITQ256,LSH", None, 256 * (2**10), None),
]
+ [
(f"OPQ32_128,Residual2x14,PQ32x{b}", None, 256 * (2**14), None)
for b in range(8, 16, 2)
]
+ [
(f"PCAR{2 ** d_out},SQ{b}", None, 256 * (2**10), None)
for d_out in range(6, 11)
if 2**d_out <= d
for b in [4, 8]
]
+ [
(f"OPQ{M}_{M * dim},PQ{M}x{b}", None, 256 * (2**b), None)
for M in [8, 12, 16, 32, 64, 128]
for dim in [2, 4, 6, 8, 12, 16]
if M * dim <= d
for b in range(8, 16, 2)
]
+ [
(
f"RQ{cs // b}x{b}",
[{"max_beam_size": 32}],
256 * (2**b),
{"max_beam_size": bs, "use_beam_LUT": bl},
)
for cs in [64, 128, 256, 512]
for b in [6, 8, 10, 12]
for bs in [1, 2, 4, 8, 16, 32]
for bl in [0, 1]
if cs // b > 1
if cs // b < 65
if cs < d * 8 * 2
]
+ [
(
f"LSQ{cs // b}x{b}",
[{"encode_ils_iters": 16}],
256 * (2**b),
{"encode_ils_iters": eii, "lsq_gpu": lg},
)
for cs in [64, 128, 256, 512]
for b in [6, 8, 10, 12]
for eii in [2, 4, 8, 16]
for lg in [0, 1]
if cs // b > 1
if cs // b < 65
if cs < d * 8 * 2
]
+ [
(
f"PRQ{sub}x{cs // sub // b}x{b}",
[{"max_beam_size": 32}],
256 * (2**b),
{"max_beam_size": bs, "use_beam_LUT": bl},
)
for sub in [2, 3, 4, 8, 16, 32]
for cs in [64, 96, 128, 192, 256, 384, 512, 768, 1024, 2048]
for b in [6, 8, 10, 12]
for bs in [1, 2, 4, 8, 16, 32]
for bl in [0, 1]
if cs // sub // b > 1
if cs // sub // b < 65
if cs < d * 8 * 2
if d % sub == 0
]
+ [
(
f"PLSQ{sub}x{cs // sub // b}x{b}",
[{"encode_ils_iters": 16}],
256 * (2**b),
{"encode_ils_iters": eii, "lsq_gpu": lg},
)
for sub in [2, 3, 4, 8, 16, 32]
for cs in [64, 128, 256, 512, 1024, 2048]
for b in [6, 8, 10, 12]
for eii in [2, 4, 8, 16]
for lg in [0, 1]
if cs // sub // b > 1
if cs // sub // b < 65
if cs < d * 8 * 2
if d % sub == 0
]
)
def run_local(rp):
bio, d, tablename, distance_metric = rp
if tablename == "contriever":
training_vectors = DatasetDescriptor(tablename="training_set.npy")
database_vectors = DatasetDescriptor(
tablename="database1M.npy",
)
query_vectors = DatasetDescriptor(
tablename="queries.npy",
)
else:
training_vectors = DatasetDescriptor(
namespace="std_t",
tablename=tablename,
)
database_vectors = DatasetDescriptor(
namespace="std_d",
tablename=tablename,
)
query_vectors = DatasetDescriptor(
namespace="std_q",
tablename=tablename,
)
benchmark = Benchmark(
num_threads=32,
training_vectors=training_vectors,
database_vectors=database_vectors,
query_vectors=query_vectors,
index_descs=[
IndexDescriptorClassic(
factory=factory,
construction_params=construction_params,
training_size=training_size,
search_params=search_params,
)
for (
factory,
construction_params,
training_size,
search_params,
) in factory_factory(d)
],
k=1,
distance_metric=distance_metric,
)
benchmark.set_io(bio)
benchmark.benchmark(
result_file="result.json",
train=True,
reconstruct=False,
knn=False,
range=False,
)
def run(bio, d, tablename, distance_metric):
bio.launch_jobs(
run_local, [(bio, d, tablename, distance_metric)], local=True
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("experiment")
parser.add_argument("path")
args = parser.parse_args()
assert os.path.exists(args.path)
path = os.path.join(args.path, args.experiment)
if not os.path.exists(path):
os.mkdir(path)
bio = BenchmarkIO(
path=path,
)
if args.experiment == "sift1M":
run(bio, 128, "sift1M", "L2")
elif args.experiment == "bigann":
run(bio, 128, "bigann1M", "L2")
elif args.experiment == "deep1b":
run(bio, 96, "deep1M", "L2")
elif args.experiment == "contriever":
run(bio, 768, "contriever", "IP")