Saltar al contenido principal

Resumen

El lenguaje de Expresiones (Expressions) (o DSL) es la forma de hacer dinámicos los modelos de ProDex. En cualquier lugar donde esperarías ingresar un número fijo — condiciones de enrutamiento, prioridades de cola, requisitos de recursos, valores de atributos de entidad, disparadores de eventos y los parámetros de las distribuciones de tiempo de procesamiento — puedes ingresar una expresión en su lugar. Las expresiones referencian el estado de simulación, atributos de entidad, constantes, tablas de búsqueda (Lookup Tables) y variables de estado, de modo que tu modelo responde a los datos que fluyen a través de él en lugar de comportarse idénticamente para cada entidad. Un usuario que solo ingresa números fijos está usando una pequeña fracción de lo que el Modelador (Modeler) puede hacer. Aprender el lenguaje de expresiones es lo que convierte un diagrama de flujo estático en un modelo vivo de tus operaciones.

Dónde aparecen las expresiones

La mayoría de los campos numéricos y lógicos en la configuración de un componente aceptan tanto un valor literal como una expresión. Lugares comunes:
  • Arrival rate en una Fuente (Source) — puede depender del tiempo de simulación, calendario (Schedule) o estado
  • Routing conditions en un Enrutador (Router) — ramifica según atributos de entidad, disponibilidad de recursos o estado de cola
  • Resource requirements en un Proceso (Process) — cuántas unidades de un recurso (Resource) se necesitan, condicionado a la entidad
  • Queue priority en un Búfer (Buffer) — ordena entidades en espera por una puntuación calculada
  • Resource allocation priority — elige entre demandas en competencia cuando la capacidad está restringida
  • Event Hook condition y argumentos de Action — consulta Event Hooks
  • Event Listener condition y argumentos de Action — consulta Event Listeners
  • Scheduled action condition — controla si un assign / emit programado dispara (consulta Calendarios)
  • Asignaciones de atributo de Entidad (Entity) en una salida de Source, Transformador (Transformer), Combinador (Combiner) o Separador (Separator) — calcula valores iniciales o actualizados de atributos
  • Combinador batch_expr — el disparador booleano que cierra un lote de tamaño dinámico
  • Separador output count — expresión DSL que retorna el número de salidas por entrada
  • Parámetros de distribución (Distribution) — cada campo numérico que acepta una distribución tiene un toggle </> que cambia la entrada del parámetro a modo de expresión. Consulta Distribuciones vs. Expresiones más adelante.

Sintaxis básica

Las expresiones siguen una sintaxis tipo Excel: literales numéricos, literales de cadena en comillas simples O dobles, llamadas de función en forma FUNCTION(args), operadores aritméticos, operadores de comparación y operadores lógicos.
5
"TypeA"
'TypeB'
FUNCTION(arg1, arg2)
a + b * c
IF(condition, then_value, else_value)
priority > 5 AND qc_passed
Los literales booleanos no distinguen entre mayúsculas y minúsculas — TRUE, True, true, FALSE, False, false todos se analizan correctamente.

Precedencia de operadores

Las expresiones siguen la precedencia estándar de operadores (de mayor a menor):
  1. NOT, - unario
  2. Multiplicación, división*, /
  3. Suma, resta+, -
  4. Comparación<, <=, >, >=, =, ==, !=
  5. AND
  6. OR
AND, OR y NOT son operadores infijo y prefijo, no funciones — escribe a AND b, a OR b, NOT a, nunca AND(a, b). Tanto = como == se aceptan como operadores de igualdad. Usa paréntesis para agrupación explícita cuando quieras anular la precedencia.

Contextos de expresión

El contexto en el que se ejecuta una expresión determina qué identificadores están disponibles para referenciar. Equivocarse de contexto produce errores de validación como “identifier not available here” que son confusos sin entender el modelo. Hay tres contextos.

Contexto sin Entidad

Se ejecuta sin una entidad específica en alcance. Identificadores disponibles: Usado en: tasas de llegada de Source (antes de que exista cualquier entidad), condiciones y acciones de Event Listener (los listeners siempre se ejecutan sin entidad), eventos de Resource, acciones programadas y verificaciones de estado global.

Contexto de Entidad única

Se ejecuta con una entidad específica en alcance. Todo lo del contexto sin entidad, más:
  • Atributos de entidad por nombre simplepriority, product_class, weight
  • ENTITY_TYPE, ENTITY_AGE
Usado en: tiempo de procesamiento de Process, condiciones de Router, asignaciones de atributo de Transformer, Event Hooks por entidad (p. ej., entity created, process started) y lugares similares donde una entidad está claramente en alcance.

Contexto de múltiples Entidades

Se ejecuta con múltiples entidades en alcance. Las cuatro superficies multi-entidad son:
  • Asignación de atributo de Combiner — atributos de la entidad de salida derivados de las entradas
  • Combiner batch_expr — el disparador booleano que cierra un lote dinámico
  • Hook on_batch_assembled de Combiner — dispara una vez por lote ensamblado con todas las entradas en alcance
  • Hook on_batch_created de Separator — dispara una vez por separación con todas las salidas en alcance
En cualquier contexto multi-entidad, las referencias de atributo simples como priority son ambiguas (¿de qué entidad?). Debes envolverlas en una función de agregación: MAX(priority) > 5, ANY(qc_passed).

Variables de estado integradas

  • SIM_TIME — tiempo actual de simulación
  • SIM_DURATION — duración configurada de la simulación
  • ENTITY_TYPE — slug de tipo de entidad de la entidad actual (solo contexto de entidad única). Retorna el slug (p. ej., widget), no el nombre visible (p. ej., Widget).
  • ENTITY_AGE — tiempo que la entidad actual ha estado en el sistema (solo contexto de entidad única)
  • SELF — el componente actual (consulta Disponibilidad de SELF)

Disponibilidad de SELF

SELF es solo válido dentro de expresiones de event hook y event listener. No está disponible en:
  • Acciones programadas
  • Campos de configuración de componente fuera de hooks/listeners (processing_time, arrival_logic, reglas de enrutamiento, prioridad de cola, prioridad de asignación de recursos, asignaciones de atributos)
Si necesitas referenciar un componente específico desde fuera de un hook, usa el nombre de ese componente explícitamente dentro de una función de consulta de componente.

Funciones de consulta de componentes

Estas funciones leen el estado vivo de simulación para un componente específico. Toman el campo id del componente (el id del esquema, no el nombre visible) como primer argumento.
  • BUFFER_LEVEL(buffer_id) — número actual de entidades en el búfer nombrado
  • BUFFER_CAPACITY(buffer_id) — capacidad configurada del búfer nombrado
  • RESOURCE_AVAILABLE(resource_id) — unidades actualmente disponibles del recurso nombrado
  • RESOURCE_CAPACITY(resource_id) — capacidad configurada del recurso nombrado
  • STATION_WIP(station_id [, entity_type]) — trabajo en curso en la estación (Station) nombrada; segundo argumento opcional filtra a un tipo de entidad específico
Las funciones de consulta de componentes toman el id del componente, no el nombre visible mostrado en el Modelador. Si el nombre visible de tu búfer es “WIP Buffer” y su id es wip-buffer, debes escribir BUFFER_LEVEL("wip-buffer"). Pasar el nombre visible retorna silenciosamente 0 y tu modelo se comporta como si el búfer estuviera siempre vacío.

Valor por defecto

Todas las funciones de consulta de componentes aceptan un argumento de palabra clave opcional default:= que anula el valor de respaldo cuando el componente no se encuentra:
BUFFER_LEVEL("wip-buffer", default:=-1)
Sin default:=, los componentes faltantes retornan el numérico 0. A diferencia de LOOKUP, las consultas de componentes no retornan cero específico de tipo ("" o FALSE) — solo 0.

Variables de estado personalizadas

Las variables de estado definidas en el modelo son legibles por su nombre simple en SCREAMING_SNAKE_CASE en cualquier contexto DSL — sin entidad, entidad única o multi-entidad:
current_shift_efficiency
UNITS_COMPLETED + 1
IF(SHIFT_MODE == "night", base_time * 1.2, base_time)
Las variables de estado se leen directamente en las expresiones y se escriben a través de la acción assign en event hooks, event listeners o acciones programadas. Persisten a través de entidades y de toda la ejecución. Para la distinción entre variables de estado (a nivel de modelo, mutables) y atributos de entidad (por entidad, se mueven con la entidad), consulta Atributos de Entidad más adelante.

Atributos de Entidad

Las entidades llevan atributos tipados a través del flujo — booleanos, números, texto, listas de texto, listas de números. Referencia los atributos de la entidad actual por su nombre simple en cualquier expresión que se ejecute en un contexto de entidad única:
priority
product_class
weight
Sin prefijo self. — la entidad en alcance es implícita. Las expresiones referencian atributos directamente por el nombre definido en el tipo de entidad. En contextos multi-entidad, los nombres simples de atributo se refieren al conjunto de entidades y deben envolverse en una función de agregación como SUM(weight) o MAX(priority). Consulta Funciones de agregación. Los atributos de entidad se establecen en una Source, pueden ser modificados por un Transformer y pueden ser leídos desde cualquier expresión aguas abajo. Persisten con la entidad a través del flujo completo. Consulta Entidades para el sistema completo de tipos de atributos y las estrategias de asignación.

Distribuciones vs. Expresiones

Una confusión común: las distribuciones no son funciones DSL. No puedes escribir NORMAL(60, 10) como una expresión. Las distribuciones se seleccionan de un menú desplegable en cada campo numérico que las admite — Normal, Uniform, Triangular, Beta y el resto de las diez opciones. Seleccionar una revela los campos de parámetros debajo del selector. Cada campo de parámetro tiene un toggle </> que lo cambia a modo de expresión — ahí entra el DSL. La forma de la distribución permanece estática; los valores de los parámetros se vuelven dinámicos. Por ejemplo, en lugar de una media codificada en 60, puedes cambiar el campo Mean a modo de expresión y escribir:
base_time + weight * 0.5
O hacer que la media dependa de una tabla de búsqueda por tipo de entidad:
LOOKUP(cycle_times_by_product, ENTITY_TYPE) * complexity_factor
El campo Standard Deviation puede permanecer como literal 10, o también ser una expresión. Consulta Distribuciones para la lista completa de tipos de distribución admitidos.

Funciones comunes

Flujo de control

  • IF(condition, then, else) — ramifica entre dos valores
  • AND, OR, NOT — combinaciones lógicas (operadores infijo/prefijo, no funciones)
  • Operadores de comparación: ==, !=, <, <=, >, >=, =

Matemáticas

  • ABS(x) — valor absoluto
  • POW(x, y)x elevado a y
  • MOD(x, y) — resto de x dividido entre y
  • Aritmética estándar: +, -, *, /

Cadenas

  • CONTAINS(text, substring) — si una cadena contiene una subcadena (distingue mayúsculas/minúsculas)
  • LEN(text) — longitud de una cadena, como número

Búsquedas

  • LOOKUP(table_name, key1, key2, ...) — busca un valor de una Tabla de búsqueda. Suministra una clave por dimensión. Acepta un argumento de palabra clave opcional default:=:
LOOKUP(setup_times, product_class, default:=300)
Sin default:=, las filas faltantes retornan el cero específico de tipo (0 para tablas numéricas, "" para texto, FALSE para booleano). Consulta Constantes y Tablas de búsqueda para el esquema completo.

Funciones de agregación

Válidas solo en contextos multi-entidad (asignación de atributo de Combiner, batch_expr de Combiner, on_batch_assembled de Combiner, on_batch_created de Separator). Las agregaciones operan sobre el conjunto de entidades en alcance:
  • SUM(expr) — suma
  • MEAN(expr) — promedio
  • COUNT(expr) — cuenta de entidades en alcance (canónicamente COUNT(1))
  • MAX(expr) — valor máximo
  • MIN(expr) — valor mínimo
  • MODE(expr) — valor más común
  • N_UNIQUE(expr) — cuenta de valores distintos
  • ANY(expr) — verdadero si la expresión es verdadera para alguna entidad
  • ALL(expr) — verdadero si la expresión es verdadera para cada entidad
Cada agregación acepta dos argumentos de palabra clave opcionales:
  • filter:=<boolean expr> — solo agrega entidades donde el filtro evalúa verdadero
  • type:=<entity_type_slug> — solo agrega entidades del tipo nombrado (slug sin comillas)
SUM(weight, filter:=qc_passed)
COUNT(1, type:=tube)
MAX(priority, filter:=is_rush)
type:= toma un slug sin comillas, y los slugs con guión no se admiten en esta posición. Un tipo con un guión en su slug no puede filtrarse con type:= — soluciónalo con filter:=ENTITY_TYPE == "my-type" en su lugar.
Ejemplo — un Combiner produciendo un ensamblaje, estableciendo atributos de salida desde sus entradas:
# Atributo de salida: total_weight
SUM(weight)

# Atributo de salida: priority
MAX(priority)

# Condición de salida: emitir solo si cada entrada pasó QC
ALL(qc_passed)

Seguridad de tipos

El DSL es estáticamente tipado. Cada expresión se verifica de tipo en tiempo de validación del modelo, no en tiempo de ejecución. Un campo de condición espera un booleano; una asignación de atributo para un atributo Number debe producir un número; una expresión de cantidad debe producir un entero. Mezclar tipos falla la validación con un error específico apuntando a la expresión ofensiva — consulta Validación. No hay coerción implícita de tipos. 5 + "x" no se convierte silenciosamente en "5x" — falla la validación. Convierte explícitamente cuando lo necesites.

Patrones comunes

Enrutamiento condicional — envía cada entidad por la ruta correcta:
IF(product_class = "rush", "express_line", "standard_line")
Parámetro de distribución impulsado por atributos — cambia el campo Mean de una distribución Normal a modo de expresión para que se adapte a cada entidad, mientras Standard Deviation permanece en 10 fijo:
LOOKUP(cycle_times_by_product, ENTITY_TYPE) * complexity_factor
Contrapresión — frena las llegadas cuando aguas abajo está congestionado, vía una expresión en la tasa de llegada de Source:
IF(BUFFER_LEVEL("wip-buffer") > 100, 0, 1)
Puntuación de prioridad — ordena entidades en espera por importancia calculada:
due_priority * 0.7 + customer_tier * 0.3
Salida de ensamblaje — combina varias entradas en una (Combiner, contexto multi-entidad):
# El peso de la entidad ensamblada es la suma de sus entradas
SUM(weight)

# Emitir solo si todas las entradas pasaron QC
ALL(qc_passed)

Consejos y trampas

  • Las expresiones se evalúan en cada entidad, cada vez. Mantenlas simples donde sea posible — las expresiones complejas en rutas de alto rendimiento se acumulan.
  • Las consultas de componentes retornan cero numérico. Un nombre de componente faltante produce 0, no nulo. Usa el argumento de palabra clave default:= si necesitas un centinela diferente.
  • LOOKUP retorna cero específico de tipo. 0, "" o FALSE dependiendo del tipo de valor de la tabla. Envuelve con default:= para un respaldo diferente.
  • Los atributos de entidad no son variables de estado. Los atributos pertenecen a una entidad y se mueven con ella. Las Variables de estado pertenecen al modelo y persisten a través de las entidades.
  • El contexto importa. Si encuentras un error de validación como “identifier priority not available here”, la expresión se está ejecutando en un contexto que no tiene una entidad en alcance. Consulta Contextos de expresión.
  • SELF vs. nombres simples de atributo. SELF se refiere al componente al que está adjunta la expresión (solo hooks y listeners). Los nombres simples se refieren a atributos de entidad. No se superponen.
  • ENTITY_TYPE retorna el slug, no el nombre visible. Compara contra "widget", no "Widget".
  • Prefiere Constantes y Tablas de búsqueda sobre valores codificados. Cambia una constante en un solo lugar; no puedes fácilmente buscar-y-reemplazar a través de decenas de expresiones.