Re: Programming

*To*: mathgroup at smc.vnet.net*Subject*: [mg2821] Re: Programming*From*: villegas (Robert Villegas)*Date*: Sat, 23 Dec 1995 03:16:38 -0500*Organization*: Wolfram Research, Inc.

In article <4b8583$app at dragonfly.wri.com> Jack Goldberg <jackgold at umich.edu> writes: > Here is my problem: Suppose BuiltIn[expr_] is an > operation either native to Mma or an operation appearing in > some complicated, lengthly package. Suppose that BuiltIn > does not always work. (An example might be Integrate which > fails to find the anti-derivative Integrate[1/(1+Log[x]),x].) > When BuiltIn fails I want to try MyOperation[expr_], but ONLY > if BuiltIn fails! Interactively, this is trivial. Whenever > BuiltIn fails, I recognize the failure because Mma echos the > Input in the Output. (The output of Integrate[1/(1+Log[x]),x] > is itself.) I then apply MyOperation[expr_]. But how does one code > this so that Mma will do MyOperation automatically? That is, I > want a snippet of code that determines the failure of BuiltIn > and then applies MyOperation. Here is a quick and reasonably general template for attaching your own baggage to a built-in function: General Technique: built-in functions ========================================== Unprotect[SomeFunction] $SomeFunctionFlag = True SomeFunction[args___] := Block[{$SomeFunctionFlag = False}, MyExtraCode[ SomeFunction[args] ] ] /; $SomeFunctionFlag ========================================== As an example, suppose we want unresolved Integrate commands to pass their arguments to MyOperation. MyOperation doesn't do anything useful in this example. In[1]:= Unprotect[Integrate] Out[1]= {Integrate} In[2]:= $IntegrateFlag = True Out[2]= True In[3]:= Integrate[args___] := Block[{$IntegrateFlag = False}, With[{builtinResult = Integrate[args]}, If[Head[builtinResult] === Integrate, MyOperation[args], builtinResult] ] ] /; $IntegrateFlag In[4]:= Integrate[f[x], x] Out[4]= MyOperation[f[x], x] In[5]:= Integrate[1/Sqrt[x^3 + x^2 + x + 1], x] 1 Out[5]= MyOperation[---------------------, x] 2 3 Sqrt[1 + x + x + x ] In[6]:= Integrate[1/Sqrt[x^2 + x + 1], x] 1 + 2 x Out[6]= ArcSinh[-------] Sqrt[3] If the built-in or other function is recursive, then it might get somewhere with the original input, but still return something that has unresolved subexpressions in it. Integrate will do this if it can handle part of the integrand but not all of it: In[7]:= Integrate[1 + x + f[x], x] 2 x Out[7]= x + -- + Integrate[f[x], x] 2 If this is the situation, then you could find all the unresolved subexpressions and apply your operator. I haven't tested it much, but maybe the following more powerful replacement would handle simple recursive situations: In[3]:= Integrate[args___] := Block[{$IntegrateFlag = False}, With[{builtinResult = Integrate[args]}, builtinResult /. Integrate[anything___] :> MyOperation[anything] ] ] /; $IntegrateFlag (see the bottom of this note for a sometimes stronger alternative to /. for nested matches) If you want to use this technique on functions that have top-level rules, such as functions from a package, then you usually want to arrange for your rule to fire before the normal ones for the function. Make sure the function is defined first (e.g. by loading a package), then use a modification of the template I gave before for built-in functions: General Technique: top-level functions =========================================== Unprotect[SomeFunction] $SomeFunctionFlag = True PrependTo[DownValues[SomeFunction], Literal @ SomeFunction[args___] :> Block[{$SomeFunctionFlag = False}, MyExtraCode[ SomeFunction[args] ] ] /; $SomeFunctionFlag ] =========================================== The difference is that I force my rule to be placed at the beginning of the list of rules for that function by prepending it to the DownValues (i.e. the assignments, or rules; use UpValues or other if appropriate). Ordinary = and := assignments leave the priority of the rule up to the whim of the internal code. Here's that alternative to /. (the ReplaceAll operator) that is more powerful in some situations because it will do nested substitutions, which ReplaceAll won't (it's not overall *better* than ReplaceAll for a couple of subtle reasons, but for simple situations it can be stronger). ReplaceCases[expr_, rule:(_Rule | _RuleDelayed)] := MapAt[Replace[#, rule]&, expr, Position[expr, First[rule]] ] Just work that into the rule in In[3]: Integrate[args___] := Block[{$IntegrateFlag = False}, With[{builtinResult = Integrate[args]}, ReplaceCases[builtinResult, Integrate[anything___] :> MyOperation[anything]] ] ] /; $IntegrateFlag and now Integrate will handle nested Integrate's if you need it to: In[9]:= Integrate[1 + x + f[x] + Integrate[g[x], x], x] 2 x Out[9]= x + -- + MyOperation[f[x] + MyOperation[g[x], x], x] 2 I hope this helps. Robby Villegas