4
$\begingroup$

First time posting.

Reproducing the Problem

I'm relatively new to Mathematica (using v.12.3), and working on a project. My problem can be reproduced with this.

m[x_] := {{x, 0}, {0, x}}

f[x_] := Piecewise[{{m[x], x <= 5}}, m[1]]

test = NDSolve[{y'[t] == f[t][[1, 1]], y[0] == 0}, y, {t, 0, 10}]

Outside of NDSolve, f[t][[1,1]] evaluates as expected using the Piecewise function (i.e., f[3][[1,1]] = m[3][[1,1]] but f[10][[1,1]] = m[1][[1,1]]).

However, NDSolve does not seem to evaluate the Piecewise function before attempting to use it, as the stack trace gives:

NDSolve[{Derivative[1][y][t] == {{{t, 0}, {0, t}}, t <= 5}, y[0] == 0}, y, {t, 0, 10}]

Attempted Solutions & Workarounds

Moving the Piecewise statement within NDSolve seems to produce the expected result.

m[x_] := {{x, 0}, {0, x}}

f[x_] := m[x]

test = NDSolve[{
  y'[t] == Piecewise[{{f[t][[1, 1]], t <= 5}}, m[1][[1, 1]]], 
  y[0] == 0}, 
  y, {t, 0, 10}]

I also tried If statements:

m[x_] := {{x, 0}, {0, x}}

f[x_] := If[x >= 10, m[x], m[1]]

test = NDSolve[{y'[t] == f[t][[1, 1]], y[0] == 0}, y, {t, 0, 10}]

However, this appears to ignore the If statement entirely when comparing the outputs using Plot[y[t] /. test, {t, 0, 10}].

I have looked around extensively on StackExchange and the documentation for solutions, but haven't come up with much besides a suspicion that it's

I would appreciate an explanation for why this behavior occurs (or something I can look up to find that information myself; maybe I don't know what to look for), as I've been struggling for some 8+ hours on this. Thank you!

Edit: All excellent responses; thank you so much!

$\endgroup$
1

4 Answers 4

5
$\begingroup$

I think the simplest solution is to use Indexed instead of Part:

test = NDSolveValue[{y'[t] == Indexed[f[t], {1,1}], y[0] == 0}, y, {t, 0, 10}];
ListPlot[test]

enter image description here

$\endgroup$
3
$\begingroup$

Define functions for numerical input and create a second function g[t_?NumericQ] , that takes the desired part of f.

m[x_] = {{x, 0}, {0, x}};

f[x_?NumericQ] := Piecewise[{{m[x], x <= 5}}, m[1]]

g[t_?NumericQ] := f[t][[1, 1]]

ysol = y /. Flatten@NDSolve[{y'[t] == g[t], y[0] == 0}, y, {t, 0, 10}]

Plot[ysol[t], {t, 0, 10}]

enter image description here

$\endgroup$
2
$\begingroup$

It's a matter of evaluation order. Since NDSolve doesn't own attribute like HoldAll, HoldFirst, etc., the equation will automatically evaluate before fed into NDSolve i.e. what happens here is amount to

sys = {y'[t] == f[t][[1, 1]], y[0] == 0}
(* {y'[t] == {{{t, 0}, {0, t}}, t <= 5}, y[0] == 0} *)
test = NDSolve[sys, y, {t, 0, 10}]
(* NDSolve::ndnum *)

You can verify this with Trace:

NDSolve[{y'[t] == f[t][[1, 1]], y[0] == 0}, y, {t, 0, 10}] // Trace

enter image description here

So how to circumvent? Generally somewhat advanced techniques for evaluation order adjustion may be needed, but the matrix inside your Piecewise is just an explicit matrix formed by 4 arithmetic expressions, so we can simply use Simplify`PWToUnitStep:

Clear[x];
m[x_] = {{x, 0}, {0, x}};
f[x_] = Piecewise[{{m[x], x <= 5}}, m[1]] // Simplify`PWToUnitStep
(*
{{1 - UnitStep[5 - x] + x UnitStep[5 - x], 0}, 
 {0, 1 - UnitStep[5 - x] + x UnitStep[5 - x]}}
 *)

NDSolveValue[{y'[t] == f[t][[1, 1]], y[0] == 0}, y, {t, 0, 10}]
% // ListPlot

enter image description here

Here I've made use of an undocumented syntax of ListPlot. See this post for more info.

$\endgroup$
1
$\begingroup$

Note that your function F[x_] := If [x >= 10, f[t][[1,1]], m[1][[1,1]] ] remains unevaluated when condition x >= 10 evaluates to neither True or False. So,

In[1]:= f[t] (*evaluating at x = t, for t a symbol*)

Out[1]= If[t >= 10, m[t], m[1]]

Then the expression

In[2]:= f[t][[1]]

Out[2]= t >= 10

and finally you have

In[3]:= f[t][[1, 1]] (* equivalently f[t][[1]][[1]]*)

Out[3]= t

The expression in Out[3] remains unchanged when you used in

test = NDSolve[{y'[t] == f[t][[1, 1]], y[0] == 0}, y, {t, 0, 10}]
(*equivalently*)
test = NDSolve[{y'[t] == t, y[0] == 0}, y, {t, 0, 10}]

Something different occurs when you use Piecewise. This Piecewise command is developed to be evaluated in expressions such as as Integrate, Minimize, Reduce, DSolve, and Simplify, as well as their numeric analogs. So, when you used inside this last set of functions what occurs is something like this

Piecewise[{conditions in terms of t}] /. (t->(*evaluating at*) tt ) 
$\endgroup$
1
  • 1
    $\begingroup$ "Something different occurs when you use Piecewise. … So, when you used inside this last function what occurred is something like this Piecewise[{conditions in terms of t}] /. (t->(*evaluating at*) tt )" Not quite correct. What happens here is essentially the same as that happens on If[…]: f[x][[1, 1]] has evaulated to {{{x, 0}, {0, x}}, x <= 5}. $\endgroup$
    – xzczd
    May 24, 2022 at 2:21

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.