MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

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


  • Prev by Date: Re: ParametricPlot3D
  • Next by Date: Re: shell command
  • Previous by thread: Programming
  • Next by thread: Re: Programming