Skip to main content
replaced http://mathematica.stackexchange.com/ with https://mathematica.stackexchange.com/
Source Link

On the other hand, cacheing the value does store the differential expression df in the SubValues (What is the distinction between DownValues, UpValues, SubValues, and OwnValues?What is the distinction between DownValues, UpValues, SubValues, and OwnValues?) of dFunction. In the case of d20, that adds about 200K to the memory footprint of dFunction, whose basic definitions take up only 6240 bytes.

On the other hand, cacheing the value does store the differential expression df in the SubValues (What is the distinction between DownValues, UpValues, SubValues, and OwnValues?) of dFunction. In the case of d20, that adds about 200K to the memory footprint of dFunction, whose basic definitions take up only 6240 bytes.

On the other hand, cacheing the value does store the differential expression df in the SubValues (What is the distinction between DownValues, UpValues, SubValues, and OwnValues?) of dFunction. In the case of d20, that adds about 200K to the memory footprint of dFunction, whose basic definitions take up only 6240 bytes.

Added explanation
Source Link
Michael E2
  • 244.7k
  • 18
  • 350
  • 774

 

Discussion

Old answer There are some pitfalls in this simple approach. Since Set works by evaluating the right-hand side before making the definition, if F, x or xdot have any values (OwnValues or in the case of F also DownValues for F[x]), they will be used in the definition, creating a different function than the one created when they have no values. In the case where F is undefined, then the definition will depend on the external symbol F.

These things may or may not be desired, or even may be unimportant. For instance, since D[F[x], x] will not work if x has a numeric value. So it is unlikely to be important to Block the symbol in creating the definition. It is more likely that the dependence of the definition of F will be a source of annoyance and perhaps confusion. For instance if F[x_] := Cos[x] is executed before the definition of Fdot, Fdot[x0, xdot0] will always use Sin[x0] * xdot0 (unless a new definition is executed). If F[x_] := Cos[x] is executed after the definition of Fdot, Fdot[x0, xdot0] will use F'[x0] * xdot0; thus the definition of F in force at the time of execution will be used, so that if F is changed at some point, the value of ``Fdot[x0, xdot0]` will automatically be change, too.

Here is a general function that creates a function to evaluate a differential expression (i.e. in terms of x, Dt[x], Dt[Dt[x]] etc.) at inputs of the form {x0, dx0, ddx0,...}, similar to the way one lists the values of a function and its derivatives in Interpolation. The expression to be evaluated is stored explicitly, so any dependence on external symbols is clear.

dxvecClearAll[dFunction];
dFunction[df_, var: _Symbol] := dFunction[df, {2var}];
dFunction[df_, 3vars: {__Symbol}][vals__] /; (*Length[{vals}] replacement== valuesLength@Flatten[{vars}] for:=
 Dt[x] df /. Flatten @ MapThread[
     Thread[NestList[Dt, Dt@Dt[x]#1, etc.Length[#2] *)- 1] -> #2] &,
dyvec =    {5Flatten[{vars}], 7Flatten @* List /@ {vals};}];
Dt@Dt[x(* Sin[y]]
%optional /.formatting dt_Dt*)
Format[dFunction[df_, vars:> With[{levels__Symbol}]] := Level[dt
 HoldForm[dFunction][
  Union @ DeleteCases[
     Cases[Hold[df], s_Symbol /; Context[s] === "Global`", Infinity, Heads -1]}> True],
   Switch[First@levels  Alternatives @@ vars],
  vars]

The Format value, which is optional and shown below, might take a long time on a large expression df. If that is a concern, delete it, delete just the Union @..., or wrap the Union in TimeConstrained:

TimeConstrained[Union@ ..., 0.01] x,/. dxvec[[Length@levels]]$Aborted -> "\[LeftSkeleton]\[RightSkeleton]"

Examples and further utilities:

Undefined function F:

Clear[F];
Fdot2 = dFunction[Dt@F[x], x]
Fdotdot = dFunction[Dt@Dt@F[x, y], {x, y}]

Mathematica graphics

Fdot2[{2, dyvec[[Length@levels]],3}]
(*  3 F'[2]  _*)

Fdotdot[{2, dt]3, /;5}, MatchQ[levels{1, 7, 11}]

Mathematica graphics

Defining F causes Fdot to have the corresponding value:

F[x_] := Cos[x];
Fdot2[{_Symbol2, ___Dt3}]]]
(*
   2-3 Cos[y]Sin[2] Dt[x] Dt[y]*)

Using a previously defined function U:

ClearAll[U, +G, M, m, x, Cos[y]y, Dt[Dt[y]]z];
U[x, y, z] := -G xM Dt[y]^2m/z;
energy Sin[y]= dFunction[U[x, y, z] + (1/2) Dt[Dt[x]]m Sin[y](Dt[x]^2 + Dt[y]^2 + Dt[z]^2), {x, y, z}]

Mathematica graphics

One can get the expression stored in the dFunction with First:

First @ energy
(*  20-((G Cos[y]m M)/z) + 71/2 xm Cos[y](Dt[x]^2 + 3Dt[y]^2 Sin[y]+ -Dt[z]^2) 25 x Sin[y]
*)

I can adapt thisOr one could add methods to a function, if it's on track....If not, I'll delete it.the definition so that

energy["Expression"]

Alternative wayyields the expression above. One might also want to constructput the replacement rulecode from the Format into its own method, that can probably be generalized easily..to inspect a complicated expression for parameters.

With[{repldFunction[df_, =vars <|x: ->{__Symbol}]["Expression"] dxvec:= df;
dFunction[df_, yvars ->: dyvec|>{__Symbol},
]["IndependentVariables"] %:= /.vars;
dFunction[df_, dt_Dtvars :> With[{levels__Symbol}]["Parameters"] := Level[dt, 
 -1]} dFunction[df,
  vars]["Parameters"] =  
 repl[First@levels][[Length@levels]] /; Union@DeleteCases[
     FreeQ[repl[First@levels]Cases[Hold[df], Missing]s_Symbol &&/; Context[s] === "Global`", Infinity, Heads -> True],
     Alternatives MatchQ[levels@@ vars];
dFunction[df_, vars : {_Symbol__Symbol}]["Properties"] :=
 {"Expression", ___Dt"IndependentVariables", "Parameters"}];

With

TimeConstrained[dFunction[df, &&vars]["Parameters"], 0.01] /.
  $Aborted -> "\[LeftSkeleton]\[RightSkeleton]"

in the Format value:

d10 = Length@levelsdFunction[Nest[Dt, <=Sin[a Length@repl[First@levels]x^2], 10], {x}]
d20 = dFunction[Nest[Dt, Sin[a x^2], 20], ]]{x}]

Mathematica graphics

Since the "Parameters" property method is cached above, one can compute it explicitly and then it will be displayed.

d20["Parameters"]
d20

Mathematica graphics

On the other hand, cacheing the value does store the differential expression df in the SubValues (What is the distinction between DownValues, UpValues, SubValues, and OwnValues?) of dFunction. In the case of d20, that adds about 200K to the memory footprint of dFunction, whose basic definitions take up only 6240 bytes.

[Original attempt can be seen in the edit history.]


 

Old answer

dxvec = {2, 3}; (* replacement values for Dt[x], Dt@Dt[x], etc. *)
dyvec = {5, 7};
Dt@Dt[x Sin[y]]
% /. dt_Dt :> With[{levels = Level[dt, -1]},
   Switch[First@levels,
     x, dxvec[[Length@levels]],
     y, dyvec[[Length@levels]],
     _, dt] /; MatchQ[levels, {_Symbol, ___Dt}]]
(*
   2 Cos[y] Dt[x] Dt[y] + x Cos[y] Dt[Dt[y]] - x Dt[y]^2 Sin[y] +  Dt[Dt[x]] Sin[y]

  20 Cos[y] + 7 x Cos[y] + 3 Sin[y] - 25 x Sin[y]
*)

I can adapt this to a function, if it's on track....If not, I'll delete it.

Alternative way to construct the replacement rule, that can probably be generalized easily...

With[{repl = <|x -> dxvec, y -> dyvec|>},
 % /. dt_Dt :> With[{levels = Level[dt, -1]},
     repl[First@levels][[Length@levels]] /; 
     FreeQ[repl[First@levels], Missing] && 
      MatchQ[levels, {_Symbol, ___Dt}] && 
      Length@levels <= Length@repl[First@levels]
    ]]

Discussion

There are some pitfalls in this simple approach. Since Set works by evaluating the right-hand side before making the definition, if F, x or xdot have any values (OwnValues or in the case of F also DownValues for F[x]), they will be used in the definition, creating a different function than the one created when they have no values. In the case where F is undefined, then the definition will depend on the external symbol F.

These things may or may not be desired, or even may be unimportant. For instance, since D[F[x], x] will not work if x has a numeric value. So it is unlikely to be important to Block the symbol in creating the definition. It is more likely that the dependence of the definition of F will be a source of annoyance and perhaps confusion. For instance if F[x_] := Cos[x] is executed before the definition of Fdot, Fdot[x0, xdot0] will always use Sin[x0] * xdot0 (unless a new definition is executed). If F[x_] := Cos[x] is executed after the definition of Fdot, Fdot[x0, xdot0] will use F'[x0] * xdot0; thus the definition of F in force at the time of execution will be used, so that if F is changed at some point, the value of ``Fdot[x0, xdot0]` will automatically be change, too.

Here is a general function that creates a function to evaluate a differential expression (i.e. in terms of x, Dt[x], Dt[Dt[x]] etc.) at inputs of the form {x0, dx0, ddx0,...}, similar to the way one lists the values of a function and its derivatives in Interpolation. The expression to be evaluated is stored explicitly, so any dependence on external symbols is clear.

ClearAll[dFunction];
dFunction[df_, var: _Symbol] := dFunction[df, {var}];
dFunction[df_, vars: {__Symbol}][vals__] /; Length[{vals}] == Length@Flatten[{vars}] :=
  df /. Flatten @ MapThread[
     Thread[NestList[Dt, #1, Length[#2] - 1] -> #2] &,
     {Flatten[{vars}], Flatten @* List /@ {vals}}];
(* optional formatting *)
Format[dFunction[df_, vars: {__Symbol}]] := 
 HoldForm[dFunction][
  Union @ DeleteCases[
     Cases[Hold[df], s_Symbol /; Context[s] === "Global`", Infinity, Heads -> True],
     Alternatives @@ vars],
  vars]

The Format value, which is optional and shown below, might take a long time on a large expression df. If that is a concern, delete it, delete just the Union @..., or wrap the Union in TimeConstrained:

TimeConstrained[Union@ ..., 0.01] /. $Aborted -> "\[LeftSkeleton]\[RightSkeleton]"

Examples and further utilities:

Undefined function F:

Clear[F];
Fdot2 = dFunction[Dt@F[x], x]
Fdotdot = dFunction[Dt@Dt@F[x, y], {x, y}]

Mathematica graphics

Fdot2[{2, 3}]
(*  3 F'[2]  *)

Fdotdot[{2, 3, 5}, {1, 7, 11}]

Mathematica graphics

Defining F causes Fdot to have the corresponding value:

F[x_] := Cos[x];
Fdot2[{2, 3}]
(*  -3 Sin[2]  *)

Using a previously defined function U:

ClearAll[U, G, M, m, x, y, z];
U[x, y, z] := -G M m/z;
energy = dFunction[U[x, y, z] + (1/2) m (Dt[x]^2 + Dt[y]^2 + Dt[z]^2), {x, y, z}]

Mathematica graphics

One can get the expression stored in the dFunction with First:

First @ energy
(*  -((G m M)/z) + 1/2 m (Dt[x]^2 + Dt[y]^2 + Dt[z]^2)  *)

Or one could add methods to the definition so that

energy["Expression"]

yields the expression above. One might also want to put the code from the Format into its own method, to inspect a complicated expression for parameters.

dFunction[df_, vars : {__Symbol}]["Expression"] := df;
dFunction[df_, vars : {__Symbol}]["IndependentVariables"] := vars;
dFunction[df_, vars : {__Symbol}]["Parameters"] :=  
  dFunction[df, vars]["Parameters"] =  
   Union@DeleteCases[
     Cases[Hold[df], s_Symbol /; Context[s] === "Global`", Infinity, Heads -> True],
     Alternatives @@ vars];
dFunction[df_, vars : {__Symbol}]["Properties"] :=
 {"Expression", "IndependentVariables", "Parameters"};

With

TimeConstrained[dFunction[df, vars]["Parameters"], 0.01] /.
  $Aborted -> "\[LeftSkeleton]\[RightSkeleton]"

in the Format value:

d10 = dFunction[Nest[Dt, Sin[a x^2], 10], {x}]
d20 = dFunction[Nest[Dt, Sin[a x^2], 20], {x}]

Mathematica graphics

Since the "Parameters" property method is cached above, one can compute it explicitly and then it will be displayed.

d20["Parameters"]
d20

Mathematica graphics

On the other hand, cacheing the value does store the differential expression df in the SubValues (What is the distinction between DownValues, UpValues, SubValues, and OwnValues?) of dFunction. In the case of d20, that adds about 200K to the memory footprint of dFunction, whose basic definitions take up only 6240 bytes.

[Original attempt can be seen in the edit history.]

Changed answer
Source Link
Michael E2
  • 244.7k
  • 18
  • 350
  • 774

Is this the sort of thing you're after?

Fdot[x_, xdot_] = Dt[F[x]] /. {Dt[x] -> xdot};

Old answer

dxvec = {2, 3}; (* replacement values for Dt[x], Dt@Dt[x], etc. *)
dyvec = {5, 7};
Dt@Dt[x Sin[y]]
% /. dt_Dt :> With[{levels = Level[dt, -1]},
   Switch[First@levels,
     x, dxvec[[Length@levels]],
     y, dyvec[[Length@levels]],
     _, dt] /; MatchQ[levels, {_Symbol, ___Dt}]]
(*
  2 Cos[y] Dt[x] Dt[y] + x Cos[y] Dt[Dt[y]] - x Dt[y]^2 Sin[y] +  Dt[Dt[x]] Sin[y]

  20 Cos[y] + 7 x Cos[y] + 3 Sin[y] - 25 x Sin[y]
*)

I can adapt this to a function, if it's on track....If not, I'll delete it.

Alternative way to construct the replacement rule, that can probably be generalized easily...

With[{repl = <|x -> dxvec, y -> dyvec|>},
 % /. dt_Dt :> With[{levels = Level[dt, -1]},
    repl[First@levels][[Length@levels]] /; 
     FreeQ[repl[First@levels], Missing] && 
      MatchQ[levels, {_Symbol, ___Dt}] && 
      Length@levels <= Length@repl[First@levels]
    ]]

Is this the sort of thing you're after?

dxvec = {2, 3}; (* replacement values for Dt[x], Dt@Dt[x], etc. *)
dyvec = {5, 7};
Dt@Dt[x Sin[y]]
% /. dt_Dt :> With[{levels = Level[dt, -1]},
   Switch[First@levels,
     x, dxvec[[Length@levels]],
     y, dyvec[[Length@levels]],
     _, dt] /; MatchQ[levels, {_Symbol, ___Dt}]]
(*
  2 Cos[y] Dt[x] Dt[y] + x Cos[y] Dt[Dt[y]] - x Dt[y]^2 Sin[y] +  Dt[Dt[x]] Sin[y]

  20 Cos[y] + 7 x Cos[y] + 3 Sin[y] - 25 x Sin[y]
*)

I can adapt this to a function, if it's on track....If not, I'll delete it.

Alternative way to construct the replacement rule, that can probably be generalized easily...

With[{repl = <|x -> dxvec, y -> dyvec|>},
 % /. dt_Dt :> With[{levels = Level[dt, -1]},
    repl[First@levels][[Length@levels]] /; 
     FreeQ[repl[First@levels], Missing] && 
      MatchQ[levels, {_Symbol, ___Dt}] && 
      Length@levels <= Length@repl[First@levels]
    ]]

Is this the sort of thing you're after?

Fdot[x_, xdot_] = Dt[F[x]] /. {Dt[x] -> xdot};

Old answer

dxvec = {2, 3}; (* replacement values for Dt[x], Dt@Dt[x], etc. *)
dyvec = {5, 7};
Dt@Dt[x Sin[y]]
% /. dt_Dt :> With[{levels = Level[dt, -1]},
   Switch[First@levels,
     x, dxvec[[Length@levels]],
     y, dyvec[[Length@levels]],
     _, dt] /; MatchQ[levels, {_Symbol, ___Dt}]]
(*
  2 Cos[y] Dt[x] Dt[y] + x Cos[y] Dt[Dt[y]] - x Dt[y]^2 Sin[y] +  Dt[Dt[x]] Sin[y]

  20 Cos[y] + 7 x Cos[y] + 3 Sin[y] - 25 x Sin[y]
*)

I can adapt this to a function, if it's on track....If not, I'll delete it.

Alternative way to construct the replacement rule, that can probably be generalized easily...

With[{repl = <|x -> dxvec, y -> dyvec|>},
 % /. dt_Dt :> With[{levels = Level[dt, -1]},
    repl[First@levels][[Length@levels]] /; 
     FreeQ[repl[First@levels], Missing] && 
      MatchQ[levels, {_Symbol, ___Dt}] && 
      Length@levels <= Length@repl[First@levels]
    ]]
Source Link
Michael E2
  • 244.7k
  • 18
  • 350
  • 774
Loading