wolfram queda programa mathematica ejecutar ejecucion correr como error-handling functional-programming wolfram-mathematica

error-handling - programa - mathematica se queda en ejecucion



Configuración de mensajes de error de diagnóstico en grandes proyectos de Mathematica (5)

YAsI - ¿Otra idea (tonta?) ...

Volviendo a leer tu pregunta ...

La idea entonces es deshabilitar todos los mensajes de error propios de Mathematica e implementar la verificación de tipos y los mensajes de error propios en cada función y módulo.

Encontró esto:

$MessagePrePrint = ( #; Print[Stack[_][[;; -5]]]; Abort[]) & v[x_, y_] := w[x, y]; w[x_, y_] := x/y; StackComplete@v[1, 0]; During evaluation of In[267]:= {StackComplete[v[1,0]];, StackComplete[v[1,0]], v[1,0], w[1,0], 1/0, 1/0, Message[Power::infy,1/0]} Out[267]= $Aborted

conclusión ... Anula el primer mensaje y deja un seguimiento de pila "razonable". "Razonable" significa "Debe mejorarse".

¡Pero es completamente no intrusivo!

Siempre que creo un gran proyecto de Mathematica me encuentro con este problema: evitar la avalancha de errores de tiempo de ejecución en Mathematica , es decir, el mensaje de error de Mathematica es opaco, arcaico y legión.

La idea entonces es deshabilitar todos los mensajes de error propios de Mathematica e implementar la verificación de tipos y los mensajes de error propios en cada función y módulo. Sin embargo, no he encontrado una manera simple y eficiente de hacer esto y terminé con, por ejemplo, alguna función que genera una función de error 20, y luego recibe toda una cascada de mensajes de error hasta la rutina principal.

¿Cómo configuraría un mecanismo simple para esto que solo genere un mensaje de error en la función que experimenta el error y una lista simple de la cadena de llamadas a funciones?

EDITAR: Desde que ha surgido en un par de respuestas; Estoy buscando específicamente algo liviano con respecto a la salida que produce (de lo contrario, podría seguir con los mensajes de error de Mathematica) y, obviamente, también liviano en la sobrecarga computacional. Por lo tanto, aunque Stack y Trace son claramente ligeros en cuanto a gastos generales, su producción en proyectos complejos no es rápida de analizar y es necesario realizar algunos trabajos para simplificarlos.


¿Una sugerencia para extraer la pila, tal vez algo que se basa en Trace?

Un ejemplo del uso de Trace a continuación, de Chris Chiasson. Este código guarda el árbol de evaluación de 1 + Sin [x + y] + Tan [x + y] en ~ / temp / msgStream.m

Developer`ClearCache[]; SetAttributes[recordSteps, HoldAll]; recordSteps[expr_] := Block[{$Output = List@OpenWrite["~/temp/msgStream.m"]}, TracePrint[Unevaluated[expr], _?(FreeQ[#, Off] &), TraceInternal -> True]; Close /@ $Output; Thread[ Union@Cases[ ReadList["~/temp/msgStream.m", HoldComplete[Expression]], symb_Symbol /; AtomQ@Unevaluated@symb && Context@Unevaluated@symb === "System`" :> HoldComplete@symb, {0, Infinity}, Heads -> True], HoldComplete] ]; recordSteps[1 + Tan[x + y] + Sin[x + y]]

Para responder a la pregunta de Samsdram, el siguiente código (también de Chris) muestra el árbol de evaluación de una expresión de Mathematica. Aquí está la publicación de MathGroup con código fuente y ejemplos.

(Attributes@# = {HoldAllComplete}) & /@ {traceToTreeAux, toVertex, HoldFormComplete, getAtoms, getAtomsAux} MakeBoxes[HoldFormComplete[args___], form_] := MakeBoxes[HoldForm[args], form] edge[{head1_, pos1_, xpr1_}, {head2_, pos2_, xpr2_}] := Quiet[Rule[{head1, vertexNumberFunction@pos1, xpr1}, {head2, vertexNumberFunction@pos2, xpr2}], {Rule::"rhs"}] getAtomsAux[atom_ /; AtomQ@Unevaluated@atom] := Sow[HoldFormComplete@atom, getAtomsAux] getAtomsAux[xpr_] := Map[getAtomsAux, Unevaluated@xpr, Heads -> True] getAtoms[xpr_] := Flatten@Reap[getAtomsAux@xpr][[2]] toVertex[traceToTreeAux[HoldForm[heldXpr_], pos_]] := toVertex[heldXpr] toVertex[traceToTreeAux[HoldForm[heldXprs___], pos_]] := toVertex@traceToTreeAux[Sequence[], pos] (*this code is strong enough to not need the ToString commands,but / some of the resulting graph vertices give trouble to the graphing / routines*) toVertex[ traceToTreeAux[xpr_, pos_]] := {ToString[ Short@Extract[Unevaluated@xpr, 0, HoldFormComplete], StandardForm], pos, ToString[Short@First@originalTraceExtract@{pos}, StandardForm]} traceToTreeAux[xpr_ /; AtomQ@Unevaluated@xpr, ___] := Sequence[] traceToTreeAux[_HoldForm, ___] := Sequence[] traceToTreeAux[xpr_, pos_] := With[{lhs = toVertex@traceToTreeAux[xpr, pos], args = HoldComplete @@ Unevaluated@xpr}, Identity[Sequence][ ReleaseHold[ Function[Null, edge[lhs, toVertex@#], HoldAllComplete] /@ args], ReleaseHold@args]] traceToTree[xpr_] := Block[{vertexNumber = -1, vertexNumberFunction, originalTraceExtract}, vertexNumberFunction[arg_] := vertexNumberFunction[arg] = ++vertexNumber; originalTraceExtract[pos_] := Extract[Unevaluated@xpr, pos, HoldFormComplete]; {MapIndexed[ traceToTreeAux, Unevaluated@xpr, {0, Infinity}]}] TraceTreeFormPlot[trace_, opts___] := Block[{$traceExpressionToTree = True}, Through@{Unprotect, Update}@SparseArray`ExpressionToTree; SparseArray`ExpressionToTree[trace, Infinity] = traceToTree@trace; With[{result = ToExpression@ToBoxes@TreeForm[trace, opts]}, Through@{Unprotect, Update}@SparseArray`ExpressionToTree; SparseArray`ExpressionToTree[trace, Infinity] =.; Through@{Update, Protect, Update}@SparseArray`ExpressionToTree; result]]; TraceTreeFormPlot[Trace[Tan[x] + Sin[x] - 2*3 - 55]]


Para hacer rodar la pelota aquí es una idea con la que he estado jugando; La creación de un pseudo stack.

Primero haga una variable global theStack={} y luego en cada Function o Module comience con AppendTo[theStack,"thisFuncName"] y finalice con theStack=Most@theStack . Suponiendo que la intensidad de las llamadas a funciones sea moderada (~ unas pocas decenas), esto no debería agregar ningún gasto general significativo.

Luego, implemente su propia comprobación de errores de escritura y use Print@theStack;Abort[]; en los errores.

Los refinamientos de este método podrían incluir:

  1. Descubrir una manera de obtener dinámicamente "thisFuncionName" para que el AppendTo[] se pueda convertir en una llamada de función idéntica para todas las Functions y el Module .
  2. Usando el Message[] lugar de Print[] .
  3. Empujando otras variables importantes / información con estado en el theStack .

Quizás hemos estado pensando demasiado en esto. ¿Qué pasa si acabamos de ajustar un poco el patrón que coincide con los argumentos? Por ejemplo, si modificamos la función para verificar una cantidad numérica y agregamos algún código para imprimir un error si falla. Por ejemplo,

TypeNumeric[x_] := If[! NumericQ[Evaluate[x]], Print["error at "]; Print[Stack[]]; Print["Expression "]; Print[x]; Print["Did not return a numeric value"];Return[False], (*Else*) Return[True];] SetAttributes[TypeNumeric, HoldAll];

Paso 2: Si tiene una función, f [x_] que requiere una cantidad numérica, simplemente escríbala con la prueba de patrón estándar y todo debería estar bien

Input: f[x_?TypeNumeric] := Sqrt[x] f[Log[y]] f[Log[5]] Output: error at {f} Expression Log[y] Did not return a numeric value f[Log[y]] Sqrt[Log[5]]

Creo que esto funcionará y hace que la comprobación de tipos robusta sea tan simple como escribir una función o dos. El problema es que esto podría ser muy ineficiente porque este código evalúa la expresión x dos veces, una para la comprobación de tipos y otra para la real. Esto podría ser malo si se trata de una llamada de función costosa.

No he descubierto la forma de evitar este segundo problema y agradecería sugerencias en ese frente. ¿Son las continuaciones la salida de este problema?

Espero que esto ayude.


Un intento de implementar la idea de @Timo (theStack)

Incompleto y tal vez defectuoso, pero solo para seguir pensando en ello:

Clear["Global`*"]; funcDef = t_[args___] /[CircleMinus] a_ :> {t["nude", args] := a, ReleaseHold[Hold[t[args] := (If[! ValueQ[theStack], theStack = {}]; AppendTo[theStack, ToString[t]]; Check[ss = a, Print[{"-TheStack->", Evaluate@theStack}]; Print@Hold[a]; Abort[]]; theStack = Most@theStack; Return[ss]) ]]}; v[x_, y_]/[CircleMinus] (Sin@ g[x, y]) /. funcDef; g[x_, y_]/[CircleMinus] x/y /. funcDef; v[2, 3] v[2, 0]

Salida:

Out[299]= Sin[2/3] During evaluation of In[295]:= Power::infy: Infinite expression 1/0 encountered. >> During evaluation of In[295]:= {-TheStack->,{v,g}} During evaluation of In[295]:= Hold[2/0] Out[300]= $Aborted