Wolfram mathematica [[i]]的未估价形式

Wolfram mathematica [[i]]的未估价形式,wolfram-mathematica,operator-precedence,Wolfram Mathematica,Operator Precedence,考虑下面的简单示例 cf = Block[{a, x, degree = 3}, With[{expr = Product[x - a[[i]], {i, degree}]}, Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr] ] ] 这是在编译语句体中传输代码的可能方法之一。它产生Part::partd错误,因为[[i]]在求值时不是列表 简单的解决方法是忽略此消息或将其关闭。当然还有其他的方法。例如,可以通过在编译前在编译体中替

考虑下面的简单示例

cf = Block[{a, x, degree = 3},
  With[{expr = Product[x - a[[i]], {i, degree}]},
   Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]
   ]
  ]
这是在编译语句体中传输代码的可能方法之一。它产生Part::partd错误,因为[[i]]在求值时不是列表

简单的解决方法是忽略此消息或将其关闭。当然还有其他的方法。例如,可以通过在编译前在编译体中替换[[i]]来规避对[[i]]的计算

cf = ReleaseHold[Block[{a, x, degree = 3},
   With[{expr = Product[x - a[i], {i, degree}]},
    Hold[Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]] /. 
     a[i_] :> a[[i]]]
   ]
  ]
如果编译后的函数包含大量代码,那么最后的保留、释放和替换都有点违背我对漂亮代码的想法。有没有一个我还没有考虑过的简短而好的解决方案

对Szabolcs职位的答复 你能告诉我你为什么在这里使用吗

是的,这与我不能使用:=here的原因有关。我使用With,在C中有类似于
#define
的东西,这意味着在我需要它的地方替换代码。使用:=in延迟计算,编译体看到的不是它应该编译的最后一段代码。所以,

<< CompiledFunctionTools`
cf = Block[{a, x, degree = 3}, 
   With[{expr := Product[x - a[[i]], {i, degree}]}, 
    Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]]];
CompilePrint[cf]
这是不好的,因为Compile应该只使用局部变量来计算结果

更新 Szabolcs解决方案在这种情况下起作用,但它使整个表达式未赋值。让我解释一下,为什么在编译之前对表达式进行扩展很重要。我不得不承认,我的玩具不是最好的。因此,让我们在Szabolcs的解决方案中使用With和SetDelayed-like来尝试更好的方法

Block[{a, x}, With[
  {expr := D[Product[x - a[[i]], {i, 3}], x]}, 
  Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]
  ]
 ]
假设我有一个3次多项式,我需要它在编译中的导数。在上面的代码中,我希望Mathematica计算未赋值根a[[I]]的导数,以便在编译代码中经常使用该公式。查看上面的编译代码 我们可以看到,D[…]不能像产品那样被很好地编译,并且保持未评估状态

11  R1 = MainEvaluate[ Hold[D][ R5, R0]]
因此,我最新的问题是:是否有可能在不评估部分[]的情况下评估一段代码-访问它比使用更好/更好

Block[{a, x}, With[
  {expr = D[Quiet@Product[x - a[[i]], {i, 3}], x]}, 
  Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]
  ]
 ]
编辑:我把安静的地方。我把它放在代码块前面,让每个人都能看到,我在这里使用Quiet来抑制警告。正如Ruebenko已经指出的,在实际代码中,它应该总是尽可能接近它所属的位置。使用这种方法,您可能不会错过其他重要的警告/错误

更新2 既然我们离开了原来的问题,我们应该把讨论转移到一个新的话题上。我不知道我的问题应该给谁颁发最佳答案奖,因为我们讨论的是Mathematica和范围界定,而不是如何抑制a[[I]]问题

更新3 给出最终的解决方案:我只是用Quiet来抑制(不幸的是,就像我一直做的那样)a[[I]]警告。在下面的一个真实示例中,我必须在整个块之外使用Quiet来抑制警告

为了将所需的代码注入编译体,我使用纯函数并将代码作为参数内联。这与迈克尔·特罗特(Michael Trott)在他的数学书中使用的方法相同。这有点像Haskell中的
where
子句,您可以在其中定义以后使用的内容

newtonC = Function[{degree, f, df, colors},
   Compile[{{x0, _Complex, 0}, {a, _Complex, 1}},
    Block[{x = x0, xn = 0.0 + 0.0 I, i = 0, maxiter = 256, 
      eps = 10^(-6.), zeroId = 1, j = 1},
     For[i = 0, i < maxiter, ++i,
      xn = x - f/(df + eps);
      If[Abs[xn - x] < eps,
       Break[]
       ];
      x = xn;
      ];
     For[j = 1, j <= degree, ++j,
      If[Abs[xn - a[[j]]] < eps*10^2,
        zeroId = j + 1;
        Break[];
        ];
      ];
     colors[[zeroId]]*(1 - (i/maxiter)^0.3)*1.5
     ],
    CompilationTarget -> "C", RuntimeAttributes -> {Listable}, 
    RuntimeOptions -> "Speed", Parallelization -> True]]@@
    (Quiet@Block[{degree = 3, polynomial, a, x},
     polynomial = HornerForm[Product[x - a[[i]], {i, degree}]];
     {degree, polynomial, HornerForm[D[polynomial, x]], 
      List @@@ (ColorData[52, #] & /@ Range[degree + 1])}])
挑逗者:

单向:

cf = Block[{a, x, degree = 3}, 
  With[{expr = Quiet[Product[x - a[[i]], {i, degree}]]}, 
   Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]]]
不过要小心,如果你真的想要这个

编辑--大警告将使用
函数
的代码注入到使用一些
编译
的局部变量的
编译
中是不可靠的!考虑以下事项:

In[63]:= With[{y=x},Compile[x,y]]
Out[63]= CompiledFunction[{x$},x,-CompiledCode-]

In[64]:= With[{y=x},Compile[{{x,_Real}},y]]
Out[64]= CompiledFunction[{x},x,-CompiledCode-]
注意在第一种情况下,
x
重命名为
x$
。我建议您阅读有关本地化和本地化的内容。(是的,这是令人困惑的!)我们可以猜测为什么这只发生在第一种情况而不是第二种情况,但我的观点是,这种行为可能不是故意的(称之为bug、暗角或未定义的行为),因此依赖它是脆弱的

替换基于
的解决方案,比如我的do work(这不是我对该功能的预期用途,但它非常适合这里…)


原始答案 您可以将
中的
:=
一起使用,如下所示:

cf = Block[{a, x, degree = 3},
  With[{expr := Product[x - a[[i]], {i, degree}]},
   Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]
   ]
  ]
cf = Block[{a, x, degree = 3}, 
   With[{expr := Product[x - a[[i]], {i, degree}]}, 
    Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr, 
     CompilationOptions -> {"InlineExternalDefinitions" -> True}]]];

CompilePrint[cf]
它将避免评估
expr
部分的错误

通常,
=
:=
在所有
模块和
块中都能正常工作


您能告诉我为什么在这里使用
吗?(我相信你有一个很好的理由,从这个简化的例子中我看不出来。)


附加答案

解决@halirutan对编译过程中
未内联的担忧

我认为这与我们在
编译中定义的全局变量完全相同。例如:

In[18]:= global=1
Out[18]= 1

In[19]:= cf2=Compile[{},1+global]
Out[19]= CompiledFunction[{},1+global,-CompiledCode-]

In[20]:= CompilePrint[cf2]
Out[20]= 
        No argument
        3 Integer registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        I0 = 1
        Result = I2

1   I1 = MainEvaluate[ Function[{}, global][ ]]
2   I2 = I0 + I1
3   Return
这是一个普遍的问题。解决方法是告诉
编译
,如下所示:

cf = Block[{a, x, degree = 3},
  With[{expr := Product[x - a[[i]], {i, degree}]},
   Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr]
   ]
  ]
cf = Block[{a, x, degree = 3}, 
   With[{expr := Product[x - a[[i]], {i, degree}]}, 
    Compile[{{x, _Real, 0}, {a, _Real, 1}}, expr, 
     CompilationOptions -> {"InlineExternalDefinitions" -> True}]]];

CompilePrint[cf]
您可以检查,现在没有对主计算器的回调


或者,您可以使用一层额外的
With
而不是
Block
注入
度的值。这会让你非常渴望


Mathematica中的宏展开 这有点不相关,但您在帖子中提到,您使用
进行宏扩展。这是我在Mathematica中实现宏扩展的第一步(可能是错误的)。这没有经过很好的测试,请尝试打破它并发表评论

Clear[defineMacro, macros, expandMacros]

macros = Hold[];

SetAttributes[defineMacro, HoldAllComplete]
defineMacro[name_Symbol, value_] := (AppendTo[macros, name]; name := value)

SetAttributes[expandMacros, HoldAllComplete]
expandMacros[expr_] := Unevaluated[expr] //. Join @@ (OwnValues /@ macros)
说明:

是要展开的所有符号的(保留)列表。
defineMacro
将生成一个新宏。
expandMacros
将在表达式中展开宏定义

注意:我没有实现宏重新定义,当使用
$Pre
进行扩展时,这将不起作用。还要注意递归宏定义和无限循环

用法:Clear[defineMacro, macros, expandMacros] macros = Hold[]; SetAttributes[defineMacro, HoldAllComplete] defineMacro[name_Symbol, value_] := (AppendTo[macros, name]; name := value) SetAttributes[expandMacros, HoldAllComplete] expandMacros[expr_] := Unevaluated[expr] //. Join @@ (OwnValues /@ macros)
$Pre = expandMacros;
defineMacro[a, 1]
b := a + 1
?b

Global`b

b:=1+1
$Pre =.
ClearAll[symbolToHideQ]
SetAttributes[symbolToHideQ, HoldFirst];
symbolToHideQ[s_Symbol, expandedSymbs_] :=! MemberQ[expandedSymbs, Unevaluated[s]];

ClearAll[globalProperties]
globalProperties[] := {DownValues, SubValues, UpValues (*,OwnValues*)};

ClearAll[getSymbolsToHide];
Options[getSymbolsToHide] = {
     Exceptions -> {List, Hold, HoldComplete, 
        HoldForm, HoldPattern, Blank, BlankSequence, BlankNullSequence, 
       Optional, Repeated, Verbatim, Pattern, RuleDelayed, Rule, True, 
       False, Integer, Real, Complex, Alternatives, String, 
       PatternTest,(*Note-  this one is dangerous since it opens a hole 
                    to evaluation leaks. But too good to be ingored *)
       Condition, PatternSequence, Except
      }
 };

getSymbolsToHide[code_Hold, headsToExpand : {___Symbol}, opts : OptionsPattern[]] :=
  Join @@ Complement[
       Cases[{
          Flatten[Outer[Compose, globalProperties[], headsToExpand]], code},
            s_Symbol /; symbolToHideQ[s, headsToExpand] :> Hold[s],
            Infinity,
            Heads -> True
       ],
       Hold /@ OptionValue[Exceptions]];

ClearAll[makeHidingSymbol]
SetAttributes[makeHidingSymbol, HoldAll];
makeHidingSymbol[s_Symbol] := 
    Unique[hidingSymbol(*Unevaluated[s]*) (*,Attributes[s]*)];

ClearAll[makeHidingRules]
makeHidingRules[symbs : Hold[__Symbol]] :=
     Thread[List @@ Map[HoldPattern, symbs] -> List @@ Map[makeHidingSymbol, symbs]];

ClearAll[reverseHidingRules];
reverseHidingRules[rules : {(_Rule | _RuleDelayed) ..}] :=
   rules /. (Rule | RuleDelayed)[Verbatim[HoldPattern][lhs_], rhs_] :> (rhs :> lhs);


FrozenCodeEval[code_Hold, headsToEvaluate : {___Symbol}] :=   
   Module[{symbolsToHide, hidingRules, revHidingRules,  result}, 
      symbolsToHide = getSymbolsToHide[code, headsToEvaluate];
      hidingRules = makeHidingRules[symbolsToHide];
      revHidingRules = reverseHidingRules[hidingRules];
      result = 
         Hold[Evaluate[ReleaseHold[code /. hidingRules]]] /. revHidingRules;
      Apply[Remove, revHidingRules[[All, 1]]];
      result];
In[80]:= 
FrozenCodeEval[
  Hold[Compile[{{x,_Real,0},{a,_Real,1}},D[Product[x-a[[i]],{i,3}],x]]],
  {D,Product,Derivative,Plus}
]

Out[80]= 
Hold[Compile[{{x,_Real,0},{a,_Real,1}},
  (x-a[[1]]) (x-a[[2]])+(x-a[[1]]) (x-a[[3]])+(x-a[[2]]) (x-a[[3]])]]
In[102]:= 
FrozenCodeEval[
  Hold[f[x_, y_, z_] := 
    With[Thread[{a, b, c} = Map[Sqrt, {x, y, z}]], 
       a + b + c]], 
  {Thread, Map}]

Out[102]= 
Hold[
  f[x_, y_, z_] := 
    With[{a = Sqrt[x], b = Sqrt[y], c = Sqrt[z]}, a + b + c]]
newtonC = Function[{degree, f, df, colors},
Compile[{{x0, _Complex, 0}, {a, _Complex, 1}},
Block[{x = x0, xn = 0.0 + 0.0 I, i = 0, maxiter = 256, 
...
RuntimeOptions -> "Speed", Parallelization -> True]]@@
(Quiet@Block[{degree = 3, polynomial, a, x},
 polynomial = HornerForm[Product[x - a[[i]], {i, degree}]];
...
newtonC = Function[{degree, f, df, colors},
Compile[{{x0, _Complex, 0}, {a, _Complex, 1}},
Block[{x = x0, xn = 0.0 + 0.0 I, i = 0, maxiter = 256, 
...
RuntimeOptions -> "Speed", Parallelization -> True],HoldAllComplete]@@
( (( (HoldComplete@@#)/.a[i_]:>a[[i]] )&)@Block[{degree = 3, polynomial, a, x},
 polynomial = HornerForm[Product[x - a[i], {i, degree}]];
...