首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在大型Mathematica项目中设置诊断错误消息

在大型Mathematica项目中设置诊断错误消息
EN

Stack Overflow用户
提问于 2010-11-14 15:36:21
回答 3查看 1.9K关注 0票数 18

每当我创建一个大型的Mathematica项目时,我都会遇到这样的问题:Preventing avalanche of runtime errors in Mathematica,也就是说,Mathematica的错误消息是不透明的、陈旧的和大量的。

这样做的想法是禁用Mathematica自己的所有错误消息,并在每个函数和模块中实现您自己的类型检查和错误消息。然而,我还没有找到一种简单而有效的方法来做到这一点,例如,一些函数生成一个错误20函数调用,然后得到整个级联的错误消息一直返回到主例程。

如何建立一种简单的机制,只在遇到错误的函数处生成一条错误消息和一个简单的函数调用链列表?

EDIT:,因为它已经在几个答案中出现了;我特别在寻找一些关于它产生的输出的轻量级的东西(否则我只能坚持使用Mathematica的错误消息),而且显然计算开销也是轻量级的。因此,虽然StackTrace的开销很小,但它们在复杂项目中的输出解析速度并不快,需要做一些工作来简化它。

EN

回答 3

Stack Overflow用户

发布于 2010-11-15 04:47:52

这里有一个我一直在尝试的想法:创建一个伪堆栈。

首先创建一个全局变量theStack={},然后在每个FunctionModule中,以AppendTo[theStack,"thisFuncName"]开头,以theStack=Most@theStack结尾。假设函数调用的深度适中(~几十),这应该不会增加任何显著的开销。

然后实现您自己的输入/错误检查,并对错误使用Print@theStack;Abort[];

此方法的改进可能包括:

  1. 想出一种动态获取"thisFuncionName“的方法,这样就可以使AppendTo[]成为所有FunctionsPrint[].
  2. Pushing的相同函数调用,而不是theStack.

上的其他重要变量/状态信息

票数 3
EN

Stack Overflow用户

发布于 2010-11-15 05:56:35

一个提取堆栈的建议,也许是依赖于Trace的东西?

下面是一个使用Trace的示例,来自Chris Chiasson。此代码将1+ Sinx +y+ Tanx +y的求值树保存到~/temp/msgStream.m中

代码语言:javascript
复制
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]]

为了回答Samsdram的问题,下面的代码(也来自Chris)给出了一个数学表达式的求值树。Here is the post from MathGroup with source code and examples.

代码语言:javascript
复制
(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]]
票数 3
EN

Stack Overflow用户

发布于 2010-11-15 08:00:54

也许我们已经想得太多了。如果我们只是稍微调整一下参数上的模式匹配会怎么样?例如,如果我们修改了函数以检查数值,并添加了一些代码以在失败时打印错误。例如,

代码语言:javascript
复制
 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];

步骤2:如果您有一个需要数值的函数fx_,那么只需使用标准模式测试来编写它,一切都应该很好

代码语言:javascript
复制
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]]

我相信这是可行的,它使得健壮的类型检查就像编写一两个函数一样简单。问题是这可能是非常低效的,因为这段代码计算表达式x两次,一次是类型检查,一次是实数。如果涉及昂贵的函数调用,这可能会很糟糕。

希望这能有所帮助。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4176612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档