Divisive Clustering with Coresets
Cluster a large dataset on small quantum hardware by first compressing it to a weighted coreset, then recursively splitting it with QAOA Max-Cut.
Why coresets?
A coreset is a small weighted subset that approximates the full dataset. It shrinks an intractable problem down to a qubit count today's devices can handle.
The recursive split
One subtlety decides whether the split is even meaningful: what the edge weights mean. Max-Cut maximizes the total weight of edges crossing the partition, so if the weight were a similarity, the cut would tear apart the points that are most alike — exactly the wrong thing. The edge weight must therefore encode dissimilarity (or separation benefit), so that Max-Cut tends to place the most different points on opposite sides.
import qalgora
def divisive_cluster(points, weights, depth):
if len(points) <= 1 or depth == 0:
return [points]
# encode a 2-way split as Max-Cut on a dissimilarity graph, solve with QAOA
graph = weighted_dissimilarity_graph(points, weights)
cut = qalgora_qaoa_maxcut(graph)
left = [p for p, b in zip(points, cut) if b == 0]
right = [p for p, b in zip(points, cut) if b == 1]
left_w = [w for w, b in zip(weights, cut) if b == 0]
right_w = [w for w, b in zip(weights, cut) if b == 1]
# carry the points AND their coreset weights into each branch
return divisive_cluster(left, left_w, depth - 1) + \
divisive_cluster(right, right_w, depth - 1)
基于核心集的分裂式聚类
先将大型数据集压缩为加权核心集,再通过 QAOA Max-Cut 递归二分,从而在小规模量子硬件上完成聚类。
为何使用核心集
核心集是一个近似表示完整数据集的小型加权子集,能将规模难以处理的问题压缩至当前设备可支持的量子比特数量。
递归二分流程
有一处细节决定二分是否有意义:边权代表什么。Max-Cut 会最大化跨越划分的边权总和,因此若边权表示相似度,切割反而会把最相像的点撕开——恰恰是错的。这里的边权应表示不相似度或分离收益,使 Max-Cut 倾向于把差异大的点分到两侧。
import qalgora
def divisive_cluster(points, weights, depth):
if len(points) <= 1 or depth == 0:
return [points]
# encode a 2-way split as Max-Cut on a dissimilarity graph, solve with QAOA
graph = weighted_dissimilarity_graph(points, weights)
cut = qalgora_qaoa_maxcut(graph)
left = [p for p, b in zip(points, cut) if b == 0]
right = [p for p, b in zip(points, cut) if b == 1]
left_w = [w for w, b in zip(weights, cut) if b == 0]
right_w = [w for w, b in zip(weights, cut) if b == 1]
# 同时把点与其核心集权重带入每个分支
return divisive_cluster(left, left_w, depth - 1) + \
divisive_cluster(right, right_w, depth - 1)