To inspect the tradeoffs between recall and throughput, select a dataset and a value of \(k\). Then, using the legend below, select the algorithms you are interested in.
db = DuckDBClient.of({
summary: FileAttachment("results/summary.parquet"),
algorithm_basics: {file: FileAttachment("algorithms_basics.csv"), header: true}
});
alldata = db.sql`select * from summary;`
algorithms = db.sql`
select distinct algorithm
from summary natural join algorithm_basics
where is_gpu = ${gpu_algorithms}
order by all;
`
datasets = db.sql`
select distinct dataset
from summary
where dataset not like '%-id-%'
order by dataset;
`
palette = Array.from(d3["schemeTableau10"]);
ncolors = palette.length;mutable_non_gpu_color_map = new Mutable(new Map([
["lorann", palette[0]],
["glass", palette[1]],
["symphonyqg", palette[2]],
]));
non_gpu_color_map = mutable_non_gpu_color_map.generator
mutable_gpu_color_map = new Mutable(new Map([
["cuvs-cagra", palette[0]],
["faiss-gpu-ivf", palette[1]],
["ggnn", palette[2]],
]));
gpu_color_map = mutable_gpu_color_map.generator
color_map = gpu_algorithms ? gpu_color_map : non_gpu_color_mapd3.select("#legend")
.selectAll("div")
.data(algorithms)
.join("div")
.style("border-bottom", d => `solid 6px ${(color_map.has(d.algorithm))? color_map.get(d.algorithm) : "lightgray"}`)
.style("border-top", "solid 1px lightgray")
.style("border-left", "solid 1px lightgray")
.style("border-right", "solid 1px lightgray")
.style("border-radius", "4px")
.style("padding-right", "5pt")
.style("padding-left", "5pt")
.on("click", (event, d)=> {
const key = d.algorithm;
let cm = new Map(color_map);
console.log("Algorithm " + key);
if (cm.has(key)) {
cm.delete(key);
} else {
const usedColors = new Set(cm.values());
const color = palette.find(color => !usedColors.has(color));
if (color !== undefined) {
cm.set(key, color);
}
}
if (gpu_algorithms) {
mutable_gpu_color_map.value = cm;
} else {
mutable_non_gpu_color_map.value = cm;
}
console.log(color_map);
console.log(event.target);
})
.text(d => d.algorithm);viewof gpu_algorithms = {
const control = html`
<div class="form-check form-switch d-flex align-items-center gap-2">
<input class="form-check-input mt-0" type="checkbox" role="switch" id="gpu-algorithms-toggle">
<label class="form-check-label" for="gpu-algorithms-toggle">GPU algorithms</label>
</div>
`;
const toggle = control.querySelector("input");
Object.defineProperty(control, "value", {get: () => toggle.checked});
return control;
}pareto = db.sql`WITH
filtered_summary AS (
SELECT *
FROM summary natural left join algorithm_basics
WHERE is_gpu = ${gpu_algorithms}
),
ranked_points AS (
SELECT
algorithm, dataset, params, qps, recall,
ROW_NUMBER() OVER (PARTITION BY algorithm, dataset ORDER BY qps) AS rank_qps,
ROW_NUMBER() OVER (PARTITION BY algorithm, dataset ORDER BY recall) AS rank_recall
FROM filtered_summary
where dataset = ${selected_dataset} and k = ${k_value}
),
non_dominated AS (
SELECT
r1.algorithm, r1.dataset, r1.params, r1.qps, r1.recall
FROM ranked_points r1
LEFT JOIN ranked_points r2
ON r1.algorithm = r2.algorithm
AND r1.dataset = r2.dataset
AND ((r1.rank_qps < r2.rank_qps AND r1.rank_recall <= r2.rank_recall) OR
(r1.rank_qps <= r2.rank_qps AND r1.rank_recall < r2.rank_recall))
WHERE r2.recall IS NULL -- no dominating point
)
SELECT * FROM non_dominated;
`
highlighted = pareto.filter(d => color_map.has(d.algorithm));
background = pareto.filter(d => !color_map.has(d.algorithm));viewof paretoplot = Plot.plot({
style: {fontSize: "10pt"},
x: {domain: [0, 1], grid: true},
y: {type: "log", grid: true},
marks: [
Plot.ruleY([1]),
Plot.ruleX([0]),
Plot.line(background, {
x: "recall",
y: "qps",
stroke: "lightgray",
z: "algorithm",
marker: "circle-stroke",
tip: false
}),
Plot.line(highlighted, {
x: "recall",
y: "qps",
stroke: (d) => color_map.get(d.algorithm),
z: "algorithm",
marker: "circle-stroke",
tip: false
}),
Plot.ruleX(background, Plot.pointerX({x: "recall", py: "qps", stroke: "red"}))
]
})dynamic_recall_threshold = (paretoplot)? paretoplot.recall : null;
rankdata = db.sql`
SELECT dataset, algorithm, k, max(qps) as qps
FROM summary natural left join algorithm_basics
WHERE recall > ${dynamic_recall_threshold}
AND dataset = ${selected_dataset}
AND is_gpu = ${gpu_algorithms}
GROUP BY dataset, algorithm, k
`
half = d3.max(rankdata, d => d.qps) / 2
console.log(half)Plot.plot({
style: {fontSize: "12pt"},
marginLeft: 180,
marks: [
Plot.ruleY([0]),
Plot.barX(rankdata, {
y: "algorithm",
x: "qps",
fill: d => color_map.has(d.algorithm)? color_map.get(d.algorithm) : "gray",
sort: {y: "-x"}
}),
Plot.text(rankdata.filter(d => d.qps < half), {
y: "algorithm",
x: "qps",
text: d => d3.format(".0f")(d.qps) + " qps",
dx: 10,
textAnchor: "start",
fill: "black"
}),
Plot.text(rankdata.filter(d => d.qps >= half), {
y: "algorithm",
x: "qps",
text: d => d3.format(".0f")(d.qps) + " qps",
dx: -10,
textAnchor: "end",
fill: "white"
})
]
})