Skip to content

05_01_00_level_definitions - La Taxonomía de la Complejidad

🎯 Propósito

Implementación de las definiciones fundamentales de la jerarquía L0→L1→L2→L3 que gobierna toda la arquitectura AudioLab DSP.

Este módulo provee: - Enums de niveles (L0_KERNEL, L1_ATOM, L2_CELL, L3_ENGINE) - Matriz de dependencias (4x4) enforceando reglas arquitectónicas - Parser de metadata para módulos (JSON/YAML) - API completa para query y validación de niveles


📂 Estructura

05_01_00_level_definitions/
├── include/
│   └── level_definitions.hpp      # Header principal (API pública)
├── src/
│   ├── level_registry.cpp         # Implementación de LevelRegistry
│   ├── dependency_matrix.cpp      # Implementación de matriz 4x4
│   └── metadata_parser.cpp        # Parser JSON/YAML
├── tests/
│   └── test_level_definitions.cpp # Suite de tests (>95% coverage)
├── examples/
│   └── level_usage.cpp            # Ejemplo de uso completo
├── docs/
│   ├── LEVEL_SEMANTICS.md         # Definición formal de cada nivel
│   └── decision_tree.puml         # Árbol de decisión visual
├── CMakeLists.txt                 # Build system
└── README.md                      # Este archivo

🚀 Quick Start

1. Compilar

mkdir build && cd build
cmake ..
cmake --build .

2. Ejecutar tests

./test_level_definitions

3. Ejecutar ejemplo

./example_level_usage

💻 Uso Básico

Incluir header

#include <audiolab/hierarchy/level_definitions.hpp>
using namespace audiolab::hierarchy;

Clasificar un módulo

auto& registry = LevelRegistry::instance();

// Parse level from string
ModuleLevel level = registry.level_from_string("L1_ATOM");

// Get characteristics
auto chars = registry.get_characteristics(level);
if (chars) {
    std::cout << "Level: " << chars->name << "\n";
    std::cout << "Stateless: " << chars->is_stateless << "\n";
    std::cout << "Max dependencies: " << chars->max_dependencies << "\n";
}

Validar dependencia

// Check if L1_ATOM can depend on L0_KERNEL
bool valid = is_valid_dependency(
    ModuleLevel::L1_ATOM,
    ModuleLevel::L0_KERNEL
);
// valid == true ✅

// Check if L1_ATOM can depend on L1_ATOM
bool invalid = is_valid_dependency(
    ModuleLevel::L1_ATOM,
    ModuleLevel::L1_ATOM
);
// invalid == false ❌

Parsear metadata de módulo

std::string json = R"({
    "module_name": "SVF_Filter",
    "level": "L1_ATOM",
    "version": "1.0.0",
    "dependencies": ["mul_kernel", "add_kernel"]
})";

auto metadata = MetadataParser::from_json(json);
if (metadata) {
    std::cout << "Module: " << metadata->module_name << "\n";
    std::cout << "Level: " << level_name(metadata->level) << "\n";
}

Ver matriz de dependencias

auto& matrix = DependencyMatrix::instance();
std::cout << matrix.to_string();

// Output:
// Dependency Matrix [from][to]:
//
//            L0   L1   L2   L3
// L0_KERNEL  ❌   ❌   ❌   ❌
// L1_ATOM    ✅   ❌   ❌   ❌
// L2_CELL    ✅   ✅   ✅*  ❌
// L3_ENGINE  ✅   ✅   ✅   ❌

📊 Matriz de Dependencias

           L0   L1   L2   L3
L0_KERNEL  ❌   ❌   ❌   ❌
L1_ATOM    ✅   ❌   ❌   ❌
L2_CELL    ✅   ✅   ✅*  ❌
L3_ENGINE  ✅   ✅   ✅   ❌

* = permitido sin ciclos

Lectura: Fila "puede depender de" Columna


🔑 Clases Principales

LevelRegistry

Singleton que mantiene características de cada nivel.

LevelRegistry& registry = LevelRegistry::instance();

// Convert string ↔ enum
ModuleLevel level = registry.level_from_string("L1_ATOM");
std::string name = registry.level_to_string(level);

// Get characteristics
auto chars = registry.get_characteristics(ModuleLevel::L0_KERNEL);

// Get all levels
auto all = registry.all_levels();  // [L0, L1, L2, L3]

DependencyMatrix

Singleton que enforcea reglas de dependencias.

DependencyMatrix& matrix = DependencyMatrix::instance();

// Validate single dependency
bool valid = matrix.is_valid_dependency(from_level, to_level);

// Get allowed dependencies for a level
auto allowed = matrix.allowed_dependencies(ModuleLevel::L2_CELL);
// Returns: [L0_KERNEL, L1_ATOM, L2_CELL]

// Get matrix as 2D array
const auto& mat = matrix.get_matrix();  // [4][4] array

MetadataParser

Parse y serializa metadata de módulos.

// Parse from JSON
auto meta = MetadataParser::from_json(json_string);

// Parse from YAML
auto meta = MetadataParser::from_yaml(yaml_string);

// Parse from file (auto-detect format)
auto meta = MetadataParser::from_file("module.json");

// Serialize to JSON
std::string json = MetadataParser::to_json(metadata);

// Serialize to YAML
std::string yaml = MetadataParser::to_yaml(metadata);

📚 Documentación

Lectura Recomendada (en orden)

  1. LEVEL_SEMANTICS.md ⭐ IMPORTANTE
  2. Definición formal de cada nivel
  3. Ejemplos correctos e incorrectos
  4. Decision tree de clasificación
  5. 20+ ejemplos de módulos clasificados

  6. examples/level_usage.cpp

  7. 6 ejemplos completos de uso
  8. Cómo usar cada clase
  9. Casos de uso comunes

  10. decision_tree.puml

  11. Árbol de decisión visual
  12. Diagrama PlantUML

🎯 Decision Tree: ¿Qué nivel es mi módulo?

¿Tiene estado interno? (phase, buffers, etc.)
NO → L0_KERNEL
│     (add, mul, sin, interpolate)
YES → ¿Es combinación de otros módulos?
      NO → L1_ATOM
      │    (Oscillator, Filter, Envelope)
      YES → ¿Es sistema completo listo para plugin?
            NO → L2_CELL
            │    (SynthVoice, Compressor, EffectChain)
            YES → L3_ENGINE
                 (PolySynth, Reverb, MasteringChain)

✅ Tests

Ejecutar suite completa

cd build
./test_level_definitions

Cobertura esperada

  • Target: >95% code coverage
  • Frameworks: Catch2 v3
  • Test cases: 30+ test sections

Categorías de tests

  • [level_registry] - Tests de LevelRegistry
  • [dependency_matrix] - Tests de matriz de dependencias
  • [metadata] - Tests de ModuleMetadata
  • [metadata_parser] - Tests de parser JSON/YAML
  • [utilities] - Tests de funciones helper
  • [properties] - Property-based tests (transitividad, etc.)

📋 API Reference

Enums

enum class ModuleLevel : uint8_t {
    L0_KERNEL = 0,
    L1_ATOM   = 1,
    L2_CELL   = 2,
    L3_ENGINE = 3,
    INVALID   = 255
};

Structs

struct LevelCharacteristics {
    ModuleLevel level;
    std::string name;
    std::string description;
    bool is_stateless;
    bool is_composable;
    bool allows_dependencies;
    uint32_t max_dependencies;
    std::vector<std::string> responsibilities;
    std::vector<std::string> prohibitions;
};

struct ModuleMetadata {
    std::string module_name;
    ModuleLevel level;
    std::vector<std::string> dependencies;
    std::string version;
    std::string description;

    bool is_valid() const;
};

Utility Functions

// Validate dependency
bool is_valid_dependency(ModuleLevel from, ModuleLevel to);

// Get level name
std::string level_name(ModuleLevel level);

// Parse level from string
ModuleLevel parse_level(const std::string& name);

🛠️ Build Options

# Build with tests
cmake -DBUILD_TESTS=ON ..

# Build with examples
cmake -DBUILD_EXAMPLES=ON ..

# Build with coverage (GCC/Clang)
cmake -DCMAKE_CXX_FLAGS="--coverage" ..

# Release build
cmake -DCMAKE_BUILD_TYPE=Release ..

📝 Formato de Metadata

JSON

{
  "module_name": "SVF_Filter",
  "level": "L1_ATOM",
  "version": "1.0.0",
  "description": "State Variable Filter",
  "dependencies": ["mul_kernel", "add_kernel"]
}

YAML

module_name: SVF_Filter
level: L1_ATOM
version: 1.0.0
description: State Variable Filter
dependencies:
  - mul_kernel
  - add_kernel

⚡ Performance

  • Level lookup: O(1) (array indexing)
  • Dependency check: O(1) (matrix lookup)
  • String parsing: O(n) (simple string ops)
  • Metadata parsing: O(n) (streaming parser)

Recomendación: Cache results en hot paths.


🔗 Dependencias

Runtime

  • C++20 compiler (para concepts, ranges)
  • STL standard library

Build-time

  • CMake 3.20+
  • Catch2 v3 (auto-fetched si no encontrado)

Optional

  • nlohmann/json (para mejor JSON parsing)
  • yaml-cpp (para mejor YAML parsing)

📌 Próximos Pasos

Después de completar este módulo, continuar con:

  1. 05_01_01_composition_rules - Reglas de composición
  2. 05_01_02_validation_engine - Motor de validación

🆘 FAQ

P: ¿Cómo sé si mi módulo es L1 o L2? R: Si compone múltiples L1_ATOMs → L2_CELL. Si es un solo algoritmo → L1_ATOM.

P: ¿L2 puede depender de L2? R: Sí, PERO sin crear ciclos. Usa DAG analysis para verificar.

P: ¿Por qué L0 no puede depender de nada? R: L0 es la base del sistema. Si dependiera de algo, ese "algo" debería ser L0 (contradicción).

P: ¿Cómo clasificar un módulo ambiguo? R: Usa el decision tree en LEVEL_SEMANTICS.md.


Status: ✅ Completado Cobertura: >95% Última actualización: 2025-10-10