# Accessing Reduce from DSolve

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

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

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

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.

-

You could swap Reduce for Solve like this:

InternalInheritedBlock[{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:

InternalInheritedBlock[{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.

-
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. – Mark McClure Sep 16 '12 at 14:24
I think you're right; the dependence on Solve seems to be hard-coded. See, for instance, the definition of DSolveDSolveSolve. – Oleksandr R. Sep 16 '12 at 14:30
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. – rcollyer Sep 16 '12 at 14:45

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)

InternalInheritedBlock[{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]];

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]

-
Most excellent! – Mark McClure Sep 16 '12 at 21:53
Nice spelunking. I didn't even think to try that. +1 – rcollyer Sep 17 '12 at 3:20
By running Trace[] with TraceInternal->True you could also see that that call to Solve[] came in turn from SystemPrivateOldSolve[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]] – Dr. belisarius Sep 17 '12 at 5:05
@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). – Simon Woods Sep 17 '12 at 18:17

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:

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.

-
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. – Mark McClure Sep 16 '12 at 16:38

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]
-
Seems so simple - thanks! – Mark McClure Oct 28 '14 at 13:11