πŸ“˜ Measures#

The galactic.algebras.convex.measures.core module provides abstractions for measuring the quality of formal concepts. Measures are used to evaluate sub-concepts relative to their parent concepts.

A Measure is a callable that takes a sub-concept and a super-concept and returns a non-negative float value representing the measure of quality. This is particularly useful for filtering or ranking concepts during lattice traversal.

Available Measures#

The module provides several built-in measure implementations:

  • Support: Returns the cardinality of the concept’s extent (count of items)

  • NormalisedSupport: Returns the support normalised by the domain size (a value in [0, 1])

Creating and Using Measures#

Measures can be instantiated and applied directly to concepts:

from galactic.algebras.concept.core import ItemUniverse
from galactic.algebras.convex.characteristics.core import Component, Integer
from galactic.algebras.convex.descriptions.core import (
    Concept,
    Context,
    GaloisConnection,
    PredicateUniverse,
)
from galactic.algebras.convex.descriptions.examples.arithmetic.core import (
    DivisorDescription,
    MultipleDescription,
)
from galactic.algebras.convex.measures.core import Support, NormalisedSupport
from galactic.algebras.convex.strategies.core import NaiveStrategy

# Set up the context
characteristic = Integer(components=(Component(),))
descriptions = [
    DivisorDescription(space=(characteristic,)),
    MultipleDescription(space=(characteristic,)),
]
dataset = [36, 48, 16, 32, 12, 24, 18, 30, 42, 60]
domain = ItemUniverse(dataset)
co_domain = PredicateUniverse(*descriptions)
context = Context(domain, co_domain)
connection = GaloisConnection(context)

# Create the top concept
top = Concept(connection)
print(f"Top concept extent size: {len(top.extent)}")

# Apply the naive strategy to get sub-concepts
strategy = NaiveStrategy(descriptions=descriptions)
sub_concepts = list(strategy(top))
print(f"Number of sub-concepts: {len(sub_concepts)}")
Top concept extent size: 10
Number of sub-concepts: 4

Now let’s measure these concepts using different measures:

# Create measure instances
support = Support()
norm_support = NormalisedSupport()

# Measure each sub-concept
print("Support measurements:")
supports = [support(sub, top) for sub in sub_concepts]
display(supports)

print("\nNormalised Support measurements:")
norm_supports = [norm_support(sub, top) for sub in sub_concepts]
display(norm_supports)
Support measurements:
[8.0, 9.0, 8.0, 9.0]
Normalised Support measurements:
[0.8, 0.9, 0.8, 0.9]

Filtering Concepts with Measures#

Measures become particularly powerful when combined with filtering strategies. The FilteringStrategy allows you to keep only concepts that meet a threshold:

from galactic.algebras.convex.strategies.core import FilteringStrategy

# Create a filtering strategy that keeps concepts with support >= 8
filtering = FilteringStrategy(
    strategies=(strategy,),
    measure=support,
    threshold=8,
)

# Get filtered concepts
filtered_concepts = list(filtering(top))
print(f"Filtered concepts (support >= 8): {len(filtered_concepts)}")

# Show their support values
filtered_supports = [support(sub, top) for sub in filtered_concepts]
display(filtered_supports)
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Cell In[3], line 1
----> 1 from galactic.algebras.convex.strategies.core import FilteringStrategy
      2 
      3 # Create a filtering strategy that keeps concepts with support >= 8
      4 filtering = FilteringStrategy(

ImportError: cannot import name 'FilteringStrategy' from 'galactic.algebras.convex.strategies.core' (/builds/galactic/public/src/algebras/galactic-algebra-convex/src/galactic/algebras/convex/strategies/core/__init__.py)

Selective Filtering with Relative Measures#

The SelectiveStrategy provides a more flexible filtering mechanism by keeping concepts whose measure is at least ratio * best_measure:

from galactic.algebras.convex.strategies.core import SelectiveStrategy

# Keep only concepts with support >= 0.5 * best_support
selective_half = SelectiveStrategy(
    strategies=(strategy,),
    measure=support,
    ratio=0.5,
)

# Get selectively filtered concepts
selected_concepts = list(selective_half(top))
print(f"Selectively filtered concepts (ratio=0.5): {len(selected_concepts)}")

# Show their support values
selected_supports = [support(sub, top) for sub in selected_concepts]
display(selected_supports)

# Compare with ratio=1 (keep only the best)
selective_best = SelectiveStrategy(
    strategies=(strategy,),
    measure=support,
    ratio=1,
)

selected_best_concepts = list(selective_best(top))
print(f"\nSelectively filtered concepts (ratio=1): {len(selected_best_concepts)}")
best_supports = [support(sub, top) for sub in selected_best_concepts]
display(best_supports)

Creating Custom Measures#

You can create your own measure by subclassing the Measure abstract class and implementing the __call__() method:

from galactic.algebras.convex.measures.core import Measure

class RelativeSize(Measure):
    """Measure the relative size of a concept compared to its parent."""

    def __call__(self, pred, succ):
        """
        Return the ratio of extents: len(pred.extent) / len(succ.extent).
        """
        if len(succ.extent) == 0:
            return 0.0
        return len(pred.extent) / len(succ.extent)

# Use the custom measure
relative_size = RelativeSize()
rel_sizes = [relative_size(sub, top) for sub in sub_concepts]
print("Relative Size measurements:")
display(rel_sizes)

# Create a filtering strategy with the custom measure
filtering_relative = FilteringStrategy(
    strategies=(strategy,),
    measure=relative_size,
    threshold=0.8,  # Keep concepts with at least 80% of parent's size
)

filtered_by_relative = list(filtering_relative(top))
print(f"\nFiltered concepts (relative size >= 0.8): {len(filtered_by_relative)}")
rel_sizes_filtered = [relative_size(sub, top) for sub in filtered_by_relative]
display(rel_sizes_filtered)