diff --git a/README.md b/README.md index 6843f05..cb5d94d 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,25 @@ -# catopt-category-theoretic-compositional- +# CatOpt: Category-Theoretic Compositional Optimizer (MVP) -Problem space: distributed, offline-first optimization across heterogeneous edge devices (DERs, meters, controllers, EV chargers) in mesh networks. Centralized solvers are infeasible due to latency, bandwidth, and privacy. We need a modular, provably compositional optimization framework that can be plugged into existing energy and robotics ecosystems with privacy by design and offline resilience. +CatOpt is a lightweight, open-source framework for privacy-preserving, compositional distributed optimization across edge meshes. The MVP emphasizes a minimal, well-structured surface built on category-theory abstractions, enabling edge-to-edge collaboration with offline resilience and vendor interoperability. -This repository implements a minimal MVP scaffold for CatOpt, a light-weight framework that uses category-theory-inspired abstractions to express distributed optimization problems and a toy solver stack to validate the idea in CI. +What you get in this MVP +- Local problems expressed by agents (objects) +- Data exchange channels (morphisms) and problem transformers (functors) +- Global assembly via Limits/Colimits and a lightweight ADMM-like solver +- Privacy-by-design data contracts and modular adapters +- A tiny Python runtime surface suitable for rapid prototyping and CI validation -MVP Runtime (new): lightweight primitives to experiment with CatOpt concepts locally. -- LocalProblem: representation of an agent's optimization task. -- DataContract, SharedVariables, PlanDelta: lightweight data-exchange primitives for a privacy-conscious mesh. -- ADMMTwoAgentSolver: tiny, in-process ADMM-like solver to demonstrate joint optimization across two agents. -- demo_two_agent_admm(): quick in-repo demonstration function returning final variables. +Why this matters +- Composability: add/remove agents without re-deriving the global problem +- Privacy: only exchanged, abstracted quantities per contracts +- Convergence: disciplined, modular solver structure with verifiable properties +- Interoperability: bridges to existing energy/robotics ecosystems via a common DSL -Usage notes: -- Import from the package and optionally run the demo function to observe convergence on a toy problem. -- Example: - ```python - from catopt_category_theoretic_compositional.runtime import ADMMTwoAgentSolver, demo_two_agent_admm - result = demo_two_agent_admm() - print(result) - ``` +Usage (quick start) +- The core runtime primitives live in src/catopt_category_theoretic_compositional_/ +- The tiny DSL bridge to contracts lives in src/catopt_category_theoretic_compositional_/dsl.py +- Importing and testing is kept simple to satisfy the CI gate (see tests/test_basic.py) + +For more details, see tests, the MVP runtime, and the protocol DSL (ProtocolContract, build_minimal_contract). + +This README is a starting point. As we evolve, we will add more examples, adapters, and end-to-end demos. diff --git a/src/catopt_category_theoretic_compositional_/__init__.py b/src/catopt_category_theoretic_compositional_/__init__.py index 6578c21..a98e3a2 100644 --- a/src/catopt_category_theoretic_compositional_/__init__.py +++ b/src/catopt_category_theoretic_compositional_/__init__.py @@ -1,6 +1,7 @@ """CatOpt: Minimal placeholder surface & MVP runtime exposure.""" from .runtime import LocalProblem, SharedVariables, DataContract, PlanDelta, ADMMTwoAgentSolver, demo_two_agent_admm # noqa: F401 +from .dsl import ProtocolContract, build_minimal_contract # noqa: F401 def add(a: int, b: int) -> int: """Return the sum of two integers. @@ -10,4 +11,14 @@ def add(a: int, b: int) -> int: """ return a + b -__all__ = ["add", "LocalProblem", "SharedVariables", "DataContract", "PlanDelta", "ADMMTwoAgentSolver", "demo_two_agent_admm"] +__all__ = [ + "add", + "LocalProblem", + "SharedVariables", + "DataContract", + "PlanDelta", + "ADMMTwoAgentSolver", + "demo_two_agent_admm", + "ProtocolContract", + "build_minimal_contract", +] diff --git a/src/catopt_category_theoretic_compositional_/dsl.py b/src/catopt_category_theoretic_compositional_/dsl.py new file mode 100644 index 0000000..71acc78 --- /dev/null +++ b/src/catopt_category_theoretic_compositional_/dsl.py @@ -0,0 +1,67 @@ +"""CatOpt Minimal Protocol DSL + +Lightweight protocol primitives to express a minimal, vendor-agnostic +contract between agents in the CatOpt MVP. This module is intentionally +small and proto-like to avoid pulling in heavy dependencies while still +providing a useful representation that can be serialized for transport. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Dict, List +import json + +from .runtime import LocalProblem, DataContract, SharedVariables + + +@dataclass +class ProtocolContract: + """A minimal, JSON-serializable contract describing the exchange schema.""" + + version: int = 1 + objects: List[Dict] = field(default_factory=list) + morphisms: List[Dict] = field(default_factory=list) + functors: List[Dict] = field(default_factory=list) + limits: List[Dict] = field(default_factory=list) + time_structure: Dict = field(default_factory=lambda: {"monoid": "temporal", "rounds": 1}) + + def to_dict(self) -> Dict: + return { + "version": self.version, + "objects": self.objects, + "morphisms": self.morphisms, + "functors": self.functors, + "limits": self.limits, + "time_structure": self.time_structure, + } + + def to_json(self) -> str: + return json.dumps(self.to_dict(), indent=2, sort_keys=True) + + +def build_minimal_contract(lp: LocalProblem, dc: DataContract, sv: SharedVariables) -> ProtocolContract: + """Construct a tiny, canonical contract from local problem state. + + This is intentionally small but demonstrates how a solver could export a + structured contract for cross-agent interoperability. + """ + obj = { + "type": "LocalProblem", + "id": lp.id, + "x_name": lp.x_name, + "objective": { + "quadratic": lp.a, + "linear": lp.b, + }, + } + + contract = ProtocolContract( + version=1, + objects=[obj], + morphisms=[{"from": "agentA", "to": "agentB", "contract": "delta-sharing"}], + functors=[{"name": "Canonicalize", "description": "maps to vendor-agnostic representation"}], + limits=[{"type": "global-constraint", "description": "sum(x) == 1"}], + time_structure={"monoid": "temporal", "rounds": 1}, + ) + return contract