DMUG-Archiv 2000

Frühere   Chronologischer Index   Spätere
Vorherige   Thematischer Index   Nächste

Re: Rechnungen beschleunigen

> Stimmt das?
> 
> >Es kann in bestimmten Fällen hilfreich sein, das Optimize-Package von
> >mathsource zu benutzen (mathsource.wolfram.com). Die Optimierung besteht
> >dabei darin, mehrfach auftretende Ausdrücke nur einmal berechnen zu
> >müssen. Allerdings ist meine Erfahrung, daß dieses Unterfangen für Mma 4
>                                                                 ^^^^^^^^^
> >praktisch nichts bringt, da offensichtlich der Kernel diese Form der
>                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >Optimierung schon selbst vornimmt.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ich kann nicht sagen, in welcher Form der Kernel optimiert.
Hier nur einige Zahlen (Optimize.m hängt als Attachment an):

<<Optimize`
expr = Nest[(# + Sin[#])&, x, 10];
f1[x_Real] := Optimize[expr];
f2 = Compile[x, Optimize[expr]];
t1 = Timing[ Plot[expr//Evaluate, {x, 0, 0.01}] ][[1]];
t2 = Timing[ Plot[f1[x], {x, 0, 0.01}] ][[1]];
t3 = Timing[ Plot[f2[x], {x, 0, 0.01}] ][[1]];

ergibt für Mma 4:

t1 = 0.06 Second
t2 = 0.22 Second
t3 = 0.01 Second

Gruß,

Thomas Hahn

(* :Name:      Optimize`               *)
(* :Title:     Expression Optimization *)
(* :Author:    Terry Robb              *) (* tdr@XXXXXXX.au *)
(* :Copyright: Copyright 1993 T.D.Robb *)
(* :Summary:   Basic structural optimization of expressions. See ?Optimize *)
(* :Keywords:  Optimize, efficiency, compiling *)
(* :Version:   1.2 *)
(* :Discussion: See examples at the end of this file. *)

BeginPackage["Optimize`"]

Optimize::usage = StringJoin[
  "Optimize[expr] optimizes an expression and returns a HoldBlock object. ",
  "An example usage is: Optimize[Sin[x] + Cos[Sin[x]]] ",
  "and it returns an object that can be used when defining a function, ",
  "for example: f[x_Real] := Optimize[Sin[x] + Cos[Sin[x]]]; ",
  "or it can be used as an argument inside Compile or Function as in: ",
  "g = Compile[x, Optimize[Sin[x] + Cos[Sin[x]]]];. ",
  "An optimized object can also be evaluated directly using ",
  "Normal or ReleaseHold as in: ",
  "Normal[Optimize[Sin[x] + Cos[Sin[x]]] /. x->2.2]." ];

HoldBlock::usage = StringJoin[
  "HoldBlock[vars, body] represents an optimized expression. ",
  "The commands SetDelayed, Compile, Function, Normal and ReleaseHold ",
  "all know about HoldBlock and will convert it to Block as necessary." ];

Cost::usage = StringJoin[
  "Cost[expr] estimates the cost of evaluating an expression by simply ",
  "counting the number of basic elementary operations that are used. ",
  "An example usage is: Cost[Sin[x] + Cos[Sin[x]]] which returns ",
  "Cos + Plus + 2*Sin. Cost also works with optimized objects, so if ",
  "you apply (Cost[#] - Cost[Optimize[#]])& to an expression you will ",
  "see the operations that might be saved." ];

Begin["`Private`"]

  Optimize[expr_, Times->True] := Block[{TIMES, a, b},
      Optimize[expr //. Times[a_, b__] :> TIMES[a, Times[b]]] /. TIMES->Times];

  Optimize[expr_] := Block[{COMP,dups,objs,unis,offs,vars,ruls,sets,body,i,d,v},
    Attributes[COMP] = {HoldAll};
    dups = Table[objs = Level[expr, {-i}, Hold (*, Heads->True *)];
                 unis = List @@ Map[Literal, Union[objs]];
                 Select[unis,  (* Count[objs, #]>1 &, *)
                        Length[Position[objs, #, {1}, 2, Heads->False]]>1 &,
                        Length[objs] - Length[unis]],
                {i, 2, Depth[expr] - 1}];
    dups = DeleteCases[dups, {}]; If[dups==={}, Return[expr]];
    offs = Partition[FoldList[Plus, 0, Map[Length, dups]], 2, 1];
    vars = GETVARS[Last[Last[offs]]];
    ruls = Apply[Rule, Transpose[{Flatten[dups], vars}], {1}];
    ruls = Map[Reverse[Take[ruls, # + {1,0}]]&, offs] // Reverse;
    sets = MapIndexed[Fold[ReplaceAll, #1, Drop[ruls, First[#2]]]&, ruls, {2}];
    sets = Reverse[COMP @@ Flatten[sets]];
    body = Append[sets /. Rule[_[d_], v_] :> Set[v, d], If[Length[ruls]===1,
                  expr /. ruls[[1]], expr //. Flatten[ruls]]];
    HoldBlock @@ {vars, body} /. COMP -> CompoundExpression
  ];

  Optimize  /: (op:SetDelayed|Compile|Function)[args_, o_Optimize, opts___] :=
                  op[args, Evaluate[o], opts];

  Attributes[HoldBlock] = {HoldAll};
  HoldBlock /: (ReleaseHold|Normal)[HoldBlock[vars_,body_]] := Block[vars,body];
  HoldBlock /: (func_ := HoldBlock[vars_,body_]) := (func := Block[vars,body]);
  HoldBlock /: (op:Compile|Function)[args_, HoldBlock[vars_,body_], opts___] :=
                  op[args, Block[vars, body], opts];

  Cost[HoldBlock[vars_, body_] | body_] :=
    Plus @@ Map[Part[#, 1, 0]&, Map[Literal, Level[Hold[body], -2, Hold]]] /.
      CompoundExpression -> 0;

  GETVARS[n_] := ( If[n>NVARS, NVARS = Length[OPTVARS = Join[OPTVARS,
    Table[Unique[System`O, Protected], {n-NVARS+64}]]]]; Take[OPTVARS, n] );

  If[!ListQ[OPTVARS], OPTVARS = {}; NVARS = 0; GETVARS[64]];

  SetAttributes[{Optimize, HoldBlock, Cost}, {ReadProtected, Protected}];
 
End[]

EndPackage[]

(* :Examples:
     expr = Nest[(#+Sin[#])&, x, 10];
     f1[x_Real]  :=  Optimize[expr];
     f2 = Compile[x, Optimize[expr]];
     Plot[expr//Evaluate, {x, 0, 0.01}];//Timing  (* 2.3 Seconds *)
     Plot[f1[x],          {x, 0, 0.01}];//Timing  (* 0.5 Seconds *)
     Plot[f2[x],          {x, 0, 0.01}];//Timing  (* 0.1 Seconds *)
     ?f1

     expr = Expand[(Sin[x*y] + ArcTan[x] + Log[y] + Cosh[x^-y]^5)^10];
     oexpr = Optimize[expr];
     (expr        /. {x->1.1, y->0.5})//Timing  (* 1.0 Seconds *)
     Normal[oexpr /. {x->1.1, y->0.5}]//Timing  (* 0.3 Seconds *)
     Cost[expr]
     Cost[oexpr]

     roots = z /. Solve[z^4 - 12*z^3 - 16*z^2 + 4*z + c == 0, z];
     Optimize[roots]

     expr = (1+x*y)/(1-x*y);
     Optimize[expr]
     FullForm[expr]
     Optimize[expr //. Times[a_, b__] :> TIMES[a, Times[b]]] /. TIMES->Times
     Optimize[expr, Times->True]
*)

(* :Limitations:
  Expressions that contain objects with a HoldAll attribute cause problems.
*)

(* :Inefficiencies:
  The implementation used here works well if only a smallish number (say
  less than 500) of the optimize O$* variables are ultimately needed.
  The worst case is if the number of O$* variables is half the number
  of components in a very large expression, but such cases are rare.
  The code above works well for all the common cases though, and the
  only obvious slow parts are
    1) the part where the Select[] is used, and
    2) the part where the expr//.ruls is used.
  Part 1) could easily be sped up, for example by using something like:
                 Clear[count];
                 Scan[(count[#]=0)&, unis];
                 Scan[(count[#]++)&, objs];
                 Select[unis, count[#]>1 &, Length[objs] - Length[unis]]
  which would asymptotically run much faster for the worst cases, but
  is a lot slower (even asymptotically) for the common cases. One could
  dynamically decide when to use that alternative though.
  Another way to speed up the above is to replace the lines:
   -------------------
                 unis = List @@ Map[Literal, Union[objs]];
                 Select[unis,  (* Count[objs, #]>1 &, *)
                        Length[Position[objs, #, {1}, 2, Heads->False]]>1 &,
                        Length[objs] - Length[unis]],
   -------------------
  with the lines
   -------------------
                 objs = List @@ Map[Literal, objs];
                 If[OddQ[Length[objs]], AppendTo[objs, Null]];
                 Intersection @@ Transpose @ Partition[Sort[objs], 2],
   -------------------
  The above change speeds up the hard cases a lot, but it seems to slow
  down by just a little bit the common cases.
  Part 2) could be sped up by using Dispatch[ruls] which would hash
  the rules and so make the operation linear not quadratic. However
  there is a bug in Dispatch (in both Mma2.1 and Mma2.2) which stopped
  me doing that :-(.
*)

(* :Miscellaneous: Here's my first (but slower) version of Optimize:
  Optimize[expr_] := Block[{COMP,dups,objs,unis,vars,ruls,sets,body,i,d,v},
    Attributes[COMP] = {HoldAll};
    dups = Table[objs = Level[expr, {-i}, Hold];
                 unis = List @@ Map[Literal, Union[objs]];
                 Select[unis, Count[objs, #]>1 &, Length[objs] - Length[unis]],
                {i, 2, Depth[expr] - 1}] // Flatten;
    vars = GETVARS[Length[dups]]; If[vars==={}, Return[expr]];
    ruls = Apply[Rule, Transpose[{dups, vars}], {1}] // Reverse;
    sets = COMP @@ MapIndexed[(#1 //. Drop[ruls, #2[[1]]])&, ruls] // Reverse;
    body = Append[sets /. Rule[_[d_], v_] :> Set[v, d], expr //. ruls];
    HoldBlock @@ {vars, body} /. COMP -> CompoundExpression
  ];
*)

Null;


Verweise:
Frühere   Chronologischer Index   Spätere
Vorherige   Thematischer Index   Nächste

DMUG DMUG-Archiv, http://www.mathematica.ch/archiv.html