Skip to content

HammingGraph space#170

Merged
vabor112 merged 10 commits into
geometric-kernels:mainfrom
colmont:main
Dec 15, 2025
Merged

HammingGraph space#170
vabor112 merged 10 commits into
geometric-kernels:mainfrom
colmont:main

Conversation

@colmont
Copy link
Copy Markdown
Contributor

@colmont colmont commented Nov 14, 2025

Two related changes:

  1. Add support for Hamming graphs (HammingGraph), which generalize hypercube graphs (HypercubeGraph) from binary to categorical.
  2. Add closed-form implementation of both HypercubeGraph and HammingGraph, although this new implementation is not always faster... see notebooks/HammingGraph.ipynb.

Copy link
Copy Markdown
Member

@vabor112 vabor112 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, thank you, Colin! I'm leaving a few comments to discuss. Additionally, a code update will follow shortly.

Comment thread geometric_kernels/utils/utils.py Outdated
"""
return count_nonzero(logical_xor(x1[:, None, :], x2[None, :, :]), axis=-1)
x1_int = B.cast(int_like(x1), x1)
x2_int = B.cast(int_like(x2), x2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this? Shouldn't we expect integers here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, perhaps x1: B.Bool, x2: B.Bool should be changed to x1: B.Int, x2: B.Int now that we admin non-binary categories.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/feature_maps/test_feature_maps.py is going to call lines 114-116 in geometric_kernels/feature_maps/random_phase.py:

phi_product = self.eigenfunctions.phi_product(
	X, random_phases_b, **params
)  # [N, O, L]

Here, for the HammingGraph space, X will be an integer, but random_phases_b will be a float... leading to a mismatch later on in the hamming_distance function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the cast into a more relevant location pls

atol=1e-10,
)

if d > 5:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree: this d > 5 is a bit arbitrary... I decided to keep it for coherence with the test_hypercube_graph_heat_kernel function (same file), which has a similar d > 5 structure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just rename the test pls

Comment thread docs/theory/hamming_graph.rst Outdated
$$
where $\omega_q = e^{2\pi i/q}$ is a primitive $q$-th root of unity and $x = (x_0, \ldots, x_{d-1}) \in H(d,q)$.

The eigenfunctions with the same number of non-zero frequency components $j = |\{i : s_i \neq 0\}|$ share the same eigenvalue $\lambda_j = (q-1)j / d$ and form a *level* $j$. The dimension of level $j$ is $\binom{d}{j}(q-1)^j$.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't coincide with the value in get_eigenvalues in HammingGraph:

                (self.n_cat * level)
                / (
                    self.dim * (self.n_cat - 1)
                )  # we assume normalized Laplacian (for numerical stability)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad... I believe the fraction in the code is the right one, and the above text should be modified with:

$lambda_j = \frac{q j}{(q-1) d$

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix in the docs pls.

@vabor112 vabor112 changed the title HammingGraph space: initial commit HammingGraph space Nov 16, 2025
Copy link
Copy Markdown
Member

@vabor112 vabor112 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double checked the theory, LGTM! Thanks again for the PR.

@vabor112 vabor112 merged commit f33fa83 into geometric-kernels:main Dec 15, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants