在Mathematica中定义数值常量的最佳方法是什么?
例如,假设我希望g
是由于地球表面引力引起的近似加速度。我给它一个数值(在m/s^2
中),告诉Mathematica它是数字,正数和常数使用
Unprotect[g];
ClearAll[g]
N[g] = 9.81;
NumericQ[g] ^= True;
Positive[g] ^= True;
SetAttributes[g, Constant];
Protect[g];
然后我可以将它用作符号计算中的符号,当需要数值结果时,它将自动计算到9.81。例如1.0 g
评估为9.81
。
这似乎与数学常量中内置的Mathematica无关。例如,Pi > 0
将评估为True
,但g > 0
不会。 (我可以将g > 0
添加到全局$Assumptions
,但即使这样,我也需要调用Simplify
才能使其生效。)
另外,Positive[g]
会返回True
,但Positive[g^2]
不会评估 - 请将其与使用Pi
的等效语句进行比较。
所以我的问题是,我还应该做些什么来定义数值常数?可以设置哪些其他属性/属性?有没有更简单的方法来解决这个问题?等...
答案 0 :(得分:5)
我建议使用零参数“函数”。这样就可以同时给出NumericFunction属性和数字评估规则。后者对于诸如积极的谓词很重要。
SetAttributes[gravUnit, NumericFunction]
N[gravUnit[], prec_: $MachinePrecision] := N[981/100, prec]
In[121]:= NumericQ[gravitUnit[]]
Out[121]= True
In[122]:= Positive[gravUnit[]^2 - 30]
Out[122]= True
Daniel Lichtblau
答案 1 :(得分:3)
可能我天真,但在我看来,你的定义是一个好的开始。可以通过g > 0->True
添加UpValues
之类的内容。要让Positive[g^2]
返回True
,您可能需要重载Positive
,因为UpValues
的深度为1的限制。通常,我认为涉及常量的确切自动求值表达式集是一个移动目标,即使对于内置常量也是如此。换句话说,这些额外的内置规则似乎是根据便利性和频繁使用来确定的,而不是基于第一原则。只要你觉得自己需要它,我就会随时添加新的规则。您可能不能指望您的常量与内置函数一样集成在系统中,但我认为您可以非常接近。您可能不得不在这些符号上重载许多内置函数,但是,这些符号将取决于符号所需的内容。
修改强>
我犹豫要包含这个,因为下面的代码是黑客,但可能在某些情况下有用。这是代码:
Clear[evalFunction];
evalFunction[fun_Symbol, HoldComplete[sym_Symbol]] := False;
Clear[defineAutoNValue];
defineAutoNValue[s_Symbol] :=
Module[{inSUpValue},
s /: expr : f_[left___, s, right___] :=
Block[{inSUpValue = True},
With[{stack = Stack[_]},
If[
expr === Unevaluated[expr] &&
(evalFunction[f, HoldComplete[s]] ||
MemberQ[
stack,
HoldForm[(op_Symbol /; evalFunction[op, HoldComplete[s]])
[___, x_ /; ! FreeQ[Unevaluated[x], HoldPattern@expr], ___]],
Infinity
]
),
f[left, N[s], right],
(* else *)
expr
]]] /; ! TrueQ[inSUpValue]];
ClearAll[substituteNumeric];
SetAttributes[substituteNumeric, HoldFirst];
substituteNumeric[code_, rules : {(_Symbol :> {__Symbol}) ..}] :=
Internal`InheritedBlock[{evalFunction},
MapThread[
Map[Function[f, evalFunction[f, HoldComplete[#]] = True], #2] &,
Transpose[List @@@ rules]
];
code]
有了这个,你可以启用一个符号,在我们指出某些功能调用周围的某些功能可以从中受益的地方自动替换它的数值。这是一个例子:
ClearAll[g, f];
SetAttributes[g, Constant];
N[g] = 9.81;
NumericQ[g] ^= True;
defineAutoNValue[g];
f[g] := "Do something with g";
在这里,我们将尝试计算一些涉及g
的表达式,通常是:
In[391]:= {f[g],g^2,g^2>0, 2 g, Positive[2 g+1],Positive[2g-a],g^2+a^2,g^2+a^2>0,g<0,g^2+a^2<0}
Out[391]= {Do something with g,g^2,g^2>0,2 g,Positive[1+2 g],
Positive[-a+2 g],a^2+g^2,a^2+g^2>0,g<0,a^2+g^2<0}
现在在我们的包装器中(第二个参数给出了一个规则列表,用于指示哪些符号在包含这些符号的代码时包含哪些符号应该导致这些符号被其数值替换):
In[392]:=
substituteNumeric[{f[g],g^2,g^2>0, 2 g, Positive[2 g+1],Positive[2g-a],g^2+a^2,g^2+a^2>0,
g<0,g^2+a^2<0},
{g:>{Positive,Negative,Greater}}]
Out[392]= {Do something with g,g^2,True,2 g,True,Positive[19.62\[VeryThinSpace]-a],
a^2+g^2,96.2361\[VeryThinSpace]+a^2>0,g<0,a^2+g^2<0}
由于以上是黑客,我不能保证任何事情。它在某些情况下可能有用,但必须根据具体情况决定。
答案 2 :(得分:2)
您可能需要考虑使用单位而不仅仅是常量。 Mathematica有几个选项
与单位合作有很多技术问题和细微之处。我发现Designer Units的backgrounder非常有用。关于MathGroup也有一些有趣的讨论。 (例如here)。