Skip to content

Conversation

@kevinchern
Copy link
Collaborator

@kevinchern kevinchern commented Nov 14, 2025

TODOs:

  • tests
  • documentation
  • fix this ugly "forced compilation" steps

some low-hanging fruits for optimization:

  • minimize the recreating objects like zeros in method step_
  • better data structures, e.g., recreate as dense representation in the preprocessing step (?). or a four-partite-like data structure (zephyr case)

@kevinchern kevinchern marked this pull request as draft November 17, 2025 21:24
@kevinchern kevinchern assigned VolodyaCO and mhramani and unassigned VolodyaCO and mhramani Nov 17, 2025
tricks were employed. Ideally, an adjacency list can be used, however, adjacencies are ragged,
which makes vectorization inapplicable.

Block-Gibbs and Block-Metropolis obey detailed balance and are ergodic methods at finite

Choose a reason for hiding this comment

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

Very clear wording

Copy link

@jackraymond jackraymond 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, I'll come back to this when you add tests. Per your summary. Thanks for getting this draft up quickly.

Would be nice to have a tidy public GPU code to use and cite for speedup relative to our CPU implementation in higher throughput applications as soon as possible.

def __init__(self, G: Graph, grbm: GRBM, num_reads: int, kind: str):
super().__init__()
topology = G.graph.get("family", None)
if topology not in {"zephyr", "pegasus", "chimera"}:

Choose a reason for hiding this comment

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

Maybe make partition an optional argument. It seems like we only have this restriction in order to make the partition?

Choose a reason for hiding this comment

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

i.e. make partition an optional argument. If partition is provided don't check for the graph or topology arguments.
A user may provide a subgraph of Zephyr as a zephyr family graph for example (e.g. a Chimera[2m,t] inside a Zephyr[m,t] would permit a 2-coloring).

h = self.linear[block]
J = self.quadratic[self.padded_adjacencies_weight[block]]
effective_field = (xnbr * J.unsqueeze(0)).sum(2) + h
if self.kind == "metropolis":

Choose a reason for hiding this comment

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

Can be polite and capitalize Mr Metropolis's and Mr Gibb's names, the least they deserve?

@torch.compile
@torch.no_grad
def step_(self, beta: torch.Tensor):
"""Performs a block-Gibbs update in-place.

Choose a reason for hiding this comment

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

or block-Metropolis

grbm (GRBM): The Graph-Restricted Boltzmann Machine to sample from.
"""

def __init__(self, G: Graph, grbm: GRBM, num_reads: int, kind: str):

Choose a reason for hiding this comment

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

I think 'kind' is called 'proposal_acceptance_criteria' in SimulatedAnnealingSampler. It took me a while to work out what kind was, and would be good to standardize.

Choose a reason for hiding this comment

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

Add 'Gibbs' as default

def get_partition(self, topology):
partition = defaultdict(list)
if topology == "zephyr":
lin2lattice = dnx.zephyr_coordinates(self.G.graph['rows']).linear_to_zephyr

Choose a reason for hiding this comment

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

Before applying this you should check if you should check the node type property of the graph, it may already be coordinates and then this would fail.

lin2lattice = dnx.zephyr_coordinates(self.G.graph['rows']).linear_to_zephyr
crayon = dnx.zephyr_four_color
elif topology == "pegasus":
lin2lattice = dnx.pegasus_coordinates(self.G.graph['rows']).linear_to_pegasus

Choose a reason for hiding this comment

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

pegasus graphs support 3-node types, this transformation may be inappriate.

lin2lattice = dnx.pegasus_coordinates(self.G.graph['rows']).linear_to_pegasus
crayon = dnx.pegasus_four_color
elif topology == "chimera":
lin2lattice = dnx.chimera_coordinates(self.G.graph['rows']).linear_to_chimera

Choose a reason for hiding this comment

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

chimera graphs support 2 node types, this is not required if the graph is already coordinated.

self.idx_to_node = grbm.idx_to_node
self.partition = self.get_partition(topology)
self.padded_adjacencies, self.padded_adjacencies_weight = self.get_adjacencies()
self.x = nn.Parameter(rands((num_reads, grbm.n_nodes)), requires_grad=False)

Choose a reason for hiding this comment

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

x should be allowed as an input, and the random number should allow a seed when its not provided.

grbm (GRBM): The Graph-Restricted Boltzmann Machine to sample from.
"""

def __init__(self, G: Graph, grbm: GRBM, num_reads: int, kind: str):

Choose a reason for hiding this comment

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

x should also be allowed as an input, from which num_reads could be inferred (num_reads and x both optional).

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.

4 participants