25
$\begingroup$

When solving transcendental equations, Solve frequently warns us that inverse functions are being used so that some solutions may not be found.

enter image description here

We also see that Reduce might provide a more complete solution and, indeed, simply changing Solve to Reduce provides a complete, quantified result.

enter image description here

Somtimes, however, this same message is produced by DSolve.

enter image description here

My guess is that DSolve calls Solve which in turn generates the message. Is it possible, though, to access Reduce through DSolve? For this particular equation, it would be easy enough to separate variables, Integrate and then apply Reduce. I'm wondering about a more general solution, though.

$\endgroup$
0

5 Answers 5

15
$\begingroup$

You could swap Reduce for Solve like this:

Internal`InheritedBlock[{Solve}, Unprotect[Solve];Solve = Reduce; Solve[t^2 + t + 1 == 0, t]]

t == -(-1)^(1/3) || t == (-1)^(2/3)

which is indeed Reduce's output. Solve's output would have looked like this:

Solve[t^2 + t + 1 == 0, t]

{{t -> -(-1)^(1/3)}, {t -> (-1)^(2/3)}}

Unfortunately, this trick doesn't work for DSolve:

Internal`InheritedBlock[{Solve}, Unprotect[Solve];Solve = Reduce; 
                                 DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t]
]

DSolve[Derivative[1][u][t] == u[t]/(4 + u[t]^2), u[t], t]

It clearly has an effect as it now returns unevaluated, whereas previously you got a solution. So it seems Solve is indeed used internally. My guess is that the results as returned from Reduce are not in the form DSolve expects and wants, so it certainly isn't the last step. I assume that internal error checking then halts execution and spits out the unresolved call.

Given that DSolve doesn't seem to have options that determine the way the output is treated I don't think that what you want is possible.

$\endgroup$
3
  • $\begingroup$ Very interesting comments - thanks! I'm pretty sure you're right about the difficulties. Ultimately, I'm trying to produce DSolve output that is as palatable as possible for my DE students. $\endgroup$ Sep 16, 2012 at 14:24
  • $\begingroup$ I think you're right; the dependence on Solve seems to be hard-coded. See, for instance, the definition of DSolve`DSolveSolve. $\endgroup$ Sep 16, 2012 at 14:30
  • 1
    $\begingroup$ It can be salvaged, somewhat. The difficulty lies in how the results of Solve and Reduce differ, and likely DSolve relies on that distinction. The DE $u^\prime(t)=-5u(t)$ illustrates it nicely. So, replace Solve = Reduce with Solve[a___]:= {ToRules@Reduce[a]} which works fine for my example. However, it still emits a lot of messages with Mark's DE, but that seems due to a number of conditions being imposed on the solutions. It may be workable, if not easily readable. $\endgroup$
    – rcollyer
    Sep 16, 2012 at 14:45
19
$\begingroup$

It's interesting to see what DSolve is using Solve for. This code prints Solve expressions which occur during the evaluation:

(Note - @belisarius reminds me that TracePrint[DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t], Solve[__], TraceInternal -> True]; would also work for this purpose)

Internal`InheritedBlock[{Solve},
  Unprotect[Solve];
  Solve[x___] := Block[{$guard = True},
     Print["Solve called : ", HoldForm[Solve[x]]];
     Solve[x]] /; ! TrueQ[$guard];
  DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t]];

enter image description here

The first of these is just rearranging the original differential equation to get an expression for u'[t] and causes no problems. The second is an attempt to rearrange the solution, and it's here that the warning is produced. Evaluating Reduce[4 Log[u[t]] + u[t]^2/2 == t + C[1], u[t]] gives the result and message that rcollyer obtained.

The more general solution that Reduce provides can also be obtained like this:

SetOptions[Solve, MaxExtraConditions -> All];
DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t]

enter image description here

$\endgroup$
4
  • $\begingroup$ Most excellent! $\endgroup$ Sep 16, 2012 at 21:53
  • 1
    $\begingroup$ Nice spelunking. I didn't even think to try that. +1 $\endgroup$
    – rcollyer
    Sep 17, 2012 at 3:20
  • 1
    $\begingroup$ By running Trace[] with TraceInternal->True you could also see that that call to Solve[] came in turn from System`Private`OldSolve[4 Log[u[t]] + u[t]^2/2 == t + C[1], {u[t]}, {}, InverseFunctions -> Automatic, MakeRules -> False, Method -> 3, Mode -> Generic, Sort -> True, VerifySolutions -> Automatic, WorkingPrecision -> \[Infinity]] $\endgroup$ Sep 17, 2012 at 5:05
  • $\begingroup$ @belisarius, interesting observation. Of course Trace would have been a far simpler way to extract the calls to Solve. (My excuse is that I originally had extra code in there, comparing the output of Solve and Reduce). $\endgroup$ Sep 17, 2012 at 18:17
10
$\begingroup$

As a piggy back onto Sjoerd's solution, here's a solution that will give you Solve like answers with the conditions still attached:

Block[{Solve, conds},
 Unprotect[Solve];
 Solve[e_, v_] :=
  With[{res = Reduce[e, v]},

   (* capture the conditiions via a side-effect *)
   conds = res /. Equal[var_?(MemberQ[Flatten[{v}], #] &), __] :> Sequence[];

   {
    Cases[res, 
          var_?(MemberQ[Flatten[{v}], #] &) == rhs_ :> Rule[var, rhs], 
          Infinity
   ]
  }
 ];
 Transpose[{
    DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t][[1]], 
    List @@ LogicalExpand[conds]
 }]
]

(* 
{{u[t] -> -2*
  some obscene condition},
  ...
 }
*)

But, it also produces this message:

enter image description here

which could be removed with Quiet, but I left it in as I don't think it is as bad as the Solve one. Also, I used Block instead of Internal`InheritedBlock as we are completely replacing the behavior of Solve with something else.

$\endgroup$
1
  • $\begingroup$ Thanks. I tried a few variations of this without real success. As I said in a response to Sjoerd, it's really an attempt to make things simpler for my students so I'd really need a fairly simple solution. $\endgroup$ Sep 16, 2012 at 16:38
10
$\begingroup$

Update (V11): DSolve now calls SetOptions[Solve,...] internally and overrides SetOptions[Solve, Method -> Reduce] (see this Q&A). Instead one can do the following:

Internal`InheritedBlock[{Solve},
 Unprotect[Solve];
 Solve[eq_, v_, opts___] /; ! TrueQ[$in] :=
  Block[{$in = True, $res1, $res2},
   Solve[eq, v, Method -> Reduce, opts]
   ];
 Protect[Solve];
 DSolve[u'[t] == u[t]/(4 + u[t]^2), u, t]
 ]

Original answer (pre-V11): One can access Reduce through Solve via the Solve option Method -> Reduce. To get this through DSolve, we can use SetOptions.

opts = Options[Solve];
SetOptions[Solve, Method -> Reduce];
DSolve[u'[t] == u[t]/(4 + u[t]^2), u[t], t] // FullSimplify
SetOptions[Solve, opts];

(* long messy answer that looks quite like rcollyer's and Simon Wood's,
   together with the same warning message. *)

It's still not suitable for undergraduates, of course.

The usual by-hand solution has the form t = f(u), so an alternative is to solve the differential equation obtained by transforming the original into terms of the inverse function t[u]:

DSolve[{u'[t] == u[t]/(4 + u[t]^2)} /. {u[t] -> u, u'[t] -> 1/t'[u]}, t[u], u]
(*
  {{t[u] -> u^2/2 + C[1] + 4 Log[u]}}
*)

You can get back the OP's DSolve output with

Solve[First[%] /. {Rule -> Equal, t[u] -> t}, u] /. u -> u[t]
$\endgroup$
1
  • 1
    $\begingroup$ Seems so simple - thanks! $\endgroup$ Oct 28, 2014 at 13:11
3
$\begingroup$

It's worth to note: Solve is called by DSolve`DSolveSolve. So the solution can be

Block[{DSolve`DSolveSolve = Reduce},
    DSolve[u'[t]==u[t]/(4+u[t]^2),u@t,t]
]
$\endgroup$

Your Answer

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

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