v0.12.0 regression: evaluation time exponential in derived features referenced from untaken if branches

Abierto
#1,929 1 comentario 1 reacción 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@devin-ai-integration ya está trabajando en esto.

Desde el 4/11/2026.

  • #1933 de @devin-ai-integration — abierto

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
25/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Estancado
Stack tecnológico
go
Área
performance

Línea de trabajo

Start by reviewing the v0.12.0 changelog entries about order-dependence marks and cycle detection, then trace evaluation of if operands declared as in expr in ControlFunctions. Reproduce with the supplied gen.py model and compare the expression-valued and plain-default feature timings. Done means untaken branches avoid exponential evaluation while preserving the reported results; linked pull request #1933 is already open.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

Summary

In v0.12.0, evaluating a feature valued by an expression takes time exponential in the number of other expression-valued features referenced from untaken if branches. v0.11.0 evaluates the same model in constant time. The results are the same in both versions; only the time differs. No diagnostic is emitted, so a larger model just appears to hang.

Reproduction

gen.py writes N features a1..aN. Each ai picks another feature by an integer selector pi (default 0, so every branch is untaken):

import sys
n, target = int(sys.argv[1]), sys.argv[2]   # target: "a" (expression-valued features) or "c" (plain defaults)
print(f"package R {{ private import ScalarValues::*; part def T {{")
for i in range(1, n + 1):
    e = "false"
    for j in range(n, 0, -1):
        e = f"(if p{i} == {j} ? {target}{j} else {e})"
    print(f"  attribute p{i} : Integer default 0; attribute c{i} : Boolean default true;")
    print(f"  attribute a{i} : Boolean = {e};")
print("} part t : T; }")
python3 gen.py 9 a > r.sysml
sysml r.sysml -e '$::R::t.a1'

Timings (linux-amd64 release binaries, same machine)

N branches reference a_j — v0.11.0 branches reference a_j — v0.12.0 branches reference c_j — v0.12.0
7 ~0.05 s 0.17 s 0.05 s
8 0.05 s 0.31 s 0.05 s
9 0.06 s 2.71 s 0.05 s
10 0.07 s 29.94 s 0.05 s

All runs print = false. Loading and validating r.sysml alone takes about 0.02 s, so the time is spent in evaluation.

Control experiments (N = 9, v0.12.0)

  • Only if, all branches untaken (the generator above): 2.8 s. This rules out or/and as the cause.
  • The same chain prefixed with p1 == 0 or …, or with p1 != 0 and …: about 3 s each.
  • The same shape, but the branches reference plain default features c_j, so there are no references between expression-valued features: 0.05 s.
  • A direct self-reference only (a = true or a): 0.06 s.

So the slowdown needs untaken branches that reference other expression-valued features which, syntactically, form cycles. The cycles are never taken at run time.

Expected

ControlFunctions declares the branch operands of if, and, or and implies as in expr. Its doc describes these operands as "expressions whose evaluation is determined by another operand". An untaken branch should therefore not need to be evaluated. In any case, the cost should not grow exponentially with the size of the model, as it did not in v0.11.0.

Notes

The 0.12.0 changelog has two entries that may be related, though we have not confirmed either:

  • expression-valued features now carry order-dependence marks "through features so valued in turn";
  • "a cycle among such features is refused by the interpreter at the start".

We found this in a model with about 9 mutually referencing derived features. One evaluation went from 0.45 s in v0.11.0 to more than 90 s in v0.12.0, after which we stopped it. We have since rewritten that model with ref features, which v0.12.0 evaluates fast, so this is not blocking us. We are reporting it as a regression.

Lenguaje dominante
Go
Estrellas
56
Forks
17
Merge medio
12 h 38 min
PR fusionados (30 d)
903

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Open-MBEE/OpenSysML

Todos los issues de Open-MBEE/OpenSysML

Issues similares

Más issues de Go

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.