Skip to content

Structures

Abstract

Structures are advanced, dictionary-like data structures that act as proxies or containers for collections of objects.

Dictifier

Dictifier is a strict, type-safe container that proxies method calls and attribute access to a collection of objects.

from mappingtools.structures import Dictifier


class Greeter:
    def __init__(self, greeting: str):
        self.greeting = greeting

    def greet(self, name: str) -> str:
        return f"{self.greeting}, {name}!"


# Create a Dictifier of Greeters
greeters = Dictifier[Greeter]({
    "english": Greeter("Hello"),
    "spanish": Greeter("Hola"),
})

# Broadcast a method call
greetings = greeters.greet("World")
print(greetings)
# output: {'english': 'Hello, World!', 'spanish': 'Hola, World!'}

Auto-Inference Mode

For convenience, you can use the Dictifier.auto() factory to create a Dictifier that infers the type of its contents.

from mappingtools.structures import Dictifier


class User:
    def __init__(self, name: str):
        self.name = name

    def greet(self):
        return f"Hi, I'm {self.name}"


# No type hint needed
users = Dictifier.auto({
    "u1": User("Alice"),
    "u2": User("Bob"),
})

# It infers 'User' and allows method calls
greetings = users.greet()
print(greetings)
# output: {'u1': "Hi, I'm Alice", 'u2': "Hi, I'm Bob"}

Deep Proxying

Dictifier enables powerful, chained access to nested object attributes when type hints are present.

from mappingtools.structures import Dictifier


class Address:
    def __init__(self, city: str):
        self.city = city


class User:
    address: Address  # Type hint is crucial

    def __init__(self, name: str, city: str):
        self.name = name
        self.address = Address(city)


# Create a Dictifier of Users
users = Dictifier[User]({
    "u1": User("Alice", "New York"),
    "u2": User("Bob", "London"),
})

# Accessing 'address' returns a new Dictifier
addresses = users.address

# Chain the access to get the 'city' from each Address
cities = addresses.city
print(cities)
# output: {'u1': 'New York', 'u2': 'London'}

dictify

A class decorator that transforms a class definition into a specialized Dictifier collection with optimized performance.

from mappingtools.structures import dictify


@dictify
class UserCollection:
    # This class body defines the interface for the items.
    def __init__(self, name: str):
        self.name = name

    def greet(self):
        return f"Hi, I'm {self.name}"


# UserCollection is now a Dictifier for UserCollection.Item
users = UserCollection({
    "admin": UserCollection.Item("Admin"),
    "guest": UserCollection.Item("Guest"),
})

greetings = users.greet()
print(greetings)
# output: {'admin': "Hi, I'm Admin", 'guest': "Hi, I'm Guest"}

Performance

Dictifier provides a lot of convenience, but this comes with some overhead compared to a native loop. The performance characteristics depend on how you use it and the size of your collection.

Key Takeaways

  • Async is cheap: The overhead for async methods is very low (often <10%).
  • @dictify is fast: The decorator pre-compiles proxies, making it significantly faster than the generic Dictifier[T] for synchronous code.
  • Overhead matters less on large collections: The fixed cost of proxying is less significant as the time spent looping over items increases.

Below are example benchmark results.

Synchronous Overhead

Collection Size Native Loop Dictifier[T] (Generic) @dictify (Decorator)
10 items 0.02s ~300% overhead ~100% overhead
1000 items 0.02s ~80% overhead ~70% overhead

Asynchronous Overhead

Collection Size Native asyncio.gather Dictifier[T] (Async)
10 items 0.7s ~18% overhead
1000 items 0.6s ~8% overhead

LazyDictifier

A lazy version of Dictifier that defers execution until results are accessed. This is ideal for large datasets or streaming pipelines where memory efficiency is critical.

from mappingtools.structures import LazyDictifier


class Greeter:
    def __init__(self, name: str):
        self.call_count = 0
        self.name = name

    def greet(self) -> str:
        self.call_count += 1
        return f"Hello, {self.name}!"


greeter = Greeter("Alice")
data = {"a": greeter}
lazy = LazyDictifier(data)

# Create the proxy - should NOT call greet() yet
greetings = lazy.greet()
print(f"Call count before access: {greeter.call_count}")
# output: Call count before access: 0

# Access an item - SHOULD call greet() now
print(greetings["a"])
# output: Hello, Alice!
print(f"Call count after access: {greeter.call_count}")
# output: Call count after access: 1

map_objects

A factory function that provides a unified entry point for creating Dictifier or LazyDictifier instances.

from mappingtools.structures import map_objects


class User:
    def __init__(self, name: str):
        self.name = name

    def greet(self):
        return f"Hi, I'm {self.name}"


data = {"u1": User("Alice")}

# Create a strict Dictifier
strict_users = map_objects(data, type_hint=User)

# Create an auto-inferring Dictifier
auto_users = map_objects(data)

# Create a lazy Dictifier
lazy_users = map_objects(data, lazy=True)

print(f"Strict: {strict_users.greet()}")
# output: Strict: {'u1': "Hi, I'm Alice"}
print(f"Auto: {auto_users.greet()}")
# output: Auto: {'u1': "Hi, I'm Alice"}
print(f"Lazy (on access): {lazy_users.greet()['u1']}")
# output: Lazy (on access): Hi, I'm Alice

Classical Semirings

  • Shortest Path: ⊕=Min, ⊗=Sum. Use: Distance (Dijkstra).
  • Reliability: ⊕=Max, ⊗=Product. Use: Probability.
  • Bottleneck: ⊕=Max, ⊗=Min. Use: Bandwidth/Capacity.
  • Connectivity: ⊕=OR, ⊗=AND. Use: Reachability.

Advanced Semirings (Matrix/Quillen)

  • Fiber Bundle (Matrix): ⊕=Min (Element-wise), ⊗=MatMul. Use: Gauge Theory, Robotics (Non-commutative).
  • Arbitrage: ⊕=Max, ⊗=Product. Use: Currency loops.
  • Group / Homotopy: ⊕=Composition, ⊗=Concatenation. Use: Path equivalence.
  • Traffic / Flow: ⊕=Sum, ⊗=Sum. Use: Momentum.

AI & Intelligence Structures

  • LLM Semiring: ⊕=Random Sample, ⊗=Probability Chain.
  • Attention Semiring: ⊕=Softmax Sum, ⊗=Dot Product.
  • Meaning Semiring: ⊕=Vector Sum, ⊗=Contextual Embedding.

Physics & Signal Processing (Plesset)

  • Convolution: ⊕=Sum, ⊗=Convolution. Use: GNNs, smoothing.
  • Min-Plus Convolution: ⊕=Min, ⊗=Inf-Convolution. Use: Network Calculus (Delay).
  • Fourier / Spectral: ⊕=Sum, ⊗=Pointwise Product. Use: Spectral Graph Theory.
  • Pressure: ⊕=Sum, ⊗=Difference. Use: Cavitation modeling.

Metrics

  • Graph Reynolds Number: Total Momentum / Topological Viscosity.