Skip to content

Advanced Usage

The kmeanssa-ng library is designed with extensibility in mind, following a classic Strategy design pattern. This allows you to create your own custom components, such as initialization or robustification strategies, without altering the core package code.

Implementing a Custom Initialization Strategy

The main algorithm, SimulatedAnnealing, accepts an initialization_strategy object. This object must be an instance of a class that inherits from the InitializationStrategy abstract base class and implements its required methods.

Let’s demonstrate this by creating a custom strategy that initializes centers at fixed, predefined locations.

1. Define the Custom Strategy

First, create a new class that inherits from kmeanssa_ng.core.strategies.initialization.InitializationStrategy. You must implement the initialize_centers method.

from kmeanssa_ng.core.strategies.initialization import InitializationStrategy
from kmeanssa_ng.core.simulated_annealing import SimulatedAnnealing

class MyFixedInit(InitializationStrategy):
    """Initializes centers at predefined positions."""
    def __init__(self, fixed_centers):
        super().__init__()
        self.fixed_centers = fixed_centers

    def initialize_centers(self, sa: SimulatedAnnealing):
        """Returns the list of predefined centers."""
        print("Using a custom fixed initialization strategy!")

        # It's good practice to ensure the number of centers is correct.
        if len(self.fixed_centers) != sa.k:
            raise ValueError(
                f"The number of predefined centers ({len(self.fixed_centers)}) "
                f"does not match the required number of clusters k={sa.k}."
            )

        return self.fixed_centers

2. Use the Custom Strategy

Now, you can instantiate your custom strategy and pass it to the run_interleaved or run_sequential method of the SimulatedAnnealing object.

# Example setup
from kmeanssa_ng import generate_sbm
from kmeanssa_ng.quantum_graph.sampling import UniformNodeSampling

# Generate space and data
my_space = generate_sbm(sizes=[50, 50], p=[[0.8, 0.1], [0.1, 0.8]])

observations = my_space.sample_points(200, strategy=UniformNodeSampling())
k = 4

# Create the predefined centers for our strategy
points_for_centers = my_space.sample_points(k, strategy=UniformNodeSampling())
predefined_centers = [my_space.center_from_point(p) for p in points_for_centers]

# Instantiate your custom strategy
my_strategy = MyFixedInit(predefined_centers)

# Run the algorithm with your strategy
sa = SimulatedAnnealing(observations, k=k)
final_centers = sa.run_interleaved(initialization_strategy=my_strategy)

print("\nClustering completed successfully using a custom strategy.")
Using a custom fixed initialization strategy!

Clustering completed successfully using a custom strategy.

This same principle applies to other strategic components in the library, such as RobustificationStrategy, allowing for a high degree of customization to fit your specific use case.