2
$\begingroup$

There is a very convenient function Dt that allows to take a total differential of any expression, e.g.:

expr = (a + b c)/d;
Dt[expr]

(Dt[a] + c Dt[b] + b Dt[c])/d - ((a + b c) Dt[d])/d^2

Consider a case where expr is generic (it is not known a priori which and how many variables appear). I would like to have a function that extracts a list of all Dt[x_] from an expression. For the above example it should do:

extract[Dt[expr]]

{Dt[a],Dt[b],Dt[c],Dt[d]}

My own version of this function is:

extract[x_] := Select[Variables[x], (Head[#] === Dt) &]

but I feel like extracting all variables and then selecting a subset is too hacky. Is there a nice way to implement this?

EDIT

Bob Hanlon and Mr. Wizard suggested to use Cases and Union. Unfortunately, these functions appear to be slower than the above in some cases:

Select[Variables[ Dt[(a + b c)/d + (a + b c)/d q]], (Head[#] === Dt) &] // AbsoluteTiming

{0.0000811731, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q]}}

compared to

Cases[Dt[(a + b c)/d + (a + b c)/d q], _Dt, {-2}] // Union // AbsoluteTiming

{0.000136221, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q]}}

$\endgroup$
4
  • 1
    $\begingroup$ Cases[Dt[expr], _Dt, Infinity] // Union $\endgroup$
    – Bob Hanlon
    May 22, 2017 at 21:37
  • 2
    $\begingroup$ @BobHanlon Or slightly shorter: Cases[Dt[expr], _Dt, {-2}] // Union -- the single level search should be somewhat faster with large expressions as well. $\endgroup$
    – Mr.Wizard
    May 22, 2017 at 21:38
  • $\begingroup$ @Mr.Wizard BobHanlon Thank you for the suggestions! Unfortunately that does not yield a speed up. See the edit of my question. $\endgroup$
    – Kagaratsch
    May 22, 2017 at 21:45
  • 1
    $\begingroup$ Union@Cases[expr, HoldPattern[Dt[_]], Infinity] $\endgroup$
    – Ali Hashmi
    May 22, 2017 at 21:50

2 Answers 2

2
$\begingroup$

Of the various methods proposed in comments, plus a hybrid, I find my proposal fastest:

foo = Dt[(a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z + 
    q r ((a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z)];

Select[Variables @ foo, (Head[#] === Dt) &]      // RepeatedTiming

Cases[foo, _Dt, Infinity] // Union               // RepeatedTiming

foo // Variables // Cases[_Dt]                   // RepeatedTiming

Union@Cases[foo, HoldPattern[Dt[_]], Infinity]   // RepeatedTiming

Cases[foo, _Dt, {-2}] // Union                   // RepeatedTiming
{0.0000269, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.00002049, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.000019798, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.00001882, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.0000145, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}
$\endgroup$
4
  • $\begingroup$ Guess, I was not using the correct timing function. Sorry about that! $\endgroup$
    – Kagaratsch
    May 22, 2017 at 22:02
  • $\begingroup$ Wouldn't the results be more accurate if you precede each line with ClearSystemCache[];? $\endgroup$
    – Bob Hanlon
    May 23, 2017 at 0:08
  • $\begingroup$ @BobHanlon I don't see why that would be needed in this case, and using it doesn't appear to change the result. Were we using something like Simplify I think it would be another story. $\endgroup$
    – Mr.Wizard
    May 23, 2017 at 9:08
  • $\begingroup$ On my system (Mac) I got a slightly different ordering using it. $\endgroup$
    – Bob Hanlon
    May 23, 2017 at 13:00
1
$\begingroup$
foo = 
Dt[(a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z + 
 q r ((a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/
     z)];

Union@Level[foo, {-2}] // Cases[#, _Dt] &
(* {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]} *)

or

Select[Union@Level[expr, {-2}], (Head@# === Dt)&]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.