ISAC-Sim

Core Framework Module Guide

Infrastructure layer for Symbion reproducible experiments

This guide details how to use the Core framework module (symbion/core) of the Symbion library, which provides the core abstractions and tools needed for building reproducible scientific experiments.

Table of Contents

1. Module Overview

1.1 Design Philosophy

The Core module is the infrastructure layer of the Symbion library, following these design principles:

  • Reproducibility First: All experiments can be fully reproduced via seeds and configurations
  • Type Safety: Complete TypeScript type definitions
  • Modular Design: Each sub-module is independent and composable
  • Standardized Logging: Structured logs in JSONL/CSV format
  • Standard RL Compatible: Seamless integration with Python Reinforcement Learning ecosystem

1.2 Core Submodules

SubmoduleFunctionMain Usage
SpaceSpace DefinitionDefine structure of observations and actions
ObjectiveMetric SystemCombine multiple optimization objectives
ConstraintConstraint SystemDefine and evaluate hard/soft constraints
RunnerExperiment RunnerExecute complete experiment loop
LoggingLogging SystemRecord experiment data

2. Space - Space Definition

The Space module provides standard RL-compatible observation space and action space definitions.

DiscreteSpace

Represents a finite set of discrete options [0, n).

import { discrete } from 'symbion/core';

// MCS Selection: 0-28 Total 29 options
const mcsSpace = discrete(29, ['MCS-0', 'MCS-1', ..., 'MCS-28']);

// Direction Selection
const directionSpace = discrete(4, ['North', 'East', 'South', 'West']);

BoxSpace - Continuous Space

Represents an n-dimensional continuous space, with bounds for each dimension.

import { box } from 'symbion/core';

// 3D Position Space
const positionSpace = box(
  [3],                    // Shape: 3D vector
  [0, 0, 30],            // Low: x, y, z min values
  [1000, 1000, 150]       // High: x, y, z max values
);

// Normalized Observation Space
const normalizedObs = box(
  [12],        // 12D observation vector
  -1,          // Lower bound -1 for all dimensions
  1,           // Upper bound 1 for all dimensions
  'float32'    // Data type
);

DictSpace

Named dictionary of spaces, used for structured inputs or outputs.

import { dict, box, discrete } from 'symbion/core';

const inputSpace = dict({
  // Motion State
  position: box([3], 0, 1000),
  velocity: box([3], -20, 20),
  
  // Communication State
  mcsIndex: discrete(29),
  txPower: box([1], 0, 23),
});

Space Operations

Sampling

import { sample, createRng } from 'symbion/core';

const space = box([3], 0, 1000);
const rng = createRng(42); // Use seed for reproducibility

const value = sample(space, rng.random.bind(rng));
console.log('Sample:', value);

Flattening & Unflattening

import { flatten, unflatten, dict, box } from 'symbion/core';

const space = dict({ position: box([3], 0, 1000) });
const value = { position: [100, 200, 50] };

const flattened = flatten(space, value); // [100, 200, 50]
const restored = unflatten(space, flattened);

3. Objective - Metric System

Objective module provides metric definition, composition, and tracking functions for multi-objective optimization.

Simplified Metric Creation

import { simpleMetric } from 'symbion/core';

// Maximize reward
const reward = simpleMetric('reward', (s) => s.reward, 'maximize');

// Minimize energy
const energy = simpleMetric('energy', (s) => s.energy, 'minimize');

Metric Composition

import { combineMetricsWithTracking, simpleMetric } from 'symbion/core';

const metrics = [
  simpleMetric('throughput', (s) => s.throughput, 'maximize'),
  simpleMetric('energy', (s) => s.energy, 'minimize'),
];

// Create composite evaluator (Weighted Sum)
const composite = combineMetricsWithTracking(metrics, 'weighted_sum');

const result = composite.evaluate({ throughput: 100, energy: 50 });
console.log('Total Score:', result.total);
console.log('Breakdown:', result.breakdown);

4. Constraint - Constraint System

Constraint module provides constraint definition and evaluation, distinguishing between hard constraints (must satisfy) and soft constraints (violation incurs penalty).

Creating Constraints

import { leConstraint, geConstraint } from 'symbion/core';

// Max Speed Constraint: speed ≤ 20 (Hard)
const maxSpeed = leConstraint(
  'max_speed',
  (state) => state.speed,
  20,
  'hard'
);

// Min SINR Constraint: sinrDb ≥ 0 (Soft)
const minSinr = geConstraint(
  'min_sinr',
  (state) => state.sinrDb,
  0,
  'soft',
  { penaltyWeight: 10 }
);

Constraint Evaluation

import { evaluateConstraints } from 'symbion/core';

const constraints = [maxSpeed, minSinr];
const state = { speed: 18, sinrDb: -3 };

const report = evaluateConstraints(constraints, state);

console.log('Feasible (Hard constraints met?):', report.feasible);
console.log('Total Penalty (Soft violations):', report.totalPenalty);
console.log('Violations:', report.violations);

5. Runner - Experiment Runner

Runner module provides a unified experiment execution framework, integrating environment, policy, metrics, and constraints.

Runner Configuration

import { Runner, createTaskConfig, ConsoleLogger } from 'symbion/core';

const config = {
  // Task Config
  taskConfig: createTaskConfig({
    taskName: 'uav-sim',
    seed: 42
  }),

  // Environment and Policy
  environment: myEnvironment,
  policy: myPolicy,

  // Run Parameters
  maxStepsPerEpisode: 500,
  totalEpisodes: 100,

  // Logging
  loggers: [new ConsoleLogger('info')]
};

const runner = new Runner(config);

Running Experiments

// Run complete experiment
const result = await runner.run();

console.log(`Total Episodes: ${result.totalEpisodes}`);
console.log(`Avg Metric: ${result.avgEpisodeMetric.toFixed(2)}`);
console.log(`Success Rate: ${(result.successRate * 100).toFixed(1)}%`);

6. Logging - Logging System

Logging module provides structured logging, supporting step-level, episode-level, and report-level logs.

ConsoleLogger

import { ConsoleLogger } from 'symbion/core';

const logger = new ConsoleLogger('info'); // 'debug' | 'info' | 'warn' | 'error'

// Log a step
logger.logStep({
    task: 'uav-sim',
    seed: 42,
    episode: 1,
    step: 10,
    observation: [...],
    action: [...],
    reward: 1.0
});