|
| 1 | +import { createContext } from "react"; |
| 2 | + |
| 3 | +import type { Color, ID, Place, SDCPN, Transition } from "../core/types/sdcpn"; |
| 4 | + |
| 5 | +/** |
| 6 | + * Current state of the simulation lifecycle. |
| 7 | + */ |
| 8 | +export type SimulationState = |
| 9 | + | "NotRun" |
| 10 | + | "Running" |
| 11 | + | "Complete" |
| 12 | + | "Error" |
| 13 | + | "Paused"; |
| 14 | + |
| 15 | +/** |
| 16 | + * State of a transition within a simulation frame. |
| 17 | + * |
| 18 | + * Contains timing information and firing counts for tracking transition behavior |
| 19 | + * during simulation execution. |
| 20 | + */ |
| 21 | +export type SimulationFrameState_Transition = { |
| 22 | + /** |
| 23 | + * Time elapsed since this transition last fired, in milliseconds. |
| 24 | + * Resets to 0 when the transition fires. |
| 25 | + */ |
| 26 | + timeSinceLastFiringMs: number; |
| 27 | + /** |
| 28 | + * Whether this transition fired in this specific frame. |
| 29 | + * True only during the frame when the firing occurred. |
| 30 | + */ |
| 31 | + firedInThisFrame: boolean; |
| 32 | + /** |
| 33 | + * Total cumulative count of times this transition has fired |
| 34 | + * since the start of the simulation (frame 0). |
| 35 | + */ |
| 36 | + firingCount: number; |
| 37 | +}; |
| 38 | + |
| 39 | +// |
| 40 | +// Simulation Instance Types |
| 41 | +// |
| 42 | +// These types define the internal simulation data structures. They are defined |
| 43 | +// here to ensure the context module has no dependencies on the simulator module, |
| 44 | +// making the context the source of truth for type definitions. |
| 45 | +// |
| 46 | +// TODO FE-207: This is a temporary solution that leaks implementation details of the |
| 47 | +// SDCPN simulator (e.g., compiled function types, buffer layouts) into the |
| 48 | +// context module. Ideally, the context should only expose a minimal public |
| 49 | +// interface, and these internal types should live in the simulator module. |
| 50 | +// This would require refactoring SimulationContextValue to not expose the |
| 51 | +// full SimulationInstance, but instead provide accessor methods or a |
| 52 | +// simplified public state type. |
| 53 | +// |
| 54 | + |
| 55 | +/** |
| 56 | + * Runtime parameter values used during simulation execution. |
| 57 | + * Maps parameter names to their resolved numeric or boolean values. |
| 58 | + */ |
| 59 | +export type ParameterValues = Record<string, number | boolean>; |
| 60 | + |
| 61 | +/** |
| 62 | + * Compiled differential equation function for continuous dynamics. |
| 63 | + * Computes the rate of change for tokens in a place with dynamics enabled. |
| 64 | + */ |
| 65 | +export type DifferentialEquationFn = ( |
| 66 | + tokens: Record<string, number>[], |
| 67 | + parameters: ParameterValues, |
| 68 | +) => Record<string, number>[]; |
| 69 | + |
| 70 | +/** |
| 71 | + * Compiled lambda function for transition firing probability. |
| 72 | + * Returns a rate (number) for stochastic transitions or a boolean for predicate transitions. |
| 73 | + */ |
| 74 | +export type LambdaFn = ( |
| 75 | + tokenValues: Record<string, Record<string, number>[]>, |
| 76 | + parameters: ParameterValues, |
| 77 | +) => number | boolean; |
| 78 | + |
| 79 | +/** |
| 80 | + * Compiled transition kernel function for token generation. |
| 81 | + * Computes the output tokens to create when a transition fires. |
| 82 | + */ |
| 83 | +export type TransitionKernelFn = ( |
| 84 | + tokenValues: Record<string, Record<string, number>[]>, |
| 85 | + parameters: ParameterValues, |
| 86 | +) => Record<string, Record<string, number>[]>; |
| 87 | + |
| 88 | +/** |
| 89 | + * Input configuration for building a new simulation instance. |
| 90 | + */ |
| 91 | +export type SimulationInput = { |
| 92 | + /** The SDCPN definition to simulate */ |
| 93 | + sdcpn: SDCPN; |
| 94 | + /** Initial token distribution across places */ |
| 95 | + initialMarking: Map<string, { values: Float64Array; count: number }>; |
| 96 | + /** Parameter values from the simulation store (overrides SDCPN defaults) */ |
| 97 | + parameterValues: Record<string, string>; |
| 98 | + /** Random seed for deterministic stochastic behavior */ |
| 99 | + seed: number; |
| 100 | + /** Time step for simulation advancement */ |
| 101 | + dt: number; |
| 102 | +}; |
| 103 | + |
| 104 | +/** |
| 105 | + * A running simulation instance with compiled functions and frame history. |
| 106 | + * Contains all state needed to execute and advance the simulation. |
| 107 | + */ |
| 108 | +export type SimulationInstance = { |
| 109 | + /** Place definitions indexed by ID */ |
| 110 | + places: Map<string, Place>; |
| 111 | + /** Transition definitions indexed by ID */ |
| 112 | + transitions: Map<string, Transition>; |
| 113 | + /** Color type definitions indexed by ID */ |
| 114 | + types: Map<string, Color>; |
| 115 | + /** Compiled differential equation functions indexed by place ID */ |
| 116 | + differentialEquationFns: Map<string, DifferentialEquationFn>; |
| 117 | + /** Compiled lambda functions indexed by transition ID */ |
| 118 | + lambdaFns: Map<string, LambdaFn>; |
| 119 | + /** Compiled transition kernel functions indexed by transition ID */ |
| 120 | + transitionKernelFns: Map<string, TransitionKernelFn>; |
| 121 | + /** Resolved parameter values for this simulation run */ |
| 122 | + parameterValues: ParameterValues; |
| 123 | + /** Time step for simulation advancement */ |
| 124 | + dt: number; |
| 125 | + /** Current state of the seeded random number generator */ |
| 126 | + rngState: number; |
| 127 | + /** History of all computed frames */ |
| 128 | + frames: SimulationFrame[]; |
| 129 | + /** Index of the current frame in the frames array */ |
| 130 | + currentFrameNumber: number; |
| 131 | +}; |
| 132 | + |
| 133 | +/** |
| 134 | + * A single frame (snapshot) of the simulation state at a point in time. |
| 135 | + * Contains the complete token distribution and transition states. |
| 136 | + */ |
| 137 | +export type SimulationFrame = { |
| 138 | + /** Back-reference to the parent simulation instance */ |
| 139 | + simulation: SimulationInstance; |
| 140 | + /** Simulation time at this frame */ |
| 141 | + time: number; |
| 142 | + /** Place states with token buffer offsets */ |
| 143 | + places: Map< |
| 144 | + ID, |
| 145 | + { instance: Place; offset: number; count: number; dimensions: number } |
| 146 | + >; |
| 147 | + /** Transition states with firing information */ |
| 148 | + transitions: Map< |
| 149 | + ID, |
| 150 | + SimulationFrameState_Transition & { instance: Transition } |
| 151 | + >; |
| 152 | + /** |
| 153 | + * Buffer containing all place values concatenated. |
| 154 | + * |
| 155 | + * Size: sum of (place.dimensions * place.count) for all places. |
| 156 | + * |
| 157 | + * Layout: For each place, its tokens are stored contiguously. |
| 158 | + * |
| 159 | + * Access to a place's token values can be done via the offset and count in the `places` map. |
| 160 | + */ |
| 161 | + buffer: Float64Array; |
| 162 | +}; |
| 163 | + |
| 164 | +/** |
| 165 | + * Simplified view of a simulation frame for UI consumption. |
| 166 | + * Provides easy access to place and transition states without internal details. |
| 167 | + */ |
| 168 | +export type SimulationFrameState = { |
| 169 | + /** Frame index in the simulation history */ |
| 170 | + number: number; |
| 171 | + /** Simulation time at this frame */ |
| 172 | + time: number; |
| 173 | + /** Place states indexed by place ID */ |
| 174 | + places: { |
| 175 | + [placeId: string]: |
| 176 | + | { |
| 177 | + /** Number of tokens in the place at the time of the frame. */ |
| 178 | + tokenCount: number; |
| 179 | + } |
| 180 | + | undefined; |
| 181 | + }; |
| 182 | + /** Transition states indexed by transition ID */ |
| 183 | + transitions: { |
| 184 | + [transitionId: string]: SimulationFrameState_Transition | undefined; |
| 185 | + }; |
| 186 | +}; |
| 187 | + |
| 188 | +/** |
| 189 | + * Initial token distribution for starting a simulation. |
| 190 | + * Maps place IDs to their initial token values and counts. |
| 191 | + */ |
| 192 | +export type InitialMarking = Map< |
| 193 | + string, |
| 194 | + { values: Float64Array; count: number } |
| 195 | +>; |
| 196 | + |
| 197 | +/** |
| 198 | + * The combined simulation context containing both state and actions. |
| 199 | + */ |
| 200 | +export type SimulationContextValue = { |
| 201 | + // State values |
| 202 | + simulation: SimulationInstance | null; |
| 203 | + state: SimulationState; |
| 204 | + error: string | null; |
| 205 | + errorItemId: string | null; |
| 206 | + parameterValues: Record<string, string>; |
| 207 | + initialMarking: InitialMarking; |
| 208 | + /** |
| 209 | + * The currently viewed simulation frame state. |
| 210 | + * Null when no simulation is running or no frames exist. |
| 211 | + */ |
| 212 | + currentViewedFrame: SimulationFrameState | null; |
| 213 | + dt: number; |
| 214 | + |
| 215 | + // Actions |
| 216 | + setInitialMarking: ( |
| 217 | + placeId: string, |
| 218 | + marking: { values: Float64Array; count: number }, |
| 219 | + ) => void; |
| 220 | + setParameterValue: (parameterId: string, value: string) => void; |
| 221 | + setDt: (dt: number) => void; |
| 222 | + initializeParameterValuesFromDefaults: () => void; |
| 223 | + initialize: (params: { seed: number; dt: number }) => void; |
| 224 | + run: () => void; |
| 225 | + pause: () => void; |
| 226 | + reset: () => void; |
| 227 | + setCurrentViewedFrame: (frameIndex: number) => void; |
| 228 | +}; |
| 229 | + |
| 230 | +const DEFAULT_CONTEXT_VALUE: SimulationContextValue = { |
| 231 | + simulation: null, |
| 232 | + state: "NotRun", |
| 233 | + error: null, |
| 234 | + errorItemId: null, |
| 235 | + parameterValues: {}, |
| 236 | + initialMarking: new Map(), |
| 237 | + currentViewedFrame: null, |
| 238 | + dt: 0.01, |
| 239 | + setInitialMarking: () => {}, |
| 240 | + setParameterValue: () => {}, |
| 241 | + setDt: () => {}, |
| 242 | + initializeParameterValuesFromDefaults: () => {}, |
| 243 | + initialize: () => {}, |
| 244 | + run: () => {}, |
| 245 | + pause: () => {}, |
| 246 | + reset: () => {}, |
| 247 | + setCurrentViewedFrame: () => {}, |
| 248 | +}; |
| 249 | + |
| 250 | +export const SimulationContext = createContext<SimulationContextValue>( |
| 251 | + DEFAULT_CONTEXT_VALUE, |
| 252 | +); |
0 commit comments